From f24e5460b0148c4b3b929ff0591ae7291970fe0b Mon Sep 17 00:00:00 2001 From: Bloonbig <147891710+Bloonbig@users.noreply.github.com> Date: Sat, 16 Aug 2025 20:02:55 -0400 Subject: [PATCH 01/36] Update Autumnaton.ash removes autumn-aton tile in standard --- Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash b/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash index 3b8bc0bb..a0ff25ae 100644 --- a/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash +++ b/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash @@ -5,6 +5,7 @@ void IOTMAutumnatonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt # if (!__misc_state["in run"]) return; // Turned off because TES likes this tile to appear in aftercore if (!get_property_boolean("hasAutumnaton")) return; // Don't show if they don't actually have Fall-E if (my_path() == $path[Legacy of Loathing]) return; // Cannot use fall-e in LoL + if (my_path() == $path[Standard]) return; // Cannot use fall-e in Standard if (my_path().id == PATH_G_LOVER) return; // Cannot use fall-e in G-Lover if (in_bad_moon()) return; // Cannot use fall-e in Bad Moon From 8806aeaaf6ede161163c3a54d69c259fe1c717cf Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sat, 16 Aug 2025 21:26:01 -0400 Subject: [PATCH 02/36] perhaps i should add mobius to the iotm import, huh --- .../TourGuide/Items of the Month/Items of the Month import.ash | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/relay/TourGuide/Items of the Month/Items of the Month import.ash b/Source/relay/TourGuide/Items of the Month/Items of the Month import.ash index 22d5dd1a..b1c8cc63 100644 --- a/Source/relay/TourGuide/Items of the Month/Items of the Month import.ash +++ b/Source/relay/TourGuide/Items of the Month/Items of the Month import.ash @@ -167,4 +167,5 @@ import "relay/TourGuide/Items of the Month/2025/April Shower Thoughts Calendar.a import "relay/TourGuide/Items of the Month/2025/Peridot.ash"; import "relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash"; import "relay/TourGuide/Items of the Month/2025/Cooler Yeti.ash"; -import "relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash"; \ No newline at end of file +import "relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash"; +import "relay/TourGuide/Items of the Month/2025/Mobius Ring.ash"; \ No newline at end of file From f3e8aee76dce47cb5bb6f90eeb39bdf15e8a4732 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sat, 16 Aug 2025 21:43:56 -0400 Subject: [PATCH 03/36] some minor cleanup tasks --- .../2025/Allied Radio Backpack.ash | 6 ++--- .../2025/April Shower Thoughts Calendar.ash | 4 +-- .../2025/McHugeLarge Ski Set.ash | 25 ++++++++++++------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash b/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash index 13f10f51..6fb52a2c 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash @@ -13,9 +13,9 @@ void IOTTAlliedRadioBackpackGenerateResource(ChecklistEntry [int] resource_entri if (radioDropsLeft > 0) { description.listAppend("Request an airdrop!"); - description.listAppend("|*SNIPER SUPPORT for +1 Sneak! +100% item, or weak turngen"); - if (!usedIntel) description.listAppend("|*MATERIAL INTEL for 10 turns of +100% item!"); - description.listAppend("|*FUEL or RATIONS for weak turngen"); + description.listAppend("|*" + HTMLGenerateSpanOfClass("SNIPER SUPPORT", "r_bold") + " for a sneak!"); + if (!usedIntel) description.listAppend("|*" + HTMLGenerateSpanOfClass("MATERIAL INTEL", "r_bold") + " for +100% item!"+HTMLGenerateSpanFont("(10 turns)", "gray", "0.9em")); + description.listAppend("|*" + HTMLGenerateSpanOfClass("FUEL or RATIONS", "r_bold") + " for weak turngen!"); resource_entries.listAppend(ChecklistEntryMake("__item allied radio backpack", url, ChecklistSubentryMake(title, "", description))); } } \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2025/April Shower Thoughts Calendar.ash b/Source/relay/TourGuide/Items of the Month/2025/April Shower Thoughts Calendar.ash index 6ea482ec..7e8641c0 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/April Shower Thoughts Calendar.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/April Shower Thoughts Calendar.ash @@ -36,7 +36,7 @@ void IOTMAprilShowerThoughtsGenerateResource(ChecklistEntry [int] resource_entri } int globCount = available_amount($item[glob of wet paper]); { - description.listAppend("Craft your shower thoughts!"); + description.listAppend("Craft your shower thoughts, with your "+pluralise(globCount,"glob","globs")+"!"); } - resource_entries.listAppend(ChecklistEntryMake("__item april shower thoughts shield", "", ChecklistSubentryMake(main_title, description), 10).ChecklistEntrySetIDTag("april shower thoughts calendar resource")); + resource_entries.listAppend(ChecklistEntryMake("__item april shower thoughts shield", url, ChecklistSubentryMake(main_title, description), 10).ChecklistEntrySetIDTag("april shower thoughts calendar resource")); } \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2025/McHugeLarge Ski Set.ash b/Source/relay/TourGuide/Items of the Month/2025/McHugeLarge Ski Set.ash index 0c603406..bcd93269 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/McHugeLarge Ski Set.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/McHugeLarge Ski Set.ash @@ -1,14 +1,21 @@ //Ski set -RegisterResourceGenerationFunction("IOTMSkiSetGenerateResource"); -void IOTMSkiSetGenerateResource(ChecklistEntry [int] resource_entries) +RegisterTaskGenerationFunction("IOTMSkiSetGenerateTasks"); +void IOTMSkiSetGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { if ($item[McHugeLarge duffel bag].available_amount() < 1) return; - - if ($item[McHugeLarge duffel bag].available_amount() > 0 && $item[McHugeLarge right ski].available_amount() == 0); + + if ($item[McHugeLarge duffel bag].available_amount() > 0 && $item[McHugeLarge right ski].available_amount() == 0) { - resource_entries.listAppend(ChecklistEntryMake("__item McHugeLarge duffel bag", "inventory.php?ftext=McHugeLarge+duffel+bag", ChecklistSubentryMake("McHugeLarge duffel bag", "", "Open it!"), 0).ChecklistEntrySetIDTag("McHugeLarge duffel bag resource")); + task_entries.listAppend(ChecklistEntryMake("__item McHugeLarge duffel bag", "inventory.php?ftext=McHugeLarge+duffel+bag", ChecklistSubentryMake("McHugeLarge duffel bag", "", "Open it!"), -10).ChecklistEntrySetIDTag("McHugeLarge duffel bag resource")); } +} + + +RegisterResourceGenerationFunction("IOTMSkiSetGenerateResource"); +void IOTMSkiSetGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[McHugeLarge duffel bag].available_amount() < 1) return; int skiAvalanchesLeft = clampi(3 - get_property_int("_mcHugeLargeAvalancheUses"), 0, 3); int skiSlashesLeft = clampi(3 - get_property_int("_mcHugeLargeSlashUses"), 0, 3); @@ -21,11 +28,11 @@ void IOTMSkiSetGenerateResource(ChecklistEntry [int] resource_entries) //fixme: currently not supported by sneako tile if (lookupItem("McHugeLarge left ski").equipped_amount() == 1) { - description.listAppend(HTMLGenerateSpanFont("LEFT SKI equipped!", "blue")); + description.listAppend(HTMLGenerateSpanFont("|*LEFT SKI equipped!", "blue")); } else if (lookupItem("McHugeLarge left ski").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the LEFT SKI first.", "red")); + description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT SKI first.", "red")); } } if (skiSlashesLeft > 0) @@ -33,11 +40,11 @@ void IOTMSkiSetGenerateResource(ChecklistEntry [int] resource_entries) description.listAppend(HTMLGenerateSpanOfClass(skiSlashesLeft + " slashes", "r_bold") + " left. Track a monster."); if (lookupItem("McHugeLarge left pole").equipped_amount() == 1) { - description.listAppend(HTMLGenerateSpanFont("LEFT POLE equipped!", "blue")); + description.listAppend(HTMLGenerateSpanFont("|*LEFT POLE equipped!", "blue")); } else if (lookupItem("McHugeLarge left pole").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the LEFT POLE first.", "red")); + description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT POLE first.", "red")); } } resource_entries.listAppend(ChecklistEntryMake("__item McHugeLarge duffel bag", url, ChecklistSubentryMake("McHugeLarge ski set skills", description), 1)); From cca5747aaeb4e5baf0ad8ce22adfb7ee985668d8 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sat, 16 Aug 2025 21:48:50 -0400 Subject: [PATCH 04/36] var name error --- .../relay/TourGuide/Items of the Month/2025/Mobius Ring.ash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash index fb210b6a..fe482901 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash @@ -85,9 +85,9 @@ void IOTMMobiusRingGenerateResource(ChecklistEntry [int] resource_entries) description.listAppend("You have encountered " + countMobiusNCs +" NCs so far today."); description.listAppend("|*You have "+pluralise(turnsUntilNextNC, " turn", " turns")+" turns to the next NC, and at least"+pluralise(turnsUntilNextNextNC, " turn", " turns")+" until the NC after that."); - description.listAppend("You have encountered " + countMobiusNCs +" time cops so far today."); - if(timecopFights < 11) description.listAppend(pluralise(min(11-timecopFights,0),"free time cop remains."," free time cops remain.")); - if(timecopFights > 11) description.listAppend(HTMLGenerateSpanFont("No free time cops remain; be careful wearing your ring!", "red")); + description.listAppend("You have encountered " + countTimeCops +" time cops so far today."); + if(countTimeCops < 11) description.listAppend(pluralise(min(11-countTimeCops,0),"free time cop remains."," free time cops remain.")); + if(countTimeCops > 11) description.listAppend(HTMLGenerateSpanFont("No free time cops remain; be careful wearing your ring!", "red")); description.listAppend("|*If every NC today raised Paradoxicity, you have at minimum a " + assumedTimeCopRate + "% chance of encountering a time cop on any given adventure with the mobius ring equipped. Increase Paradoxicity to gradually increase that rate!"); description.listAppend("Try to get to 13 Paradoxicity for +100% item & +50% booze drop on your ring!"); resource_entries.listAppend(ChecklistEntryMake("__item möbius ring", url, ChecklistSubentryMake(title, "", description), 0)); From 4b4a2f7b6b9fba70843f809a46194fd7ab4bf855 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sat, 16 Aug 2025 22:31:41 -0400 Subject: [PATCH 05/36] basically finalized mobius tile --- .../Items of the Month/2025/Mobius Ring.ash | 74 ++++++++++++------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash index fe482901..f679314b 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash @@ -2,10 +2,10 @@ RegisterTaskGenerationFunction("IOTMMobiusRingGenerateTasks"); void IOTMMobiusRingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - item mobRing = $item[möbius ring]; + item mobRing = $item[Möbius ring]; if (mobRing.available_amount() == 0) return; - // Native game prefs. Wish there was a Paradoxicity one... + // Native game prefs. Note that my_paradoxicity() also exists! int lastMobiusTurn = get_property_int("_lastMobiusStripTurn"); int countMobiusNCs = get_property_int("_mobiusStripEncounters"); int countTimeCops = get_property_int("_timeCopsFoughtToday"); @@ -16,79 +16,103 @@ void IOTMMobiusRingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt // There are clearly better ways to do this, but I'm tired and this // is "fine." After 17 NCs, they'll all be 76 turns between, so cap // inputs to 17. - int [int] turnsBetweenNCs = listMake(4,7,13,19,25,31,41,41,41,41,41,51,51,51,51,51,76); + + int [int] turnsBetweenNCs = {1:4, 2:7, 3:13, 4:19, 5:25, 6:31, 7:41, 8:41, 9:41, 10:41, 11:41, 12:51, 13:51, 14:51, 15:51, 16:51, 17:76}; int turnsSinceLastNC = total_turns_played() - lastMobiusTurn; int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - turnsSinceLastNC); - int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] - turnsSinceLastNC); + int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] + turnsUntilNextNC); - // This is sort of a dumb way to do this too, but alas. Also incorrect, - // as we don't have paradoxicity in mafia yet... - int [int] timeCopRate = listMake(2,2,2,2,2,4,4,4,4,4,8,8,8,8,8,16,16,16,16,16,32); - int assumedTimeCopRate = timeCopRate[min(countMobiusNCs + 1, 21)]; + // This is sort of a dumb way to do this too, but alas. Also incorrect, as + // we don't have paradoxicity in mafia yet... + int [int] timeCopRate = { + 0:2, 1:2, 2:2, 3:2, 4:2, + 5:4, 6:4, 7:4, 8:4, 9:4, + 10:8, 11:8, 12:8, 13:8, 14:8, + 15:16, 16:16, 17:16, 18:16, 19:19, + 20:32}; + int currentTimeCopRate = timeCopRate[min(my_paradoxicity(), 20)]; // First, a generic time cop counter task. Low priority if you have // freebies left, high priority if you don't. string url = "inventory.php?ftext=bius+ring"; string [int] copDescription; - string copTitle = HTMLGenerateSpanFont(pluralise(min(11-countTimeCops, 0), "free Time Cop fight", "free Time Cop fights"), "black"); + string copSubTitle = "Forecast is "+currentTimeCopRate+"% chance of cops"; + string copTitle = HTMLGenerateSpanFont(pluralise(min(11-countTimeCops, 0), "free Time Cops fought today", "free Time Cops fought today"), "black"); boolean copsNoLongerFree = countTimeCops > 11; int priority = 10; if (mobEquipped) { - if (!copsNoLongerFree) copDescription.listAppend(HTMLGenerateSpanFont("Ring equipped, it's Möbing time!", "blue")); + if (!copsNoLongerFree) { + copDescription.listAppend(HTMLGenerateSpanFont("Ring equipped, it's Möbing time!", "blue")); + optional_task_entries.listAppend(ChecklistEntryMake("__monster time cop", "", ChecklistSubentryMake(copTitle, copSubtitle, copDescription), priority).ChecklistEntrySetIDTag("morb ring cop task")); + } if (copsNoLongerFree) { copDescription.listAppend(HTMLGenerateSpanFont("Möbius ring equipped, danger!", "red")); priority = -11; + task_entries.listAppend(ChecklistEntryMake("__monster time cop", "", ChecklistSubentryMake(copTitle, copSubtitle, copDescription), priority).ChecklistEntrySetIDTag("morb ring cop task")); } - task_entries.listAppend(ChecklistEntryMake("__monster time cop", "", ChecklistSubentryMake(copTitle, copDescription), priority).ChecklistEntrySetIDTag("morb ring cop task")); } - // Next, a supernag if you happen to have an NC available. + // Next, a supernag if you happen to have an NC available. (Demote from + // a supernag if you already have 11 free cops fought, though.) string [int] ncDescription; string ncTitle = "Möbius non-combat available!"; + string ncSubtitle = "Currently @ " + my_paradoxicity() + " paradoxicity"; + int ncPriority = copsNoLongerFree ? 0 : -11; - if (mobEquipped) ncDescription.listAppend("Keep your Möbius ring equipped for a shot at a Paradoxicity NC!"); + if (mobEquipped) ncDescription.listAppend("Keep your Möbius ring equipped for an NC"); if (!mobEquipped) ncDescription.listAppend(HTMLGenerateSpanFont("Equip your Möbius ring for a shot at a Paradoxicity NC!", "red")); - task_entries.listAppend(ChecklistEntryMake("__item möbius ring", "", ChecklistSubentryMake(ncTitle, ncDescription), -11).ChecklistEntrySetIDTag("morb ring nc task")); + task_entries.listAppend(ChecklistEntryMake("__item Möbius ring", "", ChecklistSubentryMake(ncTitle, ncSubtitle, ncDescription), ncPriority).ChecklistEntrySetIDTag("morb ring nc task")); } RegisterResourceGenerationFunction("IOTMMobiusRingGenerateResource"); void IOTMMobiusRingGenerateResource(ChecklistEntry [int] resource_entries) { - item mobRing = $item[möbius ring]; + item mobRing = $item[Möbius ring]; if (mobRing.available_amount() == 0) return; - // Native game prefs. Wish there was a Paradoxicity one... + // Native game prefs. Note that my_paradoxicity() also exists! int lastMobiusTurn = get_property_int("_lastMobiusStripTurn"); int countMobiusNCs = get_property_int("_mobiusStripEncounters"); int countTimeCops = get_property_int("_timeCopsFoughtToday"); + // Is it equipped? + boolean mobEquipped = mobRing.equipped_amount() == 1; + // There are clearly better ways to do this, but I'm tired and this // is "fine." After 17 NCs, they'll all be 76 turns between, so cap // inputs to 17. - int [int] turnsBetweenNCs = listMake(4,7,13,19,25,31,41,41,41,41,41,51,51,51,51,51,76); + + int [int] turnsBetweenNCs = {1:4, 2:7, 3:13, 4:19, 5:25, 6:31, 7:41, 8:41, 9:41, 10:41, 11:41, 12:51, 13:51, 14:51, 15:51, 16:51, 17:76}; int turnsSinceLastNC = total_turns_played() - lastMobiusTurn; int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - turnsSinceLastNC); - int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] - turnsSinceLastNC); + int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] + turnsUntilNextNC); // This is sort of a dumb way to do this too, but alas. Also incorrect, as // we don't have paradoxicity in mafia yet... - int [int] timeCopRate = listMake(2,2,2,2,2,4,4,4,4,4,8,8,8,8,8,16,16,16,16,16,32); - int assumedTimeCopRate = timeCopRate[min(countMobiusNCs + 1, 21)]; + int [int] timeCopRate = { + 0:2, 1:2, 2:2, 3:2, 4:2, + 5:4, 6:4, 7:4, 8:4, 9:4, + 10:8, 11:8, 12:8, 13:8, 14:8, + 15:16, 16:16, 17:16, 18:16, 19:19, + 20:32}; + int currentTimeCopRate = timeCopRate[min(my_paradoxicity(), 20)]; string [int] description; string url = "inventory.php?ftext=bius+ring"; string title = HTMLGenerateSpanFont(pluralise(turnsUntilNextNC, " turn", " turns") + " to your next Möbius NC", "black"); description.listAppend("You have encountered " + countMobiusNCs +" NCs so far today."); - description.listAppend("|*You have "+pluralise(turnsUntilNextNC, " turn", " turns")+" turns to the next NC, and at least"+pluralise(turnsUntilNextNextNC, " turn", " turns")+" until the NC after that."); + if (turnsUntilNextNC == 0) description.listAppend("|*"+HTMLGenerateSpanFont("You can encounter an NC right now!", "red")); + if (turnsUntilNextNC > 0) description.listAppend("|*You have "+pluralise(turnsUntilNextNC, " turn", " turns")+" turns to the next NC."); + description.listAppend("|*You have at least "+pluralise(turnsUntilNextNextNC, " turn", " turns")+" until the NC after that."); description.listAppend("You have encountered " + countTimeCops +" time cops so far today."); - if(countTimeCops < 11) description.listAppend(pluralise(min(11-countTimeCops,0),"free time cop remains."," free time cops remain.")); + if(countTimeCops < 11) description.listAppend(pluralise(max(11-countTimeCops,0),"free time cop remains."," free time cops remain.")); if(countTimeCops > 11) description.listAppend(HTMLGenerateSpanFont("No free time cops remain; be careful wearing your ring!", "red")); - description.listAppend("|*If every NC today raised Paradoxicity, you have at minimum a " + assumedTimeCopRate + "% chance of encountering a time cop on any given adventure with the mobius ring equipped. Increase Paradoxicity to gradually increase that rate!"); - description.listAppend("Try to get to 13 Paradoxicity for +100% item & +50% booze drop on your ring!"); - resource_entries.listAppend(ChecklistEntryMake("__item möbius ring", url, ChecklistSubentryMake(title, "", description), 0)); + description.listAppend("|*You have a " + currentTimeCopRate + "% chance of encountering a time cop on any given adventure with the ring equipped. Increase Paradoxicity to gradually increase that rate!"); + if(my_paradoxicity() < 13) description.listAppend("Try to get to 13 Paradoxicity for +100% item & +50% booze drop on your ring!"); + resource_entries.listAppend(ChecklistEntryMake("__item Möbius ring", url, ChecklistSubentryMake(title, "", description), 0)); } \ No newline at end of file From 018e68f48eb41362a06b1e4fe6184c853eb0e0e5 Mon Sep 17 00:00:00 2001 From: Bloonbig <147891710+Bloonbig@users.noreply.github.com> Date: Sat, 16 Aug 2025 22:50:35 -0400 Subject: [PATCH 06/36] Update Autumnaton.ash --- Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash b/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash index a0ff25ae..01780ffa 100644 --- a/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash +++ b/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash @@ -4,9 +4,9 @@ void IOTMAutumnatonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt { # if (!__misc_state["in run"]) return; // Turned off because TES likes this tile to appear in aftercore if (!get_property_boolean("hasAutumnaton")) return; // Don't show if they don't actually have Fall-E + if (!$item[autumn dollar].is_unrestricted()) return; // Remove from standard-restricted paths if (my_path() == $path[Legacy of Loathing]) return; // Cannot use fall-e in LoL - if (my_path() == $path[Standard]) return; // Cannot use fall-e in Standard - if (my_path().id == PATH_G_LOVER) return; // Cannot use fall-e in G-Lover + if (my_path().id == PATH_G_LOVER) return; // Cannot use fall-e in G-Lover if (in_bad_moon()) return; // Cannot use fall-e in Bad Moon int autobotsToday = get_property_int("_autumnatonQuests"); From 1f76c80e448aed962732bd5d503b6c5492cc7347 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sat, 16 Aug 2025 23:10:12 -0400 Subject: [PATCH 07/36] initial sea edits --- .../Items of the Month/2025/Mobius Ring.ash | 7 ++-- Source/relay/TourGuide/Quests/Sea.ash | 33 +++++++++++-------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash index f679314b..450759cc 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash @@ -106,13 +106,12 @@ void IOTMMobiusRingGenerateResource(ChecklistEntry [int] resource_entries) string title = HTMLGenerateSpanFont(pluralise(turnsUntilNextNC, " turn", " turns") + " to your next Möbius NC", "black"); description.listAppend("You have encountered " + countMobiusNCs +" NCs so far today."); - if (turnsUntilNextNC == 0) description.listAppend("|*"+HTMLGenerateSpanFont("You can encounter an NC right now!", "red")); + if (turnsUntilNextNC == 0) description.listAppend("|*"+HTMLGenerateSpanFont("You can encounter an NC right now!", "blue")); if (turnsUntilNextNC > 0) description.listAppend("|*You have "+pluralise(turnsUntilNextNC, " turn", " turns")+" turns to the next NC."); description.listAppend("|*You have at least "+pluralise(turnsUntilNextNextNC, " turn", " turns")+" until the NC after that."); - description.listAppend("You have encountered " + countTimeCops +" time cops so far today."); - if(countTimeCops < 11) description.listAppend(pluralise(max(11-countTimeCops,0),"free time cop remains."," free time cops remain.")); + description.listAppend("You have encountered " + countTimeCops +"/11 free time cops today."); if(countTimeCops > 11) description.listAppend(HTMLGenerateSpanFont("No free time cops remain; be careful wearing your ring!", "red")); - description.listAppend("|*You have a " + currentTimeCopRate + "% chance of encountering a time cop on any given adventure with the ring equipped. Increase Paradoxicity to gradually increase that rate!"); + description.listAppend("|*Currently at " + currentTimeCopRate + "% chance of cops; increase Paradoxicity for a higher rate."); if(my_paradoxicity() < 13) description.listAppend("Try to get to 13 Paradoxicity for +100% item & +50% booze drop on your ring!"); resource_entries.listAppend(ChecklistEntryMake("__item Möbius ring", url, ChecklistSubentryMake(title, "", description), 0)); } \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Sea.ash b/Source/relay/TourGuide/Quests/Sea.ash index f96d55ff..491262a2 100644 --- a/Source/relay/TourGuide/Quests/Sea.ash +++ b/Source/relay/TourGuide/Quests/Sea.ash @@ -2,18 +2,21 @@ void QSeaInit() { - - //Have they adventured anywhere underwater? - boolean have_adventured_in_relevant_area = false; - foreach l in $locations[the briny deeps, the brinier deepers, the briniest deepests, an octopus's garden,the wreck of the edgar fitzsimmons, the mer-kin outpost, madness reef,the marinara trench, the dive bar,anemone mine, the coral corral, mer-kin elementary school,mer-kin library,mer-kin gymnasium,mer-kin colosseum,the caliginous abyss] { - if (l.turnsAttemptedInLocation() > 0 || my_location() == l) { - have_adventured_in_relevant_area = true; - break; + // While in 11,037 leagues under the sea, you want this showing no matter what. + + if (my_path().id != 55){ + //Have they adventured anywhere underwater? + boolean have_adventured_in_relevant_area = false; + foreach l in $locations[the briny deeps, the brinier deepers, the briniest deepests, an octopus's garden,the wreck of the edgar fitzsimmons, the mer-kin outpost, madness reef,the marinara trench, the dive bar,anemone mine, the coral corral, mer-kin elementary school,mer-kin library,mer-kin gymnasium,mer-kin colosseum,the caliginous abyss] { + if (l.turnsAttemptedInLocation() > 0 || my_location() == l) { + have_adventured_in_relevant_area = true; + break; + } } + //don't list the quest unless they've started on the path under the sea: + if (!have_adventured_in_relevant_area && $items[Mer-kin trailmap,Mer-kin lockkey,Mer-kin stashbox,wriggling flytrap pellet,damp old boot,Grandma's Map,Grandma's Chartreuse Yarn,Grandma's Fuchsia Yarn,Grandma's Note,black glass].available_amount() == 0) + return; } - //don't list the quest unless they've started on the path under the sea: - if (!have_adventured_in_relevant_area && $items[Mer-kin trailmap,Mer-kin lockkey,Mer-kin stashbox,wriggling flytrap pellet,damp old boot,Grandma's Map,Grandma's Chartreuse Yarn,Grandma's Fuchsia Yarn,Grandma's Note,black glass].available_amount() == 0) - return; if (true) { @@ -80,7 +83,8 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name //gladiator: if (at_gladiator_boss) { description.listAppend("Buff muscle, equip a powerful weapon."); - description.listAppend("Delevel him with jam band bootlegs for a bit, then attack with your weapon."); + description.listAppend("Delevel him for a bit, then attack with your weapon."); + if ($item[crayon shavings].available_amount() > 0) description.listAppend("|*Your crayon shavings are great for this!"); description.listAppend("Make sure not to have anything along that will attack him. (familiars, etc)"); //umm... this probably won't be updated: string [int] things_to_do; @@ -99,7 +103,7 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name string line = "Possibly "; if ($item[dark porquoise ring].available_amount() == 0) line += "acquire and "; - line += "equip a dark porquoise ring to use less jam band bootlegs."; + line += "equip a dark porquoise ring to use fewer delevelers."; description.listAppend(line); } if ($effect[Ruthlessly Efficient].have_effect() == 0) { @@ -192,6 +196,8 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name potential_healers[$item[mer-kin healscroll]] = "mer-kin healscroll (full HP)"; potential_healers[$item[scented massage oil]] = "scented massage oil (full HP)"; potential_healers[$item[soggy used band-aid]] = "soggy used band-aid (full HP)"; + potential_healers[$item[sea gel]] = "sea gel (+500 HP)"; + potential_healers[$item[waterlogged scroll of healing]] = "waterlogged scroll of healing (+250 HP)"; potential_healers[$item[extra-strength red potion]] = "extra-strength red potion (+200 HP)"; potential_healers[$item[red pixel potion]] = "red pixel potion (+100-120 HP)"; potential_healers[$item[red potion]] = "red potion (+100 HP)"; @@ -402,7 +408,7 @@ void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] o string get_fishy, how_to_get_fishy; if ($effect[fishy].have_effect() == 0) { get_fishy = "Acquire fishy."; - how_to_get_fishy = "|*Easy way: Lucky adventure in the brinier deeps, 50 turns."; + how_to_get_fishy = "|*Easy way: Lucky adventure in the brinier deeps, 20 turns."; if ($item[fishy pipe].available_amount() > 0 && !get_property_boolean("_fishyPipeUsed")) how_to_get_fishy += "|*Use fishy pipe."; if (monkees_quest_state.state_string["skate park status"] == "ice" && !get_property_boolean("_skateBuff1")) @@ -537,6 +543,7 @@ void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] o //Find grandpa in one of the three zones. need_minus_combat_modifier = true; temple_subentry.entries.listAppend("Find grandpa sea monkee in " + class_grandpa_location + ".|" + pluraliseWordy(grandpa_ncs_remaining, "non-combat remains", "non-combats remain").capitaliseFirstLetter() + "."); + if(grandpa_ncs_remaining == 3) temple_subentry.entries.listAppend("|*Make sure you talk to little brother, too; the quest only starts when you talk to him!"); } else if (monkees_quest_state.mafia_internal_step == 4) { //Talk to little brother. temple_subentry.entries.listAppend("Talk to little brother."); From 5379c81092090f2b491b85b1bbf6129ae5d4904e Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sat, 16 Aug 2025 23:30:36 -0400 Subject: [PATCH 08/36] minor tweaks --- .../Items of the Month/2022/Autumnaton.ash | 1 - .../2025/Allied Radio Backpack.ash | 2 +- .../Items of the Month/2025/Mobius Ring.ash | 17 +++++++---------- Source/relay/TourGuide/Quests/Level 2.ash | 3 +++ Source/relay/TourGuide/Support/Statics.ash | 1 + 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash b/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash index f04c2690..01780ffa 100644 --- a/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash +++ b/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash @@ -8,7 +8,6 @@ void IOTMAutumnatonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt if (my_path() == $path[Legacy of Loathing]) return; // Cannot use fall-e in LoL if (my_path().id == PATH_G_LOVER) return; // Cannot use fall-e in G-Lover if (in_bad_moon()) return; // Cannot use fall-e in Bad Moon - if (!$item[autumn dollar].is_unrestricted()) return; // Remove from standard-restricted paths int autobotsToday = get_property_int("_autumnatonQuests"); int turncountWhereAutobotReturns = get_property_int("autumnatonQuestTurn"); diff --git a/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash b/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash index 6fb52a2c..383b0c1b 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash @@ -14,7 +14,7 @@ void IOTTAlliedRadioBackpackGenerateResource(ChecklistEntry [int] resource_entri { description.listAppend("Request an airdrop!"); description.listAppend("|*" + HTMLGenerateSpanOfClass("SNIPER SUPPORT", "r_bold") + " for a sneak!"); - if (!usedIntel) description.listAppend("|*" + HTMLGenerateSpanOfClass("MATERIAL INTEL", "r_bold") + " for +100% item!"+HTMLGenerateSpanFont("(10 turns)", "gray", "0.9em")); + if (!usedIntel) description.listAppend("|*" + HTMLGenerateSpanOfClass("MATERIAL INTEL", "r_bold") + " for +100% item! "+HTMLGenerateSpanFont("(10 turns)", "gray", "0.9em")); description.listAppend("|*" + HTMLGenerateSpanOfClass("FUEL or RATIONS", "r_bold") + " for weak turngen!"); resource_entries.listAppend(ChecklistEntryMake("__item allied radio backpack", url, ChecklistSubentryMake(title, "", description))); } diff --git a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash index 450759cc..f2413b7b 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash @@ -22,8 +22,7 @@ void IOTMMobiusRingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - turnsSinceLastNC); int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] + turnsUntilNextNC); - // This is sort of a dumb way to do this too, but alas. Also incorrect, as - // we don't have paradoxicity in mafia yet... + // This is sort of a dumb way to do this too, but alas. int [int] timeCopRate = { 0:2, 1:2, 2:2, 3:2, 4:2, 5:4, 6:4, 7:4, 8:4, 9:4, @@ -91,8 +90,7 @@ void IOTMMobiusRingGenerateResource(ChecklistEntry [int] resource_entries) int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - turnsSinceLastNC); int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] + turnsUntilNextNC); - // This is sort of a dumb way to do this too, but alas. Also incorrect, as - // we don't have paradoxicity in mafia yet... + // This is sort of a dumb way to do this too, but alas. int [int] timeCopRate = { 0:2, 1:2, 2:2, 3:2, 4:2, 5:4, 6:4, 7:4, 8:4, 9:4, @@ -105,13 +103,12 @@ void IOTMMobiusRingGenerateResource(ChecklistEntry [int] resource_entries) string url = "inventory.php?ftext=bius+ring"; string title = HTMLGenerateSpanFont(pluralise(turnsUntilNextNC, " turn", " turns") + " to your next Möbius NC", "black"); - description.listAppend("You have encountered " + countMobiusNCs +" NCs so far today."); - if (turnsUntilNextNC == 0) description.listAppend("|*"+HTMLGenerateSpanFont("You can encounter an NC right now!", "blue")); - if (turnsUntilNextNC > 0) description.listAppend("|*You have "+pluralise(turnsUntilNextNC, " turn", " turns")+" turns to the next NC."); - description.listAppend("|*You have at least "+pluralise(turnsUntilNextNextNC, " turn", " turns")+" until the NC after that."); + if (turnsUntilNextNC == 0) description.listAppend(HTMLGenerateSpanFont("You can encounter NC #" + (countMobiusNCs+1) +" right now!", "blue")); + if (turnsUntilNextNC > 0) description.listAppend("You have "+pluralise(turnsUntilNextNC, " turn", " turns")+" turns to NC #" +(countMobiusNCs+1)+ "."); + description.listAppend("|*You have at least "+pluralise(turnsUntilNextNextNC, " turn", " turns")+" until NC #"+(countMobiusNCs+2)+"."); description.listAppend("You have encountered " + countTimeCops +"/11 free time cops today."); if(countTimeCops > 11) description.listAppend(HTMLGenerateSpanFont("No free time cops remain; be careful wearing your ring!", "red")); - description.listAppend("|*Currently at " + currentTimeCopRate + "% chance of cops; increase Paradoxicity for a higher rate."); - if(my_paradoxicity() < 13) description.listAppend("Try to get to 13 Paradoxicity for +100% item & +50% booze drop on your ring!"); + description.listAppend("|*At " + currentTimeCopRate + "% chance of cops; increase Paradoxicity for more."); + if(my_paradoxicity() < 13) description.listAppend("Boost to 13 Paradoxicity for +100% item & +50% booze drop!"); resource_entries.listAppend(ChecklistEntryMake("__item Möbius ring", url, ChecklistSubentryMake(title, "", description), 0)); } \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Level 2.ash b/Source/relay/TourGuide/Quests/Level 2.ash index 4e158ade..316ff8c1 100644 --- a/Source/relay/TourGuide/Quests/Level 2.ash +++ b/Source/relay/TourGuide/Quests/Level 2.ash @@ -7,6 +7,9 @@ void QLevel2Init() QuestStateParseMafiaQuestProperty(state, "questL02Larva"); if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // Finish this quest if you are in 11,037 Leagues Under the Sea, so the tiles never generate. + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Spooky Forest Quest"; state.image_name = "Spooky Forest"; state.council_quest = true; diff --git a/Source/relay/TourGuide/Support/Statics.ash b/Source/relay/TourGuide/Support/Statics.ash index 19bef736..3a3a9e4e 100644 --- a/Source/relay/TourGuide/Support/Statics.ash +++ b/Source/relay/TourGuide/Support/Statics.ash @@ -60,6 +60,7 @@ static { int PATH_SMOL = 49; // easier to type int PATH_A_SHRUNKEN_ADVENTURER_AM_I = 49; int PATH_WEREPROFESSOR = 50; + int PATH_SEA = 55; } float numeric_modifier_replacement(item it, string modifier_string) { From 9c209f0fff074008a6540dfcea45d05b965a3b93 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sun, 17 Aug 2025 00:00:50 -0400 Subject: [PATCH 09/36] do not display impossible quests in the new sea paths --- Source/relay/TourGuide/Quests/8-bit Realm.ash | 3 +++ Source/relay/TourGuide/Quests/Level 10.ash | 8 +++++++- .../TourGuide/Quests/Level 11 - Copperhead.ash | 14 ++++++++++++-- .../relay/TourGuide/Quests/Level 11 - Desert.ash | 7 ++++++- .../TourGuide/Quests/Level 11 - Hidden City.ash | 7 ++++++- .../TourGuide/Quests/Level 11 - Hidden Temple.ash | 8 +++++++- Source/relay/TourGuide/Quests/Level 11 - Manor.ash | 7 ++++++- .../TourGuide/Quests/Level 11 - Palindome.ash | 7 ++++++- .../relay/TourGuide/Quests/Level 11 - Pyramid.ash | 7 ++++++- Source/relay/TourGuide/Quests/Level 11.ash | 7 ++++++- Source/relay/TourGuide/Quests/Level 12.ash | 5 +++++ Source/relay/TourGuide/Quests/Level 13.ash | 2 +- Source/relay/TourGuide/Quests/Level 3.ash | 4 ++++ Source/relay/TourGuide/Quests/Level 4.ash | 8 ++++++-- Source/relay/TourGuide/Quests/Level 5.ash | 9 +++++++-- Source/relay/TourGuide/Quests/Level 6.ash | 5 +++++ Source/relay/TourGuide/Quests/Level 7.ash | 7 ++++++- Source/relay/TourGuide/Quests/Level 8.ash | 5 +++++ Source/relay/TourGuide/Quests/Level 9.ash | 5 +++++ 19 files changed, 109 insertions(+), 16 deletions(-) diff --git a/Source/relay/TourGuide/Quests/8-bit Realm.ash b/Source/relay/TourGuide/Quests/8-bit Realm.ash index 27628974..faecc4d1 100644 --- a/Source/relay/TourGuide/Quests/8-bit Realm.ash +++ b/Source/relay/TourGuide/Quests/8-bit Realm.ash @@ -7,6 +7,9 @@ void Q8BitInit() // Set the state as "started" if you have the continuum transfunctioner. if (!state.started && $items[continuum transfunctioner].available_amount() > 0) state.started = true; + + // Finish this quest if you are in 11,037 Leagues Under the Sea, so the tiles never generate. + if (my_path().id == PATH_SEA) state.finished = true; // Finish this quest if you are in community service, so the tiles never generate. if (my_path().id == PATH_COMMUNITY_SERVICE) state.finished = true; diff --git a/Source/relay/TourGuide/Quests/Level 10.ash b/Source/relay/TourGuide/Quests/Level 10.ash index 778f8296..7995e758 100644 --- a/Source/relay/TourGuide/Quests/Level 10.ash +++ b/Source/relay/TourGuide/Quests/Level 10.ash @@ -4,7 +4,13 @@ void QLevel10Init() //questL10Garbage QuestState state; QuestStateParseMafiaQuestProperty(state, "questL10Garbage"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Castle Quest"; state.image_name = "castle"; state.council_quest = true; diff --git a/Source/relay/TourGuide/Quests/Level 11 - Copperhead.ash b/Source/relay/TourGuide/Quests/Level 11 - Copperhead.ash index 1b6f6fb9..c0ed02ec 100644 --- a/Source/relay/TourGuide/Quests/Level 11 - Copperhead.ash +++ b/Source/relay/TourGuide/Quests/Level 11 - Copperhead.ash @@ -5,7 +5,12 @@ void QLevel11CopperheadInit() if (true) { QuestState state; QuestStateParseMafiaQuestProperty(state, "questL11Ron"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Zeppelin Quest"; //"Merry-Go-Ron"; state.image_name = "__item copperhead charm (rampant)"; //__item bitchin ford anglia @@ -24,7 +29,12 @@ void QLevel11CopperheadInit() if (true) { QuestState state; QuestStateParseMafiaQuestProperty(state, "questL11Shen"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Copperhead Club Quest"; //"Of Mice and Shen"; state.image_name = "__item copperhead charm"; //"__effect Ancient Annoying Serpent Poison"; diff --git a/Source/relay/TourGuide/Quests/Level 11 - Desert.ash b/Source/relay/TourGuide/Quests/Level 11 - Desert.ash index 3e86baf7..fcbdb1aa 100644 --- a/Source/relay/TourGuide/Quests/Level 11 - Desert.ash +++ b/Source/relay/TourGuide/Quests/Level 11 - Desert.ash @@ -2,7 +2,12 @@ void QLevel11DesertInit() { QuestState state; QuestStateParseMafiaQuestProperty(state, "questL11Desert"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Desert Quest"; state.image_name = "Pyramid"; //"__item instant karma"; diff --git a/Source/relay/TourGuide/Quests/Level 11 - Hidden City.ash b/Source/relay/TourGuide/Quests/Level 11 - Hidden City.ash index 5047501e..cb5342c4 100644 --- a/Source/relay/TourGuide/Quests/Level 11 - Hidden City.ash +++ b/Source/relay/TourGuide/Quests/Level 11 - Hidden City.ash @@ -16,7 +16,12 @@ int numberOfDenseLianaFoughtInShrine(location shrine) void QLevel11HiddenCityInit() { QuestState state; QuestStateParseMafiaQuestProperty(state, "questL11Worship"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Hidden City Quest"; state.image_name = "Hidden City"; diff --git a/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash b/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash index 188baaba..7cc73872 100644 --- a/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash +++ b/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash @@ -10,7 +10,13 @@ void QLevel11HiddenTempleInit() } else QuestStateParseMafiaQuestPropertyValue(state, "unstarted"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_EXPLOSIONS || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_EXPLOSIONS) state.finished = true; + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Hidden Temple Unlock"; state.image_name = "spooky forest"; diff --git a/Source/relay/TourGuide/Quests/Level 11 - Manor.ash b/Source/relay/TourGuide/Quests/Level 11 - Manor.ash index bbc453e6..fddd9043 100644 --- a/Source/relay/TourGuide/Quests/Level 11 - Manor.ash +++ b/Source/relay/TourGuide/Quests/Level 11 - Manor.ash @@ -2,7 +2,12 @@ void QLevel11ManorInit() { QuestState state; QuestStateParseMafiaQuestProperty(state, "questL11Manor"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Lord Spookyraven Quest"; state.image_name = "Spookyraven manor"; diff --git a/Source/relay/TourGuide/Quests/Level 11 - Palindome.ash b/Source/relay/TourGuide/Quests/Level 11 - Palindome.ash index 858a3022..cf94dc0d 100644 --- a/Source/relay/TourGuide/Quests/Level 11 - Palindome.ash +++ b/Source/relay/TourGuide/Quests/Level 11 - Palindome.ash @@ -2,7 +2,12 @@ void QLevel11PalindomeInit() { QuestState state; QuestStateParseMafiaQuestProperty(state, "questL11Palindome"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Palindome Quest"; state.image_name = "Palindome"; diff --git a/Source/relay/TourGuide/Quests/Level 11 - Pyramid.ash b/Source/relay/TourGuide/Quests/Level 11 - Pyramid.ash index 1b8edfc0..b7038427 100644 --- a/Source/relay/TourGuide/Quests/Level 11 - Pyramid.ash +++ b/Source/relay/TourGuide/Quests/Level 11 - Pyramid.ash @@ -3,7 +3,12 @@ void QLevel11PyramidInit() { QuestState state; QuestStateParseMafiaQuestProperty(state, "questL11Pyramid"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Pyramid Quest"; state.image_name = "Pyramid"; __quest_state["Level 11 Pyramid"] = state; diff --git a/Source/relay/TourGuide/Quests/Level 11.ash b/Source/relay/TourGuide/Quests/Level 11.ash index 670342b5..14573ba6 100644 --- a/Source/relay/TourGuide/Quests/Level 11.ash +++ b/Source/relay/TourGuide/Quests/Level 11.ash @@ -26,7 +26,12 @@ void QLevel11Init() { QuestState state; QuestStateParseMafiaQuestProperty(state, "questL11MacGuffin"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "MacGuffin Quest"; state.image_name = "MacGuffin"; state.council_quest = true; diff --git a/Source/relay/TourGuide/Quests/Level 12.ash b/Source/relay/TourGuide/Quests/Level 12.ash index 4b93993e..8c97e781 100644 --- a/Source/relay/TourGuide/Quests/Level 12.ash +++ b/Source/relay/TourGuide/Quests/Level 12.ash @@ -12,7 +12,12 @@ void QLevel12Init() //state_boolean["Orchard Finished"] QuestState state; QuestStateParseMafiaQuestProperty(state, "questL12War"); + + // Finish the quest state in paths that don't need the tile. if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can complete in gg + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Island War Quest"; state.image_name = "island war"; state.council_quest = true; diff --git a/Source/relay/TourGuide/Quests/Level 13.ash b/Source/relay/TourGuide/Quests/Level 13.ash index 0c675d6d..7e13d8e3 100644 --- a/Source/relay/TourGuide/Quests/Level 13.ash +++ b/Source/relay/TourGuide/Quests/Level 13.ash @@ -309,7 +309,7 @@ void QLevel13Init() QuestState state; QuestStateParseMafiaQuestProperty(state, "questL13Final"); - if (__misc_state["in aftercore"] || my_path().id == PATH_BUGBEAR_INVASION || my_path().id == PATH_GREY_GOO || (!state.in_progress && my_path().id == PATH_ACTUALLY_ED_THE_UNDYING)) //FIXME mafia may track the ed L13 quest under this variable + if (__misc_state["in aftercore"] || my_path().id == PATH_BUGBEAR_INVASION || my_path().id == PATH_SEA || my_path().id == PATH_GREY_GOO || (!state.in_progress && my_path().id == PATH_ACTUALLY_ED_THE_UNDYING)) //FIXME mafia may track the ed L13 quest under this variable QuestStateParseMafiaQuestPropertyValue(state, "finished"); //never will start if (__misc_state["Example mode"]) QuestStateParseMafiaQuestPropertyValue(state, "step6"); diff --git a/Source/relay/TourGuide/Quests/Level 3.ash b/Source/relay/TourGuide/Quests/Level 3.ash index 071c2987..c9443174 100644 --- a/Source/relay/TourGuide/Quests/Level 3.ash +++ b/Source/relay/TourGuide/Quests/Level 3.ash @@ -5,7 +5,11 @@ void QLevel3Init() //lastTavernSquare QuestState state; QuestStateParseMafiaQuestProperty(state, "questL03Rat"); + + // Finish the quest state in paths that don't need the tile. if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG + if (my_path().id == PATH_SEA) state.finished = true; state.quest_name = "Typical Tavern Quest"; state.image_name = "Typical Tavern"; diff --git a/Source/relay/TourGuide/Quests/Level 4.ash b/Source/relay/TourGuide/Quests/Level 4.ash index 48d02b86..fb724e2b 100644 --- a/Source/relay/TourGuide/Quests/Level 4.ash +++ b/Source/relay/TourGuide/Quests/Level 4.ash @@ -10,8 +10,12 @@ void QLevel4Init() //step3 -> 3 areas unlocked QuestState state; QuestStateParseMafiaQuestProperty(state, "questL04Bat"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Boss Bat Quest"; state.image_name = "Boss Bat"; state.council_quest = true; diff --git a/Source/relay/TourGuide/Quests/Level 5.ash b/Source/relay/TourGuide/Quests/Level 5.ash index fe9a130b..098110cc 100644 --- a/Source/relay/TourGuide/Quests/Level 5.ash +++ b/Source/relay/TourGuide/Quests/Level 5.ash @@ -4,11 +4,16 @@ void QLevel5Init() //questL05Goblin QuestState state; QuestStateParseMafiaQuestProperty(state, "questL05Goblin"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Knob Goblin Quest"; state.image_name = "cobb's knob"; state.council_quest = true; - + if (my_level() >= 5 || my_path().id == PATH_EXPLOSIONS) state.startable = true; diff --git a/Source/relay/TourGuide/Quests/Level 6.ash b/Source/relay/TourGuide/Quests/Level 6.ash index 6a3770f6..a9c58ea4 100644 --- a/Source/relay/TourGuide/Quests/Level 6.ash +++ b/Source/relay/TourGuide/Quests/Level 6.ash @@ -4,7 +4,12 @@ void QLevel6Init() //questL06Friar QuestState state; QuestStateParseMafiaQuestProperty(state, "questL06Friar"); + + // Finish the quest state in paths that don't need the tile. if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Deep Fat Friars' Quest"; state.image_name = "forest friars"; state.council_quest = true; diff --git a/Source/relay/TourGuide/Quests/Level 7.ash b/Source/relay/TourGuide/Quests/Level 7.ash index 01891041..4f5159ea 100644 --- a/Source/relay/TourGuide/Quests/Level 7.ash +++ b/Source/relay/TourGuide/Quests/Level 7.ash @@ -4,7 +4,12 @@ void QLevel7Init() //questL07Cyrptic QuestState state; QuestStateParseMafiaQuestProperty(state, "questL07Cyrptic"); - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Cyrpt Quest"; state.image_name = "cyrpt"; state.council_quest = true; diff --git a/Source/relay/TourGuide/Quests/Level 8.ash b/Source/relay/TourGuide/Quests/Level 8.ash index 7c970cfe..cbcb8285 100644 --- a/Source/relay/TourGuide/Quests/Level 8.ash +++ b/Source/relay/TourGuide/Quests/Level 8.ash @@ -5,7 +5,12 @@ void QLevel8Init() //questL08Trapper QuestState state; QuestStateParseMafiaQuestProperty(state, "questL08Trapper"); + + // Finish the quest state in paths that don't need the tile. if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Trapper Quest"; state.image_name = "trapper"; state.council_quest = true; diff --git a/Source/relay/TourGuide/Quests/Level 9.ash b/Source/relay/TourGuide/Quests/Level 9.ash index 812a9cc8..18ca065f 100644 --- a/Source/relay/TourGuide/Quests/Level 9.ash +++ b/Source/relay/TourGuide/Quests/Level 9.ash @@ -7,7 +7,12 @@ void QLevel9Init() //booPeakProgress QuestState state; QuestStateParseMafiaQuestProperty(state, "questL09Topping"); + + // Finish the quest state in paths that don't need the tile. if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG + if (my_path().id == PATH_SEA) state.finished = true; + state.quest_name = "Highland Lord Quest"; state.image_name = "orc chasm"; state.council_quest = true; From c2e077f5a33f3894f10d5d6a52bba16ecb4c1773 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sun, 17 Aug 2025 11:16:37 -0400 Subject: [PATCH 10/36] remove CBB from standard restricted paths --- .../TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash b/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash index d19635fb..ae2ef3c6 100644 --- a/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash +++ b/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash @@ -2,8 +2,8 @@ RegisterTaskGenerationFunction("IOTMCosmicBowlingBallGenerateTasks"); void IOTMCosmicBowlingBallGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - if (!get_property_boolean("hasCosmicBowlingBall") == true) - return; + if (!get_property_boolean("hasCosmicBowlingBall") == true) return; + if (!$item[cosmic bowling ball].is_unrestricted()) return; // Remove from standard-restricted paths if (my_path() == $path[Legacy of Loathing]) return; if (my_path().id == PATH_G_LOVER) return; // you can technically use it to bank buffs but the buffs don't work From 1411b4ea5ee10044f20a2a0ff9181fc7d788479d Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sun, 17 Aug 2025 11:22:29 -0400 Subject: [PATCH 11/36] 2nd stab at removing unnecessary tiles --- .../relay/TourGuide/Quests/Level 11 - Hidden Temple.ash | 1 + Source/relay/TourGuide/Quests/Level 5.ash | 9 ++++----- Source/relay/TourGuide/Quests/Manor.ash | 1 + Source/relay/TourGuide/Sets/Area Unlocks.ash | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash b/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash index 7cc73872..108bfdc8 100644 --- a/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash +++ b/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash @@ -28,6 +28,7 @@ void QLevel11HiddenTempleGenerateTasks(ChecklistEntry [int] task_entries, Checkl if (!__quest_state["Hidden Temple Unlock"].in_progress) return; if (my_path().id == PATH_G_LOVER) return; + if (my_path().id == PATH_SEA) return; QuestState base_quest_state = __quest_state["Hidden Temple Unlock"]; ChecklistSubentry subentry; diff --git a/Source/relay/TourGuide/Quests/Level 5.ash b/Source/relay/TourGuide/Quests/Level 5.ash index 098110cc..03689679 100644 --- a/Source/relay/TourGuide/Quests/Level 5.ash +++ b/Source/relay/TourGuide/Quests/Level 5.ash @@ -4,11 +4,6 @@ void QLevel5Init() //questL05Goblin QuestState state; QuestStateParseMafiaQuestProperty(state, "questL05Goblin"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; state.quest_name = "Knob Goblin Quest"; state.image_name = "cobb's knob"; @@ -25,6 +20,10 @@ void QLevel5Init() QuestStateParseMafiaQuestPropertyValue(state, "started"); } + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; __quest_state["Level 5"] = state; __quest_state["Knob Goblin King"] = state; diff --git a/Source/relay/TourGuide/Quests/Manor.ash b/Source/relay/TourGuide/Quests/Manor.ash index f06c05f3..5a40b209 100644 --- a/Source/relay/TourGuide/Quests/Manor.ash +++ b/Source/relay/TourGuide/Quests/Manor.ash @@ -57,6 +57,7 @@ void QManorInit() QuestStateParseMafiaQuestPropertyValue(state, "started"); } if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_SEA) QuestStateParseMafiaQuestPropertyValue(state, "finished"); state.quest_name = "Spookyraven Manor Unlock"; state.image_name = "Spookyraven Manor"; diff --git a/Source/relay/TourGuide/Sets/Area Unlocks.ash b/Source/relay/TourGuide/Sets/Area Unlocks.ash index 2e921545..0b0a5cd3 100644 --- a/Source/relay/TourGuide/Sets/Area Unlocks.ash +++ b/Source/relay/TourGuide/Sets/Area Unlocks.ash @@ -1,7 +1,7 @@ RegisterTaskGenerationFunction("SAreaUnlocksGenerateTasks"); void SAreaUnlocksGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - if (!__misc_state["desert beach available"] && __misc_state["in run"] && my_path().id != PATH_NUCLEAR_AUTUMN) + if (!__misc_state["desert beach available"] && __misc_state["in run"] && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_SEA) { string url; ChecklistSubentry subentry; From c41acda1ac49a047f8b46f8e9fd52d0fbff76ca3 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sun, 17 Aug 2025 11:33:28 -0400 Subject: [PATCH 12/36] 3rd stab at removing unnecessary tiles (and moving tearaway task) --- .../2022/Cosmic Bowling Ball.ash | 2 +- .../2023/Candy Cane Sword Cane.ash | 2 ++ .../2024/Tearaway Pants.ash | 2 +- Source/relay/TourGuide/Missing Items.ash | 2 +- Source/relay/TourGuide/Pulls.ash | 27 ++++++++++--------- Source/relay/TourGuide/Quests/Level 5.ash | 2 +- Source/relay/TourGuide/Sets/Area Unlocks.ash | 1 + 7 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash b/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash index ae2ef3c6..a39051eb 100644 --- a/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash +++ b/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash @@ -39,7 +39,7 @@ void IOTMCosmicBowlingBallGenerateResource(ChecklistEntry [int] resource_entries if (!get_property_boolean("hasCosmicBowlingBall") == true) return; if (my_path() == $path[Legacy of Loathing]) return; if (my_path().id == PATH_G_LOVER) return; // not generating tiles when nothing works right - if ($item[cosmic bowling ball].is_unrestricted()) return; + if (!$item[cosmic bowling ball].is_unrestricted()) return; // Entries int bowlingUses = get_property_int("_cosmicBowlingSkillsUsed"); diff --git a/Source/relay/TourGuide/Items of the Month/2023/Candy Cane Sword Cane.ash b/Source/relay/TourGuide/Items of the Month/2023/Candy Cane Sword Cane.ash index 6f00c1c1..4997e956 100644 --- a/Source/relay/TourGuide/Items of the Month/2023/Candy Cane Sword Cane.ash +++ b/Source/relay/TourGuide/Items of the Month/2023/Candy Cane Sword Cane.ash @@ -13,7 +13,9 @@ void IOTMCandyCaneSwordGenerateTasks(ChecklistEntry [int] task_entries, Checklis // Added a check for all paths where you do not want the tile at all: // - Community Service & Grey Goo: irrelevant // - Avatar of Boris: cannot wield a weapon other than trusty or use a familiar + // - 11,037 Leagues Under the Sea: irrelevant boolean pathCheck = true; + pathCheck = my_path().id == PATH_SEA ? false : true; pathCheck = my_path().id == PATH_COMMUNITY_SERVICE ? false : true; pathCheck = my_path().id == PATH_GREY_GOO ? false : true; pathCheck = my_path().id == PATH_AVATAR_OF_BORIS ? false : true; diff --git a/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash b/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash index 04f99b5c..195fefbf 100644 --- a/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash +++ b/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash @@ -1,5 +1,5 @@ // Tearaway Pants -RegisterResourceGenerationFunction("IOTMTearawayPantsGenerateTask"); +RegisterTaskGenerationFunction("IOTMTearawayPantsGenerateTask"); void IOTMTearawayPantsGenerateTask(ChecklistEntry [int] optional_task_entries) { // Don't show the tile if you don't have the pants. diff --git a/Source/relay/TourGuide/Missing Items.ash b/Source/relay/TourGuide/Missing Items.ash index e2ecedc8..d7f4deca 100644 --- a/Source/relay/TourGuide/Missing Items.ash +++ b/Source/relay/TourGuide/Missing Items.ash @@ -123,7 +123,7 @@ void generateMissingItems(Checklist [int] checklists) if (__quest_state["Level 11 Palindome"].state_boolean["Need instant camera"]) { item camera = 7266.to_item(); if (camera != $item[none]) { - items_needed_entries.listAppend(ChecklistEntryMake("__item " + camera, $location[the haunted bedroom].getClickableURLForLocation(), ChecklistSubentryMake("Disposable instant camera", "", "Found in the Haunted Bedroom.")).ChecklistEntrySetIDTag("Instant camera reminder")); + if (my_path().id != PATH_SEA) items_needed_entries.listAppend(ChecklistEntryMake("__item " + camera, $location[the haunted bedroom].getClickableURLForLocation(), ChecklistSubentryMake("Disposable instant camera", "", "Found in the Haunted Bedroom.")).ChecklistEntrySetIDTag("Instant camera reminder")); } } diff --git a/Source/relay/TourGuide/Pulls.ash b/Source/relay/TourGuide/Pulls.ash index 78230887..18cb7e78 100644 --- a/Source/relay/TourGuide/Pulls.ash +++ b/Source/relay/TourGuide/Pulls.ash @@ -357,18 +357,19 @@ void generatePullList(Checklist [int] checklists) } // As with machete, these are just flat-out great pulls, quest relevant or not - if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && !have_outfit_components("eXtreme Cold-Weather Gear")) - { - item [int] missing_ninja_components = items_missing($items[ninja carabiner, ninja crampons, ninja rope]); - if (missing_ninja_components.count() > 0) - { - string description = missing_ninja_components.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; + // 2025 UPDATE: ... or, well, they were. lol. + // if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && !have_outfit_components("eXtreme Cold-Weather Gear")) + // { + // item [int] missing_ninja_components = items_missing($items[ninja carabiner, ninja crampons, ninja rope]); + // if (missing_ninja_components.count() > 0) + // { + // string description = missing_ninja_components.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; - if (numeric_modifier("cold resistance") < 5.0) - description += "|Will require five " + HTMLGenerateSpanOfClass("cold", "r_element_cold") + " resist to use properly."; - pullable_item_list.listAppend(GPItemMake("Ninja peak climbing", "__item " + missing_ninja_components[0], description)); - } - } + // if (numeric_modifier("cold resistance") < 5.0) + // description += "|Will require five " + HTMLGenerateSpanOfClass("cold", "r_element_cold") + " resist to use properly."; + // pullable_item_list.listAppend(GPItemMake("Ninja peak climbing", "__item " + missing_ninja_components[0], description)); + // } + // } // Literally just 3 straight turnsave to pull scrips if you need em, lol string [int] scrip_reasons; @@ -389,7 +390,7 @@ void generatePullList(Checklist [int] checklists) } // Zepp mob, if done via faceroll, is 40+ turns. This stuff is massive value in ignoring that. - if (__quest_state["Level 11 Ron"].mafia_internal_step <= 2 && __quest_state["Level 11 Ron"].state_int["protestors remaining"] > 1) + if (my_path().id != PATH_SEA && __quest_state["Level 11 Ron"].mafia_internal_step <= 2 && __quest_state["Level 11 Ron"].state_int["protestors remaining"] > 1) { item [int] missing_freebird_components = items_missing( __misc_state["Torso aware"] ? $items[lynyrdskin cap,lynyrdskin tunic,lynyrdskin breeches,lynyrd musk] : $items[lynyrdskin cap,lynyrdskin breeches,lynyrd musk] ); @@ -478,7 +479,7 @@ void generatePullList(Checklist [int] checklists) pullable_item_list.listAppend(GPItemMake($item[stench jelly], "Skips ahead to an NC, saves 2-3 turns each.", 20)); // Quest-y pull; just save searching for an NC, like an NC forcer, but also save the turn spent! - if (!get_property_ascension("lastTempleUnlock") && $item[spooky-gro fertilizer].item_amount() == 0 && $item[spooky-gro fertilizer].item_is_usable()) + if (my_path().id != PATH_SEA && !get_property_ascension("lastTempleUnlock") && $item[spooky-gro fertilizer].item_amount() == 0 && $item[spooky-gro fertilizer].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[spooky-gro fertilizer], "Saves 2-ish turns while unlocking temple.")); if (my_path().id != PATH_COMMUNITY_SERVICE && $item[11-leaf clover].item_is_usable()) diff --git a/Source/relay/TourGuide/Quests/Level 5.ash b/Source/relay/TourGuide/Quests/Level 5.ash index 03689679..c637c29d 100644 --- a/Source/relay/TourGuide/Quests/Level 5.ash +++ b/Source/relay/TourGuide/Quests/Level 5.ash @@ -34,7 +34,7 @@ void QLevel5GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int { if (!__quest_state["Level 5"].in_progress) return; - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO || __misc_state["in aftercore"]) + if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO || my_path().id == PATH_SEA || __misc_state["in aftercore"]) return; string url = "place.php?whichplace=plains"; //if the quest isn't started and we have unlocked the barracks, wait until it's started: diff --git a/Source/relay/TourGuide/Sets/Area Unlocks.ash b/Source/relay/TourGuide/Sets/Area Unlocks.ash index 0b0a5cd3..0e730e58 100644 --- a/Source/relay/TourGuide/Sets/Area Unlocks.ash +++ b/Source/relay/TourGuide/Sets/Area Unlocks.ash @@ -77,6 +77,7 @@ void SAreaUnlocksGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry { ChecklistSubentry subentry; subentry.header = "Unlock mysterious island"; + if (my_path().id == PATH_SEA) return; if (my_path().id == PATH_COMMUNITY_SERVICE) { subentry.header += "?"; From d9a4877fa9a8edf8423b0c982a2b5ea256b1ccee Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sun, 17 Aug 2025 11:40:48 -0400 Subject: [PATCH 13/36] need to add other task entries to make it generate w/ optional tasks --- .../relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash b/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash index 195fefbf..2693c78f 100644 --- a/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash +++ b/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash @@ -1,6 +1,6 @@ // Tearaway Pants RegisterTaskGenerationFunction("IOTMTearawayPantsGenerateTask"); -void IOTMTearawayPantsGenerateTask(ChecklistEntry [int] optional_task_entries) +void IOTMTearawayPantsGenerateTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { // Don't show the tile if you don't have the pants. if (!__iotms_usable[lookupItem("tearaway pants")]) return; From 5b3c8cfbd6b794b90c5620d897aa5c4b33c55fff Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sun, 17 Aug 2025 15:09:15 -0400 Subject: [PATCH 14/36] mobius error & beret hammertime support --- .../Items of the Month/2025/Mobius Ring.ash | 9 ++++---- .../2025/Prismatic Beret.ash | 21 ++++++++++++------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash index f2413b7b..3896128e 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash @@ -19,7 +19,7 @@ void IOTMMobiusRingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt int [int] turnsBetweenNCs = {1:4, 2:7, 3:13, 4:19, 5:25, 6:31, 7:41, 8:41, 9:41, 10:41, 11:41, 12:51, 13:51, 14:51, 15:51, 16:51, 17:76}; int turnsSinceLastNC = total_turns_played() - lastMobiusTurn; - int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - turnsSinceLastNC); + int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - (lastMobiusTurn == 0 ? my_turncount() : turnsSinceLastNC)); int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] + turnsUntilNextNC); // This is sort of a dumb way to do this too, but alas. @@ -63,7 +63,7 @@ void IOTMMobiusRingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt if (mobEquipped) ncDescription.listAppend("Keep your Möbius ring equipped for an NC"); if (!mobEquipped) ncDescription.listAppend(HTMLGenerateSpanFont("Equip your Möbius ring for a shot at a Paradoxicity NC!", "red")); - task_entries.listAppend(ChecklistEntryMake("__item Möbius ring", "", ChecklistSubentryMake(ncTitle, ncSubtitle, ncDescription), ncPriority).ChecklistEntrySetIDTag("morb ring nc task")); + if(turnsUntilNextNC == 0) task_entries.listAppend(ChecklistEntryMake("__item Möbius ring", "", ChecklistSubentryMake(ncTitle, ncSubtitle, ncDescription), ncPriority).ChecklistEntrySetIDTag("morb ring nc task")); } @@ -87,7 +87,7 @@ void IOTMMobiusRingGenerateResource(ChecklistEntry [int] resource_entries) int [int] turnsBetweenNCs = {1:4, 2:7, 3:13, 4:19, 5:25, 6:31, 7:41, 8:41, 9:41, 10:41, 11:41, 12:51, 13:51, 14:51, 15:51, 16:51, 17:76}; int turnsSinceLastNC = total_turns_played() - lastMobiusTurn; - int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - turnsSinceLastNC); + int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - (lastMobiusTurn == 0 ? my_turncount() : turnsSinceLastNC)); int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] + turnsUntilNextNC); // This is sort of a dumb way to do this too, but alas. @@ -106,9 +106,8 @@ void IOTMMobiusRingGenerateResource(ChecklistEntry [int] resource_entries) if (turnsUntilNextNC == 0) description.listAppend(HTMLGenerateSpanFont("You can encounter NC #" + (countMobiusNCs+1) +" right now!", "blue")); if (turnsUntilNextNC > 0) description.listAppend("You have "+pluralise(turnsUntilNextNC, " turn", " turns")+" turns to NC #" +(countMobiusNCs+1)+ "."); description.listAppend("|*You have at least "+pluralise(turnsUntilNextNextNC, " turn", " turns")+" until NC #"+(countMobiusNCs+2)+"."); - description.listAppend("You have encountered " + countTimeCops +"/11 free time cops today."); + description.listAppend("" + countTimeCops +"/11 free time cops today. (currently @ "+currentTimeCopRate+"% rate)"); if(countTimeCops > 11) description.listAppend(HTMLGenerateSpanFont("No free time cops remain; be careful wearing your ring!", "red")); - description.listAppend("|*At " + currentTimeCopRate + "% chance of cops; increase Paradoxicity for more."); if(my_paradoxicity() < 13) description.listAppend("Boost to 13 Paradoxicity for +100% item & +50% booze drop!"); resource_entries.listAppend(ChecklistEntryMake("__item Möbius ring", url, ChecklistSubentryMake(title, "", description), 0)); } \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash b/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash index eed47c99..1c2c6dd0 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash @@ -9,8 +9,10 @@ void IOTMPrismaticBeretGenerateResource(ChecklistEntry [int] resource_entries) string [int] description; string title = HTMLGenerateSpanFont(busksLeft + " Prismatic Beret Busks", "purple"); - int total; + int hatpower; + int pantspower; int shartpower; + int total = 0; item thing; item shart2; foreach shart in $slots[shirt] { @@ -18,24 +20,29 @@ void IOTMPrismaticBeretGenerateResource(ChecklistEntry [int] resource_entries) if (shart2 != $item[none]) shartpower += get_power(shart2); } - foreach it in $slots[hat, pants] { + foreach it in $slots[hat] { thing = equipped_item(it); if (thing != $item[none]) - total += get_power(thing); + hatpower += get_power(thing); + } + + foreach it in $slots[pants] { + thing = equipped_item(it); + if (thing != $item[none]) + pantspower += get_power(thing); } if (busksLeft > 0) { - if (lookupSkill("tao of the terrapin").have_skill()) { - total = total*2; - } + if (lookupSkill("tao of the terrapin").have_skill()) total += hatpower*2 + pantspower*2; + if ($effect[Hammertime].have_effect() > 0) total += pantspower*3; description.listAppend("Gain buffs based on current equipment Power"); description.listAppend("Currently " + (HTMLGenerateSpanFont(shartpower+total, "blue")) + " Power"); if (lookupItem("prismatic beret").equipped_amount() == 0) { description.listAppend(HTMLGenerateSpanFont("Equip the beret to busk!", "red")); } - if (lookupFamiliar("mad hatrack").familiar_is_usable()); { + if (lookupFamiliar("mad hatrack").familiar_is_usable() && $item[sane hatrack].is_unrestricted()); { description.listAppend(HTMLGenerateSpanFont("(You can put it on your hatrack)", "blue")); } From 599c2b16133b6a2a2141c6a51e47e2c44afcd091 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sun, 17 Aug 2025 16:16:25 -0400 Subject: [PATCH 15/36] do not need nagamar under the sea --- Source/relay/TourGuide/State.ash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/relay/TourGuide/State.ash b/Source/relay/TourGuide/State.ash index 2cf5ef47..216c2306 100644 --- a/Source/relay/TourGuide/State.ash +++ b/Source/relay/TourGuide/State.ash @@ -550,7 +550,7 @@ void setUpState() if ($item[wand of nagamar].available_amount() > 0) wand_of_nagamar_needed = false; - + if (my_path().id == PATH_SEA) wand_of_nagamar_needed = false; if (!wand_of_nagamar_needed) { From caec0b26c223b5b218777cd78b8c56e6ea23ff86 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sun, 17 Aug 2025 17:32:22 -0400 Subject: [PATCH 16/36] removing hatrack ping --- .../relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash b/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash index 1c2c6dd0..822f85e2 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash @@ -42,7 +42,7 @@ void IOTMPrismaticBeretGenerateResource(ChecklistEntry [int] resource_entries) if (lookupItem("prismatic beret").equipped_amount() == 0) { description.listAppend(HTMLGenerateSpanFont("Equip the beret to busk!", "red")); } - if (lookupFamiliar("mad hatrack").familiar_is_usable() && $item[sane hatrack].is_unrestricted()); { + if (lookupFamiliar("mad hatrack").familiar_is_usable() && $item[sane hatrack].is_unrestricted()) { description.listAppend(HTMLGenerateSpanFont("(You can put it on your hatrack)", "blue")); } From b630a3e3c0bf8c9873cba432af5551e90733e6bc Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sun, 17 Aug 2025 21:35:55 +0000 Subject: [PATCH 17/36] Import changes from refs/heads/under-the-sea --- .editorconfig | 11 - .github/ISSUE_TEMPLATE/bug-report.yml | 36 - .github/ISSUE_TEMPLATE/feature_request.yml | 31 - .../pull_request_template.md | 11 - .github/workflows/main.yml | 424 - .github/workflows/sync-to-testing-branch.yml | 27 - Bundle_ASH_script.py | 193 - LICENSE | 24 - Matrix/glyphs.png | Bin 16177 -> 0 bytes Matrix/matrix.html | 16 - Matrix/matrix.js | 202 - README.md | 31 - Source/relay/TourGuide/Daily Resources.ash | 655 - .../Items of the Month/2009/Sugar.ash | 53 - .../2010/Crown of Thrones.ash | 316 - .../2011/Plastic Vampire Fangs.ash | 131 - .../2013/Psychoanalytic.ash | 537 - .../Items of the Month/2013/Smithsness.ash | 129 - .../TourGuide/Items of the Month/2014/DNA.ash | 572 - .../Items of the Month/2014/Grimstone.ash | 292 - .../Items of the Month/2014/Speakeasy.ash | 118 - .../2014/SpringBreakBeach.ash | 20 - .../Items of the Month/2015/Barrel God.ash | 84 - .../2015/Deck of Every Card.ash | 330 - .../2015/Haunted Doghouse.ash | 14 - .../Items of the Month/2015/Machine Elf.ash | 187 - .../Items of the Month/2015/Mayo Clinic.ash | 91 - .../Items of the Month/2016/Clan Floundry.ash | 51 - .../2016/Detective School.ash | 57 - .../2016/Gingerbread City.ash | 141 - .../Items of the Month/2016/Intergnat.ash | 103 - .../2016/LT&T Cowboy Boots.ash | 254 - .../2016/Protonic Accelerator Pack.ash | 191 - .../Items of the Month/2016/Snojo.ash | 208 - .../2016/Source Terminal.ash | 311 - .../2016/Telegraph Office.ash | 263 - .../Items of the Month/2016/Thanksgarden.ash | 141 - .../Items of the Month/2016/Time-Spinner.ash | 50 - .../Items of the Month/2016/Witchess.ash | 76 - .../Items of the Month/2017/Asdon Martin.ash | 146 - .../Items of the Month/2017/GenieBottle.ash | 35 - .../Items of the Month/2017/KGBriefcase.ash | 34 - .../Items of the Month/2017/Meteor Lore.ash | 87 - .../Items of the Month/2017/New You.ash | 62 - .../2017/Portable Pantogram.ash | 69 - .../2017/Space Jellyfish.ash | 121 - .../Items of the Month/2017/Spacegate.ash | 56 - .../2017/Tunnel of Love.ash | 71 - .../Items of the Month/2017/XO Skeleton.ash | 93 - .../2018/Bastille Battalion.ash | 80 - .../Items of the Month/2018/BoomBox.ash | 42 - .../2018/Boxing Daycare.ash | 82 - .../Items of the Month/2018/Cat Burglar.ash | 81 - .../Items of the Month/2018/Garbage Tote.ash | 98 - .../Items of the Month/2018/God Lobster.ash | 87 - .../Items of the Month/2018/Latte.ash | 70 - .../2018/Neverending Party.ash | 194 - .../Items of the Month/2018/Voting Booth.ash | 74 - .../Items of the Month/2018/Zatara.ash | 42 - .../Items of the Month/2019/Beach Comb.ash | 49 - .../2019/Eight Days a Week Pills.ash | 44 - .../2019/Getaway Campsite.ash | 146 - .../2019/Kramco Sausage-o-Matic.ash | 95 - .../2019/Lil Doctor Bag.ash | 92 - .../Items of the Month/2019/May Saber.ash | 76 - .../Items of the Month/2019/Pizza Cube.ash | 62 - .../2019/Pocket Professor.ash | 129 - .../2019/Red Nosed Snapper.ash | 380 - .../Items of the Month/2019/Rune Spoon.ash | 88 - .../Items of the Month/2019/Vampire Cloak.ash | 19 - .../2020/Better Shrooms and Gardens.ash | 96 - .../2020/Bird-a-Day Calendar.ash | 138 - .../Items of the Month/2020/Box O Ghosts.ash | 34 - .../2020/Cargo Cultist Shorts.ash | 43 - .../2020/Comprehensive Cartography.ash | 100 - .../Items of the Month/2020/Guzzlr.ash | 183 - .../Items of the Month/2020/Melodramedary.ash | 65 - .../2020/Powerful Glove.ash | 43 - .../2020/Spinmaster Lathe.ash | 12 - .../2020/Superhero Cape.ash | 135 - .../Items of the Month/2021/Backup Camera.ash | 33 - .../2021/Cold Medicine Cabinet.ash | 178 - .../2021/Daylight Shavings Helmet.ash | 111 - .../Items of the Month/2021/Emotion Chip.ash | 97 - .../2021/Familiar Scrapbook.ash | 29 - .../2021/Industrial Fire Extinguisher.ash | 65 - .../2021/Miniature Crystal Ball.ash | 66 - .../2021/Potted Power Plant.ash | 57 - .../2021/Short Order Cook.ash | 18 - .../2021/Underground Fireworks Shop.ash | 66 - .../2021/Vampire Vintner.ash | 87 - .../Items of the Month/2022/Autumnaton.ash | 118 - .../2022/Combat Lover Locket.ash | 98 - .../Items of the Month/2022/Cookbookbat.ash | 95 - .../2022/Cosmic Bowling Ball.ash | 84 - .../2022/Cursed Magnifying Glass.ash | 73 - .../2022/Designer Sweatpants.ash | 31 - .../Items of the Month/2022/Grey Goose.ash | 112 - .../Items of the Month/2022/June Cleaver.ash | 128 - .../2022/Jurassic Parka.ash | 70 - .../2022/Mayday Supply Package.ash | 12 - .../2022/Model Train Set.ash | 206 - .../2022/Oliver's Place.ash | 16 - .../2022/Tiny Stillsuit.ash | 211 - .../2022/Unbreakable Umbrella.ash | 37 - .../Items of the Month/2023/2002 Catalog.ash | 169 - .../2023/A Guide to Burning Leaves.ash | 304 - .../2023/August Scepter.ash | 289 - .../Items of the Month/2023/Book of Facts.ash | 92 - .../2023/Candy Cane Sword Cane.ash | 105 - .../2023/Cincho de Mayo.ash | 87 - .../2023/Closed Circuit Pay Phone.ash | 176 - .../2023/Cursed Monkey Paw.ash | 361 - .../2023/Jill of all Trades.ash | 49 - .../2023/Patriotic Eagle.ash | 150 - .../Items of the Month/2023/Rock Garden.ash | 92 - .../2023/SIT Course Certificate.ash | 64 - .../2024/Apriling Band Helmet.ash | 69 - .../Items of the Month/2024/Chest Mimic.ash | 33 - .../2024/Everfull Dart Holster.ash | 51 - .../2024/Mayam Calendar.ash | 106 - .../Items of the Month/2024/Mini Kiwi.ash | 34 - .../Items of the Month/2024/Peace Turkey.ash | 26 - .../2024/Roman Candelabra.ash | 37 - .../2024/Sept-Ember Censer.ash | 43 - .../Items of the Month/2024/Spring Shoes.ash | 47 - .../Items of the Month/2024/TakerSpace.ash | 37 - .../2024/Tearaway Pants.ash | 29 - .../2024/VIP Photobooth.ash | 35 - .../Items of the Month/2024/bat wings.ash | 93 - .../2025/Allied Radio Backpack.ash | 21 - .../2025/April Shower Thoughts Calendar.ash | 42 - .../Items of the Month/2025/Cooler Yeti.ash | 58 - .../Items of the Month/2025/CyberRealm.ash | 126 - .../Items of the Month/2025/Leprecondo.ash | 50 - .../2025/McHugeLarge Ski Set.ash | 51 - .../Items of the Month/2025/Mobius Ring.ash | 113 - .../Items of the Month/2025/Peridot.ash | 20 - .../2025/Prismatic Beret.ash | 51 - .../Items of the Month import.ash | 171 - .../Items of the Month/Misc/Gardens.ash | 110 - .../Items of the Month/Misc/Horsery.ash | 10 - .../Items of the Month/Misc/Libram.ash | 103 - .../Items of the Month/Misc/Tomes.ash | 244 - .../Time-Twitching Tower/Tea Tree.ash | 135 - .../TourGuide/Limit Mode/Batfellow State.ash | 201 - .../relay/TourGuide/Limit Mode/Batfellow.ash | 405 - .../relay/TourGuide/Limit Mode/Spelunking.ash | 1013 - Source/relay/TourGuide/Main.ash | 371 - Source/relay/TourGuide/Missing Items.ash | 199 - .../Paths/Actually Ed the Undying.ash | 388 - .../TourGuide/Paths/Avatar of Jarlsberg.ash | 90 - .../Paths/Avatar of Shadows over Loathing.ash | 117 - .../TourGuide/Paths/Avatar of Sneaky Pete.ash | 288 - .../Paths/Avatar of West of Loathing.ash | 203 - Source/relay/TourGuide/Paths/Bad Moon.ash | 544 - .../TourGuide/Paths/Bugbear Invasion.ash | 536 - .../TourGuide/Paths/Community Service.ash | 236 - Source/relay/TourGuide/Paths/Dark Gift.ash | 24 - Source/relay/TourGuide/Paths/Explosions.ash | 30 - .../TourGuide/Paths/Fall of the Dinosaurs.ash | 21 - Source/relay/TourGuide/Paths/G-Lover.ash | 19 - .../relay/TourGuide/Paths/Gelatinous Noob.ash | 364 - Source/relay/TourGuide/Paths/Grey Goo.ash | 10 - Source/relay/TourGuide/Paths/Heavy Rains.ash | 232 - Source/relay/TourGuide/Paths/KOLHS.ash | 162 - .../TourGuide/Paths/Legacy of Loathing.ash | 37 - .../TourGuide/Paths/License to Adventure.ash | 114 - Source/relay/TourGuide/Paths/Low Key.ash | 36 - .../relay/TourGuide/Paths/Nuclear Autumn.ash | 158 - Source/relay/TourGuide/Paths/Paths import.ash | 25 - Source/relay/TourGuide/Paths/The Source.ash | 154 - .../Paths/Way of the Surprising Fist.ash | 40 - .../relay/TourGuide/Paths/WereProfessor.ash | 185 - .../relay/TourGuide/Paths/Zombie Slayer.ash | 57 - Source/relay/TourGuide/Plants.ash | 371 - Source/relay/TourGuide/Pulls.ash | 1131 - Source/relay/TourGuide/QuestState.ash | 134 - Source/relay/TourGuide/Quests.ash | 92 - Source/relay/TourGuide/Quests/8-bit Realm.ash | 348 - Source/relay/TourGuide/Quests/Airport.ash | 1670 - Source/relay/TourGuide/Quests/Artist.ash | 80 - Source/relay/TourGuide/Quests/Azazel.ash | 255 - Source/relay/TourGuide/Quests/Felonia.ash | 171 - Source/relay/TourGuide/Quests/Guild.ash | 138 - .../relay/TourGuide/Quests/Intergalaktik.ash | 56 - .../relay/TourGuide/Quests/Legendary Beat.ash | 201 - Source/relay/TourGuide/Quests/Level 10.ash | 381 - .../Quests/Level 11 - Copperhead.ash | 430 - .../TourGuide/Quests/Level 11 - Desert.ash | 245 - .../Quests/Level 11 - Hidden City.ash | 502 - .../Quests/Level 11 - Hidden Temple.ash | 143 - .../TourGuide/Quests/Level 11 - Manor.ash | 309 - .../TourGuide/Quests/Level 11 - Palindome.ash | 336 - .../TourGuide/Quests/Level 11 - Pyramid.ash | 231 - Source/relay/TourGuide/Quests/Level 11.ash | 229 - Source/relay/TourGuide/Quests/Level 12.ash | 906 - Source/relay/TourGuide/Quests/Level 13.ash | 1577 - Source/relay/TourGuide/Quests/Level 2.ash | 93 - Source/relay/TourGuide/Quests/Level 3.ash | 146 - Source/relay/TourGuide/Quests/Level 4.ash | 173 - Source/relay/TourGuide/Quests/Level 5.ash | 245 - Source/relay/TourGuide/Quests/Level 6.ash | 194 - Source/relay/TourGuide/Quests/Level 7.ash | 327 - Source/relay/TourGuide/Quests/Level 8.ash | 300 - Source/relay/TourGuide/Quests/Level 9.ash | 693 - .../relay/TourGuide/Quests/Madness Bakery.ash | 44 - Source/relay/TourGuide/Quests/Manor.ash | 551 - Source/relay/TourGuide/Quests/Marty.ash | 103 - Source/relay/TourGuide/Quests/Meatsmith.ash | 82 - Source/relay/TourGuide/Quests/Memories.ash | 106 - Source/relay/TourGuide/Quests/Nemesis.ash | 868 - .../relay/TourGuide/Quests/Old Landfill.ash | 74 - Source/relay/TourGuide/Quests/Pirate.ash | 387 - .../relay/TourGuide/Quests/Quest import.ash | 36 - Source/relay/TourGuide/Quests/Sea.ash | 731 - Source/relay/TourGuide/Quests/Space Elves.ash | 122 - .../Quests/Spookyraven Lights Out.ash | 212 - Source/relay/TourGuide/Quests/Subject 37.ash | 113 - Source/relay/TourGuide/Quests/Untinker.ash | 59 - .../relay/TourGuide/Quests/White Citadel.ash | 247 - .../relay/TourGuide/Quests/Wizard of Ego.ash | 139 - Source/relay/TourGuide/Sections/API.ash | 199 - Source/relay/TourGuide/Sections/CSS.ash | 141 - .../relay/TourGuide/Sections/Checklists.ash | 299 - .../TourGuide/Sections/Contextual Menu.ash | 79 - Source/relay/TourGuide/Sections/Data.ash | 13 - Source/relay/TourGuide/Sections/Globals.ash | 69 - .../TourGuide/Sections/Location Bar Popup.ash | 1415 - .../relay/TourGuide/Sections/Location Bar.ash | 625 - Source/relay/TourGuide/Sections/Messages.ash | 977 - .../TourGuide/Sections/Navigation Bar.ash | 84 - Source/relay/TourGuide/Sections/Tests.ash | 215 - .../TourGuide/Sections/User Preferences.ash | 87 - Source/relay/TourGuide/Sets.ash | 49 - .../relay/TourGuide/Sets/Active Banishes.ash | 206 - Source/relay/TourGuide/Sets/Aftercore.ash | 310 - Source/relay/TourGuide/Sets/Area Unlocks.ash | 187 - .../TourGuide/Sets/Bounty Hunter Hunter.ash | 260 - Source/relay/TourGuide/Sets/Buff Upkeep.ash | 100 - .../TourGuide/Sets/Calculate Universe.ash | 149 - Source/relay/TourGuide/Sets/Classes.ash | 233 - .../relay/TourGuide/Sets/Copied Monsters.ash | 520 - Source/relay/TourGuide/Sets/Council.ash | 36 - Source/relay/TourGuide/Sets/Counters.ash | 363 - .../relay/TourGuide/Sets/Crepe Parachute.ash | 15 - Source/relay/TourGuide/Sets/Daily Dungeon.ash | 276 - Source/relay/TourGuide/Sets/Demon Summon.ash | 79 - Source/relay/TourGuide/Sets/Dispensary.ash | 49 - .../relay/TourGuide/Sets/Dungeons of Doom.ash | 67 - Source/relay/TourGuide/Sets/Equipment.ash | 72 - Source/relay/TourGuide/Sets/Events.ash | 45 - Source/relay/TourGuide/Sets/Familiars.ash | 510 - Source/relay/TourGuide/Sets/Fax.ash | 312 - Source/relay/TourGuide/Sets/Florist.ash | 82 - .../relay/TourGuide/Sets/Hole in the Sky.ash | 303 - Source/relay/TourGuide/Sets/Holidays.ash | 94 - Source/relay/TourGuide/Sets/Level 13 Door.ash | 17 - Source/relay/TourGuide/Sets/Lucky.ash | 145 - Source/relay/TourGuide/Sets/Misc Items.ash | 1263 - Source/relay/TourGuide/Sets/Misc Tasks.ash | 267 - Source/relay/TourGuide/Sets/Monorail.ash | 19 - .../TourGuide/Sets/Old Level 9 quest.ash | 61 - Source/relay/TourGuide/Sets/Olfaction.ash | 120 - Source/relay/TourGuide/Sets/PVP.ash | 542 - Source/relay/TourGuide/Sets/Powerlevel.ash | 140 - Source/relay/TourGuide/Sets/Pulverise.ash | 212 - Source/relay/TourGuide/Sets/Reminders.ash | 407 - Source/relay/TourGuide/Sets/Sets import.ash | 36 - Source/relay/TourGuide/Sets/Skills.ash | 289 - Source/relay/TourGuide/Sets/Sneaks.ash | 395 - .../relay/TourGuide/Sets/Sweet Synthesis.ash | 320 - Source/relay/TourGuide/Settings.ash | 48 - Source/relay/TourGuide/State.ash | 962 - Source/relay/TourGuide/Strategy.ash | 17 - .../Support/AdventurePHP Locations.ash | 80 - Source/relay/TourGuide/Support/Banishers.ash | 271 - Source/relay/TourGuide/Support/Campground.ash | 154 - Source/relay/TourGuide/Support/Checklist.ash | 849 - .../relay/TourGuide/Support/Cornucopias.ash | 27 - .../TourGuide/Support/Cost To Acquire.ash | 110 - Source/relay/TourGuide/Support/Counter.ash | 699 - .../Support/Equipment Requirement.ash | 61 - Source/relay/TourGuide/Support/Error.ash | 31 - .../relay/TourGuide/Support/Fold Groups.ash | 31 - Source/relay/TourGuide/Support/HTML.ash | 190 - Source/relay/TourGuide/Support/Holiday.ash | 85 - Source/relay/TourGuide/Support/IOTMs.ash | 320 - .../relay/TourGuide/Support/Ingredients.ash | 308 - .../relay/TourGuide/Support/Item Filter.ash | 114 - Source/relay/TourGuide/Support/KOLImage.ash | 777 - Source/relay/TourGuide/Support/Library 2.ash | 398 - Source/relay/TourGuide/Support/Library.ash | 1721 - Source/relay/TourGuide/Support/List.ash | 1109 - .../TourGuide/Support/Location Choice.ash | 75 - .../TourGuide/Support/LocationAvailable.ash | 1197 - Source/relay/TourGuide/Support/Math.ash | 395 - Source/relay/TourGuide/Support/Modifiers.ash | 111 - .../relay/TourGuide/Support/Monster Data.ash | 133 - .../relay/TourGuide/Support/Numberology.ash | 120 - Source/relay/TourGuide/Support/Page.ash | 434 - .../TourGuide/Support/Passive Damage.ash | 271 - .../relay/TourGuide/Support/Spell Damage.ash | 192 - Source/relay/TourGuide/Support/Statics 2.ash | 17 - Source/relay/TourGuide/Support/Statics.ash | 403 - Source/relay/TourGuide/Support/Strings.ash | 367 - Source/relay/TourGuide/Tasks.ash | 21 - Source/relay/relay_TourGuide.ash | 9 - documentation/develop.md | 7 - documentation/history.md | 25 - documentation/scope.md | 33 - documentation/usage.md | 73 - .../relay => relay}/TourGuide/TourGuide.js | 0 relay/relay_TourGuide.ash | 61399 ++++++++++++++++ 314 files changed, 61399 insertions(+), 63253 deletions(-) delete mode 100644 .editorconfig delete mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml delete mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml delete mode 100644 .github/PULL_REQUEST_TEMPLATE/pull_request_template.md delete mode 100644 .github/workflows/main.yml delete mode 100644 .github/workflows/sync-to-testing-branch.yml delete mode 100644 Bundle_ASH_script.py delete mode 100644 LICENSE delete mode 100644 Matrix/glyphs.png delete mode 100644 Matrix/matrix.html delete mode 100644 Matrix/matrix.js delete mode 100644 README.md delete mode 100644 Source/relay/TourGuide/Daily Resources.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2009/Sugar.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2010/Crown of Thrones.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2011/Plastic Vampire Fangs.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2013/Psychoanalytic.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2013/Smithsness.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2014/DNA.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2014/Grimstone.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2014/Speakeasy.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2014/SpringBreakBeach.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2015/Barrel God.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2015/Deck of Every Card.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2015/Haunted Doghouse.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2015/Machine Elf.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2015/Mayo Clinic.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Clan Floundry.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Detective School.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Gingerbread City.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Intergnat.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/LT&T Cowboy Boots.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Protonic Accelerator Pack.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Snojo.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Source Terminal.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Telegraph Office.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Thanksgarden.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Time-Spinner.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2016/Witchess.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2017/Asdon Martin.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2017/GenieBottle.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2017/KGBriefcase.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2017/Meteor Lore.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2017/New You.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2017/Portable Pantogram.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2017/Space Jellyfish.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2017/Spacegate.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2017/Tunnel of Love.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2017/XO Skeleton.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2018/Bastille Battalion.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2018/BoomBox.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2018/Boxing Daycare.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2018/Cat Burglar.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2018/Garbage Tote.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2018/God Lobster.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2018/Latte.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2018/Neverending Party.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2018/Voting Booth.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2018/Zatara.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/Beach Comb.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/Eight Days a Week Pills.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/Getaway Campsite.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/Kramco Sausage-o-Matic.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/Lil Doctor Bag.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/May Saber.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/Pizza Cube.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/Pocket Professor.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/Red Nosed Snapper.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/Rune Spoon.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2019/Vampire Cloak.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2020/Better Shrooms and Gardens.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2020/Bird-a-Day Calendar.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2020/Box O Ghosts.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2020/Cargo Cultist Shorts.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2020/Comprehensive Cartography.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2020/Guzzlr.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2020/Melodramedary.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2020/Powerful Glove.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2020/Spinmaster Lathe.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2020/Superhero Cape.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Backup Camera.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Cold Medicine Cabinet.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Daylight Shavings Helmet.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Emotion Chip.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Familiar Scrapbook.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Industrial Fire Extinguisher.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Miniature Crystal Ball.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Potted Power Plant.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Short Order Cook.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Underground Fireworks Shop.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2021/Vampire Vintner.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Combat Lover Locket.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Cookbookbat.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Cursed Magnifying Glass.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Designer Sweatpants.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Grey Goose.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/June Cleaver.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Jurassic Parka.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Mayday Supply Package.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Model Train Set.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Oliver's Place.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Tiny Stillsuit.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2022/Unbreakable Umbrella.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/2002 Catalog.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/A Guide to Burning Leaves.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/August Scepter.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/Book of Facts.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/Candy Cane Sword Cane.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/Cincho de Mayo.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/Closed Circuit Pay Phone.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/Cursed Monkey Paw.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/Jill of all Trades.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/Patriotic Eagle.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/Rock Garden.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2023/SIT Course Certificate.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/Apriling Band Helmet.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/Chest Mimic.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/Everfull Dart Holster.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/Mayam Calendar.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/Mini Kiwi.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/Peace Turkey.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/Roman Candelabra.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/Sept-Ember Censer.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/Spring Shoes.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/TakerSpace.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/VIP Photobooth.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2024/bat wings.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2025/April Shower Thoughts Calendar.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2025/Cooler Yeti.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2025/CyberRealm.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2025/Leprecondo.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2025/McHugeLarge Ski Set.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2025/Peridot.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/Items of the Month import.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/Misc/Gardens.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/Misc/Horsery.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/Misc/Libram.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/Misc/Tomes.ash delete mode 100644 Source/relay/TourGuide/Items of the Month/Time-Twitching Tower/Tea Tree.ash delete mode 100644 Source/relay/TourGuide/Limit Mode/Batfellow State.ash delete mode 100644 Source/relay/TourGuide/Limit Mode/Batfellow.ash delete mode 100644 Source/relay/TourGuide/Limit Mode/Spelunking.ash delete mode 100644 Source/relay/TourGuide/Main.ash delete mode 100644 Source/relay/TourGuide/Missing Items.ash delete mode 100644 Source/relay/TourGuide/Paths/Actually Ed the Undying.ash delete mode 100644 Source/relay/TourGuide/Paths/Avatar of Jarlsberg.ash delete mode 100644 Source/relay/TourGuide/Paths/Avatar of Shadows over Loathing.ash delete mode 100644 Source/relay/TourGuide/Paths/Avatar of Sneaky Pete.ash delete mode 100644 Source/relay/TourGuide/Paths/Avatar of West of Loathing.ash delete mode 100644 Source/relay/TourGuide/Paths/Bad Moon.ash delete mode 100644 Source/relay/TourGuide/Paths/Bugbear Invasion.ash delete mode 100644 Source/relay/TourGuide/Paths/Community Service.ash delete mode 100644 Source/relay/TourGuide/Paths/Dark Gift.ash delete mode 100644 Source/relay/TourGuide/Paths/Explosions.ash delete mode 100644 Source/relay/TourGuide/Paths/Fall of the Dinosaurs.ash delete mode 100644 Source/relay/TourGuide/Paths/G-Lover.ash delete mode 100644 Source/relay/TourGuide/Paths/Gelatinous Noob.ash delete mode 100644 Source/relay/TourGuide/Paths/Grey Goo.ash delete mode 100644 Source/relay/TourGuide/Paths/Heavy Rains.ash delete mode 100644 Source/relay/TourGuide/Paths/KOLHS.ash delete mode 100644 Source/relay/TourGuide/Paths/Legacy of Loathing.ash delete mode 100644 Source/relay/TourGuide/Paths/License to Adventure.ash delete mode 100644 Source/relay/TourGuide/Paths/Low Key.ash delete mode 100644 Source/relay/TourGuide/Paths/Nuclear Autumn.ash delete mode 100644 Source/relay/TourGuide/Paths/Paths import.ash delete mode 100644 Source/relay/TourGuide/Paths/The Source.ash delete mode 100644 Source/relay/TourGuide/Paths/Way of the Surprising Fist.ash delete mode 100644 Source/relay/TourGuide/Paths/WereProfessor.ash delete mode 100644 Source/relay/TourGuide/Paths/Zombie Slayer.ash delete mode 100644 Source/relay/TourGuide/Plants.ash delete mode 100644 Source/relay/TourGuide/Pulls.ash delete mode 100644 Source/relay/TourGuide/QuestState.ash delete mode 100644 Source/relay/TourGuide/Quests.ash delete mode 100644 Source/relay/TourGuide/Quests/8-bit Realm.ash delete mode 100644 Source/relay/TourGuide/Quests/Airport.ash delete mode 100644 Source/relay/TourGuide/Quests/Artist.ash delete mode 100644 Source/relay/TourGuide/Quests/Azazel.ash delete mode 100644 Source/relay/TourGuide/Quests/Felonia.ash delete mode 100644 Source/relay/TourGuide/Quests/Guild.ash delete mode 100644 Source/relay/TourGuide/Quests/Intergalaktik.ash delete mode 100644 Source/relay/TourGuide/Quests/Legendary Beat.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 10.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 11 - Copperhead.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 11 - Desert.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 11 - Hidden City.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 11 - Manor.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 11 - Palindome.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 11 - Pyramid.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 11.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 12.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 13.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 2.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 3.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 4.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 5.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 6.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 7.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 8.ash delete mode 100644 Source/relay/TourGuide/Quests/Level 9.ash delete mode 100644 Source/relay/TourGuide/Quests/Madness Bakery.ash delete mode 100644 Source/relay/TourGuide/Quests/Manor.ash delete mode 100644 Source/relay/TourGuide/Quests/Marty.ash delete mode 100644 Source/relay/TourGuide/Quests/Meatsmith.ash delete mode 100644 Source/relay/TourGuide/Quests/Memories.ash delete mode 100644 Source/relay/TourGuide/Quests/Nemesis.ash delete mode 100644 Source/relay/TourGuide/Quests/Old Landfill.ash delete mode 100644 Source/relay/TourGuide/Quests/Pirate.ash delete mode 100644 Source/relay/TourGuide/Quests/Quest import.ash delete mode 100644 Source/relay/TourGuide/Quests/Sea.ash delete mode 100644 Source/relay/TourGuide/Quests/Space Elves.ash delete mode 100644 Source/relay/TourGuide/Quests/Spookyraven Lights Out.ash delete mode 100644 Source/relay/TourGuide/Quests/Subject 37.ash delete mode 100644 Source/relay/TourGuide/Quests/Untinker.ash delete mode 100644 Source/relay/TourGuide/Quests/White Citadel.ash delete mode 100644 Source/relay/TourGuide/Quests/Wizard of Ego.ash delete mode 100644 Source/relay/TourGuide/Sections/API.ash delete mode 100644 Source/relay/TourGuide/Sections/CSS.ash delete mode 100644 Source/relay/TourGuide/Sections/Checklists.ash delete mode 100644 Source/relay/TourGuide/Sections/Contextual Menu.ash delete mode 100644 Source/relay/TourGuide/Sections/Data.ash delete mode 100644 Source/relay/TourGuide/Sections/Globals.ash delete mode 100644 Source/relay/TourGuide/Sections/Location Bar Popup.ash delete mode 100644 Source/relay/TourGuide/Sections/Location Bar.ash delete mode 100644 Source/relay/TourGuide/Sections/Messages.ash delete mode 100644 Source/relay/TourGuide/Sections/Navigation Bar.ash delete mode 100644 Source/relay/TourGuide/Sections/Tests.ash delete mode 100644 Source/relay/TourGuide/Sections/User Preferences.ash delete mode 100644 Source/relay/TourGuide/Sets.ash delete mode 100644 Source/relay/TourGuide/Sets/Active Banishes.ash delete mode 100644 Source/relay/TourGuide/Sets/Aftercore.ash delete mode 100644 Source/relay/TourGuide/Sets/Area Unlocks.ash delete mode 100644 Source/relay/TourGuide/Sets/Bounty Hunter Hunter.ash delete mode 100644 Source/relay/TourGuide/Sets/Buff Upkeep.ash delete mode 100644 Source/relay/TourGuide/Sets/Calculate Universe.ash delete mode 100644 Source/relay/TourGuide/Sets/Classes.ash delete mode 100644 Source/relay/TourGuide/Sets/Copied Monsters.ash delete mode 100644 Source/relay/TourGuide/Sets/Council.ash delete mode 100644 Source/relay/TourGuide/Sets/Counters.ash delete mode 100644 Source/relay/TourGuide/Sets/Crepe Parachute.ash delete mode 100644 Source/relay/TourGuide/Sets/Daily Dungeon.ash delete mode 100644 Source/relay/TourGuide/Sets/Demon Summon.ash delete mode 100644 Source/relay/TourGuide/Sets/Dispensary.ash delete mode 100644 Source/relay/TourGuide/Sets/Dungeons of Doom.ash delete mode 100644 Source/relay/TourGuide/Sets/Equipment.ash delete mode 100644 Source/relay/TourGuide/Sets/Events.ash delete mode 100644 Source/relay/TourGuide/Sets/Familiars.ash delete mode 100644 Source/relay/TourGuide/Sets/Fax.ash delete mode 100644 Source/relay/TourGuide/Sets/Florist.ash delete mode 100644 Source/relay/TourGuide/Sets/Hole in the Sky.ash delete mode 100644 Source/relay/TourGuide/Sets/Holidays.ash delete mode 100644 Source/relay/TourGuide/Sets/Level 13 Door.ash delete mode 100644 Source/relay/TourGuide/Sets/Lucky.ash delete mode 100644 Source/relay/TourGuide/Sets/Misc Items.ash delete mode 100644 Source/relay/TourGuide/Sets/Misc Tasks.ash delete mode 100644 Source/relay/TourGuide/Sets/Monorail.ash delete mode 100644 Source/relay/TourGuide/Sets/Old Level 9 quest.ash delete mode 100644 Source/relay/TourGuide/Sets/Olfaction.ash delete mode 100644 Source/relay/TourGuide/Sets/PVP.ash delete mode 100644 Source/relay/TourGuide/Sets/Powerlevel.ash delete mode 100644 Source/relay/TourGuide/Sets/Pulverise.ash delete mode 100644 Source/relay/TourGuide/Sets/Reminders.ash delete mode 100644 Source/relay/TourGuide/Sets/Sets import.ash delete mode 100644 Source/relay/TourGuide/Sets/Skills.ash delete mode 100644 Source/relay/TourGuide/Sets/Sneaks.ash delete mode 100644 Source/relay/TourGuide/Sets/Sweet Synthesis.ash delete mode 100644 Source/relay/TourGuide/Settings.ash delete mode 100644 Source/relay/TourGuide/State.ash delete mode 100644 Source/relay/TourGuide/Strategy.ash delete mode 100644 Source/relay/TourGuide/Support/AdventurePHP Locations.ash delete mode 100644 Source/relay/TourGuide/Support/Banishers.ash delete mode 100644 Source/relay/TourGuide/Support/Campground.ash delete mode 100644 Source/relay/TourGuide/Support/Checklist.ash delete mode 100644 Source/relay/TourGuide/Support/Cornucopias.ash delete mode 100644 Source/relay/TourGuide/Support/Cost To Acquire.ash delete mode 100644 Source/relay/TourGuide/Support/Counter.ash delete mode 100644 Source/relay/TourGuide/Support/Equipment Requirement.ash delete mode 100644 Source/relay/TourGuide/Support/Error.ash delete mode 100644 Source/relay/TourGuide/Support/Fold Groups.ash delete mode 100644 Source/relay/TourGuide/Support/HTML.ash delete mode 100644 Source/relay/TourGuide/Support/Holiday.ash delete mode 100644 Source/relay/TourGuide/Support/IOTMs.ash delete mode 100644 Source/relay/TourGuide/Support/Ingredients.ash delete mode 100644 Source/relay/TourGuide/Support/Item Filter.ash delete mode 100644 Source/relay/TourGuide/Support/KOLImage.ash delete mode 100644 Source/relay/TourGuide/Support/Library 2.ash delete mode 100644 Source/relay/TourGuide/Support/Library.ash delete mode 100644 Source/relay/TourGuide/Support/List.ash delete mode 100644 Source/relay/TourGuide/Support/Location Choice.ash delete mode 100644 Source/relay/TourGuide/Support/LocationAvailable.ash delete mode 100644 Source/relay/TourGuide/Support/Math.ash delete mode 100644 Source/relay/TourGuide/Support/Modifiers.ash delete mode 100644 Source/relay/TourGuide/Support/Monster Data.ash delete mode 100644 Source/relay/TourGuide/Support/Numberology.ash delete mode 100644 Source/relay/TourGuide/Support/Page.ash delete mode 100644 Source/relay/TourGuide/Support/Passive Damage.ash delete mode 100644 Source/relay/TourGuide/Support/Spell Damage.ash delete mode 100644 Source/relay/TourGuide/Support/Statics 2.ash delete mode 100644 Source/relay/TourGuide/Support/Statics.ash delete mode 100644 Source/relay/TourGuide/Support/Strings.ash delete mode 100644 Source/relay/TourGuide/Tasks.ash delete mode 100644 Source/relay/relay_TourGuide.ash delete mode 100644 documentation/develop.md delete mode 100644 documentation/history.md delete mode 100644 documentation/scope.md delete mode 100644 documentation/usage.md rename {Source/relay => relay}/TourGuide/TourGuide.js (100%) create mode 100644 relay/relay_TourGuide.ash diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index a7b5d23d..00000000 --- a/.editorconfig +++ /dev/null @@ -1,11 +0,0 @@ -# EditorConfig is awesome: https://EditorConfig.org -root = true - -[*] -end_of_line = lf -insert_final_newline = true -charset = utf-8 - -[*.ash] -indent_style = space -indent_size = 4 diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml deleted file mode 100644 index ae875c5b..00000000 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: "Bug Report" -description: "Report a bug in TourGuide" -title: "[Bug]: " -labels: bug -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out a bug report! As a heads up -- if your Mafia or TourGuide version is out of date when posting this issue, it may already be resolved and your issue may be closed. Please keep your things up to date! - - type: textarea - id: whats-the-bug - attributes: - label: "What's the bug?" - description: Tell us the bug you encountered. Please include an account of the incorrect behavior, as well as what you would deem as the "correct" behavior. - placeholder: Tell us what you see! - - type: dropdown - id: user-state - attributes: - label: Account State - description: Were you in Standard or Unrestricted? - options: - - "Standard (In-Run)" - - "Unrestricted (In-Run)" - - "Aftercore" - - type: input - id: classpath - attributes: - label: In-Game Path & Class - description: Please put your in-game path & class. - placeholder: ex. "Seal Clubber in Grey Goo" - - type: input - id: commit-version - attributes: - label: TourGuide Commit - description: Please paste your TourGuide Commit hash, via `ash git_info("tourguide")`. - placeholder: ex. "925e68c5af96edd52b482887aa07758c5284dc47" diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index d0a0f31a..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: "Feature Request" -description: "Request a new feature for TourGuide" -title: "[Feature]: " -labels: enhancement -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out a feature request! Due to limited developer resources, we cannot guarantee we will fulfill your request at major speed. But we'll do our best! - - type: textarea - id: whats-the-request - attributes: - label: "What's the request?" - description: "Tell us the basic behavior that TourGuide doesn't currently do that you'd love to see. The more detail you can give, the better -- any similar pieces of the codebase, any tiles that are similar to a newly proposed tile, the reasons why this would improve TourGuide, et cetera." - placeholder: Tell us what you want to see! - - type: dropdown - id: user-state - attributes: - label: Account State - description: "Is this feature most helpful for a specific account state?" - options: - - "Standard (In-Run)" - - "Unrestricted (In-Run)" - - "Aftercore" - - "All account states would benefit equally!" - - type: input - id: commit-version - attributes: - label: Your current TourGuide version - description: Please paste your current TourGuide Commit hash, via `ash git_info("tourguide")` in the CLI. - placeholder: ex. "925e68c5af96edd52b482887aa07758c5284dc47" diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md deleted file mode 100644 index 001f443a..00000000 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ /dev/null @@ -1,11 +0,0 @@ -# Description -Please include a summary of the change. Pull requests should always be against the [main branch](https://github.com/loathers/tourguide/tree/main). If it addresses a particular issue, please put the issue numbers below (see also [Closing Issues Using Keywords](https://help.github.com/en/articles/closing-issues-using-keywords)). - -## How Has This Been Tested? -If you did any particular tests, or have particular tests you would like to do but cannot (e.g. need to test with an expensive item you dont have access to) please mention that here. A screenshot of any new tiles would be great, also. - -## Checklist: - -- [ ] I have performed a self-review of my own code. -- [ ] I have commented my code, particularly in hard-to-understand areas. -- [ ] I have based my pull request against the [main branch](https://github.com/loathers/autoscend/tree/main) or have a good reason not to. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 21bf064a..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,424 +0,0 @@ -name: bundle ASH script(s), and push to new branch -# By https://github.com/fredg1 - -# USER MANUAL -# This workflow should run by itself without the need for any change. -# It's, however, currently tailored to TourGuide. -# If you wish to change its behavior (change the name of the target branch, where it places the result in it, or if you wish to use it on a folder + script other than Source + relay/TourGuide.ash), all you need to modify should be in the "env" section down below. -# I'm working on making this its own action that can be called as many times as needed, on any script, with as much customization as possible, but github is still not done on the feature I'd need for that :/ - -env: - # Branch to checkout under ./target_branch/ . If contains {0}, {0} will be replaced by the source branch's name. - # (doesn't need to be the name of an existing branch. Will create one if needed (will be a copy of the source branch)) - # examples: 'Pre-Release', 'Bundled-{0}', 'my_{0}_2.0' or just '{0}' (not the best idea, though...) - TARGET_NAME: 'Bundled-{0}' - - - - # The path to take (folders to go through) to reach the "mafia folder" in both branches. - # RELATIVE paths only (relative to the root of the repository). - # Empty string if it is reachable from the root. - - # Only its content will be transferred to - SOURCE_PATH_TO_MAFIA: 'Source' - - # If this folder already exists on the target branch, IT'S PREVIOUS CONTENT WILL BE ERASED. - # Stuff outside of it won't. - TARGET_PATH_TO_MAFIA: '' - - - - # comma-separated list of (relative) path and name of the ASH scripts you want to bundle, and their new names and (relative) destinations. - # Paths need to be relative to the "mafia folder". - # Any .ash script not in this list won't be transferred, so if you have scripts that don't have imports, but want them in the result, include them here anyway - - # The scripts to bundle - ASH_SCRIPT_SOURCES: 'relay/relay_TourGuide.ash' - # Their (RESPECTIVE; order matters) destinations - ASH_SCRIPT_DESTINATIONS: 'relay/relay_TourGuide.ash' - - - -on: - workflow_dispatch: - # for more info about this if you want to modify it, see - # https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestbranchestags - # and - # https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#onpushpull_requestpaths - push: - paths: - #- '${{ SOURCE_PATH_TO_MAFIA }}/**' # it's impossible to query env. variables at this point, sorry :( - - '**' - - '!.github/**' # security measure: doesn't trigger if anything in .github was changed (such as the creation, modification or deletion of this very file) - - - -# Anything past this point shouldn't need to be modified. - -jobs: - build: - runs-on: windows-latest - - steps: - - name: setup Python - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - - name: Get branch name - uses: nelonoel/branch-name@v1.0.1 - - # Checkout referrer (source) under ./source_branch/ - - name: checkout current branch - uses: actions/checkout@v2 - with: - path: ./source_branch - - - # Parse wanted target name, then checkout under ./target_branch/ - - name: set desired target branch - id: set-target - shell: python - run: | - source = '${{ env.BRANCH_NAME }}' - target = '${{ env.TARGET_NAME }}' - - if target == source: - pass - elif target == '': - target = 'Bundled-' + source - elif '{0}' in target: - target = target.format( source ) - - print(f'::set-output name=target-branch::{target}') - - - name: checkout target branch - id: target_get - uses: actions/checkout@v2 - continue-on-error: true - with: - ref: ${{ steps.set-target.outputs.target-branch }} - path: ./target_branch - persist-credentials: false - fetch-depth: 0 - - # target branch doesn't exist; create it - - name: create target branch - id: target_create - if: ${{ steps.target_get.outcome == 'failure' }} - uses: peterjgrainger/action-create-branch@v3.0.0 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - branch: ${{ steps.set-target.outputs.target-branch }} - - # NOW checkout the newly-made target branch - - name: checkout created target branch - id: target_get_created - if: ${{ steps.target_create.outcome == 'success' }} - uses: actions/checkout@v2 - with: - ref: ${{ steps.set-target.outputs.target-branch }} - path: ./target_branch - persist-credentials: false - fetch-depth: 0 - - # If this branch needed to be created, assume the user doesn't want to have this workflow trigger in it - # this was way too much work for something so situational/niche... X_X - - name: get workflow path - id: get-workflow-path - if: ${{ steps.target_get_created.outcome == 'success' }} - shell: pwsh - run: | - $Header = @{"Accept" = "application/vnd.github.v3+json"} - $uri = "https://api.github.com/repos/${{ github.repository }}/actions/workflows" - $Workflows = Invoke-RestMethod -Method GET -Header $Header -uri $uri - Foreach ($workflow in $Workflows.workflows) - { - if ( $workflow.path -eq "${{ github.workflow }}" -or $workflow.name -eq "${{ github.workflow }}" ) - { - $workflow_path = $workflow.path - echo "::set-output name=workflow-path::$workflow_path" - break - } - } - - name: don't carry workflow - if: ${{ steps.get-workflow-path.outcome == 'success' }} - working-directory: ./target_branch - shell: python - run: | - import os - - workflow_file = '${{ steps.get-workflow-path.outputs.workflow-path }}' - new_branch_to_exclude = '${{ steps.set-target.outputs.target-branch }}' - - - def removeComment(line: str, start = 0): - comment_start = line.find('#', start) - if comment_start == -1: - return line - else: - if line[comment_start - 1] == '\\': - removeComment( line, comment_start + 1 ) - else: - return line[:comment_start] - - - extra_line_separator_characters = len( os.linesep ) - 1 # may mess us up when we manually move the pointer on Windows (which is \r\n , 2 characters) - if os.path.exists( workflow_file ): - with open(workflow_file, mode='r+', encoding='UTF-8') as f: - in_event_trigger_section = False # whether we reached "on:". Never set back to False; we exit the loop instead - in_push_event_trigger = False # whether we reached "push:", and if we're still in it - push_event_trigger_indentation = 0 # the indentation of the "push:" block. Used to check when to set in_push_event_trigger back to False, and in case the push: block ends up being empty, as a backup of indentation_after_push - push_event_trigger_location = 0 # pointer location after the "push:" block. Used in case the push: block ends up being empty - indentation_after_push = 0 # the indentation of the "branches:"/"branches-ignore:" block (or, if we don't see it, the first block inside of "push:" that we see). Used to tell when we left the branches:/branches-ignore: block, and, if that block didn't end up being here, the indentation we'll use to MAKE said block - found_branches = False # which, of branches or branches-ignore, we found - found_branches_ignore = False # which, of branches or branches-ignore, we found - branches_start_location = 0 # pointer location after the "branches:" or "branches-ignore:" block (currently unused) - branches_end_location = None # furthest we got the pointer while in_branches was True. We want to add something right after that - branches_indentation = 0 # by how much the user indented what's IN their branches:/branches-ignore: scope. They all need the same indentation - in_branches = False # whether we reached "branches:" or "branches-ignore:", and if we're still in it - branches_lines = [] # list of lines interpreted as being under the "branches:" or "branches-ignore:" scope - while True: - line = f.readline() - # we're looking for: - #on: (event_trigger_section) - # [...] - # push: (push_event_trigger) - # [...] - # branches: - if line == '': - if in_branches: - branches_end_location = f.tell() - break # end of file - elif in_event_trigger_section: - # remove comments from the line - no_commented_line = removeComment( line ) - stripped_line = no_commented_line.lstrip() - current_indentation = len( no_commented_line ) - len( stripped_line ) - - if stripped_line == '': - if in_branches: - branches_lines.append( line ) - continue - - if in_push_event_trigger and current_indentation <= push_event_trigger_indentation: - in_push_event_trigger = False # we left that block - if in_branches and current_indentation <= indentation_after_push and (current_indentation < indentation_after_push or not stripped_line.startswith('-')): - in_branches = False - branches_end_location = f.tell() - ( len( line ) + extra_line_separator_characters ) - - if current_indentation == 0: - break # we left the event trigger section - - if stripped_line.startswith('push:') and ( push_event_trigger_indentation == 0 or current_indentation < push_event_trigger_indentation ): - in_push_event_trigger = True - push_event_trigger_indentation = current_indentation - push_event_trigger_location = f.tell() - # also reset all the other variables in case we previously set them in the wrong(???) "push:" block - indentation_after_push = 0 - found_branches = False - found_branches_ignore = False - branches_start_location = 0 - branches_end_location = None - branches_indentation = 0 - in_branches = False - branches_lines = [] - elif in_push_event_trigger: - if indentation_after_push == 0: - indentation_after_push = current_indentation # save this for later in case there's no "branches:" tag, and we need to add it ourselves - - if in_branches: - if stripped_line.startswith('-') and branches_indentation == 0: - branches_indentation = current_indentation - branches_lines.append( line ) - elif stripped_line.startswith('branches:'): - found_branches = True - branches_start_location = f.tell() - in_branches = True - indentation_after_push = current_indentation - elif stripped_line.startswith('branches-ignore:'): - found_branches_ignore = True - branches_start_location = f.tell() - in_branches = True - indentation_after_push = current_indentation - - elif line.startswith('on:'): - in_event_trigger_section = True - - - - if push_event_trigger_location > 0: # if it's just not there, don't bother creating it - rest_of_file = """""" - - if indentation_after_push == 0: # push: is empty - indentation_after_push = push_event_trigger_indentation * 2 - - if not found_branches and not found_branches_ignore: # need to create one ourselves - f.seek(push_event_trigger_location) - rest_of_file = f.read() - f.seek(push_event_trigger_location) - - most_recently_added_line = ''.rjust( indentation_after_push ) - most_recently_added_line += 'branches-ignore:\n' - most_recently_added_line += ''.rjust( indentation_after_push ) + "- '" - else: - # trim any lines at the end that are empty lines / only a comment - for x in range(len( branches_lines ), 0, -1): - branches_line = branches_lines[x-1] - if removeComment( branches_line ).lstrip() != '': - break - branches_lines.pop(x) - branches_end_location -= len( branches_line ) + extra_line_separator_characters - - f.seek( branches_end_location ) - rest_of_file = f.read() - f.seek( branches_end_location ) - - if branches_indentation == 0: - branches_indentation = indentation_after_push - - most_recently_added_line = ''.rjust( branches_indentation ) + "- '" - if found_branches: - most_recently_added_line += '!' - - most_recently_added_line += new_branch_to_exclude + "'\n" - f.write( most_recently_added_line ) - f.write( rest_of_file ) - - # Clean mafia folder in target branch - - name: clean target branch - shell: python - run: | - import os - import shutil - - target_base = os.path.join( 'target_branch', '${{ env.TARGET_PATH_TO_MAFIA }}' ) - if not os.path.exists( target_base ): - os.makedirs( target_base ) - - with os.scandir(target_base) as cur_dir: - for dir_entry in cur_dir: - if dir_entry.name != '.git': - path_to_entry = os.path.join(target_base, dir_entry.name) - if dir_entry.is_dir(follow_symlinks=False): - shutil.rmtree(path=path_to_entry) - else: - os.remove(path=path_to_entry) - - - - - name: checkout bundler - uses: actions/checkout@v2 - with: - repository: fredg1/ASH-bundler - path: bundler_branch - - - name: Forward bundle output to target branch - id: bundle-ASH - shell: python - run: | - import os - import sys - - sys.path.append( os.path.join( os.getcwd(), 'bundler_branch' ) ) - import Bundle_ASH_script - - - source_scripts = tuple( map(str, '${{ env.ASH_SCRIPT_SOURCES }}'.split(',') ) ) - destinations = tuple( map(str, '${{ env.ASH_SCRIPT_DESTINATIONS }}'.split(',') ) ) - - if len(source_scripts) != len(destinations): - raise Exception("ASH_SCRIPT_SOURCES and ASH_SCRIPT_DESTINATIONS aren't properly paired") - - imported_files = [] - bundled_files = [] - - for i in range( len( source_scripts ) ): - # The script that bundles the target script. - # First argument is the source script. - source_script = source_scripts[i] - - # Second argument is the path to reach the file to create/put the result in. - destination = os.path.join( 'target_branch', '${{ env.TARGET_PATH_TO_MAFIA }}', destinations[i] ) - - # Third argument (optional) is the path to reach the "mafia folder". - path_to_source_script = os.path.join( 'source_branch', '${{ env.SOURCE_PATH_TO_MAFIA }}' ) - - imports = Bundle_ASH_script.bundle_and_write( source_script, destination, path_to_source_script, allow_overwrite=True, return_imported_files=True ) - - imported_files.extend( imports ) - bundled_files.append( source_script ) - - print(f'::set-output name=imported_files::{imported_files}') - print(f'::set-output name=bundled_files::{bundled_files}') - - # copy any non-ASH file in target_branch - - name: Add non-ash in Source - id: parse-rest - shell: python - run: | - import os - - source_base = os.path.join('source_branch', '${{ env.SOURCE_PATH_TO_MAFIA }}') - target_base = os.path.join('target_branch', '${{ env.TARGET_PATH_TO_MAFIA }}') - - imported_files = ${{ steps.bundle-ASH.outputs.imported_files }} - bundled_files = ${{ steps.bundle-ASH.outputs.bundled_files }} - used_ASH_files = [] - for file in (imported_files + bundled_files): - used_ASH_files.append( os.path.normcase( os.path.normpath( file ) ) ) - unused_ASH_files = [] - - def parse_folder(cur_dir, current_path = ''): - for dir_entry in cur_dir: - if dir_entry.is_symlink(): - continue - if dir_entry.is_dir(): - next_path = os.path.join(current_path, dir_entry.name) - with os.scandir( os.path.join(source_base, next_path) ) as next_dir: - parse_folder(next_dir, next_path) - elif dir_entry.is_file(): - this_path = os.path.join(current_path, dir_entry.name) - if this_path.endswith('.ash'): - if used_ASH_files.count( os.path.normcase( os.path.normpath( this_path ) ) ) == 0: - unused_ASH_files.append( this_path ) - else: - print('Grabbing ' + this_path + ' ...') - - this_path_source = os.path.join(source_base, this_path) - this_path_target = os.path.join(target_base, this_path) - if os.path.exists( this_path_target ): - os.remove( this_path_target ) - os.renames(this_path_source, this_path_target) - - with os.scandir(source_base) as source_dir: - parse_folder(cur_dir = source_dir) - - if len( unused_ASH_files ) > 0: - print() - with open('artifact.txt', mode='x', encoding='UTF-8') as f: - message = str( len( unused_ASH_files ) ) + ' unused ASH file(s) (not imported by any of the scripts) found:' - print( message ) - f.write( message + '\n' ) - - for unused_file in unused_ASH_files: - message = ' ' + unused_file - print( message ) - f.write( message + '\n' ) - - - name: upload unused files message as artifact - uses: actions/upload-artifact@v4 - with: - name: unused files found - path: ./artifact.txt - if-no-files-found: ignore - - - name: commit changes to target - working-directory: ./target_branch - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add --all -v * - git commit -m "Import changes from ${{ github.ref }}" -a - git push "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" HEAD:refs/heads/${{ steps.set-target.outputs.target-branch }} --follow-tags --tags diff --git a/.github/workflows/sync-to-testing-branch.yml b/.github/workflows/sync-to-testing-branch.yml deleted file mode 100644 index da5b70a7..00000000 --- a/.github/workflows/sync-to-testing-branch.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Sync Bundled-main to testing - -on: - workflow_run: - workflows: [bundle ASH script(s), and push to new branch] - types: [completed] - workflow_dispatch: -permissions: - contents: write - -jobs: - sync-branch: - name: Sync Bundled-main to testing branch - runs-on: ubuntu-latest - steps: - # See https://github.com/connor-baer/action-sync-branch - # GitHub recommends pinning the SHA for security: - # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-third-party-actions - - name: Checkout - uses: actions/checkout@v3 - with: - ref: Bundled-main - - uses: connor-baer/action-sync-branch@b54ed9b2c68941d1b2974a7776dc8e3d7d14073c - with: - branch: testing - token: ${{ secrets.GITHUB_TOKEN }} - force: false diff --git a/Bundle_ASH_script.py b/Bundle_ASH_script.py deleted file mode 100644 index 7b3381b8..00000000 --- a/Bundle_ASH_script.py +++ /dev/null @@ -1,193 +0,0 @@ -import os - -# USER MANUAL -# -# to use, call "bundle_and_write()" with 2, 3 or 4 arguments. -# argument 1, path_to_file: path to the script you want to bundle. -# WARNING: this path needs to be RELATIVE TO THE MAFIA FOLDER. -# This means this value will always be either "relay/[...].ash" or "scripts/[...].ash" -# example: "relay/relay_TourGuide.ash" -# -# argument 2, path_to_result: path to the soon-to-be-created bundled file. -# Can either be absolute or relative. -# if relative, the reference is the folder in which THIS SCRIPT was ran. -# examples: "C:/Users/Keith/Documents/my_precious/my_script.ash" -# or "my_script.ash" -# -# argument 3, path_to_folder (optional): the path to REACH YOUR MAFIA FOLDER -# Can be either absolute or relative -# if you run this script from within your mafia folder, don't submit anything here. -# Otherwise, this is the folders that this script has to go through to reach your mafia folder -# (or whatever folder contains the "scripts" or "relay" folder(s) containing your scripts to import) -# -# argument 4, allow_overwrite (optional): True -# The capital T matters. -# A safety measure; whether or not you allow the script to act -# if path_to_result already exists. -# Not including it makes it default to False. -# -# -# -# EXAMPLE: -# - you run this program from your DESKTOP -# - you want to put the result in C:/Users/Me/Desktop/Sekrits/my_bundled_script.ash -# - your script is at C:/Users/Me/Desktop/Games/Actually_entertaining_games/KoLMafia/scripts/my_script.ash -# -# In the command line, you would do: -# C:\Users\Me\Desktop> py Bundle_ASH_script.bundle_and_write( path_to_file='scripts/my_script.ash' , path_to_result='Sekrits/my_bundled_script.ash' , path_to_folder='Games/Actually_entertaining_games/KoLMafia/' ) -# -# Another way to do it would be to put, at the end of this file: -# bundle_and_write( path_to_file='scripts/my_script.ash' , path_to_result='Sekrits/my_bundled_script.ash' , path_to_folder='Games/Actually_entertaining_games/KoLMafia/' ) -# and then run, in the command line: -# C:\Users\Me\Desktop> py Bundle_ASH_script -# -# -# bundle_and_write('relay/relay_TourGuide.ash', 'test.ash', 'Source') - -debug = False - -def bundle(path_to_file,path_to_folder,resulting_file = """""",imported_files = []): - with open( os.path.join( path_to_folder, path_to_file ), mode='r', encoding='UTF-8') as ash_file: - if debug: - print('Importing ' + path_to_file) - saw_presumed_start_of_code = False - saw_script = False - saw_notify = False - saw_since = False - - - currently_commented_out = False - - while True: - original_line = ash_file.readline() - if original_line == '': - break - - if saw_presumed_start_of_code: - resulting_file += original_line - continue - - if currently_commented_out: - comment_group_end = original_line.find('*/') - if comment_group_end != -1: - currently_commented_out = False - resulting_file += original_line[0:comment_group_end + 2] - original_line = original_line[comment_group_end + 2:len(original_line)] - else: - resulting_file += original_line - continue - - - def isolateComments(original_line,resulting_file): - new_line = original_line - part_to_append = '' - comment_group_start = original_line.find('/*') - comment_markers = [comment_group_start, original_line.find('#'), original_line.find('//')] - while -1 in comment_markers: - comment_markers.remove(-1) - if len(comment_markers) != 0: - beggining_of_comment = min(comment_markers) - #this assumes that something in the likes of 'import /*blablabla*/ "relay/text.ash";' isn't valid. - part_to_append = original_line[beggining_of_comment:len(original_line)] - new_line = original_line[0:beggining_of_comment] - - if beggining_of_comment == comment_group_start: - #we saw a /*, so check if the */ is in sight - comment_group_end = part_to_append[2:len(part_to_append)].find('*/') #the "[2:len(part_to_append)]" part is to avoid counting "/*/" as both start and end. - - if comment_group_end == -1: - #didn't find it, so remind that the future line starts by being commented out - currently_commented_out = True - elif comment_group_start == 0: - #we found it, and the comment is at the VERY START of our line - resulting_file += original_line[0:4+comment_group_end] - new_line = original_line[4+comment_group_end:len(original_line)] - new_line, part_to_append = isolateComments(new_line, resulting_file) - - return new_line, part_to_append - - - new_line, part_to_append = isolateComments(original_line, resulting_file) - line_was_import = False - - #search for "import" here - #order: script => notify => since => import(s) - new_line_stripped = new_line.lstrip() - if new_line_stripped == '': - resulting_file += new_line + part_to_append - continue - elif new_line_stripped.startswith('script ') and not saw_script: - saw_script = True - elif new_line_stripped.startswith('notify ') and not saw_notify: - saw_notify = True - elif new_line_stripped.startswith('since ') and not saw_since: - saw_since = True - elif new_line_stripped.startswith('import '): - line_was_import = True - #import - #import 'xxxx' - #import "xxxx" - #import xxxx; - start_index = 0 - end_index = -1 - import_command = new_line_stripped[6:len(new_line_stripped)].lstrip() - command_uses_quote = import_command.startswith("'") - command_uses_dbl_quotes = import_command.startswith('"') - command_uses_angle_brackets = import_command.startswith('<') - - if command_uses_quote: - start_index = 1 - end_index = import_command.find("'", 1) - elif command_uses_dbl_quotes: - start_index = 1 - end_index = import_command.find('"', 1) - elif command_uses_angle_brackets: - start_index = 1 - end_index = import_command.find('>', 1) - else: - end_index = import_command.find(';') - - if end_index == -1: - print('Potentially unreadable import statement over at file ' + path_to_file) - print('Full line was: ' + original_line) - print('Import argument seems to read: ' + import_command) - #try anyway - end_index = len(import_command) - - import_command = os.path.normpath( import_command[start_index:end_index] ) - #now import - if import_command not in imported_files: - imported_files.append(import_command) - resulting_file = bundle(import_command, path_to_folder, resulting_file, imported_files) - resulting_file += '\n' - - else: - saw_presumed_start_of_code = True - - if not line_was_import: - resulting_file += new_line - resulting_file += part_to_append - - if debug: - print('Finished import of ' + path_to_file) - return resulting_file - - -def bundle_and_write(path_to_file,path_to_result,path_to_folder = '',allow_overwrite=False,return_imported_files=False): - open_mode = 'x' - if allow_overwrite: - open_mode = 'w' - - path_to_target_dir = os.path.dirname(path_to_result) - if not path_to_target_dir == '' and not os.path.exists( path_to_target_dir ): - os.makedirs( path_to_target_dir ) - - imported_files = [] - - with open(path_to_result, mode=open_mode, encoding='UTF-8') as bundled_file: - bundled_file.write( bundle(path_to_file,path_to_folder,imported_files=imported_files) ) - - if return_imported_files: - return imported_files - -# bundle_and_write('relay/relay_TourGuide.ash', 'relay_TourGuide.ash', 'Source') \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index cf1ab25d..00000000 --- a/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/Matrix/glyphs.png b/Matrix/glyphs.png deleted file mode 100644 index 2dddd2584d67a342f4897801182f06678b433043..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16177 zcmV-1KhD63P)006HD0ssI2_4`7v002JtNkl0vzI4H5@BP3GU$c`_}Bytv_LRPu*CLxhFh5< z{*h0S64+v#tH@_ zSV)WQd;~ksBZo!UDEM#VrN5{b%%7NK+y88!F$&RBrHG+ga9{QLg9$_-5icNl8hwNVt8Hfgx7yG_=r-wN^sgXZjylc2E)!@VYO$Mb_!gS z!Ly$n)Wv+kZG(3mEw#-K`dDrCb^puyi5vBV5)xsVkKIVEs_VHD2;z3z{-VK1322mH z3McoOeQK<;jG+|Gu-i)}c7J7h0zHRun_68uhZ*2lCslJYF;E0A*m3t8Xe>}$ z9ilmh{izXH&{{MJ`I_|0kAo8I%RIie5s0uMRn|*@ukG(80vFE#{~Uj$Sn`6MMQR7hWPs+D}C2!X&21J(!*36Apb@9l$o1&OE> z{LMERN{mKF_W4JF#%487*9U&j-o0faU+hB(WZmbfY?0g?b)hOal;rXLMk0S$qaU!+ z-dZh4$3i7-n*|!hq3t1^pafqeCxsWw`ADsvi4uj8g8qma5237c*~laN>#j5%Gng#U z(6c&XoBcA-T)}Xlg6emkC?7(N+h(vsuvG#B+{~v!!`$03sC!Jzgulc-m)iw4+PiPq zD_RAf(pTst8KlAhXDw6wn_)zuu)wm_Z4>F4BQ#N0>{IoU76|PQO+M*O=`=d~vD6}H zVvx6kQPcDEa(j^l@7OlG*~4S|FEud!WdGfw`rj|v#EW__9|Ne<%ngH6lIbV z3lN|OXxo&Kz3G>O195g+DKLKFcIjgZCzAfNw}ic|8s7NJf*} zol)up?h0y!k1JX)o&BasYVuPB>8MnV>0P4`+)2`N3~;qZEQN|Al<)niQUlgD+rYXP zDG{GrcKFIbW2oZ0&@WgXXQKB6E~W|Ysx}X}#ja`CBlt-*`DYE`T~ zU7#VnL7q)SPhgc`8_ip>GE18jzYiC<*lHUbrq8@m3EU1YVMJWKLVj;l>LeVc zMo@^z-z>A&+j*;5JNYWHqcsN!9~!(W7@8zVOOm{qwOf;f))T{aU-wghV5pXEwAQzrioj+7O-5t2-*~#0EbstK;Y!QSQqzo-7 zcK4ms_odZdADivWk`viRedu~&TSU2S2EBAwj$gJ|-P*!TbqXeAosu9C{kXHbWr_79 zI;@tfb~-=ITb*sNfnglsj=o)@O;{_DMemLnPybHrWE3qH|xrB)l1=GdMX z1f$%f3Ux7ne%T)a6U)arR*o1a*eF;bC_n(A{QDJW$#H|i_SVId`aD^DGL*?HGc z09;_Abva#w|98B?z_CRFS;-L#sewMFLh|`>tVm+21X14@zTJVOVa}EnurbLp8U3|| zmhwHBqE^nKoqlLn(GOT8sG$&#_dmXdvsx?|llu_Qt6-~B*M(HVtQ=!CIiQByR4svn zUdfnp7C$v8;rp8erIrn*8L!jjrQj^3F^tVi8y2MiJ(nAvca;W&fz@q&OEqf z;zjrYYSp1uU!;a`wk{{C7NnriNjB&q?lHJHqlT;CySLn|tq+adXhEJ+GCJiw%aNVV zm}sQ^>5UnsG+RGqXl_I75G10>)BcF*oNsE2JEGed79VA%EJOqI$!DXML7QE4r1vQa zUdVKGrRX>!J7qP=my@J(o@Coh3eOt#2pNI(mQN*kyZ>sL;)EnbsOJUO$>yD+t}iK< z5A2mc+if~6xk@~_595(Tdrpd6bpB8I>%o6=m^B0ZyOLTh;^}86d~{JTgW<|0 zOW`j4g&Xoc%es$4nG>WVEV!*#E!PWs$VOX5Ie6q{hf;OO07hf&s_}A({Fg!Wu0fxr zBjhY@;xw}PY#xfJH##$HonAVeqbLxs(7@M76mxell$=E)r*mqWE|cY(RGMj(PzdN= zOlQwy1TT_bwZyM;0x;gql{N|Dh*sA^-LOsgQn^I~`8OS(IL9;e7Hv~Ct46BKizX8K zx#1&|g;81(-C?{e@M1LZSJmFlyDn4W`>rHcpsN{z?-9oc@dae)vh`8PotXlS@ARD2 z@ueNQR|;F=hqU3kGw6<-l~MRH_7X$aecAcFd}o#}G6Ol0~g9DgC~J-Nq5s zi*`tY3wGa?Z=yHv=6B+Vp*$10Rcu{C(fb0EnpW&k_Q~7;J7{Z^_pahU%K-U?@68+&|X{$t{PPmapFOdR$zUE*=6ep5-a6 z>4IVr~FwmONChy!ZvOC(mvDu;zqf$h%z-1HRJC#P=F z!yH4VQgyoVq(KUHx)Gs8UuB2dS+&iIkMvmu%4?nQ;FY3U@uv4WtPkHq9hTT7aFItT zZ;U63CoraegSD)ldX3JR#Y%}J67ZL{9J(0arT0`n{XG(_9YB4G)cPfMlU0fD8I@S@ z@3mq&<4M-c3A45I!zHB?(q-;rsejzi4L&2CD-eHVD)Sw8AVxp5If^Lfc?t7|v`9O_O@B|sVlLhfY z(@Ie`;50qJ#dLAU^N@2n{fGJ)BocyW&7Mm5pgmI-<*+d4fSniKk9qMusCUv^dE zJH(&Xzu+0g{T66_w)td`Q|4$hQ^Y^3gG(WXAo-Dds!i_6sdN4V!Z+i-eFxoG_tUJY z$l`X4g!c;)st|t7;5oIKJ^9k;*oMjW5zTj{NP_?w+M9E6Yt%DoUusjQq$|xc#hXW? zGl@EN41+tXPBuA~Y?i=9RqABg42HvtK|r&k%E+W3XwuPO=kn8~RltgNIXpJm!dHe1&})&JiwxUH=9 zRk4=Ek>DeA2%b1u^lMbzX}h0K%FA}Bwvd1S4^Y4ydJ#vIUsaouB*$tPFa{V0yx8?J zv!Kf;WKC>lZcp|C`lP=CWp|$ehLB2td{2uso|;d;rk2M1>7s}QnN^bOd#V)wF)r%r z8q$dPr%-eFA=)~I|4$bc{EVZ~{|WLa1Vir?RH%efUvvRI_zE(>%h^siGKB5)NRN>; z&+SS2I7b(@Gft#2lP*sa(?Ex5x2ABc98saBl!y;?CfPDv2UAXKuvPO+l?xjlY16%s=XP%2g2HAg zxt_Am34T%kKkc3QdzIDI{@G6;#6SW;LX<%UL=cccL{O}Czyae+!CDo>wxVEL2Q&}{ z5zv$Ygn}{{NK$L1*1^8`RqF88)@oIhBIIBC=KbW_r}t((d!Hv5ua_TK*SdPulP8Dg zoIGoDf*66} z=so1lZY@uDl$lfocToq=)_$d>99?-O*PD=7s#l&i=*f0tp*e*>=-3A#pljgt8(Zqh zP)x5y2jHPMxHvDJP~~g20Kwo}d0C@AQ_#@}u3awM;<}?{-)ZJyA4hz|IT=5JI8j#n z3l8``-DlD(Q#QtWp(CH-dr0HPp&h95a1-wk30u|Ao@{VQ{rQOh>1O`(DR(x?dRz1x zAT7Mo{QVD;o*woCAMSJ|%dqjSKE?VD(d1!-5cCd4a)w2EOY&XJ^meQ~+AE~}W%V`+ z%ZlijZMs_})4$cpCz77klj3Wi%@peFmE*M8SK8OgNmHuy{Wg=z6h}_!Jg)_>Ih*?H zZRpKJ1EYAi5?ix-P(+Py-tPvpaV^!lSp+xQUs~?EPAr1z`AG|yq>4<>MD+N=uiIo4II&T^G%Hs`}>6ZZx#-ca(PSD zx*y9-j2i9s_@3P$-sDWA@1!-dpHQ;)MFkCaY;iC(`K5GVbjvc5<6F%K8CYt0X`ON? zV>j*>J6J~)-9%ry>r0&MN{yYMf4oYW0km#1d3doH@=JKG-Pbe{I!+5qtiwP+Hi6fv zRbGN^h4L8=OXnvyWQ94e-BvB9QzH{dm(JIDnTARxIK_!v)20J#yiC%P96mLZ58F+F zbUb|94gJa6cRrfBo+{8L&v2P51WA>N{`IYy>0j|j3`H6ji)c9vHASCe*?*$*eOmAm zw0;8~PP(uHYod8DMSS)b@R$6>Gm2fy(DmS?Q zg#F8C6piHgk&3;T<4uO~-hrQ+%5$m=^Qy2jdPMU}WfcQ6$av6nM8-bx(-SFQc$0;z zi4pI|3QGjN{UNaV5yN<|rgzqw2cyK}1{S3Q&2?=62$h-DkxRGiC6M)lE+LfW$<{wDOrt zrQ+-U&Obq0WW)qqSd^rz``P-lv_cV_H>2k)^*s~w>d0`JLWi}wQ;-jT=lWUtiF~VL zmALlT<z?r-2X(tx*mB*0yh zj0aBv4B{t*<=!SZ`mb?9_ z%LfTl^7UXP+DhuHoWdb6vRj>`@}g@qF>Zf{KbJv7ck7H1Os#=tww@V}De%;PmRBUm zFO>&g;>dX+w0Nvp+^TfX^dnp^Q-U7#UHlGkFC6ho;-hEzq0Fi&m7iK%cL>LSk{Fbg z@gc!JFJlwfgFzB)ba7Y~Q8cAiY*hL@|H8YM{PY`&c=Aryk{17N-hT!c?+RK_rl`QJXV{>J;uW3p917&|ee&eeo{RB`xNLs{W%Vly_XQWb$UwL_TK&~Ym1guSfm zZ@F4hL+NKr3{3Plgu|dK;ypmcqZEqI=H_2C_pm1mN(f`6dMxR$K&HXg>@L}{lpbyL z&;f{y?udUYK}I~nS2~RZ&;H^RM@AEr-FDFmkKe20rwjOX?HP>a$+#U%&%Dqj zcRgEw#sQbQyhD8_@t$zt$rl*jc_DQWBZ!TQOK-QI<@>EXSK4u{SHAK81E~PeK1qqo z#bp?e?Q^s|)6LXM9>7f$@yk3zfU^#viT0FoH{K(0{FN($^W~kny6vD0|;l4aJxSL3&TN{eZwcAYW*FuC` zC3CWDZFvCxbsn5&U#H~R&nlq+N97h^LV zr#LgD&JW$(ZNfuG!hIM2XeIR@2Zg){k@rRk={3XFPWheiD#jDml&%@Vq0)74b$k`w zrR@0pH{9@l3n9lo^|2mHRFq02PTfis<+>MTT2_mP?nOb$a7?Q4ae8~p)&ZsYRBt%@F$ z_g`C#t+_?-f3k~qMiVnkTf!W%i9qH?8aUb}deHrEdbf&p$3uc0oa>_VPIpG|iwhti z1*2~84ln1Gu^yH((CkPLKhYJQ9?ms-!Wfq7csu$E-NcB5)EogK&_^i}tS0k*NU8(2qxz=* zKYz|RugVdbN?E&g#@EJ8L6h?7LbizM^iqjf?&m!az8Jb7Rz(|pOH^cUDXh^T(HYLOU3|6%H@ZMfP%CIU8cs(~ zKT832Q>MkE6r*Vfj^LL((A!HTU;f=`lGyB)EVDys6I;Tf)d)YGJT`E9X=$PspWVsv z;Ll5fa|u%#^Mbw_u4jsTKp9!VXW=mT-`6v7c*d$sA;|`@lOf=~Ovu{8(7?;YSl7E? zlG|)DyhSi*zl-~IJxiVkkFAMjqn<0+M3kuohyUo>H9rc%w`uvTRWY1u^cidrJ?i&dlcSK9+5yBRX^m9 z=P&bj;CvoW{FJ0Y;n9cdhGEf1=PAc{}+{ zYNgtoc>=rSh<+H{&k$Qg+Ab6$m1gz9)~C|apH8&0giuy}lCAsP0UI&RrJ3ine#?7` zm2_}rNLiMVnevNG3T29bJMY11ZRc)V!%5MLef9J~>CX1^eay2AYe5LyyjsEtXV^sT z0$`mHj;!UUI6KP5e(W~qmLYFe(8bRkA+p8p+gKeYf_)`pnS^S_)*+MNU6{NsXS3I9 zu1|+dGjV(=QCkrk%=7p5mhX5rIylX7{S+Upb-2JA z?ZoL`iLqPu-_p>?rc%fpLOp06neL>3i7Pl>)3}`^?bW8N6x@dJB^hCUCBL%Ir`<7` z*hl+35ew!F=$;N%6E>p;hQ;3PdNN_MwsWO$um$37>w`GUUrArN&UaLg5GCvttji3{ z!}LUh@T;2X~lQ_f4Of+^#KTjOjhvK_~2tJ1qN3!$R)FuWxY{ z<}F)VIIeyt*StjwIW=@*13jh9lDX@^B`)0-+c%Y~(@!4~exb}D*+xvTx z>0GI%I(ST~ODBMDPEWq=-5e^Pg1su8G~@71&h)=G)A>GQVu-hrl#VC(q{qEo4WM80 z4At_=kV-jT=*ve1r+t#b^_AtDuiWLZAB-|PoM>}4KDDaA_2Vgs7MG#a{3g2c{LDHM z8`s;NX(dwEp#}NP@Ys4RmHvbDe%E}9Z*%59nDWq#D)^-o!vZ9(83qpIDX_E?3p|?J zsfqqK0aS6h4%=GmqGM5qVBdoyD1)+cIpIPR|3t1#g1Rz+2ZGg`rDHf8HCux{4NYn4 zZ__GlxClj`MJ^I)5wqPuo*)>eu6>U3urB`laX-~7+o{dvSgGBt6s6%yH~+U89IMU_XH(HBhJ#dBNPQmhpw zguA%vR-XZyq{dZS$PMAMwwLTPCN~wHC7G~bhM=Y>K#i_v@81^|?+Q-iNBA4mYFzCZ z3|e!&g49+iAlpgh83-#ie`HvgzicDp*CE^8N7|wgEucIn@aGAIC%!j^qZB?+NH8VY0g;(BpUbf^oaf^z`gh$!$Qp1cqo_Sag`alD zr`%q`F}{$J#pA@r+og}&<`_jUObd`9sGzU^U~K3PcXl9oESTFB^T9&QlvKD?UetAN z>ihP~Ph~=4aw*BdJV-!a32oXW*;*ZHvpiFC&E2dvqpWV0vS{u^^OaPZUX(6uad}oe ztIAB+w1fS>MGS#!l)iE%u9Ti@Qn9(cLTuDdU2{18Ad7?@av0?2wd^}J0V%#fa4ZEP z@UH~alPjg}$J==~Yb{vs=6y>k;L#o#K5*)`-xa39I#(_Nr*HEw>R-nr#kD_q6FJKN zCfD){zJlw2fyLWTQJa^i-AfF-UZ;IgB&mtV1RrKtf(viV2QK~14vb@bKVRywzW6ki zxCNWLiMzMt;?21K?qH(wh|;$sZu=!PeM|M^35j^3(dkqnQDGvjx4$9)t35KkCIgxy zUNf{Ua>BzYbLW%hm8m;?(|UGTE4(Z0BRyU2MA5NVJ+|O^E?^d^R8u-f1+^pcj&S9$ zBx@+n&k%XQ_=pEqlp7X1n5ZxpZV@ z=z4AT_dl%wOzc}(t_HN0`;jfF5GV8Z0WWhwY3xmCk{_DW=yNF7=VHOiG1M)iMdW$i znF4;S$&Wj3h*W2EnP-Qo;%*F4U<+lL=MsgLnfLE6yoil{a*GW+zGz z#NBGYe1cyTzEoT0w1zU@ovV}&BCaie@8L7T?H}w3U_T|iUn~6Jb=@~Sm!B;xY3UK> zB7I%!7`KM4k0uw{KpeN=L*Y*JG#31tkS5!Zhv7QHJN()y7m~(Ne4p{d!p8r5DJB4W zb*WS{6h+lnszq~5Lb28b8EU7g_*Zwcdxai_io#Iws{+p(9uORq1+G zZK0q&K~~ikRh4D#?2vdN#mKBD7F=A^LGH)rUF6S6byVvl{O&#jUY3SW30yIsTb)Z@ z+r%$kEAKNQ%x8A%Kh67W$JUiy_&BKPi%k~L%#g3{LUaSB_A}gV%*cZVx(!9@k%DX}Q}2f$WUvinGNvkM3F zpku>+@ENFr$AK+sFMO(*HhVJ9VP73C6EF3u2N~R!>KO$T$n7ab-&*iBfH<8Wb9Xv# zaKP_#&ni|(GomuCYq(%jmS1=}q)-roz=XU|*n+K$khXpJDOqkBm0!Wl{Q9S*h`aT0N$E zD#PNQKFhy1BQo5#4jph##Nt}7ean?!&f#m%xGOZ(8y!THIs%LDfm}{xi^^~Iw$zfv zDpo<4&8$F6hwYvI6|(+bmWklKH-ghnOEr<{W~@^?wdrBbPmzgCOFs(8SU4qHAR>=R zB1~2|G`U^4P*Be4pm`h~#l$ zuE;vZxy^yTrGs;Q96B_?#Kp2|eaR_jak=u10?+)oD6coD&7M#wZzgUa{u4cF)of$yR6t1$Un9^efXY z6Cl`BGLcrVhr=$if03pq-z2?Zt%UQ6QF>@n`bp?1!oT;zg+*_Li~N2?ooqdBtVPMG z`~kiSle3FRUcaTOUe9SULKEczs>a?JBsE*`$Dg7&0c6DUuU_wuO z%(k}9658VIfXwt=`2qr8K_P93tP{}XR`xJ&mt}$qI2w-c+^4$*3&TaU{;YSR-7PC> z!D(%m=B~c~-5B3kEJ;Dj&0$q?D&?vNVKwfJpA&KZv{A9(0vGEnPaV!i1^i()mC&SHU`bheL6{J9`4cE=NEh<>goX zE8H_NJpV47G5PlVINH$^L@(un(TZO=EGza#m?yoKt4lBdVT;+6( zvsZlTn2GPpokdIa*n(Bo2&d9^yPGLMS~`}d`{Tmq+eI=i;T62#O6OS=#1Lv8 zwT93@ycYa(hvHFpZJsGV8PG~1PuU4ZA*rv5NJzQYX`=Br|3;uZFS~B9nV-fT6?9|q zD0+C0{=ia{ZjkcDe&5Se8~C>nc1MIu;64`)V?*3Wc4B0QNVV?+HYDX}twIaVHBQx0 zp1+o+4}#2!6JrSTTxh{olqRd%tm&qtVaSc@JYBFqHnT* z^-k#U=Ef?ZRITSw8e>3!RfUN7@m|aXb$Lsd-?V55Jt~MuZU|?9e8quZUt)&s#j)K- z-RCyKob}>3&tA0{;(@!DslRA?GS^_H`fdK&<>!$b;jY)2uW4t1V~VaNE0_mg9UqmY zZPyv`L#57q%%(U2!rt2?>IXMc{a7vKl&LNlCo+%u{I#YJeM5L-bz;G@90`$WVUb4a z+GtThJx0m3r-XtrtdEdWWuCgR%lw@}U*|;!Gri|iR(xIDg43#e*)%43Yvf9WI;;LE zUa)*dn960`(<0M3ZjnK>hy9D&owS6b555@(l=+z$9j1rXkG5Bv z&w6X(ypmgF$ds0st&A6==^!`FC4uQ0a?=UeN5hFK6^u-{KLtSYHlNNLCAkrlb^M^K5w}`?@_dR2MB=<{#GA+6nJp1 zOrgk?D1B&?po{*sgQ4=vT&m-=h0^znk!$Ygf;x94muUU>SS9*_&a6udkjMYw`X`e8 zfX{SZdvb;D3%uc%cz2DQ$5I!wW2vT?>1Mq-dikQ{TV!bO&VnAyQTBsM1x>>uqC=GX zr+dbf9i~$=IA^Kiee8?ly%rj2EItWfa}rfkLF+y_EW3APG;SO1nRN~T7Kl<^F&2}! z!~W%(=amJX$T<*{C!JHPe;Ul=!z@_;-rr=r6Y_K%7roK}W=4hi>dCvfoL&(HJCf%V zl|ka7^aLw7uvLjwgD9*nk(Sr}Ae?_g0W~8w9$@0_eG&jS(_XucKGH-IwsHClc?R}S zbVwL`Uz2zIva&B9xW0%$z0M9gdCWiWf01FS-LL$D|BbE}EHE|tAOY}4xe7e$sy^je z6tQc{7J96M-{^``BWJsC&>Yr(LUP$FpfR2ymY(8|H?}&)m5*E{u<*YnX9fm^7Xh<& zDnJvN+QROv@$zqU9U+at!$~*l4yJj98zznyx1-l ztb;roeLF-`+vT#Mt-pMww=!5f)=U1mGc`n`vHes()*Em+&H@Wm>$_i^?10s^Q06EvJmJMOuAdeQ(w~C9g79+LnJuf z>tNfx5=m9Bm3OmxCqAR_xPi#z3bCG_kO<~l@OZ3hM_HBT&vL1X50X6=58zYJvY1Lv zoe5rNgkRJI(W$;Lmq`VxA=u&(IcBLzNF50Fe+Wv0xpI}MB`ONNpE5Ek1O zUH7HTfS!vsQc|iGEJx8^!|YQF)@7p zs0qH$_9@$+)NM~Lf!gHtS^h<>d(X*nhB)P81O?Lf`TW6EW}oV({63XQ4g3-`}R?%CE{W#Y-V&b!B747@d_rTMLN(Xlb2dT}b+YMcZZe6d6IJrHMv~6mh)&4bN z!Id6WS&OPaTkUZjgSkMa0m+&|+)%%i?`LrW0rnyE8yU{q{mLtzc%mb;Hn<#4^K=ZX zl~S%VM0aLR79?odL-fSUR#navEvR$fj8s{QgomWpfC;Im47x@dHYx$?xmj!b^IVGdtLD^u95!~eU|=4Me(RuQ*9L)uBu?f@h(3m z=oim}3l_`T0JOvilGlfBzKu~B;|fF-tvWqJon2(Ykgi>tnk*QvHf{I`x$(2o@s8xp z=;&vD<)rL#7-=R+b#iDFkBUjPQ;+r;eRGf-X(?{OnF%IN07{7k`N|dM*obyPw3HDJ z=pZPIPjc)u-^|R|!7hY<9YUWHwcx10lV2&GzaJIaHj{^q<&GaJpo_~LU+n_HtSnxO z)=E&kTen$PJ|xaYDvR4>2z|l0^8RoZ^q_LhhP`2M(>K|$dejxUd1JvlU5`fyPog#Z z8Qtbymz!WAe;S7pB-W9Xl`3kyour$!1uovep%M*kBCx%a)Z-=>OBZ)LK%B|@(Kr7V zKwSB6{z^YkRAc7i;>bgOxW&U`3pbc+y!J2r{v)YF6_j)Mn1exq6_;_v8_9e*Bhn1+ z`BV+hL2CW-&*C+#27cu(X8iP~fD-u?N^ju25;APGrZ?UVibDaZ0AzH?)HaKW#>uI_ zR)gQkvXNRrVlBit#%L@|>SF#kHOPmYq*o*ZL=5#gqWpATPu3wX&+C6Y3Z8We#f`o+ zY;FL8ImwvQ0zhp_t&WQ>MnPw2gQCDeR4WN$N95mYO~%hpgfp}L*^{Vy2zky-(c^;g z*VnIgDcr~b-Y|Cq_@(ztAE>3vWTrAaADKFDzF8$|{;9~ia>AR==u3gbN0cdVZ zf%?=s>9?3Np6ui_dWgLl`T>5~!@PN7;p=y0QP-vW*fx^Et2Fg|U+)-FuXfTQWe+#U zGnA|3Ul~l5ThGPB=H}4_Bcr#a`#6=q*=ga;4NGsQmuH+-xrhueKSOnFGsn)X$l1`K zONy9Zw-w#y`s@_lMORga;KfwA2v&yVEm~^{3%`$ODGm5(pp=(e1wd0BzGo+srGH6) z@>oRYDp7l?rYx*7j#~OwD!nLWBXqxirG*QcGs{L1c($1eDWSDaqbw9Zu5uC9b$q|Y zTB!q`W$rsIdq_bz3d~N+YnIlKXOYTk{iCN~yesAC+z|aPPzoRA+14t9tv?$2Hs`(6 z2Y5=GM=s)=zk=U=M+~vMgZ8t$2&hUMGCXHLk_mF1;RN6RCr#*Kh4G-P9V0NU;s{h~ zB#tRf?pd8&1^%$p!>K^7oEiVOF3%Z0jTVaggVEDX`k^*>} zd1kjt1?_o>RM$s#e^+W17b~wayBvZX15S#uzJt9GP|GkWis@(8?#*}M?raz0jkF!4 z7ThBEDLt9n^ka&T$aEry2M*KNS6fUU)T#Q{(TD}VApy`pDW`WzuRX6#!UfW(9uRxV zRzw2Dm-5ia%7#;t#b$v$WO>`|TFBeR`!F@5sXm#V#v>wAgzXT@dt5X`@8HN$3swZ= zD4+Ok48!=#3~6JVH|u`3=_F429Dpm$)`B&D=Gj$wR)MGbqi|l4W)@@8V>CJ;t1BGh z6!@%)2$okgHUUqt5xsKg4X+v&r#7FRl*89@md<-_BSM5;%ay4iCDtOaMh(j-1? zy#}Q{7YA$M6+tWyH79)fc-zErrBLmCWc)7D1lmC`RCbr*Nb%Y8&Bdujj~{?_(&5be zsV-@JI2JzL-Haz)17LVh7EDU`8s_}XaX?J0$F+%~Rr%(i$yxU~pJkf%{`Z$lI6TfM zL0)|DRPa5GaJp8|+WNJF{Y6QPqgyFJ=W zd>P7#{lm&oKH3F|mGtQI04}JDbWgjX2RBi&?@Ro0DMv^@vs8JKSA7Jh0HdE~RxVdF zw&9M5-bGUIe=ds||9L-g!}ofOs`0E#63W=c1_@jj6wrp^BdIMG&`iU-)&+>en#k_I z16lqY8s%2$kBW@snMbIR)=hxa?O9T9mof7=RvS+g9o%7R(bdc?*_zZ{rD-+&B{@s$ zGzAhD(6ZQ+#&X=>tHM!GKb7liBYaEPn~TdouqZ6y5Aa^ zz%Ji2*YA|;XS%{f!pOyw0t=Sw&9tnw1ua+#-7}3|Eo;r^GT9@vU|^K|h-*YKyGu>} zs+5tFUQh8p*GQqGU{RsdgODnS(kEd6!_lv0{QPKsG)2RdQnK4-Iua9H+=8`MpuSBl zSlq^dB$!Jt*3e0ZW=xmshnNPqPIOIM@LfGbXxt{>PfT1g!Wdz4iVDf8G^OrJs9vxu zgk_>#MwnR_>OrZH`xgmIZNc+uGwCm3!5i}y(OaX;pzYe#zw<*2)~8{**?Mo^C|xPsO+ zrL+4bE0e#8?60W-b@~wsFky?5xG=xW}Zop@6jx_Xuq-6}u5HstMp5q7C7 z%as^)-NJ4yrNz-tr?c|I{l*Z}EJRC-8vn-q2TFUG*?Q~gdHJprC-v5 zfYSvG-AZNE<0bD?4UeTvB8W#QVQh!bph5J&U z7~Y!t;Bzz@CBmqhbUE$V{1So6l&VP#rEH+QCuHXSi>NqqUyt0m(U0Yn+ zA)N-YG#;CQ@l=V>`XneYlG-5jYF;_%IhU9snIikvn6#Vlr|`&ViRx7@iBEO@Or}m2 zpNQFzhCmSue53-dS;$VWs2SBeNcl zhOzN5`mBRY=b%%{a8-V8a|gYO`KChBK*H7->H)c>Hff4X^=E_hBxKGkdQf_fGo?iT z6PFi5paHo-i$|mFGWq1}j@w*$3%&zr{~F$Bt}j_^v1x96{dwls?4$XUk?zrwQ#lLX zCQkGrMqac~G`==30aK3Coj?Qbp_Vis=3GInXRB1%21>?%MD8RLdW7GYbavUepVSryrSLI3py!EbsL*adzUe0v2qel~>frw7;uDS>rRP17FL_ctjT@^xT4-j#NaSBUMPtK&rc!19Q|S?h9Ge%8PFwt>}g?Nm|k---F71 z#{JvG1~rHp-57d{sLV3i#9A^@S|BC@x}qvSmA-YSAic z&Ud;}C~E;nQ7cbForeL6TSf|ShiuR}EuJ+7;eOKPy3gohwpOQ$S5iap{+zeh^broE znmmI!B=7uj8i+pM1x<-N`C1R8i$TRL7(+Z{n$68#H^4Dh(XP}U${OR%7=pTIL>^k>9M_=dU z)TTu2cyIA)IqIcK*&ct5>Q*XNhj6#K>r`HVoqXEo=zjslQKYtTpZqJ=yJ$~h4ali8 zKEb8r68&pA(24Ej8mCFe55Rm($WP@qaNdPQnrX`jjLXtQKBk3_HTIH>vL*5ha-PdT ze857u`d1a8rPhK0y9=E|uy;YuQ@IFi%3Ndt1?jIzn2E}4 zEw`T?(kl8Me*S`-N1~B%8%gR5A?~6!R-HkgC710mFy;$#zKELdEEyqCdhsC_&3&J9 z27>|P;ewn;vP*_oIXhC8`kcx%`Oy~0QX>?}jOV@}=Z)yzGN2xgm}^hC-%F*!G;~z~ zEnkrHN$xcms3YYT9yBOuNOT)>T`$P_B{im`Y1i?p%#wBCR!=b*?}D6PQUhz~kQ6@^ zcepN#Zv9y5abL?q>fZ%9A7vcOgG=eX{Mh9Ko~y&Y>`=j#Y4&_U&Lf%L-Cg&c+ACl= zC=_{2SOM1p)+01WM{2*81K@(3M>0ilzp8dKkD_)Hy5oHF!53sf*nib3RdvpGUMY1M z-3;#cf}D3U8w}LvG&{cq^8bK~HU#?t+Uhdy<6QhLk@g-sQRht$@q+w++4 - - - - The Matrix - - - - - - - - - \ No newline at end of file diff --git a/Matrix/matrix.js b/Matrix/matrix.js deleted file mode 100644 index 4548aa2c..00000000 --- a/Matrix/matrix.js +++ /dev/null @@ -1,202 +0,0 @@ - -//Min, max inclusive. -function randomi(min, max) -{ - return Math.floor(Math.random() * (max - min + 1)) + min; -} - -var __matrix_spinners = []; -var __matrix_spinner_counter = 0; -var __matrix_animation_interval = 16; -var __matrix_glyph_size = 16; - -function matrixDrawGlyph(context, glyphs, glyph_index, x_index, y_index, alpha, colour) -{ - if (y_index < 0 || x_index < 0) - return; - var gx = glyph_index % 10; - var gy = Math.floor(glyph_index / 10); - - context.globalCompositeOperation = "source-over"; - if (false) - { - context.globalAlpha = 1.0; - context.fillStyle = "rgb(0,0,0)"; - context.fillRect(x_index * __matrix_glyph_size, y_index * __matrix_glyph_size, __matrix_glyph_size, __matrix_glyph_size); - } - //context.globalCompositeOperation = "lighter"; - context.globalAlpha = alpha; - context.drawImage(glyphs, gx * __matrix_glyph_size, gy * __matrix_glyph_size, __matrix_glyph_size, __matrix_glyph_size, x_index * __matrix_glyph_size, y_index * __matrix_glyph_size, __matrix_glyph_size, __matrix_glyph_size); - //context.globalCompositeOperation = "source-over"; - - if (colour != "") - { - context.globalCompositeOperation = "multiply"; - context.fillStyle = colour; //"rgb(0,127,255)"; - context.fillRect(x_index * __matrix_glyph_size, y_index * __matrix_glyph_size, __matrix_glyph_size, __matrix_glyph_size); - context.globalCompositeOperation = "source-over"; - } -} - - -function matrixTick() -{ - var context_width = window.innerWidth; //document.body.clientWidth; - var context_height = window.innerHeight; //document.body.clientHeight; - var canvas = document.getElementById("matrix_canvas"); - var needs_resize = false; - if (canvas.width != context_width) - needs_resize = true; - if (canvas.height != context_height) - needs_resize = true; - if (needs_resize) - { - - var stored_data = undefined; - - try - { - //This is an invalid operation on file:// in chrome, so catch and fallback: - stored_data = canvas.toDataURL(); - var previous_image = new Image; - //Once the image has been parsed, resize and update: - previous_image.onload = function() - { - canvas.width = context_width; - canvas.height = context_height; - canvas.getContext("2d").drawImage(previous_image, 0, 0); - matrixTick(); - } - previous_image.src = stored_data; - return; - } - catch (exception) - { - canvas.width = context_width; - canvas.height = context_height; - } - } - - var context = canvas.getContext("2d"); - - var glyphs = document.getElementById("matrix_glyphs"); - //var glyphs_white = document.getElementById("matrix_glyphs_white"); - - - var maximum_glyphs_x = Math.ceil(context_width / __matrix_glyph_size); - var maximum_glyphs_y = Math.ceil(context_height / __matrix_glyph_size); - - - //Fade out: - if (true) - { - //Subtraction method: - context.globalCompositeOperation = "difference"; - context.fillStyle = "rgb(2, 2, 2)"; - context.globalAlpha = 1.0; - context.fillRect(0, 0, context_width, context_height); - context.globalCompositeOperation = "source-over"; - } - else - { - //Alpha method: - context.fillStyle = "rgb(0,0,0)"; - context.globalAlpha = 1.0 / __matrix_glyph_size; //1.0 / (60.0); - context.fillRect(0, 0, context_width, context_height); - } - - if (false) - { - //Fill the screen: - for (var y = 0; y < maximum_glyphs_y; y++) - { - for (var x = 0; x < maximum_glyphs_x; x++) - { - var glyph_index = randomi(0, 102 - 1); - var alpha = Math.random(); - matrixDrawGlyph(context, glyphs, glyph_index, x, y, alpha, ""); - } - } - } - if (false) - { - //Random glyphs: - for (var i = 0; i < 128; i++) - { - var x = randomi(0, maximum_glyphs_x); - var y = randomi(0, maximum_glyphs_y); - var glyph_index = randomi(0, 102 - 1); - var alpha = Math.random(); - matrixDrawGlyph(context, glyphs, glyph_index, x, y, alpha, ""); - } - } - - //Create spinners: - var spinner_density = (context_width * context_height) / (__matrix_glyph_size * 256); - while (__matrix_spinners.length < spinner_density) - { - var spinner = new Object(); - - spinner.x_index = randomi(0, maximum_glyphs_x); - spinner.y_index = randomi(-16, maximum_glyphs_y); - spinner.alpha = Math.random(); //Math.random() * 0.25 + 0.75; - spinner.counter = randomi(0, 11); - spinner.glyph_index = randomi(0, 102 - 1); - spinner.interval = randomi(1, 15); - - __matrix_spinners.push(spinner); - } - //Draw spinners: - var spinners_next = []; - for (var i = 0; i < __matrix_spinners.length; i++) - { - var spinner = __matrix_spinners[i]; - var should_delete = false; - - /*if (spinner.counter % 6 == 0) - { - spinner.glyph_index = randomi(0, 102 - 1); - matrixDrawGlyph(context, glyphs_white, spinner.glyph_index, spinner.x_index, spinner.y_index, spinner.alpha, ""); - }*/ - if (spinner.counter % spinner.interval == 0) - { - //matrixDrawGlyph(context, glyphs_white, spinner.glyph_index, spinner.x_index, spinner.y_index, spinner.alpha, "rgb(0, 200, 0);"); - matrixDrawGlyph(context, glyphs, spinner.glyph_index, spinner.x_index, spinner.y_index, spinner.alpha, ""); - spinner.y_index++; - spinner.glyph_index = randomi(0, 102 - 1); - if (spinner.y_index > maximum_glyphs_y) - { - should_delete = true; - } - //matrixDrawGlyph(context, glyphs, spinner.glyph_index, spinner.x_index, spinner.y_index, spinner.alpha, ""); //rgb(255, 255, 255);"); - } - else - { - //matrixDrawGlyph(context, glyphs_white, spinner.glyph_index, spinner.x_index, spinner.y_index, spinner.alpha, ""); //rgb(255, 255, 255);"); - } - if (Math.random() < 0.05 / 60.0) - should_delete = true; - if (true && spinner.interval > 1) - { - var percentage = ((spinner.counter % spinner.interval) + 1) / (spinner.interval); - matrixDrawGlyph(context, glyphs, spinner.glyph_index, spinner.x_index, spinner.y_index, spinner.alpha * percentage, ""); - } - if (!should_delete) - spinners_next.push(spinner); - - spinner.counter++; - } - __matrix_spinners = spinners_next; - __matrix_spinner_counter++; - - setTimeout(function() {matrixTick()}, __matrix_animation_interval); -} - -function matrixInit() -{ - var context = document.getElementById("matrix_canvas").getContext("2d"); - context.fillStyle = "rgb(0,0,0)"; - context.fillRect(0, 0, 1024, 1024); - - setTimeout(function() {matrixTick()}, __matrix_animation_interval); -} \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index df90ebf1..00000000 --- a/README.md +++ /dev/null @@ -1,31 +0,0 @@ -tourguide logo - -**TourGuide** is a script meant to help [Kingdom of Loathing](https://www.kingdomofloathing.com/) players efficiently play through an ascension. It will give you advice on getting through your active quests, tips on how to efficiently use your resources, and reminders on using time-limited resources. - -To install, run the following command on an up-to-date [KolMafia](https://github.com/kolmafia/kolmafia) version: -``` - git checkout loathers/tourguide Release -``` - -To update, run `git update` or check the "Update installed Git projects on login" box within Mafia preferences. - -## Running TourGuide -Once TourGuide is installed, look at the top bar within your relay browser. In the upper right, underneath the moon state and the bug report button, there will be a drop-down menu. Select TourGuide from this menu, and the script will dock to the right side of your window. - -![image](https://user-images.githubusercontent.com/8014761/190516930-c70cf5b7-e93b-4b6a-a3a8-31f2839e6ed2.png) - -## Using TourGuide -At its core, TourGuide is like Clippy, Microsoft's wildly unsuccessful advice daemon from Microsoft Word 1997. You can use it as actively or as minimally as you want. TourGuide aims to inform you of the many resources a KoL player has -- things like free runaways, banishes, free kills, et cetera -- and give you ideas on what to use them on. TourGuide aims to give users a heads up on the many arcane speedster strats used to complete ascensions in the minimum possible turns. KoL is a complicated game, and TourGuide is the little parrot that sits on your shoulder and pecks at you to remind you not to lose track of your resources. - -Some people use TourGuide on every quest, referring back to it like a treasured family accountant. Others open it at the end of a KoL day to see what resources they may have forgotten to use. Others still use it, but minimize every tab except for Guzzlr, because they love Guzzlr so much that the entire game is just endless Guzzlr parties. There are many ways to use TourGuide. - -For samples of TourGuide output (and general notes on how to read and use the tool), please visit our [TourGuide Usage Documentation](documentation/usage.md) page. - -## Development & History -TourGuide is open source and contributions are encouraged. This script, as well as its support scripts, are in the public domain. - -- For an overview on how to develop for TourGuide and create PRs, [click here](documentation/develop.md). -- For more information about TourGuide's scope and the limitations of the tool, [click here](documentation/scope.md). -- For more information about TourGuide's history, [click here](documentation/history.md). - -For support, questions, and comments visit the Ascension Speed Society discord channel. diff --git a/Source/relay/TourGuide/Daily Resources.ash b/Source/relay/TourGuide/Daily Resources.ash deleted file mode 100644 index 310bb824..00000000 --- a/Source/relay/TourGuide/Daily Resources.ash +++ /dev/null @@ -1,655 +0,0 @@ -import "relay/TourGuide/QuestState.ash" -import "relay/TourGuide/Support/Checklist.ash" -import "relay/TourGuide/Support/LocationAvailable.ash" -import "relay/TourGuide/Sets/Sets import.ash" - - - -string [int] generateHotDogLine(string hotdog, string description, int fullness) -{ - description += " " + fullness + " full."; - if (availableFullness() < fullness) { - hotdog = HTMLGenerateSpanOfClass(hotdog , "r_future_option"); - description = HTMLGenerateSpanOfClass(description , "r_future_option"); - } - return listMake(hotdog, description); -} - - -void generateDailyResources(Checklist [int] checklists) -{ - ChecklistEntry [int] resource_entries; - - SetsGenerateResources(resource_entries); - QuestsGenerateResources(resource_entries); - - if (!get_property_boolean("_fancyHotDogEaten") && availableFullness() > 0 && __misc_state["VIP available"] && __misc_state["can eat just about anything"] && $item[Clan hot dog stand].is_unrestricted()) { //too expensive to use outside a run? well, more that it's information overload - - string name = "Fancy hot dog edible"; - string [int] description; - string image_name = "basic hot dog"; - - string [int][int] options; - options.listAppend(generateHotDogLine("Optimal Dog", "Get Lucky!", 1)); - - if (__misc_state["in run"]) { - options.listAppend(generateHotDogLine("Ghost Dog", "-combat, 30 turns.", 3)); - options.listAppend(generateHotDogLine("Video Game Hot Dog", "+25% item, +25% meat, pixels, 50 turns.", 3)); - options.listAppend(generateHotDogLine("Junkyard dog", "+combat, 30 turns.", 3)); - if (!__quest_state["Level 8"].finished || __quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0) - options.listAppend(generateHotDogLine("Devil dog", "+3 cold/spooky res, 30 turns.", 3)); - if (!__quest_state["Level 9"].state_boolean["Peak Stench Completed"]) - options.listAppend(generateHotDogLine("Chilly dog", "+10ML and +3 stench/sleaze res, 30 turns.", 3)); - if (my_primestat() == $stat[muscle]) - options.listAppend(generateHotDogLine("Savage macho dog", "+50% muscle, 50 turns.", 2)); - if (my_primestat() == $stat[mysticality]) - options.listAppend(generateHotDogLine("One with everything", "+50% mysticality, 50 turns.", 2)); - if (my_primestat() == $stat[moxie]) - options.listAppend(generateHotDogLine("Sly Dog", "+50% moxie, 50 turns.", 2)); - if (__misc_state["Chateau Mantegna available"] && !$skill[Dog Tired].have_skill()) - options.listAppend(generateHotDogLine("Sleeping dog", "5 free rests/day (stats at chateau or cinch rests)", 2)); - } - - description.listAppend(HTMLGenerateSimpleTableLines(options)); - resource_entries.listAppend(ChecklistEntryMake(image_name, "clan_viplounge.php?action=hotdogstand", ChecklistSubentryMake(name, "", description), 5).ChecklistEntrySetIDTag("VIP hot dog stand")); - } - - - if (!get_property_boolean("_olympicSwimmingPoolItemFound") && __misc_state["VIP available"] && $item[Olympic-sized Clan crate].is_unrestricted()) - resource_entries.listAppend(ChecklistEntryMake("__item inflatable duck", "", ChecklistSubentryMake("Dive for swimming pool item", "", "\"swim item\" in GCLI"), 5).ChecklistEntrySetIDTag("VIP swimming pool item")); - if (!get_property_boolean("_olympicSwimmingPool") && __misc_state["VIP available"] && $item[Olympic-sized Clan crate].is_unrestricted()) - resource_entries.listAppend(ChecklistEntryMake("__item inflatable duck", "clan_viplounge.php?action=swimmingpool", ChecklistSubentryMake("Swim in VIP pool", "50 turns", listMake("+20 ML, +30% init", "Or -combat")), 5).ChecklistEntrySetIDTag("VIP swimming pool buff")); - if (!get_property_boolean("_aprilShower") && __misc_state["VIP available"] && $item[Clan shower].is_unrestricted()) { - string [int] description; - if (__misc_state["need to level"]) - description.listAppend("+mainstat gains. (50 turns)"); - - string [int] reasons; - if ($item[double-ice cap].available_amount() == 0) - reasons.listAppend("nice hat"); - if ($familiar[fancypants scarecrow].familiar_is_usable() && $item[double-ice britches].available_amount() == 0) - reasons.listAppend("scarecrow pants"); - //if (!__quest_state["Level 13"].state_boolean["past tower monsters"]) //don't think this is true - //reasons.listAppend("situational tower killing"); - - if (reasons.count() > 0) - description.listAppend("Double-ice. (" + reasons.listJoinComponents(", ", "and") + ")"); - else - description.listAppend("Double-ice."); - - resource_entries.listAppend(ChecklistEntryMake("__item shard of double-ice", "clan_viplounge.php?action=shower", ChecklistSubentryMake("Take a shower", description), 5).ChecklistEntrySetIDTag("VIP april shower")); - } - if (__misc_state["VIP available"] && get_property_int("_poolGames") <3 && $item[Clan pool table].is_unrestricted()) { - int games_available = 3 - get_property_int("_poolGames"); - string [int] description; - if (__misc_state["familiars temporarily blocked"]) - description.listAppend("+50% weapon damage. (aggressively)"); - else - description.listAppend("+5 familiar weight, +50% weapon damage. (aggressively)"); - description.listAppend("Or +50% spell damage, +10 MP regeneration. (strategically)"); - description.listAppend("Or +10% item, +50% init. (stylishly)"); - resource_entries.listAppend(ChecklistEntryMake("__item pool cue", "clan_viplounge.php?action=pooltable", ChecklistSubentryMake(pluralise(games_available, "pool table game", "pool table games"), "10 turns", description), 5).ChecklistEntrySetIDTag("VIP table pool resource")); - } - if (__quest_state["Level 6"].finished && !get_property_boolean("friarsBlessingReceived") && my_path().id != PATH_COMMUNITY_SERVICE && !__misc_state["in CS aftercore"]) { - string [int] description; - if (!__misc_state["familiars temporarily blocked"]) { - description.listAppend("+Familiar experience."); - description.listAppend("Or +30% food drop."); - } - else - description.listAppend("+30% food drop."); - description.listAppend("Or +30% booze drop."); - boolean should_output = true; - if (!__misc_state["in run"]) { - should_output = false; - } - if (!should_output && familiar_weight(my_familiar()) < 20 && my_familiar() != $familiar[none]) { - description.listClear(); - description.listAppend("+Familiar experience."); - should_output = true; - } - if (should_output) - resource_entries.listAppend(ChecklistEntryMake("Monk", "friars.php", ChecklistSubentryMake("Forest Friars buff", "20 turns", description), 10).ChecklistEntrySetIDTag("Friars blessing resource")); - } - - - - - - - if (!get_property_boolean("_madTeaParty") && __misc_state["VIP available"] && $item[Clan looking glass].is_unrestricted() && $item["DRINK ME" potion].item_is_usable()){ - string [int] description; - string line = "Various effects."; - if (__misc_state["in run"] && my_path().id != PATH_ZOMBIE_SLAYER && $item[pail].available_amount() > 0) { - line = "+20ML"; - line += "|Or various effects."; - } - description.listAppend(line); - resource_entries.listAppend(ChecklistEntryMake("__item insane tophat", "", ChecklistSubentryMake("Mad tea party", "30 turns", description), 5).ChecklistEntrySetIDTag("Rabbit hole tea party resource")); - } - - if (true) { - string image_name = "__item hell ramen"; - ChecklistSubentry [int] subentries; - int importance = 11; - if (availableFullness() > 0) { - string [int] description; - if ($effect[Got Milk].have_effect() > 0) - description.listAppend(pluralise($effect[Got Milk]) + " available (woah)."); - if (!get_property_boolean("_milkOfMagnesiumUsed") && lookupItem("milk of magnesium").available_amount() > 0) - description.listAppend("Use Milk of Magnesium for +5 adv."); - if ($effect[barrel of laughs].have_effect() >= 5) { - int turns = $effect[barrel of laughs].have_effect(); - description.listAppend(pluralise($effect[barrel of laughs]) + " available" + (turns % 5 > 0 ? " (" + (turns - turns % 5) + ")" : "") + "."); - } - subentries.listAppend(ChecklistSubentryMake(availableFullness() + " fullness", "", description)); - } - if (inebriety_limit() > 0) { - boolean stooper_is_equipped = my_familiar() == $familiar[Stooper]; - boolean could_equip_stooper = $familiar[Stooper].familiar_is_usable() && !stooper_is_equipped; - string title = ""; - string [int] description; - if (availableDrunkenness() >= 0) { - boolean shotglass_drink_available = !get_property_boolean("_mimeArmyShotglassUsed") && lookupItem("mime army shotglass").is_unrestricted() && lookupItem("mime army shotglass").available_amount() > 0; - if (subentries.count() == 0) - image_name = "__item gibson"; - if ($effect[ode to booze].have_effect() > 0) - description.listAppend(pluralise($effect[ode to booze]) + " available."); - if ($effect[salty mouth].have_effect() > 0) - description.listAppend(pluralise($effect[salty mouth]) + " available. Drink beer for +5 adv!"); - if ($effect[beer barrel polka].have_effect() >= 5) { - int turns = $effect[beer barrel polka].have_effect(); - description.listAppend(pluralise($effect[beer barrel polka]) + " available" + (turns % 5 > 0 ? " (" + (turns - turns % 5) + ")" : "") + "."); - } - - if (availableDrunkenness() > 0) - title = availableDrunkenness() + " drunkenness" + (could_equip_stooper ? " + Stooper" : ""); - else { - title = "Can overdrink"; - if (could_equip_stooper) - description.listAppend("Could equip Stooper for +1 drunkenness."); - } - if (shotglass_drink_available) - description.listAppend("1 free 1-drunkenness booze available."); - subentries.listAppend(ChecklistSubentryMake(title, "", description)); - } else if (availableDrunkenness() == -1 && could_equip_stooper) { - importance = -11; - title = HTMLGenerateSpanFont("Equip the Stooper", "red"); - image_name = "__familiar stooper"; - description.listAppend("Can keep adventuring/overdrink further as long as it's equipped."); - subentries.listAppend(ChecklistSubentryMake(title, "", description)); - } - } - if (availableSpleen() > 0) { - if (subentries.count() == 0) - image_name = "__item agua de vida"; - subentries.listAppend(ChecklistSubentryMake(availableSpleen() + " spleen", "", "")); - } - if (subentries.count() == 0) { - image_name = "__skill stomach of steel"; - subentries.listAppend(ChecklistSubentryMake("No organ space available")); - } - - int adventures_lost_due_to_cap = __misc_state_int["adventures lost to rollover"]; - int gain_from_rollover = __misc_state_int["adventures after rollover"] + adventures_lost_due_to_cap - my_adventures(); - - string [int] rollover_description; - rollover_description.listAppend("Will gain " + gain_from_rollover + " adventures if rollover happens now" + (adventures_lost_due_to_cap == 0 ? "" : ", wasting " + adventures_lost_due_to_cap) + "."); - - subentries[subentries.count() - 1].entries.listAppendList(rollover_description); - - resource_entries.listAppend(ChecklistEntryMake(image_name, "inventory.php?which=1", subentries, importance).ChecklistEntrySetIDTag("Organs consumption consumables")); - } - - if (__quest_state["Level 13"].state_boolean["king waiting to be freed"]) { - string [int] description; - description.listAppend("Contains one (1) monarch."); - description.listAppend(pluralise(my_ascensions(), "king", "kings") + " freed." + (my_ascensions() > 250 ? " Collect them all!" : "")); - string image_name; - image_name = "__effect sleepy"; - resource_entries.listAppend(ChecklistEntryMake(image_name, "place.php?whichplace=nstower", ChecklistSubentryMake("1 Prism", "", description), 10).ChecklistEntrySetIDTag("This is his home now")); - } - - if ((get_property("sidequestOrchardCompleted") == "hippy" || get_property("sidequestOrchardCompleted") == "fratboy") && !get_property_boolean("_hippyMeatCollected") && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) { - resource_entries.listAppend(ChecklistEntryMake("__item herbs", "island.php", ChecklistSubentryMake("Meat from the hippy store", "", "~4500 free meat."), 8).ChecklistEntrySetIDTag("Island orchard meat cut")); //FIXME consider shop.php?whichshop=hippy - } - if ((get_property("sidequestArenaCompleted") == "hippy" || get_property("sidequestArenaCompleted") == "fratboy") && !get_property_boolean("concertVisited")) { - string [int] description; - if (get_property("sidequestArenaCompleted") == "hippy") { - if (!__misc_state["familiars temporarily blocked"]) - description.listAppend("+5 familiar weight."); - description.listAppend("Or +20% item."); - if (__misc_state["need to level"]) - description.listAppend("Or +5 stats/fight."); - } else if (get_property("sidequestArenaCompleted") == "fratboy") { - description.listAppend("+40% meat."); - description.listAppend("+50% init."); - description.listAppend("+10% all attributes."); - } - - string url = "bigisland.php?place=concert"; - if (__quest_state["Level 12"].finished) - url = "postwarisland.php?place=concert"; - resource_entries.listAppend(ChecklistEntryMake("__item the legendary beat", url, ChecklistSubentryMake("Arena concert", "20 turns", description), 5).ChecklistEntrySetIDTag("Island arena daily buff")); - } - - if (skill_is_usable($skill[Unaccompanied Miner])) { - int free_digs_available = 5 - get_property_int("_unaccompaniedMinerUsed"); - if (free_digs_available > 0) { - string [int] description; - string url; - - if (__misc_state["hot airport available"]) { - //volcano mining - string [int] unmet_requirements; - int heat_resistance = numeric_modifier("Hot Resistance"); - - if (lookupItem("High-temperature mining drill").equipped_amount() == 0) { - if (lookupItem("High-temperature mining drill").available_amount() > 0) { - unmet_requirements.listAppend("to equip high-temperature mining drill"); - if (url == "") url = "inventory.php?ftext=high-temperature+mining+drill"; - } else { - unmet_requirements.listAppend("to acquire a high-temperature mining drill"); - if (url == "") url = "inventory.php?ftext=broken+high-temperature+mining+drill"; // won't bother looking at if they have the broken drill, they can figure it out - } - } - - if (heat_resistance < 15) - unmet_requirements.listAppend("15 hot resist (have " + heat_resistance + ")"); - - if (url == "") url = "mining.php?mine=6"; - - description.listAppend("Can mine in the velvet/gold mine" + (unmet_requirements.count() > 0 ? " (Need " + listJoinComponents(unmet_requirements, ", ", "and") + ")" : "" ) + "."); - } - - if (get_property_boolean("mapToAnemoneMinePurchased")) { //name is misleading; they are set to true even if this is the zone you automatically get access to based on your class - if (lookupItem("Mer-kin digpick").equipped_amount() > 0) { - if (url == "") url = "mining.php?mine=3"; - description.listAppend("Anemone Mine (free even without fishy)."); - } else if (lookupItem("Mer-kin digpick").available_amount() > 0) { - description.listAppend("Equip a Mer-kin digpick to mine in Anemone Mine (won't need fishy)."); - if (url == "") url = "inventory.php?ftext=Mer-kin+digpick"; - } else { - description.listAppend("Buy and equip a Mer-kin digpick from the mall to mine in Anemone Mine."); - if (url == "") url = "mall.php?justitems=0&pudnuggler=%22Mer-kin+digpick%22"; - } - } else if (!get_property_boolean("bigBrotherRescued")) { - if (!(__misc_state["in run"] && get_property("questS02Monkees") == "unstarted")) - description.listAppend("Could progress sea quest" + (my_primestat() != $stat[muscle] ? " (+ pay 50 sand dollars)" : "") + " to unlock Anemone Mine."); - } else { - if (my_primestat() == $stat[muscle]) { - description.listAppend("Talk to little brother to unlock Anemone Mine."); - if (url == "") url = "seafloor.php"; - } else { - description.listAppend("Unlock Anemone Mine by buying the map from big brother (50 sand dollars, have " + $item[sand dollar].available_amount() + ")."); - if (url == "") url = "seafloor.php"; - } - } - - - string [int] available_basic_mines_message; - string available_basic_mines_url; - - if (get_property("questL08Trapper") != "unstarted") { // is it the only way/a sure way to know? - available_basic_mines_message.listAppend("Itznotyerzitz Mine"); - if (get_property("questL08Trapper") == "started") { - available_basic_mines_message.listAppend(" (Talk to Trapper first)"); - if (url == "") url = "place.php?whichplace=mclargehuge"; - } - if (available_basic_mines_url == "") available_basic_mines_url = "mining.php?mine=1"; - } - if (lookupItem("Cobb's Knob lab key").available_amount() > 0) { - available_basic_mines_message.listAppend("The Knob Shaft (last resort)"); - if (available_basic_mines_url == "") available_basic_mines_url = "mining.php?mine=2"; - } - - if (available_basic_mines_message.count() > 0) { // Have access to either, or both - string help_message; - if (lookupEffect("Earthen Fist").have_effect() == 0 && !is_wearing_outfit("Mining Gear") && !is_wearing_outfit("Dwarvish War Uniform")) { - if (lookupSkill("Worldpunch").have_skill()) { - help_message += " (cast Worldpunch)"; // this is from an avatar path, so you'll never get both Unaccompanied miner AND worldpunch, right? Eh, whatever, you can still get the fist effect from hookah-like... - if (url == "") url = "skillz.php"; - } else if (can_equip_outfit("Mining Gear")) { - help_message += " (equip mining gear)"; - if (url == "") url = "inventory.php?which=2"; - } else if (can_equip_outfit("Dwarvish War Uniform")) { - help_message += " (equip Dwarvish War Uniform)"; - if (url == "") url = "inventory.php?which=2"; - } else - help_message += " (need proper equipment)"; - } else - if (url == "") url = available_basic_mines_url; - - description.listAppend("Can mine in " + listJoinComponents(available_basic_mines_message, " ", "or") + "." + HTMLGenerateIndentedText(help_message)); - } - - - resource_entries.listAppend(ChecklistEntryMake("__item 7-Foot Dwarven mattock", url, ChecklistSubentryMake( free_digs_available + " free minings", "", description), 5).ChecklistEntrySetIDTag("Unaccompanied miner resource")); - } - } - - //Not sure how I feel about this. It's kind of extraneous? - if (get_property_int("telescopeUpgrades") > 0 && !get_property_boolean("telescopeLookedHigh") && __misc_state["in run"] && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING && !in_bad_moon() && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_G_LOVER && my_path().id != PATH_WEREPROFESSOR) { - string [int] description; - int percentage = 5 * get_property_int("telescopeUpgrades"); - description.listAppend("+" + (percentage == 25 ? "35% or +25" : percentage) + "% to all attributes. (10 turns)"); - resource_entries.listAppend(ChecklistEntryMake("__effect Starry-Eyed", "campground.php?action=telescope", ChecklistSubentryMake("Telescope buff", "", description), 10).ChecklistEntrySetIDTag("Telescope buff resource")); - } - - - if (__misc_state_int["free rests remaining"] > 0) { - ChecklistEntry entry; - entry.image_lookup_name = "__effect sleepy"; - entry.tags.id = "Campground free rests resource"; - entry.importance_level = 10; - - //Build the entries in an order dependant on user preferences - boolean go_chateau = get_property_boolean("restUsingChateau"); - boolean go_away = get_property_boolean("restUsingCampAwayTent"); - string [int] order; - order [go_chateau ? 0 : 1] = "Chateau Mantegna"; - order [go_chateau ? 1 : 0] = go_away ? "Getaway Campsite" : "Your Campsite"; - order [2] = go_away ? "Your Campsite" : "Getaway Campsite"; - - - string [int] url; - ChecklistSubentry [int] subentries_handle; - string [int] description; - - foreach i, loc in order { - ChecklistSubentry subentry; - switch { - case loc == "Chateau Mantegna" && __misc_state["Chateau Mantegna available"]: - subentry.header = "At your Chateau Mantegna:"; - url.listAppend(__misc_state_string["resting url Chateau Mantegna"]); - - stat nightstand_stat = $stat[none]; - int [item] chateau = get_chateau(); - - if (chateau[$item[electric muscle stimulator]] > 0) - nightstand_stat = $stat[muscle]; - else if (chateau[$item[foreign language tapes]] > 0) - nightstand_stat = $stat[mysticality]; - else if (chateau[$item[bowl of potpourri]] > 0) - nightstand_stat = $stat[moxie]; - - string nightstand_message; - if (nightstand_stat != $stat[none] && my_path().id != PATH_THE_SOURCE) { - float experience_multiplier = (100 + numeric_modifier(nightstand_stat + " Experience Percent")) / 100; - int nightstand_statgain = clampi(12 * my_level(), 0, 100) * experience_multiplier; - nightstand_message = ", " + nightstand_statgain + " " + nightstand_stat + " stats"; - } - - subentry.entries.listAppend("250 HP, 125 MP" + nightstand_message + "."); - - if (my_level() < 9 && my_path().id != PATH_THE_SOURCE) - subentry.entries.listAppend("May want to wait until level 9(?) for more stats from resting."); - - item [int] items_equipping = generateEquipmentToEquipForExtraExperienceOnStat(nightstand_stat); - if (items_equipping.count() > 0 && __misc_state["need to level"]) - subentry.entries.listAppend("Could equip " + items_equipping.listJoinComponents(", ", "or") + " for more stats."); - - subentries_handle.listAppend(subentry); - break; - case loc == "Getaway Campsite" && __misc_state["Getaway Campsite available"]: - subentry.header = "At your Getaway Campsite:"; - url.listAppend(__misc_state_string["resting url Getaway Campsite"]); - - int tent_decoration = get_property_int("campAwayDecoration"); - effect tent_decoration_effect = $effect[none]; //Not actually used... - string tent_decoration_stat; - - switch (tent_decoration) { - case 1: - tent_decoration_effect = $effect[Muscular Intentions]; - tent_decoration_stat = "muscle"; - break; - case 2: - tent_decoration_effect = $effect[Mystical Intentions]; - tent_decoration_stat = "myst"; - break; - case 3: - tent_decoration_effect = $effect[Moxious Intentions]; - tent_decoration_stat = "moxie"; - break; - } - - subentry.entries.listAppend("250 HP, 125 MP, removes negative effects."); - - if (tent_decoration != 0) - subentry.entries.listAppend("Gives 20 turns of +3 " + tent_decoration_stat + " stats/fight."); - - subentries_handle.listAppend(subentry); - break; - case loc == "Your Campsite" && __misc_state["recommend resting at campsite"]: - subentry.header = "At your Campsite:"; - url.listAppend(__misc_state_string["resting url campsite"]); - - subentry.entries.listAppend(__misc_state_int["rest hp restore"] + " HP, " + __misc_state_int["rest mp restore"] + " MP."); - if ($item[pantsgiving].available_amount() > 0) { - if ($item[pantsgiving].equipped_amount() == 0) - subentry.entries.listAppend("Wear pantsgiving for extra HP/MP."); - if (availableFullness() > 0) - subentry.entries.listAppend("Eat more for +" + (availableFullness() * 5) + " extra HP/MP."); - } - - if (__resting_bonuses.count() > 0) { - boolean saw_a_limit; - string [int] bonus_messages; - foreach source, bonus in __resting_bonuses { - string message; - - if (source == $item[Confusing LED clock] && my_adventures() < 5) - continue; //won't activate - - if (bonus.duration > 0) { - if (source == $item[Lucky cat statue]) //SETS the remaining duration of that effect to 5 adv - message += pluralise(bonus.duration - bonus.given_effect.have_effect(), "turn", "turns") + " of "; - else if (bonus.tasteful && bonus.given_effect.have_effect() > 1) - continue; //won't activate - else - message += bonus.duration.pluralise("turn", "turns") + " of "; - } - - message += bonus.given_effect == $effect[none] ? bonus.header : bonus.given_effect + " (" + bonus.header + ")"; - - if (bonus.limit > 0) { - saw_a_limit = true; - message += ", " + bonus.limit + (bonus.limit > 1 ? "x" : "") + "/day"; - } - - //if (bonus.tasteful) //player should already be well aware of this; not relevant - // message += ", breaks after 3-5 uses"; - - message += "."; - - bonus_messages.listAppend(message); - } - - if (saw_a_limit) //tell the player that the tiles don't mean that the buffs are still obtainable today; we can't know if they reached the limits - subentry.modifiers.listAppend("Can't tell if you got them, sorry..."); - - if (bonus_messages.count() > 1) - subentry.entries.listAppend("Will give:" + HTMLGenerateIndentedText(bonus_messages.listJoinComponents("
"))); - else if (bonus_messages.count() == 1) - subentry.entries.listAppend("Will give " + bonus_messages[0]); - } - - subentries_handle.listAppend(subentry); - break; - } - } - - entry.url = url [0]; - - if (subentries_handle.count() > 1) { - entry.should_indent_after_first_subentry = true; //that feature is awesome! - entry.subentries = subentries_handle; - entry.subentries.listPrepend(ChecklistSubentryMake(pluralise(__misc_state_int["free rests remaining"], "free rest", "free rests"))); //entire entry acts as a "title" - } else if (subentries_handle.count() == 1) - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(__misc_state_int["free rests remaining"], "free rest", "free rests"), "", subentries_handle[0].entries)); - - resource_entries.listAppend(entry); - } - - if (__quest_state["Sea Monkees"].finished && !get_property_boolean("_momFoodReceived")) { - //FIXME Detect if they can breathe underwater, to go meet her - string [int] description; - - if (__misc_state["in run"]) { //who knows... - string [int] elemental_buffs; - elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Hot Sweat", "r_element_hot")); - elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Cold Sweat", "r_element_cold")); - elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Rank Sweat", "r_element_stench")); - elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Black Sweat", "r_element_spooky")); - elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Flop Sweat", "r_element_sleaze")); - - description.listAppend("" + elemental_buffs.listJoinComponents(" / ") + ": +7 X resistance."); - } - - description.listAppend("Mark of Candy Cain: +20% critical & spell critical hit."); - description.listAppend("Cereal Killer: +200 stats/fight."); - - resource_entries.listAppend(ChecklistEntryMake("Mom Monkey Castle Window", "monkeycastle.php?who=4", ChecklistSubentryMake('Have Mom "make breakfast"', "50 turns", description), 5).ChecklistEntrySetIDTag("Mom sea monkey resource")); - } - - if (true) { - //FIXME Detect if they can breathe underwater - string [string] dailySkateParkBuffs; - - switch (__quest_state["Sea Monkees"].state_string["skate park status"]) { - case "ice": - if (!get_property_boolean("_skateBuff1")) - dailySkateParkBuffs["Lutz, the Ice Skate"] = "Fishy"; - break; - case "roller": - if (!get_property_boolean("_skateBuff2")) - dailySkateParkBuffs["Comet, the Roller Skate"] = "-30% pressure penalty"; - break; - case "peace": - if (!get_property_boolean("_skateBuff3")) - dailySkateParkBuffs["The Bandshell"] = "+1 sand dollar/underwater combat"; - if (!get_property_boolean("_skateBuff4")) - dailySkateParkBuffs["A Merry-Go Round"] = "+25% underwater item"; - if (!get_property_boolean("_skateBuff5")) - dailySkateParkBuffs["The Eclectic Eels"] = "+10 underwater familiar weight"; - break; - } - - if (dailySkateParkBuffs.count() > 0) { - ChecklistEntry entry; - entry.image_lookup_name = "Skate Park"; - entry.url = "sea_skatepark.php"; - entry.tags.id = "Sea skate park buff resource"; - entry.importance_level = 5; - - if (dailySkateParkBuffs.count() > 1) { - entry.subentries.listAppend(ChecklistSubentryMake("Daily Skate Park buffs (30 turns each)")); - entry.should_indent_after_first_subentry = true; //to make it clear(er) that they are not mutually exclusive - foreach whoYouGonnaCall, buff in dailySkateParkBuffs { - entry.subentries.listAppend(ChecklistSubentryMake(whoYouGonnaCall, "", buff)); - } - } else { - foreach whoYouGonnaCall, buff in dailySkateParkBuffs //We know there's only 1 key, but I think it's the only way to get it? - entry.subentries.listAppend(ChecklistSubentryMake("Daily Skate Park buff (30 turns)", "", HTMLGenerateSpanOfClass(whoYouGonnaCall, "r_bold") + ": " + buff)); - } - - resource_entries.listAppend(entry); - } - } - - if (my_path().id != PATH_BEES_HATE_YOU && !get_property_boolean("guyMadeOfBeesDefeated") && get_property_int("guyMadeOfBeesCount") > 0 && (__misc_state["in aftercore"] || !__quest_state["Level 12"].state_boolean["Arena Finished"])) { - //Not really worthwhile? But I suppose we can track it if they've started it, and are either in aftercore or haven't flyered yet. - //For flyering, it's 20 turns at -25%, 25 turns at -15%. 33 turns at -5%. Not worthwhile? - int summon_count = get_property_int("guyMadeOfBeesCount"); - - string [int] description; - string times = ""; - if (summon_count == 4) - times = "One More Time."; - else - times = int_to_wordy(5 - summon_count) + " times."; - description.listAppend("Speak his name " + times); - if ($item[antique hand mirror].available_amount() == 0) - description.listAppend("Need antique hand mirror to win. Or towerkill."); - resource_entries.listAppend(ChecklistEntryMake("__item guy made of bee pollen", $location[the haunted bathroom].getClickableURLForLocation(), ChecklistSubentryMake("The Guy Made Of Bees", "", description), 10).ChecklistEntrySetIDTag("Guy made of bees")); - } - - if (stills_available() > 0) { - string [int] description; - string [int] mixables; - if (__misc_state["can drink just about anything"] && my_path().id != PATH_SLOW_AND_STEADY) { - mixables.listAppend("neuromancer-level drinks"); - } - mixables.listAppend("~40MP from tonic water"); - - description.listAppend(mixables.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); - - resource_entries.listAppend(ChecklistEntryMake("Superhuman Cocktailcrafting", "shop.php?whichshop=still", ChecklistSubentryMake(pluralise(stills_available(), "still use", "still uses"), "", description), 10).ChecklistEntrySetIDTag("Nash crosby still resource")); - } - - if (__last_adventure_location == $location[The Red Queen\'s Garden]) { - string will_need_effect = ""; - if ($effect[down the rabbit hole].have_effect() == 0) - will_need_effect = "|Will need to use "DRINK ME" potion first."; - if (get_property_int("pendingMapReflections") > 0) - resource_entries.listAppend(ChecklistEntryMake("__item reflection of a map", "place.php?whichplace=rabbithole", ChecklistSubentryMake(pluralise(get_property_int("pendingMapReflections"), "pending reflection of a map", "pending reflections of a map"), "+900% item", "Adventure in the Red Queen's garden to acquire." + will_need_effect), 0).ChecklistEntrySetIDTag("Rabbit hole map reflections future")); - if ($items[reflection of a map].available_amount() > 0) { - resource_entries.listAppend(ChecklistEntryMake("__item reflection of a map", "inventory.php?ftext=reflection+of+a+map", ChecklistSubentryMake(pluralise($item[reflection of a map]), "", "Queen cookies." + will_need_effect), 0).ChecklistEntrySetIDTag("Rabbit hole map reflections resource")); - } - } - - if (__misc_state["VIP available"]) { - if (!get_property_boolean("_lookingGlass") && $item[Clan looking glass].is_unrestricted()) { - resource_entries.listAppend(ChecklistEntryMake("__item "DRINK ME" potion", "clan_viplounge.php?whichfloor=2", ChecklistSubentryMake("A gaze into the looking glass", "", "Acquire a " + $item["DRINK ME" potion] + "."), 10).ChecklistEntrySetIDTag("VIP mirror gaze resource")); - } - //_deluxeKlawSummons? - //_crimboTree? - int soaks_remaining = __misc_state_int["hot tub soaks remaining"]; - if (__misc_state["in run"] && soaks_remaining > 0 && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING && my_path().id != PATH_VAMPIRE) { - string description = "Restore all HP, removes most bad effects."; - resource_entries.listAppend(ChecklistEntryMake("__effect blessing of squirtlcthulli", "clan_viplounge.php", ChecklistSubentryMake(pluralise(soaks_remaining, "hot tub soak", "hot tub soaks"), "", description), 8).ChecklistEntrySetIDTag("VIP hot tub soaks resource")); - } - - - } - //_klawSummons? - - //Skill books we have used, but don't have the skill for? - - //soul sauce tracking? - - if ($item[can of rain-doh].available_amount() > 0 && $item[empty rain-doh can].available_amount() == 0 && __misc_state["in run"]) { - resource_entries.listAppend(ChecklistEntryMake("__item can of rain-doh", "inventory.php?ftext=can+of+rain-doh", ChecklistSubentryMake("Can of Rain-Doh", "", "Open it!"), 0).ChecklistEntrySetIDTag("Can of rain-doh resource")); - } - - - - if (get_property_int("goldenMrAccessories") > 0) { - //FIXME inline with hugs - int total_casts_available = get_property_int("goldenMrAccessories") * 5; - int casts_used = get_property_int("_smilesOfMrA"); - - int casts_remaining = total_casts_available - casts_used; - - if (casts_remaining > 0) { - string image_name = "__item Golden Mr. Accessory"; - if (my_id() == 1043600) - image_name = "__item defective Golden Mr. Accessory"; //does not technically give out sunshine, but... - resource_entries.listAppend(ChecklistEntryMake(image_name, "skills.php", ChecklistSubentryMake(pluralise(casts_remaining, "smile of the Mr. Accessory", "smiles of the Mr. Accessory"), "", "Give away sunshine."), 8).ChecklistEntrySetIDTag("Smile of Mr A heart")); - } - } - - if ( __iotms_usable[$item[Chateau Mantegna room key]] && !get_property_boolean("_chateauDeskHarvested")) { - string image_name = "__item fancy calligraphy pen"; - resource_entries.listAppend(ChecklistEntryMake(image_name, "place.php?whichplace=chateau", ChecklistSubentryMake("Chateau desk openable", "", "Daily collectable."), 8).ChecklistEntrySetIDTag("Chateau Mantegna desk resource")); - } - - if (!get_property_boolean("_lyleFavored") && my_path().id != PATH_G_LOVER) { - string image_name = "__effect favored by lyle"; - string description = $effect[Favored by Lyle].have_effect() > 0 ? "Increases duration of Favored by Lyle." : "+10% all attributes."; - resource_entries.listAppend(ChecklistEntryMake(image_name, "place.php?whichplace=monorail", ChecklistSubentryMake("Visit Lyle", "10 turns", description), 10).ChecklistEntrySetIDTag("Lyle favored resource")); - } - - checklists.listAppend(ChecklistMake("Resources", resource_entries)); -} diff --git a/Source/relay/TourGuide/Items of the Month/2009/Sugar.ash b/Source/relay/TourGuide/Items of the Month/2009/Sugar.ash deleted file mode 100644 index 2216dfd6..00000000 --- a/Source/relay/TourGuide/Items of the Month/2009/Sugar.ash +++ /dev/null @@ -1,53 +0,0 @@ - -void SugarGenerateSuggestions(string [int] suggestions) -{ - if (!__misc_state["in run"]) - return; - if ($item[sugar shield].available_amount() == 0 && $item[snow suit].available_amount() == 0) - suggestions.listAppend("Sugar shield: +10 familiar weight equip"); - if ($item[sugar chapeau].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["past tower monsters"]) - suggestions.listAppend("Sugar chapeau: +50% spell damage (tower killing)"); -} - -RegisterResourceGenerationFunction("IOTMSugarGenerateResource"); -void IOTMSugarGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!$item[sugar sheet].is_unrestricted()) - return; - item [int] sugar_crafted_items; - for i from 4178 to 4183 - { - sugar_crafted_items.listAppend(i.to_item()); - } - ChecklistSubentry [int] subentries; - TagGroup tags; - tags.id = "Sugar sheet folding resource"; - - string image_name = ""; - - if ($item[sugar sheet].available_amount() > 0 && __misc_state["in run"] && in_ronin()) - { - string [int] suggestions; - SugarGenerateSuggestions(suggestions); - subentries.listAppend(ChecklistSubentryMake(pluralise($item[sugar sheet]), "", suggestions)); - - image_name = "sugar sheet"; - } - foreach key in sugar_crafted_items - { - item it = sugar_crafted_items[key]; - if (it.available_amount() == 0) - continue; - int counter = get_property_int("sugarCounter" + it.to_int()); - if (counter == 0 && (!__misc_state["in run"] || !in_ronin())) //in aftercore, probably not as relevant - continue; - int combats_left = 31 - counter; - subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", pluralise(combats_left, "combat", "combats") + " left.")); - if (image_name.length() == 0) - image_name = it; - } - if (subentries.count() > 0) - { - resource_entries.listAppend(ChecklistEntryMake(image_name, "", subentries, 10)); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2010/Crown of Thrones.ash b/Source/relay/TourGuide/Items of the Month/2010/Crown of Thrones.ash deleted file mode 100644 index d7d4f3eb..00000000 --- a/Source/relay/TourGuide/Items of the Month/2010/Crown of Thrones.ash +++ /dev/null @@ -1,316 +0,0 @@ -Record COTSuggestion -{ - string reason; - familiar [int] familiars; -}; - - -COTSuggestion COTSuggestionMake(string reason, familiar [int] familiars) -{ - COTSuggestion suggestion; - suggestion.reason = reason; - suggestion.familiars = familiars; - - return suggestion; -} - -COTSuggestion COTSuggestionMake(string reason, familiar f) -{ - familiar [int] familiar_list; - familiar_list.listAppend(f); - return COTSuggestionMake(reason, familiar_list); -} - -COTSuggestion COTSuggestionMake(string reason, boolean [familiar] familiars_in) -{ - familiar [int] familiars_out; - foreach f in familiars_in - familiars_out.listAppend(f); - return COTSuggestionMake(reason, familiars_out); -} - -void listAppend(COTSuggestion [int] list, COTSuggestion entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - - -//Follows in order. If we can't find one in the first set, we check the second, then third, etc. -//This allows for supporting +25% meat, then falling back on +20%, etc. -Record COTSuggestionSet -{ - COTSuggestion [int] suggestions; -}; - -COTSuggestionSet COTSuggestionSetMake(COTSuggestion [int] suggestions) -{ - COTSuggestionSet suggestion_set; - suggestion_set.suggestions = suggestions; - - return suggestion_set; -} - -COTSuggestionSet COTSuggestionSetMake(COTSuggestion suggestion) -{ - COTSuggestionSet suggestion_set; - suggestion_set.suggestions.listAppend(suggestion); - - return suggestion_set; -} - -void listAppend(COTSuggestionSet [int] list, COTSuggestionSet entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - - -void IOTMCOTGenerateSuggestions(string [int] description) -{ - familiar enthroned_familiar = my_enthroned_familiar(); - familiar bjorned_familiar = my_bjorned_familiar(); - //Suggest what it offers: - COTSuggestionSet [int] suggestion_sets; - - boolean have_two_available = false; - if ($item[crown of thrones].available_amount() > 0 && $item[Buddy Bjorn].available_amount() > 0) - have_two_available = true; - - //Relevant: - //+10ML - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+10 ML and +MP regen", $familiar[el vibrato megadrone]))); - //+15% item drops, or +10% - if (true) { - COTSuggestion [int] suggestions; - suggestions.listAppend(COTSuggestionMake("+15% items", $familiars[li'l xenomorph, feral kobold])); - suggestions.listAppend(COTSuggestionMake("+10% items", $familiars[Reassembled Blackbird,Reconstituted Crow,Oily Woim])); - suggestion_sets.listAppend(COTSuggestionSetMake(suggestions)); - } - //+2 moxie/muscle/mysticality stats/fight - if (__misc_state["need to level"]) { - if (my_primestat() == $stat[moxie]) { - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+2 mainstat/fight", $familiars[blood-faced volleyball,jill-o-lantern, nervous tick,mariachi chihuahua, cymbal-playing monkey,hovering skull]))); - } else if (my_primestat() == $stat[mysticality]) { - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+2 mainstat/fight", $familiars[reanimated reanimator,dramatic hedgehog,cheshire bat,pygmy bugbear shaman,hovering sombrero,sugar fruit fairy, uniclops]))); - } else if (my_primestat() == $stat[muscle]) { - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+2 mainstat/fight", $familiars[hunchbacked minion, killer bee, grinning turtle,chauvinist pig, baby mutant rattlesnake]))); - } - } - //+25% / +20% meat from monsters - if (true) { - COTSuggestion [int] suggestions; - suggestions.listAppend(COTSuggestionMake("+25% meat", $familiars[Knob Goblin Organ Grinder,Happy Medium,Hobo Monkey])); - suggestions.listAppend(COTSuggestionMake("+20% meat", $familiars[Dancing Frog,Psychedelic Bear,Hippo Ballerina,Attention-Deficit Demon,Piano Cat,Coffee Pixie,Obtuse Angel,Hand Turkey,Leprechaun,Grouper Groupie,Mutant Cactus Bud,Jitterbug,Casagnova Gnome])); - suggestion_sets.listAppend(COTSuggestionSetMake(suggestions)); - } - //+5 to familiar weight - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+5 familiar weight", $familiars[Gelatinous Cubeling,Pair of Ragged Claws,Spooky Pirate Skeleton,Autonomous Disco Ball,Ghost Pickle on a Stick,Misshapen Animal Skeleton,Animated Macaroni Duck,Penguin Goodfella,Barrrnacle]))); - //+20% to combat init - if (__misc_state["in run"]) - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+20% init", $familiars[Teddy Bear,Emo Squid,Evil Teddy Bear,Syncopated Turtle,Untamed Turtle,Mini-Skulldozer,Cotton Candy Carnie,Origami Towel Crane,Feather Boa Constrictor,Levitating Potato,Temporal Riftlet,Squamous Gibberer,Cuddlefish,Teddy Borg]))); - //+15% to moxie/muscle/mysticality - if (__misc_state["in run"]) { - if (true) { - //Either scaling monster levelling, or the NS - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+15% moxie", $familiars[Ninja Snowflake,Nosy Nose,Clockwork Grapefruit,Sabre-Toothed Lime]))); - } - if (my_primestat() == $stat[mysticality] && __misc_state["need to level"]) { - //Scaling monster levelling - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+15% mysticality", $familiars[Ragamuffin Imp,Inflatable Dodecapede,Scary Death Orb,Snowy Owl,grue]))); - } else if (my_primestat() == $stat[muscle] && __misc_state["need to level"]) { - //Scaling monster levelling - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+15% muscle", $familiars[MagiMechTech MicroMechaMech,Angry Goat,Wereturtle,Stab Bat,Wind-up Chattering Teeth,Imitation Crab]))); - } - } - //+20%/+15%/+10% to spell damage - //Too marginal? - /*if (__misc_state["in run"]) { - COTSuggestion [int] suggestions; - suggestions.listAppend(COTSuggestionMake("+20% spell damage", $familiar[mechanical songbird])); - suggestions.listAppend(COTSuggestionMake("+15% spell damage", $familiars[Magic Dragonfish,Pet Cheezling,Rock Lobster])); - suggestions.listAppend(COTSuggestionMake("+10% spell damage", $familiars[Midget Clownfish,Star Starfish,Baby Yeti,Snow Angel,Wizard Action Figure,Dataspider,Underworld Bonsai,Whirling Maple Leaf,Rogue Program,Howling Balloon Monkey])); - suggestion_sets.listAppend(COTSuggestionSetMake(suggestions)); - }*/ - //hot wings from reanimator - if (true) { - string [int] reanimator_reasons; - - if (__quest_state["Pirate Quest"].state_boolean["need more hot wings"]) - reanimator_reasons.listAppend("hot wings"); - - if (reanimator_reasons.count() > 0) - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake(reanimator_reasons.listJoinComponents(", ").capitaliseFirstLetter(), $familiar[reanimated reanimator]))); - } - if (__misc_state["in run"]) - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("50% block", $familiar[Mariachi Chihuahua]))); - - //knob mushrooms from badger - if (__misc_state["in run"] && __misc_state["can eat just about anything"]) - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("Knob mushrooms", $familiar[astral badger]))); - - boolean need_cold_res = false; - boolean need_all_res = false; - //At a-boo peak, but not finished with it: - if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0 && __quest_state["Level 9"].state_boolean["bridge complete"]) - need_all_res = true; - //Climbing the peak: - if (__quest_state["Level 8"].state_boolean["Past mine"] && !__quest_state["Level 8"].state_boolean["Groar defeated"] && numeric_modifier("cold resistance") < 5.0) - need_cold_res = true; - - if (__misc_state["in run"] && need_cold_res) - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+3 cold res", $familiar[Flaming Face]))); - if (need_cold_res && !$familiar[flaming face].have_familiar_replacement()) - need_all_res = true; - if (__misc_state["in run"] && need_all_res) - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+2 all res", $familiars[Bulky Buddy Box,Exotic Parrot,Holiday Log,Pet Rock,Toothsome Rock]))); - - //if (__misc_state["in run"] && availableSpleen() >= 4) - //suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("Spleen items", $familiar[Grim Brother]))); - - //slightly powerful: - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+combat", $familiar[Grim Brother]))); - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("-combat", $familiar[Grimstone Golem]))); - - if (get_property_int("_grimstoneMaskDropsCrown") == 0) - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("Grimstone mask", $familiar[Grimstone Golem]))); - if (get_property_int("_grimFairyTaleDropsCrown") < 2 && !(__misc_state["in run"] && spleen_limit() == 0)) - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake(pluraliseWordy(clampi(2 - get_property_int("_grimFairyTaleDropsCrown"), 0, 2), "spleen item", "spleen items").capitaliseFirstLetter(), $familiar[grim Brother]))); - - if ($item[blackberry].available_amount() < 3 && $item[blackberry galoshes].available_amount() == 0 && __quest_state["Level 11"].mafia_internal_step < 2) - suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("Blackberries for galoshes", $familiars[reassembled blackbird,reconstituted crow]))); - string [int][int] familiar_options; - foreach key in suggestion_sets { - boolean found_relevant = false; - COTSuggestionSet suggestion_set = suggestion_sets[key]; - foreach key2 in suggestion_set.suggestions { - //Suggest the familiar with the highest weight, under the assumption they're using it more. - COTSuggestion suggestion = suggestion_set.suggestions[key2]; - familiar best_familiar_by_weight = $familiar[none]; - familiar second_best_familiar_by_weight = $familiar[none]; - foreach key3 in suggestion.familiars { - familiar f = suggestion.familiars[key3]; - if (f == $familiar[none]) //didn't find it - continue; - if (f.have_familiar_replacement()) { - if ((best_familiar_by_weight != enthroned_familiar || enthroned_familiar == $familiar[none]) && (best_familiar_by_weight == $familiar[none] || f.familiar_weight() > best_familiar_by_weight.familiar_weight() || f == enthroned_familiar)) { - second_best_familiar_by_weight = best_familiar_by_weight; - best_familiar_by_weight = f; - } else if (second_best_familiar_by_weight == $familiar[none] || f.familiar_weight() > second_best_familiar_by_weight.familiar_weight()) { - if (best_familiar_by_weight != f) - second_best_familiar_by_weight = f; - } - } - } - if (best_familiar_by_weight != $familiar[none]) { - string familiar_string; - - familiar_string = best_familiar_by_weight; - if ((enthroned_familiar == best_familiar_by_weight && enthroned_familiar != $familiar[none]) || (bjorned_familiar == best_familiar_by_weight && bjorned_familiar != $familiar[none])) - familiar_string = HTMLGenerateSpanOfClass(best_familiar_by_weight, "r_bold"); - - if (second_best_familiar_by_weight != $familiar[none] && have_two_available) - familiar_string += "|" + second_best_familiar_by_weight; - familiar_options.listAppend(listMake(suggestion.reason, familiar_string)); - break; - } - } - } - if (familiar_options.count() > 0) - description.listAppend(HTMLGenerateSimpleTableLines(familiar_options)); -} - -RegisterResourceGenerationFunction("IOTMCOTGenerateResource"); -void IOTMCOTGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[crown of thrones].available_amount() == 0 && $item[Buddy Bjorn].available_amount() == 0) - return; - if (__misc_state["familiars temporarily blocked"]) //avatar paths - return; - string [int] description; - - void addFamiliarDropsLine(string fam, string prop, int limit, string dropdesc) { - int currentDrops = get_property_int(prop); - familiar thisFam = fam.to_familiar(); - if ( !thisFam.have_familiar() ) { return; } - string txtclr = ""; - if ( fam.index_of("Stomping") > -1 ) { - txtclr = (get_property_boolean("bootsCharged"))?"blue":"black"; - } - if ( currentDrops == limit ) { txtclr = "gray"; } - - description.listAppend(HTMLGenerateSpanFont(fam+": "+currentDrops + "/"+limit+" "+dropdesc+".", txtclr)); - return; - } - - description.listAppend(HTMLGenerateSpanFont("Crown/Bjorn-specific drops", "purple")); - addFamiliarDropsLine("Garbage Fire", "_garbageFireDropsCrown", 3, "burning newspapers"); - addFamiliarDropsLine("Grim Brother", "_grimFairyTaleDropsCrown", 2, "grim fairy tales"); - addFamiliarDropsLine("Grimstone Golem", "_grimstoneMaskDropsCrown", 1, "grimstone mask"); - addFamiliarDropsLine("Machine Elf", "_abstractionDropsCrown", 25, "abstractions"); - addFamiliarDropsLine("Optimistic Candle", "_optimisticCandleDropsCrown", 3, "globs of melted wax"); - addFamiliarDropsLine("Ms. Puck Man", "_yellowPixelDropsCrown", 25, "yellow pixels"); - addFamiliarDropsLine("Puck Man", "_yellowPixelDropsCrown", 25, "yellow pixels"); - addFamiliarDropsLine("Trick-or-Treating Tot", "_hoardedCandyDropsCrown", 3, "hoarded candy wads"); - - description.listAppend(HTMLGenerateSpanFont("General familiar drops", "purple")); - addFamiliarDropsLine("Adventurous Spelunker", "_spelunkingTalesDrops", 1, "Tales of Spelunking"); - addFamiliarDropsLine("Astral Badger", "_astralDrops", 5, "astral mushrooms"); - addFamiliarDropsLine("Baby Sandworm", "_aguaDrops", 5, "Agua de Vidae"); - addFamiliarDropsLine("Blavious Kloop", "_kloopDrops", 5, "devlish folios"); - addFamiliarDropsLine("Bloovian Groose", "_grooseDrops", 5, "groose grease"); - addFamiliarDropsLine("Cat Burglar", "_catBurglarCharge", 30, "Heist charges"); - #addFamiliarDropsLine("Cookbookbat", "_turkeyBooze", 5, "Turkey booze"); - addFamiliarDropsLine("Fist Turkey", "_turkeyBooze", 5, "Turkey booze"); - addFamiliarDropsLine("Galloping Grill", "_hotAshesDrops", 5, "hot ashes"); - addFamiliarDropsLine("Golden Monkey", "_powderedGoldDrops", 5, "powdered gold"); - addFamiliarDropsLine("Green Pixie", "_absintheDrops", 5, "bottles of absinthe"); - addFamiliarDropsLine("Grim Brother", "_grimFairyTaleDrops", 5, "grim fairy tales"); - addFamiliarDropsLine("Li'l Xenomorph", "_transponderDrops", 5, "transponders"); - addFamiliarDropsLine("Llama Lama", "_gongDrops", 5, "Llama gongs"); - addFamiliarDropsLine("Puck Man", "_powerPillDrops", 11, "power pills"); - addFamiliarDropsLine("Ms. Puck Man", "_powerPillDrops", 11, "power pills"); - addFamiliarDropsLine("Rogue Program", "_tokenDrops", 5, "GG tokens"); - addFamiliarDropsLine("Stomping Boots", "_pasteDrops", 7, "spleen pastes"); - addFamiliarDropsLine("Unconscious Collective", "_dreamJarDrops", 5, "dream jars"); - item crown_item = $item[crown of thrones]; - if (crown_item.equipped_amount() == 0 && $item[Buddy Bjorn].available_amount() > 0) - crown_item = $item[Buddy Bjorn]; - - string image_name = "__item " + crown_item; - familiar enthroned_familiar = my_enthroned_familiar(); - familiar bjorned_familiar = my_bjorned_familiar(); - - if (($item[crown of thrones].equipped_amount() > 0 || $item[Buddy Bjorn].equipped_amount() > 0) || __misc_state["in run"]) { - IOTMCOTGenerateSuggestions(description); - } - - if (enthroned_familiar != $familiar[none]) { - description.listAppend(enthroned_familiar + " enthroned."); - //image_name = "__familiar " + enthroned_familiar.to_string(); - } - if (bjorned_familiar != $familiar[none]) - description.listAppend(bjorned_familiar + " bjorned."); - //FIXME my_bjorned_familiar() when 16.3 - - string url = "familiar.php"; - if ($item[crown of thrones].equipped_amount() == 0 && $item[Buddy Bjorn].equipped_amount() == 0) - url = "inventory.php?which=2"; - - string header = crown_item; - item [int] available_sources; - - if ($item[Buddy Bjorn].available_amount() > 0) - available_sources.listAppend($item[Buddy Bjorn]); - if ($item[crown of thrones].available_amount() > 0) - available_sources.listAppend($item[crown of thrones]); - if (available_sources.count() > 0) - header = available_sources.listJoinComponents(", ", "and"); - - if (description.count() > 0) - resource_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(header, "", description), 8).ChecklistEntrySetIDTag("Crown of Bjorn/Buddy thrones resource")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2011/Plastic Vampire Fangs.ash b/Source/relay/TourGuide/Items of the Month/2011/Plastic Vampire Fangs.ash deleted file mode 100644 index b377da83..00000000 --- a/Source/relay/TourGuide/Items of the Month/2011/Plastic Vampire Fangs.ash +++ /dev/null @@ -1,131 +0,0 @@ -RegisterResourceGenerationFunction("IOTMPlasticVampireFangsGenerateResource"); -void IOTMPlasticVampireFangsGenerateResource(ChecklistEntry [int] resource_entries) -{ - // Commenting out since the replica is unrestricted. I think ownership handles this. - - // if (!$item[plastic vampire fangs].is_unrestricted()) - // return; - if ($items[replica plastic vampire fangs, plastic vampire fangs, Interview With You (a Vampire)].available_amount() == 0) - return; - item fang_source = $item[plastic vampire fangs]; - string url = ""; - string separator = " " + __html_right_arrow_character + " "; - - // Detect if your access is through the replica, the book, or the O.G. - - if ($item[replica plastic vampire fangs].available_amount() > 0) { - fang_source = $item[replica plastic vampire fangs]; - url = "place.php?whichplace=town"; - if ($item[plastic vampire fangs].equipped_amount() == 0) { - url = "inventory.php?ftext=plastic+vampire+fangs"; - } - } - - else if ($item[Interview With You (a Vampire)].available_amount() > 0) { - fang_source = $item[Interview With You (a Vampire)]; - url = "inventory.php?ftext=interview+with+you"; - } - - else { - url = "place.php?whichplace=town"; - if ($item[plastic vampire fangs].equipped_amount() == 0) { - url = "inventory.php?ftext=plastic+vampire+fangs"; - } - } - - // Show the Isabella interview option if it is valid for the user. - - if (!get_property_boolean("_interviewIsabella") && __misc_state["in run"] && __misc_state["need to level"]) { - string [int] description; - int stats_gained = MIN(500, 4 * my_basestat(my_primestat())) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); - - description.listAppend(stats_gained + " " + my_primestat().to_lower_case() + " gained, one adventure cost."); - if ($item[Interview With You (a Vampire)].available_amount() > 0) { - description.listAppend("Vamp out via Interview With You (a Vampire)."); - } - else { - description.listAppend("Vamp out in Seaside Town, with fangs equipped."); - } - - if (my_primestat() == $stat[muscle]) - description.listAppend("Visit Isabella's" + separator + "Drain Her."); - else if (my_primestat() == $stat[mysticality]) - description.listAppend("Visit Isabella's" + separator + "Tell Her How You Feel" + separator + "Find Other Prey."); - else if (my_primestat() == $stat[moxie]) - description.listAppend("Visit Isabella's" + separator + "Redirect Your Desire" + separator + "Go to the Bar."); - - - resource_entries.listAppend(ChecklistEntryMake("__item " + fang_source, url, ChecklistSubentryMake("Vampire stats", "", description), 5).ChecklistEntrySetIDTag("Plastic vampire fangs Isabella interview")); - - } - - if (!__misc_state["in run"]) { - string [int] description; - if ($item[Interview With You (a Vampire)].available_amount() > 0) { - description.listAppend("Vamp out via Interview With You (a Vampire)."); - } - else { - description.listAppend("Vamp out in Seaside Town, with fangs equipped."); - } - - int vamp_outs_remaining = 0; - - //Disabled, unless there's something useful about these to be reminded of in aftercore: - /*if (!get_property_boolean("_interviewVlad")) { - description.listAppend("Vlad's Boutique - DR or spell damage or weapon damage buff."); - vamp_outs_remaining += 1; - } - if (!get_property_boolean("_interviewIsabella")) { - description.listAppend("Isabella's - mainstat gain, meat."); - vamp_outs_remaining += 1; - }*/ - if (!get_property_boolean("_interviewMasquerade")) { - string [int] masquerade_description; - if ($item[Sword of the Brouhaha Prince].available_amount() == 0) { - string [int] interview_questions = listMake("Warehouse", "Growl", "The Clash", "Motorcycle", "Lager"); - string [int] nomination = listMake("Malkovich", "Torremolinos", "Brouhaha", "Ventrilo"); - string item_name = "Sword of the Brouhaha Prince"; - masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); - } - if ($item[Chalice of the Malkovich Prince].available_amount() == 0) { - string [int] interview_questions = listMake("Laugh Factory", "Giggle", "Glass breaking", "Wheelbarrow", "Blood"); - string [int] nomination = listMake("Torremolinos", "Ventrilo", "Brouhaha", "Malkovich"); - string item_name = "Chalice of the Malkovich Prince"; - - masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); - } - if ($item[Sceptre of the Torremolinos Prince].available_amount() == 0) { - string [int] interview_questions = listMake("Loft", "Flirty", "Mozart", "Carriage", "Absinthe"); - string [int] nomination = listMake("Malkovich", "Ventrilo", "Torremolinos", "Brouhaha"); - string item_name = "Sceptre of the Torremolinos Prince"; - masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); - } - if ($item[Medallion of the Ventrilo Prince].available_amount() == 0) { - string [int] interview_questions = listMake("Penthouse", "Terse", "No time", "Limo", "Espresso"); - string [int] nomination = listMake("Ventrilo", "Malkovich", "Brouhaha", "Torremolinos"); - string item_name = "Medallion of the Ventrilo Prince"; - masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); - } - if (true) { - string [int] interview_questions = listMake("Warehouse", "Growl", "The Clash", "Motorcycle", "Lager"); - string [int] nomination = listMake("Ventrilo", "Brouhaha", "Torremolinos", "Malkovich"); - string item_name = "Your own black heart (restores 100% HP/MP)"; - masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); - } - if ($item[plastic vampire fangs].available_amount() > 0) { - string [int] interview_questions = listMake("Warehouse", "Growl", "The Clash", "Motorcycle", "Lager"); - string [int] nomination = listMake("Ventrilo", "Malkovich", "Torremolinos", "Brouhaha"); - string item_name = "Interview With You (a Vampire)"; - masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); - } - //description.listAppend("The Masquerade." + HTMLGenerateIndentedText(masquerade_description)); - description.listAppendList(masquerade_description); - vamp_outs_remaining += 1; - } - - if (vamp_outs_remaining > 0) { - //resource_entries.listAppend(ChecklistEntryMake("__item " + fang_source, url, ChecklistSubentryMake(pluralise(vamp_outs_remaining, "vamp out", "vamp outs"), "", description), 8)); - resource_entries.listAppend(ChecklistEntryMake("__item " + fang_source, url, ChecklistSubentryMake("Vampire masquerade", "", description), 8).ChecklistEntrySetIDTag("Plastic vampire fangs vamp out resource")); - } - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2013/Psychoanalytic.ash b/Source/relay/TourGuide/Items of the Month/2013/Psychoanalytic.ash deleted file mode 100644 index d1dd1415..00000000 --- a/Source/relay/TourGuide/Items of the Month/2013/Psychoanalytic.ash +++ /dev/null @@ -1,537 +0,0 @@ - - -void IOTMPShadyPastGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - string [int] description; - string [int] modifiers; - - if ($item[White Dragon Fang].available_amount() == 0) - { - boolean can_acquire_taijijian = ($item[strange goggles].available_amount() > 0 || $item[toy taijijian].available_amount() > 0 || !in_ronin()); - if ($item[magical battery].available_amount() > 0 && can_acquire_taijijian) - { - description.listAppend("To make the White Dragon Fang, meatpaste together the toy taijijian with the magical battery."); - } - } - - string last_combat = $location[chinatown tenement].lastCombatInLocation(); - if ($location[chinatown tenement].combat_queue.contains_text("White Bone Demon") && description.count() == 0) //somewhat limited way of detecting that we are finished - return; - if ($item[Test site key].available_amount() > 0) - { - //Last segment: - - int gold_pieces_needed = MAX(0, 30 - $item[gold piece].available_amount()); - if (last_combat == "the server") - { - description.listAppend("Fight the White Bone Demon."); - } - else if (gold_pieces_needed > 0) - { - //at least one gold piece from a desperate gold farmer is under 21.89% drop rate - //needs spading - description.listAppend("Adventure in the chinatown tenement, acquire " + pluralise(gold_pieces_needed, "more gold piece", "more gold pieces") + "."); - modifiers.listAppend("+400%? item"); - - if (__misc_state["have olfaction equivalent"]) - modifiers.listAppend("olfact desperate gold farmer"); - } - else - { - description.listAppend("Adventure in the chinatown tenement, fight the server.|Once the server's panel falls off, use the strange goggles."); - } - } - else if ($item[CEO office card].available_amount() > 0) - { - //Use to see wheels within wheels. - description.listAppend("Use CEO office card."); - } - else if ($items[makeshift yakuza mask,Novelty tattoo sleeves].items_missing().count() == 0) - { - //Visit the first floor. - item [int] equip_items; - foreach it in $items[makeshift yakuza mask,novelty tattoo sleeves] - { - if (it.equipped_amount() == 0) - equip_items.listAppend(it); - } - if (equip_items.count() > 0 && $location[1st floor\, shiawase-mitsuhama building].turnsAttemptedInLocation() == 0) - { - description.listAppend("Equip " + equip_items.listJoinComponents(", ", "and") + "."); - } - else - { - description.listAppend("Adventure on the floors of the Shiawase-Mitsuhama building, acquire and use cards."); - - foreach it in $items[zaibatsu level 2 card, zaibatsu level 3 card] - { - if (it.available_amount() == 0) - continue; - description.listAppend("Use " + it + "."); - } - } - } - else if ($item[strange goggles].available_amount() > 0) - { - //Make yakuza mask. - if ($item[makeshift yakuza mask].available_amount() == 0) - { - string line = "Assemble a makeshift yakuza mask with items from the chinatown shops."; - - item [int] missing_parts_list = missingComponentsToMakeItem($item[makeshift yakuza mask]); - if (missing_parts_list.count() == 0) - line = "Assemble a makeshift yakuza mask.|(rhinoceros horn + rhinoceros horn) + (furry pink pillow + bottle of limeade)"; - else - line += "|Missing " + missing_parts_list.listJoinComponents(", ", "and") + "."; - - description.listAppend(line); - } - if ($item[Novelty tattoo sleeves].available_amount() == 0) - { - description.listAppend("Buy novelty tattoo sleeves from the chinatown shops."); - } - } - else if ($item[zaibatsu lobby card].available_amount() > 0) - { - //Triad factory. - description.listAppend("Adventure in the sewer triad factory, defeat the Sierpinski brothers."); - description.listAppend("Run +item for a possible magical battery."); - modifiers.listAppend("+item"); - } - else - { - //Start of quest. - description.listAppend("Adventure in the Chinatown shops, defeat a yakuza courier."); - } - - - optional_task_entries.listAppend(ChecklistEntryMake("chinatown", "place.php?whichplace=junggate_1", ChecklistSubentryMake("The Suspicious-Looking Guy's Shady Past", modifiers, description),$locations[chinatown shops, chinatown tenement, triad factory,1st floor\, shiawase-mitsuhama building,2nd floor\, shiawase-mitsuhama building,3rd floor\, shiawase-mitsuhama building]).ChecklistEntrySetIDTag("Psychoanalytic jar suspicious-looking guy")); -} - -void IOTMPOldManGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - string [int] description; - string [int] modifiers; - - if ($location[The Old Man's Bathtime Adventures].lastNoncombatInLocation() == "Journey's End") //somewhat limited way of detecting that we are finished - return; - - description.listAppend("Sail the seas. Try to one-hit kill the sea monsters."); - - if ($item[Bloodbath].available_amount() == 0) - description.listAppend("Need to finish the area with 50+ crew to acquire Bloodbath."); - else if ($item[ornamental sextant].available_amount() == 0) - description.listAppend("Need to finish the area with 37+ crew to acquire ornamental sextant."); - else if ($item[miniature deck cannon].available_amount() == 0) - description.listAppend("Need to finish the area with [24 to 36] crew to acquire miniature deck cannon."); - else if ($item[Foam naval trousers].available_amount() == 0) - description.listAppend("Need to finish the area with [24 to 36] crew to acquire Foam naval trousers."); - else if ($item[Foam commodore's hat].available_amount() == 0) - description.listAppend("Need to finish the area with [24 to 36] crew to acquire Foam commodore's hat."); - - description.listAppend("Choose +crew non-combat options, add monsters if you can."); - - - monster olfacted_monster = get_property_monster("olfactedMonster"); - - boolean olfacted_relevant_monster = ($monsters[ferocious roc,giant man-eating shark,Bristled Man-O-War,The Cray-Kin,Deadly Hydra] contains olfacted_monster); - - if (__misc_state["have olfaction equivalent"] && !olfacted_relevant_monster) - { - description.listAppend("Olfact any monster that is not a fearsome giant squid."); - modifiers.listAppend("olfaction"); - } - - if (my_basestat($stat[mysticality]) >= 200) - { - if ($item[Mesmereyes™ contact lenses].equipped_amount() == 0) - { - description.listAppend("Wear " + $item[Mesmereyes™ contact lenses] + "."); - } - } - else - { - if ($item[Attorney's badge].equipped_amount() == 0) - { - description.listAppend("Wear " + $item[Attorney's badge] + "."); - } - description.listAppend("Possibly level mysticality to 200 to wear " + $item[Mesmereyes™ contact lenses] + ", makes this area much easier."); - } - - if ($item[Young Man's Crew Sequester].available_amount() > 0) - description.listAppend("Young Man's Crew Sequester available. (+5 crew)"); - if ($item[Young Man's Cargo Load].available_amount() > 0) - description.listAppend("Young Man's Cargo Load available. (+4 crayons, +16 bubbles)"); - - //very limited potato detection: - if (my_familiar() != $familiar[levitating potato] && !(my_familiar() == $familiar[fancypants scarecrow] && ($slot[familiar].equipped_item() == $item[swashbuckling pants] || $slot[familiar].equipped_item() == $item[spangly mariachi pants])) && !(my_familiar() == $familiar[mad hatrack] && $slot[familiar].equipped_item() == $item[spangly sombrero])) - description.listAppend("Run a potato familiar of some kind."); - - - optional_task_entries.listAppend(ChecklistEntryMake("__item inflatable duck", "", ChecklistSubentryMake("The Old Man's Bathtime Adventure", modifiers, description),$locations[The Old Man's Bathtime Adventures]).ChecklistEntrySetIDTag("Psychoanalytic jar old man")); -} - -void IOTMPMeatGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - string [int] description; - string [int] modifiers; - - if ($location[The Nightmare Meatrealm].lastCombatInLocation() == "The Beefhemoth") //somewhat limited way of detecting that we are finished - return; - - modifiers.listAppend("+meat"); - description.listAppend("Adventure until you find the beefhemoth, defeat him."); - if ($items[the sword in the steak, meatcleaver].available_amount() == 0) - description.listAppend("The Sword in the Steak is from a 0.1% likelyhood non-combat.|To find it, run away from monsters, preferrably with greatest american pants/navel ring of navel gazing."); - if ($item[meatcleaver].available_amount() == 0 && $item[the sword in the steak].available_amount() > 0) - { - if (my_buffedstat($stat[muscle]) < 1000) - description.listAppend("To pull the sword from the steak, buff muscle to 1000."); - else - description.listAppend("Pull the sword from the steak, adventurer."); - } - - - optional_task_entries.listAppend(ChecklistEntryMake("meat", "place.php?whichplace=junggate_6", ChecklistSubentryMake("The Meatsmith's Brainspace", modifiers, description),$locations[The Nightmare Meatrealm]).ChecklistEntrySetIDTag("Psychoanalytic jar meatsmith")); -} - -void IOTMPGourdGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - string [int] description; - string [int] modifiers; - - if ($location[the gourd!].lastCombatInLocation() == "Fnord the Unspeakable") //This should work for termination detection? - return; - - modifiers.listAppend("+item?"); - description.listAppend("Adventure in the gourd."); - if ($item[truthsayer].available_amount() == 0) - { - string [int] components; - boolean [item] items_implicitly_have; - if ($item[loose blade].available_amount() > 0) - { - items_implicitly_have[$item[goblin collarbone]] = true; - items_implicitly_have[$item[sharp tin strip]] = true; - } - if ($item[goblin bone hilt].available_amount() > 0) - { - items_implicitly_have[$item[goblin collarbone]] = true; - items_implicitly_have[$item[wad of spider silk]] = true; - } - if ($item[sticky sword blade].available_amount() > 0) - { - items_implicitly_have[$item[sharp tin strip]] = true; - items_implicitly_have[$item[wad of spider silk]] = true; - } - foreach it in $items[sharp tin strip, wad of spider silk, goblin collarbone] - { - string line = it; - if (it.available_amount() == 0 && !(items_implicitly_have contains it)) - line = HTMLGenerateSpanFont(line, "gray"); - components.listAppend(line); - } - description.listAppend("Truthsayer is (" + components.listJoinComponents(" + ") + "), found from gourd monsters."); - } - - - optional_task_entries.listAppend(ChecklistEntryMake("__item gourd potion", "place.php?whichplace=junggate_2", ChecklistSubentryMake("The Gourd", modifiers, description),$locations[The gourd!]).ChecklistEntrySetIDTag("Psychoanalytic jar gourd")); -} - -void IOTMPCrackpotGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - string [int] description; - string [int] modifiers; - - //Despair, rage, envy. Anger, fear, doubt, regret. - string url = "place.php?whichplace=junggate_3"; - string image_name = "__item red pixel"; - - boolean need_byte_sword = !($item[byte].available_amount() + $item[byte].storage_amount() > 0 || $item[flickering pixel].available_amount() + $item[flickering pixel].storage_amount() >= 8); - - if ($item[flickering pixel].available_amount() == 8) - { - description.listAppend("Use eight flickering pixels to acquire the sword, byte."); - } - - string [int] bosses_remaining; - - if ($location[anger man's level].lastCombatInLocation() != "Anger man") - bosses_remaining.listAppend("anger man"); - if ($location[fear man's level].lastCombatInLocation() != "Fear man") - bosses_remaining.listAppend("fear man"); - if ($location[doubt man's level].lastCombatInLocation() != "Doubt man") - bosses_remaining.listAppend("doubt man"); - if ($location[regret man's level].lastCombatInLocation() != "Regret man") - bosses_remaining.listAppend("regret man"); - - if (bosses_remaining.count() == 0 && description.count() == 0) - return; - - if (__last_adventure_location == $location[anger man's level] && $location[anger man's level].lastCombatInLocation() != "Anger man") - { - description.listAppend("Adventure in anger man's level, defeat the boss."); - string [int] stats_needed_to_complete_zone; - string [int] stats_needed_for_flickering_pixel; - foreach s in $stats[muscle, mysticality, moxie] - { - if (s.my_buffedstat() < 50) - { - stats_needed_to_complete_zone.listAppend(s.to_string().to_lower_case()); - } - if (s.my_buffedstat() < 500) - { - stats_needed_for_flickering_pixel.listAppend(s.to_string().to_lower_case()); - } - } - - float resistance = numeric_modifier("hot resistance"); - int resistance_needed = MAX(0, floor(25 - resistance)); - if (resistance < 25.0 && need_byte_sword) - description.listAppend("Need " + resistance_needed + " more hot resistance for the first flickering pixel."); - - if (stats_needed_to_complete_zone.count() > 0) - description.listAppend("Need 50 " + stats_needed_to_complete_zone.listJoinComponents(", ", "and") + " to pass first test."); - if (stats_needed_for_flickering_pixel.count() > 0 && need_byte_sword) - description.listAppend("Need 500 " + stats_needed_for_flickering_pixel.listJoinComponents(", ", "and") + " for the second flickering pixels."); - - - } - else if (__last_adventure_location == $location[fear man's level] && $location[fear man's level].lastCombatInLocation() != "Fear man") - { - description.listAppend("Adventure in fear man's level, defeat the boss."); - - //50 moxie to complete - //300 moxie for first flickering - //25 spooky res for second flickering - - if (my_buffedstat($stat[moxie]) < 50) - description.listAppend("Need 50 total moxie pass first test."); - - if (my_buffedstat($stat[moxie]) < 300 && need_byte_sword) - description.listAppend("Need 300 total moxie for the first flickering pixel."); - - float resistance = numeric_modifier("spooky resistance"); - int resistance_needed = MAX(0, floor(25 - resistance)); - if (resistance < 25.0 && need_byte_sword) - description.listAppend("Need " + resistance_needed + " more spooky resistance for the second flickering pixel."); - } - else if (__last_adventure_location == $location[doubt man's level] && $location[doubt man's level].lastCombatInLocation() != "Doubt man") - { - description.listAppend("Adventure in doubt man's level, defeat the boss."); - - //weapon damage >= 100 to complete - //HP > 100 to complete - //weapon damage >= 276(?) for first flickering - //HP >= 1000 for second flickering - - int weapon_damage = numeric_modifier("weapon damage").floor(); - if (weapon_damage < 100) - description.listAppend("Need " + (100 - weapon_damage) + " more weapon damage to pass first test."); - if (weapon_damage < 276 && need_byte_sword) - description.listAppend("Need " + (276 - weapon_damage) + "(?) more weapon damage for the first flickering pixel."); - - if (my_hp() < 100) - description.listAppend("Need 100 total HP to pass second test."); - if (my_hp() < 1000 && need_byte_sword) - description.listAppend("Need 1000 total HP for the second flickering pixel."); - } - else if (__last_adventure_location == $location[regret man's level] && $location[regret man's level].lastCombatInLocation() != "Regret man") - { - description.listAppend("Adventure in regret man's level, defeat the boss."); - - //MP >= 100 to complete - //total elemental damage >= 50 to complete - //MP >= 1000 for first flickering - //total elemental damage >= 100 for second flickering - - if (my_mp() < 100) - description.listAppend("Need 100 total MP to pass first test."); - if (my_mp() < 1000 && need_byte_sword) - description.listAppend("Need 1000 total MP for the first flickering pixel."); - //int total_elemental_damage = numeric_modifier("cold damage") + numeric_modifier("hot damage") + numeric_modifier("sleaze damage") + numeric_modifier("spooky damage") + numeric_modifier("stench damage"); - - //FIXME I am not sure if this is correct. How exactly does this test work? - string [int] missing_second_test; - string [int] missing_second_pixel_test; - foreach e in $strings[cold,hot,sleaze,spooky,stench] - { - string element_html_id = "r_element_" + e; - int damage = numeric_modifier(e + " damage").floor(); - if (damage < 50) - missing_second_test.listAppend(HTMLGenerateSpanOfClass((50 - damage) + " more " + e, element_html_id)); - if (damage < 60 && need_byte_sword) - missing_second_pixel_test.listAppend(HTMLGenerateSpanOfClass((60 - damage) + " more " + e, element_html_id)); - - } - if (missing_second_test.count() > 0) - description.listAppend("Need " + missing_second_test.listJoinComponents(", ", "and") + " damage to pass the second test."); - if (missing_second_pixel_test.count() > 0) - description.listAppend("Need " + missing_second_pixel_test.listJoinComponents(", ", "and") + " damage for the second flickering pixel."); - } - - string await = " await."; - if (bosses_remaining.count() == 1) - await = " awaits."; - if (bosses_remaining.count() > 0) - description.listAppend(bosses_remaining.listJoinComponents(", ", "and").capitaliseFirstLetter() + await); - else if ($item[flickering pixel].available_amount() == 8) - { - url = "inventory.php?ftext=flickering+pixel"; - image_name = "__item flickering pixel"; - } - - if (__misc_state["in run"]) - description.listAppend("(this isn't ascension relevant after you've gotten a digital key)"); - - optional_task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake("The Crackpot Mystic's Psychoses", modifiers, description),$locations[anger man's level, fear man's level, doubt man's level, regret man's level]).ChecklistEntrySetIDTag("Psychoanalytic jar crackpot mystic")); -} - - - -void IOTMPJickGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - string [int] description; - string [int] modifiers; - - if ($item[sword of procedural generation].available_amount() > 0) - return; - - description.listAppend("Fight skeletons."); - description.listAppend("Make sure you have a monster manuel first; once this tower is complete, there's no way to get these factoids ever again."); - - //FIXME be more specific - - optional_task_entries.listAppend(ChecklistEntryMake("__item skeleton", "", ChecklistSubentryMake("Jick's Obsessions", modifiers, description),$locations[the tower of procedurally-generated skeletons]).ChecklistEntrySetIDTag("Psychoanalytic jar Jick")); -} - - - -void IOTMPArtistGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - string [int] description; - string [int] modifiers; - - - foreach e in $effects[My Breakfast With Andrea,The Champion's Breakfast,Tiffany's Breakfast,Breakfast Clubbed] - { - if (e.have_effect() > 0) - return; - } - //Let's see. - //The way this quest works is, you find utensils in the kitchen drawer. (or the mall) - //Then, you adventure in the grocery bag, and use a utensil on the monsters. - //The utensil you use on the monster determines breakfast. - - - description.listAppend("Make a breakfast."); - description.listAppend("To do this, you find utensils in the kitchen drawer, and use them, in combat, on the five different foods in the grocery bag.|Which utensil you use on which food helps determine your breakfast."); - - - string [int] missing_utensils; - foreach it in $items[Artist's Butterknife of Regret,Artist's Cookie Cutter of Loneliness,Artist's Crème Brulée Torch of Fury,Artist's Spatula of Despair,Artist's Whisk of Misery] - { - if (it.available_amount() > 0) - continue; - string utensil_readable_name = it.to_string().replace_string("Artist's ", ""); - - missing_utensils.listAppend(utensil_readable_name); - } - - if (missing_utensils.count() > 0) - { - modifiers.listAppend("+300% item"); - description.listAppend("Find utensils in the kitchen drawer, or buy in the mall.|Utensils missing:|*" + missing_utensils.listJoinComponents(", ", "and") + "."); - } - - string [int] breakfasts; - - string breakfast_line; - //Meat & Knife, Bread & Knife, Batter & Spatula, Eggs & Whisk, Potatoes & Knife - breakfast_line += "My Breakfast With Andrea: (+meat)"; - breakfast_line += "|*Meat" + __html_right_arrow_character + "Butterknife"; - breakfast_line += "|*Bread" + __html_right_arrow_character + "Butterknife"; - breakfast_line += "|*Batter" + __html_right_arrow_character + "Spatula"; - breakfast_line += "|*Eggs" + __html_right_arrow_character + "Whisk"; - breakfast_line += "|*Potatoes" + __html_right_arrow_character + "Butterknife"; - breakfasts.listAppend(breakfast_line); breakfast_line = ""; - - //Meat & Cutter, Bread & Torch, Batter & Whisk, Eggs & Torch, Potatoes & Torch - breakfast_line += "
"; - breakfast_line += "The Champion's Breakfast: (+init)"; - breakfast_line += "|*Meat" + __html_right_arrow_character + "Cookie Cutter"; - breakfast_line += "|*Bread" + __html_right_arrow_character + "Crème Brulée Torch"; - breakfast_line += "|*Batter" + __html_right_arrow_character + "Whisk"; - breakfast_line += "|*Eggs" + __html_right_arrow_character + "Crème Brulée Torch"; - breakfast_line += "|*Potatoes" + __html_right_arrow_character + "Crème Brulée Torch"; - breakfasts.listAppend(breakfast_line); breakfast_line = ""; - - //Meat & Spatula, Bread & Cutter, Batter & Cutter, Eggs & Spatula, Potatoes & Whisk - breakfast_line += "
"; - breakfast_line += "Tiffany's Breakfast: (+item)"; - breakfast_line += "|*Meat" + __html_right_arrow_character + "Spatula"; - breakfast_line += "|*Bread" + __html_right_arrow_character + "Cookie Cutter"; - breakfast_line += "|*Batter" + __html_right_arrow_character + "Cookie Cutter"; - breakfast_line += "|*Eggs" + __html_right_arrow_character + "Spatula"; - breakfast_line += "|*Potatoes" + __html_right_arrow_character + "Whisk"; - breakfasts.listAppend(breakfast_line); breakfast_line = ""; - - - //It's actually anything, but let's pick one: - //Meat & Torch, Bread & Whisk, Batter & Knife, Eggs & Cutter, Potatoes & Spatula - breakfast_line += "
"; - breakfast_line += "Breakfast Clubbed: (+ML)"; - breakfast_line += "|*Meat" + __html_right_arrow_character + "Crème Brulée Torch"; - breakfast_line += "|*Bread" + __html_right_arrow_character + "Whisk"; - breakfast_line += "|*Batter" + __html_right_arrow_character + "Butterknife"; - breakfast_line += "|*Eggs" + __html_right_arrow_character + "Cookie Cutter"; - breakfast_line += "|*Potatoes" + __html_right_arrow_character + "Spatula"; - breakfasts.listAppend(breakfast_line); breakfast_line = ""; - - description.listAppend("There are four different breakfasts possible:" + HTMLGenerateIndentedText(breakfasts)); - - if ($item[Ginsu™].available_amount() == 0) - description.listAppend("Making all four breakfasts in the same ascension lets you acquire the sword, " + $item[Ginsu™] + "."); - - optional_task_entries.listAppend(ChecklistEntryMake("__effect My Breakfast With Andrea", "place.php?whichplace=junggate_5", ChecklistSubentryMake("The Pretentious Artist's Obsession", modifiers, description),$locations[a kitchen drawer, a grocery bag]).ChecklistEntrySetIDTag("Psychoanalytic jar pretentious artist")); -} - -RegisterTaskGenerationFunction("IOTMPsychoanalyticGenerateTasks"); -void IOTMPsychoanalyticGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!get_property_boolean("_psychoJarUsed")) - return; - //Can't detect which jar was used, so check where they've been: - if ($locations[chinatown shops, chinatown tenement, triad factory,1st floor\, shiawase-mitsuhama building,2nd floor\, shiawase-mitsuhama building,3rd floor\, shiawase-mitsuhama building] contains __last_adventure_location) - { - //√ - IOTMPShadyPastGenerateTasks(task_entries, optional_task_entries, future_task_entries); - } - if ($locations[The Old Man's Bathtime Adventures] contains __last_adventure_location) - { - //√ - IOTMPOldManGenerateTasks(task_entries, optional_task_entries, future_task_entries); - } - if ($locations[The Nightmare Meatrealm] contains __last_adventure_location) - { - IOTMPMeatGenerateTasks(task_entries, optional_task_entries, future_task_entries); - } - if ($locations[The gourd!] contains __last_adventure_location) - { - IOTMPGourdGenerateTasks(task_entries, optional_task_entries, future_task_entries); - } - if ($locations[anger man's level, fear man's level, doubt man's level, regret man's level] contains __last_adventure_location) - { - //√ - IOTMPCrackpotGenerateTasks(task_entries, optional_task_entries, future_task_entries); - } - if ($locations[the tower of procedurally-generated skeletons] contains __last_adventure_location) - { - IOTMPJickGenerateTasks(task_entries, optional_task_entries, future_task_entries); - } - if ($locations[a kitchen drawer, a grocery bag] contains __last_adventure_location) - { - //√ - IOTMPArtistGenerateTasks(task_entries, optional_task_entries, future_task_entries); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2013/Smithsness.ash b/Source/relay/TourGuide/Items of the Month/2013/Smithsness.ash deleted file mode 100644 index e7675b16..00000000 --- a/Source/relay/TourGuide/Items of the Month/2013/Smithsness.ash +++ /dev/null @@ -1,129 +0,0 @@ -void smithsnessGenerateCoalSuggestions(string [int] coal_suggestions) -{ - if (!__misc_state["in run"]) - return; - string [item] coal_item_suggestions; - - if (__misc_state["can equip just about any weapon"]) - { - if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) - coal_item_suggestions[$item[half a purse]] = "2x smithsness meat for nuns"; - coal_item_suggestions[$item[A Light that Never Goes Out]] = "2x smithsness +item"; - - - if (my_class() == $class[seal clubber]) - coal_item_suggestions[$item[Meat Tenderizer is Murder]] = "weapon, +2x smithsness muscle %"; - else if (my_class() == $class[turtle tamer]) - coal_item_suggestions[$item[Ouija Board, Ouija Board]] = "weapon, +2x smithsness muscle %"; - else if (my_class() == $class[pastamancer]) - coal_item_suggestions[$item[Hand that Rocks the Ladle]] = "weapon, +2x smithsness mysticality %"; - else if (my_class() == $class[sauceror]) - coal_item_suggestions[$item[Saucepanic]] = "weapon, +myst stats, +2x smithsness mysticality %"; - else if (my_class() == $class[disco bandit]) - coal_item_suggestions[$item[Frankly Mr. Shank]] = "weapon, +2x smithsness moxie %"; - else if (my_class() == $class[accordion thief]) - coal_item_suggestions[$item[Shakespeare's Sister's Accordion]] = "weapon, +2x smithsness moxie %, useful cadenza"; - //not sure I like these suggestions based off of mainstat, but... - else if (my_primestat() == $stat[mysticality]) - coal_item_suggestions[$item[Staff of the Headmaster's Victuals]] = "weapon, +smithsnesss spell damage"; - else if (my_primestat() == $stat[muscle]) - coal_item_suggestions[$item[Work is a Four Letter Sword]] = "weapon, +2x smithsness weapon damage"; - else if (my_primestat() == $stat[moxie]) - coal_item_suggestions[$item[Sheila Take a Crossbow]] = "weapon, +smithsness initiative"; - - string [int] sheila_reasons; - if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"]) - sheila_reasons.listAppend("modern zmobies"); - if (!__quest_state["Level 13"].state_boolean["Init race completed"]) - sheila_reasons.listAppend("lair init race"); - if (sheila_reasons.count() > 0) - coal_item_suggestions[$item[Sheila Take a Crossbow]] = "weapon, +smithsness initiative (useful for " + sheila_reasons.listJoinComponents(", ", "and") + ")"; - - - } - coal_item_suggestions[$item[Hand in Glove]] = "lots of +ML"; - if ($item[dirty hobo gloves].available_amount() == 0) - coal_item_suggestions[$item[Hand in Glove]] += " (need dirty hobo gloves)"; - else - coal_item_suggestions[$item[Hand in Glove]] += " (have dirty hobo gloves)"; - if (knoll_available() || $item[maiden wig].available_amount() > 0) - coal_item_suggestions[$item[Hairpiece On Fire]] = "+4 adventures, +5 smithness hat, +smithsness MP"; - if (knoll_available() || $item[frilly skirt].available_amount() > 0) - { - coal_item_suggestions[$item[Vicar's Tutu]] = "+5 smithsness pants, +smithsness HP"; - - if (hippy_stone_broken()) - coal_item_suggestions[$item[Vicar's Tutu]] = coal_item_suggestions[$item[Vicar's Tutu]] + ", +3 PVP fights"; - } - - if ($skill[pulverize].skill_is_usable()) - coal_suggestions.listAppend("Smash smithed equipment for more smithereens"); - foreach it in coal_item_suggestions - { - int number_wanted_max = 1; - if (it.to_slot() == $slot[weapon] && it.weapon_hands() == 1) - { - if ($skill[double-fisted skull smashing].skill_is_usable() && it.item_type() != "accordion") - number_wanted_max += 1; - if (familiar_is_usable($familiar[disembodied hand])) - number_wanted_max += 1; - } - - if (it.available_amount() >= number_wanted_max) - continue; - string suggestion = coal_item_suggestions[it]; - coal_suggestions.listAppend(it + ": " + suggestion); - } -} - -void smithsnessGenerateSmithereensSuggestions(string [int] smithereen_suggestions) //suggestereens -{ - smithereen_suggestions.listAppend(7014.to_item().to_string() + ": " + (__misc_state["free runs usable"] ? "free run/" : "") + "banish for 20 turns"); - - if (__misc_state["can eat just about anything"] && availableFullness() >= 2 && my_path().id != PATH_SLOW_AND_STEADY) - { - smithereen_suggestions.listAppend("Charming Flan: 2 fullness epic food
Miserable Pie: 2 fullness awesome food, 50 turns of +10 smithsness"); - } - - if (__misc_state["can drink just about anything"] && availableDrunkenness() >= 2 && my_path().id != PATH_SLOW_AND_STEADY) - { - smithereen_suggestions.listAppend("Vulgar Pitcher: 2 drunkenness epic drink
Bigmouth: 2 drunkenness awesome drink, 50 turns of +10 smithsness"); - } - if (!$familiar[he-boulder].familiar_is_usable()) - { - string line = "Golden Light: Yellow ray"; - if ($effect[everything looks yellow].have_effect() > 0) - line = HTMLGenerateSpanFont(line, "gray"); - smithereen_suggestions.listAppend(line); - } - - if (__misc_state["in run"]) - smithereen_suggestions.listAppend("Handsome Devil: single-turn +100% item"); - -} - -RegisterResourceGenerationFunction("IOTMSmithsnessGenerateResource"); -void IOTMSmithsnessGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (__misc_state["in run"] && $item[handful of smithereens].available_amount() > 0 && in_ronin()) - { - string [int] smithereen_suggestions; - smithsnessGenerateSmithereensSuggestions(smithereen_suggestions); - resource_entries.listAppend(ChecklistEntryMake("__item handful of smithereens", "", ChecklistSubentryMake(pluralise($item[handful of smithereens]), "", smithereen_suggestions.listJoinComponents("
")), 10).ChecklistEntrySetIDTag("Smithsness smithereens suggestions")); - } - if (__misc_state["in run"] && $item[lump of Brituminous coal].available_amount() > 0 && in_ronin()) - { - string [int] coal_suggestions; - smithsnessGenerateCoalSuggestions(coal_suggestions); - resource_entries.listAppend(ChecklistEntryMake("__item lump of Brituminous coal", "", ChecklistSubentryMake(pluralise($item[lump of Brituminous coal]), "", coal_suggestions.listJoinComponents("
")), 10).ChecklistEntrySetIDTag("Smithsness brituminous suggestions")); - } - if ($item[flaskfull of hollow].available_amount() > 0 && $effect[Merry Smithsness].have_effect() < 25 && __misc_state["in run"] && my_path().id != PATH_G_LOVER) - { - int turns_left = $effect[Merry Smithsness].have_effect(); - string [int] details; - details.listAppend(pluralise((turns_left + 150 * $item[flaskfull of hollow].available_amount()), "turn", "turns") + " of +25 smithsness"); - if (turns_left > 0) - details.listAppend("Effect will run out in " + pluralise(turns_left, "turn", "turns")); - resource_entries.listAppend(ChecklistEntryMake("__item flaskfull of hollow", "inventory.php?ftext=flaskfull+of+hollow", ChecklistSubentryMake(pluralise($item[flaskfull of hollow]), "", details), 10).ChecklistEntrySetIDTag("Smithsness flaskfull of hollow")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2014/DNA.ash b/Source/relay/TourGuide/Items of the Month/2014/DNA.ash deleted file mode 100644 index d9f88c8c..00000000 --- a/Source/relay/TourGuide/Items of the Month/2014/DNA.ash +++ /dev/null @@ -1,572 +0,0 @@ -//_dnaPotionsMade - int, count of potions made -//dnaSyringe - int, current phylum of syringe. seems to track if it's become empty? double check -//_dnaHybrid - boolean, true if you're become a human abomination today -//r13912 or higher - - -string [phylum] __dna_phylum_to_description; -string [phylum] __dna_phylum_to_description_colourless; -item [phylum] __dna_phylum_to_item; -effect [phylum] __dna_phylum_to_effect; -phylum [effect] __dna_effect_to_phylum; -string [int] __dna_intrinsic_ideas; - -record DNASuggestion -{ - phylum [int] phylums; - string relevant_effect_description; - string reason; - boolean always_show; -}; - - -DNASuggestion DNASuggestionMake(phylum [int] phylums, string relevant_effect_description, string reason, boolean always_show) -{ - DNASuggestion result; - result.phylums = phylums; - result.relevant_effect_description = relevant_effect_description; - result.reason = reason; - result.always_show = always_show; - return result; -} - -DNASuggestion DNASuggestionMake(phylum p, string relevant_effect_description, string reason) -{ - phylum [int] phylums; - phylums[0] = p; - return DNASuggestionMake(phylums, relevant_effect_description, reason, false); -} - -DNASuggestion DNASuggestionMake(phylum p, string relevant_effect_description, string reason, boolean always_show) -{ - phylum [int] phylums; - phylums[0] = p; - return DNASuggestionMake(phylums, relevant_effect_description, reason, always_show); -} - - -DNASuggestion DNASuggestionMake(boolean [phylum] phylums_in, string relevant_effect_description, string reason) -{ - phylum [int] phylums; - foreach p in phylums_in - { - phylums.listAppend(p); - } - return DNASuggestionMake(phylums, relevant_effect_description, reason, false); -} - -void listAppend(DNASuggestion [int] list, DNASuggestion entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -boolean DNAHavePhylum(phylum p) -{ - if (__dna_phylum_to_effect[p].have_effect() > 0) - return true; - - if (__dna_phylum_to_item[p].available_amount() > 0) - return true; - - return false; -} - -string DNABoldPhylumIfCurrentMonster(phylum p) -{ - if (monster_phylum() == p) - return HTMLGenerateSpanOfClass(p.to_string(), "r_bold"); - else - return p.to_string(); -} - -DNASuggestion [int] __phylum_potion_suggestions; -DNASuggestion [int] __phylum_potion_reminder_suggestions; -effect __current_dna_intrinsic = $effect[none]; - -RegisterInitFunction("IOTMDNAInit"); -void IOTMDNAInit() -{ - if (!__iotms_usable[$item[Little Geneticist DNA-Splicing Lab]]) - return; - - - //this is not a particulary good idea: - __dna_phylum_to_description[$phylum[beast]] = "+30 weapon damage"; - __dna_phylum_to_description[$phylum[bug]] = "+25% init"; - __dna_phylum_to_description[$phylum[constellation]] = "+50% meat"; - __dna_phylum_to_description[$phylum[construct]] = "+5 familiar weight, +50 DA, +5 DR"; - __dna_phylum_to_description[$phylum[dude]] = "+10% item, +10 muscle/mysticality/moxie"; - __dna_phylum_to_description[$phylum[elemental]] = "+3 resistances"; - __dna_phylum_to_description[$phylum[elf]] = "+100% spell damage, +50% candy drops"; - __dna_phylum_to_description[$phylum[fish]] = "+10 familiar weight"; - __dna_phylum_to_description[$phylum[goblin]] = "+20% pickpocket, +50% food drops"; - __dna_phylum_to_description[$phylum[hippy]] = "+1 stat/fight, +20 max MP"; - __dna_phylum_to_description[$phylum[humanoid]] = "+20% meat, +10% muscle/mysticality/moxie"; - __dna_phylum_to_description[$phylum[horror]] = "+10% critical hit, +10% critical spell hit"; - __dna_phylum_to_description[$phylum[mer-kin]] = "+25 ML"; - __dna_phylum_to_description[$phylum[orc]] = "+1 stat/fight, +40 max HP"; - __dna_phylum_to_description[$phylum[penguin]] = "+25% item"; - __dna_phylum_to_description[$phylum[pirate]] = "+50% gear drops, +50% booze drops"; - - - __dna_phylum_to_description_colourless[$phylum[demon]] = "+20 hot damage / hot spell damage"; - __dna_phylum_to_description_colourless[$phylum[hobo]] = "+20 stench damage / stench spell damage"; - __dna_phylum_to_description_colourless[$phylum[plant]] = "+20 cold damage / cold spell damage"; - __dna_phylum_to_description_colourless[$phylum[slime]] = "+20 sleaze damage / sleaze spell damage"; - __dna_phylum_to_description_colourless[$phylum[undead]] = "+20 spooky damage / spooky spell damage"; - - __dna_phylum_to_description[$phylum[demon]] = HTMLGenerateSpanOfClass(__dna_phylum_to_description_colourless[$phylum[demon]], "r_element_hot_desaturated"); - __dna_phylum_to_description[$phylum[hobo]] = HTMLGenerateSpanOfClass(__dna_phylum_to_description_colourless[$phylum[hobo]], "r_element_stench_desaturated"); - __dna_phylum_to_description[$phylum[plant]] = HTMLGenerateSpanOfClass(__dna_phylum_to_description_colourless[$phylum[plant]], "r_element_cold_desaturated"); - __dna_phylum_to_description[$phylum[slime]] = HTMLGenerateSpanOfClass(__dna_phylum_to_description_colourless[$phylum[slime]], "r_element_sleaze_desaturated"); - __dna_phylum_to_description[$phylum[undead]] = HTMLGenerateSpanOfClass(__dna_phylum_to_description_colourless[$phylum[undead]], "r_element_spooky_desaturated"); - - __dna_phylum_to_description[$phylum[weird]] = "+4 stats/fight"; - - foreach p in __dna_phylum_to_description - { - if (__dna_phylum_to_description_colourless contains p) - continue; - __dna_phylum_to_description_colourless[p] = __dna_phylum_to_description[p]; - } - - __dna_phylum_to_item[$phylum[beast]] = $item[Gene Tonic: Beast]; - __dna_phylum_to_item[$phylum[bug]] = $item[Gene Tonic: Insect]; - __dna_phylum_to_item[$phylum[constellation]] = $item[Gene Tonic: Constellation]; - __dna_phylum_to_item[$phylum[construct]] = $item[Gene Tonic: Construct]; - __dna_phylum_to_item[$phylum[demon]] = $item[Gene Tonic: Demon]; - __dna_phylum_to_item[$phylum[dude]] = $item[Gene Tonic: Dude]; - __dna_phylum_to_item[$phylum[elemental]] = $item[Gene Tonic: Elemental]; - __dna_phylum_to_item[$phylum[elf]] = $item[Gene Tonic: Elf]; - __dna_phylum_to_item[$phylum[fish]] = $item[Gene Tonic: Fish]; - __dna_phylum_to_item[$phylum[goblin]] = $item[Gene Tonic: Goblin]; - __dna_phylum_to_item[$phylum[hippy]] = $item[Gene Tonic: Hippy]; - __dna_phylum_to_item[$phylum[hobo]] = $item[Gene Tonic: Hobo]; - __dna_phylum_to_item[$phylum[horror]] = $item[Gene Tonic: Horror]; - __dna_phylum_to_item[$phylum[humanoid]] = $item[Gene Tonic: Humanoid]; - __dna_phylum_to_item[$phylum[mer-kin]] = $item[Gene Tonic: Mer-kin]; - __dna_phylum_to_item[$phylum[orc]] = $item[Gene Tonic: Orc]; - __dna_phylum_to_item[$phylum[penguin]] = $item[Gene Tonic: Penguin]; - __dna_phylum_to_item[$phylum[pirate]] = $item[Gene Tonic: Pirate]; - __dna_phylum_to_item[$phylum[plant]] = $item[Gene Tonic: Plant]; - __dna_phylum_to_item[$phylum[slime]] = $item[Gene Tonic: Slime]; - __dna_phylum_to_item[$phylum[undead]] = $item[Gene Tonic: Undead]; - __dna_phylum_to_item[$phylum[weird]] = $item[Gene Tonic: Weird]; - - __dna_phylum_to_effect[$phylum[beast]] = $effect[Human-Beast Hybrid]; - __dna_phylum_to_effect[$phylum[bug]] = $effect[Human-Insect Hybrid]; - __dna_phylum_to_effect[$phylum[constellation]] = $effect[Human-Constellation Hybrid]; - __dna_phylum_to_effect[$phylum[construct]] = $effect[Human-Machine Hybrid]; - __dna_phylum_to_effect[$phylum[demon]] = $effect[Human-Demon Hybrid]; - __dna_phylum_to_effect[$phylum[dude]] = $effect[Human-Human Hybrid]; - __dna_phylum_to_effect[$phylum[elemental]] = $effect[Human-Elemental Hybrid]; - __dna_phylum_to_effect[$phylum[elf]] = $effect[Human-Elf Hybrid]; - __dna_phylum_to_effect[$phylum[fish]] = $effect[Human-Fish Hybrid]; - __dna_phylum_to_effect[$phylum[goblin]] = $effect[Human-Goblin Hybrid]; - __dna_phylum_to_effect[$phylum[hippy]] = $effect[Human-Hippy Hybrid]; - __dna_phylum_to_effect[$phylum[hobo]] = $effect[Human-Hobo Hybrid]; - __dna_phylum_to_effect[$phylum[horror]] = $effect[Human-Horror Hybrid]; - __dna_phylum_to_effect[$phylum[humanoid]] = $effect[Human-Humanoid Hybrid]; - __dna_phylum_to_effect[$phylum[mer-kin]] = $effect[Human-Mer-kin Hybrid]; - __dna_phylum_to_effect[$phylum[orc]] = $effect[Human-Orc Hybrid]; - __dna_phylum_to_effect[$phylum[penguin]] = $effect[Human-Penguin Hybrid]; - __dna_phylum_to_effect[$phylum[pirate]] = $effect[Human-Pirate Hybrid]; - __dna_phylum_to_effect[$phylum[plant]] = $effect[Human-Plant Hybrid]; - __dna_phylum_to_effect[$phylum[slime]] = $effect[Human-Slime Hybrid]; - __dna_phylum_to_effect[$phylum[undead]] = $effect[Human-Undead Hybrid]; - __dna_phylum_to_effect[$phylum[weird]] = $effect[Human-Weird Thing Hybrid]; - - foreach p in __dna_phylum_to_effect - { - __dna_effect_to_phylum[__dna_phylum_to_effect[p]] = p; - } - - - foreach e in __dna_effect_to_phylum - { - if (e.have_effect() == 2147483647) - { - __current_dna_intrinsic = e; - break; - } - } - - - if (my_path().id == PATH_COMMUNITY_SERVICE) - { - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[fish], "", "+10 familiar weight for statgain, parrot")); - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[elemental], "", "saves three turns on resistance test")); - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[pirate], "", "~3.3 turns saved on item test")); - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[construct], "", "+5 familiar weight")); - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[elf], "", "spell damage test")); - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[beast], "", "marginal?")); - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[dude], "", "marginal?")); - - return; - } - - if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"]) - { - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[bug], "", "speed up defiled alcove")); - __phylum_potion_reminder_suggestions.listAppend(DNASuggestionMake($phylum[bug], "", "speed up defiled alcove")); - } - - if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) - { - //FIXME only suggest constellation if they've not finished HITS? - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylums[constellation,humanoid], "+meat", "nuns")); - __phylum_potion_reminder_suggestions.listAppend(DNASuggestionMake($phylum[constellation], "+meat", "nuns")); - __phylum_potion_reminder_suggestions.listAppend(DNASuggestionMake($phylum[humanoid], "+meat", "nuns")); - - } - if (!__quest_state["Level 3"].finished) - { - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylums[demon,hobo,plant,undead], "+elemental damage", "tavern NC skipping")); - } - if (!__quest_state["Level 12"].finished && (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues")) && !__misc_state["yellow ray potentially available"]) - { - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[pirate], "+50% gear drop", "war outfit?")); - } - if (__quest_state["Level 11 Palindome"].mafia_internal_step < 5 && $item[mega gem].available_amount() == 0 && in_hardcore() && !($skill[Check Hair].skill_is_usable() && $skill[Natural Dancer].skill_is_usable())) //avatar of sneaky pete usually can cap this easily... usually - { - if ($item[wet stunt nut stew].available_amount() == 0 && !(($item[bird rib].available_amount() > 0 && $item[lion oil].available_amount() > 0 || $item[wet stew].available_amount() > 0))) - { - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[goblin], "+50% food drop", "Wet stunt nut stew components")); - __phylum_potion_reminder_suggestions.listAppend(DNASuggestionMake($phylum[goblin], "+50% food drop", "Wet stunt nut stew components")); //300% drop, very important - } - } - - if (true) - { - string [int] reasons; - if (!__quest_state["Level 8"].finished && numeric_modifier("cold resistance") < 5.0) - reasons.listAppend("icy peak"); - if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0) - reasons.listAppend("a-boo peak"); - - if (reasons.count() > 0) - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[elemental], "+3 all resistance", reasons.listJoinComponents(", ", "and").capitaliseFirstLetter())); - } - - if (__misc_state["in run"]) - { - if (__current_dna_intrinsic != __dna_phylum_to_effect[$phylum[construct]] && !__misc_state["familiars temporarily blocked"]) - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[construct], "+5 familiar weight, DR/DA", "", true)); - if (__current_dna_intrinsic != __dna_phylum_to_effect[$phylum[dude]]) - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[dude], "+10% item", "", true)); - - if (!__quest_state["Level 13"].state_boolean["Elemental damage race completed"]) - { - string element_needed = __quest_state["Level 13"].state_string["Elemental damage race type"]; - DNASuggestion element_suggestion; - string suggestion_effect = "+" + HTMLGenerateSpanOfClass(element_needed, "r_element_" + element_needed + "_desaturated") + " damage/spell damage"; - string suggestion_description = "Lair race"; - if (element_needed == "hot") - element_suggestion = DNASuggestionMake($phylum[demon], suggestion_effect, suggestion_description, true); - else if (element_needed == "cold") - element_suggestion = DNASuggestionMake($phylum[plant], suggestion_effect, suggestion_description, true); - else if (element_needed == "sleaze") - element_suggestion = DNASuggestionMake($phylum[slime], suggestion_effect, suggestion_description, true); - else if (element_needed == "spooky") - element_suggestion = DNASuggestionMake($phylum[undead], suggestion_effect, suggestion_description, true); - else if (element_needed == "stench") - element_suggestion = DNASuggestionMake($phylum[hobo], suggestion_effect, suggestion_description, true); - if (element_suggestion.phylums.count() > 0 && element_needed != "") - { - __phylum_potion_suggestions.listAppend(element_suggestion); - __phylum_potion_reminder_suggestions.listAppend(element_suggestion); - } - } - } - else - { - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[penguin], "", "", true)); - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[fish], "", "", true)); - __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[constellation], "", "", true)); - } - - - if (__current_dna_intrinsic == $effect[none]) - { - if (!__misc_state["familiars temporarily blocked"]) - { - if (!__misc_state["in run"] || my_path().id == PATH_HEAVY_RAINS) - __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[fish]) + " (+10 familiar weight)"); - else if ($item[grimstone mask].available_amount() > 0) - { - __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[fish]) + " (+10 familiar weight, via grimstone mask candy witch's lake)"); - __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[construct]) + " (+5 familiar weight)"); - } - else - __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[construct]) + " (+5 familiar weight)"); - } - if (__misc_state["need to level"]) - { - if ($familiar[astral badger].familiar_is_usable() || $item[astral mushroom].available_amount() > 0 || $effect[Half-Astral].have_effect() > 0 || __misc_state_int["pulls available"] > 0) - { - string method = "astral badger"; - if (!$familiar[astral badger].familiar_is_usable() || $item[astral mushroom].available_amount() > 0) - method = "astral mushroom"; - __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[weird]) + " (+4 stats/fight, via " + method + ")"); - } - else if (__misc_state["sleaze airport available"]) - { - __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[weird]) + " (+4 stats/fight, via sloppy seconds diner)"); - } - } - __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[dude]) + " (+10% item)"); - - } -} - -RegisterResourceGenerationFunction("IOTMDNAGenerateResource"); -void IOTMDNAGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (__misc_state["campground unavailable"]) - return; - if (!__iotms_usable[$item[Little Geneticist DNA-Splicing Lab]]) - return; - - //Player has a genetic engineering lab installed. Let's play with our DNA! - - phylum syringe_phylum = getDNASyringePhylum(); - int potions_made = get_property_int("_dnaPotionsMade"); - int potions_left = MAX(0, 3 - potions_made); - boolean became_a_genetic_monstrosity_today = get_property_boolean("_dnaHybrid"); - - - //Some ideas: - //Intrinsics: - //√constructs - +5 familiar weight - also a potion option - //√weird - +4 stats/fight - hard to find without badger - //√dudes - +10% items - - //fish - +10 familiar weight - HCO only? possible with agua de vida, but takes at least two turns? 70% NC base, 2 NCs, need two of an NC. this is versus zero-turn +5 familiar weight... - //mer-kin - +25 ML - fax only. even with sea access, requires wreck access - //orcs/hippies - +1 stat/fight... ??? marginal? - //penguins - +25% item - nowhere to be found in-run before level 11 - - //Potions: - //√bug - +25% init - modern zmobies, potion, if we can find bugs - //√elemental - +3 all res - icy peak, a-boo, stench for twin/bats - //√constellation - +50% meat - nuns, potion - //√humanoid - +20% meat - more nuns? - //√demon - +20 hot damage - skipping tavern NC - //√hobo - +20 stench damage - skipping tavern NCs, but isn't there a better source? (the pool) - //√plant - +20 cold damage - tavern skipping, somewhat silly, song of north exists - //√undead - +20 spooky damage - tavern skipping...? - //pirate - +50% gear drops - not sure. potion? seems like it'd be useful in a handful of places - - - - - - ChecklistSubentry [int] subentries; - TagGroup tags; - tags.id = "DNA lab various resources"; //seems to include a lot, but IDK enough about the lab - - string syringe_description = ""; - boolean syringe_description_output = false; - if (syringe_phylum != $phylum[none]) - { - string line = "Syringe has " + syringe_phylum + "." + " (" + __dna_phylum_to_description_colourless[syringe_phylum] + ")"; - syringe_description = line; - } - - if (potions_left > 0) - { - string [int] description; - - if (syringe_description != "" && !syringe_description_output) - { - description.listAppend(syringe_description); - syringe_description_output = true; - } - - string [int] potion_suggestion_descriptions; - foreach key in __phylum_potion_suggestions - { - DNASuggestion suggestion = __phylum_potion_suggestions[key]; - - phylum [int] needed_phylums; - - foreach key2 in suggestion.phylums - { - phylum p = suggestion.phylums[key2]; - if (!DNAHavePhylum(p) || suggestion.always_show) - { - needed_phylums.listAppend(p); - } - } - - if (needed_phylums.count() > 0) - { - string [int] phylum_descriptions; - string [int] output_effect_description; - - foreach key in needed_phylums - { - phylum p = needed_phylums[key]; - - phylum_descriptions.listAppend(DNABoldPhylumIfCurrentMonster(p)); - - if (suggestion.relevant_effect_description.length() == 0) - output_effect_description.listAppend(__dna_phylum_to_description_colourless[p]); - } - if (suggestion.relevant_effect_description != "") - output_effect_description.listAppend(suggestion.relevant_effect_description); - - string line; - - line = phylum_descriptions.listJoinComponents("/"); - line += ": " + output_effect_description.listJoinComponents("/"); - if (suggestion.reason != "") - line += " - " + suggestion.reason; - - potion_suggestion_descriptions.listAppend(line); - } - } - //HTMLGenerateSimpleTableLines - if (potion_suggestion_descriptions.count() > 0) - description.listAppend("Tonic ideas:|*" + potion_suggestion_descriptions.listJoinComponents("
|*")); - subentries.listAppend(ChecklistSubentryMake(pluralise(potions_left, "gene tonic", "gene tonics") + " creatable", "", description)); - } - if (!became_a_genetic_monstrosity_today) - { - string [int] description; - if (syringe_description != "" && !syringe_description_output) - { - description.listAppend(syringe_description); - syringe_description_output = true; - } - - if (__current_dna_intrinsic != $effect[none] && (__dna_effect_to_phylum contains __current_dna_intrinsic)) - description.listAppend("Currently a " + __dna_effect_to_phylum[__current_dna_intrinsic] + ". (" + __dna_phylum_to_description_colourless[__dna_effect_to_phylum[__current_dna_intrinsic]] + ")"); - - - if (__current_dna_intrinsic == $effect[none]) - { - if (__dna_intrinsic_ideas.count() > 0) - description.listAppend("Could try " + __dna_intrinsic_ideas.listJoinComponents(", ", "or") + "."); - } - - subentries.listAppend(ChecklistSubentryMake("Genetic intrinsic available", "", description)); - } - - int importance = 5; - - if (potions_left == 0 && __current_dna_intrinsic != $effect[none]) //no potions, already a hybrid - importance = 8; - - string image_name = "__effect Human-Human Hybrid"; - - if (__misc_state["in run"]) - { - foreach p in __dna_phylum_to_item - { - item it = __dna_phylum_to_item[p]; - if (it.available_amount() == 0) - continue; - if (subentries.count() == 0) - image_name = "__item Gene Tonic: Constellation"; - subentries.listAppend(ChecklistSubentryMake(it.pluralise(), "", __dna_phylum_to_description_colourless[p])); - - } - } - - if (subentries.count() > 0) - resource_entries.listAppend(ChecklistEntryMake(image_name, "campground.php?action=workshed", subentries, tags, importance)); -} - -RegisterTaskGenerationFunction("IOTMDNAGenerateTasks"); -void IOTMDNAGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (__misc_state["campground unavailable"]) - return; - if (!__iotms_usable[$item[Little Geneticist DNA-Splicing Lab]]) - return; - - //Reminders: - phylum syringe_phylum = getDNASyringePhylum(); - - - if (get_property_int("_dnaPotionsMade") < 3) - { - if (syringe_phylum != $phylum[none] && !DNAHavePhylum(syringe_phylum)) - { - //Make the resulting tonic: - string suggestion_reason; - - string relevant_effect_description; - - - foreach key in __phylum_potion_reminder_suggestions - { - DNASuggestion suggestion = __phylum_potion_reminder_suggestions[key]; - foreach key2 in suggestion.phylums - { - phylum suggestion_phylum = suggestion.phylums[key2]; - if (syringe_phylum == suggestion_phylum) - { - suggestion_reason = suggestion.reason; - relevant_effect_description = suggestion.relevant_effect_description; - } - } - } - - - if (suggestion_reason != "") - { - string description = suggestion_reason.capitaliseFirstLetter() + "."; - task_entries.listAppend(ChecklistEntryMake("__effect Human-Human Hybrid", "campground.php?action=workshed", ChecklistSubentryMake("Make gene tonic for " + syringe_phylum, "", description), -11).ChecklistEntrySetIDTag("DNA lab make DNA potion")); - } - } - - - - if (monster_phylum() != $phylum[none] && monster_phylum() != syringe_phylum && !DNAHavePhylum(monster_phylum())) - { - //Syringe a monster when we find it: - phylum p = monster_phylum(); - - string suggestion_reason; - - string relevant_effect_description; - - - foreach key in __phylum_potion_reminder_suggestions - { - DNASuggestion suggestion = __phylum_potion_reminder_suggestions[key]; - foreach key2 in suggestion.phylums - { - phylum suggestion_phylum = suggestion.phylums[key2]; - if (p == suggestion_phylum) - { - suggestion_reason = suggestion.reason; - relevant_effect_description = suggestion.relevant_effect_description; - } - } - } - - if (suggestion_reason != "") - { - if (relevant_effect_description.length() == 0) - relevant_effect_description = __dna_phylum_to_description[p]; - string description = suggestion_reason.capitaliseFirstLetter() + "."; - description += "|" + monster_phylum().to_string().capitaliseFirstLetter() + " (" + relevant_effect_description + ")"; - task_entries.listAppend(ChecklistEntryMake("__effect Human-Human Hybrid", "", ChecklistSubentryMake("Extract DNA from " + last_monster().to_string().HTMLEscapeString(), "", description), -11).ChecklistEntrySetIDTag("DNA lab use syringe")); - } - } - } - - if (__current_dna_intrinsic == $effect[none] && !get_property_boolean("_dnaHybrid")) - { - string [int] description; - if (__dna_intrinsic_ideas.count() > 0) - description.listAppend("Could try " + __dna_intrinsic_ideas.listJoinComponents(", ", "or") + "."); - optional_task_entries.listAppend(ChecklistEntryMake("__effect Human-Human Hybrid", "campground.php?action=workshed", ChecklistSubentryMake("Hybridize yourself", "", description), 5).ChecklistEntrySetIDTag("DNA lab become hybrid")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2014/Grimstone.ash b/Source/relay/TourGuide/Items of the Month/2014/Grimstone.ash deleted file mode 100644 index c88800ed..00000000 --- a/Source/relay/TourGuide/Items of the Month/2014/Grimstone.ash +++ /dev/null @@ -1,292 +0,0 @@ -void IOTMGrimstoneHareGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - string [int] description; - string [int] modifiers; - - modifiers.listAppend("mysticality"); - modifiers.listAppend("spell damage percent"); - modifiers.listAppend("spell critical percent"); - int time_remaining = $effect[hare-brained].have_effect(); - - //FIXME deal with coldform / hotform / etc - - description.listAppend("Adventure on the deserted stretch of road.|Cast elemental-aligned powerful spells on vehicles.|The more damage, the faster you go."); - - description.listAppend("The speedy/expensive strategy is to nanorhino/ice house/batter up/pantsgiving/crystal skull/etc. banish everything that isn't an ice cream truck, and olfact ice cream trucks.|Then run coldform, buff spell damage, mysticality, and spell damage critical.|Then cast shrap."); - - string [string] elemental_descriptions; - - string [int] missing_hobopolis_spells; - - elemental_descriptions["hot"] = HTMLGenerateSpanOfClass("hot", "r_element_hot"); - elemental_descriptions["cold"] = HTMLGenerateSpanOfClass("cold", "r_element_cold"); - elemental_descriptions["spooky"] = HTMLGenerateSpanOfClass("spooky", "r_element_spooky"); - elemental_descriptions["stench"] = HTMLGenerateSpanOfClass("stench", "r_element_stench"); - elemental_descriptions["sleaze"] = HTMLGenerateSpanOfClass("sleaze", "r_element_sleaze"); - - - boolean have_shrap = $skill[shrap].skill_is_usable(); - - if (have_shrap && $effect[hotform].have_effect() > 0) - elemental_descriptions["hot"] = "Shrap (" + elemental_descriptions["hot"] + ")"; - else if ($skill[volcanometeor showeruption].skill_is_usable()) - elemental_descriptions["hot"] = "Volcanometeor Showeruption (" + elemental_descriptions["hot"] + ")"; - else if ($skill[Awesome Balls of Fire].skill_is_usable()) - elemental_descriptions["hot"] = "Awesome Balls of Fire (" + elemental_descriptions["hot"] + ")"; - else - missing_hobopolis_spells.listAppend("Awesome Balls of Fire"); - - - if (have_shrap && $effect[coldform].have_effect() > 0) - elemental_descriptions["cold"] = "Shrap (" + elemental_descriptions["cold"] + ")"; - else if ($skill[Snowclone].skill_is_usable()) - elemental_descriptions["cold"] = "Snowclone (" + elemental_descriptions["cold"] + ")"; - else - missing_hobopolis_spells.listAppend("Snowclone"); - - if (have_shrap && $effect[spookyform].have_effect() > 0) - elemental_descriptions["spooky"] = "Shrap (" + elemental_descriptions["spooky"] + ")"; - else if ($skill[Raise Backup Dancer].skill_is_usable()) - elemental_descriptions["spooky"] = "Raise Backup Dancer (" + elemental_descriptions["spooky"] + ")"; - else - missing_hobopolis_spells.listAppend("Raise Backup Dancer"); - - if (have_shrap && $effect[stenchform].have_effect() > 0) - elemental_descriptions["stench"] = "Shrap (" + elemental_descriptions["stench"] + ")"; - else if ($skill[Eggsplosion].skill_is_usable()) - elemental_descriptions["stench"] = "Eggsplosion (" + elemental_descriptions["stench"] + ")"; - else - missing_hobopolis_spells.listAppend("Eggsplosion"); - - - if (have_shrap && $effect[sleazeform].have_effect() > 0) - elemental_descriptions["sleaze"] = "Shrap (" + elemental_descriptions["sleaze"] + ")"; - else if ($skill[Grease Lightning].skill_is_usable()) - elemental_descriptions["sleaze"] = "Grease Lightning (" + elemental_descriptions["sleaze"] + ")"; - else - missing_hobopolis_spells.listAppend("Grease Lightning"); - - - - string [int][int] vehicle_descriptions; - if (!$monster[Fire truck].is_banished()) - vehicle_descriptions.listAppend(listMake("Fire truck", elemental_descriptions["hot"])); - if (!$monster[ice cream truck].is_banished()) - vehicle_descriptions.listAppend(listMake("ice cream truck", elemental_descriptions["cold"])); - if (!$monster[monster hearse].is_banished()) - vehicle_descriptions.listAppend(listMake("monster hearse", elemental_descriptions["spooky"])); - if (!$monster[sewer tanker].is_banished()) - vehicle_descriptions.listAppend(listMake("sewer tanker", elemental_descriptions["stench"])); - if (!$monster[sketchy van].is_banished()) - vehicle_descriptions.listAppend(listMake("sketchy van", elemental_descriptions["sleaze"])); - - monster last_encounter = get_property_monster("lastEncounter"); - //string [int] vehicles = split_string_alternate("Fire truck,ice cream truck,monster hearse,sewer tanker,sketchy van", ","); - monster [int] vehicles = {$monster[Fire truck],$monster[ice cream truck],$monster[monster hearse],$monster[sewer tanker],$monster[sketchy van]}; - - foreach key in vehicles - { - monster vehicle = vehicles[key]; - if (vehicle == $monster[none]) - continue; - - if (last_encounter != vehicle) - continue; - - vehicle_descriptions[key][0] = HTMLGenerateSpanOfClass(vehicle_descriptions[key][0], "r_bold"); - vehicle_descriptions[key][1] = HTMLGenerateSpanOfClass(vehicle_descriptions[key][1], "r_bold"); - } - - description.listAppend("Spells to cast: " + HTMLGenerateIndentedText(HTMLGenerateSimpleTableLines(vehicle_descriptions))); - - if (my_familiar() != $familiar[magic dragonfish]) - description.listAppend("Run magic dragonfish familiar."); - else if ($familiar[magic dragonfish].familiar_weight() < 20) - description.listAppend("Gain " + (20 - $familiar[magic dragonfish].familiar_weight()) + " pounds on your magic dragonfish."); - - if (missing_hobopolis_spells.count() > 0) - description.listAppend("Could acquire " + missing_hobopolis_spells.listJoinComponents(", ", "or") + " from the mall."); - - if ($skill[frigidalmatian].skill_is_usable() && $effect[frigidalmatian].have_effect() == 0) - description.listAppend("Could cast frigidalmatian. (expensive)"); - - if (my_basestat($stat[mysticality]) < 400) - description.listAppend("May want to gain " + (400 - my_basestat($stat[mysticality])) + " more mysticality."); - - description.listAppend(pluralise(time_remaining, "turn", "turns") + " remaining in race."); - - - - - //$location[A Deserted Stretch of I-911] - optional_task_entries.listAppend(ChecklistEntryMake("__effect hare-brained", "place.php?whichplace=ioty2014_hare", ChecklistSubentryMake("Hare Race", modifiers, description)).ChecklistEntrySetIDTag("Grimstone mask hare")); -} - -void IOTMGrimstoneStepmotherGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - int minutes_to_midnight = get_property_int("cinderellaMinutesToMidnight"); - if (minutes_to_midnight <= 0) - return; - - //if (__misc_state["in run"] && !($locations[the prince's kitchen,the prince's balcony,the prince's lounge,the prince's canapes table,the prince's restroom,the prince's dance floor] contains __last_adventure_location) && minutes_to_midnight < 30) - //return; - - int score = get_property_int("cinderellaScore"); - string [int] description; - string [int] modifiers; - - - if (minutes_to_midnight > 0) - { - string line; - line = pluralise(minutes_to_midnight, "minute", "minutes") + " to midnight."; - - if (score > 0) - line += " " + pluralise(score, "point", "points") + " earned."; - - description.listAppend(line); - } - - /* - The idea behind this solution is you want to put three items into cindy's purse. - The first two make her ignore her hankerchief and go to the restroom - where the doctored soap gives her puffy eyes - whereupon she returns and confirms the disease rumor. - The third is the mouse, which you confront her about. Then later she'll not have the purse at all and go to the restroom again. - - There are other solutions, but I don't know them. Find them! It's a fun puzzle. - */ - - string [int][int] minute_to_action; - minute_to_action[30] = listMake("Lounge", "Take a cigar from the sideboard"); //I say, old chap - minute_to_action[29] = listMake("Balcony", "Examine the flowers."); //to give to prince - minute_to_action[28] = listMake("Canapés Table", "Give your carnation to the Prince."); //causes sneezing fit at 23, 13, 3 - minute_to_action[27] = listMake("Canapés Table", "Slip something into Cindy's purse while she's distracted", "The cigar."); //Make her leave when sneezing - minute_to_action[26] = listMake("Balcony", "Examine the flowers."); //For doctoring - minute_to_action[25] = listMake("Restroom", "Rub the flower on the soap."); //For 23 sneezing. - minute_to_action[24] = listMake("Lounge", "Start a rumor about Cinderella", "Cinderella has a terrible disease."); //Points! - minute_to_action[23] = listMake("Lounge", "Take the empty cigar box."); //Mouse trap setup. 3 points (from sneezing) - minute_to_action[22] = listMake("Kitchen", "Inspect the kitchen pantry."); //Acquire cinnamon, notice mouse hole. - minute_to_action[21] = listMake("Canapés Table", "Take a piece of cheese."); //Mouse trap setup. - minute_to_action[20] = listMake("Kitchen", "Set a trap for the mouse."); //Set up mouse trap with cigar box and cheese. (if we had room, soap too, but that adds one point and there's no room - used in 31-point solution) - minute_to_action[19] = listMake("Canapés Table", "Slip something into Cindy's purse while she's distracted", "The cinnamon."); //For 13 sneezing fit, makes her ignore hankerchief. - minute_to_action[18] = listMake("Lounge", "Take the whiskey flask."); //To make cindy drunk. 5 points (prince hears rumor) - minute_to_action[17] = listMake("Canapés Table", "Pour some whisky into Cindy's glass."); //Cindy's drunk - used at 16, 6, and extra points from soap. - minute_to_action[16] = listMake("Balcony", "Examine the flowers."); //For stealing a hairpin from baronness. 6 points (16 behavior hits, she's drunk) - minute_to_action[15] = listMake("Balcony", "Speak with the Baroness."); //First step baronness - minute_to_action[14] = listMake("Balcony", "Ask the Baroness what troubles her."); //Makes baronness move to dance floor - minute_to_action[13] = listMake("Dance Floor", "Give your carnation to the Baroness and steal one of her hairpins."); //Now we can steal a hairpin. 11 points (sneezing fit with disease rumor) - minute_to_action[12] = listMake("Restroom", "Look in the medicine cabinet", "Pick the lock", "Take the bottle of syrup of ipecac."); //Which we use to pick the lock of the medicine cabinet, acquiring ipecac. - minute_to_action[11] = listMake("Kitchen", "Dose the tray of cannoli with ipecac."); //Ipecac we use here. - minute_to_action[10] = listMake("Restroom", "Take some soap."); //We'll be throwing it later. - minute_to_action[9] = listMake("Canapés Table", "Offer Cindy your 'customized' cannoli."); //Makes her throw up in eight turns. (no cinnamon) - minute_to_action[8] = listMake("Kitchen", "Take the mouse out of the trap."); //It showed up. Hello mouse. - minute_to_action[7] = listMake("Canapés Table", "Slip something into Cindy's purse while she's distracted", "The mouse."); //Third time. - minute_to_action[6] = listMake("Canapés Table", "Ask Cindy to loan you her handkerchief."); //Hey, is that a mouse in your purse? 13 points. (one from mouse, one from 6 behavior) - minute_to_action[5] = listMake("Dance Floor", "Kick some soap at Cindy."); //She's on the dance floor. Let's make her dance. 15 points. (dance!) - minute_to_action[4] = listMake("Restroom", "Take some soap."); //Dancing supplies. - minute_to_action[3] = listMake("Dance Floor", "Kick some soap at Cindy."); //Dance. 21 points (sneezing, dance!) - minute_to_action[2] = listMake("Restroom", "Take some soap."); //Dancing supplies. - minute_to_action[1] = listMake("Dance Floor", "Kick some soap at Cindy."); //She throws up. Dance. 32 points. (she threw up, dance!) - - if (false) - { - //output full details for reference: - string line; - foreach minute in minute_to_action - { - string description = minute_to_action[minute]; - line = "|" + pluralise(minute, "minute", "minutes") + ":|*" + minute_to_action[minute].listJoinComponents(" > ") + line; - } - description.listAppend(line); - } - //FIXME add the other two trophies? - - - //int [int] needed_points_at_spot_to_be_following_correct_path; //score isn't tracked properly, and anyways there's split score per turn - - /* -√30 take cigar -√29 flower -√28 give flower to prince -√27 give cigar to cindy -√26 flower -√25 doctor soap -√24 spread rumour (disease) -√23 take empty cigar box -√22 inspect kitchen -√21 get cheese -√20 set trap -√19 plant cinnamon in cindy's purse -√18 get whiskey -√17 pour whiskey -√16 flower -√15 ask baronness -√14 ask baronness x2 -√13 steal from baronness -√12 steal ipecac -√11 make cannoli (mouse available) -√10 get soap -√9 give cindy cannoli -√8 get mouse -√7 plant mouse -√6 ask for hankerchief -√5 kick soap -√4 get soap -√3 kick soap -√2 get soap -√1 kick soap - */ - - boolean output_next_step = true; - //if (needed_points_at_spot_to_be_following_correct_path contains minutes_to_midnight && score != needed_points_at_spot_to_be_following_correct_path[minutes_to_midnight]) //they're doing a different route - //output_next_step = false; - - if (minute_to_action contains minutes_to_midnight && output_next_step) - { - description.listAppend("Next step for 32 points:|*" + minute_to_action[minutes_to_midnight].listJoinComponents(__html_right_arrow_character)); - description.listAppend("Though, this is a fun puzzle to solve on your own."); - } - - //FIXME add suggestions for other two trophies (partners in crime, ending party early) - optional_task_entries.listAppend(ChecklistEntryMake("__item long-stemmed rose", "place.php?whichplace=ioty2014_cindy", ChecklistSubentryMake("The Prince's Ball", modifiers, description)).ChecklistEntrySetIDTag("Grimstone mask stepmother")); -} - -void IOTMGrimstoneWolfGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //FIXME I have no idea - return; -} - -void IOTMGrimstoneWitchGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //FIXME I have no idea - return; -} - -void IOTMGrimstoneGnomeGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //FIXME I have no idea - return; -} - -RegisterTaskGenerationFunction("IOTMGrimstoneGenerateTasks"); -void IOTMGrimstoneGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //grimstoneMaskPath - //rumpelstiltskinTurnsUsed gives number of turns used getting materials. rumpelstiltskinKidsRescued gives the number of children rescued. It is likely that there are more messages than are documented on the wiki, so if some are missing and aren't parsed correctly, please put a note in the forum. - //cinderellaMinutesToMidnight gives number of turns remaining. cinderellaScore gives the current score. Also added grimstoneMaskPath which gives the current grimstone content available, "stepmother", "wolf", "witch", "gnome" or "hare". - - string mask_path = get_property("grimstoneMaskPath").to_lower_case(); - - if ($effect[hare-brained].have_effect() > 0) - IOTMGrimstoneHareGenerateTasks(task_entries, optional_task_entries, future_task_entries); - if (mask_path == "stepmother") - IOTMGrimstoneStepmotherGenerateTasks(task_entries, optional_task_entries, future_task_entries); - if (mask_path == "wolf") - IOTMGrimstoneWolfGenerateTasks(task_entries, optional_task_entries, future_task_entries); - if (mask_path == "witch") - IOTMGrimstoneWitchGenerateTasks(task_entries, optional_task_entries, future_task_entries); - if (mask_path == "gnome") - IOTMGrimstoneGnomeGenerateTasks(task_entries, optional_task_entries, future_task_entries); - if (mask_path == "tuxedo") - task_entries.listAppend(ChecklistEntryMake("__item long-stemmed rose", "place.php?whichplace=arcade", ChecklistSubentryMake("Believe in yourself", "", ""), -11).ChecklistEntrySetIDTag("Grimstone mask Sailor Moon reference")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2014/Speakeasy.ash b/Source/relay/TourGuide/Items of the Month/2014/Speakeasy.ash deleted file mode 100644 index 00f9d19f..00000000 --- a/Source/relay/TourGuide/Items of the Month/2014/Speakeasy.ash +++ /dev/null @@ -1,118 +0,0 @@ - -RegisterResourceGenerationFunction("IOTMSpeakeasyGenerateResource"); -void IOTMSpeakeasyGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["VIP available"]) - return; - - if (!(__misc_state["can drink just about anything"] && get_property_int("_speakeasyDrinksDrunk") <3 && mafiaIsPastRevision(14155) && availableDrunkenness() >= 0)) - return; - if (!$item[clan speakeasy].is_unrestricted()) - return; - - //speakeasy: - /* - √Lucky lindy - good 1-potency, gives semi-rare. crucial in zombie slayer - Bee's Knees - awesome 2-potency, 25 turns of +100% all stats - √Sockdollager - awesome 2-potency, 25 turns of (+20 all elemental damage, +40 all elemental spell damage, +20 ranged/weapon damage, +50% weapon/spell damage, +50 spell damage - Flivver - 20,000 meat epic 2-potency, restores mana (not useful in-run) - √Hot Socks - awesome 3-potency, 50 turns of (+2 familiar experience, +10 familiar weight, +20 familiar damage) - √Sloppy Jalopy - 100,000 meat awesome 5-potency, gives skill Hollow Leg (+1 liver capacity) for aftercore - Phonus Balonus - +fights/+adventures - Ish Kabibble - +3 all res, +DA/DR - */ - int drinks_remaining = MAX(3 - get_property_int("_speakeasyDrinksDrunk"), 0); - - string [int][int] options; - - options.listAppend(listMake("Drink", "Size", "Description")); - options.listAppend(listMake("Lucky Lindy", "6", "Get Lucky!")); - - //FIXME every drink - //FIXME gray out drinks we can't drink at the moment (drunkenness, meat) - - if ($effect[1701].have_effect() == 0 && !__misc_state["familiars temporarily blocked"] && __misc_state["in run"]) //hip to the jive - { - string [int] description; - description.listAppend("+10 familiar weight"); - if (familiar_weight(my_familiar()) < 20) - description.listAppend("+2 familiar exp/fight"); - options.listAppend(listMake("Hot Socks", "3", description.listJoinComponents("|"))); - } - - if (!__misc_state["in run"] && !$skill[Hollow Leg].skill_is_usable()) - options.listAppend(listMake("Sloppy Jalopy", "5", "+1 liver capacity skill|Very expensive")); - - - string [int] reasons_to_sockdollager; - if (!__quest_state["Level 3"].finished) - { - boolean can_skip_cold = numeric_modifier("Cold Damage") >= 20.0; - boolean can_skip_hot = numeric_modifier("Hot Damage") >= 20.0; - boolean can_skip_spooky = numeric_modifier("Spooky Damage") >= 20.0; - boolean can_skip_stench = numeric_modifier("Stench Damage") >= 20.0; - if (!can_skip_cold || !can_skip_hot || !can_skip_spooky || !can_skip_stench) - reasons_to_sockdollager.listAppend("tavern NC skipping"); - } - - if (!__quest_state["Level 13"].state_boolean["Elemental damage race completed"]) - reasons_to_sockdollager.listAppend("Elemental damage race"); - - if (my_path().id == PATH_HEAVY_RAINS && !__quest_state["Level 13"].finished) - reasons_to_sockdollager.listAppend("fighting rain king"); - - if (reasons_to_sockdollager.count() > 0) - options.listAppend(listMake("Sockdollager", "2", reasons_to_sockdollager.listJoinComponents(", ", "and").capitaliseFirstLetter())); - - if (__misc_state["in run"] && my_meat() >= 20000) - options.listAppend(listMake("Flivver", "2", "Epic-level drunkenness.")); - - if (__misc_state["need to level"]) - { - string drink_name = ""; - - if (my_primestat() == $stat[muscle]) - { - drink_name = "Glass of \"milk\""; - } - else if (my_primestat() == $stat[mysticality]) - { - drink_name = "Cup of \"tea\""; - } - else if (my_primestat() == $stat[moxie]) - { - drink_name = "Thermos of \"whiskey\""; - } - if (drink_name != "") - { - float mainstat_gain = 87.5 * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); - string description = mainstat_gain.roundForOutput(0) + " mainstat"; - //if (my_path().id != PATH_SLOW_AND_STEADY) - //description += ""; - options.listAppend(listMake(drink_name, "1", description)); - } - - } - - if (hippy_stone_broken()) - { - options.listAppend(listMake("Phonus Balonus", "3", "+fights/+adventures")); - } - - if (my_path().id == PATH_NUCLEAR_AUTUMN) - { - foreach key in options - { - if (options[key][1].to_int_silent() > 1) - remove options[key]; - } - } - - string [int] description; - if (options.count() > 1) - description.listAppend(HTMLGenerateSimpleTableLines(options)); - - if (__misc_state["in run"] || drinks_remaining > 0) - resource_entries.listAppend(ChecklistEntryMake("__item observational glasses", "clan_viplounge.php?action=speakeasy", ChecklistSubentryMake(pluralise(drinks_remaining, "speakeasy drink", "speakeasy drinks"), "", description), 8).ChecklistEntrySetIDTag("Clan VIP speakeasy resource")); //the eyes of T.J. Eckleburg - -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2014/SpringBreakBeach.ash b/Source/relay/TourGuide/Items of the Month/2014/SpringBreakBeach.ash deleted file mode 100644 index 309a68ef..00000000 --- a/Source/relay/TourGuide/Items of the Month/2014/SpringBreakBeach.ash +++ /dev/null @@ -1,20 +0,0 @@ -//Spring Break Beach cash register -RegisterTaskGenerationFunction("IOTMSpringBreakBeachGenerateTasks"); -void IOTMSpringBreakBeachGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__misc_state["sleaze airport available"]) - return; - int dinerBucksLeft = clampi(4 - get_property_int("_sloppyDinerBeachBucks"), 0, 4); - string url; - string [int] description; - if (dinerBucksLeft > 0) - { - string title = (dinerBucksLeft + " Sloppy Seconds Diner cash register raids"); - url = "place.php?whichplace=airport_sleaze"; - description.listAppend("Money money money money monay!"); - if (!lookupSkill("sloppy secrets").have_skill()) { - description.listAppend("Learn Sloppy Secrets for more Beach Bucks."); - } - optional_task_entries.listAppend(ChecklistEntryMake("__item beach buck", url, ChecklistSubentryMake(title, "", description), 8)); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2015/Barrel God.ash b/Source/relay/TourGuide/Items of the Month/2015/Barrel God.ash deleted file mode 100644 index 4f310184..00000000 --- a/Source/relay/TourGuide/Items of the Month/2015/Barrel God.ash +++ /dev/null @@ -1,84 +0,0 @@ - -RegisterResourceGenerationFunction("IOTMBarrelGodGenerateResource"); -void IOTMBarrelGodGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[shrine to the Barrel god]]) - return; - - - if (!get_property_boolean("_barrelPrayer") && mafiaIsPastRevision(16316)) - { - string [int] description; - string [int][int] gear; - - if (__misc_state["can equip just about any weapon"] && !get_property_boolean("prayedForProtection")) - gear.listAppend(listMake("Protection", "+50 ML, +100 HP, +25% muscle offhand")); - if (!get_property_boolean("prayedForGlamour")) - gear.listAppend(listMake("Glamour", "+50% item, ~8 MP regen, +25% myst accessory")); - if (!get_property_boolean("prayedForVigor")) - gear.listAppend(listMake("Vigor", "+50% init, ~15 HP regen, +25% moxie pants")); - - if (gear.count() > 0) - description.listAppend("Once/ascension gear:|*" + HTMLGenerateSimpleTableLines(gear)); - string buff_description; - if (my_class() == $class[seal clubber]) - buff_description = "+150% weapon damage"; - else if (my_class() == $class[turtle tamer]) - buff_description = "ode-to-booze type for food"; - else if (my_class() == $class[pastamancer]) - buff_description = "+90% item"; - else if (my_class() == $class[sauceror]) - buff_description = "+150% spell damage"; - else if (my_class() == $class[disco bandit]) - buff_description = "+150% ranged damage"; - else if (my_class() == $class[accordion thief]) - buff_description = "ode-to-booze type / +45% booze drops"; - - if (buff_description != "") - description.listAppend(buff_description.capitaliseFirstLetter() + " buff for 50 turns." + ($item[map to the Biggest Barrel].available_amount() == 0 && (my_daycount() >= 7 || !in_ronin()) ? "|Might give the map to the Biggest Barrel." : "")); - - resource_entries.listAppend(ChecklistEntryMake("barrel god", "da.php?barrelshrine=1", ChecklistSubentryMake("Barrel worship", "", description), 8).ChecklistEntrySetIDTag("Barrel God resource")); - } - - item [int] barrels_around; - foreach it in $items[little firkin,normal barrel,big tun,weathered barrel,dusty barrel,disintegrating barrel,moist barrel,rotting barrel,mouldering barrel,barnacled barrel] - { - if (it.item_amount() > 0) - barrels_around.listAppend(it); - } - if (barrels_around.count() > 0) - { - string [int] plurals; - foreach key, it in barrels_around - { - plurals.listAppend(pluralise(it.item_amount(), it)); - } - string url = "inv_use.php?pwd=" + my_hash() + "&whichitem=" + barrels_around[0].to_int() + "&choice=1"; - string [int] description; - description.listAppend(plurals.listJoinComponents(", ", "and") + "."); - resource_entries.listAppend(ChecklistEntryMake("__item " + barrels_around[0], url, ChecklistSubentryMake("Smashable barrels", "", description), 8)); - - } -} -RegisterTaskGenerationFunction("IOTMBarrelGodGenerateTasks"); -void IOTMBarrelGodGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //we could suggest they defeat the barrelmech if they have the map anyways... hmm - if ($item[map to the Biggest Barrel].available_amount() > 0 && (!$item[chest barrel].haveAtLeastXOfItemEverywhere(1) || !$item[barrelhead].haveAtLeastXOfItemEverywhere(1) || !$item[bottoms of the barrel].haveAtLeastXOfItemEverywhere(1))) - { - string [int] description; - description.listAppend("Use map to the Biggest Barrel."); - description.listAppend("To defeat him, deal up to, but not over, 150 HP/round. Otherwise, he'll heal his HP.|You'll also want healing items."); - if ($skill[belch the rainbow].have_skill()) - description.listAppend("Could run -250 ML and cast belch the rainbow over and over, if you've upgraded that."); - if (!in_ronin()) - { - string line = "Could throw chipotle wasabi cilantro aioli repeatedly."; - if ($item[chipotle wasabi cilantro aioli].item_amount() < 22) - line += "|Acquire 22 of them first, though."; - description.listAppend(line); - } - description.listAppend("Can only be fought once a day, until defeated."); - optional_task_entries.listAppend(ChecklistEntryMake("barrel god", "inventory.php?ftext=map+to+the+Biggest+Barrel", ChecklistSubentryMake("Defeat the Barrelmech", "", description), 8).ChecklistEntrySetIDTag("Barrel god biggest fight")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2015/Deck of Every Card.ash b/Source/relay/TourGuide/Items of the Month/2015/Deck of Every Card.ash deleted file mode 100644 index ad523702..00000000 --- a/Source/relay/TourGuide/Items of the Month/2015/Deck of Every Card.ash +++ /dev/null @@ -1,330 +0,0 @@ -record DOECSummon -{ - string [int] cards; - string reason; -}; - -DOECSummon DOECSummonMake(string [int] cards, string reason) -{ - DOECSummon summon; - summon.cards = cards; - summon.reason = reason; - return summon; -} - -DOECSummon DOECSummonMake(string card, string reason) -{ - string [int] cards; - cards.listAppend(card); - return DOECSummonMake(cards, reason); -} - -void listAppend(DOECSummon [int] list, DOECSummon entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -RegisterResourceGenerationFunction("IOTMDeckOfEveryCardGenerateResource"); -void IOTMDeckOfEveryCardGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[Deck of Every Card]]) - return; - - if (!mafiaIsPastRevision(16018)) - return; - - if (my_path().id == PATH_G_LOVER) return; // cannot use in glover - - int card_summons_left = clampi(15 - get_property_int("_deckCardsDrawn"), 0, 15); - - /* - In-run: - √Sheep - 3 stone wool - √X - The Wheel of Fortune - +100% item for 20 turns - √[mainstat cards] - gain 500 mainstat - √XVI - The Tower - DD key - Professor Plum - lets you make ten crimbo pies under the knoll sign. maybe useful if we have fullness over, like, twenty-five? - √Spare tire/Extra tank - something meatcar outside of knoll, might not be worth it? just summon the 10k card and buy a bus pass (ignoring... maybe surprising fist?) - Fish DNA - acquire a free runaway in... HCO? or any path where that's relevant (not HR) - X of Coins - X * 500 meat - if we have low meat and we've already summoned the mantle... maybe - √[three +mainstat cards] - stat test in the tower - √weapons - - - - Aftercore: - √random cards - fun! - √knife - meat farming - Laboratory - five random potions? ??? - √[monster types] - fight a random monster for factoids - √gift card - sell a draw in the mall to the needy - √IV - The Emperor - until we have outfit - IX - The Hermit - until we have all factoids - - Both: - √ancestral recall / Island - if you have Ancestral Recall, indirectly gives +3 adventures. not useful in S&S - √X of Clubs - +3 PVP fights - √1952 Mickey Mantle - 10k autosell - - Unknown: - X of Diamonds - X * 100 meat - never? maybe ~550 meat on average? even in run... eh... - X of Swords - technically optimal (saw one that gave two SBIPs and an antique machete) but random - - - one card/day/card limit when cheating - */ - - boolean in_run = __misc_state["in run"]; - - DOECSummon [int] summons; - - if (in_run && (__misc_state_int["fat loot tokens needed"] > 0 || (!in_ronin() && __misc_state_int["hero keys missing"] > 0))) - summons.listAppend(DOECSummonMake("XVI - The Tower", "Daily Dungeon key.")); - - - if (my_path().id != PATH_SLOW_AND_STEADY) - { - if ($skill[ancestral recall].skill_is_usable()) - { - summons.listAppend(DOECSummonMake(listMake("Ancestral Recall", "Island"), "+3 adventures via ancestral recall.")); - } - else if (!in_run) - { - summons.listAppend(DOECSummonMake("Ancestral Recall", "Gives +adventure summoning skill.")); - } - } - - if (hippy_stone_broken()) - summons.listAppend(DOECSummonMake("X of Clubs", "+3 PVP fights.")); - - if (in_run) - summons.listAppend(DOECSummonMake("X - The Wheel of Fortune", "+100% item for 20 turns.")); - - if (in_run && __misc_state["need to level"] && my_path().id != PATH_THE_SOURCE) - { - string card_name = "Cardiff"; - if (my_primestat() == $stat[muscle]) - card_name = "XXI - The World"; - else if (my_primestat() == $stat[mysticality]) - card_name = "III - The Empress"; - else if (my_primestat() == $stat[moxie]) - card_name = "VI - The Lovers"; - - summons.listAppend(DOECSummonMake(card_name, "+" + (500 * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0)).floor() + " mainstat.")); - } - - if (in_run && !__quest_state["Level 8"].state_boolean["Past mine"]) - { - int missing_ore = MAX(0, 3 - __quest_state["Level 8"].state_string["ore needed"].to_item().available_amount()); - if (missing_ore > 0) - summons.listAppend(DOECSummonMake("Mine", "One of every ore.")); - } - - if (!in_run && $item[knife].available_amount() == 0) - summons.listAppend(DOECSummonMake("Knife", "+50% meat farming weapon.")); - - if (in_run && $items[lead pipe,rope,wrench,candlestick,knife,revolver].items_missing().count() == 6) - { - /* - Important point on the +stat equipment - there's another card that gives 500 mainstat. So, if that's all you're using the weapon for, you'd need to use it for over 250 fights in a day to be worthwhile. - You can, of course, summon both... but in that situation, there's probably a better summon instead? - - √lead pipe - 1h club. +100% muscle, +50 HP, vanishes at rollover. - Hmm... for muscle classes that don't have familiars? Or seal clubbers? - +100% mainstat is a lot... - √rope - 1h whip. +2 muscle/fight, +10 familiar weight, vanishes at rollover. - Muscle classes. Any class that has a runaway familiar. Maybe just any class that has a familiar? - - √wrench - 1h utensil. +100% spell damage, +50 MP. - For myst classes that don't need stats. - √candlestick - 1h wand. +2 myst/fight, +100% myst, vanishes at rollover. - For myst classes that need stats. - - √knife - 1h knife. +50% meat, +100% moxie, vanishes at rollover. - For moxie classes. Even then... - +100% mainstat is a lot... - √revolver - 1h pistol. +50% init, +2 moxie/fight, vanishes at rollover. - For moxie classes that need stats? Ehh... - */ - DOECSummon [int] weapon_choices; - - - if (my_primestat() == $stat[muscle]) - { - if (!($skill[summon smithsness].skill_is_usable() && my_class() == $class[seal clubber])) - weapon_choices.listAppend(DOECSummonMake("Lead pipe", "+100% muscle, +HP club.")); - //Rope is mentioned elsewhere - } - if (my_primestat() == $stat[mysticality] && !$skill[summon smithsness].skill_is_usable()) - { - weapon_choices.listAppend(DOECSummonMake("Wrench", "+100% spell damage weapon.")); //this will do more damage on average than the candlestick, so it's more worthwhile? (compare capped spells versus scaling spells - spell damage affects saucestorm, +myst doesnt') - //Is the candlestick worth summoning? - if (__misc_state["need to level"]) - weapon_choices.listAppend(DOECSummonMake("Candlestick", "+100% myst, +2 myst/fight weapon. (wrench may be better)")); - } - if (my_primestat() == $stat[moxie] && !$skill[summon smithsness].skill_is_usable()) - { - if ($skill[tricky knifework].skill_is_usable()) - weapon_choices.listAppend(DOECSummonMake("Knife", "+50% meat, +100% moxie knife.")); - if (__misc_state["need to level"] && !$skill[tricky knifework].skill_is_usable()) - weapon_choices.listAppend(DOECSummonMake("Revolver", "+50% init, +2 moxie/fight ranged weapon.")); //ignored for DBs, because of the stat issue mentioned above - } - if (!__misc_state["familiars temporarily blocked"]) - { - //is this worthwhile for non-muscle classes without free runaway familiars? - string line; - line = "+10 familiar weight"; - if (my_primestat() == $stat[muscle] && __misc_state["need to level"]) - line += ", +2 muscle/fight"; - line += " weapon."; - weapon_choices.listAppend(DOECSummonMake("Rope", line)); - } - - foreach key, summon in weapon_choices - { - //FIXME combine? - summons.listAppend(summon); - } - } - - summons.listAppend(DOECSummonMake("1952 Mickey Mantle", "Autosells for 10k.")); - - - if (in_run && my_path().id != PATH_COMMUNITY_SERVICE) - { - int wool_needed = 0; - if (!$location[the hidden park].locationAvailable()) - { - wool_needed += 1; - if ($item[the nostril of the serpent].available_amount() == 0 && !get_property_ascension("lastTempleButtonsUnlock")) - wool_needed += 1; - } - if ($item[stone wool].available_amount() < wool_needed) - { - summons.listAppend(DOECSummonMake("Sheep", "3 stone wool.")); - } - else if ($item[stone wool].available_amount() - wool_needed <= 0 && !get_property_ascension("lastTempleAdventures") && my_path().id != PATH_SLOW_AND_STEADY) - { - summons.listAppend(DOECSummonMake("Sheep", "Stone wool for +3 adventures via temple.")); - } - } - - if (!in_run) - { - int missing_emperor_pieces = missing_outfit_components("The Emperor's New Clothes").count(); - if (missing_emperor_pieces > $item[The Emperor's dry cleaning].available_amount()) - summons.listAppend(DOECSummonMake("IV - The Emperor", "The Emperor's New Clothes outfit.")); - - summons.listAppend(DOECSummonMake("Gift card", "Sell to the needy.")); - - string [int][int] tooltip_table; - tooltip_table.listAppend(listMake("II - The High Priestess", "Hippy")); - tooltip_table.listAppend(listMake("V - The Hierophant", "Dude")); - tooltip_table.listAppend(listMake("VII - The Chariot", "Construct")); - tooltip_table.listAppend(listMake("XII - The Hanged Man", "Orc")); - tooltip_table.listAppend(listMake("XIII - Death", "Undead")); - tooltip_table.listAppend(listMake("XIV - Temperance", "Hobo")); - tooltip_table.listAppend(listMake("XV - The Devil", "Demon")); - tooltip_table.listAppend(listMake("XVII - The Star", "Constellation")); - tooltip_table.listAppend(listMake("XVIII - The Moon", "Horror")); - tooltip_table.listAppend(listMake("The Hive", "Bug")); - tooltip_table.listAppend(listMake("Goblin Sapper", "Goblin")); - tooltip_table.listAppend(listMake("Fire Elemental", "Elemental")); - tooltip_table.listAppend(listMake("Unstable Portal", "Weird")); - tooltip_table.listAppend(listMake("Werewolf", "Beast")); - tooltip_table.listAppend(listMake("Go Fish", "Fish")); - tooltip_table.listAppend(listMake("Plantable Greeting Card", "Plant")); - tooltip_table.listAppend(listMake("Pirate Birthday Card", "Pirate")); - tooltip_table.listAppend(listMake("Christmas Card", "Elf")); - tooltip_table.listAppend(listMake("Suit Warehouse Discount Card", "Penguin")); - tooltip_table.listAppend(listMake("Slimer Trading Card", "Slime")); - tooltip_table.listAppend(listMake("Aquarius Horoscope", "Mer-Kin")); - tooltip_table.listAppend(listMake("Hunky Fireman Card", "Humanoid")); - - buffer tooltip_text; - tooltip_text.append(HTMLGenerateTagWrap("div", "Monster Cards", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); - tooltip_text.append(HTMLGenerateSimpleTableLines(tooltip_table)); - - string title = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Monster card", "r_tooltip_outer_class"); - summons.listAppend(DOECSummonMake(title, "Past factoids.")); - } - - if (in_run && !__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "") - { - stat stat_race_type = __quest_state["Level 13"].state_string["Stat race type"].to_stat(); - string card_name = "Joker"; - effect relevant_effect; - if (stat_race_type == $stat[muscle]) - { - card_name = "XI - Strength"; - relevant_effect = to_effect("1912"); - } - else if (stat_race_type == $stat[mysticality]) - { - card_name = "I - The Magician"; - relevant_effect = to_effect("1911"); - } - else if (stat_race_type == $stat[moxie]) - { - card_name = "0 - The Fool"; - relevant_effect = to_effect("1910"); - } - if (relevant_effect.have_effect() == 0) - summons.listAppend(DOECSummonMake(card_name, "+200% " + stat_race_type.to_lower_case() + " for lair races. (marginal)")); - } - if (!in_run) - { - if (!haveAtLeastXOfItemEverywhere($item[talking spade], 1)) - summons.listAppend(DOECSummonMake("X of Spades", "Solve spade puzzle.")); - if (card_summons_left >= 5) - summons.listAppend(DOECSummonMake("Random card", pluralise(card_summons_left, "luck of the draw", "lucks of the draw") + ".")); - } - - boolean [string] cards_already_drawn = get_property("_deckCardsSeen").split_string("\\|").listInvert(); - - string [int][int] card_table; - if (card_summons_left >= 5) - { - foreach key, summon in summons - { - string [int] valid_cards; - foreach key, card in summon.cards - { - if (!cards_already_drawn[card]) - valid_cards.listAppend(card); - } - if (valid_cards.count() == 0) continue; - card_table.listAppend(listMake(valid_cards.listJoinComponents(" / "), summon.reason)); - } - } - - if ((card_table.count() > 0 || card_summons_left < 5) && card_summons_left > 0) - { - string title; - string [int] description; - - if (card_summons_left >= 5) - { - title = pluralise(card_summons_left / 5, "card drawable", "cards drawable"); - } - else - { - title = pluralise(card_summons_left, "random card summon", "random card summons"); - string line = "Luck of the draw."; - if (in_run) - line += " (may cost turns)"; - description.listAppend(line); - } - - - // Detect replica versus genie classic for the purposes of the URL - string activeDeckID = lookupItem("replica deck of every card").available_amount() > 0 ? "11230" : "8382"; - - if (card_table.count() > 0) - description.listAppend(HTMLGenerateSimpleTableLines(card_table)); - resource_entries.listAppend(ChecklistEntryMake("__item deck of every card", "inv_use.php?cheat=1&pwd=" + my_hash() + "&whichitem="+activeDeckID, ChecklistSubentryMake(title, "", description), 1).ChecklistEntrySetIDTag("Deck of every card resource")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2015/Haunted Doghouse.ash b/Source/relay/TourGuide/Items of the Month/2015/Haunted Doghouse.ash deleted file mode 100644 index 95612a54..00000000 --- a/Source/relay/TourGuide/Items of the Month/2015/Haunted Doghouse.ash +++ /dev/null @@ -1,14 +0,0 @@ -RegisterResourceGenerationFunction("IOTMHauntedDoghouseGenerateResource"); -void IOTMHauntedDoghouseGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["in run"]) - return; - if ($item[tennis ball].available_amount() > 0 && in_ronin() && $item[tennis ball].item_is_usable()) - { - resource_entries.listAppend(ChecklistEntryMake("__item tennis ball", "", ChecklistSubentryMake(pluralise($item[tennis ball]), "", "Free run/banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Haunted doghouse banish")); - } - //I, um, hmm. I guess there's not much to say. Poor lonely file, nearly empty. -} - - - diff --git a/Source/relay/TourGuide/Items of the Month/2015/Machine Elf.ash b/Source/relay/TourGuide/Items of the Month/2015/Machine Elf.ash deleted file mode 100644 index a7fb12f9..00000000 --- a/Source/relay/TourGuide/Items of the Month/2015/Machine Elf.ash +++ /dev/null @@ -1,187 +0,0 @@ -static -{ - string [item] __machine_elf_abstractions_description; - - void machineElfAbstractionDescriptionsInit() - { - __machine_elf_abstractions_description[$item[abstraction: motion]] = "+100% init"; - __machine_elf_abstractions_description[$item[abstraction: certainty]] = "+100% item"; - __machine_elf_abstractions_description[$item[abstraction: joy]] = "+10 familiar weight"; - __machine_elf_abstractions_description[$item[abstraction: category]] = "+25% mysticality gains"; - __machine_elf_abstractions_description[$item[abstraction: perception]] = "+25% moxie gains"; - __machine_elf_abstractions_description[$item[abstraction: purpose]] = "+25% muscle gains"; - } - machineElfAbstractionDescriptionsInit(); -} - -//Machine Elf DMT Alert -RegisterTaskGenerationFunction("IOTMMachineElfGenerateTasks"); -void IOTMMachineElfGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - string [int] description; - string url = "place.php?whichplace=dmt"; - int DMTDuplicationAscension = get_property_int("lastDMTDuplication"); - int DMTTimer = get_property_int("encountersUntilDMTChoice"); - if (DMTTimer == 0 && my_ascensions() > DMTDuplicationAscension) - { - description.listAppend("" + HTMLGenerateSpanFont("Item duplication available!", "blue") + ""); - description.listAppend("Copy a PVPable potion, food, drink, or spleen item."); - task_entries.listAppend(ChecklistEntryMake("__item abstraction: comprehension", url, ChecklistSubentryMake("Deep Machine Tunnels noncom ready!", "", description), -11)); - } -} - -RegisterResourceGenerationFunction("IOTMMachineElfFamiliarGenerateResource"); -void IOTMMachineElfFamiliarGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!$familiar[machine elf].familiar_is_usable()) - return; - - string url = "place.php?whichplace=dmt"; - if (my_familiar() != $familiar[machine elf]) - url = "familiar.php"; - int importance = 0; - if (!__misc_state["in run"] || !__misc_state["need to level"]) - importance = 6; - - ChecklistEntry entry; - entry.image_lookup_name = "__familiar machine elf"; - entry.url = url; - entry.tags.id = "Machine elf tunnels resource"; - entry.importance_level = importance; - if (__last_adventure_location == $location[the deep machine tunnels]) - entry.should_highlight = true; - - // Using prefs for this now! Whoo! - int lastDMTDuplication = get_property_int("lastDMTDuplication"); - int encountersUntilDMTChoice = get_property_int("encountersUntilDMTChoice"); - - // Starts every ascension at 5, but is every 50 turns after that first turn #6 dupe. Given - // how long ascensions take and how many turns are likely used in the DMT (read: not many), - // this feels like pretty safe logic as long as we keep the in_run checks in this code. - boolean duplication_nc_probably_visited = encountersUntilDMTChoice > 6 ? true : false; - - // if (!duplication_nc_probably_visited && $location[the deep machine tunnels].turns_spent >= 5) - // Checks that the DMT choice is up and you haven't gotten one this run - if (encountersUntilDMTChoice == 0 && lastDMTDuplication < my_ascensions()) - { - string [int] description; - description.listAppend("Next turn in the DMT. Costs a turn."); - description.listAppend("Copy a PVPable potion, food, drink, or spleen item."); - item [int] suggested_items; - if (suggested_items.count() > 0) - description.listAppend("Possibly " + suggested_items.listJoinComponents(", ", "or") + "."); - entry.subentries.listAppend(ChecklistSubentryMake("Item duplication available", "", description)); - } - - - - int free_fights_remaining = clampi(5 - get_property_int("_machineTunnelsAdv"), 0, 5); - if (free_fights_remaining > 0 && mafiaIsPastRevision(16550)) - { - string [int] description; - string [int] modifiers; - string [int] tasks; - if (my_familiar() != $familiar[machine elf]) - { - tasks.listAppend("bring along your machine elf"); - } - tasks.listAppend("adventure in the machine tunnels"); - string line = tasks.listJoinComponents(", ", "and").capitaliseFirstLetter(); - if (__misc_state["need to level"]) - { - modifiers.listAppend("+" + my_primestat().to_lower_case()); - line += " to gain stats"; - } - line += "."; - description.listAppend(line); - - if (spleen_limit() > 0) - { - //abstraction: sensation -> square monster -> abstraction: motion (+100% init) - //abstraction: thought -> triangle monster -> abstraction: certainty (+100% item) - //abstraction: action -> circle monster -> abstraction: joy (+10 familiar weight) - //FIXME suggest abstraction methods. - item [item] abstraction_conversions; - abstraction_conversions[$item[abstraction: sensation]] = $item[abstraction: motion]; - abstraction_conversions[$item[abstraction: thought]] = $item[abstraction: certainty]; - if (!__misc_state["familiars temporarily blocked"]) - abstraction_conversions[$item[abstraction: action]] = $item[abstraction: joy]; - - monster [item] abstraction_monsters; - abstraction_monsters[$item[abstraction: sensation]] = $monster[Performer of Actions]; - abstraction_monsters[$item[abstraction: thought]] = $monster[Perceiver of Sensations]; - abstraction_monsters[$item[abstraction: action]] = $monster[Thinker of Thoughts]; - - string [monster] monster_descriptions; - monster_descriptions[$monster[Performer of Actions]] = "square"; - monster_descriptions[$monster[Perceiver of Sensations]] = "triangle"; - monster_descriptions[$monster[Thinker of Thoughts]] = "circle"; - - - - foreach source, result in abstraction_conversions - { - string result_description = __machine_elf_abstractions_description[result]; - if (result_description == "") - continue; - if (source.item_amount() == 0) - continue; - - monster m = abstraction_monsters[source]; - string monster_text = monster_descriptions[m] + " monster"; - - string line = "Throw " + source + " at " + monster_text; - if (last_monster() == m) - line = HTMLGenerateSpanOfClass(line, "r_bold"); - line += " for " + result_description + " spleen potion. (50 turns)"; - - description.listAppend(line); - } - if ($item[abstraction: thought].item_amount() == 0) - description.listAppend("Possibly run the machine elf elsewhere first, for transmutable potions."); - } - //entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_fights_remaining, "free elf fight", "free elf fights"), modifiers, description)); - resource_entries.listAppend(ChecklistEntryMake(entry.image_lookup_name, entry.url, ChecklistSubentryMake(pluralise(free_fights_remaining, "free elf fight", "free elf fights"), modifiers, description)).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Machine elf free fights")); - } - if (entry.subentries.count() > 0) - { - resource_entries.listAppend(entry); - } -} - -RegisterResourceGenerationFunction("IOTMMachineElfGenerateResource"); -void IOTMMachineElfGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (in_ronin() && spleen_limit() > 0) - { - boolean [item] useful_abstractions; - - useful_abstractions[$item[abstraction: motion]] = true; - useful_abstractions[$item[abstraction: certainty]] = true; - if (!__misc_state["familiars temporarily blocked"]) - useful_abstractions[$item[abstraction: joy]] = true; - if (__misc_state["need to level"]) - { - if (my_primestat() == $stat[muscle]) - useful_abstractions[$item[abstraction: purpose]] = true; - else if (my_primestat() == $stat[mysticality]) - useful_abstractions[$item[abstraction: category]] = true; - else if (my_primestat() == $stat[moxie]) - useful_abstractions[$item[abstraction: perception]] = true; - } - - string image_name = ""; - ChecklistSubentry [int] abstraction_lines; - foreach it in useful_abstractions - { - if (it.available_amount() == 0 || !it.is_unrestricted()) - continue; - string description = __machine_elf_abstractions_description[it] + ". (50 turns, one spleen)"; - if (image_name == "") - image_name = "__item " + it; - abstraction_lines.listAppend(ChecklistSubentryMake(pluralise(it), "", description)); - } - if (abstraction_lines.count() > 0) - resource_entries.listAppend(ChecklistEntryMake(image_name, "inventory.php?which=1", abstraction_lines, 7).ChecklistEntrySetIDTag("Machine elf abstraction resource")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2015/Mayo Clinic.ash b/Source/relay/TourGuide/Items of the Month/2015/Mayo Clinic.ash deleted file mode 100644 index 469f9c4b..00000000 --- a/Source/relay/TourGuide/Items of the Month/2015/Mayo Clinic.ash +++ /dev/null @@ -1,91 +0,0 @@ -RegisterResourceGenerationFunction("IOTMMayoClinicGenerateResource"); -void IOTMMayoClinicGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (__misc_state["campground unavailable"]) - return; - if (__campground[$item[portable Mayo Clinic]] == 0 || in_bad_moon()) - return; - - //mayoLevel - int mayo_level = get_property_int("mayoLevel"); - - if (availableFullness() > 0) - { - //stuff: - //Mayonex - food adventures -> blood mayo (???) - //Mayodiol -> one fullness becomes one drunkenness - //Mayostat -> one-fullness same quality restore - //Mayozapine -> increased stat gains - //Mayoflex -> +1 adventure - //Mayo Minder™ -> um... I guess it uses the above things for you. reminds me of buying the autorefueler in EV.. - } - - if (!get_property_boolean("_mayoDeviceRented")) - { - string [int] description; - //sphygmayomanometer - +(20 + mayo_level)% stats - //tomayohawk-style reflex hammer - reusable combat item. stagger, mayo-level sleaze damage - //mayo lance - YR combat item, requires at least one blood mayo - //miracle whip - nice day two/three equip. +50% init, +50% item, +100% meat, +100% wait, I only get one of these a run? - - string line = "Lasts the rest of the day. Can only choose one."; - if (my_meat() < 2500) - line += "|Need at least 2500 meat first."; - description.listAppend(line); - - string [int][int] choices; - - choices.listAppend(listMake("Sphygmayomanometer", "+" + (20 + mayo_level) + "% all stats")); - choices.listAppend(listMake("Tomayohawk-style reflex hammer", "Reusable combat item.|Staggers and deals mayo-level sleaze damage.")); - string lance_description = "Yellow ray. "; - if (__misc_state["yellow ray available"]) - lance_description = "Shorter yellow ray. "; - lance_description += HTMLGenerateDivOfClass("Uses up blood mayo.", "r_word_wrap_group"); - choices.listAppend(listMake("Mayo lance", lance_description)); - - if (!get_property_boolean("mayoWhipRented") && !get_property_boolean("itemBoughtPerAscension8266") && my_path().id != PATH_GELATINOUS_NOOB) - { - choices.listAppend(listMake("Miracle whip", "Weapon, usable " + HTMLGenerateSpanFont("once", "red") + " per run.|+50% item, +100% meat, +50% init.")); - } - description.listAppend(HTMLGenerateSimpleTableLines(choices)); - resource_entries.listAppend(ChecklistEntryMake("__item sphygmayomanometer", "campground.php?action=workshed", ChecklistSubentryMake("Mayo Device Rental", "", description), 8).ChecklistEntrySetIDTag("Mayo clinic device resource")); - } - if (!get_property_boolean("_mayoTankSoaked") && __misc_state["in run"]) - { - string [int] description; - string [int] benefits; - if (my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) - benefits.listAppend("HP restore"); - benefits.listAppend("+2 all resistance"); - description.listAppend("Gives " + benefits.listJoinComponents(", ", "and") + "."); - resource_entries.listAppend(ChecklistEntryMake("__item bubblin' chemistry solution", "campground.php?action=workshed", ChecklistSubentryMake("Mayo Tank Soak", "", description), 8).ChecklistEntrySetIDTag("Mayo clinic tank soak resource")); - } - if ($item[mayo lance].available_amount() > 0) - { - string url = ""; - string [int] description; - int turns_yellow_ray_will_be = clampi(150 - get_property_int("mayoLevel") * 5, 0, 150); - if (get_property_int("mayoLevel") == 0) - { - string line = "Need blood mayo to yellow ray"; - if ($effect[everything looks yellow].have_effect() > 0) - line += " later"; - line += "."; - if (get_property("mayoInMouth") == "") - line += "|Use a mayo packet."; - description.listAppend(line); - if (availableFullness() > 0) - url = "campground.php?action=workshed"; - } - else - { - string line = pluralise(turns_yellow_ray_will_be, "turn", "turns") + " yellow ray"; - if ($effect[everything looks yellow].have_effect() > 0) - line += " later"; - line += ". Affected by mayo level."; - description.listAppend(line); - } - resource_entries.listAppend(ChecklistEntryMake("__item mayo lance", url, ChecklistSubentryMake("Mayo lance", "", description), 8).ChecklistEntrySetIDTag("Mayo clinic mayo lance resource")); - - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2016/Clan Floundry.ash b/Source/relay/TourGuide/Items of the Month/2016/Clan Floundry.ash deleted file mode 100644 index 4e198a26..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Clan Floundry.ash +++ /dev/null @@ -1,51 +0,0 @@ - -RegisterResourceGenerationFunction("IOTMClanFloundryGenerateResource"); -void IOTMClanFloundryGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["VIP available"] || !$item[Clan Floundry].is_unrestricted()) - return; - if (!__misc_state["in run"]) - return; - if (my_path().id == PATH_G_LOVER) - return; - - //if (get_property_boolean("_floundryFabricated") || !mafiaIsPastRevision(18000)) - //return; - foreach it in $items[bass clarinet,fish hatchet,carpe,codpiece,troutsers,tunac] - { - if (it.available_amount() > 0) - return; - if (it == $item[none]) - return; - } - - string [int] description; - - string [int][int] equipment; - if (__misc_state["can equip just about any weapon"]) - { - //Bass clarinet: -10% combat, 1h ranged weapon, +100% moxie, -3 MP skill cost, +50 ranged damage, 10 white pixels - string line = "-10% combat, +100% moxie, -3 MP skill cost, +50 ranged damage"; - equipment.listAppend(listMake("Bass clarinet", "ranged weapon", line)); - //Fish hatchet: -10% combat, 1h axe, +100% muscle, +5 familiar weight, +50 weapon damage, +5 bridge progress - line = "-10% combat, +100% muscle, +5 familiar weight, +50 weapon damage"; - if (!__quest_state["Level 9"].state_boolean["bridge complete"]) - line += ", +5 bridge progress"; - equipment.listAppend(listMake("Fish hatchet", "weapon", line)); - } - //Codpiece: acc, -?% combat, +100% myst, +100 max MP, +50 spell damage, 8 bubblin' crudes - equipment.listAppend(listMake("Codpiece", "acc", "-10% combat, +100% myst, +100 max MP, +50 spell damage" + (can_interact() ? "" : ", 8 bubblin' crudes"))); - //Carpe: back, +combat, +50% myst, regen ~8 MP, +50% meat - equipment.listAppend(listMake("Carpe", "back", "+combat, +50% meat, +50% myst, regen ~8 MP")); - //Tunac tunac tun: +combat, shirt, +50% muscle, +25 ML, +25% item - if (__misc_state["Torso aware"]) - { - equipment.listAppend(listMake("Tunac", "shirt", "+combat, +25 ML, +25% item, +50% muscle")); - } - //Troutsers: pants, +50% moxie, +50% pickpocket, +5 all res, +11 prismatic damage - equipment.listAppend(listMake("Troutsers", " pants", "+50% moxie, +50% pickpocket, +5 all res, +11 prismatic damage")); - description.listAppend(HTMLGenerateSimpleTableLines(equipment)); - - - resource_entries.listAppend(ChecklistEntryMake("__item fishy fish", "clan_viplounge.php?action=floundry", ChecklistSubentryMake("Rentable floundry equipment", "", description), 8).ChecklistEntrySetIDTag("Clan floundry resource")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2016/Detective School.ash b/Source/relay/TourGuide/Items of the Month/2016/Detective School.ash deleted file mode 100644 index df276213..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Detective School.ash +++ /dev/null @@ -1,57 +0,0 @@ -RegisterTaskGenerationFunction("IOTMDetectiveSchoolGenerateTasks"); -void IOTMDetectiveSchoolGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!mafiaIsPastRevision(17048)) - return; - if (!__iotms_usable[$item[detective school application]]) - return; - - //Should we always mention this in aftercore? - //Hmm... I suppose. - int cases_remaining = clampi(3 - get_property_int("_detectiveCasesCompleted"), 0, 3); - if (cases_remaining > 0) - { - optional_task_entries.listAppend(ChecklistEntryMake("__item noir fedora", "place.php?whichplace=town_wrong&action=townwrong_precinct", ChecklistSubentryMake("Solve " + pluraliseWordy(cases_remaining, "more case", "more cases"), "", "Gives cop dollars."), 5).ChecklistEntrySetIDTag("Detective school daily cases")); - } - if ($items[plastic detective badge,bronze detective badge,silver detective badge,gold detective badge].available_amount() == 0) - { - optional_task_entries.listAppend(ChecklistEntryMake("__item plastic detective badge", "place.php?whichplace=town_wrong&action=townwrong_precinct", ChecklistSubentryMake("Collect your Precinct badge", "", ""), 5).ChecklistEntrySetIDTag("Detective school new badge")); - - } -} - -RegisterResourceGenerationFunction("IOTMDetectiveSchoolGenerateResource"); -void IOTMDetectiveSchoolGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!mafiaIsPastRevision(17048)) - return; - if (!__iotms_usable[$item[detective school application]]) - return; - - //FIXME mention how much more they need to upgrade to the next badge? - if (__misc_state["in run"] && in_ronin()) - { - int cop_dollars_have = $item[cop dollar].available_amount(); - if (cop_dollars_have > 0) - { - string [int] description; - - string [int] buyables; - - string [int] ml_types_can_eat_drink; - if (__misc_state["can eat just about anything"]) - ml_types_can_eat_drink.listAppend("food"); - if (__misc_state["can drink just about anything"]) - ml_types_can_eat_drink.listAppend("drink"); - if (ml_types_can_eat_drink.count() > 0 && cop_dollars_have >= 4) - buyables.listAppend(ml_types_can_eat_drink.listJoinComponents("/")); - if (cop_dollars_have >= 10) - { - buyables.listAppend("a -combat potion (50 turns)"); - } - if (buyables.count() > 0) - description.listAppend("Buy " + buyables.listJoinComponents(", ", "or") + "."); - resource_entries.listAppend(ChecklistEntryMake("__item cop dollar", "shop.php?whichshop=detective", ChecklistSubentryMake(pluralise($item[cop dollar]), "", description), 7).ChecklistEntrySetIDTag("Detective school precinct shop")); - } - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2016/Gingerbread City.ash b/Source/relay/TourGuide/Items of the Month/2016/Gingerbread City.ash deleted file mode 100644 index c9869de7..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Gingerbread City.ash +++ /dev/null @@ -1,141 +0,0 @@ -//Gingerbread City -RegisterTaskGenerationFunction("IOTMGingerbreadCityGenerateTasks"); -void IOTMGingerbreadCityGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[$item[Build-a-City Gingerbread kit]]) return; - - string [int] description; - string [int] GCTurnsLeftdescription; - string [int] trainOptions; - string [int] civicOptions; - string [int] industrialOptions; - string [int] retailOptions; - string url = "place.php?whichplace=gingerbreadcity"; - { - int GingerCityTimer = get_property_int("_gingerbreadCityTurns"); - if (get_property_boolean("_gingerbreadClockAdvanced") == true) { - GingerCityTimer += 5; - //increment gingercity timer by 5 if clock is used - } - - if (GingerCityTimer < 30) - { - if (GingerCityTimer < 9) { - GCTurnsLeftdescription.listAppend(9 - GingerCityTimer + " combats until Noon."); - } - if (GingerCityTimer == 9) - { - trainOptions.listAppend("Look for candy."); - civicOptions.listAppend("Knock over a sprinkle column (+50 sprinkles)."); - if ($item[gingerbread blackmail photos].available_amount() == 1) { - civicOptions.listAppend("Use the photos to blackmail a politician."); - } - if (get_property_int("gingerLawChoice") >= 3) { - industrialOptions.listAppend("Buy a teethpick (1000 sprinkles)."); - } - if (get_property_boolean("gingerRetailUnlocked") == false) { - civicOptions.listAppend("Build a retail district."); - } - if (get_property_boolean("gingerSewersUnlocked") == false) { - civicOptions.listAppend("Build a sewer... district."); - } - if (get_property_boolean("gingerRetailUnlocked") == true) { - retailOptions.listAppend("Buy some stuff (50-500 sprinkles)."); - } - if ($item[fruit-leather negatives].available_amount() == 1) { - retailOptions.listAppend("Develop your fruit-leather negatives."); - } - if (get_property_boolean("gingerNegativesDropped") == true) { - retailOptions.listAppend("Pick up your blackmail photos."); - } - if (trainOptions.count() > 0) { - description.listAppend(HTMLGenerateSpanOfClass("Train Station:", "r_bold") + "|*" + trainOptions.listJoinComponents("|*")); - } - if (civicOptions.count() > 0) { - description.listAppend(HTMLGenerateSpanOfClass("Civic Center:", "r_bold") + "|*" + civicOptions.listJoinComponents("|*")); - } - if (industrialOptions.count() > 0) { - description.listAppend(HTMLGenerateSpanOfClass("Industrial District:", "r_bold") + "|*" + industrialOptions.listJoinComponents("|*")); - } - if (retailOptions.count() > 0) { - description.listAppend(HTMLGenerateSpanOfClass("Retail District:", "r_bold") + "|*" + retailOptions.listJoinComponents("|*")); - } - task_entries.listAppend(ChecklistEntryMake("__item gingerbread house", url, ChecklistSubentryMake("Gingerbread City Noon noncom available!", "", description), -11)); - } - if (GingerCityTimer < 19) { - GCTurnsLeftdescription.listAppend(19 - GingerCityTimer + " combats until Midnight."); - } - if (GingerCityTimer == 19) - { - if (get_property_int("gingerMuscleChoice") < 3) { - int gingerTracksLeft = clampi(3 - get_property_int("gingerMuscleChoice"), 0, 3); - trainOptions.listAppend("Lay some track (" + gingerTracksLeft + " remaining)."); - } - if (get_property_boolean("gingerSubwayLineUnlocked") == true && !get_property_boolean("gingerBlackmailAccomplished") == true) { - trainOptions.listAppend("Get some fruit-leather negatives."); - } - if ($item[teethpick].available_amount() == 1) { - int gingerDigsLeft = clampi(7 - get_property_int("gingerDigCount"), 0, 7); - if (gingerDigsLeft > 4) { - trainOptions.listAppend("Dig up " + pluralise(gingerDigsLeft -4, " green-iced sweet roll", "green-iced sweet rolls") + "."); - } - else if (gingerDigsLeft > 1) { - trainOptions.listAppend("Dig up " + pluralise(gingerDigsLeft -1, " green rock candy", "green rock candies") + "."); - } - else if (gingerDigsLeft == 1) { - trainOptions.listAppend("Dig up a sugar raygun (final)."); - } - } - if (get_property_boolean("_gingerbreadColumnDestroyed") == true) { - civicOptions.listAppend("Fight Judge Fudge to take his gavel " + HTMLGenerateSpanFont("(no other Civic options available)", "red")); - } - if (get_property_boolean("_gingerbreadColumnDestroyed") == false) { - civicOptions.listAppend("Buy some cigarettes (5 sprinkles)."); - civicOptions.listAppend("Buy a counterfeit city (300 sprinkles)."); - if (get_property_int("gingerLawChoice") < 3) { - int gingerStudiesLeft = clampi(3 - get_property_int("gingerLawChoice"), 0, 3); - civicOptions.listAppend("Study digging laws (" + gingerStudiesLeft + " remaining)."); - } - } - if (have_outfit_components("Gingerbread Best")) { - retailOptions.listAppend("Get some ginger wine (free)"); - retailOptions.listAppend("Buy a chocolate sculpture (300 sprinkles)"); - if (!is_wearing_outfit("Gingerbread Best")) { - retailOptions.listAppend(HTMLGenerateSpanFont("Retail District options require Gingerbread Best equipped", "red")); - } - else { - retailOptions.listAppend(HTMLGenerateSpanFont("Gingerbread Best equipped for Retail District options", "blue")); - } - } - if (trainOptions.count() > 0) { - description.listAppend(HTMLGenerateSpanOfClass("Train Station:", "r_bold") + "|*" + trainOptions.listJoinComponents("|*")); - } - if (civicOptions.count() > 0) { - description.listAppend(HTMLGenerateSpanOfClass("Civic Center:", "r_bold") + "|*" + civicOptions.listJoinComponents("|*")); - } - if (industrialOptions.count() > 0) { - description.listAppend(HTMLGenerateSpanOfClass("Industrial District:", "r_bold") + "|*" + industrialOptions.listJoinComponents("|*")); - } - if (retailOptions.count() > 0) { - description.listAppend(HTMLGenerateSpanOfClass("Retail District:", "r_bold") + "|*" + retailOptions.listJoinComponents("|*")); - } - - task_entries.listAppend(ChecklistEntryMake("__item gingerbread house", url, ChecklistSubentryMake("Gingerbread City Midnight noncom available!", "", description), -11)); - } - if (GingerCityTimer > 19) { - GCTurnsLeftdescription.listAppend("No NCs left."); - } - - if (($locations[Gingerbread Train Station,Gingerbread Civic Center,Gingerbread Industrial Zone,Gingerbread Upscale Retail District,Gingerbread Sewers] contains __last_adventure_location) && GingerCityTimer != 9 && GingerCityTimer != 19) - task_entries.listAppend(ChecklistEntryMake("__item gingerbread house", url, ChecklistSubentryMake(30 - GingerCityTimer + " Gingerbread City turns remaining", "", GCTurnsLeftdescription), -11)); - else - if (gingercitytimer == 9) { - GCTurnsLeftdescription.listAppend("Noon NC now!"); - } - if (gingercitytimer == 19) { - GCTurnsLeftdescription.listAppend("Midnight NC now!"); - } - optional_task_entries.listAppend(ChecklistEntryMake("__item gingerbread house", url, ChecklistSubentryMake(30 - GingerCityTimer + " Gingerbread City turns remaining", "", GCTurnsLeftdescription), 10)); - } - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2016/Intergnat.ash b/Source/relay/TourGuide/Items of the Month/2016/Intergnat.ash deleted file mode 100644 index 7b30d505..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Intergnat.ash +++ /dev/null @@ -1,103 +0,0 @@ -RegisterTaskGenerationFunction("IOTMIntergnatGenerateTasks"); -void IOTMIntergnatGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - - if (!get_property_boolean("demonSummoned") && __misc_state["in run"] && !__quest_state["Level 13"].state_boolean["king waiting to be freed"] && $familiar[intergnat].familiar_is_usable() && my_path().id != PATH_AVATAR_OF_SNEAKY_PETE) - { - //Should we show this if they aren't using the intergnat? ... Yes? - //demonName12, thin black candle, scroll of ancient forbidden unspeakable evil - string [int] reasons; - if (!get_property("demonName12").contains_text("Neil ") && my_level() < 13) //13 is +50% init... it's kind of useful? But not worth mentioning if they don't have it by this point? - { - reasons.listAppend("learn demon name"); - } - if ($item[thin black candle].available_amount() < 3) - { - if ($item[thin black candle].available_amount() < 2) - reasons.listAppend("collect " + int_to_wordy(3 - $item[thin black candle].available_amount()) + " more thin black candles"); - else - reasons.listAppend("collect One More Thin black candle"); - } - if ($item[scroll of ancient forbidden unspeakable evil].available_amount() == 0) - { - reasons.listAppend("collect a scroll of ancient forbidden unspeakable evil"); - } - if (reasons.count() > 0) - { - string [int] description; - description.listAppend(reasons.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - string url = ""; - string title = "Continue running Intergnat for demon summon"; - if (my_familiar() != $familiar[intergnat]) - { - url = "familiar.php"; - title = "Possibly run Intergnat for demon summon"; - } - //Don't use the intergnat icon, because animation is distracting: - optional_task_entries.listAppend(ChecklistEntryMake("__item thin black candle", url, ChecklistSubentryMake(title, "", description)).ChecklistEntrySetIDTag("Intergnat summon Neil")); - } - } -} - -RegisterResourceGenerationFunction("IOTMIntergnatGenerateResource"); -void IOTMIntergnatGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[infinite BACON machine].available_amount() > 0 && !get_property_boolean("_baconMachineUsed") && mafiaIsPastRevision(16926)) - { - //suggest using it: - resource_entries.listAppend(ChecklistEntryMake("__item infinite BACON machine", "inventory.php?which=3?ftext=infinite+bacon+machine", ChecklistSubentryMake("Infinite BACON machine", "", "100 BACON/day."), 7).ChecklistEntrySetIDTag("Intergnat infinite bacon machine")); - } - if ($item[daily dungeon malware].available_amount() > 0 && __misc_state_int["fat loot tokens needed"] > 0) - { - resource_entries.listAppend(ChecklistEntryMake("__item daily dungeon malware", "da.php", ChecklistSubentryMake("Daily dungeon malware", "", "Use on a daily dungeon monster to gain a fat loot token."), 7).ChecklistEntrySetIDTag("Intergnat daily dungeon malware")); - } - int bacon_amount = $item[BACON].available_amount(); - if (__misc_state["in run"] && bacon_amount > 0 && in_ronin()) - { - /* - Viral video - YR if they don't have one. - Print screen button - Copy, kind of unlimited use. - Daily dungeon malware - It seems very expensive for what it does, but, we could suggest it? - - Gallon of milk - food, though not amazing. The debuff causes issues, but mostly just for the alcove. - */ - coinmaster meme_shop = "Internet Meme Shop".to_coinmaster(); - if (meme_shop != $coinmaster[none]) - { - string [item] bacon_description; - if (!__misc_state["yellow ray available"] & $effect[everything looks yellow].have_effect() == 0 && $item[viral video].item_is_usable()) - bacon_description[$item[Viral video]] = "yellow ray"; - if ($item[print screen button].item_is_usable()) - bacon_description[$item[print screen button]] = "copies a monster"; - if (__misc_state_int["fat loot tokens needed"] > 0) - bacon_description[$item[daily dungeon malware]] = "expensive DD token source"; - if (availableFullness() >= 15) - bacon_description[$item[gallon of milk]] = "lazy/expensive food source. Incurs a debuff"; - - string [int][int] table; - foreach it, item_description in bacon_description - { - int bacon_cost = meme_shop.sell_price(it); - string [int] line; - line.listAppend(it.capitaliseFirstLetter()); - line.listAppend(bacon_cost); - line.listAppend(item_description.capitaliseFirstLetter() + "."); - if (bacon_cost > bacon_amount) - { - foreach key in line - { - line[key] = HTMLGenerateSpanFont(line[key], "grey"); - } - } - table.listAppend(line); - } - if (table.count() > 0) - { - string [int] description; - description.listAppend(HTMLGenerateSimpleTableLines(table)); - - resource_entries.listAppend(ChecklistEntryMake("__item BACON", "shop.php?whichshop=bacon", ChecklistSubentryMake(pluralise($item[BACON]), "", description), 7).ChecklistEntrySetIDTag("Intergnat bacon shop resource")); - } - } - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2016/LT&T Cowboy Boots.ash b/Source/relay/TourGuide/Items of the Month/2016/LT&T Cowboy Boots.ash deleted file mode 100644 index 445b393b..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/LT&T Cowboy Boots.ash +++ /dev/null @@ -1,254 +0,0 @@ -RegisterTaskGenerationFunction("IOTMTelegraphOfficeGenerateTasks"); -void IOTMTelegraphOfficeGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[$item[LT&T telegraph office deed]]) - return; - - - if ($item[your cowboy boots].available_amount() == 0) - { - optional_task_entries.listAppend(ChecklistEntryMake("__item your cowboy boots", "place.php?whichplace=town_right", ChecklistSubentryMake("Acquire your cowboy boots", "", "Visit the LT&T office."), 0).ChecklistEntrySetIDTag("Telegraph office LT&T cowboy boots")); - - } - - - if (!mafiaIsPastRevision(16674)) - return; - - QuestState ltt_quest = QuestState("questLTTQuestByWire"); - - if (!ltt_quest.in_progress) - return; - - int difficulty = get_property_int("lttQuestDifficulty"); - int stage_count = get_property_int("lttQuestStageCount"); - string quest_name = get_property("lttQuestName"); - if (quest_name == "") - return; - - //step1 - the investigation begins - //step2 - The Investigation Continues - //step3 - The Investigation Continues - //step4 - boss fight - - int turns_completed = stage_count; - if (ltt_quest.mafia_internal_step > 2) - turns_completed += 10; - if (ltt_quest.mafia_internal_step > 3) - turns_completed += 10; - if (ltt_quest.mafia_internal_step > 4) - turns_completed += 10; - //quest_name is blank when not on the quest - int turns_remaining = clampi(29 - turns_completed, 0, 29); - //"Missing: Many Children" - clara - //"Wagon Train Escort Wanted" - Granny Hackleton - //"Madness at the Mine" - unusual construct - - monster [string] boss_for_quest; - - boss_for_quest["Missing: Fancy Man"] = $monster[Jeff the Fancy Skeleton]; - boss_for_quest["Help! Desperados!"] = $monster[Pecos Dave]; - boss_for_quest["Missing: Pioneer Daughter"] = $monster[Daisy the Unclean]; - - boss_for_quest["Big Gambling Tournament Announced"] = $monster[Snake-Eyes Glenn]; - boss_for_quest["Haunted Boneyard"] = $monster[Pharaoh Amoon-Ra Cowtep]; - boss_for_quest["Sheriff Wanted"] = $monster[Former Sheriff Dan Driscoll]; - - boss_for_quest["Missing: Many Children"] = $monster[Clara]; - boss_for_quest["Wagon Train Escort Wanted"] = $monster[Granny Hackleton]; - boss_for_quest["Madness at the Mine"] = $monster[unusual construct]; - - - - string [int] description; - string [int] modifiers; - if (turns_remaining > 0) - description.listAppend(pluraliseWordy(turns_remaining, "more turn", "more turns").capitaliseFirstLetter() + " until the boss."); - if (turns_remaining == 0 || ltt_quest.mafia_internal_step == 5) - { - string url = "inventory.php?ftext=plaintive+telegram"; - monster boss = boss_for_quest[quest_name]; - boolean frigidalmatian_eligible = false; - if (boss == $monster[Clara]) - { - modifiers.listAppend("+elemental resistance"); - description.listAppend("Use high-damage spells, like shrap + snow mobile/green lantern."); - frigidalmatian_eligible = true; - } - else if (boss == $monster[Granny Hackleton]) - { - description.listAppend("Use different high-damage combat items, or frigidalmatian and attack."); - //FIXME suggest a list of combat items to use - frigidalmatian_eligible = true; - } - else if (boss == $monster[unusual construct]) - { - description.listAppend("Each round, you have to respond with the correct shiny disc to survive. Mafia will select the correct one.|Maybe funksling with new-age hurting crystals."); - frigidalmatian_eligible = true; - } - else if (boss == $monster[Jeff the Fancy Skeleton]) - { - description.listAppend("Attack with a blunt weapon. (clubs, flails, saucepans...)"); - description.listAppend("Combat items won't work, skills are mostly blocked."); - } - else if (boss == $monster[Pecos Dave]) - { - description.listAppend("Attack with multiple sources of damage."); - if ($item[wicker slicker].available_amount() > 0 && $skill[shell up].have_skill()) - { - if ($item[wicker slicker].equipped_amount() > 0) - description.listAppend("Shell up on alternate rounds?"); - else - description.listAppend("Equip wicker slicker and shell up on alternate rounds?"); - } - frigidalmatian_eligible = true; - } - else if (boss == $monster[Daisy the Unclean]) - { - //FIXME - } - else if (boss == $monster[Snake-Eyes Glenn]) - { - description.listAppend("Immune to all but a single element type each round.|Previous round's second roll indicates which."); - } - else if (boss == $monster[Pharaoh Amoon-Ra Cowtep]) - { - description.listAppend("Avoid attacking with spell damage."); - } - else if (boss == $monster[Former Sheriff Dan Driscoll]) - { - description.listAppend("Acquire passive damage (glowing syringes?), attack repeatedly."); - frigidalmatian_eligible = true; - } - string image_name = "__monster " + boss; - task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake("Defeat " + boss + "!", modifiers, description), -11)); - if (frigidalmatian_eligible) - { - string [int] tasks; - boolean frigidalmatian_obtainable = false; - if ($effect[frigidalmatian].have_effect() > 0) - frigidalmatian_obtainable = true; - if ($effect[frigidalmatian].have_effect() == 0 && $skill[frigidalmatian].have_skill()) - { - frigidalmatian_obtainable = true; - tasks.listAppend("cast frigidalmatian"); - } - if (frigidalmatian_obtainable && $items[rain-doh green lantern,snow mobile,meteorb].equipped_amount() == 0) - { - if ($item[rain-doh green lantern].available_amount() > 0) - { - tasks.listAppend("equip rain-doh green lantern"); - } - else if (lookupItems("meteorb,metal meteoroid").available_amount() > 0) - { - tasks.listAppend("equip meteorb"); - } - else if ($item[snow mobile].is_unrestricted()) - { - if ($item[snow mobile].available_amount() > 0) - { - tasks.listAppend("equip snow mobile"); - } - else - tasks.listAppend("acquire and equip snow mobile"); - } - } - if (tasks.count() > 0) - description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - } - } - - if (false) - { - foreach s in $strings[lttQuestDifficulty,lttQuestStageCount,lttQuestName,questLTTQuestByWire] - description.listAppend(s + " = " + get_property(s)); - } - - ChecklistEntry entry = ChecklistEntryMake("__item sea cowboy hat", "inventory.php?ftext=plaintive+telegram", ChecklistSubentryMake(quest_name, modifiers, description), $locations[Investigating a Plaintive Telegram]); - entry.tags.id = "Telegraph office LT&T quest"; - if (__misc_state["in run"]) - future_task_entries.listAppend(entry); - else - optional_task_entries.listAppend(entry); -} - -RegisterResourceGenerationFunction("IOTMTelegraphOfficeGenerateResource"); -void IOTMTelegraphOfficeGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (__misc_state["in run"] && $item[Clara's bell].available_amount() > 0 && !get_property_boolean("_claraBellUsed")) - { - string [int] description; - description.listAppend("Ring for a non-combat next turn, once/day."); - - LocationChoice [int] options; - - //√spooky forest - unlocking the hidden temple - //6 - advance one of the quest areas - //7 - defiled cranny - //8 - umm... maybe the extreme slow? unimportant? - //9 - twin peak - //10 - top/bottom of the castle, best place in the game(?) - //11 - copperhead, protestors, fun hidden city exploit, hidden temple but marginal, palindome but marginal, pyramid in situations where you can't run lots of +item, poop deck, haunted billiards room, haunted bathroom - //12 - starting the war(??) - - //2 - mosquito - not terribly important - //3 - tavern - forces a skippable NC, not important - - if (!get_property_ascension("lastTempleUnlock")) - { - //options.listAppend("") - options.listAppend(LocationChoiceMake($location[the spooky forest], "unlocking the hidden temple")); - } - - if (my_path().id == PATH_COMMUNITY_SERVICE) - { - foreach key in options - remove options[key]; - } - - if (options.count() > 0) - { - description.listAppend("Suggested areas:|*" + LocationChoiceGenerateDescription(options).listJoinComponents("|*")); - } - - - resource_entries.listAppend(ChecklistEntryMake("__item clara's bell", "inventory.php?ftext=clara's+bell", ChecklistSubentryMake("Clara's Bell", "", description), 5).ChecklistEntrySetIDTag("LT&T claras bell resource")); - } - - //skills: - //Bow-Legged Swagger -> _bowleggedSwaggerUsed - //Bend Hell -> _bendHellUsed - //Steely-Eyed Squint -> _steelyEyedSquintUsed - //bend hell - double elemental damage/elemental spell damage - if (true) - { - string [skill] telegraph_skill_properties; - if (__misc_state["in run"]) - { - telegraph_skill_properties[$skill[Bow-Legged Swagger]] = "_bowleggedSwaggerUsed"; - telegraph_skill_properties[$skill[Bend Hell]] = "_bendHellUsed"; - } - telegraph_skill_properties[$skill[Steely-Eyed Squint]] = "_steelyEyedSquintUsed"; - - string [skill] telegraph_skill_descriptions; - telegraph_skill_descriptions[$skill[Bow-Legged Swagger]] = "Double +initiative and physical damage. Once/day."; - telegraph_skill_descriptions[$skill[Bend Hell]] = "Double elemental damage/elemental spell damage. Once/day."; - telegraph_skill_descriptions[$skill[Steely-Eyed Squint]] = "Double +item. Once/day."; - - string image_name; - ChecklistSubentry [int] subentries; - foreach s, property in telegraph_skill_properties - { - if (!s.skill_is_usable()) - continue; - if (get_property_boolean(property)) - continue; - - if (image_name == "") - image_name = "__skill " + s; - subentries.listAppend(ChecklistSubentryMake(s + " castable", "", telegraph_skill_descriptions[s])); - } - if (subentries.count() > 0) - resource_entries.listAppend(ChecklistEntryMake(image_name, "skillz.php", subentries, 9).ChecklistEntrySetIDTag("LT&T daily cowboy skills resource")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2016/Protonic Accelerator Pack.ash b/Source/relay/TourGuide/Items of the Month/2016/Protonic Accelerator Pack.ash deleted file mode 100644 index a1637542..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Protonic Accelerator Pack.ash +++ /dev/null @@ -1,191 +0,0 @@ -import "relay/TourGuide/Support/Monster Data.ash"; - -RegisterTaskGenerationFunction("IOTMProtonicAcceleratorPackGenerateTasks"); -void IOTMProtonicAcceleratorPackGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!$item[protonic accelerator pack].have()) return; - { int nextGhostTurn = get_property_int("nextParanormalActivity"); - int nextGhostTimer = (nextGhostTurn - total_turns_played()); - string [int] description; - string url; - url = invSearch("protonic accelerator pack"); - - if (nextGhostTurn <= total_turns_played()) - { - description.listAppend(HTMLGenerateSpanFont("Who you gonna call? You!", "blue")); - if (!lookupItem("protonic accelerator pack").equipped()) - description.listAppend(HTMLGenerateSpanFont("Equip the protopack first", "red")); - task_entries.listAppend(ChecklistEntryMake("__item protonic accelerator pack", url, ChecklistSubentryMake("It's ghost bustin' time!", "", description), -11)); - } - else - description.listAppend(nextGhostTimer + " adventures until your next protonic ghost."); - optional_task_entries.listAppend(ChecklistEntryMake("__item protonic accelerator pack", url, ChecklistSubentryMake("It's ghost bustin' time... eventually.", "", description), 8)); - } - //Quest: - if (QuestState("questPAGhost").in_progress || get_property("ghostLocation") != "") - { - int priority = 0; - if (__misc_state["in run"]) - priority = -1; - location ghost_location = get_property_location("ghostLocation"); - monster ghost = __protonic_monster_for_location[ghost_location]; - float ml_in_location = ghost_location.monster_level_adjustment_for_location(); - string title = "Defeat the ghost in " + ghost_location; - string [int] description; - string [int] modifiers; - string url = ghost_location.getClickableURLForLocation(); - description.listAppend("Won't cost a turn."); - if ($item[protonic accelerator pack].equipped_amount() > 0) - { - float expected_damage = ghost.expectedDamageFromGhostAfterCastingShootGhost(); - float hp_needed = expected_damage * 3; - - //FIXME initial hit damage - //don't know if expected_damage() will be correct, it isn't always - float initial_hit_damage = ghost.expected_damage(); - float elemental_ml_damage = 0.0; - if (ml_in_location >= 26.0 && ghost.defense_element != $element[none]) - { - //[Monster Attack] * MIN( ( [Bonus ML] - 25 ) / 500 , 1 / 2 ) - //FIXME range. 1.1? - elemental_ml_damage = 1.1 * ghost.base_attack * min(0.5, (ml_in_location - 25.0) / 500.0); - elemental_ml_damage *= 1.0 - elemental_resistance(ghost.defense_element) / 100.0; - elemental_ml_damage = ceil(elemental_ml_damage); - } - hp_needed += elemental_ml_damage + initial_hit_damage; - - if (hp_needed >= my_maxhp()) - { - description.listAppend(HTMLGenerateSpanFont("Do not cast \"shoot ghost\", you won't survive.", "red")); - if (ml_in_location <= 50) - description.listAppend("Or stun the monster for multiple rounds, and cast \"shoot ghost\" three times, then \"trap ghost\"."); - } - else if (hp_needed >= my_hp()) - { - description.listAppend(HTMLGenerateSpanFont("Restore HP", "red") + " to cast \"shoot ghost\"."); - if (ml_in_location <= 50) - description.listAppend("Or stun the monster for multiple rounds, and cast \"shoot ghost\" three times, then \"trap ghost\"."); - } - else - { - description.listAppend("Cast \"shoot ghost\" three times, then \"trap ghost\"."); - } - description.listAppend("After casting \"shoot ghost\", the ghost will deal " + expected_damage.to_int() + " damage/round."); - } - item [int] items_to_equip; - if ($item[protonic accelerator pack].equipped_amount() == 0 && $item[protonic accelerator pack].available_amount() > 0) - { - //Strictly speaking, they don't need the pack equipped to fight the monster, but they won't be able to trap it and get the item. - url = "inventory.php?which=2"; - items_to_equip.listAppend($item[protonic accelerator pack]); - } - if (ghost_location == $location[inside the palindome] && $item[Talisman o' Namsilat].equipped_amount() == 0) - { - if ($item[Talisman o' Namsilat].available_amount() == 0) - { - priority = 10; - description.listAppend("Need Talisman o' Namsilat first."); - } - else - { - url = "inventory.php?which=2"; - items_to_equip.listAppend($item[talisman o' namsilat]); - } - } - if (ghost_location == $location[the skeleton store] && !ghost_location.locationAvailable()) - { - //bone with a price tag on it - if (my_path().id == PATH_NUCLEAR_AUTUMN) - { - if ($item[bone with a price tag on it].available_amount() > 0) - { - url = "inventory.php?ftext=bone+with+a+price+tag+on+it"; - description.listAppend("Use the bone with a price tag on it to unlock the store."); - } - } - else - { - url = "shop.php?whichshop=meatsmith&action=talk"; - description.listAppend("Talk to the meatsmith and start his quest."); - } - } - if (ghost_location == $location[The Overgrown Lot] && !ghost_location.locationAvailable()) - { - //bone with a price tag on it - if (my_path().id == PATH_NUCLEAR_AUTUMN) - { - if ($item[map to a hidden booze cache].available_amount() > 0) - { - url = "inventory.php?ftext=map+to+a+hidden+booze+cache"; - description.listAppend("Use the map to a hidden booze cache to unlock the store."); - } - } - else - { - url = "shop.php?whichshop=doc&action=talk"; - description.listAppend("Talk to Doc Galaktik and start his quest."); - } - } - if (ghost_location == $location[Madness Bakery] && !ghost_location.locationAvailable()) - { - //bone with a price tag on it - if (my_path().id == PATH_NUCLEAR_AUTUMN) - { - if ($item[hypnotic breadcrumbs].available_amount() > 0) - { - url = "inventory.php?ftext=hypnotic+breadcrumbs"; - description.listAppend("Use the hypnotic breadcrumbs to unlock the store."); - } - } - else - { - url = "shop.php?whichshop=armory&action=talk"; - description.listAppend("Talk to Armorer and start his quest."); - } - } - - if (items_to_equip.count() > 0) - description.listAppend("Equip the " + items_to_equip.listJoinComponents(", ", "and") + " first."); - - element [location] elements_to_resist; - elements_to_resist[$location[Cobb's Knob Treasury]] = $element[spooky]; - elements_to_resist[$location[The Haunted Conservatory]] = $element[stench]; - elements_to_resist[$location[The Haunted Gallery]] = $element[hot]; - elements_to_resist[$location[The Haunted Kitchen]] = $element[cold]; - elements_to_resist[$location[The Haunted Wine Cellar]] = $element[sleaze]; - elements_to_resist[$location[The Icy Peak]] = $element[hot]; - elements_to_resist[$location[Inside the Palindome]] = $element[spooky]; - elements_to_resist[$location[Madness Bakery]] = $element[hot]; - elements_to_resist[$location[The Old Landfill]] = $element[stench]; - elements_to_resist[$location[The Overgrown Lot]] = $element[sleaze]; - elements_to_resist[$location[The Skeleton Store]] = $element[spooky]; - elements_to_resist[$location[The Smut Orc Logging Camp]] = $element[spooky]; - elements_to_resist[$location[The Spooky Forest]] = $element[spooky]; - - if (elements_to_resist contains ghost_location) - modifiers.listAppend(HTMLGenerateSpanOfClass("+" + elements_to_resist[ghost_location] + " resist", "r_element_" + elements_to_resist[ghost_location])); - - if (ghost_location != $location[none]) - optional_task_entries.listAppend(ChecklistEntryMake("__item protonic accelerator pack", url, ChecklistSubentryMake(title, modifiers, description), priority).ChecklistEntrySetIDTag("Protonic pack ghost busting task")); - } -} - - -RegisterResourceGenerationFunction("IOTMProtonicAcceleratorPackGenerateResource"); -void IOTMProtonicAcceleratorPackGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[protonic accelerator pack]]) return; - - if (!get_property_boolean("_streamsCrossed") &&__misc_state["in run"] && mafiaIsPastRevision(17085) && my_path().id != PATH_G_LOVER) - { - string [int] description; - string url = "showplayer.php?who=2807390"; //ProtonicBot is a real bot that will steal your turtle mechs at the first sign of defiance. - description.listAppend("+20% stats for 10 turns."); - if ($item[protonic accelerator pack].equipped_amount() == 0) - { - url = "inventory.php?ftext=protonic+accelerator+pack"; - description.listAppend("Equip the protonic accelerator pack first."); - } - resource_entries.listAppend(ChecklistEntryMake("__item protonic accelerator pack", url, ChecklistSubentryMake("Stream crossing", "", description), 8).ChecklistEntrySetIDTag("Protonic pack cross stream")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash b/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash deleted file mode 100644 index 2b5e8580..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash +++ /dev/null @@ -1,208 +0,0 @@ -RegisterResourceGenerationFunction("IOTMSnojoGenerateResource"); -void IOTMSnojoGenerateResource(ChecklistEntry [int] resource_entries) -{ - ChecklistEntry snojo_skill_entry; - if ($skill[Shattering Punch].skill_is_usable() && mafiaIsPastRevision(16617)) - { - int punches_left = clampi(3 - get_property_int("_shatteringPunchUsed"), 0, 3); - if (punches_left > 0) - { - string [int] description; - description.listAppend("Win a fight without taking a turn."); - - - //if (snojo_skill_entry.image_lookup_name == "") - //snojo_skill_entry.image_lookup_name = "__skill shattering punch"; - resource_entries.listAppend(ChecklistEntryMake("__skill shattering punch", "", ChecklistSubentryMake(pluralise(punches_left, "shattering punch", "shattering punches"), "", description), 0).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Snojo shattering punch free kill")); - - } - } - if ($skill[Snokebomb].skill_is_usable() && mafiaIsPastRevision(16599)) - { - int snokes_left = clampi(3 - get_property_int("_snokebombUsed"), 0, 3); - if (snokes_left > 0) - { - string [int] description; - description.listAppend("Free run, 30-turn banish."); - if (snojo_skill_entry.image_lookup_name == "") - snojo_skill_entry.image_lookup_name = "__skill Snokebomb"; - Banish snoke_banish = BanishByName("snokebomb"); - int turns_left_of_banish = snoke_banish.BanishTurnsLeft(); - if (turns_left_of_banish > 0) - { - //is this relevant? we don't describe this for pantsgiving - description.listAppend("Currently used on " + snoke_banish.banished_monster + " for " + pluralise(turns_left_of_banish, "more turn", "more turns") + "."); - } - //snojo_skill_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(snokes_left, "snokebomb", "snokebombs"), "", description)); - resource_entries.listAppend(ChecklistEntryMake("__skill snokebomb", "", ChecklistSubentryMake(pluralise(snokes_left, "snokebomb", "snokebombs"), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Snojo snokebomb banish")); - } - } - - if (snojo_skill_entry.subentries.count() > 0) - { - snojo_skill_entry.importance_level = 6; - if (!__misc_state["in run"]) - snojo_skill_entry.importance_level = 9; - resource_entries.listAppend(snojo_skill_entry); - } - - - //Everything past here is for snojo owners: - if (!__iotms_usable[$item[X-32-F snowman crate]]) - return; - - int fights_remaining = clampi(10 - get_property_int("_snojoFreeFights"), 0, 10); - if (!mafiaIsPastRevision(16598)) - fights_remaining = 0; - if (fights_remaining > 0) - { - item [stat] training_equipment_for_stat; - training_equipment_for_stat[$stat[muscle]] = $item[training belt]; - training_equipment_for_stat[$stat[mysticality]] = $item[training legwarmers]; - training_equipment_for_stat[$stat[moxie]] = $item[training helmet]; - - item [stat] consumable_reward_for_stat; - consumable_reward_for_stat[$stat[muscle]] = $item[ancient medicinal herbs]; - consumable_reward_for_stat[$stat[mysticality]] = $item[ice rice]; - consumable_reward_for_stat[$stat[moxie]] = $item[iced plum wine]; - - string [item] reward_descriptions; - reward_descriptions[$item[training belt]] = "+25 ML accessory"; - reward_descriptions[$item[training helmet]] = "+25% item hat"; - reward_descriptions[$item[training legwarmers]] = "+5 res accessory"; - reward_descriptions[$item[ice rice]] = "epic food"; - reward_descriptions[$item[iced plum wine]] = "epic drink"; - - - string [int] description; - - string setting = get_property("snojoSetting"); - - if (setting == "NONE" || setting == "") - { - description.listAppend("Visit the control console."); - } - - string wins_property = ""; - stat current_stat; - if (setting == "MUSCLE") - { - current_stat = $stat[muscle]; - wins_property = "snojoMuscleWins"; - } - else if (setting == "MOXIE") - { - current_stat = $stat[moxie]; - wins_property = "snojoMoxieWins"; - } - else if (setting == "MYSTICALITY") - { - current_stat = $stat[mysticality]; - wins_property = "snojoMysticalityWins"; - } - - int wins = 0; - if (wins_property != "") - wins = get_property_int(wins_property); - - - int [string] winnings; - if (wins_property != "") - { - winnings["skill scroll"] = 50; - if (reward_descriptions[training_equipment_for_stat[current_stat]] != "") - winnings[reward_descriptions[training_equipment_for_stat[current_stat]]] = 11; - if (consumable_reward_for_stat[current_stat] != $item[none]) - { - int value = ceil(wins.to_float() / 7.0) * 7; - if (value == wins) - value += 7; - winnings[consumable_reward_for_stat[current_stat].to_string()] = MAX(7, value); - } - } - - //Output in order of upcoming appearance: - string [int] winnings_order; - foreach winning in winnings - winnings_order.listAppend(winning); - sort winnings_order by winnings[value]; - - string [int] various_winnings_upcoming; - foreach key, winning in winnings_order - { - int timing = winnings[winning]; - if (wins >= timing) - continue; - int turns_remaining = timing - wins; - if (turns_remaining == 1) - various_winnings_upcoming.listAppend(winning + " next turn"); - else - various_winnings_upcoming.listAppend(winning + " in " + pluralise(turns_remaining, "turn", "turns")); - } - - if (various_winnings_upcoming.count() > 0) - description.listAppend(various_winnings_upcoming.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - - if (setting != "TOURNAMENT" && (!__misc_state["in run"] || wins >= 50)) - { - //Skill scrolls: - string [int] switchables; - if (get_property_int("snojoMuscleWins") < 50 && setting != "MUSCLE") - switchables.listAppend("muscle"); - if (get_property_int("snojoMoxieWins") < 50 && setting != "MOXIE") - switchables.listAppend("moxie"); - if (get_property_int("snojoMysticalityWins") < 50 && setting != "MYSTICALITY") - switchables.listAppend("mysticality"); - if (switchables.count() > 0) - { - string line = "Could switch to " + switchables.listJoinComponents(", ", "or") + " for "; - string additional = ""; - if (wins < 50) - additional = "different "; - if (switchables.count() > 1) - line += additional + "skill scrolls"; - else - line += "a " + additional + "skill scroll"; - line += "."; - description.listAppend(line); - } - } - if (__misc_state["in run"]) - { - //Possible rewards to switch to: - string [int] switchable_options; - foreach s in $stats[muscle,moxie,mysticality] - { - if (s == current_stat) - continue; - item training_equipment = training_equipment_for_stat[s]; - item consumable = consumable_reward_for_stat[s]; - - string [int] acquirable_descriptions; - if (training_equipment.available_amount() == 0 && my_path().id != PATH_GELATINOUS_NOOB) - { - acquirable_descriptions.listAppend("a " + reward_descriptions[training_equipment]); - } - if (s != $stat[muscle] && !(!__misc_state["can drink just about anything"] && s == $stat[moxie]) && !(!__misc_state["can eat just about anything"] && s == $stat[mysticality])) - { - acquirable_descriptions.listAppend(reward_descriptions[consumable]); - } - if (acquirable_descriptions.count() > 0) - switchable_options.listAppend(s.to_string().to_lower_case() + " for " + acquirable_descriptions.listJoinComponents("/")); - } - if (switchable_options.count() > 0) - { - description.listAppend("Could switch to " + switchable_options.listJoinComponents(", ", "or") + "."); - } - } - int importance = 6; - if (__misc_state["in run"]) - importance = 0; - ChecklistSubentry [int] subentries; - subentries.listAppend(ChecklistSubentryMake(pluralise(fights_remaining, "free Snojo fight", "free Snojo fights"), "", description)); - TagGroup tags; - tags.id = "Snojo X-32-F free fights"; - tags.combination = "daily free fight"; - resource_entries.listAppend(ChecklistEntryMake("__item snow suit", "place.php?whichplace=snojo", subentries, tags, importance, $locations[the x-32-f combat training snowman])); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2016/Source Terminal.ash b/Source/relay/TourGuide/Items of the Month/2016/Source Terminal.ash deleted file mode 100644 index 4de4097f..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Source Terminal.ash +++ /dev/null @@ -1,311 +0,0 @@ -void IOTMSourceTerminalGenerateDigitiseTargets(string [int] description) -{ - string [int] potential_targets; - if (!__misc_state["in CS aftercore"]) { - if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) - potential_targets.listAppend("lobsterfrogman"); - if (__quest_state["Level 7"].state_int["alcove evilness"] > 31) - potential_targets.listAppend("modern zmobie"); - if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && $items[ninja rope,ninja carabiner,ninja crampons].available_amount() == 0 && !have_outfit_components("eXtreme Cold-Weather Gear")) - potential_targets.listAppend("ninja assassin"); - } - //FIXME witchess bishop or knight - if (__iotms_usable[$item[Witchess Set]] && get_property_int("_witchessFights") < 5) - { - string [int] witchess_list; - if (__misc_state["can eat just about anything"]) - witchess_list.listAppend("knight"); - if (__misc_state["can drink just about anything"] && my_path().id != PATH_G_LOVER) - witchess_list.listAppend("bishop"); - if (my_path().id != PATH_G_LOVER) - witchess_list.listAppend("rook"); - potential_targets.listAppend("witchess " + witchess_list.listJoinComponents("/")); - } - if (potential_targets.count() > 0) - description.listAppend("Could target a " + potential_targets.listJoinComponents(", ", "or") + "."); - if (get_property_int("_sourceTerminalDigitizeMonsterCount") >= 2) - description.listAppend("Could re-digitise to reset the window."); -} - -RegisterTaskGenerationFunction("IOTMSourceTerminalGenerateTasks"); -void IOTMSourceTerminalGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (in_bad_moon() || __campground[$item[Source Terminal]] == 0 || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - return; - if (!mafiaIsPastRevision(17011)) - return; - ChecklistSubentry [int] subentries; - - boolean [string] chips = getInstalledSourceTerminalSingleChips(); - //Learn extract/a skill if we don't have one: - boolean [skill] skills_have = getActiveSourceTerminalSkills(); - int skill_limit = 1; - if (chips["DRAM"]) - skill_limit = 2; - int skills_need = skill_limit - skills_have.count(); - if (skills_need > 0 && my_path().id != PATH_POCKET_FAMILIARS) - { - //FIXME this could be rewritten to suggest turbo + compress, when we have enough extractions. - string [int] possible_skills; - if (!skills_have[$skill[Extract]]) - possible_skills.listAppend("Extract"); - if (!skills_have[$skill[Turbo]]) - possible_skills.listAppend("Turbo"); - - string linker = "or"; - if (skills_need > 1) - linker = "and"; - subentries.listAppend(ChecklistSubentryMake("Learn " + pluralise(skills_need, "skill", "skills"), "", "Maybe " + possible_skills.listJoinComponents(", ", linker) + ".")); - } - - //Set an enquiry: - if (get_property("sourceTerminalEnquiry") == "" && my_path().id != PATH_G_LOVER) - { - //familiar - +5 familiar weight - //monsters - +25 ML (in-run) - //protect - +3 all res (?) - //stats - +all stats (in-run) - string [int][int] enquiries; - if (!__misc_state["familiars temporarily blocked"]) - enquiries.listAppend(listMake("familiar.enq", "+5 familiar weight")); - if (__misc_state["in run"]) - { - enquiries.listAppend(listMake("monsters.enq", "+25 ML")); - enquiries.listAppend(listMake("stats.enq", "+100% stats")); - } - string [int] description; - - if (chips["DIAGRAM"] && get_property_int("sourceTerminalGram") >= 10) - description.listAppend("200 turn buff gained at rollover."); - else //gram chips are mysterious - description.listAppend("Buff gained at rollover."); - foreach key in enquiries - { - description.listAppend(enquiries[key][0] + ": " + enquiries[key][1]); - } - subentries.listAppend(ChecklistSubentryMake("Set an enquiry", "", description)); - } - //"Digitise something" like arrow something? - if (get_property_int("_sourceTerminalDigitizeUses") == 0 && __misc_state["in run"] && my_path().id != PATH_ZOMBIE_SLAYER && my_path().id != PATH_LIVE_ASCEND_REPEAT && my_path().id != PATH_POCKET_FAMILIARS) - { - string [int] description; - IOTMSourceTerminalGenerateDigitiseTargets(description); - subentries.listAppend(ChecklistSubentryMake("Digitise a monster", "", description)); - } - //Complicated, since we have three uses, and those are sort of resources... - //Maybe suggest the first use, and always list in resources for the rest. - //"Upgrade your source terminal" suggestions? Chips, essentially. - - string url = "campground.php?action=terminal"; - if (my_path().id == PATH_NUCLEAR_AUTUMN) - url = "place.php?whichplace=falloutshelter&action=vault_term"; - if (subentries.count() > 0) - optional_task_entries.listAppend(ChecklistEntryMake("__item source essence", url, subentries, 5).ChecklistEntrySetIDTag("Source terminal task")); -} - -RegisterResourceGenerationFunction("IOTMSourceTerminalGenerateResource"); -void IOTMSourceTerminalGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (in_bad_moon() || __campground[$item[Source Terminal]] == 0 || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - return; - - boolean [string] chips = getInstalledSourceTerminalSingleChips(); - //sourceTerminalChips, sourceTerminalPram, sourceTerminalGram, sourceTerminalSpam - ChecklistSubentry [int] subentries; - //Enhancement buffs: - int enhancement_limit = 1; - if (chips["CRAM"]) //CRAM chip installed - enhancement_limit += 1; - if (chips["SCRAM"]) //SCRAM chip installed - enhancement_limit += 1; - int enhancements_remaining = clampi(enhancement_limit - get_property_int("_sourceTerminalEnhanceUses"), 0, enhancement_limit); - if (enhancements_remaining > 0 && mafiaIsPastRevision(17011)) - { - int turn_duration = 25; //up to 100 - if (chips["INGRAM"]) - turn_duration += 25; - turn_duration += get_property_int("sourceTerminalPram") * 5; - turn_duration = clampi(turn_duration, 25, 100); - string turns_description = " (" + turn_duration + " turns)"; - string [int] description; - if (my_path().id != PATH_G_LOVER) - description.listAppend("items.enh: +30% item." + turns_description); - if (my_path().id != PATH_G_LOVER) - description.listAppend("meat.enh: +60% meat." + turns_description); - if (__misc_state["in run"] && my_path().id != PATH_G_LOVER) - description.listAppend("init.enh: +50% init." + turns_description); - if (my_path().id == PATH_G_LOVER) - description.listAppend("damage.enh: +5 prismatic damage, only usable buff in this path." + turns_description); - //the others are moderately boring - //+critical hit? niche - //+all elemental damage? useful in two places, but still niche enough to not be put here - //substats.enh is probably less than 150 mainstat. that's not a lot... +item is much more useful - subentries.listAppend(ChecklistSubentryMake(pluralise(enhancements_remaining, "source enhancement", "source enhancements") + " remaining", "", description)); - } - - int total_duplicate_uses_available = 1; - if (my_path().id == PATH_THE_SOURCE) - total_duplicate_uses_available = 5; - int duplicate_uses_remaining = clampi(total_duplicate_uses_available - get_property_int("_sourceTerminalDuplicateUses"), 0, total_duplicate_uses_available); - if (!mafiaIsPastRevision(17062)) - { - duplicate_uses_remaining = 1; - if (get_property_boolean("_sourceTerminalDuplicateUsed")) - duplicate_uses_remaining = 0; - } - if (my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_POCKET_FAMILIARS) - duplicate_uses_remaining = 0; - if (mafiaIsPastRevision(17031) && duplicate_uses_remaining > 0 && __misc_state["in run"] && my_path().id != PATH_G_LOVER) - { - //Duplication of a monster: - string [int] description; - boolean [skill] skills_have = getActiveSourceTerminalSkills(); - - string line = "Doubles"; - if (my_path().id == PATH_THE_SOURCE) - line = "Triples"; - string times = "once/day"; - if (total_duplicate_uses_available > 1) - times = total_duplicate_uses_available.int_to_wordy() + " times/day"; - line += " item drops from a monster, " + times + ".|Makes them stronger, so be careful."; - description.listAppend(line); - if (!skills_have[$skill[Duplicate]]) - { - description.listAppend("Learn with command \"educate duplicate.edu\"."); - } - - string [int] potential_targets; - //FIXME grey out if the area isn't available? - if ($item[goat cheese].available_amount() < 2 && !__quest_state["Level 8"].state_boolean["Past mine"]) - potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("dairy goat", $location[the goatlet])); - /*if (!__quest_state["Level 11"].finished && !__quest_state["Level 11 Palindome"].finished && $item[talisman o' namsilat].available_amount() == 0 && $items[gaudy key,snakehead charrrm].available_amount() < 2) - potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("gaudy pirate", $location[belowdecks])); //now obsolete*/ - if (my_path().id == PATH_THE_SOURCE) - { - //5x copies - //LFM, filthworms, evil eyes, tomb rats?, star monsters, Green Ops Soldier? - //FIXME actually test for these - potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("lobsterfrogman", $location[sonofa beach])); - potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("filthworms", $location[the hatching chamber])); - potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("defiled nook?", $location[the defiled nook])); - potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("tomb rats?", $location[the middle chamber])); - potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("hedge trimmers", $location[twin peak])); - potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("hole-in-the-sky monsters", $location[the hole in the sky])); - potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("green ops soldier", $location[the battlefield (frat uniform)])); - if (in_hardcore()) - potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("bloopers?", $location[8-bit realm])); - if (__iotms_usable[$item[Witchess Set]] && get_property_int("_witchessFights") < 5) - potential_targets.listAppend("witchess bishop/knight/rooks?"); - } - if (potential_targets.count() > 0) - description.listAppend("Could use on a " + potential_targets.listJoinComponents(", ", "or") + "."); - if (lookupItem("exploding cigar").item_amount() > 0) - description.listAppend("Use exploding cigar immediately after to win the fight."); - string title = "Duplication castable"; - if (total_duplicate_uses_available > 1) - { - title = pluralise(duplicate_uses_remaining, "duplication", "duplications"); - } - - subentries.listAppend(ChecklistSubentryMake(title, "", description)); - } - //Portscans: (the source) - int portscans_remaining = clampi(3 - get_property_int("_sourceTerminalPortscanUses"), 0, 3); - if (mafiaIsPastRevision(17031) && portscans_remaining > 0 && my_path().id == PATH_THE_SOURCE) - { - //Should we suggest portscan outside of the source? - //It's three scaling monsters a day, that can make one government potion/run, if optimally used in delay-burning areas. Otherwise, they're +turncount for no reason. - //So, do we give advice that's easy to get wrong? - - string [int] description; - description.listAppend("Cast to summon an agent next turn. Make sure to use it to burn delay."); - if (my_path().id == PATH_THE_SOURCE) - description.listAppend("To use optimally, cast once. Then set your autoattack to portscan, and adventure in a delay-burning area.|This will chain the agents, causing them to cost a single turn."); - if (get_property_int("sourceInterval") != 0 && my_path().id == PATH_THE_SOURCE) - description.listAppend("Wait a bit, this is better after an agent had just appeared."); - - subentries.listAppend(ChecklistSubentryMake(pluralise(portscans_remaining, "portscan", "portscans") + " remaining", "", description)); - - } - //Extrudes: - int extrudes_remaining = clampi(3 - get_property_int("_sourceTerminalExtrudes"), 0, 3); - - if (extrudes_remaining > 0 && mafiaIsPastRevision(16992) && my_path().id != PATH_ZOMBIE_SLAYER && my_path().id != PATH_POCKET_FAMILIARS && my_path().id != PATH_G_LOVER) - { - int essence = $item[source essence].available_amount(); - string [int] description; - if (__misc_state["can eat just about anything"] && my_path().id != PATH_NUCLEAR_AUTUMN) - { - string line = "Food: 4 fullness epic."; - if (essence < 10) - line = HTMLGenerateSpanFont(line, "grey"); - description.listAppend(line); - } - if ((my_path().id == PATH_LICENSE_TO_ADVENTURE || __misc_state["can drink just about anything"]) && my_path().id != PATH_NUCLEAR_AUTUMN) - { - string line = "Drink: 4 inebriety epic."; - if (__misc_state["in run"]) - line += " Useful nightcap."; - if (essence < 10) - line = HTMLGenerateSpanFont(line, "grey"); - description.listAppend(line); - } - if (!__misc_state["in run"]) - { - //In aftercore, suggest chips we don't have. Also the shades. - if ($item[source shades].available_amount() == 0 && essence >= 100) - description.listAppend("Source Shades: extra essence extracted when equipped."); - if (!$familiar[software bug].have_familiar() && essence >= 10000) - description.listAppend("Software bug: pet rock."); - string [int] chips_missing; - foreach s in $strings[CRAM,DRAM,TRAM] - { - if (!chips[s]) - chips_missing.listAppend(s); - } - if (get_property_int("sourceTerminalGram") < 10) - chips_missing.listAppend("GRAM"); - if (get_property_int("sourceTerminalPram") < 10) - chips_missing.listAppend("PRAM"); - if (get_property_int("sourceTerminalSpam") < 10) - chips_missing.listAppend("SPAM"); - if (chips_missing.count() > 0) - description.listAppend("Chip upgrades: " + chips_missing.listJoinComponents(", ", "or") + "."); - } - if (essence == 0 && __misc_state["in run"]) - { - boolean have_extract_skill = true; - if (!have_extract_skill) - description.listAppend("Learn and use the extract skill in combat for more essence."); - else - description.listAppend("Use the extract skill in combat for more essence."); - } - - subentries.listAppend(ChecklistSubentryMake(pluralise(extrudes_remaining, "source extrude", "source extrudes") + " remaining", "", description)); - } - //Digitise? - int digitisations = get_property_int("_sourceTerminalDigitizeUses"); - int digitisation_limit = 1; - if (chips["TRAM"]) - digitisation_limit += 1; - if (chips["TRIGRAM"]) - digitisation_limit += 1; - if (my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_LIVE_ASCEND_REPEAT || my_path().id == PATH_POCKET_FAMILIARS) - digitisation_limit = 0; - int digitisations_left = clampi(digitisation_limit - digitisations, 0, 3); - if (digitisations_left > 0) - { - string [int] description; - string monster_name = get_property("_sourceTerminalDigitizeMonster").to_lower_case(); - if (monster_name != "") - description.listAppend("Currently set to " + monster_name + "."); - IOTMSourceTerminalGenerateDigitiseTargets(description); - - subentries.listAppend(ChecklistSubentryMake(pluralise(digitisations_left, "digitisation", "digitisations") + " remaining", "", description)); - } - string url = "campground.php?action=terminal"; - if (my_path().id == PATH_NUCLEAR_AUTUMN) - url = "place.php?whichplace=falloutshelter&action=vault_term"; - if (subentries.count() > 0) - resource_entries.listAppend(ChecklistEntryMake("__item source essence", url, subentries, 5).ChecklistEntrySetIDTag("Source terminal resource")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2016/Telegraph Office.ash b/Source/relay/TourGuide/Items of the Month/2016/Telegraph Office.ash deleted file mode 100644 index 4d914c28..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Telegraph Office.ash +++ /dev/null @@ -1,263 +0,0 @@ -import "relay/TourGuide/Support/Location Choice.ash"; - -RegisterTaskGenerationFunction("IOTMTelegraphOfficeGenerateTasks"); -void IOTMTelegraphOfficeGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[$item[LT&T telegraph office deed]]) - return; - - - if ($item[your cowboy boots].available_amount() == 0) - { - optional_task_entries.listAppend(ChecklistEntryMake("__item your cowboy boots", "place.php?whichplace=town_right", ChecklistSubentryMake("Acquire your cowboy boots", "", "Visit the LT&T office."), 0).ChecklistEntrySetIDTag("Telegraph office LT&T cowboy boots")); - - } - - - if (!mafiaIsPastRevision(16674)) - return; - - QuestState ltt_quest = QuestState("questLTTQuestByWire"); - - if (!ltt_quest.in_progress) - return; - - int difficulty = get_property_int("lttQuestDifficulty"); - int stage_count = get_property_int("lttQuestStageCount"); - string quest_name = get_property("lttQuestName"); - if (quest_name == "") - return; - - //step1 - the investigation begins - //step2 - The Investigation Continues - //step3 - The Investigation Continues - //step4 - boss fight - - int turns_completed = stage_count; - if (ltt_quest.mafia_internal_step > 2) - turns_completed += 10; - if (ltt_quest.mafia_internal_step > 3) - turns_completed += 10; - if (ltt_quest.mafia_internal_step > 4) - turns_completed += 10; - //quest_name is blank when not on the quest - int turns_remaining = clampi(29 - turns_completed, 0, 29); - //"Missing: Many Children" - clara - //"Wagon Train Escort Wanted" - Granny Hackleton - //"Madness at the Mine" - unusual construct - - monster [string] boss_for_quest; - - boss_for_quest["Missing: Fancy Man"] = $monster[Jeff the Fancy Skeleton]; - boss_for_quest["Help! Desperados!"] = $monster[Pecos Dave]; - boss_for_quest["Missing: Pioneer Daughter"] = $monster[Daisy the Unclean]; - - boss_for_quest["Big Gambling Tournament Announced"] = $monster[Snake-Eyes Glenn]; - boss_for_quest["Haunted Boneyard"] = $monster[Pharaoh Amoon-Ra Cowtep]; - boss_for_quest["Sheriff Wanted"] = $monster[Former Sheriff Dan Driscoll]; - - boss_for_quest["Missing: Many Children"] = $monster[Clara]; - boss_for_quest["Wagon Train Escort Wanted"] = $monster[Granny Hackleton]; - boss_for_quest["Madness at the Mine"] = $monster[unusual construct]; - - - - string [int] description; - string [int] modifiers; - if (turns_remaining > 0) - description.listAppend(pluraliseWordy(turns_remaining, "more turn", "more turns").capitaliseFirstLetter() + " until the boss."); - if (turns_remaining == 0 || ltt_quest.mafia_internal_step == 5) - { - string url = "inventory.php?ftext=plaintive+telegram"; - monster boss = boss_for_quest[quest_name]; - if (boss == $monster[none]) - description.listAppend("Defeat the boss."); - else - description.listAppend("Defeat " + boss + "."); - boolean frigidalmatian_eligible = false; - if (boss == $monster[Clara]) - { - modifiers.listAppend("+elemental resistance"); - description.listAppend("Use high-damage spells, like shrap + snow mobile/green lantern."); - frigidalmatian_eligible = true; - } - else if (boss == $monster[Granny Hackleton]) - { - description.listAppend("Use different high-damage combat items, or frigidalmatian and attack."); - //FIXME suggest a list of combat items to use - frigidalmatian_eligible = true; - } - else if (boss == $monster[unusual construct]) - { - description.listAppend("Each round, you have to respond with the correct shiny disc to survive. Mafia will select the correct one.|Maybe funksling with new-age hurting crystals."); - frigidalmatian_eligible = true; - } - else if (boss == $monster[Jeff the Fancy Skeleton]) - { - description.listAppend("Attack with a blunt weapon. (clubs, flails, saucepans...)"); - description.listAppend("Combat items won't work, skills are mostly blocked."); - } - else if (boss == $monster[Pecos Dave]) - { - description.listAppend("Attack with multiple sources of damage."); - if ($item[wicker slicker].available_amount() > 0 && $skill[shell up].have_skill()) - { - if ($item[wicker slicker].equipped_amount() > 0) - description.listAppend("Shell up on alternate rounds?"); - else - description.listAppend("Equip wicker slicker and shell up on alternate rounds?"); - } - frigidalmatian_eligible = true; - } - else if (boss == $monster[Daisy the Unclean]) - { - //FIXME - } - else if (boss == $monster[Snake-Eyes Glenn]) - { - description.listAppend("Immune to all but a single element type each round.|Previous round's second roll indicates which."); - } - else if (boss == $monster[Pharaoh Amoon-Ra Cowtep]) - { - description.listAppend("Avoid attacking with spell damage."); - } - else if (boss == $monster[Former Sheriff Dan Driscoll]) - { - description.listAppend("Acquire passive damage (glowing syringes?), attack repeatedly."); - frigidalmatian_eligible = true; - } - - // This already existed but it was in the wrong ash file lol. - string image_name = "__monster " + boss; - task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake("Defeat " + boss + "!", modifiers, description), -11)); - - if (frigidalmatian_eligible) - { - string [int] tasks; - boolean frigidalmatian_obtainable = false; - if ($effect[frigidalmatian].have_effect() > 0) - frigidalmatian_obtainable = true; - if ($effect[frigidalmatian].have_effect() == 0 && $skill[frigidalmatian].have_skill()) - { - frigidalmatian_obtainable = true; - tasks.listAppend("cast frigidalmatian"); - } - if (frigidalmatian_obtainable && $items[rain-doh green lantern,snow mobile].equipped_amount() == 0) - { - if ($item[rain-doh green lantern].available_amount() > 0) - { - tasks.listAppend("equip rain-doh green lantern"); - } - else if (lookupItems("meteorb,metal meteoroid").available_amount() > 0) - { - tasks.listAppend("equip meteorb"); - } - else if ($item[snow mobile].is_unrestricted()) - { - if ($item[snow mobile].available_amount() > 0) - { - tasks.listAppend("equip snow mobile"); - } - else - tasks.listAppend("acquire and equip snow mobile"); - } - } - if (tasks.count() > 0) - description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - } - } - - if (false) - { - foreach s in $strings[lttQuestDifficulty,lttQuestStageCount,lttQuestName,questLTTQuestByWire] - description.listAppend(s + " = " + get_property(s)); - } - - ChecklistEntry entry = ChecklistEntryMake("__item sea cowboy hat", "inventory.php?ftext=plaintive+telegram", ChecklistSubentryMake(quest_name, modifiers, description), $locations[Investigating a Plaintive Telegram]); - entry.tags.id = "Telegraph office LT&T quest"; - if (__misc_state["in run"]) - future_task_entries.listAppend(entry); - else - optional_task_entries.listAppend(entry); -} - -RegisterResourceGenerationFunction("IOTMTelegraphOfficeGenerateResource"); -void IOTMTelegraphOfficeGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (__misc_state["in run"] && $item[Clara's bell].available_amount() > 0 && !get_property_boolean("_claraBellUsed")) - { - string [int] description; - description.listAppend("Ring for a non-combat next turn, once/day."); - - LocationChoice [int] options; - - //√spooky forest - unlocking the hidden temple - //6 - advance one of the quest areas - //7 - defiled cranny - //8 - umm... maybe the extreme slow? unimportant? - //9 - twin peak - //10 - top/bottom of the castle, best place in the game(?) - //11 - copperhead, protestors, fun hidden city exploit, hidden temple but marginal, palindome but marginal, pyramid in situations where you can't run lots of +item, poop deck, haunted billiards room, haunted bathroom - //12 - starting the war(??) - - //2 - mosquito - not terribly important - //3 - tavern - forces a skippable NC, not important - - if (!get_property_ascension("lastTempleUnlock")) - { - //options.listAppend("") - options.listAppend(LocationChoiceMake($location[the spooky forest], "unlocking the hidden temple")); - } - - if (my_path().id == PATH_COMMUNITY_SERVICE) - { - foreach key in options - remove options[key]; - } - - if (options.count() > 0) - { - description.listAppend("Suggested areas:|*" + LocationChoiceGenerateDescription(options).listJoinComponents("|*")); - } - - - resource_entries.listAppend(ChecklistEntryMake("__item clara's bell", "inventory.php?ftext=clara's+bell", ChecklistSubentryMake("Clara's Bell", "", description), 5).ChecklistEntrySetIDTag("LT&T claras bell resource")); - } - - //skills: - //Bow-Legged Swagger -> _bowleggedSwaggerUsed - //Bend Hell -> _bendHellUsed - //Steely-Eyed Squint -> _steelyEyedSquintUsed - //bend hell - double elemental damage/elemental spell damage - if (true) - { - string [skill] telegraph_skill_properties; - if (__misc_state["in run"]) - { - telegraph_skill_properties[$skill[Bow-Legged Swagger]] = "_bowleggedSwaggerUsed"; - telegraph_skill_properties[$skill[Bend Hell]] = "_bendHellUsed"; - } - telegraph_skill_properties[$skill[Steely-Eyed Squint]] = "_steelyEyedSquintUsed"; - - string [skill] telegraph_skill_descriptions; - telegraph_skill_descriptions[$skill[Bow-Legged Swagger]] = "Double +initiative and physical damage. Once/day."; - telegraph_skill_descriptions[$skill[Bend Hell]] = "Double elemental damage/elemental spell damage. Once/day."; - telegraph_skill_descriptions[$skill[Steely-Eyed Squint]] = "Double +item. Once/day."; - - string image_name; - ChecklistSubentry [int] subentries; - foreach s, property in telegraph_skill_properties - { - if (!s.skill_is_usable()) - continue; - if (get_property_boolean(property)) - continue; - - if (image_name == "") - image_name = "__skill " + s; - subentries.listAppend(ChecklistSubentryMake(s + " castable", "", telegraph_skill_descriptions[s])); - } - if (subentries.count() > 0) - resource_entries.listAppend(ChecklistEntryMake(image_name, "skillz.php", subentries, 9).ChecklistEntrySetIDTag("LT&T daily cowboy skills resource")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2016/Thanksgarden.ash b/Source/relay/TourGuide/Items of the Month/2016/Thanksgarden.ash deleted file mode 100644 index e5a3aad0..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Thanksgarden.ash +++ /dev/null @@ -1,141 +0,0 @@ -RegisterResourceGenerationFunction("IOTMThanksgardenGenerateResource"); -void IOTMThanksgardenGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["in run"]) - return; - - item turkey_blaster = $item[turkey blaster]; - item stuffing_fluffer = $item[stuffing fluffer]; - item cashew = $item[cashew]; - item cornucopia = $item[cornucopia]; - - ChecklistSubentry [int] subentries; - string url; - string image_name; - TagGroup tags; - tags.id = "Campground thanksgarden cornucopia resource"; - - - - if (cornucopia.available_amount() > 0 && in_ronin()) - { - string [int] description; - description.listAppend("Open for thanksgarden food."); - if (image_name == "") - image_name = "__item cornucopia"; - if (url == "") - url = "inventory.php?ftext=cornucopia"; - subentries.listAppend(ChecklistSubentryMake(pluralise(cornucopia), "", description)); - } - int cashew_amount = cashew.available_amount(); - if (cashew_amount > 0 && in_ronin()) - { - string [int] description; - string [int] options; - //so creatable_amount() is weird, so we perform the calculation ourselves - /* - > ash $item[cashew].available_amount() - - Returned: 13 - - > ash $item[turkey blaster].creatable_amount() - - Returned: 0 - */ - if (my_path().id != PATH_NUCLEAR_AUTUMN && spleen_limit() > 0 && $item[cashew].available_amount() >= 3) - options.listAppend(HTMLGreyOutTextUnlessTrue(pluralise($item[cashew].available_amount() / 3, $item[turkey blaster]) + " to burn delay", cashew_amount >= 3)); - if (!__quest_state["Level 12"].finished) - options.listAppend(HTMLGreyOutTextUnlessTrue(pluralise($item[cashew].available_amount() / 3, $item[stuffing fluffer]) + " for the war", cashew_amount >= 3)); - if (my_path().id != PATH_NUCLEAR_AUTUMN && fullness_limit() > 0) - options.listAppend("various foods"); - if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"] && $item[gravy boat].available_amount() == 0) - options.listAppend(HTMLGreyOutTextUnlessTrue("gravy boat for the cyrpt (somewhat marginal)", cashew_amount >= 3)); - if (options.count() > 0) - description.listAppend("Could make into " + options.listJoinComponents(", ", "or") + "."); - - string [int] foods_we_can_make; - - if (image_name == "") - image_name = "__item cashew"; - if (url == "") - url = "shop.php?whichshop=thankshop"; - subentries.listAppend(ChecklistSubentryMake(pluralise(cashew), "", description)); - } - - if (turkey_blaster.available_amount() > 0 && my_path().id != PATH_NUCLEAR_AUTUMN) - { - string [int] description; - int uses_left = clampi(3 - get_property_int("_turkeyBlastersUsed"), 0, 3); - int pre_spleen_uses_left = uses_left; - uses_left = MIN(uses_left, availableSpleen() / 2); - - string [int] delay_areas; - foreach l in $locations[the outskirts of cobb's knob,the spooky forest,The Castle in the Clouds in the Sky (Ground Floor),the haunted gallery,the haunted bathroom,the haunted ballroom,the boss bat's lair] - { - if (l.delayRemainingInLocation() > 1) - delay_areas.listAppend(l); - } - - description.listAppend("Will burn five turns of delay in the last area you've adventured."); - if (delay_areas.count() > 0) - description.listAppend("Suggested areas:|*" + delay_areas.listJoinComponents(", ", "and") + "."); - if (uses_left == 0) - { - if (pre_spleen_uses_left > 0) - description.listAppend("Cannot use any more today; no spleen room."); - else - description.listAppend("Cannot use any more today."); - } - else - description.listAppend("Can use " + pluraliseWordy(uses_left, "more time", "more times") + " today."); - - - if (image_name == "") - image_name = "__item turkey blaster"; - if (url == "") - url = "inventory.php?ftext=turkey+blaster"; - subentries.listAppend(ChecklistSubentryMake(pluralise(turkey_blaster), "", description)); - } - if (!__quest_state["Level 12"].finished && __quest_state["Level 12"].state_int["frat boys left on battlefield"] > 0 && __quest_state["Level 12"].state_int["hippies left on battlefield"] > 0 && stuffing_fluffer.available_amount() > 0) - { - string [int] description; - description.listAppend("Clears out level twelve armies. Use before adventuring on the battlefield."); - - if (image_name == "") - image_name = "__item stuffing fluffer"; - if (url == "") - url = "inventory.php?ftext=stuffing+fluffer"; - subentries.listAppend(ChecklistSubentryMake(pluralise(stuffing_fluffer), "", description)); - } - - - if (subentries.count() > 0) - { - resource_entries.listAppend(ChecklistEntryMake(image_name, url, subentries, tags, 4)); - } - -} - -RegisterTaskGenerationFunction("IOTMThanksgardenGenerateTasks"); -void IOTMThanksgardenGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - int delay_limit = 4; - if (get_property_int("_turkeyBlastersUsed") < 3 && availableSpleen() >= 2 && $item[turkey blaster].available_amount() + $item[turkey blaster].creatable_amount() > 0 && get_property_location("lastAdventure").delayRemainingInLocation() >= delay_limit) - { - string url = ""; - if ($item[turkey blaster].available_amount() > 0) - url = "inventory.php?ftext=turkey+blaster"; - else - url = "shop.php?whichshop=thankshop"; - location last_location = get_property_location("lastAdventure"); - string [int] description; - description.listAppend("Save " + MIN(5, last_location.delayRemainingInLocation()) + " turns in " + last_location + "."); - if (my_level() < 4) - description.listAppend("Reach level four first."); - boolean allow = true; - if ($locations[the penultimate fantasy airship,the hidden office building,the hidden apartment building] contains last_location) - allow = false; - if (allow) - task_entries.listAppend(ChecklistEntryMake("__item turkey blaster", url, ChecklistSubentryMake("Chew turkey blaster", "", description), -11).ChecklistEntrySetIDTag("Campground thanksgarden turkey blaster resource")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2016/Time-Spinner.ash b/Source/relay/TourGuide/Items of the Month/2016/Time-Spinner.ash deleted file mode 100644 index a03d5774..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Time-Spinner.ash +++ /dev/null @@ -1,50 +0,0 @@ -RegisterResourceGenerationFunction("IOTMTimeSpinnerGenerateResource"); -void IOTMTimeSpinnerGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!mafiaIsPastRevision(17209)) - return; - //Warn about eating if they're low on turns - you can't use the time spinner when you're out of adventures. - if (!__iotms_usable[$item[Time-Spinner]]) return; - int minutes_left = clampi(10 - get_property_int("_timeSpinnerMinutesUsed"), 0, 10); - if (minutes_left <= 0) - return; - - string [int] description; - - if (minutes_left >= 3) - { - //Recent fight - 3 minutes - fight something past. Umm... hmm... same as any monster you copy? Though with restrictions. Plus olfaction-lite in NA. - int amount = minutes_left / 3; - description.listAppend(HTMLGenerateSpanOfClass(pluralise(amount, "recent fight", "recent fights"), "r_bold") + ": Re-fight a monster this ascension."); - //Delicious meal - 3 minutes - if (__misc_state["can eat just about anything"] && availableFullness() > 0) - { - description.listAppend(HTMLGenerateSpanOfClass(pluralise(amount, "meal", "meals"), "r_bold") + ": Re-eat something else today."); - } - } - //Way back in time - 1 minute, stats, costs a turn(?) - if (minutes_left >= 2) - { - //Visit the far future - 2 minutes, star-trek mini-game, lets you replicate things. Script fodder. - if (!get_property_boolean("_timeSpinnerReplicatorUsed")) - { - string [int] options; - if (__misc_state["can eat just about anything"] && availableFullness() > 0) - options.listAppend("epic food"); - if (__misc_state["can drink just about anything"] && availableDrunkenness() > 0) - options.listAppend("drink"); - if (!in_ronin()) - options.listAppend("something to sell"); - if (my_path().id == PATH_GELATINOUS_NOOB && !lookupSkill("Pathological Greed").have_skill() && $item[shot of Kardashian Gin].available_amount() == 0) - { - options.listAppend("Kardashian Gin for +meat skill"); - } - if (options.count() == 0) - options.listAppend("item"); - description.listAppend(HTMLGenerateSpanOfClass("Future", "r_bold") + ": once/day " + options.listJoinComponents(" / ") + "."); - } - } - //Play a time prank - 1 minute, heart - - resource_entries.listAppend(ChecklistEntryMake("__item Time-Spinner", "inv_use.php?whichitem=9104&pwd=" + my_hash(), ChecklistSubentryMake(pluralise(minutes_left, "Time-Spinner minute", "Time-Spinner minutes"), "", description), 5).ChecklistEntrySetIDTag("Time-spinner resource")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2016/Witchess.ash b/Source/relay/TourGuide/Items of the Month/2016/Witchess.ash deleted file mode 100644 index b71d676c..00000000 --- a/Source/relay/TourGuide/Items of the Month/2016/Witchess.ash +++ /dev/null @@ -1,76 +0,0 @@ -RegisterResourceGenerationFunction("IOTMWitchessGenerateResource"); -void IOTMWitchessGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[Witchess Set]]) - return; - if (!mafiaIsPastRevision(16813)) - return; - - string image_name = ""; - ChecklistSubentry [int] subentries; - if (get_property_int("_witchessFights") < 5) - { - string [int] description; - int fights_remaining = clampi(5 - get_property_int("_witchessFights"), 0, 5); - - string [int][int] fight_descriptions; - //fight_descriptions.listAppend(listMake(HTMLGenerateSpanOfClass("Piece", "r_bold"), HTMLGenerateSpanOfClass("Drop", "r_bold"))); - if (__misc_state["in run"]) - { - //√pawn - +50% init potion for moderns - if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"] && $item[armored prawn].available_amount() == 0 && $item[armored prawn].to_effect().have_effect() == 0 && my_path().id != PATH_G_LOVER) - { - fight_descriptions.listAppend(listMake("Pawn", "+50% init spleen potion.")); - } - //rook - +ML / +stat potion - if (my_path().id != PATH_G_LOVER) - fight_descriptions.listAppend(listMake("Rook", "+25 ML/+statgain potion. (25 turns)")); - //ox - shield - if ($item[ox-head shield].available_amount() == 0 && $item[ox-head shield].item_is_usable()) - fight_descriptions.listAppend(listMake("Ox", "+100HP, +2 all res, +8 PVP fights shield.")); - //king - club - if ((my_path().id == PATH_COMMUNITY_SERVICE || my_primestat() == $stat[muscle]) && $item[dented scepter].available_amount() == 0 && $item[dented scepter].item_is_usable()) - fight_descriptions.listAppend(listMake("King", "+5 muscle stats/fight, +50% muscle, +50% weapon damage club.")); - //queen - -combat hat - if ($item[very pointy crown].available_amount() == 0 && $item[very pointy crown].item_is_usable()) - fight_descriptions.listAppend(listMake("Queen", "-combat, +5 adventures, +50% moxie, +5 moxie stats/fight hat.|Queen is exceptionally difficult to defeat, probably requiring deleveling via items" + ($skill[tricky knifework].have_skill() ? ", or maybe knife tricks" : "") + ".")); - //witch - myst broom - if ((my_path().id == PATH_COMMUNITY_SERVICE || my_primestat() == $stat[mysticality]) && $item[battle broom].available_amount() == 0 && $item[battle broom].item_is_usable()) - fight_descriptions.listAppend(listMake("Witch", "+5 myst stats/fight, +50% myst, +100% spell damage accessory.|Immune to spells, but not skills.")); - } - //knight - epic food, +meat drop - if (__misc_state["can eat just about anything"]) - { - fight_descriptions.listAppend(listMake("Knight", "+100% meat epic food.")); - } - //bishop - epic drink, +50% item - if (__misc_state["can drink just about anything"] && my_path().id != PATH_G_LOVER) - { - fight_descriptions.listAppend(listMake("Bishop", "+50% item epic drink.")); - } - - if (fight_descriptions.count() > 0) - { - //Bold the piece names: - foreach key in fight_descriptions - { - fight_descriptions[key][0] = HTMLGenerateSpanOfClass(fight_descriptions[key][0], "r_bold"); - } - description.listAppend(HTMLGenerateSimpleTableLines(fight_descriptions)); - } - - image_name = "__itemsize __monster Witchess Pawn"; - //subentries.listAppend(ChecklistSubentryMake(pluralise(fights_remaining, "witchess fight", "witchess fights"), "", description)); - resource_entries.listAppend(ChecklistEntryMake(image_name, "campground.php?action=witchess", ChecklistSubentryMake(pluralise(fights_remaining, "witchess fight", "witchess fights"), "", description)).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Witchess set free fights")); - } - if (!get_property_boolean("_witchessBuff") && mafiaIsPastRevision(16879) && !__misc_state["familiars temporarily blocked"] && $effect[puzzle champ].effect_is_usable()) - { - int familiar_weight_modifier = MAX(5, get_property_int("puzzleChampBonus")); - if (image_name == "") - image_name = "__effect Puzzle Champ"; - subentries.listAppend(ChecklistSubentryMake("Witchess buff", "", "+" + familiar_weight_modifier + " familiar weight. (25 turns)")); - //resource_entries.listAppend(ChecklistEntryMake("__effect Puzzle Champ", "campground.php?action=witchess", ChecklistSubentryMake("Witchess buff", "", "+" + familiar_weight_modifier + " familiar weight. (25 turns)"), 4)); - } - if (subentries.count() > 0) - resource_entries.listAppend(ChecklistEntryMake(image_name, "campground.php?action=witchess", subentries, 4).ChecklistEntrySetIDTag("Witchess set resource")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2017/Asdon Martin.ash b/Source/relay/TourGuide/Items of the Month/2017/Asdon Martin.ash deleted file mode 100644 index 3372d43c..00000000 --- a/Source/relay/TourGuide/Items of the Month/2017/Asdon Martin.ash +++ /dev/null @@ -1,146 +0,0 @@ - -import "relay/TourGuide/Support/Library 2.ash" -import "relay/TourGuide/Support/Ingredients.ash" - -RegisterTaskGenerationFunction("IOTMAsdonMartinGenerateTasks"); -void IOTMAsdonMartinGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[lookupItem("Asdon martin keyfob")]) - return; - //BanishIsActive - if (!BanishIsActive("Spring-Loaded Front Bumper") && __misc_state["in run"] && (my_path().id != PATH_POCKET_FAMILIARS || (__iotms_usable[$item[source terminal]] && __iotms_usable[lookupItem("FantasyRealm membership packet")]))) - { - string description = "Banish" + (__misc_state["free runs usable"] ? "/free run" : "") + ", "; - - string fuel = "costs 50 fuel."; - if (get_fuel() < 50) - { - description += HTMLGenerateSpanFont(fuel, "red"); - description += "|" + HTMLGenerateSpanFont("Fuel up to 50 first.", "red"); - } - else - description += fuel; - if (my_path().id == PATH_POCKET_FAMILIARS) - description += "|In FantasyRealm, where you can extract for consumables."; - task_entries.listAppend(ChecklistEntryMake("__item Asdon Martin keyfob", "campground.php?action=fuelconvertor", ChecklistSubentryMake("Cast Spring-Loaded Front Bumper", "", description), -11).ChecklistEntrySetIDTag("Asdon front bumper reminder")); - } -} - -RegisterResourceGenerationFunction("IOTMAsdonMartinGenerateResource"); -void IOTMAsdonMartinGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[lookupItem("Asdon martin keyfob")]) - return; - ChecklistEntry entry; - entry.importance_level = 0; - entry.tags.id = "Asdon Martin resource"; - if (__misc_state["in run"] && in_ronin()) - { - item [int] fuelables = asdonMartinGenerateListOfFuelables(); - if (fuelables.count() > 0) - { - string [int] fuelables_extended; - string [int] fuelables_extended_part_2; - foreach key, fuelable in fuelables - { - int creatable_amount = fuelable.creatable_amount(); - string line; - line = " ("; - line += (fuelable.averageAdventuresForConsumable() * (creatable_amount + fuelable.item_amount())).round(); - if (fuelable.item_amount() == 0) - { - if (fuelable.craft_type() == "Summon Clip Art") continue; - line += ", "; - boolean first = true; - foreach it, amount in fuelable.get_ingredients_fast() - { - if (first) - first = false; - else - line += " + "; - if (amount > 1) - line += amount + " "; - line += it; - } - } - line += ")"; - line = fuelable.to_string() + HTMLGenerateSpanOfClass(line, "r_cl_modifier_inline"); - - string desired_colour = ""; - if (fuelable.quality == "EPIC") - desired_colour = "blueviolet"; - else if (fuelable.quality == "awesome") - desired_colour = "blue"; - else if (fuelable.quality == "good") - desired_colour = "green"; - else if (fuelable.quality == "crappy") - desired_colour = "#999999"; - boolean cannot_consume_anyways = false; - if (!__misc_state["can eat just about anything"] && fuelable.fullness > 0) - cannot_consume_anyways = true; - if (!__misc_state["can drink just about anything"] && fuelable.inebriety > 0 && !(my_path().id == PATH_LICENSE_TO_ADVENTURE && fuelable.image == "martini.gif")) - cannot_consume_anyways = true; - if (!fuelable.is_unrestricted()) - cannot_consume_anyways = true; - if (cannot_consume_anyways) - desired_colour = "#999999"; - if (desired_colour != "") - line = HTMLGenerateSpanFont(line, desired_colour); - if (key >= 0 && true) - { - fuelables_extended_part_2.listAppend(line); - //break; - } - else - fuelables_extended.listAppend(line); - } - string [int] description; - if (fuelables_extended_part_2.count() > 0) - { - //fuelables_extended.listAppend("(...)"); - int estimated_margin = fuelables_extended_part_2.count() * 1.2; - fuelables_extended.listAppend(HTMLGenerateSpanOfClass(HTMLGenerateTagWrap("span", fuelables_extended_part_2.listJoinComponents("
"), mapMake("class", "r_tooltip_inner_class r_tooltip_inner_class_margin", "style", "margin-top:-" + estimated_margin + "em;margin-left:-5em;")) + "Fuel list.", "r_tooltip_outer_class") + ($item[loaf of soda bread].creatable_amount() > 0 ? "|Or create and feed loaf of soda breads." : "")); - } - else if ($item[loaf of soda bread].creatable_amount() > 0) - description.listAppend("Or create and feed loaf of soda breads."); - //description.listAppend(HTMLGenerateSpanOfClass(HTMLGenerateTagWrap("span",HTMLGenerateSimpleTableLines(table, false), mapMake("class", "r_tooltip_inner_class r_tooltip_inner_class_margin", "style", "margin-top:-" + estimated_margin + "em;margin-left:-5em;")) + "Costs one spleen and two candies.", "r_tooltip_outer_class")); - //description.listAppend("Could fuel with:|*" + fuelables_extended.listJoinComponents("|*", "")); - description.listAppend(fuelables_extended.listJoinComponents("|*", "")); - entry.subentries.listAppend(ChecklistSubentryMake(get_fuel() + " Fuel", "", description)); - if (entry.url == "") - entry.url = "campground.php?action=fuelconvertor"; - if (entry.image_lookup_name == "") - entry.image_lookup_name = "__item Asdon Martin keyfob"; - } - } - if (!get_property_boolean("_missileLauncherUsed") && my_path().id != PATH_POCKET_FAMILIARS && my_path().id != PATH_G_LOVER) - { - if (entry.image_lookup_name == "") - entry.image_lookup_name = "__skill asdon martin: missile launcher"; - if (entry.url == "") - entry.url = "campground.php?action=workshed"; - string fuel_costs = "Costs 100 fuel"; - if (get_fuel() < 100) - fuel_costs = HTMLGenerateSpanFont(fuel_costs, "red"); - resource_entries.listAppend(ChecklistEntryMake("__item Asdon Martin keyfob", "campground.php?action=workshed", ChecklistSubentryMake("Asdon Missile", "", fuel_costs + ", instakill + YR-equivalent.")).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Asdon Martin missile launcher")); - //entry.subentries.listAppend(ChecklistSubentryMake("Asdon Missile", "", fuel_costs + ", instakill + YR-equivalent.")); - } - if (BanishIsActive("Spring-Loaded Front Bumper")) - { - Banish b = BanishByName("Spring-Loaded Front Bumper"); - int turns_left = b.banish_turn_length - (my_turncount() - b.turn_banished); - - if (turns_left > 0 && turns_left <= 30) - { - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(turns_left, "turn", "turns") + " to next asdon bumper", "", "Banish/runaway.")); - if (entry.image_lookup_name == "") - entry.image_lookup_name = "__item Asdon Martin keyfob"; - } - if (entry.url == "") - entry.url = "campground.php?action=workshed"; - } - if (entry.subentries.count() > 0) - { - resource_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2017/GenieBottle.ash b/Source/relay/TourGuide/Items of the Month/2017/GenieBottle.ash deleted file mode 100644 index 4085ba25..00000000 --- a/Source/relay/TourGuide/Items of the Month/2017/GenieBottle.ash +++ /dev/null @@ -1,35 +0,0 @@ -RegisterResourceGenerationFunction("IOTMGenieBottleGenerateResource"); -void IOTMGenieBottleGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (lookupItem("genie bottle").item_amount() + lookupItem("pocket wish").item_amount() + lookupItem("replica genie bottle").item_amount() == 0) return; - - // Detect replica versus genie classic for the purposes of the URL - string activeGenieID = lookupItem("replica genie bottle").available_amount() > 0 ? "11234" : "9529"; - - int wishes_left = 0; - - // Add up all possible wish sources; pocket wishes, replicas, and genie bottles - if (__misc_state["in run"] && in_ronin()) - wishes_left += lookupItem("pocket wish").item_amount(); - if (lookupItem("genie bottle").item_amount() > 0 && mafiaIsPastRevision(18219) && my_path().id != PATH_BEES_HATE_YOU) - wishes_left += clampi(3 - get_property_int("_genieWishesUsed"), 0, 3); - if (lookupItem("replica genie bottle").item_amount() > 0) - wishes_left += clampi(3 - get_property_int("_genieWishesUsed"), 0, 3); - - string [int] description; - - if (wishes_left > 0) - { - - activeGenieID = get_property_int("_genieWishesUsed") >= 3 ? "9537" : activeGenieID; - - // URL to the correct genie as per activeGenieID - string url = "inv_use.php?pwd=" + my_hash() + "&whichitem=" + activeGenieID; - - boolean [monster] invalid_monsters = $monsters[ninja snowman assassin, modern zmobie, giant swarm of ghuol whelps, screambat, monstrous boiler]; - string potential_monsters = SFaxGeneratePotentialFaxes(true, invalid_monsters).listJoinComponents("|
"); - if (potential_monsters != "") - description.listAppend("Could fight a monster:
" + potential_monsters); - resource_entries.listAppend(ChecklistEntryMake("__item genie bottle", url, ChecklistSubentryMake(pluralise(wishes_left, "wish", "wishes"), "", description), 1).ChecklistEntrySetIDTag("Genie bottle resource")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2017/KGBriefcase.ash b/Source/relay/TourGuide/Items of the Month/2017/KGBriefcase.ash deleted file mode 100644 index c4111aec..00000000 --- a/Source/relay/TourGuide/Items of the Month/2017/KGBriefcase.ash +++ /dev/null @@ -1,34 +0,0 @@ -RegisterResourceGenerationFunction("IOTMKGBriefcaseGenerateResource"); -void IOTMKGBriefcaseGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[lookupItem("kremlin's greatest briefcase")]) return; - ChecklistEntry entry; - entry.image_lookup_name = "__item Kremlin's Greatest Briefcase"; - entry.importance_level = 5; - entry.url = "place.php?whichplace=kgb"; - entry.tags.id = "Kremlin Briefcase resource"; - if (get_property_int("_kgbTranquilizerDartUses") < 3 && my_path().id != PATH_POCKET_FAMILIARS) - { - string [int] description; - description.listAppend("Free run, 20-turn banish.|Use the KGB tranquilizer dart skill in-combat."); - if (lookupItem("kremlin's greatest briefcase").equipped_amount() == 0) - { - description.listAppend(HTMLGenerateSpanFont("Equip the briefcase first!", "red")); - entry.url = "inventory.php?ftext=kremlin"; - } - resource_entries.listAppend(ChecklistEntryMake("__item Kremlin's Greatest Briefcase", entry.url, ChecklistSubentryMake(pluralise(3 - get_property_int("_kgbTranquilizerDartUses"), "briefcase dart", "briefcase darts"), "", description),0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Kremlin Briefcase tranq dart banish")); - } - int clicks_remaining = clampi(22 - get_property_int("_kgbClicksUsed"), 0, 22); - if (!mafiaIsPastRevision(18110)) - clicks_remaining = 0; - if (clicks_remaining > 0) - { - string [int] description; - description.listAppend("All sorts of things. Buffs, martinis, cigars!"); - entry.url = "place.php?whichplace=kgb"; - - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(clicks_remaining, "click", "clicks"), "", description)); - } - if (entry.subentries.count() > 0) - resource_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Items of the Month/2017/Meteor Lore.ash b/Source/relay/TourGuide/Items of the Month/2017/Meteor Lore.ash deleted file mode 100644 index 278e4471..00000000 --- a/Source/relay/TourGuide/Items of the Month/2017/Meteor Lore.ash +++ /dev/null @@ -1,87 +0,0 @@ - -//_macrometeoriteUses -//_meteorShowerUses -RegisterResourceGenerationFunction("IOTMMeteorLoreGenerateResource"); -void IOTMMeteorLoreGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupSkill("Meteor Lore").have_skill()) - return; - if (!__misc_state["in run"]) return; - if (!mafiaIsPastRevision(18174)) return; - if (my_path().id == PATH_G_LOVER) return; - - ChecklistEntry entry; - entry.image_lookup_name = "__skill Meteor Lore"; - entry.tags.id = "Meteor lore resource"; - entry.importance_level = 3; - if (get_property_int("_macrometeoriteUses") < 10) - { - int macrometeorite_uses_remaining = clampi(10 - get_property_int("_macrometeoriteUses"), 0, 10); - string [int] description; - description.listAppend("Reroll a monster to another in the area."); - - string [int] useful_places; - if (spleen_limit() > 0 && lookupFamiliar("space jellyfish").familiar_is_usable() && get_property_int("_spaceJellyfishDrops") < 4 && my_path().id != PATH_LIVE_ASCEND_REPEAT) - { - string line = "stench monster area"; - if ($location[Pirates of the Garbage Barges].locationAvailable()) - line += " (garbage pirates)"; - line += " - extract stench jelly repeatedly, with the space jellyfish"; - useful_places.listAppend(line); - } - if (!__quest_state["Level 11 Palindome"].finished && get_property_int("palindomeDudesDefeated") < 5) - useful_places.listAppend("inside the palindome"); - if (!__quest_state["Level 11 Manor"].finished && __quest_state["Level 11 Manor"].mafia_internal_step < 4 && $items[wine bomb, unstable fulminate].available_amount() == 0) - useful_places.listAppend("haunted laundry room / haunted wine cellar"); - useful_places.listAppend("anywhere you olfact and get the wrong monster" + (($item[time-spinner].available_amount() > 0) ? ", unless time-spinning" : "")); - - if (useful_places.count() > 0 && my_path().id != PATH_COMMUNITY_SERVICE) - description.listAppend("Reroll:|*-" + useful_places.listJoinComponents("|*-")); - - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(macrometeorite_uses_remaining, "macrometeorite", "macrometeorites"), "", description)); - } - if (get_property_int("_meteorShowerUses") < 5 && !__misc_state["familiars temporarily blocked"]) - { - int meteor_shower_uses_remaining = clampi(5 - get_property_int("_meteorShowerUses"), 0, 5); - - string [int] description; - description.listAppend("+200% weapon/spell damage, +20 familiar weight, for a single fight."); - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(meteor_shower_uses_remaining, "meteor shower", "meteor showers"), "", description)); - } - if (lookupItem("metal meteoroid").available_amount() > 0 && in_ronin()) - { - string [int] description; - description.listAppend("Craft into useful equipment."); - - string [item] item_descriptions; - item_descriptions[lookupItem("meteorb")] = "spell damage x2, like a lantern"; - item_descriptions[lookupItem("meteorthopedic shoes")] = "+5 adventures/day, +30% init, +15% moxie"; - item_descriptions[lookupItem("asteroid belt")] = "+10 ML, deflects attacks"; - //shooting morning star - 15% muscle tower test - //meteorthopedic shoes - 15% moxie tower test - //meteortarboard - 15% myst tower test - if (!__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "") - { - - stat stat_race_type = __quest_state["Level 13"].state_string["Stat race type"].to_stat(); - if (stat_race_type == $stat[muscle]) - item_descriptions[lookupItem("shooting morning star")] = "+15% muscle for tower test"; - else if (stat_race_type == $stat[mysticality]) - item_descriptions[lookupItem("meteortarboard")] = "+15% myst for tower test"; - } - string [int] items; - foreach it, desc in item_descriptions - { - if (it.available_amount() == 0) - items.listAppend(it + " (" + desc + ")"); - } - if (items.count() > 0) - description.listAppend("Could make " + items.listJoinComponents(", ", "or") + "."); - if (lookupItem("metal meteoroid").item_amount() > 0) - entry.url = "inv_use.php?pwd=" + my_hash() + "&whichitem=9516"; - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(lookupItem("metal meteoroid")), "", description)); - } - - if (entry.subentries.count() > 0) - resource_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Items of the Month/2017/New You.ash b/Source/relay/TourGuide/Items of the Month/2017/New You.ash deleted file mode 100644 index 2e435689..00000000 --- a/Source/relay/TourGuide/Items of the Month/2017/New You.ash +++ /dev/null @@ -1,62 +0,0 @@ -RegisterResourceGenerationFunction("IOTMNewYouGenerateResource"); -void IOTMNewYouGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (__misc_state["in run"] && in_ronin()) - { - string [item] affirmation_effects; - string [item] affirmation_combat_uses; - affirmation_effects[lookupItem("Daily Affirmation: Adapt to Change Eventually")] = "+4 stats/fight, +50% init"; - if (!__misc_state["need to level"]) - affirmation_effects[lookupItem("Daily Affirmation: Adapt to Change Eventually")] = "+50% init"; - affirmation_effects[lookupItem("Daily Affirmation: Always be Collecting")] = "+50% item, +100% meat"; - affirmation_effects[lookupItem("Daily Affirmation: Be a Mind Master")] = "+100% spell damage, 15 MP regen"; - affirmation_effects[lookupItem("Daily Affirmation: Be Superficially interested")] = "-combat / +combat (togglable)"; - affirmation_effects[lookupItem("Daily Affirmation: Keep Free Hate in your Heart")] = "+30 ML"; - affirmation_effects[lookupItem("Daily Affirmation: Think Win-Lose")] = "+50% all stats"; - affirmation_effects[lookupItem("Daily Affirmation: Work For Hours a Week")] = "+5 familiar weight, 15 HP regen"; - if (__misc_state["familiars temporarily blocked"]) - affirmation_effects[lookupItem("Daily Affirmation: Work For Hours a Week")] = "15 HP regen"; - - - affirmation_combat_uses[lookupItem("Daily Affirmation: Adapt to Change Eventually")] = "reroll monster"; //monster change - affirmation_combat_uses[lookupItem("Daily Affirmation: Always be Collecting")] = "duplicate item drops"; - affirmation_combat_uses[lookupItem("Daily Affirmation: Be a Mind Master")] = "banish for 80 turns (not free)"; - if (!__misc_state["have reusable olfaction equivalent"]) - affirmation_combat_uses[lookupItem("Daily Affirmation: Be Superficially interested")] = "olfact weakly"; - if (hippy_stone_broken()) - affirmation_combat_uses[lookupItem("Daily Affirmation: Keep Free Hate in your Heart")] = "gain 3 PVP fights"; - affirmation_combat_uses[lookupItem("Daily Affirmation: Think Win-Lose")] = "instakill"; - affirmation_combat_uses[lookupItem("Daily Affirmation: Work For Hours a Week")] = "earn some meat"; - - ChecklistEntry entry; - foreach it in affirmation_effects - { - if (it.item_amount() == 0) continue; - if (!it.item_is_usable()) continue; - if (!it.to_effect().effect_is_usable()) continue; - if (entry.image_lookup_name == "") - entry.image_lookup_name = "__item " + it; - string combat_text = ""; - if (affirmation_combat_uses[it] != "") - combat_text = "Or throw in combat to " + affirmation_combat_uses[it] + "."; - ChecklistSubentry subentry = ChecklistSubentryMake(pluralise(it), "100 turns, " + affirmation_effects[it], combat_text); - if (it == lookupItem("Daily Affirmation: Think Win-Lose")) - { - resource_entries.listAppend(ChecklistEntryMake("__item " + it, "", subentry).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("New you affirmation win-lose free kill")); - } - else if (it == lookupItem("Daily Affirmation: Be a Mind Master")) - { - resource_entries.listAppend(ChecklistEntryMake("__item " + it, "", subentry, 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("New you affirmation mind master banish")); - } - else - entry.subentries.listAppend(subentry); - } - if (entry.subentries.count() > 0) - { - entry.url = "inventory.php?ftext=daily+affirmation"; - entry.tags.id = "New you affirmation resource"; - entry.importance_level = 6; - resource_entries.listAppend(entry); - } - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2017/Portable Pantogram.ash b/Source/relay/TourGuide/Items of the Month/2017/Portable Pantogram.ash deleted file mode 100644 index 5c00cf58..00000000 --- a/Source/relay/TourGuide/Items of the Month/2017/Portable Pantogram.ash +++ /dev/null @@ -1,69 +0,0 @@ - -RegisterTaskGenerationFunction("IOTMPortablePantogramGenerateTasks"); -void IOTMPortablePantogramGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[lookupItem("portable pantogram")]) return; - if (lookupItem("pantogram pants").available_amount() > 0) return; - - if (my_path().id == PATH_BEES_HATE_YOU) return; - string [int] description; - - - string [int][int] slot_options; - for i from 1 to 5 - slot_options[i] = listMakeBlankString(); - - //Slot 1: muscle, myst, moxie. Tower stat test, then muscle. - if (__misc_state["in run"] && !__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "") - slot_options[1].listAppend(__quest_state["Level 13"].state_string["Stat race type"]); - else if (__misc_state["in run"]) - slot_options[1].listAppend("muscle"); - //Slot 2: Resistance. Cold? Spooky? - if (__misc_state["in run"]) - { - if (my_path().id == PATH_COMMUNITY_SERVICE) - slot_options[2].listAppend("hot resistance"); - else if (!__quest_state["Level 9"].state_boolean["bridge complete"]) - slot_options[2].listAppend("sleaze resistance"); //bridge building - else - slot_options[2].listAppend("spooky resistance"); //a-boo peak, and slightly more useful than cold resistance - } - //Slot 3: drops of blood (+40 HP). -3 MP to use skills is nice, I guess? but it takes a baconstone - if (__misc_state["in run"]) - slot_options[3].listAppend("drops of blood (+40 HP)"); - if ($item[baconstone].available_amount() > 0 && __misc_state["in run"]) - slot_options[3].listAppend("baconstone (-3 MP to use skills)"); - //Slot 4: - if ($item[taco shell].npc_price() > 0) - slot_options[4].listAppend("taco shell (+30% meat)"); - if (($item[porquoise].npc_price() > 0 && __misc_state["in run"]) || can_interact()) - slot_options[4].listAppend("porquoise (+60% meat)"); - if (my_path().id == PATH_COMMUNITY_SERVICE) - { - slot_options[4].listAppend("your hopes (+20 weapon damage)"); - slot_options[4].listAppend("your dreams (+20% spell damage)"); - } - if (__misc_state["in run"]) - { - } - else - { - slot_options[4].listAppend("tiny dancer (+30% item)"); - } - //slot_options[4].listAppend("???"); - //Slot 5: - slot_options[5].listAppend("some self-respect (-combat)"); - if (my_path().id != PATH_COMMUNITY_SERVICE) - slot_options[5].listAppend("some self-control (+combat)"); - if (!__misc_state["in run"]) - slot_options[5].listAppend("ten-leaf clover (hilarious items)"); - if ($item[bar skin].available_amount() > 0 && __misc_state["in run"]) - slot_options[5].listAppend("bar skin (+50% init)"); - - foreach slot_id in slot_options - { - if (slot_options[slot_id].count() == 0) continue; - description.listAppend(slot_options[slot_id].listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); - } - optional_task_entries.listAppend(ChecklistEntryMake("__item portable pantogram", "inv_use.php?pwd=" + my_hash() + "&whichitem=9573", ChecklistSubentryMake("Summon pants", "", description), 1).ChecklistEntrySetIDTag("Portable pantogram summon")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2017/Space Jellyfish.ash b/Source/relay/TourGuide/Items of the Month/2017/Space Jellyfish.ash deleted file mode 100644 index 3c117d7e..00000000 --- a/Source/relay/TourGuide/Items of the Month/2017/Space Jellyfish.ash +++ /dev/null @@ -1,121 +0,0 @@ - -RegisterTaskGenerationFunction("IOTMSpaceJellyfishGenerateTasks"); -void IOTMSpaceJellyfishGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!$familiar[space jellyfish].familiar_is_usable()) - return; - if (!get_property_boolean("_seaJellyHarvested") && my_level() >= 11 && !__misc_state["sea access blocked"]) - { - string url = "place.php?whichplace=thesea&action=thesea_left2"; - string [int] description; - if (!QuestState("questS01OldGuy").started) - { - url = "oldman.php"; - description.listAppend("Visit the old man first."); - } - else if (my_familiar() != $familiar[space jellyfish]) - { - url = "familiar.php"; - description.listAppend("Bring along your space jellyfish first."); - } - description.listAppend("Once/day."); - optional_task_entries.listAppend(ChecklistEntryMake("__familiar space jellyfish", url, ChecklistSubentryMake("Harvest sea jelly", "", description)).ChecklistEntrySetIDTag("Space jellyfish sea jelly harvest")); - } -} - - -RegisterResourceGenerationFunction("IOTMSpaceJellyfishGenerateResource"); -void IOTMSpaceJellyfishGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!$familiar[space jellyfish].familiar_is_usable()) - return; - - ChecklistEntry entry; - entry.url = ""; - entry.image_lookup_name = "__familiar space jellyfish"; - entry.tags.id = "Space jellyfish jelly extraction resource"; - entry.importance_level = 5; - - //_spaceJellyfishDrops - //_hotJellyUses - if (my_familiar() != $familiar[space jellyfish]) - { - entry.url = "familiar.php"; - } - - int [int] percent_chance_at_use = { - 0:100, - 1:50, - 2:33, - 3:25, - 4:20, - 5:5, - 6:5, - 7:5, - 8:5, - 9:5, - 10:5, - 11:5, - 12:5, - 13:5, - 14:5, - }; - //FIXME spade rest - - if (__misc_state["in run"] && spleen_limit() > 0) - { - /* - hot - free run/banish - spooky - YR with no cooldown - stench - clara's bell, more or less - - The other two aren't too useful in-run. - */ - if (get_property_int("_hotJellyUses") > 0) - { - resource_entries.listAppend(ChecklistEntryMake("__item hot jelly", "", ChecklistSubentryMake(pluralise(get_property_int("_hotJellyUses"), "breathe out", "breathe outs"), "", "Cast Breathe Out. Free run/banish.")).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Space jellyfish breathe out banish")); - } - - string [item] jelly_descriptions; - //jelly_descriptions[$item[hot jelly]] = "Free run/banish."; - jelly_descriptions[$item[spooky jelly]] = "YR with no cooldown."; - jelly_descriptions[$item[stench jelly]] = "Forces non-combat."; - foreach it, desc in jelly_descriptions - { - if (it.available_amount() > 0 && in_ronin()) - { - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", desc)); - } - } - - if ($item[hot jelly].available_amount() > 0 && in_ronin()) - resource_entries.listAppend(ChecklistEntryMake("__item hot jelly", "", ChecklistSubentryMake(pluralise($item[hot jelly]), "", "Chew for free run/banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Space jellyfish hot jelly banish")); - - - - int extractions = get_property_int("_spaceJellyfishDrops"); - string [int] description; - string line = "Extract jelly against elemental monsters."; - if (percent_chance_at_use contains extractions) - line += "|" + percent_chance_at_use[extractions] + "% chance of success."; - - //Should we list common areas to find these? - //Spooky is defiled alcove. Hot is the level six quest. Stench is level twelve, i.e. level never before you need it. - line += "|*" + HTMLGenerateSpanOfClass("Stench", "r_bold r_element_stench_desaturated") + " - forces non-combat"; - if (!__quest_state["Level 12"].finished) - line += " (try hippies)"; - line += "|*" + HTMLGenerateSpanOfClass("Spooky", "r_bold r_element_spooky_desaturated") + " - YR with no cooldown"; - if (!__quest_state["Level 7"].finished) - line += " (try cyrpt)"; - line += "|*" + HTMLGenerateSpanOfClass("Hot", "r_bold r_element_hot_desaturated") + " - free run/banish"; - if (!__quest_state["Level 12"].finished) - line += " (try friars)"; - description.listAppend(line); - if (availableDrunkenness() >= 0) - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(extractions, "jelly extraction", "jelly extractions"), "", description)); - } - - - if (entry.subentries.count() > 0) - resource_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Items of the Month/2017/Spacegate.ash b/Source/relay/TourGuide/Items of the Month/2017/Spacegate.ash deleted file mode 100644 index 25a8f403..00000000 --- a/Source/relay/TourGuide/Items of the Month/2017/Spacegate.ash +++ /dev/null @@ -1,56 +0,0 @@ -//Spacegate -RegisterTaskGenerationFunction("IOTMSpacegateGenerateTasks"); -void IOTMSpacegateGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[lookupItem("Spacegate access badge")]) - return; - string [int] description; - string url = "place.php?whichplace=spacegate"; - { - int SpacegateTimer = get_property_int("_spacegateTurnsLeft"); - description.listAppend("Plan " + get_property("_spacegateCoordinates") + " from Outer Space"); - - if (SpacegateTimer > 0 && __last_adventure_location == $location[through the spacegate]) { - task_entries.listAppend(ChecklistEntryMake("__item portable spacegate", url, ChecklistSubentryMake(SpacegateTimer + " Spacegate turns remaining", "", description), -11)); - } - } -} - -RegisterResourceGenerationFunction("IOTMSpacegateGenerateResource"); -void IOTMSpacegateGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[lookupItem("Spacegate access badge")]) - return; - if (!get_property_boolean("_spacegateVaccine") && my_path().id != PATH_G_LOVER) - { - boolean rainbow_unlocked = get_property_boolean("spacegateVaccine1"); //+3 all res - boolean broad_spectrum_unlocked = get_property_boolean("spacegateVaccine2"); //+50% all stats - boolean emotional_unlocked = get_property_boolean("spacegateVaccine3"); //+30 ML - - string [int] options; - if (emotional_unlocked) - options.listAppend("+30 ML"); - if (broad_spectrum_unlocked) - options.listAppend("+50% stats"); - if (rainbow_unlocked) - options.listAppend("+3 all res"); - - boolean missing_one = !rainbow_unlocked || !broad_spectrum_unlocked || !emotional_unlocked; - if (missing_one && lookupItem("spacegate research").available_amount() > 0) - options.listAppend("unlock additional vaccines"); - if (options.count() > 0) - { - string [int] description; - description.listAppend("30 turns, once/day.|" + options.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); - - resource_entries.listAppend(ChecklistEntryMake("__item plus sign", "place.php?whichplace=spacegate&action=sg_vaccinator", ChecklistSubentryMake("Vaccination", "", description), 8).ChecklistEntrySetIDTag("Spacegate daily vaccine resource")); - } - } - if (__misc_state["in run"] && my_primestat() == $stat[moxie] && __misc_state["need to level"] && get_property("_spacegatePlanetName") == "") - { - //Dial TFHSXKK: - string [int] description; - description.listAppend("Dial TFHSXKK, and skip every adventure until you reach Paradise Under a Strange Sun.|Will give 1000 stats and cost a turn. Not strictly optimal."); - resource_entries.listAppend(ChecklistEntryMake("__item portable spacegate", "place.php?whichplace=spacegate&action=sg_Terminal", ChecklistSubentryMake("Spacegate dial", "", description), 8).ChecklistEntrySetIDTag("Spacegate moxie boost trick")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2017/Tunnel of Love.ash b/Source/relay/TourGuide/Items of the Month/2017/Tunnel of Love.ash deleted file mode 100644 index 850c45fe..00000000 --- a/Source/relay/TourGuide/Items of the Month/2017/Tunnel of Love.ash +++ /dev/null @@ -1,71 +0,0 @@ -RegisterTaskGenerationFunction("IOTMTunnelOfLoveGenerateTasks"); -void IOTMTunnelOfLoveGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //FIXME whatever these end up being named: - if (!mafiaIsPastRevision(17805)) - return; - if (!__iotms_usable[lookupItem("heart-shaped crate")]) - return; - if (get_property_boolean("_loveTunnelUsed")) - return; - - string [int] description; - //equipment: LOV Eardigan (+25% muscle exp, +25 ML), LOV Epaulettes (+25% myst exp), LOV Earrings (+25% moxie exp, +50% meat, +3 all res) - //50-turn buffs: Lovebotamy (10 stats/fight), Open Heart Surgery (+10 familiar weight), Wandering Eye Surgery (+50% item) - //item: boomerang (arrow), toy dart gun (???), chocolate (adventures), flowers (???), elephant (???), TOAST! (toasty!) - - description.listAppend("Three free fights. Attack, spell, and pickpocket respectively for elixirs."); - if (my_path().id == PATH_GELATINOUS_NOOB) - description.listAppend("Equipment choice unimportant."); - else - { - string [int] equipment_choices; - equipment_choices.listAppend(HTMLBoldIfTrue("Eardigan", my_primestat() == $stat[muscle] && __misc_state["in run"] && my_level() < 13) + " (+25% muscle exp, +25 ML)"); - if (my_path().id != PATH_G_LOVER) - equipment_choices.listAppend(HTMLBoldIfTrue("Epaulettes", my_primestat() == $stat[mysticality] && __misc_state["in run"] && my_level() < 13) + " (+25% myst exp)"); - equipment_choices.listAppend(HTMLBoldIfTrue("Earrings", (my_primestat() == $stat[moxie] && __misc_state["in run"] && my_level() < 13) || __misc_state["in aftercore"] || my_level() >= 13) + " (+25% moxie exp, +50% meat, +3 all res)"); - description.listAppend("Equipment choice:|*" + equipment_choices.listJoinComponents(", ", "or")); - } - string [int] buff_choices; - if (my_path().id != PATH_G_LOVER) - buff_choices.listAppend("+10 stats/fight"); - buff_choices.listAppend("+10 familiar weight"); - buff_choices.listAppend("+50% item"); - description.listAppend("Buff choice: (50 turns)|*" + buff_choices.listJoinComponents(", ", "or")); - - string [int] usable_items; - if (my_path().id != PATH_LIVE_ASCEND_REPEAT) - usable_items.listAppend("single-use wandering copier"); - usable_items.listAppend("chat hearts"); - if (my_path().id != PATH_SLOW_AND_STEADY && my_path().id != PATH_G_LOVER) - usable_items.listAppend("chocolate (adventures)"); - if ($familiar[space jellyfish].familiar_is_usable()) - usable_items.listAppend("toast"); - description.listAppend("Item choice:|*" + usable_items.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); - - optional_task_entries.listAppend(ChecklistEntryMake("__item pink candy heart", "place.php?whichplace=town_wrong", ChecklistSubentryMake("Take a love trip", "", description)).ChecklistEntrySetIDTag("Love tunnel daily trip")); -} - -RegisterResourceGenerationFunction("IOTMTunnelOfLoveGenerateResource"); -void IOTMTunnelOfLoveGenerateResource(ChecklistEntry [int] resource_entries) -{ - //mostly the boomerang - //what does sokka throw? a boomeraang! - - if (__misc_state["in run"] && in_ronin()) - { - /*item enamorang = $item[LOV Enamorang]; - if (enamorang.available_amount() > 0) - { - resource_entries.listAppend(ChecklistEntryMake("__item LOV Enamorang", "", ChecklistSubentryMake(pluralise(enamorang), "", "Copies the monster once as an arrow."), 5).ChecklistEntrySetIDTag("Love tunnel LOV enamorang")); - - }*/ - item chocolate = lookupItem("LOV Extraterrestrial Chocolate"); - if (chocolate.available_amount() > 0 && $item[LOV Extraterrestrial Chocolate].item_is_usable()) - { - //FIXME list other chocolates? - resource_entries.listAppend(ChecklistEntryMake("__item LOV Extraterrestrial Chocolate", "", ChecklistSubentryMake(pluralise(chocolate), "", "Adventures!"), 5).ChecklistEntrySetIDTag("Love tunnel chocolates resource")); - - } - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2017/XO Skeleton.ash b/Source/relay/TourGuide/Items of the Month/2017/XO Skeleton.ash deleted file mode 100644 index 5247d664..00000000 --- a/Source/relay/TourGuide/Items of the Month/2017/XO Skeleton.ash +++ /dev/null @@ -1,93 +0,0 @@ - -RegisterResourceGenerationFunction("IOTMXOSkeletonGenerateResource"); -void IOTMXOSkeletonGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("XO Skeleton").familiar_is_usable()) return; - - - - int hugs_remaining = clampi(11 - get_property_int("_xoHugsUsed"), 0, 11); - - ChecklistEntry entry; - entry.image_lookup_name = "__familiar xo skeleton"; - entry.tags.id = "XO skeleton familiar resource"; - entry.importance_level = 3; - if (my_familiar() != lookupFamiliar("XO Skeleton")) - entry.url = "familiar.php"; - - - if ((my_familiar() == lookupFamiliar("XO Skeleton") || __misc_state["in run"]) && hugs_remaining > 0) - { - string [int] description; - description.listAppend("Instantly v-pocket an item."); - if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) - { - string [int] options; - if (!__quest_state["Level 12"].finished && get_property("sidequestOrchardCompleted") == "none" && !($effect[Filthworm Guard Stench].have_effect() > 0 || $item[Filthworm royal guard scent gland].available_amount() > 0)) - options.listAppend("filthworms"); - if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && !QuestState("questM20Necklace").finished) - options.listAppend("banshee librarian (killing jar)"); - if (get_property_int("hiddenApartmentProgress") < 7 || get_property_int("hiddenOfficeProgress") < 7) - options.listAppend("pygmy witch lawyer (short writs)"); - if (!have_outfit_components("Swashbuckling Getup") && __quest_state["Pirate Quest"].state_boolean["valid"]) - options.listAppend("obligatory pirate's cove (outfit)"); - if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] >= 90) - options.listAppend("Whatsian Commando Ghost (ghost free runaway)"); - if (options.count() > 0) - description.listAppend(options.listJoinComponents(", ").capitaliseFirstLetter() + ", etc."); - } - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(hugs_remaining, "hug", "hugs"), "", description)); - } - - if (__misc_state["in run"] && in_ronin()) - { - int xes = lookupItem("9543").available_amount(); - int os = lookupItem("9544").available_amount(); - - //two Os: pair of candy glasses (10 adventures of +50% item) - //Hide-rox™ cookie: 3 os, 1-size food, myst tower test - //jug of booze: 3 xes, 1-size booze, moxie tower test - //glyph of athleticism: 5 Os, 1-size spleen, muscle tower test - //bridge truss: 23 xes, 15 bridge progress, takes forever to acquire - - string header; - string [int] description; - if (xes > 0) - header += pluralise(xes, "X", "Xes"); - if (os > 0) - { - if (header != "") - header += ", "; - header += pluralise(os, "O", "Os"); - } - - boolean [string] options; - - options["pair of candy glasses: +50% item (10 turns)"] = (os >= 2); - if (!__quest_state["Level 9"].state_boolean["bridge complete"] && my_path().id != PATH_COMMUNITY_SERVICE) - { - int turns_left = (23 - xes) * 9 - get_property_int("xoSkeleltonXProgress"); - string line = "bridge truss: half a bridge"; - if (turns_left > 0) - line += ", " + pluralise(turns_left, "combat", "combats") + " to get"; - options[line] = (xes >= 23); - } - if (!__quest_state["Level 13"].state_boolean["Stat race completed"]) - { - stat stat_race_type = __quest_state["Level 13"].state_string["Stat race type"].to_stat(); - //if (stat_race_type == $stat[muscle]) - } - foreach option, available in options - { - string line = option; - if (!available) - line = HTMLGenerateSpanFont(line, "gray"); - description.listAppend(line); - } - - entry.subentries.listAppend(ChecklistSubentryMake(header, "", description)); - } - - if (entry.subentries.count() > 0) - resource_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Items of the Month/2018/Bastille Battalion.ash b/Source/relay/TourGuide/Items of the Month/2018/Bastille Battalion.ash deleted file mode 100644 index dffab546..00000000 --- a/Source/relay/TourGuide/Items of the Month/2018/Bastille Battalion.ash +++ /dev/null @@ -1,80 +0,0 @@ - - -RegisterTaskGenerationFunction("IOTMBastilleBattalionGenerateTasks"); -void IOTMBastilleBattalionGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (lookupItem("Bastille Battalion control rig").available_amount() == 0 || my_sign().to_lower_case() == "bad moon") return; - - if (lookupItem("Draftsman's driving gloves").available_amount() > 0 || lookupItem("Nouveau nosering").available_amount() > 0 || lookupItem("Brutal brogues").available_amount() > 0) return; - - string [int] description; - string url = "inv_use.php?pwd=" + my_hash() + "&whichitem=9928"; - - //FIXME suggest the right configuration - if (lookupItem("Bastille Battalion control rig").storage_amount() > 0) - { - url = "storage.php?which=3"; - description.listAppend("Free pull from Hagnk's."); - } - //FIXME in the future, we might want to suggest options for them. We haven't, because it's a lot of space, especially the equipment. - string [int] suggested_configuration; - if (__misc_state["need to level"]) - { - int stats_gained = ceil(250 * (1.0 + numeric_modifier(my_primestat() + " experience percent") / 100.0)); - if (my_primestat() == $stat[muscle]) - { - description.listAppend(HTMLGenerateSpanOfClass("Babar", "r_bold") + ": " + stats_gained + " muscle stats."); - suggested_configuration.listAppend("Babar"); - } - else if (my_primestat() == $stat[mysticality]) - { - description.listAppend(HTMLGenerateSpanOfClass("Barbarian Barbecue", "r_bold") + ": " + stats_gained + " mysticality stats."); - suggested_configuration.listAppend("Barbarian Barbecue"); - } - else if (my_primestat() == $stat[moxie]) - { - description.listAppend(HTMLGenerateSpanOfClass("Barbershop", "r_bold") + ": " + stats_gained + " moxie stats."); - suggested_configuration.listAppend("Barbershop"); - } - } - string [int] accessories; - accessories.listAppend(HTMLGenerateSpanOfClass("Accessory:", "r_bold")); - accessories.listAppend(HTMLGenerateSpanOfClass("Brutalist", "r_bold") + ": +50% muscle, +50% weapon damage, +8 familiar weight, +4 muscle stats/fight."); - accessories.listAppend(HTMLGenerateSpanOfClass("Draftsman", "r_bold") + ": +50% myst, +50% spell damage, +8 adventures/day, +4 myst stats/fight."); - accessories.listAppend(HTMLGenerateSpanOfClass("Art Nouveau", "r_bold") + ": +50% moxie, +25% item, +25 HP/MP, +4 moxie stats/fight."); - description.listAppend(accessories.listJoinComponents("|*")); - - string [int] buffs; - buffs.listAppend(HTMLGenerateSpanOfClass("Buff:", "r_bold") + " (100 turns)"); - buffs.listAppend(HTMLGenerateSpanOfClass("Cannon", "r_bold") + ": +25 muscle, +10% critical hit, ~15 HP/adventure."); - buffs.listAppend(HTMLGenerateSpanOfClass("Catapult", "r_bold") + ": +25 myst, +10% spell critical hit, ~7.5 MP/adventure."); - buffs.listAppend(HTMLGenerateSpanOfClass("Gesture", "r_bold") + ": +25 moxie, +25% init, +25% meat."); - description.listAppend(buffs.listJoinComponents("|*")); - - if (!in_ronin()) - { - //+adventures in aftercore - suggested_configuration.listAppend("Draftsman"); - } - else if (my_primestat() == $stat[muscle]) - { - suggested_configuration.listAppend("Brutalist"); - } - else if (my_primestat() == $stat[mysticality]) - { - suggested_configuration.listAppend("Draftsman"); - } - else if (my_primestat() == $stat[moxie]) - { - suggested_configuration.listAppend("Art Nouveau"); - } - - if (!in_ronin()) - suggested_configuration.listAppend("Gesture"); - else - suggested_configuration.listAppend("Catapult"); - - description.listAppend("Suggested configuration: " + HTMLGenerateSpanOfClass(suggested_configuration.listJoinComponents(" / "), "r_bold") + "."); - - optional_task_entries.listAppend(ChecklistEntryMake("__item Bastille Battalion control rig", url, ChecklistSubentryMake("Collect Bastille rewards", "", description), 8).ChecklistEntrySetIDTag("Bastille Battalion daily")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2018/BoomBox.ash b/Source/relay/TourGuide/Items of the Month/2018/BoomBox.ash deleted file mode 100644 index b8759259..00000000 --- a/Source/relay/TourGuide/Items of the Month/2018/BoomBox.ash +++ /dev/null @@ -1,42 +0,0 @@ -//Songboom -RegisterTaskGenerationFunction("IOTMBoomBoxGenerateTasks"); -void IOTMBoomBoxGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (lookupItem("SongBoom™ BoomBox").available_amount() == 0) return; - - - string song = get_property("boomBoxSong"); - int changes_left = get_property_int("_boomBoxSongsLeft"); //the boys are back in town, eleven times. everyone will love it - - int boomboxProgress = get_property_int("_boomBoxFights"); - string [int] description; - { - description.listAppend("Now playing: " + HTMLGenerateSpanOfClass(song, "r_bold")); //+ " (" + changes_left + " song swaps today)"); - if (boomboxProgress < 9) - { - description.listAppend((11 - boomboxProgress).pluralise("combat", "combats") + " until next drop."); - optional_task_entries.listAppend(ChecklistEntryMake("__item SongBoom™ BoomBox", "inv_use.php?pwd=" + my_hash() + "&whichitem=9919", ChecklistSubentryMake("Boombox song stuff", "", description), 8)); - } - if (boomboxProgress == 9) - { - task_entries.listAppend(ChecklistEntryMake("__item SongBoom™ BoomBox", "inv_use.php?pwd=" + my_hash() + "&whichitem=9919", ChecklistSubentryMake("Boombox drop in 2 fights", "", description), -11)); - } - - if (boomboxProgress == 10) - { - task_entries.listAppend(ChecklistEntryMake("__item SongBoom™ BoomBox", "inv_use.php?pwd=" + my_hash() + "&whichitem=9919", ChecklistSubentryMake("Boombox drop this fight", "", description), -11)); - } - } - - if (song == "" && changes_left > 0) - { - string [int] description; - if (!__quest_state["Level 7"].finished && my_path().id != PATH_COMMUNITY_SERVICE) - description.listAppend("Eye of the Giger: Nightmare Fuel for the cyrpt."); - if (fullness_limit() > 0) - description.listAppend("Food Vibrations: extra adventures from food" + (__misc_state["in run"] ? ", +30% food drop" : "") + "."); - description.listAppend("Total Eclipse of Your Meat: extra meat, +30% meat."); - - optional_task_entries.listAppend(ChecklistEntryMake("__item SongBoom™ BoomBox", "inv_use.php?pwd=" + my_hash() + "&whichitem=9919", ChecklistSubentryMake("Set BoomBox song", "", description), 8).ChecklistEntrySetIDTag("SongBoom BoomBox turn on")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2018/Boxing Daycare.ash b/Source/relay/TourGuide/Items of the Month/2018/Boxing Daycare.ash deleted file mode 100644 index b03892ca..00000000 --- a/Source/relay/TourGuide/Items of the Month/2018/Boxing Daycare.ash +++ /dev/null @@ -1,82 +0,0 @@ -RegisterTaskGenerationFunction("IOTMBoxingDaycareGenerateTasks"); -void IOTMBoxingDaycareGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[lookupItem("Boxing Day care package")]) return; - //collect nap consumable - ChecklistEntry entry; - entry.url = "place.php?whichplace=town_wrong&action=townwrong_boxingdaycare"; - entry.image_lookup_name = "__item orange boxing gloves"; - entry.tags.id = "Boxing daycare daily tasks"; - entry.importance_level = 8; - if (!get_property_boolean("_daycareNap")) - { - entry.subentries.listAppend(ChecklistSubentryMake("Take a daycare nap", "", "Gives a consumable.")); - } - //scavenge once - if (get_property_int("_daycareGymScavenges") == 0 && __misc_state["need to level"]) - { - entry.subentries.listAppend(ChecklistSubentryMake("Scavenge for daycare equipment", "", "Statgain.")); - } - else if (get_property_int("_daycareRecruits") < 1 && __misc_state["in run"] && $skill[Army of Toddlers].skill_is_usable() && __misc_state["need to level"] && my_meat() >= 100) - { - entry.subentries.listAppend(ChecklistSubentryMake("Recruit at the boxing daycare?", "", "100 meat, benefits army of toddlers statgain.")); - } - if (entry.subentries.count() > 0) - { - optional_task_entries.listAppend(entry); - } -} - -RegisterResourceGenerationFunction("IOTMBoxingDaycareGenerateResource"); -void IOTMBoxingDaycareGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[lookupItem("Boxing Day care package")]) return; - //buffs - if (!get_property_boolean("_daycareSpa")) - { - string [int] description; - if (in_ronin() && my_path().id != PATH_G_LOVER) - { - description.listAppend("+200% muscle, +15 ML"); - description.listAppend("+200% moxie, +50% init"); - description.listAppend("+200% myst, +25% item"); - description.listAppend("+100 HP, +50 MP, +25 DR, +~8 MP regen, +~15 HP regen"); - } - else if (in_ronin() && my_path().id == PATH_G_LOVER) - description.listAppend("+100 HP, +50 MP, +25 DR, +~8 MP regen, +~15 HP regen"); - else - description.listAppend("+200% myst, +25% item"); - resource_entries.listAppend(ChecklistEntryMake("__item orange boxing gloves", "place.php?whichplace=town_wrong&action=townwrong_boxingdaycare", ChecklistSubentryMake("Boxing daycare buff (100 turns)", description), 5).ChecklistEntrySetCombinationTag("boxing daycare resources").ChecklistEntrySetIDTag("Boxing daycare daily spa")); - } - if (hippy_stone_broken() && !get_property_boolean("_daycareFights") && !__misc_state["in run"]) - { - string [int] description; - description.listAppend("Costs one adventure. Spar."); - if (get_property_int("daycareToddlers") <= 2) - description.listAppend("Should recruit first."); - resource_entries.listAppend(ChecklistEntryMake("__item orange boxing gloves", "place.php?whichplace=town_wrong&action=townwrong_boxingdaycare", ChecklistSubentryMake("Boxing daycare PVP fights", description), 5).ChecklistEntrySetCombinationTag("boxing daycare resources").ChecklistEntrySetIDTag("Boxing daycare daily spar")); - - } - if (__misc_state["in run"] && $skill[Army of Toddlers].skill_is_usable() && !get_property_boolean("_armyToddlerCast") && __misc_state["need to level"]) - { - string [int] description; - //is this mainstat or what - float total_statgain = sqrt(get_property_int("daycareToddlers"));// * (1.0 + numeric_modifier(my_primestat() + " experience percent") / 100.0); - float [stat] split_statgain = {$stat[muscle]:total_statgain * 0.25, $stat[mysticality]:total_statgain * 0.25, $stat[moxie]:total_statgain * 0.25}; - split_statgain[my_primestat()] = total_statgain * 0.5; - foreach s, v in split_statgain - { - split_statgain[s] = v * (1.0 + numeric_modifier(s + " experience percent") / 100.0); - } - string [int] stats_out; - stats_out.listAppend(split_statgain[$stat[muscle]].roundForOutput(0)); - stats_out.listAppend(split_statgain[$stat[mysticality]].roundForOutput(0)); - stats_out.listAppend(split_statgain[$stat[moxie]].roundForOutput(0)); - - description.listAppend("50 MP, gain " + stats_out.listJoinComponents(" / ") + " stats."); - if (split_statgain[my_primestat()] < 3.0 || get_property_int("daycareToddlers") <= 2) - description.listAppend("Might want to recruit first."); - resource_entries.listAppend(ChecklistEntryMake("__skill Army of Toddlers", "", ChecklistSubentryMake("Army of Toddlers castable", description), 5).ChecklistEntrySetCombinationTag("boxing daycare resources").ChecklistEntrySetIDTag("Boxing daycare toddler army")); - - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2018/Cat Burglar.ash b/Source/relay/TourGuide/Items of the Month/2018/Cat Burglar.ash deleted file mode 100644 index c2996ce8..00000000 --- a/Source/relay/TourGuide/Items of the Month/2018/Cat Burglar.ash +++ /dev/null @@ -1,81 +0,0 @@ -RegisterResourceGenerationFunction("IOTMCatBurglarGenerateResource"); -void IOTMCatBurglarGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("cat burglar").familiar_is_usable()) return; - - int charges_left = CatBurglarChargesLeftToday(); - int burglar_progress = (get_property_int("_catBurglarCharge")); - if (charges_left > 0) - { - string [int] description; - string url = "familiar.php"; - if (my_familiar() == lookupFamiliar("cat burglar")) - url = "main.php?heist=1"; - //√rusty hedge trimmers - //√bowling ball - //cigarette lighter, if they're doing zeppelin - //scent glands, but only if they don't xoxoxoxo - //√green smoke bomb - //There are also certainly even more options. - description.listAppend("Obtains one item from a recent fight."); - if (burglar_progress >= 150) - description.listAppend("" + burglar_progress + "/310 charges today for 5th heist."); - else if (burglar_progress >= 70) - description.listAppend("" + burglar_progress + "/150 charges today for 4th heist."); - else if (burglar_progress >= 30) - description.listAppend("" + burglar_progress + "/70 charges today for 3rd heist."); - else if (burglar_progress >= 10) - description.listAppend("" + burglar_progress + "/30 charges today for 2nd heist."); - else if (burglar_progress >= 0) - description.listAppend("" + burglar_progress + "/10 charges today for 1st heist."); - - string [int] options; - if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) { - int bowling_progress = get_property_int("hiddenBowlingAlleyProgress"); - if (bowling_progress < 7) { - int balls_needed = 6 - bowling_progress - $item[bowling ball].available_amount(); - if (balls_needed > 0) - options.listAppend("Bowling ball, from the hidden bowling alley."); - } - if (get_property_int("twinPeakProgress") != 15 && $item[rusty hedge trimmers].available_amount() < __quest_state["Level 9"].state_int["peak tests remaining"]) { - options.listAppend("Rusty hedge trimmers, from the twin peak."); - } - if (!__quest_state["Level 12"].finished && get_property("sidequestOrchardCompleted") == "none") { - options.listAppend("Green smoke bomb, from the war."); - if (!lookupFamiliar("XO Skeleton").familiar_is_usable()) - options.listAppend("Scent glands, from the filthworms quest."); - } - if (get_property_int("zeppelinProtestors") < 80 && QuestState("questL11Ron").mafia_internal_step < 3) { - options.listAppend("Cigarette lighters, from the zeppelin protesters."); - } - if ($item[pirate fledges].available_amount() == 0 && !have_outfit_components("Swashbuckling Getup") && __quest_state["Pirate Quest"].state_boolean["valid"]) { - options.listAppend("Pirate outfit."); - } - - if ($item[S.O.C.K.].available_amount() == 0) { - string [int] airship_stealables; - foreach it in $items[mohawk wig,amulet of extreme plot significance] { - if (it.available_amount() == 0) { - if (it == $item[mohawk wig] && lookupSkill("Comprehensive Cartography").skill_is_usable() && $item[model airship].available_amount() >= 1) { - //mohawk wig not needed with a model airship and Cartography - } - else - airship_stealables.listAppend(it); - } - } - if (airship_stealables.count() > 0) - options.listAppend(airship_stealables.listJoinComponents(", ", "and").capitaliseFirstLetter() + ", from the airship."); - } - if (__quest_state["Level 4"].state_int["areas unlocked"] + $item[sonar-in-a-biscuit].available_amount() < 3) - options.listAppend("Sonar-in-a-biscuit, from the bat hole."); - if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && !__quest_state["Level 11 Desert"].state_boolean["Killing Jar Given"] && $item[killing jar].available_amount() == 0) // && !($location[The Haunted Gallery].locationAvailable() && !$location[The Haunted Library].locationAvailable()) //that was from when you could use copied/wished writing desks to skip the library... - options.listAppend("Killing jar, from the haunted library."); - if (!have_outfit_components("Knob Goblin Elite Guard Uniform") && !have_outfit_components("Knob Goblin Harem Girl Disguise") && !__quest_state["Level 5"].finished) - options.listAppend("Harem girl outfit, if you can't reach +400% item."); - } - if (options.count() > 0) - description.listAppend("Could steal:|*-" + options.listJoinComponents("|*-")); - - resource_entries.listAppend(ChecklistEntryMake("__familiar Cat Burglar", url, ChecklistSubentryMake(pluralise(charges_left, "heist", "heists"), "", description), 1).ChecklistEntrySetIDTag("Cat burglar resource")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2018/Garbage Tote.ash b/Source/relay/TourGuide/Items of the Month/2018/Garbage Tote.ash deleted file mode 100644 index d7a8f3e8..00000000 --- a/Source/relay/TourGuide/Items of the Month/2018/Garbage Tote.ash +++ /dev/null @@ -1,98 +0,0 @@ - -RegisterTaskGenerationFunction("IOTMGarbageToteGenerateTasks"); -void IOTMGarbageToteGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[$item[January's Garbage Tote]]) return; - boolean [item] relevant_items; - if (get_property_int("garbageTreeCharge") > 0) - relevant_items[lookupItem("deceased crimbo tree")] = true; - if (get_property_int("garbageShirtCharge") > 0 && __misc_state["Torso aware"]) - relevant_items[lookupItem("makeshift garbage shirt")] = true; - if (get_property_int("garbageChampagneCharge") > 0) - relevant_items[lookupItem("broken champagne bottle")] = true; - relevant_items[lookupItem("tinsel tights")] = true; - relevant_items[lookupItem("wad of used tape")] = true; - if (relevant_items.available_amount() == 0) { - string [int] description; - if (my_level() < 13 && get_property_int("garbageShirtCharge") > 0 && __misc_state["Torso aware"]) { - description.listAppend("Makeshift garbage shirt (double statgain for " + pluralise(get_property_int("garbageShirtCharge"), "more turn", "more turns") + ".)"); - } - else if (my_level() < 13) - description.listAppend("Tinsel tights (+25 ML)"); - description.listAppend("Wad of used tape (+15% item, +30% meat)"); - if (get_property_int("garbageChampagneCharge") > 0) - description.listAppend("Broken champagne bottle (double +item for " + pluralise(get_property_int("garbageChampagneCharge"), "more turn", "more turns") + ".)"); - - // Use the right item ID depending on if you are using a replica or a non-replica - string activeToteID = lookupItem("replica January's Garbage Tote").available_amount() > 0 ? "11238" : "9690"; - - optional_task_entries.listAppend(ChecklistEntryMake("__item January's Garbage Tote", "inv_use.php?pwd=" + my_hash() + "&whichitem=" + activeToteID, ChecklistSubentryMake("Collect a garbage tote item", "", description), 1).ChecklistEntrySetIDTag("Garbage tote should switch item")); - } -} - - -RegisterResourceGenerationFunction("IOTMGarbageToteGenerateResource"); -void IOTMGarbageToteGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (lookupItem("January's Garbage Tote").available_amount() == 0) return; - //_garbageShirtCharge from 37 to 0 - //_garbageChampagneCharge from 11 to 0 - //_garbageTreeCharge from 1000 to 0 - - string [item] item_charge_property; - string [item] item_effect_description; - int [item] item_charge_default; - - if (__misc_state["Torso aware"]) { - item_charge_property[lookupItem("makeshift garbage shirt")] = "garbageShirtCharge"; - item_effect_description[lookupItem("makeshift garbage shirt")] = "Doubles statgain"; - item_charge_default[lookupItem("makeshift garbage shirt")] = 37; - } - - item_charge_property[lookupItem("broken champagne bottle")] = "garbageChampagneCharge"; - item_effect_description[lookupItem("broken champagne bottle")] = "Doubles +item"; - item_charge_default[lookupItem("broken champagne bottle")] = 11; - - item_charge_property[lookupItem("deceased crimbo tree")] = "garbageTreeCharge"; - item_effect_description[lookupItem("deceased crimbo tree")] = "Absorbs damage"; - item_charge_default[lookupItem("deceased crimbo tree")] = 1000; - - // Use the right item ID depending on if you are using a replica or a non-replica - string activeToteID = lookupItem("replica January's Garbage Tote").available_amount() > 0 ? "11238" : "9690"; - - ChecklistEntry entry; - entry.url = "inv_use.php?pwd=" + my_hash() + "&whichitem="+activeToteID; - entry.importance_level = 8; - entry.tags.id = "Garbage tote items resource"; - - boolean outdatedGarbage = !get_property_boolean("_garbageItemChanged"); - - foreach it, property_name in item_charge_property { - int charge = get_property_int(property_name); - boolean have = it.available_amount() > 0; - if (!have && outdatedGarbage) - charge = item_charge_default[it]; - - if (!have && charge == 0) continue; - if (!have && !(lookupItems("makeshift garbage shirt,broken champagne bottle") contains it)) continue; - string title; - string [int] description; - string url = "inventory.php?which=2"; - if (charge > 0) { - title = pluralise(charge, "charge", "charges") + " of " + it; - description.listAppend(item_effect_description[it] + "." + (!have ? " Not active." : "")); - if (have && outdatedGarbage) - description.listAppend("Charges are from previous day. Will get " + item_charge_default[it] + " more when you interact with the Tote (you will lose those " + charge + ")."); - } else { - title = HTMLGenerateSpanFont("No charges of " + it, "red"); - description.listAppend(outdatedGarbage ? "Interact with Tote to refill charges." : "Switch out for something else."); - url = "inv_use.php?pwd=" + my_hash() + "&whichitem="+activeToteID; - } - if (entry.image_lookup_name == "") - entry.image_lookup_name = "__item " + it; - entry.subentries.listAppend(ChecklistSubentryMake(title, "", description)); - //resource_entries.listAppend(ChecklistEntryMake("__item " + it, url, ChecklistSubentryMake(title, "", description), 8).ChecklistEntrySetIDTag("Garbage tote items resource")); - } - if (entry.subentries.count() > 0) - resource_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Items of the Month/2018/God Lobster.ash b/Source/relay/TourGuide/Items of the Month/2018/God Lobster.ash deleted file mode 100644 index 6d9906d8..00000000 --- a/Source/relay/TourGuide/Items of the Month/2018/God Lobster.ash +++ /dev/null @@ -1,87 +0,0 @@ - -RegisterResourceGenerationFunction("IOTMGodLobsterGenerateResource"); -void IOTMGodLobsterGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("god lobster").familiar_is_usable()) return; - int free_fights_left = clampi(3 - get_property_int("_godLobsterFights"), 0, 3); - - if (free_fights_left == 0) return; - string url = "familiar.php"; - if (lookupFamiliar("god lobster") == my_familiar()) - url = ""; - - string [int] description; - //This is so complicated. - - item [int] equipment_order; - equipment_order.listAppend(lookupItem("God Lobster's Scepter")); - equipment_order.listAppend(lookupItem("God Lobster's Ring")); - equipment_order.listAppend(lookupItem("God Lobster's Rod")); - equipment_order.listAppend(lookupItem("God Lobster's Robe")); - equipment_order.listAppend(lookupItem("God Lobster's Crown")); - - item [item] equipment_to_next_reward; - equipment_to_next_reward[$item[none]] = lookupItem("God Lobster's Scepter"); - equipment_to_next_reward[lookupItem("God Lobster's Scepter")] = lookupItem("God Lobster's Ring"); - equipment_to_next_reward[lookupItem("God Lobster's Ring")] = lookupItem("God Lobster's Rod"); - equipment_to_next_reward[lookupItem("God Lobster's Rod")] = lookupItem("God Lobster's Robe"); - equipment_to_next_reward[lookupItem("God Lobster's Robe")] = lookupItem("God Lobster's Crown"); - equipment_to_next_reward[lookupItem("God Lobster's Crown")] = $item[none]; - - string [item] equipment_to_boon_description; - equipment_to_boon_description[$item[none]] = "40 mp/adv / +20 MP"; - equipment_to_boon_description[lookupItem("God Lobster's Scepter")] = "+10 stats/fight"; - equipment_to_boon_description[lookupItem("God Lobster's Ring")] = "-combat"; - equipment_to_boon_description[lookupItem("God Lobster's Rod")] = "+combat"; - equipment_to_boon_description[lookupItem("God Lobster's Robe")] = "+1 all res / +20 DA / +3 DR"; - equipment_to_boon_description[lookupItem("God Lobster's Crown")] = "doubles food statgain"; - - - string [item] equipment_to_equipment_effect_description; - equipment_to_equipment_effect_description[lookupItem("God Lobster's Scepter")] = "half-weight fairy/leprechaun"; - equipment_to_equipment_effect_description[lookupItem("God Lobster's Ring")] = "sombrero statgain"; - equipment_to_equipment_effect_description[lookupItem("God Lobster's Rod")] = "restore HP/MP after combat"; - equipment_to_equipment_effect_description[lookupItem("God Lobster's Robe")] = "blocking potato"; - equipment_to_equipment_effect_description[lookupItem("God Lobster's Crown")] = "full-weight fairy"; - - float [item] equipment_to_mainstat_multiplier; - equipment_to_mainstat_multiplier[$item[none]] = 1.5; - equipment_to_mainstat_multiplier[lookupItem("God Lobster's Scepter")] = 1.65; - equipment_to_mainstat_multiplier[lookupItem("God Lobster's Ring")] = 1.85; - equipment_to_mainstat_multiplier[lookupItem("God Lobster's Rod")] = 2.17; - equipment_to_mainstat_multiplier[lookupItem("God Lobster's Robe")] = 2.62; - equipment_to_mainstat_multiplier[lookupItem("God Lobster's Crown")] = 3.0; - - - item current_familiar_equipment = lookupFamiliar("god lobster").familiar_equipped_equipment(); - - string [int] current_rewards; - //[next equipment], [effect], [experience] - - current_rewards.listAppend(equipment_to_boon_description[current_familiar_equipment] + " effect (33 turns)"); - if (__misc_state["need to level"]) - { - float statgain = equipment_to_mainstat_multiplier[current_familiar_equipment] * my_basestat(my_primestat()) * (1.0 + numeric_modifier(my_primestat() + " experience percent") / 100.0); - current_rewards.listAppend(round(statgain) + " mainstat gain"); - } - - if (equipment_to_next_reward[current_familiar_equipment] != $item[none] && equipment_to_next_reward[current_familiar_equipment].available_amount() == 0) - current_rewards.listAppend("a " + equipment_to_next_reward[current_familiar_equipment].replace_string("God Lobster's", "").to_lower_case()); - - if (current_rewards.count() > 0) - description.listAppend("Can choose between " + current_rewards.listJoinComponents(", ", "or") + "."); - - string [int] other_equipment_to_switch_to; - foreach it in equipment_to_boon_description - { - if (it.available_amount() == 0) continue; - if (it == current_familiar_equipment) continue; - //FIXME write this - other_equipment_to_switch_to.listAppend(it + " (" + equipment_to_equipment_effect_description[it] + " and " + equipment_to_boon_description[it] + " obtainable effect)"); - } - - if (other_equipment_to_switch_to.count() > 0) - description.listAppend("Could switch equipment to " + other_equipment_to_switch_to.listJoinComponents(", ", "or") + "."); - - resource_entries.listAppend(ChecklistEntryMake("__familiar god lobster", url, ChecklistSubentryMake(pluralise(free_fights_left, "free God Lobster fight", "free God Lobster fights"), "", description)).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("God lobster daily fights")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2018/Latte.ash b/Source/relay/TourGuide/Items of the Month/2018/Latte.ash deleted file mode 100644 index 96414e00..00000000 --- a/Source/relay/TourGuide/Items of the Month/2018/Latte.ash +++ /dev/null @@ -1,70 +0,0 @@ - -RegisterResourceGenerationFunction("IOTMLatteGenerateResource"); -void IOTMLatteGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (lookupItem("latte lovers member's mug").available_amount() == 0) return; - - int refills_remaining = clampi(3 - get_property_int("_latteRefillsUsed"), 0, 3); - boolean banish_used = get_property_boolean("_latteBanishUsed"); - boolean copy_used = get_property_boolean("_latteCopyUsed"); //more of an olfact than a copy - boolean drink_used = get_property_boolean("_latteDrinkUsed"); - - int banishes_available = refills_remaining + (!banish_used ? 1 : 0); - int copies_available = refills_remaining + (!copy_used ? 1 : 0); - - string url; - boolean latte_needs_equipping = false; - if (lookupItem("latte lovers member's mug").equipped_amount() == 0) - { - url = "inventory.php?which=2"; - latte_needs_equipping = true; - } - if (banishes_available > 0 && $skill[Throw Latte on Opponent].skill_is_usable()) - { - string banish_url = url; - string [int] description; - - if (banish_used) { - banish_url = "main.php?latte=1"; - description.listAppend(HTMLGenerateSpanFont("Must refill latte first.", "red")); - } else if (latte_needs_equipping) { - banish_url = "inventory.php?which=3"; - description.listAppend(HTMLGenerateSpanFont("Equip the latte first", "red")); - } else { - description.listAppend("Free run/banish"); - } - - resource_entries.listAppend(ChecklistEntryMake("__item latte lovers member's mug", banish_url, ChecklistSubentryMake(pluralise(banishes_available, "latte banish", "latte banishes"), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Latte lovers mug throw banish")); - } - - ChecklistEntry entry; - entry.image_lookup_name = "__item latte lovers member's mug"; - entry.url = "main.php?latte=1"; - entry.tags.id = "Latte lovers mug resource"; - - if (refills_remaining > 0) - { - string [int] description; - if (!banish_used && __misc_state["in run"]) - description.listAppend(HTMLGenerateSpanFont("Use banish first.", "red")); - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(refills_remaining, "latte refill", "latte refills"), "", description)); - } - if (copies_available > 0 && $skill[Offer Latte to Opponent].skill_is_usable()) - { - string [int] description; - description.listAppend("Offer Latte to Opponent in combat."); - if (copy_used) - { - description.listAppend(HTMLGenerateSpanFont("Must refill latte first.", "red")); - } - if ($skill[Transcendent Olfaction].have_skill()) - description.listAppend("Stack with Transcendent Olfaction."); - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(copies_available, "latte olfaction", "latte olfactions"), "", description)); - } - if (!drink_used && my_path().id != PATH_VAMPIRE) - { - entry.subentries.listAppend(ChecklistSubentryMake("Gulp Latte available", "", "Restores half your HP and MP. Cast in combat.")); - } - if (entry.subentries.count() > 0) - resource_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Items of the Month/2018/Neverending Party.ash b/Source/relay/TourGuide/Items of the Month/2018/Neverending Party.ash deleted file mode 100644 index 32a7c7c4..00000000 --- a/Source/relay/TourGuide/Items of the Month/2018/Neverending Party.ash +++ /dev/null @@ -1,194 +0,0 @@ -RegisterTaskGenerationFunction("IOTMNeverendingPartyGenerateTasks"); -void IOTMNeverendingPartyGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!mafiaIsPastRevision(18865)) - return; - if (!__iotms_usable[lookupItem("Neverending Party invitation envelope")]) - return; - //Quest suggestions: - //_partyHard (boolean), _questPartyFair (Quest), _questPartyFairProgress (integer?), _questPartyFairQuest (string? - "partiers", ) - - QuestState quest_state = QuestState("_questPartyFair"); - //_questPartyFair is "" instead of unstarted if they didn't start it. - if (quest_state.in_progress) { - string quest_name = get_property("_questPartyFairQuest"); - //strange - went from "unstarted" to "step1" when accepting the partiers quest - boolean party_hard = get_property_boolean("_partyHard"); - int [int] progress_split; - foreach key, v in get_property("_questPartyFairProgress").split_string(" ") { - if (v == "") continue; - progress_split.listAppend(v.to_int()); - } - int progress = progress_split[0]; - - string [int] modifiers; - string [int] description; - string url = "place.php?whichplace=town_wrong"; - boolean finished = false; - if (party_hard && lookupItem("PARTY HARD T-shirt").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the PARTY HARD T-shirt.", "red")); - url = "inventory.php?ftext=party+hard+t-shirt"; - } - //partiers - progress starts at 50 in not-hard - if (quest_name == "partiers") { - if (progress > 0) { - description.listAppend(pluralise(progress, "partier", "partiers") + " remain."); - if (lookupItem("intimidating chainsaw").available_amount() == 0) { - description.listAppend("Collect the intimidating chainsaw.|" + listMake("Investigate the basement", "Grab the chainsaw").listJoinComponents(__html_right_arrow_character)); - } else if (lookupItem("intimidating chainsaw").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the intimidating chainsaw.", "red")); - url = "inventory.php?ftext=intimidating+chainsaw"; - } - if (lookupItem("jam band bootleg").item_amount() > 0) { - description.listAppend("Pop in the bootleg.|" + listMake("Head Upstairs", "Pop a bootleg in the stereo").listJoinComponents(__html_right_arrow_character)); - } else if (!in_ronin()) { - description.listAppend("Buy a jam band bootleg in the mall?"); - } - if (lookupItem("Purple Beast energy drink").item_amount() > 0) { - description.listAppend("Pour the energy drink into the pool.|" + listMake("Go to the back yard", "Pour Purple Beast into the pool").listJoinComponents(__html_right_arrow_character)); - } else if (!in_ronin()) { - description.listAppend("Buy a Purple Beast energy drink in the mall?"); - } - } else { - finished = true; - } - } else if (quest_name == "booze") { - //unremarkable duffel bag gives item; from jock - - if (quest_state.mafia_internal_step < 2) { - description.listAppend("Talk to Gerald.|" + listMake("Go to the back yard", "Find Gerald").listJoinComponents(__html_right_arrow_character)); - } else { - int amount_needed = progress_split[0]; - item item_needed = progress_split[1].to_item(); - if (item_needed == $item[none]) { - description.listAppend("Unknown item needed."); - } else if (item_needed.item_amount() < amount_needed) { - description.listAppend("Need to collect " + amount_needed + " " + item_needed + "."); - description.listAppend("Can collect from unremarkable duffel bags, from the jock."); - modifiers.listAppend("olfact jock"); - } else - description.listAppend("Talk to Gerald.|" + listMake("Go to the back yard", "Give Gerald the booze").listJoinComponents(__html_right_arrow_character)); - } - } else if (quest_name == "food") { - //van key gives item; from burnout - - if (quest_state.mafia_internal_step < 2) { - description.listAppend("Talk to Geraldine.|" + listMake("Check out the kitchen", "Talk to the woman").listJoinComponents(__html_right_arrow_character)); - } else { - int amount_needed = progress_split[0]; - item item_needed = progress_split[1].to_item(); - - if (item_needed == $item[none]) { - description.listAppend("Unknown item needed."); - } else if (item_needed.item_amount() < amount_needed) { - description.listAppend("Need to collect " + amount_needed + " " + item_needed + "."); - description.listAppend("Can collect from van keys, from the burnout."); - modifiers.listAppend("olfact burnout"); - } else - description.listAppend("Talk to Geraldine again.|" + listMake("Check out the kitchen", "Give Geraldine the snacks").listJoinComponents(__html_right_arrow_character)); - } - } else if (quest_name == "trash") { - if (true) { - modifiers.listAppend("+200% item"); - //Progress on this quest seems to be bugged - starts at zero, doesn't change unless we look at the quest log. - //description.listAppend("Progress: " + progress); - description.listAppend("Run +200% item."); - if (lookupItem("gas can").item_amount() > 0) { - description.listAppend(listMake("Check out the kitchen", "Burn some trash").listJoinComponents(__html_right_arrow_character)); - } else if (!in_ronin()) { - description.listAppend("Buy a gas can in the mall?"); - } - } else { - finished = true; - } - } else if (quest_name == "woots") { - if (progress < 100) { - description.listAppend(progress + " out of 100 megawoots."); - //equip cosmetic football - if (lookupItem("cosmetic football").available_amount() == 0 && !in_ronin()) { - description.listAppend("Buy the cosmetic football in the mall?"); - } - if (lookupItem("cosmetic football").available_amount() > 0 && lookupItem("cosmetic football").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the cosmetic football.", "red")); - url = "inventory.php?ftext=cosmetic+football"; - } - //very small red dress - if (lookupItem("very small red dress").item_amount() > 0) { - description.listAppend(listMake("Head upstairs", "Toss the red dress on the lamp").listJoinComponents(__html_right_arrow_character)); - } else if (!in_ronin()) { - description.listAppend("Buy a very small red dress in the mall?"); - } - //electronics kit - if (lookupItem("electronics kit").item_amount() > 0) { - description.listAppend(listMake("Investigate the basement", "Modify the living room lights").listJoinComponents(__html_right_arrow_character)); - } else if (!in_ronin()) { - description.listAppend("Buy a electronics kit in the mall?"); - } - } else - finished = true; - } else if (quest_name == "dj") { - if (progress > 0) { - modifiers.listAppend("+meat"); - modifiers.listAppend("olfact jocks"); - modifiers.listAppend("banish burnouts"); - description.listAppend(progress + " meat remaining."); - description.listAppend("Run +meat, olfact jocks, banish burnouts."); - if (my_buffedstat($stat[moxie]) >= 300) { - description.listAppend("Open the safe.|" + listMake("Head upstairs", "Crack the safe").listJoinComponents(__html_right_arrow_character)); - } else { - description.listAppend("Possibly buff to 300 moxie?"); - modifiers.listAppend("300 moxie"); - } - } else - finished = true; - } else if (quest_name == "") { - } else - description.listAppend("Unhandled quest \"" + quest_name + "\""); - if (finished) { - description.listAppend("Visit the party one last time to finish the quest."); - } - optional_task_entries.listAppend(ChecklistEntryMake("__item party hat", url, ChecklistSubentryMake("Neverending Party Quest", modifiers, description), 8, lookupLocations("The Neverending Party")).ChecklistEntrySetIDTag("Neverending party quest")); - } -} - -RegisterResourceGenerationFunction("IOTMNeverendingPartyGenerateResource"); -void IOTMNeverendingPartyGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!mafiaIsPastRevision(18865)) - return; - if (!__iotms_usable[lookupItem("Neverending Party invitation envelope")]) - return; - - int free_fights_left = clampi(10 - get_property_int("_neverendingPartyFreeTurns"), 0, 10); - string party_fair_state = get_property("_questPartyFair"); - if (party_fair_state == "finished") - free_fights_left = 0; - string [int] modifiers; - string [int] description; - modifiers.listAppend("+meat"); - - if (party_fair_state == "unstarted") // need to do it that way because Guide's QuestState logic confuses "unstarted" and "" - description.listAppend("Need to accept or reject daily quest first."); - - if (free_fights_left >= 2) { - if (__misc_state["need to level"]) { - string [int] directions; - if (my_primestat() == $stat[muscle]) { - directions.listAppend("Kitchen"); - directions.listAppend("Muscle spice"); - } else if (my_primestat() == $stat[mysticality]) { - directions.listAppend("Upstairs"); - directions.listAppend("Read the tomes"); - } else if (my_primestat() == $stat[moxie]) { - directions.listAppend("Basement"); - directions.listAppend("Use the hair gel"); - } - description.listAppend("Experience buff: " + directions.listJoinComponents(__html_right_arrow_character) + "."); - } - if (__misc_state["in run"]) - description.listAppend("ML buff: " + listMake("Backyard", "Candle wax").listJoinComponents(__html_right_arrow_character)); - } - if (free_fights_left > 0) - resource_entries.listAppend(ChecklistEntryMake("__item party hat", "place.php?whichplace=town_wrong", ChecklistSubentryMake(pluralise(free_fights_left, "free party fight", "free party fights"), modifiers, description), lookupLocations("The Neverending Party")).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Neverending party free fights")); - -} diff --git a/Source/relay/TourGuide/Items of the Month/2018/Voting Booth.ash b/Source/relay/TourGuide/Items of the Month/2018/Voting Booth.ash deleted file mode 100644 index 42ae57ae..00000000 --- a/Source/relay/TourGuide/Items of the Month/2018/Voting Booth.ash +++ /dev/null @@ -1,74 +0,0 @@ - -//Throw your voting boot: -RegisterTaskGenerationFunction("IOTMVotingBootGenerateTasks"); -void IOTMVotingBootGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!mafiaIsPastRevision(18965)) - return; - if (!__iotms_usable[lookupItem("voter registration form")] && lookupItem(""I Voted!" sticker").available_amount() == 0) return; - - if (lookupItem(""I Voted!" sticker").available_amount() == 0 || false) { - //Vote! - string [int] description; - if (in_ronin()) - description.listAppend("Gives special modifiers, and unlocks three free fights to burn delay."); - else - description.listAppend("Gives special modifiers."); - optional_task_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", "place.php?whichplace=town_right&action=townright_vote", ChecklistSubentryMake("Vote!", "", description), 8).ChecklistEntrySetIDTag("Voting booth daily ballot")); - return; - } - - int turns_before_vote_fight = 11 - (((total_turns_played() % 11) - 1 + 11) % 11); - boolean vote_fight_now = total_turns_played() % 11 == 1 && get_property_int("lastVoteMonsterTurn") < total_turns_played(); - int vote_free_fights_left = 3 - get_property_int("_voteFreeFights"); - - if (vote_free_fights_left > 0) { - if (vote_fight_now) { - string url = ""; - string [int] description; - if (lookupItem(""I Voted!" sticker").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the I Voted! sticker first.", "red")); - url = "inventory.php?ftext=i+voted!"; - } - description.listAppend("Free fight that burns delay. " + vote_free_fights_left + " left."); - location [int] possible_locations = generatePossibleLocationsToBurnDelay(); - if (possible_locations.count() > 0) { - description.listAppend("Adventure in " + possible_locations.listJoinComponents(", ", "or") + " to burn delay."); - if (url == "") - url = possible_locations[0].getClickableURLForLocation(); - } - monster fighting_monster = get_property_monster("_voteMonster"); - string title = "Fight voting monster"; - if (fighting_monster != $monster[none]) - title += " " + fighting_monster; - task_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", url, ChecklistSubentryMake(title, "", description), -11).ChecklistEntrySetIDTag("Voting booth voting monster now")); - } else { - optional_task_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", "", ChecklistSubentryMake("Voting monster after " + pluralise(turns_before_vote_fight, "More Turn", "more turns") + "", "", "Free fight to burn delay with (" + vote_free_fights_left + " left)."), 10).ChecklistEntrySetIDTag("Voting booth voting monster reminder")); //merge those two? or give the player the choice, at least? - } - } - - if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5 && vote_free_fights_left <= 0 && vote_fight_now && $skill[meteor lore].have_skill() && get_property_int("_macrometeoriteUses") < 10 && !CounterLookup("portscan.edu").CounterWillHitNextTurn() && $location[Sonofa Beach].locationAvailable()) { //Could change this to make it compatible with Replace Enemy? - string title = "Lobsterfrogman voting macrometeorite trick time"; - string [int] description; - string url = ""; - monster fighting_monster = get_property_monster("_voteMonster"); - if (lookupItem(""I Voted!" sticker").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the I Voted! sticker first.", "red")); - url = "inventory.php?ftext=i+voted!"; - } - description.listAppend("Adventure in the sonofa beach, macrometeorite the " + (fighting_monster == $monster[none] ? "voting monster" : fighting_monster.to_string()) + ", and you'll get a lobsterfrogman."); - task_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", url, ChecklistSubentryMake(title, "", description), -11).ChecklistEntrySetIDTag("Voting booth LFM wanderer-switch-copy trick")); - - } -} - -RegisterResourceGenerationFunction("IOTMVotingBootGenerateResource"); -void IOTMVotingBootGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (lookupItem(""I Voted!" sticker").available_amount() == 0) return; - - int vote_free_fights_left = 3 - get_property_int("_voteFreeFights"); - if (get_property_int("_voteFreeFights") < 3) { - resource_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", "", ChecklistSubentryMake(pluralise(vote_free_fights_left, "voting monster", "voting monsters"), "", "Free fight."), 8).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Voting booth voting monster free fight")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2018/Zatara.ash b/Source/relay/TourGuide/Items of the Month/2018/Zatara.ash deleted file mode 100644 index a78b8b1d..00000000 --- a/Source/relay/TourGuide/Items of the Month/2018/Zatara.ash +++ /dev/null @@ -1,42 +0,0 @@ - - -RegisterResourceGenerationFunction("IOTMZataraGenerateResource"); -void IOTMZataraGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["VIP available"] || !lookupItem("Clan Carnival Game").is_unrestricted()) - return; - ChecklistEntry entry; - entry.importance_level = 8; - entry.image_lookup_name = "__item genie's turbane"; - entry.url = "clan_viplounge.php?preaction=lovetester"; - entry.tags.id = "Clan VIP madame Zatara consults"; - if (!get_property_boolean("_clanFortuneBuffUsed")) - { - string [int] description; - if (!__misc_state["familiars temporarily blocked"] && __misc_state["in run"]) - description.listAppend(HTMLGenerateSpanOfClass("Susie:", "r_bold") + " +5 familiar weight, +familiar experience."); //only show in-run, because, like... +5 familiar weight for one hundred turns is not likely to pay out compared to hagnk/meatsmith in aftercore. - if (my_path().id != PATH_G_LOVER) - description.listAppend(HTMLGenerateSpanOfClass("Hagnk:", "r_bold") + " +50% item/booze/food."); - if (my_path().id != PATH_G_LOVER) - description.listAppend(HTMLGenerateSpanOfClass("Meatsmith:", "r_bold") + " +100% meat, +50% gear drop."); - - if (__misc_state["in run"]) - { - if (my_primestat() == $stat[muscle] || my_path().id == PATH_COMMUNITY_SERVICE) - description.listAppend(HTMLGenerateSpanOfClass("Gunther:", "r_bold") + " +5 muscle stats/fight, +100% muscle, +50% HP."); - if (my_primestat() == $stat[moxie] || my_path().id == PATH_COMMUNITY_SERVICE) - description.listAppend(HTMLGenerateSpanOfClass("Gorgonzola:", "r_bold") + " +5 myst stats/fight, +100% myst, +50% MP."); - //always show moxie, since I'm sure that +50% init will be super important to someone. maybe they have a bad lair test? - if (my_path().id != PATH_G_LOVER) - description.listAppend(HTMLGenerateSpanOfClass("Shifty:", "r_bold") + " +5 moxie stats/fight, +100% moxie, +50% init."); - } - entry.subentries.listAppend(ChecklistSubentryMake("Fortune buff (100 turns)", "", description)); - } - if (get_property_int("_clanFortuneConsultUses") < 3) - { - string [int] description; - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(3 - get_property_int("_clanFortuneConsultUses"), "fortune clan consult", "fortune clan consults"), "", description)); - } - if (entry.subentries.count() > 0) - resource_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Items of the Month/2019/Beach Comb.ash b/Source/relay/TourGuide/Items of the Month/2019/Beach Comb.ash deleted file mode 100644 index a8deb035..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/Beach Comb.ash +++ /dev/null @@ -1,49 +0,0 @@ - -RegisterResourceGenerationFunction("IOTMBeachCombGenerateResource"); -void IOTMBeachCombGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (lookupItem("beach comb").available_amount() == 0) return; - int free_walks_left = clampi(11 - get_property_int("_freeBeachWalksUsed"), 0, 11); - if (free_walks_left == 0) - return; - - boolean [int] beach_heads_used = get_property("_beachHeadsUsed").stringToIntIntList(",").listInvert(); - - string [int] description; - string [int] buffs; - - string [int] elemental_buffs; - boolean in_run = __misc_state["in run"]; - if (!beach_heads_used[1]) - elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Hot-Headed", "r_element_hot")); - if (!beach_heads_used[2]) - elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Cold as Nice", "r_element_cold")); - if (!beach_heads_used[3]) - elemental_buffs.listAppend(HTMLGenerateSpanOfClass("A Brush with Grossness", "r_element_stench")); - if (!beach_heads_used[4]) - elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Does It Have a Skull In There??", "r_element_spooky")); - if (!beach_heads_used[5]) - elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Oiled\, Slick", "r_element_sleaze")); - - if (elemental_buffs.count() > 0 && in_run) - buffs.listAppend("" + elemental_buffs.listJoinComponents(" / ") + ": +3 X resistance, +15 X damage, +15 X spell damage."); - if (!beach_heads_used[6] && in_run) - buffs.listAppend("Lack of Body-Building: +50% muscle, +25% weapon damage."); // hah - if (!beach_heads_used[7] && in_run) - buffs.listAppend("We're All Made of Starfish: +50% myst, +25% spell damage."); - if (!beach_heads_used[8] && in_run) - buffs.listAppend("Pomp & Circumsands: +50% moxie, +25% ranged damage."); - if (!beach_heads_used[9] && in_run) - buffs.listAppend("Resting Beach Face: +50% init."); - if (!beach_heads_used[10]) - buffs.listAppend("Do I Know You From Somewhere?: +5 familiar weight."); - if (!beach_heads_used[11] && in_run) - buffs.listAppend("You Learned Something Maybe!: +5 stats/fight."); - - if (buffs.count() > 0) - description.listAppend("Buffs:
" + buffs.listJoinComponents("
")); - if (free_walks_left >= 10) - description.listAppend((description.count() > 0 ? "Or collect" : "Collect") + " a bunch of items? (10 walks)"); - description.listAppend("Or farm the beach."); - resource_entries.listAppend(ChecklistEntryMake("__item beach comb", "main.php?comb=1", ChecklistSubentryMake(pluralise(free_walks_left, "beach comb", "beach combs"), "", description), 3).ChecklistEntrySetIDTag("Beach comb resource")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2019/Eight Days a Week Pills.ash b/Source/relay/TourGuide/Items of the Month/2019/Eight Days a Week Pills.ash deleted file mode 100644 index 24fd559a..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/Eight Days a Week Pills.ash +++ /dev/null @@ -1,44 +0,0 @@ -RegisterResourceGenerationFunction("IOTMEightDaysAWeekPillsGenerateResource"); -void IOTMEightDaysAWeekPillsGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[lookupItem("Eight Days a Week Pill Keeper")]) return; - if (get_property_boolean("_freePillKeeperUsed") && spleen_limit() - my_spleen_use() < 3) return; - - ChecklistSubentry getPills() { - // Title - string main_title = "Take a pill"; - - // Subtitle - string subtitle = "First is Free!"; - if (get_property_boolean("_freePillKeeperUsed")) { - subtitle = "-3 Spleen"; - } - - // Entries - string [int] description; - description.listAppend(HTMLGenerateSpanOfClass("Monday:", "r_bold") + " Yellow ray (30 turns)"); - description.listAppend(HTMLGenerateSpanOfClass("Tuesday:", "r_bold") + " Double potion length"); - description.listAppend(HTMLGenerateSpanOfClass("Wednesday:", "r_bold") + " Force Non-Combat"); - description.listAppend(HTMLGenerateSpanOfClass("Thursday:", "r_bold") + " +4 all res (30 turns)"); - description.listAppend(HTMLGenerateSpanOfClass("Friday:", "r_bold") + " +100% all stats (30 turns)"); - description.listAppend(HTMLGenerateSpanOfClass("Saturday:", "r_bold") + " Familiars 20 pounds (30 turns)"); - description.listAppend(HTMLGenerateSpanOfClass("Sunday:", "r_bold") + " Get Lucky!"); - description.listAppend(HTMLGenerateSpanOfClass("Funday:", "r_bold") + " Random adventures (30 turns)"); - - return ChecklistSubentryMake(main_title, subtitle, description); - } - - ChecklistEntry entry; - entry.image_lookup_name = "__item Eight Days a Week Pill Keeper"; - entry.url = "main.php?eowkeeper=1"; - entry.tags.id = "Pill keeper resource"; - - ChecklistSubentry pills = getPills(); - if (pills.entries.count() > 0) { - entry.subentries.listAppend(pills); - } - - if (entry.subentries.count() > 0) { - resource_entries.listAppend(entry); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2019/Getaway Campsite.ash b/Source/relay/TourGuide/Items of the Month/2019/Getaway Campsite.ash deleted file mode 100644 index bd844575..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/Getaway Campsite.ash +++ /dev/null @@ -1,146 +0,0 @@ -//Getaway Camp -RegisterResourceGenerationFunction("IOTMGetawayCampsiteGenerateResource"); -void IOTMGetawayCampsiteGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[lookupItem("Distant Woods Getaway Brochure")]) return; - - item firewood = lookupItem("stick of firewood"); - int cloud_buffs_left = clampi(1 - get_property_int("_campAwayCloudBuffs"), 0, 1); - int smile_buffs_left = clampi(3 - get_property_int("_campAwaySmileBuffs"), 0, 3); - - if (cloud_buffs_left > 0) { // && lookupEffect("That's Just Cloud-Talk, Man").have_effect() == 0) - string [int] description; - description.listAppend("Large +stat buff. Gaze at the stars."); - if (firewood.have() || lookupItem("campfire smoke").have()) - description.listAppend("If you don't see it, you could make and use campfire smoke first."); - resource_entries.listAppend(ChecklistEntryMake("__item Newbiesport™ tent", "place.php?whichplace=campaway", ChecklistSubentryMake("Cloud-talk buff obtainable", "", description), 0).ChecklistEntrySetCombinationTag("getaway campsite resources").ChecklistEntrySetIDTag("Getaway campsite cloud talk")); - } - if (smile_buffs_left > 0) { // && lookupEffect("That's Just Cloud-Talk, Man").have_effect() == 0) - // Implementation of campSmile.ash by @fredg1 - string [int] [string] buffCycle; - buffCycle [0] ["effect"] = my_sign() == "Blender" ? "+50% booze drop" : "+25% booze drop" ; - buffCycle [0] ["name"] = "Blender"; - buffCycle [1] ["effect"] = my_sign() == "Packrat" ? "+50% meat" : "+25% meat" ; - buffCycle [1] ["name"] = "Packrat"; - buffCycle [2] ["effect"] = my_sign() == "Mongoose" ? "+20% critical hit" : "+10% critical hit" ; - buffCycle [2] ["name"] = "Mongoose"; - buffCycle [3] ["effect"] = my_sign() == "Wallaby" ? "+20% spell critical hit" : "+10% spell critical hit" ; - buffCycle [3] ["name"] = "Wallaby"; - buffCycle [4] ["effect"] = my_sign() == "Vole" ? "+10-30 HP/adventure" : "+5-15 HP/adventure" ; - buffCycle [4] ["name"] = "Vole"; - buffCycle [5] ["effect"] = my_sign() == "Platypus" ? "+5 familiar experience" : "+3 familiar experience" ; - buffCycle [5] ["name"] = "Platypus"; - buffCycle [6] ["effect"] = my_sign() == "Opossum" ? "+100% candy drop" : "+50% candy drop" ; - buffCycle [6] ["name"] = "Opossum"; - buffCycle [7] ["effect"] = my_sign() == "Marmot" ? "+8~12 MP/adventure" : "+4~6 MP/adventure" ; - buffCycle [7] ["name"] = "Marmot"; - buffCycle [8] ["effect"] = my_sign() == "Wombat" ? "Damage Absorption +100" : "Damage Absorption +50" ; - buffCycle [8] ["name"] = "Wombat"; - - int getOffset(int year) { // made by @Skaazi - int offset = 5; // for 2020 - for ( int i = year; i > 2020; i-- ) { - if ( year_is_leap_year( i - 1 ) ) { offset += 1; } - offset += 365; - } - return offset % 9; - } - - string [int] description; - description.listAppend("Gaze at the stars."); - - int offset = getOffset(format_date_time("yyyyMMdd", today_to_string(), "yyyy").to_int()); - int todaysArbitraryNumber = format_date_time("yyyyMMdd", today_to_string(), "D").to_int() + my_path().id + offset; - int todaysCycleNumber = todaysArbitraryNumber % 9; - - description.listAppend("Will get: " + (my_sign() == buffCycle [todaysCycleNumber] ["name"] ? "Big " : "") + "Smile of the " + buffCycle [todaysCycleNumber] ["name"] + " (" + buffCycle [todaysCycleNumber] ["effect"] + ")"); - - string [int][int] tooltip_table; - - // Making today's buff name its own variable - string todaysBuff = buffCycle [todaysCycleNumber] ["name"]; - - // These are the given enchantments for each moonsign day - static string[string] smileEnchantments = { - "Mongoose":"% crit chance", - "Wallaby":"% spell crit", - "Vole":" HP regen", - "Platypus":" familiar XP", - "Opossum":"% candy drop", - "Marmot":" MP regen", - "Wombat":" DA", - "Blender":"% booze drop", - "Packrat":"% meat drop",}; - - // Doing a foreach through the enchantment list - foreach sign, enchantment in smileEnchantments { - // You get a "big smile" for extra bonus enchants for your given moonsign - boolean bigSmile = my_sign() == sign; - - string enchantAmount = ""; - - // There's clearly a better way to do this, but this works. It checks for big smile status - // then gives the correct enchant amount for the final list item. - if ($strings[Mongoose,Wallaby,Vole] contains sign) { - enchantAmount = bigSmile ? "20" : "10"; - } - if ($strings[Blender, Packrat] contains sign) { - enchantAmount = bigSmile ? "50" : "25"; - } - if (sign == "Platypus") { - enchantAmount = bigSmile ? "5" : "3"; - } - if ($strings[Opossum, Wombat] contains sign) { - enchantAmount = bigSmile ? "100" : "50"; - } - if (sign == "Marmot") { - enchantAmount = bigSmile ? "10" : "5" ; - } - - // UPDATE: ... I could've used what fred coded above I'm a big idiot ack - - // Highlight today's buff in red. - string signColor = todaysBuff == sign ? "blue" : "black"; - - // Add the sign to the tooltip table. - tooltip_table.listAppend(listMake(HTMLGenerateSpanFont(sign, signColor), HTMLGenerateSpanFont("+" + enchantAmount + enchantment, signColor))); - } - - buffer tooltip_text; - tooltip_text.append(HTMLGenerateTagWrap("div", "Campfire Smile cycle", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); - tooltip_text.append(HTMLGenerateSimpleTableLines(tooltip_table)); - - string campSmileCycleList = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Campfire Smile cycle", "r_tooltip_outer_class"); - description.listAppend(campSmileCycleList); - - resource_entries.listAppend(ChecklistEntryMake("__item Newbiesport™ tent", "place.php?whichplace=campaway", ChecklistSubentryMake(pluralise(smile_buffs_left, "smile buff", "smile buffs") + " obtainable", "20 turns", description), 5).ChecklistEntrySetCombinationTag("getaway campsite resources").ChecklistEntrySetIDTag("Getaway campsite sign smiles")); - } - if (firewood.have() && __misc_state["in run"]) { - string [int] description; - - string [int] various_options; - if (__misc_state["can eat just about anything"]) - various_options.listAppend("food"); - if (firewood.available_amount() >= 5 && my_path().id != PATH_GELATINOUS_NOOB) { - if (!lookupItem("whittled tiara").have()) - various_options.listAppend("whittled tiara for +elemental damage"); - if (!lookupItem("whittled shorts").have()) - various_options.listAppend("whittled shorts for +2 all res"); - if (!lookupItem("whittled flute").have()) - various_options.listAppend("whittled flute for +25% meat"); - if (firewood.available_amount() >= 10) { - if (!lookupItem("whittled bear figurine").have() && !__misc_state["familiars temporarily blocked"]) - various_options.listAppend("whittled bear figurine for +5 familiar weight"); - if (!lookupItem("whittled owl figurine").have()) - various_options.listAppend("whittled owl figurine for +20 ML"); - if (!lookupItem("whittled fox figurine").have()) - various_options.listAppend("whittled fox figurine figurine for +50% init"); - } - if (firewood.available_amount() >= 100 && !lookupItem("whittled walking stick").have()) - various_options.listAppend("whittled walking stick for a bunch of stuff"); - } - if (various_options.count() > 0) - description.listAppend(various_options.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); - resource_entries.listAppend(ChecklistEntryMake("__item Newbiesport™ tent", "shop.php?whichshop=campfire", ChecklistSubentryMake(pluralise(firewood), "", description), 5).ChecklistEntrySetCombinationTag("getaway campsite resources").ChecklistEntrySetIDTag("Getaway campsite firewood")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2019/Kramco Sausage-o-Matic.ash b/Source/relay/TourGuide/Items of the Month/2019/Kramco Sausage-o-Matic.ash deleted file mode 100644 index 85edd140..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/Kramco Sausage-o-Matic.ash +++ /dev/null @@ -1,95 +0,0 @@ -RegisterTaskGenerationFunction("IOTMKramcoSausageOMaticGenerateTasks"); -void IOTMKramcoSausageOMaticGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[lookupItem("Kramco Sausage-o-Matic™")]) return; - - //If goblin is up, display reminder: - KramcoSausageFightInformation fight_information = KramcoCalculateSausageFightInformation(); - if (fight_information.turns_to_next_guaranteed_fight == 0 && my_path().id != PATH_LIVE_ASCEND_REPEAT && __misc_state["in run"]) - { - - string url = ""; - string [int] description; - string title = "Fight sausage goblin "; - int kramcosEquipped = lookupItem("Kramco Sausage-o-Matic™").equipped_amount() + lookupItem("replica Kramco Sausage-o-Matic™").equipped_amount(); - - if (kramcosEquipped == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the Kramco Sausage-o-Matic™ first.", "red")); - url = "inventory.php?ftext=kramco+sausage-o-matic"; - } - description.listAppend("Free fight that burns delay."); - location [int] possible_locations = generatePossibleLocationsToBurnDelay(); - if (possible_locations.count() > 0) { - description.listAppend("Adventure in " + possible_locations.listJoinComponents(", ", "or") + " to burn delay."); - if (url == "") - url = possible_locations[0].getClickableURLForLocation(); - } - task_entries.listAppend(ChecklistEntryMake("__item Kramco Sausage-o-Matic™", url, ChecklistSubentryMake(title, "", description), -11).ChecklistEntrySetIDTag("Kramco sausage grinder goblin fight reminder")); - } -} - -RegisterResourceGenerationFunction("IOTMKramcoSausageOMaticGenerateResource"); -void IOTMKramcoSausageOMaticGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[lookupItem("Kramco Sausage-o-Matic™")] || my_path().id == PATH_LIVE_ASCEND_REPEAT) return; - - ChecklistEntry entry; - entry.image_lookup_name = "__item Kramco Sausage-o-Matic™"; - entry.url = "inventory.php?action=grind"; - entry.tags.id = "Kramco sausage grinder resource"; - entry.importance_level = -2; - - string [int] main_description; - string main_title; - - KramcoSausageFightInformation fight_information = KramcoCalculateSausageFightInformation(); - - int kramcosEquipped = lookupItem("Kramco Sausage-o-Matic™").equipped_amount() + lookupItem("replica Kramco Sausage-o-Matic™").equipped_amount(); - - if (fight_information.turns_to_next_guaranteed_fight == 0) { - main_title = "Sausage goblin fight available"; - if (kramcosEquipped == 0) { - main_description.listAppend(HTMLGenerateSpanFont("Equip the Kramco Sausage-o-Matic™ first.", "red")); - entry.url = "inventory.php?action=grind"; - } - } else { - main_title = round(fight_information.probability_of_sausage_fight * 100.0) + "% chance of Kramco fight this turn"; - main_description.listAppend(pluralise(fight_information.turns_to_next_guaranteed_fight, "turn", "turns") + " until next guaranteed goblin fight."); - if (kramcosEquipped == 0) { - main_description.listAppend(HTMLGenerateSpanFont("Equip the Kramco Sausage-o-Matic™ first.", "red")); - entry.url = "inventory.php?action=grind"; - } - } - - main_description.listAppend("Does not cost a turn; burns delay."); - - int fights_so_far = get_property_int("_sausageFights"); - if (fights_so_far > 0) { - main_description.listAppend("Fought " + pluralise(fights_so_far, "goblin", "goblins") + " so far."); - } - - entry.subentries.listAppend(ChecklistSubentryMake(main_title, "", main_description)); - - int sausage_casings = lookupItem("magical sausage casing").available_amount(); - int sausages_eaten = get_property_int("_sausagesEaten"); - int sausages_available = lookupItem("magical sausage").available_amount(); - int possible_sausages = sausages_available + sausage_casings; - if (possible_sausages > 0 && sausages_eaten < 23) { - string [int] sausage_description; - int sausages_made = get_property_int("_sausagesMade"); - int meat_cost = 111 * (sausages_made + 1); - sausage_description.listAppend("+1 adventure and +999 MP each."); - sausage_description.listAppend(HTMLGenerateSpanOfClass(sausage_casings, "r_bold") + " casings available, " + HTMLGenerateSpanOfClass(sausages_eaten + "/23", "r_bold") + " eaten today."); - if (sausages_made > 22) - { - sausage_description.listAppend(HTMLGenerateSpanFont(sausages_made + " sausages made today.", "purple")); - } - else - { - sausage_description.listAppend(pluralise(sausages_made, "sausage", "sausages") + " made; next costs " + meat_cost + " meat."); - } - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(MIN(sausages_available, 23 - sausages_eaten), "magical sausage", "magical sausages") + " edible", "", sausage_description)); - } - - resource_entries.listAppend(entry); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2019/Lil Doctor Bag.ash b/Source/relay/TourGuide/Items of the Month/2019/Lil Doctor Bag.ash deleted file mode 100644 index f160a6e3..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/Lil Doctor Bag.ash +++ /dev/null @@ -1,92 +0,0 @@ -RegisterTaskGenerationFunction("IOTMLilDoctorBagGenerateTasks"); -void IOTMLilDoctorBagGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (lookupItem("Lil' Doctor™ bag").available_amount() == 0) return; - //Quest: - int doctor_bag_upgrades = get_property_int("doctorBagUpgrades"); - int doctor_bag_lights = get_property_int("doctorBagQuestLights"); - string doctor_bag_quest_state = get_property("questDoctorBag"); - - if (doctor_bag_quest_state == "unstarted" && (doctor_bag_upgrades > 6 || __misc_state["in run"])) return; - - string title; - string [int] description; - string url; - - if (doctor_bag_quest_state != "unstarted") { - location doctor_bag_quest_location = get_property_location("doctorBagQuestLocation"); - item doctor_bag_quest_item = get_property_item("doctorBagQuestItem"); - title = "Medic! Medic!!"; - url = doctor_bag_quest_location.getClickableURLForLocation(); - - if (doctor_bag_quest_item.item_amount() == 0) - description.listAppend("Acquire a " + (doctor_bag_quest_item != $item[none] ? doctor_bag_quest_item + "." : "something..?")); - description.listAppend("Adventure in " + doctor_bag_quest_location + "."); - - description.listAppend("Will give " + (doctor_bag_upgrades < 7 ? "progress towards upgrading the bag and " : "") + "meat."); // There is no "n° of quests completed this ascension" property, so can't predict how much you'll get - } - - if (doctor_bag_upgrades < 7) { - if (title == "") { - title = "Upgrade your Lil' Doctor™ bag"; - description.listAppend("Adventure with your doctor bag equipped to get a delivery quest."); // no way to know if they "turned off" their bag - } - description.listAppend(pluralise(35 - doctor_bag_lights - doctor_bag_upgrades * 5, "quest", "quests") + " until bag is fully upgraded."); - } - - optional_task_entries.listAppend(ChecklistEntryMake("__item Lil' Doctor™ bag", url, ChecklistSubentryMake(title, "", description), 9).ChecklistEntrySetIDTag("Lil doctor bag upgrade quest")); -} - -RegisterResourceGenerationFunction("IOTMLilDoctorBagGenerateResource"); -void IOTMLilDoctorBagGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (lookupItem("Lil' Doctor™ bag").available_amount() == 0) return; - //Otoscope: +200% item - int otoscopes_left = clampi(3 - get_property_int("_otoscopeUsed"), 0, 3); - boolean otoscope_usable = my_path().id != PATH_G_LOVER && my_path().id != PATH_POCKET_FAMILIARS; - if (otoscopes_left > 0 && otoscope_usable && __misc_state["in run"]) - { - string url; - string [int] description; - description.listAppend("+200% item for one turn, cast in combat."); - - if (lookupItem("Lil' Doctor™ bag").equipped_amount() == 0) - { - description.listAppend("Equip the Lil' Doctor™ bag first."); - url = "inventory.php?ftext=lil'+doctor"; - } - resource_entries.listAppend(ChecklistEntryMake("__item Lil' Doctor™ bag", url, ChecklistSubentryMake(pluralise(otoscopes_left, "otoscope", "otoscopes"), "", description), 8).ChecklistEntrySetIDTag("Lil doctor bag otoscope")); - } - //Chest X-Ray: instakill - int instakills_left = clampi(3 - get_property_int("_chestXRayUsed"), 0, 3); - boolean instakills_usable = my_path().id != PATH_G_LOVER && my_path().id != PATH_POCKET_FAMILIARS; - if (instakills_left > 0 && instakills_usable) - { - string url; - string [int] description; - description.listAppend("Win a fight without taking a turn."); - - if (lookupItem("Lil' Doctor™ bag").equipped_amount() == 0) - { - description.listAppend("Equip the Lil' Doctor™ bag first."); - url = "inventory.php?ftext=lil'+doctor"; - } - resource_entries.listAppend(ChecklistEntryMake("__item Lil' Doctor™ bag", url, ChecklistSubentryMake(pluralise(instakills_left, "chest x-ray", "chest x-rays"), "", description), 0).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Lil doctor bag x-ray free kill")); - - } - //Reflex Hammer: Banish - int banishes_left = clampi(3 - get_property_int("_reflexHammerUsed"), 0, 3); - boolean banishes_usable = my_path().id != PATH_G_LOVER && my_path().id != PATH_POCKET_FAMILIARS; - if (banishes_left > 0 && banishes_usable) - { - string url; - string [int] description; - if (lookupItem("Lil' Doctor™ bag").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the Lil' Doctor™ bag first", "red")); - url = "inventory.php?ftext=lil'+doctor"; - } else { - description.listAppend("Free run, 30-turn banish."); - } - resource_entries.listAppend(ChecklistEntryMake("__item Lil' Doctor™ bag", url, ChecklistSubentryMake(pluralise(banishes_left, "reflex hammer", "reflex hammers"), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Lil doctor bag reflex hammer banish")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2019/May Saber.ash b/Source/relay/TourGuide/Items of the Month/2019/May Saber.ash deleted file mode 100644 index 5e49752a..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/May Saber.ash +++ /dev/null @@ -1,76 +0,0 @@ -RegisterTaskGenerationFunction("IOTMMaySaberPartyGenerateTasks"); -void IOTMMaySaberPartyGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[$item[Fourth of May Cosplay Saber]]) return; - if (my_path().id == PATH_G_LOVER) return; // cannot use saber in g-lover - - if (get_property_int("_saberMod") == 0) { - string [int] options; - if (in_ronin()) { - options.listAppend("Regen ~17 MP/adventure."); - options.listAppend("+20 ML."); - options.listAppend("+3 all resistances."); - } - options.listAppend("+10 familiar weight."); - - string [int] description; - if (options.count() > 1) - description.listAppend("Choose one of:|*" + options.listJoinComponents("|*")); - else - description.listAppend(options.listJoinComponents("|")); - optional_task_entries.listAppend(ChecklistEntryMake("__item Fourth of May Cosplay Saber", "main.php?action=may4", ChecklistSubentryMake("Modify your lightsaber", "", description), 8).ChecklistEntrySetIDTag("Fourth may saber daily upgrade")); - } - - - monster saber_monster = get_property_monster("_saberForceMonster"); - if (saber_monster != $monster[none]) { - int fights_left = clampi(get_property_int("_saberForceMonsterCount"), 0, 3); - location [int] possible_appearance_locations = saber_monster.getPossibleLocationsMonsterCanAppearInNaturally().listInvert(); - - if (fights_left > 0 && possible_appearance_locations.count() > 0) - optional_task_entries.listAppend(ChecklistEntryMake("__monster " + saber_monster, possible_appearance_locations[0].getClickableURLForLocation(), ChecklistSubentryMake("Fight " + pluralise(fights_left, "more " + saber_monster, "more " + saber_monster + "s"), "", "Will appear when you adventure in " + possible_appearance_locations.listJoinComponents(", ", "or") + "."), -1).ChecklistEntrySetIDTag("Fourth may saber friend copies")); - } -} - -RegisterResourceGenerationFunction("IOTMMaySaberGenerateResource"); -void IOTMMaySaberGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[Fourth of May Cosplay Saber]]) - return; - - if (my_path().id == PATH_G_LOVER) return; // cannot use saber in g-lover - - int sabersEquipped = lookupItem("Fourth of May Cosplay Saber").equipped_amount() + lookupItem("replica Fourth of May Cosplay Saber").equipped_amount(); - - int uses_remaining = clampi(5 - get_property_int("_saberForceUses"), 0, 5); - - if (uses_remaining > 0) { - if (true) { - //The section that will be sent as a stand-alone resource - string url; - if (sabersEquipped == 0) - url = "inventory.php?ftext=fourth+of+may+cosplay+saber"; - - string [int] description; - description.listAppend("Use the force skill in combat, which lets you:"); - description.listAppend("Banish a monster for thirty turns."); - description.listAppend("Make the monster appear 3x times its zone."); - description.listAppend("Or collect all* their items."); - if (my_path().id == PATH_COMMUNITY_SERVICE && $skill[Meteor Lore].have_skill()) - description.listAppend("Bonus! Use Meteor Shower + lightsaber skill to save a bunch of turns on weapon damage/spell damage/familiar weight tests."); - - resource_entries.listAppend(ChecklistEntryMake("__item Fourth of May Cosplay Saber", url, ChecklistSubentryMake(uses_remaining.pluralise("force use", "forces uses"), "", description)).ChecklistEntrySetIDTag("Fourth may saber force resource")); //"forces uses"? typo or reference/joke? - } - - if (true) { - //The section that will be sent as a "banish" tile - string [int] description; - if (sabersEquipped == 0) - description.listAppend(HTMLGenerateSpanFont("Equip the Fourth of May saber first", "red")); - else - description.listAppend("Rollover runaway-like/banish"); - - resource_entries.listAppend(ChecklistEntryMake("__item Fourth of May Cosplay Saber", "inventory.php?which=2", ChecklistSubentryMake("(up to) " + uses_remaining.pluralise("force banish", "forces banishes"), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Fourth may saber force banish")); - } - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2019/Pizza Cube.ash b/Source/relay/TourGuide/Items of the Month/2019/Pizza Cube.ash deleted file mode 100644 index 4011df26..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/Pizza Cube.ash +++ /dev/null @@ -1,62 +0,0 @@ -RegisterResourceGenerationFunction("IOTMPizzaCube"); -void IOTMPizzaCube(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[lookupItem("diabolic pizza cube")] || (fullness_limit() - my_fullness() < 3)) return; - - ChecklistSubentry getQuestItems() { - // Title - string main_title = "Make pizza"; - - // Subtitle - string subtitle = "Some ingredients give useful items"; - - // Entries - string [int] description; - - boolean need_cheese = !__quest_state["Trapper"].state_boolean["Past mine"] && $item[goat cheese].available_amount() < 3; - - if (need_cheese) { - description.listAppend(HTMLGenerateSpanOfClass("\"cheese\"/\"milk\":", "r_bold") + " 3 goat cheese"); - } - description.listAppend(HTMLGenerateSpanOfClass("\"luck\"/\"green\":", "r_bold") + " clover"); - description.listAppend(HTMLGenerateSpanOfClass("familiar equipment/hatchling:", "r_bold") + " equipment + xp for your familiar"); - description.listAppend(HTMLGenerateSpanOfClass("\"cloak\":", "r_bold") + " dead mimic"); - description.listAppend(HTMLGenerateSpanOfClass("combat item:", "r_bold") + " 3 of sonar-in-a-biscuit, Duskwalker syringe, cocktail napkin, unnamed cocktail, cigarette lighter, glark cable, short writ of habeas corpus"); - - return ChecklistSubentryMake(main_title, subtitle, description); - } - - ChecklistSubentry getBuffs() { - // Title - string main_title = "Buffs"; - - // Subtitle - string subtitle = ""; - - // Entries - string [int] description; - - description.listAppend("Get any wishable buff"); - - return ChecklistSubentryMake(main_title, subtitle, description); - } - - ChecklistEntry entry; - entry.image_lookup_name = "__item diabolic pizza"; - entry.url = "campground.php?action=workshed"; - entry.tags.id = "Diabolic pizza cube resource"; - - ChecklistSubentry questItems = getQuestItems(); - if (questItems.entries.count() > 0) { - entry.subentries.listAppend(questItems); - } - - ChecklistSubentry buffs = getBuffs(); - if (buffs.entries.count() > 0) { - entry.subentries.listAppend(buffs); - } - - if (entry.subentries.count() > 0) { - resource_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2019/Pocket Professor.ash b/Source/relay/TourGuide/Items of the Month/2019/Pocket Professor.ash deleted file mode 100644 index ef2db71f..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/Pocket Professor.ash +++ /dev/null @@ -1,129 +0,0 @@ -RegisterResourceGenerationFunction("IOTMPocketProfessorResource"); -void IOTMPocketProfessorResource(ChecklistEntry [int] resource_entries) -{ - ChecklistSubentry getLecture() { - int lecturesAtWeight(int weight, boolean chipEquipped) { - return floor(sqrt(weight - 1)) + 1 + (chipEquipped ? 2 : 0); - } - - // Title - int lecturesUsed = get_property_int("_pocketProfessorLectures"); - int potentialWeight = effective_familiar_weight($familiar[Pocket Professor]) + weight_adjustment(); - int potentialWeightChip = potentialWeight - round(equipped_item($slot[familiar]).numeric_modifier('familiar weight')); - boolean chipEquipped = lookupItem("pocket professor memory chip").have_equipped(); - - int availableLectures = lecturesAtWeight(potentialWeight, chipEquipped) - lecturesUsed; - int nextLectureWeight = lecturesUsed ** 2 + 1; - int nextLectureWeightChip = (lecturesUsed - 2) ** 2 + 1; - - string main_title = (availableLectures > 0 ? pluralise(availableLectures, "lecture", "lectures") : "No lectures") + " available, " + lecturesUsed + " lectures used"; - - // Subtitle - string subtitle = ""; - - // Entries - string [int] description; - if (availableLectures > 0) { - description.listAppend(HTMLGenerateSpanOfClass("Relativity:", "r_bold") + " Fight monster again."); - description.listAppend(HTMLGenerateSpanOfClass("Mass:", "r_bold") + " 3 chances for item drops."); - description.listAppend(HTMLGenerateSpanOfClass("Velocity:", "r_bold") + " Delevel and substats."); - } else { - string noChipMessage = nextLectureWeight + " lbs (+" + (nextLectureWeight - potentialWeight) + " lbs)"; - string chipMessage = nextLectureWeightChip + " lbs (+" + (nextLectureWeightChip - potentialWeightChip) + " lbs)"; - if (!chipEquipped) { - if (nextLectureWeightChip <= potentialWeightChip) { - description.listAppend("Next lecture at " + noChipMessage + ", or now with chip."); - } else { - description.listAppend("Next lecture at " + noChipMessage + ", " + chipMessage + " with chip."); - } - } else { - description.listAppend("Next lecture at " + chipMessage + "."); - } - } - if (get_property("_feastedFamiliars").contains_text("Pocket Professor")) { - description.listAppend(HTMLGenerateSpanFont("Warning: Numbers may not be correct if Moveable Feast has expired.", "red")); - } - - return ChecklistSubentryMake(main_title, subtitle, description); - } - - string scalerMessage(string name, int add, int cap) { - int thesisAdventures(int hp) { - return clampi(2 * floor(hp ** .25), 0, 11); - } - - int ml = numeric_modifier('monster level'); - int muscle = my_buffedstat($stat[muscle]); - int defense = clampi(muscle + add, 0, cap) + ml; - int hp = max(floor(0.75 * defense), 1); - int adventures = thesisAdventures(hp); - string description = name + " (" + adventures + " advs"; - if (adventures < 11 && cap + ml >= 1296 / .75) { - int nextAdventures = adventures + 2; - int nextThreshhold = (nextAdventures / 2) ** 4; - int muscleToCap = ceil(nextThreshhold / .75 - ml - add); - description += ", +" + (muscleToCap - muscle) + " mus for " + clampi(nextAdventures, 0, 11) + " advs"; - } - description += ")"; - return description; - } - - ChecklistSubentry getDeliverYourThesis() { - int experience = $familiar[Pocket Professor].experience; - int experienceLeft = 400 - experience; - - // Title - string main_title = "Deliver thesis"; - - // Subtitle - string subtitle = ""; - - // Entries - string [int] description; - if (!get_property_boolean("_thesisDelivered")) { - if (experience >= 400) { - description.listAppend(HTMLGenerateSpanOfClass("1 instakill", "r_bold") + " but lose 200 familiar xp."); - } else { - description.listAppend("Need " + experienceLeft + " more experience."); - } - - string [int] potential_targets; - - // we don't need to support replicas here because you'll never have pocket prof + replica kramco! - - if (lookupItem("kramco sausage-o-matic").available_amount() > 0) - { - potential_targets.listAppend(scalerMessage("Sausage goblin", 11, 10000)); - } - if (get_property_boolean("neverendingPartyAlways") || get_property_boolean("_neverendingPartyToday")) - { - potential_targets.listAppend(scalerMessage("Neverending Party monster", 0, 20000)); - } - if (potential_targets.count() > 0) { - description.listAppend("Could use it on a:" + HTMLGenerateIndentedText(potential_targets)); - } - } - - return ChecklistSubentryMake(main_title, subtitle, description); - } - - if (!lookupFamiliar("Pocket Professor").familiar_is_usable()) return; - - ChecklistEntry entry; - entry.image_lookup_name = "__familiar pocket professor"; - entry.tags.id = "Pocket professor familiar resource"; - - ChecklistSubentry lectures = getLecture(); - if (lectures.entries.count() > 0) { - entry.subentries.listAppend(lectures); - } - - ChecklistSubentry thesis = getDeliverYourThesis(); - if (thesis.entries.count() > 0) { - entry.subentries.listAppend(thesis); - } - - if (entry.subentries.count() > 0) { - resource_entries.listAppend(entry); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2019/Red Nosed Snapper.ash b/Source/relay/TourGuide/Items of the Month/2019/Red Nosed Snapper.ash deleted file mode 100644 index a78800eb..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/Red Nosed Snapper.ash +++ /dev/null @@ -1,380 +0,0 @@ -RegisterTaskGenerationFunction("IOTMRedNosedSnapperTask"); -void IOTMRedNosedSnapperTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!lookupFamiliar("Red Nosed Snapper").familiar_is_usable()) return; - if (my_familiar() != lookupFamiliar("Red Nosed Snapper")) return; - - phylum current_snapper_phylum = get_property("redSnapperPhylum").to_phylum(); - - if (current_snapper_phylum == $phylum[none]) { - optional_task_entries.listAppend(ChecklistEntryMake("__familiar red-nosed snapper", "familiar.php?action=guideme&pwd=" + my_hash(), ChecklistSubentryMake("Track monsters", "+ of them and gives items", "Choose a phylum".HTMLGenerateSpanOfClass("r_element_important")), 8).ChecklistEntrySetIDTag("Red nosed snapper familiar set tracking")); - return; - } - - - //Check if the currently tracked phylum is undoing a banish - location l = __last_adventure_location; - if (!__setting_location_bar_uses_last_location && !get_property_boolean("_relay_guide_setting_ignore_next_adventure_for_location_bar") && get_property_location("nextAdventure") != $location[none]) //want to mimic location bar popup, so they can look at it for information - l = get_property_location("nextAdventure"); - - monster [int] banishes_undone_by_snapper; - foreach index, monstr in l.get_monsters() - if (monstr.phylum == current_snapper_phylum && monstr.is_banished()) - banishes_undone_by_snapper.listAppend(monstr); - - if (banishes_undone_by_snapper.count() > 0) { - string title = "Your Snapper is undoing a banish".HTMLGenerateSpanOfClass("r_element_important"); - task_entries.listAppend(ChecklistEntryMake("__familiar red-nosed snapper", "familiar.php?action=guideme&pwd=" + my_hash(), ChecklistSubentryMake(title, "Change tracked phylum or switch familiar", "Bringing your snapper while it is tracking " + current_snapper_phylum + " is unbanishing " + banishes_undone_by_snapper.listJoinComponents(", ", "and")), -10).ChecklistEntrySetIDTag("Red nosed snapper familiar warning")); - - ChecklistEntry pop_up_reminder_entry = ChecklistEntryMake("__familiar red-nosed snapper", "", ChecklistSubentryMake(title), -11); - pop_up_reminder_entry.tags.id = "Red nosed snapper familiar popup"; - pop_up_reminder_entry.only_show_as_extra_important_pop_up = true; - pop_up_reminder_entry.container_div_attributes["onclick"] = "navbarClick(0, 'Tasks_checklist_container')"; - pop_up_reminder_entry.container_div_attributes["class"] = "r_clickable"; - task_entries.listAppend(pop_up_reminder_entry); - } -} - -RegisterResourceGenerationFunction("IOTMRedNosedSnapperResource"); -void IOTMRedNosedSnapperResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("Red Nosed Snapper").familiar_is_usable()) return; - - boolean always_display = false; //user-preference - - if (my_familiar() != lookupFamiliar("Red Nosed Snapper") && !__misc_state["in run"] && !always_display) return; - - //beast = +5 cold res (not a lot of places to go for those, esp. since it's for a quite optional effect...) - //bug = +100% HP, 8-10 HP regen (spleen) (not really... useful enough to mention those outside of the zones having them..?) - //constellation = Yellow ray - //construct = +150% init (spleen) - //demon = +5 hot res (suggested in a zone that already has one (haunted kitchen)) (there's some hellseals, though..?) - //dude = All-day free (3x/day) banish item - //elemental = +50% MP, 3-5 MP regen (spleen) (would recommend the snowman ninja lair, but we can't know if they chose hippy route instead; we know when they ARE there...) - //elf = +50% candy (not encountered in-run, nor has... any... use?) - //fish = Fishy (spleen) - //goblin = 3-size food - //hippy = +5 stench res - //hobo = +100% meat (spleen) (only seen in overgrown lot, sleazy back alley, or hobopolis) - //horror = 5x/day free kill - //humanoid = +50% muscle stats (spleen) - //mer-kin = +30% underwater items - //orc = 3-size booze - //penguin = gives meat (never useful, nor encountered in run, really) - //pirate = +50% moxie stats (spleen) - //plant = Full HP restore in combat - //slime = +5 sleaze res (would be good for bridge, but there's very few slimes before that...) - //undead = +5 spooky res - //weird = +50% myst stats (spleen) (way too rare in-run to recommend) - - boolean going_in_Degrassi_Knoll = !knoll_available() && my_path().id != PATH_NUCLEAR_AUTUMN && !__misc_state["desert beach available"] && __misc_state["guild open"]; - boolean making_Junk_Junk = !__misc_state["mysterious island available"] && __quest_state["Old Landfill"].in_progress; - boolean Azazel_quest_is_in_progress = __quest_state["Azazel"].in_progress && !in_bad_moon() && $locations[The Laugh Floor, Infernal Rackets Backstage].turnsAttemptedInLocation() > 0; - boolean nemesis_quest_at_clown_house = __quest_state["Nemesis"].mafia_internal_step == 6; - boolean nemesis_quest_at_Fungal_Nethers = $ints[13,14,15] contains __quest_state["Nemesis"].mafia_internal_step; - boolean cyrpt_modern_zmobies_are_appreciated = !__quest_state["Cyrpt"].state_boolean["alcove finished"] && __quest_state["Cyrpt"].state_int["alcove evilness"] > 1; - boolean at_chasm_bridge = __quest_state["Highland Lord"].mafia_internal_step == 1; - boolean past_chasm_bridge = __quest_state["Highland Lord"].mafia_internal_step > 1; - boolean want_more_rusty_hedge_trimmers = __quest_state["Highland Lord"].state_boolean["can complete twin peaks quest quickly"] && __quest_state["Highland Lord"].state_int["twin peak progress"] < 15 && $item[rusty hedge trimmers].available_amount() < __quest_state["Highland Lord"].state_int["peak tests remaining"]; - boolean looking_for_mining_gear = __quest_state["Trapper"].in_progress && !__quest_state["Trapper"].state_boolean["Past mine"] && __quest_state["Trapper"].state_string["ore needed"].to_item().available_amount() < 3 && !have_outfit_components("Mining Gear") && my_path().id != PATH_AVATAR_OF_BORIS && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST; - boolean they_may_be_ninjas = __quest_state["Trapper"].state_boolean["Past mine"] && ($location[lair of the ninja snowmen].turns_spent > 0 || $location[the extreme slope].turns_spent == 0); - boolean have_some_pirating_to_do = __misc_state["mysterious island available"] && __quest_state["Pirate Quest"].state_boolean["valid"] && !__quest_state["Island War"].state_boolean["War in progress"]; - boolean have_access_to_giant_castle = $item[s.o.c.k.].available_amount() > 0 || my_path().id == PATH_EXPLOSION; - boolean top_floor_done = __quest_state["Castle"].mafia_internal_step > 10 && $location[the hole in the sky].locationAvailable(); - boolean going_in_the_HITS = $location[the hole in the sky].locationAvailable() && $item[richard\'s star key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["Richard's star key used"]; - boolean exploring_desert = __quest_state["Level 11"].in_progress && !__quest_state["Level 11 Desert"].state_boolean["Desert Explored"]; - boolean at_hidden_city = __quest_state["Hidden Temple Unlock"].finished && __quest_state["Level 11 Hidden City"].in_progress; - boolean have_more_dense_lianas_to_fight = at_hidden_city && __quest_state["Level 11 Hidden City"].state_int["lianas left"] > 0; - boolean making_wine_bomb = __quest_state["Level 11 Manor"].mafia_internal_step == 3 && get_property("spookyravenRecipeUsed") == "with_glasses"; - boolean helping_Yossarian = __quest_state["Island War"].state_boolean["War in progress"] && !__quest_state["Island War"].state_boolean["Junkyard Finished"]; - boolean fighting_filthworms = __quest_state["Island War"].state_boolean["War in progress"] && !__quest_state["Island War"].state_boolean["Orchard Finished"] && my_path().id != PATH_2CRS; - boolean CS_need_to_pass_hot_res_test = my_path().id == PATH_COMMUNITY_SERVICE && !(get_property("csServicesPerformed").split_string_alternate(",").listInvert() contains "Clean Steam Tunnels"); - - - string [int] currentlyReachableInstancesOfPhylum(phylum phyl) { - string [int] reachable_instances; - if (phyl == $phylum[constellation] && !$location[the hole in the sky].locationAvailable()) - reachable_instances.listAppend("Unreachable"); - - switch (phyl) { - case $phylum[beast]: //twin peak topiary animals (is that really all there is to "good" beasts locations?) - if (past_chasm_bridge && want_more_rusty_hedge_trimmers) - reachable_instances.listAppend("twin peak topiary animals"); - break; - - case $phylum[bug]: //desert and filthworms - if (exploring_desert) - reachable_instances.listAppend("arid, extra-dry desert"); - if (fighting_filthworms) - reachable_instances.listAppend("filthworms"); - break; - - case $phylum[constellation]: //Hole in the Sky, and nothing else - if (going_in_the_HITS) - reachable_instances.listAppend("hole in the sky"); - break; - - case $phylum[construct]: //monstrous boiler and wine rack - if (making_wine_bomb) { - if ($item[unstable fulminate].available_amount() == 0 && $item[bottle of Chateau de Vinegar].available_amount() == 0) - reachable_instances.listAppend("wine rack"); - reachable_instances.listAppend("monstrous boiler"); - } - break; - - case $phylum[demon]: //(some) hellseals and demons from friars and hey-deze - if (my_class() == $class[seal clubber] && my_level() >= 5) - reachable_instances.listAppend("figurine of " + (my_level() >= 6 ? "ancient" : "cute baby") + " seal"); - if (__quest_state["Friars"].in_progress) - reachable_instances.listAppend("dark X of the woods (friars)"); - if (Azazel_quest_is_in_progress) - reachable_instances.listAppend("Hey Deze"); - break; - - case $phylum[dude]: //they're everywhere!!!! (I'm not even gonna TRY to do anything past that.) - reachable_instances.listAppend("too many to count"); - break; - - case $phylum[elemental]: //ninja snowmen, not really worth it, though..? - if (they_may_be_ninjas && !__quest_state["Trapper"].state_boolean["Mountain climbed"]) - reachable_instances.listAppend("ninja snowmen"); - break; - - case $phylum[elf]: //can't reach, nor want, in-run - break; - - case $phylum[fish]: //can't reach, nor want, in-run - break; - - case $phylum[goblin]: //kramco & cobbs knob - if (lookupItem("Kramco Sausage-o-Matic™").available_amount() > 0) - reachable_instances.listAppend("kramco sausage goblins"); - if (!__quest_state["Knob Goblin King"].finished) - reachable_instances.listAppend("cobbs knob"); - break; - - case $phylum[hippy]: //hippy camp - if (__misc_state["mysterious island available"] && __quest_state["Island War"].state_string["Side seemingly fighting for"] != "hippy") - reachable_instances.listAppend(__quest_state["Island War"].state_boolean["War in progress"] ? "war hippies" : "The Hippy Camp"); - break; - - case $phylum[hobo]: //no hobos in one's normal path. There's some in the wrong side of the track, but we don't recommend they go there for that. - break; - - case $phylum[horror]: //(some) hellseals and clowns - if (my_class() == $class[seal clubber]) - reachable_instances.listAppend("figurine of wretched-looking" + (my_level() >= 9 ? "/armored" : "") + " seal"); - if (nemesis_quest_at_clown_house) - reachable_instances.listAppend("clown fun house"); - break; - - case $phylum[humanoid]: //Degrassi Knoll, castle giants, old landfill, 7-foot dwarves, Junkyard gremlins - if (going_in_Degrassi_Knoll) - reachable_instances.listAppend("Degrassi Knoll"); - if (have_access_to_giant_castle && !top_floor_done) - reachable_instances.listAppend("castle giants"); - if (making_Junk_Junk) - reachable_instances.listAppend("old landfill"); - if (looking_for_mining_gear) - reachable_instances.listAppend("7-foot dwarves"); - if (helping_Yossarian) - reachable_instances.listAppend("island junkyard"); - break; - - case $phylum[mer-kin]: //can't reach, nor want, in-run - break; - - case $phylum[orc]: //smut orc logging camp and frat boys/warriors - if (at_chasm_bridge) - reachable_instances.listAppend("smut orcs"); - if (__misc_state["mysterious island available"] && __quest_state["Island War"].state_string["Side seemingly fighting for"] != "frat boys") - reachable_instances.listAppend("frat " + (__quest_state["Island War"].state_boolean["War in progress"] ? "warriors" : "boys")); - break; - - case $phylum[penguin]: //can't reach, nor want, in-run - break; - - case $phylum[pirate]: //pirate cove - if (have_some_pirating_to_do) - reachable_instances.listAppend("pirate cove"); - break; - - case $phylum[plant]: //fungal nethers and dense lianas - if (nemesis_quest_at_Fungal_Nethers) - reachable_instances.listAppend("fungal nethers"); - if (have_more_dense_lianas_to_fight) - reachable_instances.listAppend("dense lianas"); - break; - - case $phylum[slime]: //oil peak (yes, I KNOW that the +5 sleaze res is supposed to be for the BRIDGE BUILDING, but there's just no consistent source of slimes before that; go cry me a river won't you) - if (past_chasm_bridge && __quest_state["Highland Lord"].state_float["oil peak pressure"] > 0.0) - reachable_instances.listAppend("oil peak"); - break; - - case $phylum[undead]: //The whole spookyraven manor, or the cyrpt - if (__quest_state["Manor Unlock"].in_progress) - reachable_instances.listAppend("Spookyraven manor"); - if (__quest_state["Cyrpt"].in_progress) - reachable_instances.listAppend("Cyrpt"); - break; - - case $phylum[weird]: //I've got nuthin', they are too rare in-run - break; - } - return reachable_instances; - } - - - boolean [phylum] want_phylum_drop; - if (true) { //always up for those if available: - want_phylum_drop[$phylum[constellation]] = true; //yellow-ray - want_phylum_drop[$phylum[dude]] = true; //banish - want_phylum_drop[$phylum[horror]] = true; //free kill - want_phylum_drop[$phylum[hobo]] = true; //+100% meat - } - - if (false) { //those just... don't have an use - want_phylum_drop[$phylum[elf]] = true; //+50% candy drop - want_phylum_drop[$phylum[penguin]] = true; //an envelope which gives some meat... - want_phylum_drop[$phylum[bug]] = true; //+100% HP, ~9HP regen (not really worth it...) - } - - if (__misc_state["in run"]) { - if (__misc_state["need to level"]) - switch (my_primestat()) { //+50% gains - case $stat[muscle]: - want_phylum_drop[$phylum[humanoid]] = true; break; - case $stat[mysticality]: - want_phylum_drop[$phylum[weird]] = true; break; - case $stat[moxie]: - want_phylum_drop[$phylum[pirate]] = true; break; - } - - if (!__quest_state["Level 13"].state_boolean["Init race completed"] || cyrpt_modern_zmobies_are_appreciated) - want_phylum_drop[$phylum[construct]] = true; //+150% initiative - - if (my_path().id != PATH_COMMUNITY_SERVICE && $item[Spookyraven billiards room key].available_amount() == 0 && get_property_int("manorDrawerCount") < 20) { - if (numeric_modifier("hot resistance") < 7) - want_phylum_drop[$phylum[demon]] = true; //+5 hot res - if (numeric_modifier("stench resistance") < 7) - want_phylum_drop[$phylum[hippy]] = true; //+5 stench res - } else if (CS_need_to_pass_hot_res_test) - want_phylum_drop[$phylum[demon]] = true; //demon again; +5 hot res - - if (past_chasm_bridge) { - if (__quest_state["Highland Lord"].state_boolean["can complete twin peaks quest quickly"] && !__quest_state["Highland Lord"].state_boolean["Peak Stench Completed"] && numeric_modifier("stench resistance") <= 1.0) //if they have 2 or 3, they don't need a plus-FIVE - want_phylum_drop[$phylum[hippy]] = true; //hippy again; +5 stench res - - if (__quest_state["Highland Lord"].state_int["a-boo peak hauntedness"] > 2) { - want_phylum_drop[$phylum[beast]] = true; //+5 cold res - want_phylum_drop[$phylum[undead]] = true; //+5 spooky res - } - } else if (at_chasm_bridge) - want_phylum_drop[$phylum[slime]] = true; //+5 sleaze res - - if (they_may_be_ninjas && !__quest_state["Trapper"].state_boolean["Groar defeated"] && numeric_modifier("cold resistance") < 3.0) //if they have 3 or 4, they don't need a plus-FIVE - want_phylum_drop[$phylum[beast]] = true; //beast again; +5 cold res - - if (!lookupItem("Eight Days a Week Pill Keeper").have()) - want_phylum_drop[$phylum[elemental]] = true; //+50% MP, ~4MP regen - - if (__quest_state["Lair"].state_boolean["shadow will need to be defeated"]) - want_phylum_drop[$phylum[plant]] = true; - } else if (__quest_state["Sea Monkees"].in_progress || __quest_state["Sea Temple"].in_progress || __quest_state["Sea Monkees"].state_string["skate park status"] == "war") { - want_phylum_drop[$phylum[fish]] = true; //fishy - want_phylum_drop[$phylum[mer-kin]] = true; //+30% underwater items (meh...) - } - - if (in_ronin() && my_path().id != PATH_NUCLEAR_AUTUMN) { - if (fullness_limit() >= 3) - want_phylum_drop[$phylum[goblin]] = true; //size 3 awesome food - if (inebriety_limit() >= 3) - want_phylum_drop[$phylum[orc]] = true; //size 3 awesome booze - } - - - boolean [phylum] current_location_phylums; - foreach index, monstr in __last_adventure_location.get_monsters() - current_location_phylums[monstr.phylum] = true; - - phylum current_snapper_phylum = get_property("redSnapperPhylum").to_phylum(); - - //The selection presented to the player. The currently tracked phylum and those present in the current locations will always be in there - //This is meant to inform the player on the DROPS they can get, NOT on which phylum they could track to help progress (at least it's not the focus here) - boolean [phylum] phylum_display_list; - string [phylum] [int] reachable_options; - - foreach phyl in $phylums[] { - string [int] options = currentlyReachableInstancesOfPhylum(phyl); - - if (phyl == current_snapper_phylum) //obviously show the one they are tracking - phylum_display_list[phyl] = true; - else if (current_location_phylums contains phyl) //show those in the current location - phylum_display_list[phyl] = true; - else if (want_phylum_drop[phyl] && (options.count() > 0 || !__misc_state["in run"]) && options[0] != "Unreachable") - phylum_display_list[phyl] = true; - - reachable_options[phyl] = options; - } - - int progress = get_property_int("redSnapperProgress"); - - string title = "Track monsters"; - if (current_snapper_phylum != $phylum[none]) - title = (11 - progress).pluralise(current_snapper_phylum + " kill", current_snapper_phylum + " kills") + " until next Snapper drop"; - - string [int] description; - - if (progress > 0) - description.listAppend("Changing phylum resets progress."); - - string [phylum] snapper_drop = { - $phylum[beast]:"+5 " + "cold".HTMLGenerateSpanOfClass("r_element_cold") + " res (20 turns)", - $phylum[bug]:"+100% HP, 8-10 HP regen (1 spleen, 60 turns)", - $phylum[constellation]:"Yellow ray item (150 turns of Ev. Looks Yellow)", - $phylum[construct]:"+150% init (1 spleen, 30 turns)", - $phylum[demon]:"+5 " + "hot".HTMLGenerateSpanOfClass("r_element_hot") + " res (20 turns)", - $phylum[dude]:"All-day free (3x/day) banish item", - $phylum[elemental]:"+50% MP, 3-5 MP regen (1 spleen, 60 turns)", - $phylum[elf]:"+50% candy (20 turns)", - $phylum[fish]:"Fishy (1 spleen, 30 turns)", - $phylum[goblin]:"3-size " + "awesome".HTMLGenerateSpanOfClass("r_element_awesome") + " food", - $phylum[hippy]:"+5 " + "stench".HTMLGenerateSpanOfClass("r_element_stench") + " res (20 turns)", - $phylum[hobo]:"+100% meat (1 spleen, 60 turns)", - $phylum[horror]:"5x/day free kill item", - $phylum[humanoid]:"+50% muscle stats (1 spleen, 30 turns)", - $phylum[mer-kin]:"+30% underwater items (20 turns)", - $phylum[orc]:"3-size " + "awesome".HTMLGenerateSpanOfClass("r_element_awesome") + " booze", - $phylum[penguin]:"(500 + 500 * +meat%) meat item", - $phylum[pirate]:"+50% moxie stats (1 spleen, 30 turns)", - $phylum[plant]:"Full HP restore combat item", - $phylum[slime]:"+5 " + "sleaze".HTMLGenerateSpanOfClass("r_element_sleaze") + " res (20 turns)", - $phylum[undead]:"+5 " + "spooky".HTMLGenerateSpanOfClass("r_element_spooky") + " res (20 turns)", - $phylum[weird]:"+50% myst stats (1 spleen, 30 turns)" - }; - - foreach phyl in phylum_display_list { - string line; - if (current_location_phylums contains phyl) - line += "• "; - if (current_snapper_phylum == phyl) - line += __html_right_arrow_character; - line += capitaliseFirstLetter(phyl + ": ").HTMLGenerateSpanOfClass("r_bold"); - line += snapper_drop[phyl]; - - - //FIXME Is there a "good" way to add reachable_options to this? - - //remember to add a string HTMLGenerateSimpleTableLines(string [int] lines) to page.ash if ending up using this - /*if (reachable_options[phyl].count() > 0 && false) { - buffer tooltip; - tooltip.append(reachable_options[phyl].HTMLGenerateSimpleTableLines().HTMLGenerateSpanOfClass("r_tooltip_inner_class r_tooltip_inner_class_margin")); - tooltip.append(line); - line = tooltip.HTMLGenerateSpanOfClass("r_tooltip_outer_class"); - }*/ - - description.listAppend(line); - } - - resource_entries.listAppend(ChecklistEntryMake("__familiar red-nosed snapper", "familiar.php?action=guideme&pwd=" + my_hash(), ChecklistSubentryMake(title, "+1 item / 11 kills of tracked phylum", description)).ChecklistEntrySetIDTag("Red nosed snapper familiar tracking drops resource")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2019/Rune Spoon.ash b/Source/relay/TourGuide/Items of the Month/2019/Rune Spoon.ash deleted file mode 100644 index d3542cd8..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/Rune Spoon.ash +++ /dev/null @@ -1,88 +0,0 @@ - -//moonTuned -RegisterResourceGenerationFunction("IOTMRuneSpoonGenerateResource"); -void IOTMRuneSpoonGenerateResource(ChecklistEntry [int] resource_entries) -{ - item spoon = lookupItem("hewn moon-rune spoon"); - if (!__iotms_usable[lookupItem("hewn moon-rune spoon")] && spoon.closet_amount() == 0 || my_sign().to_lower_case() == "bad moon") return; - if (my_path().id == PATH_G_LOVER) return; // glover does not get spoon tuning - - // Use the right item ID depending on if you are using a replica or a non-replica - string activeSpoonID = lookupItem("replica hewn moon-rune spoon").available_amount() > 0 ? "11242" : "10254"; - - if (!get_property_boolean("moonTuned")) - { - stat [string] stat_for_sign = - { - "Mongoose":$stat[Muscle], - "Wallaby":$stat[Mysticality], - "Vole":$stat[Moxie], - - "Platypus":$stat[Muscle], - "Opossum":$stat[Mysticality], - "Marmot":$stat[Moxie], - - "Wombat":$stat[Muscle], - "Blender":$stat[Mysticality], - "Packrat":$stat[Moxie], - }; - string [string] signs = - { - "Mongoose":"+20% physical damage, knoll access, and free smithing", - "Wallaby":"+20% spell damage, knoll access, and free smithing", - "Vole":"+20% init, knoll access, and free smithing", - - "Platypus":"+5 familiar weight and canadia access", - "Opossum":"+5 adventures/day from food and canadia access", - "Marmot":"+1 all resistance and canadia access", - - "Wombat":"+20% meat and gnome access", - "Blender":"+5 adventures/day from drinks and gnome access", - "Packrat":"+10% item and gnome access", - - }; - boolean [string] signs_to_output_as_ideas = $strings[Marmot,Platypus,Opossum,Blender,Packrat]; - - if (!__misc_state["in run"]) - signs_to_output_as_ideas = $strings[Platypus,Opossum,Wombat,Blender,Packrat]; - boolean our_sign_is_currently_good_for_stats = stat_for_sign[my_sign()] == my_primestat(); - string [int] description; - description.listAppend("Use the hewn moon-rune spoon. Lets you switch to any other moon sign."); - if ($strings[Mongoose,Wallaby,Vole] contains my_sign()) - { - string [int] todo; - if (!__misc_state["desert beach available"]) - todo.listAppend("assemble a bitchin' meatcar"); - if (!have_outfit_components("Bugbear Costume")) - todo.listAppend("buy a bugbear costume"); - if (todo.count() > 0) - description.listAppend("May want to " + todo.listJoinComponents(", ", "and") + " before switching signs."); - } - string [int] options; - - foreach sign, desc in signs - { - if (my_sign() == sign) continue; - if (!signs_to_output_as_ideas[sign]) continue; - if (sign == "Platypus" && __misc_state["familiars temporarily blocked"]) continue; - if (sign == "Opossum" && (!__misc_state["can eat just about anything"] || my_path().id == PATH_SLOW_AND_STEADY)) continue; - if (sign == "Blender" && (!__misc_state["can drink just about anything"] || my_path().id == PATH_SLOW_AND_STEADY)) continue; - boolean this_sign_is_good_for_mainstat_gain = stat_for_sign[sign] == my_primestat(); - string line = "" + sign + ": " + desc + "."; - if (!this_sign_is_good_for_mainstat_gain && __misc_state["need to level"] && __misc_state["in run"]) - line += " Won't give mainstat gains."; - else if (this_sign_is_good_for_mainstat_gain && __misc_state["need to level"] && __misc_state["in run"]) - line += " Will give mainstat gains."; - options.listAppend(line); - } - - description.listAppend("Currently " + my_sign() + ": " + signs[my_sign()] + "."); - if (options.count() > 0) - description.listAppend("Ideas:|*" + options.listJoinComponents("
")); - - string url = "inv_use.php?whichitem=" + activeSpoonID + "&pwd=" + my_hash(); - if (!__iotms_usable[lookupItem("hewn moon-rune spoon")] && spoon.closet_amount() > 0) - url = "closet.php?which=2"; - resource_entries.listAppend(ChecklistEntryMake("__item " + spoon, url, ChecklistSubentryMake("Moon sign tunable", "", description), 10).ChecklistEntrySetIDTag("Roon spoon moon boon toon moon")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2019/Vampire Cloak.ash b/Source/relay/TourGuide/Items of the Month/2019/Vampire Cloak.ash deleted file mode 100644 index acf2e6b0..00000000 --- a/Source/relay/TourGuide/Items of the Month/2019/Vampire Cloak.ash +++ /dev/null @@ -1,19 +0,0 @@ - -RegisterResourceGenerationFunction("IOTMVampireCloakGenerateResource"); -void IOTMVampireCloakGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[vampyric cloake]]) return; - if (!(__misc_state["in run"] && in_ronin())) return; - - int uses_left = clampi(10 - get_property_int("_vampyreCloakeFormUses"), 0, 10); - if (uses_left > 0 && __iotms_usable[$item[vampyric cloake]] && my_path().id != PATH_POCKET_FAMILIARS) { - string [int] skills; - skills.listAppend("Wolf: +50% muscle, +50% meat"); - skills.listAppend("Mist: +2 all res"); - skills.listAppend("Bat: +50% item"); - - string [int] description; - description.listAppend("In-combat cast one of the Become skills, to gain a buff for that fight:|*" + skills.listJoinComponents("|*")); - resource_entries.listAppend(ChecklistEntryMake("__item vampyric cloake", !$item[vampyric cloake].equipped() ? $item[vampyric cloake].invSearch() : "", ChecklistSubentryMake(pluralise(uses_left, "vampyric skill use", "vampyric skill uses"), "", description), 5).ChecklistEntrySetIDTag("Vampyric cloake combat skills resource")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2020/Better Shrooms and Gardens.ash b/Source/relay/TourGuide/Items of the Month/2020/Better Shrooms and Gardens.ash deleted file mode 100644 index 26f08e4e..00000000 --- a/Source/relay/TourGuide/Items of the Month/2020/Better Shrooms and Gardens.ash +++ /dev/null @@ -1,96 +0,0 @@ -RegisterResourceGenerationFunction("IOTMBetterShroomsAndGardensGenerateResource"); -void IOTMBetterShroomsAndGardensGenerateResource(ChecklistEntry [int] resource_entries) -{ - ChecklistSubentry getFreeFights() { - int freeFightsUsed = get_property_int("_mushroomGardenFights"); - int totalFreeFights = 1; - - if (my_path().id == PATH_OF_THE_PLUMBER) { - totalFreeFights = 5; - } - int freeFightsLeft = totalFreeFights - freeFightsUsed; - - // Title - string main_title = pluralise(freeFightsLeft,"Piranha Plant fight","Piranha Plant fights"); - - // Subtitle - string subtitle = ""; - - // Entries - string [int] description; - if (freeFightsLeft > 0) { - description.listAppend("Free fight."); - if (my_path().id == PATH_OF_THE_PLUMBER) { - description.listAppend("Drops extra coins and mushrooms."); - } - } - - return ChecklistSubentryMake(main_title, subtitle, description); - } - - ChecklistSubentry getMushroomState() { - int mushroomLevel = get_property_int("mushroomGardenCropLevel"); - int expectedFilets = MIN(3, mushroomLevel)*3; - int expectedSlabs = clampi(mushroomLevel - 3, 0, 2); - - // Title - string main_title = "Upkeep your mushroom"; - - // Subtitle - string subtitle = "One action per day"; - - // Entries - string [int] description; - - string [int] shroomYield; - string [int] futureYield; - if (!get_property_boolean("_mushroomGardenVisited")) { - description.listAppend("Mushroom is at tier " + mushroomLevel); - shroomYield.listAppend(expectedFilets + " filets"); - if (mushroomLevel > 3) - shroomYield.listAppend( pluralise(expectedSlabs,"slab","slabs") ); - - if (mushroomLevel < 2) - futureYield.listAppend("+3 filets at tier 2"); - if (mushroomLevel < 3) - futureYield.listAppend("+3 filets at tier 3"); - if (mushroomLevel < 4) - futureYield.listAppend("+1 slab at tier 4"); - if (mushroomLevel < 5) - futureYield.listAppend("+1 slab at tier 5"); - - if (mushroomLevel > 10) - shroomYield.listAppend("A mushroom house"); - else - futureYield.listAppend("+1 mushroom house at tier 11"); - - description.listAppend("Harvesting now will give:" + HTMLGenerateIndentedText(shroomYield)); - description.listAppend( mushroomLevel > 10 ? HTMLGenerateSpanOfClass("No reason to fertilize any longer", "r_bold") : to_buffer("Otherwise, fertilize it, incrementing its size:" + HTMLGenerateIndentedText(futureYield)) ); - } - - return ChecklistSubentryMake(main_title, subtitle, description); - } - - if (!__iotms_usable[lookupItem("packet of mushroom spores")]) return; - - ChecklistEntry entry; - entry.image_lookup_name = "__item Better Shrooms and Gardens catalog"; - entry.url = "campground.php"; - entry.tags.id = "Mushroom garden resource"; - - ChecklistSubentry piranhas = getFreeFights(); - if (piranhas.entries.count() > 0) { - entry.subentries.listAppend(piranhas); - // Want this part to appear both in the garden's tile, and the free fights tile, so making a new entry - resource_entries.listAppend(ChecklistEntryMake("__item Better Shrooms and Gardens catalog", "campground.php", piranhas).ChecklistEntrySetCombinationTag("daily free fight")); - } - - ChecklistSubentry shroom = getMushroomState(); - if (shroom.entries.count() > 0) { - entry.subentries.listAppend(shroom); - } - - if (entry.subentries.count() > 0) { - resource_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2020/Bird-a-Day Calendar.ash b/Source/relay/TourGuide/Items of the Month/2020/Bird-a-Day Calendar.ash deleted file mode 100644 index 4d741a3a..00000000 --- a/Source/relay/TourGuide/Items of the Month/2020/Bird-a-Day Calendar.ash +++ /dev/null @@ -1,138 +0,0 @@ -RegisterTaskGenerationFunction("IOTMBirdADayGenerateTasks"); -void IOTMBirdADayGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[$item[Bird-a-Day calendar]]) return; - if (!get_property_boolean("_canSeekBirds")) { - string [int] description; - - description.listAppend("Use your calendar to get a new skill for the day."); - if (have_effect($effect[Blessing of the Bird]) > 0) - description.listAppend(HTMLGenerateSpanFont("Still have an old blessing", "red") + "|Using the calendar will replace the old buff's modifiers with the new ones."); - - optional_task_entries.listAppend(ChecklistEntryMake("__effect Blessing of the Bird", "inventory.php?ftext=bird-a-day+calendar", ChecklistSubentryMake("Discover your daily Bird", "", description), 8).ChecklistEntrySetIDTag("Bird-a-day calendar")); - } -} - -RegisterResourceGenerationFunction("IOTMBirdADayCalendar"); -void IOTMBirdADayCalendar(ChecklistEntry [int] resource_entries) -{ - ChecklistSubentry getBirdMods() { - - string birdMods = get_property("_birdOfTheDayMods"); - int birdsSought = get_property_int("_birdsSoughtToday"); - - // Title - string main_title = "Seek birds! " + birdsSought + " birds sought today"; - - // Subtitle - string subtitle = "10 Turn Buff"; - - // Entries - string [int] description; - int mp_cost = 5 * 2**(birdsSought); - description.listAppend("Currently costs " + mp_cost + " MP to watch."); - description.listAppend("Seek up to 6 times and still keep your old favorite."); - description.listAppend("Must make it your new favorite to watch 7 or more times."); - if (get_property_boolean("_canSeekBirds")) { - string [int] modStrings = birdMods.split_string(", "); - foreach index, modString in modStrings { - string [int] modProperties = modString.split_string(": "); - string modName = modProperties[0]; - string modValue = modProperties[1]; - - string name = modName + ": "; - switch(modName) { - case "Cold Resistance": - name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_cold"); - break; - case "Hot Resistance": - name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_hot"); - break; - case "Sleaze Resistance": - name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_sleaze"); - break; - case "Spooky Resistance": - name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_spooky"); - break; - case "Stench Resistance": - name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_stench"); - break; - } - - description.listAppend(HTMLGenerateSpanOfClass(name, "r_bold") + modValue); - } - } - - return ChecklistSubentryMake(main_title, subtitle, description); - } - - ChecklistSubentry getFavoriteBird() { - - string favoriteBirdMods = get_property("yourFavoriteBirdMods"); - boolean canSeekFavBird = have_skill($skill[Visit your Favorite Bird]); - - // Title - string main_title = "Favorite"; - - // Subtitle - string subtitle = "20 Turn Buff"; - - // Entries - string [int] description; - - if (favoriteBirdMods != "" && canSeekFavBird && !get_property_boolean("_favoriteBirdVisited")) { - string [int] modStrings = favoriteBirdMods.split_string(", "); - foreach index, modString in modStrings { - string [int] modProperties = modString.split_string(": "); - string modName = modProperties[0]; - string modValue = modProperties[1]; - - string name = modName + ": "; - switch(modName) { - case "Cold Resistance": - name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_cold"); - break; - case "Hot Resistance": - name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_hot"); - break; - case "Sleaze Resistance": - name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_sleaze"); - break; - case "Spooky Resistance": - name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_spooky"); - break; - case "Stench Resistance": - name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_stench"); - break; - } - - description.listAppend(HTMLGenerateSpanOfClass(name, "r_bold") + modValue); - } - } - - return ChecklistSubentryMake(main_title, subtitle, description); - } - - - if (!__iotms_usable[$item[Bird-a-Day calendar]]) - return; - - ChecklistEntry entry; - entry.image_lookup_name = "__effect Blessing of the Bird"; - entry.url = "skillz.php"; - entry.tags.id = "Bird-a-day cast"; - - ChecklistSubentry birdMods = getBirdMods(); - if (birdMods.entries.count() > 0) { - entry.subentries.listAppend(birdMods); - } - - ChecklistSubentry favoriteBird = getFavoriteBird(); - if (favoriteBird.entries.count() > 0) { - entry.subentries.listAppend(favoriteBird); - } - - if (entry.subentries.count() > 0) { - resource_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2020/Box O Ghosts.ash b/Source/relay/TourGuide/Items of the Month/2020/Box O Ghosts.ash deleted file mode 100644 index c3540cf8..00000000 --- a/Source/relay/TourGuide/Items of the Month/2020/Box O Ghosts.ash +++ /dev/null @@ -1,34 +0,0 @@ -//Ghost of Crimbo Commerce -RegisterTaskGenerationFunction("IOTMCommerceGhostGenerateTasks"); -void IOTMCommerceGhostGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - item commerce_item = get_property_item("commerceGhostItem"); - int commerce_statgain1 = (my_level() * 20) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); - int commerce_statgain2 = (my_level() * 25) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); - boolean in_grey_you = my_class() == $class[grey goo]; // Grey You gains zero stats from your commerce ghost. - - if (__misc_state["in run"] && $familiar[Ghost of Crimbo Commerce].familiar_is_usable() && !in_grey_you) - { - // Title - string url = "familiar.php"; - string title = get_property("commerceGhostCombats") + "/11 Commerce Ghost combats"; - string [int] description; - description.listAppend(HTMLGenerateSpanFont("Don't", "red") + " " + HTMLGenerateSpanFont("ask", "green") + " " + HTMLGenerateSpanFont("questions,", "red") + " " + HTMLGenerateSpanFont("just", "green") + " " + HTMLGenerateSpanFont("consume", "red") + " " + HTMLGenerateSpanFont("product", "green") + " " + HTMLGenerateSpanFont("and", "red") + " " + HTMLGenerateSpanFont("then", "green") + " " + HTMLGenerateSpanFont("get", "red") + " " + HTMLGenerateSpanFont("excited", "green") + " " + HTMLGenerateSpanFont("for", "red") + " " + HTMLGenerateSpanFont("new", "green") + " " + HTMLGenerateSpanFont("products.", "red")); - description.listAppend("Gain ~" + commerce_statgain1 + "-" + commerce_statgain2 + " to all 3 substats."); - description.listAppend("Wins, losses, banishes, anything works."); - - if (commerce_item != $item[none]) - { - string title = "Give yourself the gift of getting!"; - description.listAppend(HTMLGenerateSpanFont("Buy", "red") + " " + HTMLGenerateSpanFont("buy ", "green") + " " + HTMLGenerateSpanFont("buy", "red") + " " + HTMLGenerateSpanFont("buy ", "green") + " " + HTMLGenerateSpanFont("buy!", "red")); - - string url = "mall.php?justitems=0&pudnuggler=%22" + commerce_item + "%22"; - - description.listAppend("Buy " + commerce_item + " to get ~" + commerce_statgain1 + "-" + commerce_statgain2 + " to all 3 substats!"); - description.listAppend(HTMLGenerateSpanFont("Buy", "green") + " " + HTMLGenerateSpanFont("buy ", "red") + " " + HTMLGenerateSpanFont("buy ", "green") + " " + HTMLGenerateSpanFont("buy", "red") + " " + HTMLGenerateSpanFont("buy!", "green")); - - task_entries.listAppend(ChecklistEntryMake("__familiar Ghost of Crimbo Commerce", url, ChecklistSubentryMake(title, description), -11)); - } - optional_task_entries.listAppend(ChecklistEntryMake("__familiar Ghost of Crimbo Commerce", url, ChecklistSubentryMake(title, description))); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2020/Cargo Cultist Shorts.ash b/Source/relay/TourGuide/Items of the Month/2020/Cargo Cultist Shorts.ash deleted file mode 100644 index 0a4b2e5c..00000000 --- a/Source/relay/TourGuide/Items of the Month/2020/Cargo Cultist Shorts.ash +++ /dev/null @@ -1,43 +0,0 @@ -RegisterResourceGenerationFunction("IOTMCargoCultistShortsGenerateResource"); -void IOTMCargoCultistShortsGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[Cargo Cultist Shorts]]) return; - - if (!get_property_boolean("_cargoPocketEmptied")) { - string image_name = "__item cargo cultist shorts"; - - boolean [int] empty_pockets; - string [int] empty_pocket_list = split_string(get_property("cargoPocketsEmptied"), ","); - foreach _, pocket in empty_pocket_list { - empty_pockets[to_int(pocket)] = true; - } - - string [int] options; - string [int] description; - description.listAppend("Pick a pocket for something useful! Too many to list!"); - if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) - { - if (locationAvailable($location[The royal guard Chamber]) == true && !(empty_pockets contains 343)) - { - options.listAppend(HTMLGenerateSpanOfClass("343 - Filthworm Drone Stench:", "r_bold") + " Stinky!"); - } - if ($item[star chart].available_amount() == 0 && $item[richard's star key].available_amount() == 0 && !(empty_pockets contains 533)) - { - options.listAppend(HTMLGenerateSpanOfClass("533 - greasy desk bell:", "r_bold") + " star key components"); - } - if (locationAvailable($location[The eXtreme Slope]) == false && !(empty_pockets contains 565)) - { - options.listAppend(HTMLGenerateSpanOfClass("565 - mountain man:", "r_bold") + " YR for 2x ore"); - } - if (locationAvailable($location[The Battlefield (Frat Uniform)]) == false && !(empty_pockets contains 589)) - { - options.listAppend(HTMLGenerateSpanOfClass("589 - Green Ops Soldier:", "r_bold") + " olfact for funny meme strategies."); - } - - } - if (options.count() > 0) - description.listAppend("Potentially pickable pockets:|*" + options.listJoinComponents("|*")); - - resource_entries.listAppend(ChecklistEntryMake("__item cargo cultist shorts", "inventory.php?action=pocket", ChecklistSubentryMake("Cargo shorts pocket openable", "", description), 1).ChecklistEntrySetIDTag("Cargo shorts resource")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2020/Comprehensive Cartography.ash b/Source/relay/TourGuide/Items of the Month/2020/Comprehensive Cartography.ash deleted file mode 100644 index 9a85522e..00000000 --- a/Source/relay/TourGuide/Items of the Month/2020/Comprehensive Cartography.ash +++ /dev/null @@ -1,100 +0,0 @@ -//comprehensive cartography -RegisterTaskGenerationFunction("IOTMComprehensiveCartographyGenerateTasks"); -void IOTMComprehensiveCartographyGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!lookupSkill("Comprehensive Cartography").have_skill()) return; - if (get_property_boolean("mappingMonsters")) { - task_entries.listAppend(ChecklistEntryMake("__skill Map the Monsters", "", ChecklistSubentryMake("Mapping the Monsters now!", "", "Fight a chosen monster in the next zone."), -11).ChecklistEntrySetIDTag("Cartography skill map now")); - } -} - -RegisterResourceGenerationFunction("IOTMComprehensiveCartographyGenerateResource"); -void IOTMComprehensiveCartographyGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupSkill("Comprehensive Cartography").have_skill()) - return; - int maps_left = clampi(3 - get_property_int("_monstersMapped"), 0, 3); - string [int] description; - string [int] options; - string [int] monsterMaps; - if (maps_left > 0) - { - description.listAppend("Map the monsters you want to fight!"); - - if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) - { - //automatic carto NCs - description.listAppend("This IotM also gives you a special noncom in the following zones:"); - int cartoAbooAscension = get_property_int("lastCartographyBooPeak"); - if (my_ascensions() > cartoAbooAscension) { - options.listAppend(HTMLGenerateSpanOfClass("First adv", "r_bold") + " A-Boo Peak: free A-boo clue"); - } - int cartoCastleAscension = get_property_int("lastCartographyCastleTop"); - if (my_ascensions() > cartoCastleAscension) { - options.listAppend("Castle Top: finish quest"); - } - int cartoDarkNeckAscension = get_property_int("lastCartographyDarkNeck"); - if (my_ascensions() > cartoDarkNeckAscension) { - options.listAppend("The Dark Neck of the Woods: +2 progress"); - } - int cartoNookAscension = get_property_int("lastCartographyDefiledNook"); - if (my_ascensions() > cartoNookAscension) { - options.listAppend("The Defiled Nook: +2 Evil Eyes"); - } - int cartoFratAscension = get_property_int("lastCartographyFratHouse"); - if (my_ascensions() > cartoFratAscension) { - options.listAppend(HTMLGenerateSpanOfClass("First adv", "r_bold") + " Orcish Frat House: free garbage"); - } - int cartoGuanoAscension = get_property_int("lastCartographyGuanoJunction"); - if (my_ascensions() > cartoGuanoAscension) { - options.listAppend(HTMLGenerateSpanOfClass("First adv", "r_bold") + " Guano Junction: Screambat"); - } - int cartoBilliardsAscension = get_property_int("lastCartographyHauntedBilliards"); - if (my_ascensions() > cartoBilliardsAscension) { - options.listAppend("Haunted Billiards: play pool immediately"); - } - int cartoProtestersAscension = get_property_int("lastCartographyZeppelinProtesters"); - if (my_ascensions() > cartoProtestersAscension) { - options.listAppend("Mob of Zeppelin Protesters: pick any NC"); - } - int cartoWarFratAscension = get_property_int("lastCartographyFratHouseVerge"); - if (my_ascensions() > cartoWarFratAscension) { - options.listAppend("Wartime Frat House: pick any NC"); - } - int cartoWarHippyAscension = get_property_int("lastCartographyHippyCampVerge"); - if (my_ascensions() > cartoWarHippyAscension) { - options.listAppend("Wartime Hippy Camp: pick any NC"); - } - //monstermap options - if (!__quest_state["Level 11 Ron"].finished) - { - monsterMaps.listAppend("Red Butler, 30% free kill item and 15% fun drop item. Combine with Olfaction/Use the Force?"); - } - if (get_property_int("twinPeakProgress") < 15 && $item[rusty hedge trimmers].available_amount() < 4) - { - monsterMaps.listAppend("hedge beast, 15% quest progress item. Possibly Spit."); - } - if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0) - { - monsterMaps.listAppend("Whatsian Commander Ghost, 15% free runaway item. Possibly Spit."); - } - if ($item[star chart].available_amount() < 1 || $item[richard's star key].available_amount() < 1) - { - monsterMaps.listAppend("Astronomer"); - } - if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) - { - monsterMaps.listAppend("Lobsterfrogman, probably a weak option. Combine with Use the Force?"); - } - if ($location[The Battlefield (Frat Uniform)].turns_spent > 20) - { - monsterMaps.listAppend("Green Ops Soldier. Combine with Olfaction/Use the Force and Spit and Explodinal pills."); - } - if (options.count() > 0) - description.listAppend(HTMLGenerateSpanOfClass("Noncoms of interest:", "r_bold") + "|*-" + options.listJoinComponents("|*-")); - if (monsterMaps.count() > 0) - description.listAppend(HTMLGenerateSpanOfClass("Monsters to map:", "r_bold") + "|*-" + monsterMaps.listJoinComponents("|*-")); - } - resource_entries.listAppend(ChecklistEntryMake("__item Comprehensive Cartographic Compendium", "", ChecklistSubentryMake(pluralise(maps_left, "Cartography skill use", "Cartography skill uses"), "", description), 5).ChecklistEntrySetIDTag("Cartography skills resource")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2020/Guzzlr.ash b/Source/relay/TourGuide/Items of the Month/2020/Guzzlr.ash deleted file mode 100644 index de9eaec2..00000000 --- a/Source/relay/TourGuide/Items of the Month/2020/Guzzlr.ash +++ /dev/null @@ -1,183 +0,0 @@ -RegisterTaskGenerationFunction("IOTMGuzzlrGenerateTask"); -void IOTMGuzzlrGenerateTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - - if (!lookupItem("Guzzlr tablet").have()) return; - - boolean startedQuest = get_property("questGuzzlr") != "unstarted"; - string questTier = get_property("guzzlrQuestTier"); - - int guzzlrQuestProgressLeft = 100 - get_property_int("guzzlrDeliveryProgress"); - float guzzlrQuestIncrement = max(3, 10 - get_property_int("_guzzlrDeliveries")); - float guzzlrQuestShoedIncrement = floor(1.5 * guzzlrQuestIncrement); - int guzzlrQuestFightsLeft = ceil(guzzlrQuestProgressLeft / guzzlrQuestIncrement); - int guzzlrQuestShoedFightsLeft = ceil(guzzlrQuestProgressLeft / guzzlrQuestShoedIncrement); - - boolean hasShoes = lookupItem("Guzzlr shoes").available_amount() > 0; - boolean hasPants = lookupItem("Guzzlr pants").available_amount() > 0; - - if (startedQuest) { - boolean hasShoesEquipped = lookupItem("Guzzlr shoes").equipped_amount() > 0; - boolean hasPantsEquipped = lookupItem("Guzzlr pants").equipped_amount() > 0; - - location questLocation = get_property("guzzlrQuestLocation").to_location(); - item questBooze = get_property("guzzlrQuestBooze").to_item(); - boolean [item] questBoozePlatinum; - foreach platinumDrink in $strings[Steamboat, Ghiaccio Colada, Nog-on-the-Cob, Sourfinger, Buttery Boy] { - questBoozePlatinum [lookupItem(platinumDrink)] = true; - } - - boolean hasBooze = questTier == "platinum" ? questBoozePlatinum.item_amount() > 0 : questBooze.item_amount() > 0; - boolean hasBoozeSomewhere = questTier == "platinum" ? questBoozePlatinum.available_amount() + questBoozePlatinum.display_amount() > 0 : questBooze.available_amount() + questBooze.display_amount() > 0; - - boolean oneFightRemains = hasShoesEquipped && guzzlrQuestShoedFightsLeft <= 1 || !hasShoesEquipped && guzzlrQuestFightsLeft <= 1; - - string subtitle = "free fights"; - initialiseLocationCombatRates(); //not done anywhere else in this script - if (__location_combat_rates contains questLocation) { - int rate = __location_combat_rates [questLocation]; - - if (rate == -1) //if unknown - subtitle += ", +combat"; - else if (rate != 100 && rate != 0) - subtitle += ", +" + (100 - rate) + "% combat"; - } else //if unlisted - subtitle += ", +combat"; - - string [int] description; - - if (hasBooze) { - description.listAppend("Deliver " + (questTier == "platinum" ? "platinum booze" : questBooze) + " by adventuring in " + questLocation + "."); - } else { - string color_of_reminder_to_get_drink = __last_adventure_location == questLocation ? "red" : "dark"; - - if (questTier == "platinum") { - int [item] creatablePlatinumDrinks = questBoozePlatinum.creatable_items(); - buffer message; - - message.append(HTMLGenerateSpanFont("Obtain one of the following:", color_of_reminder_to_get_drink)); - message.append(to_buffer("| • Steamboat" + (creatablePlatinumDrinks contains lookupItem("Steamboat") ? " (can make with a miniature boiler)" : "") + " | • Ghiaccio Colada" + (creatablePlatinumDrinks contains lookupItem("Ghiaccio Colada") ? " (can make with a cold wad)" : "") + " | • Nog-on-the-Cob" + (creatablePlatinumDrinks contains lookupItem("Nog-on-the-Cob") ? " (can make with a robin's egg)" : "") + " | • Sourfinger" + (creatablePlatinumDrinks contains lookupItem("Sourfinger") ? " (can make with a mangled finger)" : "") + " | • Buttery Boy" + (creatablePlatinumDrinks contains lookupItem("Buttery Boy") ? " (can make with a Dish of Clarified Butter)" : "") ) ); - description.listAppend(message); - - if (hasBoozeSomewhere) { - string [int] goLookThere; - - if (get_property_boolean("autoSatisfyWithStorage") && questBoozePlatinum.storage_amount() > 0 && can_interact()) - goLookThere.listAppend("in hagnk's storage"); - if (get_property_boolean("autoSatisfyWithCloset") && questBoozePlatinum.closet_amount() > 0) - goLookThere.listAppend("in your closet"); - if (get_property_boolean("autoSatisfyWithStash") && questBoozePlatinum.stash_amount() > 0) - goLookThere.listAppend("in your clan stash"); - if (questBoozePlatinum.display_amount() > 0) // there's no relevant mafia property; is never taken into consideration - goLookThere.listAppend("in your display case"); - - description.listAppend("Go look " + (goLookThere.count() > 0 ? goLookThere.listJoinComponents(", ", "or") + "." : "...somewhere?")); - } - } else { - description.listAppend(HTMLGenerateSpanFont("Obtain a " + questBooze + ".", color_of_reminder_to_get_drink)); - if (hasBoozeSomewhere) { - string [int] goLookThere; - - if (get_property_boolean("autoSatisfyWithStorage") && questBooze.storage_amount() > 0 && can_interact()) - goLookThere.listAppend(questBooze.storage_amount() + " in hagnk's storage"); - if (get_property_boolean("autoSatisfyWithCloset") && questBooze.closet_amount() > 0) - goLookThere.listAppend(questBooze.closet_amount() + " in your closet"); - if (get_property_boolean("autoSatisfyWithStash") && questBooze.stash_amount() > 0) - goLookThere.listAppend(questBooze.stash_amount() + " in your clan stash"); - if (questBooze.display_amount() > 0) - goLookThere.listAppend(questBooze.display_amount() + " in your display case"); - - description.listAppend("Have " + (goLookThere.count() > 0 ? goLookThere.listJoinComponents(", ", "and") + "." : "some... somewhere..?")); - } - - if (questBooze.creatable_amount() > 0) - description.listAppend("Could craft one."); - } - } - - if (guzzlrQuestProgressLeft == 1 || guzzlrQuestShoedFightsLeft == 1) - { - if (hasShoesEquipped) - description.listAppend("Takes " + pluralise(guzzlrQuestShoedFightsLeft, "more fight", "more fights") + " (" + guzzlrQuestFightsLeft + " without shoes)."); - else { - if (hasShoes) description.listAppend(HTMLGenerateSpanFont("Equip your Guzzlr shoes for quicker deliveries.", "red")); - } - #task_entries.listAppend(ChecklistEntryMake("__item Guzzlr tablet", "inventory.php?tap=guzzlr", ChecklistSubentryMake("Guzzlr delivery", "", description), -11)); - task_entries.listAppend(ChecklistEntryMake("__item Guzzlr tablet", questLocation.getClickableURLForLocation(), ChecklistSubentryMake("Guzzlr delivery", subtitle, description), -11, boolean [location] {questLocation:true}).ChecklistEntrySetIDTag("Guzzlr quest task")); - } - - if (guzzlrQuestProgressLeft <= 0) - description.listAppend("Shouldn't this be over already?"); - else if (guzzlrQuestProgressLeft == 1) - description.listAppend(HTMLGenerateSpanFont("Delivery on next fight", "blue")); - else if (guzzlrQuestShoedFightsLeft == 1) - description.listAppend(HTMLGenerateSpanFont("Equip shoes to receive delivery on next fight", "blue")); - else if (!hasShoes || guzzlrQuestFightsLeft == guzzlrQuestShoedFightsLeft) // if no shoes or if doesn't matter at that point - description.listAppend("Takes " + pluralise(guzzlrQuestFightsLeft, "more fight", "more fights") + "."); - else if (hasShoesEquipped) - description.listAppend("Takes " + pluralise(guzzlrQuestShoedFightsLeft, "more fight", "more fights") + " (" + guzzlrQuestFightsLeft + " without shoes)."); - else { - description.listAppend("Takes " + guzzlrQuestFightsLeft + " more fights (" + guzzlrQuestShoedFightsLeft + " with shoes)."); - description.listAppend(HTMLGenerateSpanFont("Equip your Guzzlr shoes for quicker deliveries.", "red")); - } - - if (hasPants && !hasPantsEquipped) - description.listAppend(HTMLGenerateSpanFont("Equip your Guzzlr pants for more Guzzlrbucks.", (oneFightRemains ? "red" : "dark"))); - - if (!hasShoes) - description.listAppend(HTMLGenerateSpanFont("Could buy Guzzlr shoes for quicker deliveries.", "grey")); - if (!hasPants) - description.listAppend(HTMLGenerateSpanFont("Could buy Guzzlr pants for more Guzzlrbucks.", "grey")); - - optional_task_entries.listAppend(ChecklistEntryMake("__item Guzzlrbuck", questLocation.getClickableURLForLocation(), ChecklistSubentryMake("Deliver booze", subtitle, description), boolean [location] {questLocation:true}).ChecklistEntrySetIDTag("Guzzlr quest task")); - } - - - if (true) { // for either telling the player to accept a quest, or reminding them if they can abandon it - boolean canAbandonQuest = !get_property_boolean("_guzzlrQuestAbandoned"); - int platinumDeliveriesLeft = 1 - get_property_int("_guzzlrPlatinumDeliveries"); - int goldDeliveriesLeft = 3 - get_property_int("_guzzlrGoldDeliveries"); - int bronzeDeliveriesTotal = get_property_int("guzzlrBronzeDeliveries"); - boolean canAcceptPlatinum = get_property_int("guzzlrGoldDeliveries") >= 5; - boolean canAcceptGold = bronzeDeliveriesTotal >= 5; - - string main_title; - string subtitle; - string [int] description; - - if (startedQuest && canAbandonQuest) { - main_title = "Can abandon quest"; - description.listAppend("I mean... if you think you're not up to it..."); - if (questTier == "platinum") { - description.listAppend("Do this to keep the Guzzlr cocktail set for yourself"); - } - } else if (!startedQuest) { - if (__misc_state["in run"] && platinumDeliveriesLeft > 0 && canAcceptPlatinum) { - main_title = "Get your daily Guzzlr cocktail set"; - subtitle = "Accept a platinum quest"; - description.listAppend(canAbandonQuest ? "Then, abandon the quest." : "Will be stuck with this quest for the rest of the day."); - } else if (!__misc_state["in run"]) { - main_title = "Accept a booze delivery quest"; - string [int] chooseDeliveryMessage; - - if (bronzeDeliveriesTotal < 196) - chooseDeliveryMessage.listAppend("• Bronze"); - - if (goldDeliveriesLeft > 0 && canAcceptGold) - chooseDeliveryMessage.listAppend("• Gold " + HTMLGenerateSpanFont("(" + goldDeliveriesLeft + " available)", "grey")); - - if (platinumDeliveriesLeft > 0 && canAcceptPlatinum) - chooseDeliveryMessage.listAppend("• Platinum " + HTMLGenerateSpanFont("(" + platinumDeliveriesLeft + " available)", "grey") + (canAbandonQuest ? " (Abandon for free cocktail set?)" : "")); - - if (chooseDeliveryMessage.count() > 0) { - description.listAppend("Start a delivery by choosing a client:" + chooseDeliveryMessage.HTMLGenerateIndentedText()); - description.listAppend("Will take " + (hasShoes ? guzzlrQuestShoedFightsLeft + "-" : "") + guzzlrQuestFightsLeft + " fights."); - if (canAbandonQuest) - description.listAppend("Can abandon 1 more quest today."); - } - } - } - - if (description.count() > 0) - optional_task_entries.listAppend(ChecklistEntryMake("__item Guzzlr tablet", "inventory.php?tap=guzzlr", ChecklistSubentryMake(main_title, subtitle, description)).ChecklistEntrySetIDTag("Guzzlr tablet tap")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2020/Melodramedary.ash b/Source/relay/TourGuide/Items of the Month/2020/Melodramedary.ash deleted file mode 100644 index 81ba3cb4..00000000 --- a/Source/relay/TourGuide/Items of the Month/2020/Melodramedary.ash +++ /dev/null @@ -1,65 +0,0 @@ -RegisterTaskGenerationFunction("IOTMMelodramedaryGenerateTasks"); -void IOTMMelodramedaryGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_familiar() != lookupFamiliar("Melodramedary")) return; - - if (get_property_int("camelSpit") == 100) - task_entries.listAppend(ChecklistEntryMake("__familiar Melodramedary", "familiar.php", ChecklistSubentryMake("Melodramedary: Locked and Loaded!", "", HTMLGenerateSpanFont("Spit!", "blue")), -11).ChecklistEntrySetIDTag("Melodramedary familiar spit ready")); -} - -RegisterResourceGenerationFunction("IOTMMelodramedaryResource"); -void IOTMMelodramedaryResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("Melodramedary").familiar_is_usable()) return; - - int spit_o_meter = get_property_int("camelSpit"); - - if (!__misc_state["in run"] && spit_o_meter < 100 && my_familiar() != lookupFamiliar("Melodramedary")) return; - - string title; - string [int] description; - - if (spit_o_meter < 100) { - title = spit_o_meter + "% Melodramedary Spit Charge"; - - boolean camelCapped = lookupFamiliar("Melodramedary").familiar_equipped_equipment() == lookupItem("dromedary drinking helmet"); - int fights_left = floor((101 - spit_o_meter) / 3.33); - if (camelCapped) - fights_left = ceil(fights_left / 1.3); - - description.listAppend("Ready in " + (camelCapped ? "~" : "") + fights_left.pluralise("fight", "fights") + "."); - } else { - title = "Melodramedary: Locked and Loaded!"; - description.listAppend(HTMLGenerateSpanFont("Spit!", "blue")); - } - - description.listAppend("Spit on self for 15 turns of +100% stats & weapon/spell dmg."); - description.listAppend("Spit on monsters to get 4x of each of their items (2x for conditional items)."); - //There are also certainly even more options of varying effectiveness. - - string [int] options; - if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) { - int bowling_progress = get_property_int("hiddenBowlingAlleyProgress"); - if (bowling_progress > 0 && bowling_progress < 7) { - int balls_needed = 6 - bowling_progress - $item[bowling ball].available_amount(); - if (balls_needed >= 2) - options.listAppend("Pygmy bowler; needs +150% item."); - } - - if (__quest_state["Level 9"].state_boolean["bridge complete"] && __quest_state["Level 9"].state_int["twin peak progress"] != 15 && $item[rusty hedge trimmers].available_amount() < __quest_state["Level 9"].state_int["peak tests remaining"] - 1) - options.listAppend("Hedge beast; needs +567% item."); - - if (__quest_state["Level 11 Ron"].mafia_internal_step == 3 || __quest_state["Level 11 Ron"].mafia_internal_step == 4) //Can't really compare with progress/cable uses for that day, since they could encounter red herring/snapper / wait for the next day - options.listAppend("Red butler; needs +234% item."); - - if (__quest_state["Level 12"].mafia_internal_step > 1 && !__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 4) - options.listAppend("Lobsterfrogman; prob. a weak option."); - - if (!__quest_state["Level 12"].finished && __quest_state["Level 12"].state_int["hippies left on battlefield"] > 0 && __quest_state["Level 12"].state_int["hippies left on battlefield"] <= 600 && __misc_state["yellow ray potentially available"]) - options.listAppend("Green Ops Soldier (for free runaways); needs yellow ray."); - } - if (options.count() > 0) - description.listAppend("Possible targets:" + options.listJoinComponents("
").HTMLGenerateIndentedText()); - - resource_entries.listAppend(ChecklistEntryMake("__familiar Melodramedary", "familiar.php", ChecklistSubentryMake(title, description), 1).ChecklistEntrySetIDTag("Melodramedary familiar resource")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2020/Powerful Glove.ash b/Source/relay/TourGuide/Items of the Month/2020/Powerful Glove.ash deleted file mode 100644 index c3c36026..00000000 --- a/Source/relay/TourGuide/Items of the Month/2020/Powerful Glove.ash +++ /dev/null @@ -1,43 +0,0 @@ -RegisterResourceGenerationFunction("IOTMPowerfulGloveGenerateResource"); -void IOTMPowerfulGloveGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[Powerful Glove]]) return; - if (my_path().id == PATH_G_LOVER) return; // while you can equip the glove, you can use none of the skills lol - - int chargeLeft = 100 - get_property_int("_powerfulGloveBatteryPowerUsed"); - - if (chargeLeft < 5) return; - - string url = "skillz.php"; - if (!$item[Powerful Glove].equipped()) - url = "inventory.php?ftext=powerful+glove"; - - string [int] description; - description.listAppend(HTMLGenerateSpanOfClass("Invisible Avatar (5% charge):", "r_bold") + " -10% combat."); - description.listAppend(HTMLGenerateSpanOfClass("Triple Size (5% charge):", "r_bold") + " +200% all attributes."); - if (chargeLeft >= 10) - description.listAppend(HTMLGenerateSpanOfClass("Replace Enemy (10% charge):", "r_bold") + " Swap monster."); - description.listAppend(HTMLGenerateSpanOfClass("Shrink Enemy (5% charge):", "r_bold") + " Delevel."); - - resource_entries.listAppend(ChecklistEntryMake("__item Powerful Glove", url, ChecklistSubentryMake(chargeLeft + "% Powerful Glove battery charge", "", description)).ChecklistEntrySetIDTag("Powerful glove skills resource")); -} - -RegisterTaskGenerationFunction("IOTMPowerfulGloveTask"); -void IOTMPowerfulGloveTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - // This doesn't have replica handling, but I don't really care -- you really only need this for Plumber now, and otherwise it's meh. - if (!__misc_state["in run"] || !$item[Powerful Glove].have() || $item[Powerful Glove].have_equipped()) return; - - boolean is_plumber = my_path().id == PATH_OF_THE_PLUMBER; - - string [int] glove_drops; - - if (!__quest_state["Level 13"].state_boolean["digital key used"] && $item[digital key].available_amount() + $item[digital key].creatable_amount() == 0) - glove_drops.listAppend("pixels"); - if (is_plumber) - glove_drops.listAppend("coins"); - - if (glove_drops.count() == 0) return; - - optional_task_entries.listAppend(ChecklistEntryMake("__item white pixel", "place.php?whichplace=forestvillage&action=fv_mystic", ChecklistSubentryMake("Equip Powerful Glove", "", "Get extra " + glove_drops.listJoinComponents(" and ") + "."), is_plumber ? -10 : 0).ChecklistEntrySetIDTag("Powerful glove equip reminder")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2020/Spinmaster Lathe.ash b/Source/relay/TourGuide/Items of the Month/2020/Spinmaster Lathe.ash deleted file mode 100644 index 9c923e5d..00000000 --- a/Source/relay/TourGuide/Items of the Month/2020/Spinmaster Lathe.ash +++ /dev/null @@ -1,12 +0,0 @@ -RegisterResourceGenerationFunction("IOTMSpinmasterLatheGenerateResource"); -void IOTMSpinmasterLatheGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (available_amount($item[SpinMaster™ lathe]) < 1 || !is_unrestricted($item[SpinMaster™ lathe])) return; - - if (!get_property_boolean("_spinmasterLatheVisited")) { - string image_name = "__item purpleheart logs"; - string description = "Get wood for an +xp weapon."; - - resource_entries.listAppend(ChecklistEntryMake("__item purpleheart logs", "inventory.php?ftext=spinmaster", ChecklistSubentryMake("SpinMaster lathe wood obtainable", "", description), 1).ChecklistEntrySetIDTag("SpinMaster lathe resource")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2020/Superhero Cape.ash b/Source/relay/TourGuide/Items of the Month/2020/Superhero Cape.ash deleted file mode 100644 index 4041d968..00000000 --- a/Source/relay/TourGuide/Items of the Month/2020/Superhero Cape.ash +++ /dev/null @@ -1,135 +0,0 @@ -/* RegisterTaskGenerationFunction("IOTMSuperheroCapeGenerateTasks"); -void IOTMSuperheroCapeGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - task_entries.listAppend(ChecklistEntryMake("__item unwrapped knock-off retro superhero cape", "", ChecklistSubentryMake("", "", ""), -11).ChecklistEntrySetIDTag("Superhero cape now")); -} */ - -RegisterResourceGenerationFunction("IOTMSuperheroCapeGenerateResource"); -void IOTMSuperheroCapeGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!mafiaIsPastRevision(20494)) return; - item cape = lookupItem("unwrapped knock-off retro superhero cape"); - if (!__iotms_usable[$item[unwrapped knock-off retro superhero cape]]) return; - - if (!__misc_state["in run"]) return; //Only relevant information in aftercore is YR, but the YR tile will already mention the cape if needed anyway, in aftercore. - - // Not too sure if this should even be kept? There's no real precedent of Guide showing a resource that "never ends"... - // We could make a new section that lists a player's possessions and everything special related to them, and this would go there, but currently... not too sure... - // To be clear, I'm not saying this should be erased, just... commented out for the time being? IDK... - - string current_hero = get_property("retroCapeSuperhero"); - string current_wash = get_property("retroCapeWashingInstructions"); - - record CapeConfiguration { - string hero_name; - string main_modifiers; - string [string] tmhmkmkm; - }; - - CapeConfiguration [string] cape_configurations = { - "vampire":new CapeConfiguration( - "Vampire Slicer", - "+30% muscle, +50 HP", - string [string] { - "hold":"+3 all resistances", - "thrill":"+3 muscle stats/fight", - "kiss":"Skill: Smooch of the Daywalker|Drain 20% of your foe's HP", - "kill":"Skill: Slay the Dead|Undead insta-bone (NOT free kill, requires sword).|+1% Cyrpt evilness reduction." - } - ), - "heck":new CapeConfiguration( - "Heck General", - "+30% myst, +50 MP", - string [string] { - "hold":"Auto 3 rounds stun at start of combats", - "thrill":"+3 myst stats/fight", - "kiss":"Skill: Unleash the Devil's Kiss|Yellow Ray (100 turns)", - "kill":"+100% (multiplicative) spell dmg, dealt as spooky dmg" - } - ), - "robot":new CapeConfiguration( - "Robot Police", - "+30% moxie, +25 HP/MP", - string [string] { - "hold":"Skill: Deploy Robo-Handcuffs|Stagger + 20% delevel 1x/fight", - "thrill":"+3 moxie stats/fight", - "kiss":"Skill: Blow a Robo-Kiss
Deal ~50 sleaze damage", - "kill":"Skill: Precision Shot|Stagger + critical hit (requires gun)." - } - ) - }; - - CapeConfiguration current_cape = cape_configurations[current_hero]; - - - ChecklistSubentry getCurrentCapeConfig() { - // Title - string main_title = "Superhero Cape"; - - // Subtitle - string main_hero = current_cape.hero_name != "" ? current_cape.hero_name : "unknown?"; - string subtitle = " (" + main_hero + " / " + current_wash + " me)"; - - // Entries - string [int] description; - if (cape_configurations contains current_hero) { - description.listAppend( current_cape.main_modifiers ); - description.listAppend( current_cape.tmhmkmkm[current_wash] ); - } - - return ChecklistSubentryMake(main_title, subtitle, description); - } - - - ChecklistSubentry usefulCapeConfigs() { - string main_title = "Useful configurations: "; - string [int] description; - string cape_stats; - switch ( my_primestat() ) { - case $stat[Muscle]: - cape_stats = "Vampire"; - break; - case $stat[Mysticality]: - cape_stats = "Heck"; - break; - case $stat[Moxie]: - cape_stats = "Robot"; - break; - } - if ( __misc_state["need to level"] && cape_stats != "" && (current_hero != cape_stats.to_lower_case() || current_wash != "thrill") ) - description.listAppend( HTMLGenerateSpanOfClass("Mainstat exp: ", "r_bold" ) + cape_stats + " + Thrill" ); - - if ( $effect[Everything looks yellow].have_effect() == 0 && (current_hero != "heck" || current_wash != "kiss") ) - description.listAppend( HTMLGenerateSpanOfClass("Yellow ray: ", "r_bold" ) + "Heck + Kiss" ); - - if ( current_hero != "vampire" || current_wash != "hold" ) - description.listAppend( HTMLGenerateSpanOfClass("+3 Res: ", "r_bold" ) + "Vampire + Hold" ); - - if ( current_hero != "vampire" || current_wash != "kill" ) //reminder: add this to the cyrpt tile - description.listAppend( HTMLGenerateSpanOfClass("Instakill / Cyrpt Evil: ", "r_bold" ) + "Vampire + Kill" ); - - return ChecklistSubentryMake(main_title, "", description); - } - - - ChecklistEntry entry; - entry.image_lookup_name = "__item unwrapped knock-off retro superhero cape"; - entry.url = cape.equipped() ? "inventory.php?action=hmtmkmkm" : cape.invSearch(); // we don't even need to change/adapt the name, kol recognizes it anyway! - entry.tags.id = "Superhero cape resource"; - entry.should_indent_after_first_subentry = true; - entry.importance_level = 5; - - ChecklistSubentry ccc = getCurrentCapeConfig(); - if ( ccc.entries.count() > 0 ) { - entry.subentries.listAppend(ccc); - } - - ChecklistSubentry ucc = usefulCapeConfigs(); - if ( ucc.entries.count() > 0 ) { - entry.subentries.listAppend(ucc); - } - - if ( entry.subentries.count() > 0 ) { - resource_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2021/Backup Camera.ash b/Source/relay/TourGuide/Items of the Month/2021/Backup Camera.ash deleted file mode 100644 index 083970af..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Backup Camera.ash +++ /dev/null @@ -1,33 +0,0 @@ -//Backup Camera -RegisterResourceGenerationFunction("IOTMBackupCameraGenerateResource"); -void IOTMBackupCameraGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupItem("backup camera").have()) return; - // Title - string main_title = "Back It Up, Back It Up"; - string [int] description; - - - // Entries - int backup_camera_snapsUsed = get_property_int("_backUpUses"); - int totalBackupCameras = 11; - if (my_path().id == PATH_YOU_ROBOT) { - totalBackupCameras = 16; - //for whatever awful reason, this is buggy and will miscount when you break prism until you relog - } - - string url = "inventory.php?ftext=backup+camera"; - int backup_camera_uses_remaining = totalBackupCameras - backup_camera_snapsUsed; - if (backup_camera_uses_remaining > 0) - { - string [int] description; - monster nostalgicMonster = (get_property_monster("lastCopyableMonster")); - description.listAppend(HTMLGenerateSpanFont(nostalgicMonster, "blue") + " is currently in your camera."); - - if (!lookupItem("backup camera").equipped()) - description.listAppend(HTMLGenerateSpanFont("Equip the backup camera first", "red")); - else - description.listAppend("Back up and fight your backup monster!"); - resource_entries.listAppend(ChecklistEntryMake("__item backup camera", url, ChecklistSubentryMake(backup_camera_uses_remaining + " backup camera snaps left", "", description)).ChecklistEntrySetIDTag("Backup camera skill resource")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2021/Cold Medicine Cabinet.ash b/Source/relay/TourGuide/Items of the Month/2021/Cold Medicine Cabinet.ash deleted file mode 100644 index ec9c733c..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Cold Medicine Cabinet.ash +++ /dev/null @@ -1,178 +0,0 @@ -RegisterTaskGenerationFunction("IOTMColdMedicineCabinetGenerateTasks"); -void IOTMColdMedicineCabinetGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - monster gregarious_monster = get_property_monster("beGregariousMonster"); - int fights_left = clampi(get_property_int("beGregariousFightsLeft"), 0, 3); - string [int] description; - - if (gregarious_monster != $monster[none] && fights_left > 0) - { - description.listAppend("Neaaaar, faaaaaaar, wherever you spaaaaaaar, I believe that the heart does go onnnnn."); - description.listAppend("Will appear in any zone, so try to find a zone with few monsters."); - optional_task_entries.listAppend(ChecklistEntryMake("__monster " + gregarious_monster, "url", ChecklistSubentryMake("Fight " + pluralise(fights_left, "more gregarious " + gregarious_monster, "more gregarious " + gregarious_monster + "s"), "", description), -1)); - } - if (!__iotms_usable[lookupItem("cold medicine cabinet")]) return; - - // Parsing the lastCombatEnvironments for a count of CMC combats. - string cmcCombatString = get_property("lastCombatEnvironments"); - string[int] splitCMC = split_string(cmcCombatString, ""); - int uTurns; - int iTurns; - int oTurns; - - foreach turn in splitCMC { - if (splitCMC[turn] == "i") {iTurns +=1;} - if (splitCMC[turn] == "u") {uTurns +=1;} - if (splitCMC[turn] == "o") {oTurns +=1;} - } - - string expectedSpleenItem = "Fleshazole"; - - if (uTurns > 10) expectedSpleenItem = "Breathitin"; - if (iTurns > 10) expectedSpleenItem = "Extrovermectin"; - if (oTurns > 10) expectedSpleenItem = "Homebodyl"; - - int CMC_consults = clampi(5 - get_property_int("_coldMedicineConsults"), 0, 5); - if (CMC_consults > 0) - { - int next_CMC_Turn = get_property_int("_nextColdMedicineConsult"); - int next_CMC_Timer = (next_CMC_Turn - total_turns_played()); - string [int] description; - string url = "campground.php?action=workshed"; - - if (next_CMC_Turn -1 == total_turns_played()) - { - description.listAppend(HTMLGenerateSpanFont("Consultation ready next turn!", "red")); - description.listAppend("You'll be prescribed " + HTMLGenerateSpanOfClass(expectedSpleenItem, "r_bold")); - description.listAppend("You have " + CMC_consults + " consultations remaining."); - task_entries.listAppend(ChecklistEntryMake("__item snow suit", url, ChecklistSubentryMake("The cold medicine cabinet is almost in session", "", description), -11)); - } - else if (next_CMC_Turn <= total_turns_played()) - { - description.listAppend(HTMLGenerateSpanFont("Just what the doctor ordered!", "blue")); - description.listAppend("You'll be prescribed " + HTMLGenerateSpanOfClass(expectedSpleenItem, "r_bold")); - description.listAppend("You have " + CMC_consults + " consultations remaining."); - task_entries.listAppend(ChecklistEntryMake("__item snow suit", url, ChecklistSubentryMake("The cold medicine cabinet is in session", "", description), -11)); - } - } -} - -RegisterResourceGenerationFunction("IOTMColdMedicineCabinetGenerateResource"); -void IOTMColdMedicineCabinetGenerateResource(ChecklistEntry [int] resource_entries) -{ - //gregariousness - int uses_remaining = get_property_int("beGregariousCharges"); - if (uses_remaining > 0) - { - if (true) - { - //The section that will be sent as a stand-alone resource - string url; - - string [int] description; - description.listAppend("Be gregarious in combat, which lets you turn foes into friends!"); - string [int] gregfriends; - gregfriends.listAppend("Bob Racecar, or his brother Racecar Bob"); - gregfriends.listAppend("dirty old lihc (cyrpt progress)"); - gregfriends.listAppend("lobsterfrogman (gunpowder)"); - gregfriends.listAppend("modern zmobie (cyrpt progress)"); - gregfriends.listAppend("dense liana (free fight)"); - gregfriends.listAppend("drunk pygmy (free fight)"); - gregfriends.listAppend("eldritch tentacle (free fight, difficult)"); - gregfriends.listAppend("lynyrd (free fight)"); - gregfriends.listAppend("[degenerate aftercore farming target]"); - description.listAppend("Potentially good friendships:|*" + gregfriends.listJoinComponents("|*")); - resource_entries.listAppend(ChecklistEntryMake("__effect Good Karma", url, ChecklistSubentryMake(uses_remaining.pluralise("gregarious handshake", "gregarious handshakes"), "", description)).ChecklistEntrySetIDTag("gregarious wanderer resource")); - } - } - - //breathitin - int breaths_remaining = get_property_int("breathitinCharges"); - if (breaths_remaining > 0) - { - string [int] description; - description.listAppend("Outdoor fights become free."); - resource_entries.listAppend(ChecklistEntryMake("__item beefy pill", "", ChecklistSubentryMake(pluralise(breaths_remaining, "breathitin breath", "breathitin breaths"), "", description), -2)); - } - - //homebodyl - int homebodyls_remaining = get_property_int("homebodylCharges"); - if (homebodyls_remaining > 0) - { - string [int] description; - description.listAppend("Free crafting."); - description.listAppend("Lynyrd equipment, potions, and more."); - resource_entries.listAppend(ChecklistEntryMake("__item excitement pill", "", ChecklistSubentryMake(pluralise(homebodyls_remaining, "homebodyl free craft", "homebodyl free crafts"), "", description))); - } - - //consultation counter - int CMC_consults = clampi(5 - get_property_int("_coldMedicineConsults"), 0, 5); - if (CMC_consults > 0 && __iotms_usable[lookupItem("cold medicine cabinet")]) - { - // Tracking tile; gives the user information about the last turn-taking combats per the pref. - int next_CMC_Turn = get_property_int("_nextColdMedicineConsult"); - int next_CMC_Timer = (next_CMC_Turn - total_turns_played()); - int fleshazoleMeat = clampi(my_level(),0,11)*1000; - - // Parsing the lastCombatEnvironments for a count of CMC combats. - string cmcCombatString = get_property("lastCombatEnvironments"); - string[int] splitCMC = split_string(cmcCombatString, ""); - int uTurns; - int iTurns; - int oTurns; - string dotMatrix = ''; - - foreach turn in splitCMC { - if (splitCMC[turn] == "i") {iTurns +=1; dotMatrix = dotMatrix+'🞓 ';} - if (splitCMC[turn] == "u") {uTurns +=1; dotMatrix = dotMatrix+'🞮 ';} - if (splitCMC[turn] == "o") {oTurns +=1; dotMatrix = dotMatrix+'🞉 ';} - if (splitCMC[turn] == "?") {oTurns +=1; dotMatrix = dotMatrix+'';} - } - - string expectedSpleenItem = "Fleshazole"; - - if (uTurns > 10) expectedSpleenItem = "Breathitin"; - if (iTurns > 10) expectedSpleenItem = "Extrovermectin"; - if (oTurns > 10) expectedSpleenItem = "Homebodyl"; - - string [int] description; - string url = "campground.php?action=workshed"; - - description.listAppend(HTMLGenerateSpanFont("Route turn-taking combats into the correct environments for a helpful spleen item!", "blue")); - if (next_CMC_Turn > total_turns_played()) - { - description.listAppend("" + HTMLGenerateSpanOfClass(next_CMC_Timer, "r_bold") + " adventures until your next consultation."); - - // Commenting these out. It would be nice to actually solve the issue here, but the logic just needs to be better. - // description.listAppend("Spend " + HTMLGenerateSpanOfClass(next_CMC_Timer - 9, "r_bold") + " non-environmental adventures to double your pill."); - // description.listAppend("" + HTMLGenerateSpanOfClass("Last 20 environments: ", "r_bold") + cmcCombatString + ""); - } - - // Append the lil dot guy if it's useful. - if (length(dotMatrix) > 5) { - description.listAppend(dotMatrix); - } - - string uFormat = uTurns > 10 ? "black" : "grey"; - string iFormat = iTurns > 10 ? "black" : "grey"; - string oFormat = oTurns > 10 ? "black" : "grey"; - - string [int] currentState; - currentState.listAppend(HTMLGenerateSpanOfClass("Currently Expected Spleener: ", "r_bold")+ expectedSpleenItem); - currentState.listAppend(HTMLGenerateSpanFont(uTurns.to_string() + " Underground turns", uFormat)); - currentState.listAppend(HTMLGenerateSpanFont(iTurns.to_string() + " Indoor turns", iFormat)); - currentState.listAppend(HTMLGenerateSpanFont(oTurns.to_string() + " Outdoor turns", oFormat)); - description.listAppend(currentState.listJoinComponents("|*")); - - string [int][int] spleeners; - // Generates a reference table for the user of the spleener effects. - spleeners.listAppend(listMake("Spleen Item", "Environment", "Effect")); - spleeners.listAppend(listMake("Extrovermectin","Indoors 🞓","+3 Wandering Monsters")); - spleeners.listAppend(listMake("Breathitin","Underground 🞮","+5 Outdoor Free Kills")); - spleeners.listAppend(listMake("Homebodyl","Outdoors 🞉","+11 Free Crafts")); - spleeners.listAppend(listMake("Fleshazole","N/A","+"+fleshazoleMeat.to_string()+" meat")); - description.listAppend(HTMLGenerateSimpleTableLines(spleeners)); - - resource_entries.listAppend(ChecklistEntryMake("__item snow suit", url, ChecklistSubentryMake(CMC_consults.pluralise("CMC consultation", "CMC consultations" + " remaining"), "", description)).ChecklistEntrySetIDTag("cold medicine cabinet resource")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2021/Daylight Shavings Helmet.ash b/Source/relay/TourGuide/Items of the Month/2021/Daylight Shavings Helmet.ash deleted file mode 100644 index 206bbd82..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Daylight Shavings Helmet.ash +++ /dev/null @@ -1,111 +0,0 @@ -//Daylight Shavings Helmet - -string [int, string] dshBuffOrder = { - {"Spectacle Moustache": "+50% item and +5 " + HTMLGenerateSpanFont("Spooky", "grey") + " resist"}, - {"Toiletbrush Moustache": "+25 ML and +5 " + HTMLGenerateSpanFont("Stench", "green") + " resist"}, - {"Barbell Moustache": "+25 Muscle and +50% Gear drops"}, - {"Grizzly Beard": "+25-50 MP regen and +5 " + HTMLGenerateSpanFont("Cold", "blue") + " resist"}, - {"Surrealist's Moustache": "+25 Mysticality and +50% Food drops"}, - {"Musician's Musician's Moustache": "+25 Moxie and +50% Booze drops"}, - {"Gull-Wing Moustache": "+100% init and +5 " + HTMLGenerateSpanFont("Hot", "red") + " resist"}, - {"Space Warlord's Beard": "+25 Weapon damage and +10% Crit"}, - {"Pointy Wizard Beard": "+25 Spell damage and +10% Spell Crit"}, - {"Cowboy Stache": "+25 Ranged damage and +50 maximum HP"}, - {"Friendly Chops": "+100% meat and +5 " + HTMLGenerateSpanFont("Sleaze", "purple") + " resist"} -}; - -// Reorder the default list based on our class -string [int, string] currentClassBuffOrder() { - string [int, string] beardOrder; - int classId = my_class().to_int(); - int classIdMod = (classId <= 6) ? classId : (classId % 6 + 1); - for i from 0 to 10 { - int nextBeard = (classIdMod * i) % 11; - beardOrder[i] = dshBuffOrder[nextBeard]; - } - return beardOrder; -} - -// Get our last beard buff and map it into the order for our class -int lastBeardIndex() { - string lastBeardBuffName = get_property_int("lastBeardBuff").to_effect().name; - if (lastBeardBuffName == "") { - return 0; - } - - foreach i, name in currentClassBuffOrder() { - if (name == lastBeardBuffName) { - return i; - } - } - return 0; -} - -boolean isValuableBeard(string beardName) { - return listContainsValue(listMake( - "Spectacle Moustache", - "Toiletbrush Moustache", - "Gull-Wing Moustache", - "Friendly Chops", - "Surrealist's Moustache" - ), beardName); -} - -buffer boldIfValuable(string beardName) { - return isValuableBeard(beardName) ? - HTMLGenerateSpanOfClass(beardName, "r_bold") : - to_buffer(beardName); -} - -RegisterTaskGenerationFunction("IOTMDaylightShavingsHelmetGenerateTasks"); -void IOTMDaylightShavingsHelmetGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__misc_state["in run"]) return; - if (!lookupItem("daylight shavings helmet").have()) return; - - string [int] description; - string url = "inventory.php?ftext=daylight+shavings+helmet"; - description.listAppend("Shave turns off of your sanity!"); - - int beardBuff = get_property_int("lastBeardBuff"); - - // Shaving buff prediction - string [int, string] buffOrder = currentClassBuffOrder(); - string [string] nextBeardBuff = buffOrder[(lastBeardIndex() + 1) % 11]; - string nextBeardBuffDescription; - string nextBeardBuffEffect; - foreach nextBeardBuffName in nextBeardBuff { - nextBeardBuffDescription = nextBeardBuff[nextBeardBuffName]; - nextBeardBuffEffect = boldIfValuable(nextBeardBuffName) + ", " + to_buffer(nextBeardBuffDescription); - } - description.listAppend("Next shavings effect:
" + nextBeardBuffEffect); - - string [int][int] tooltip_table; - for i from lastBeardIndex() + 1 to lastBeardIndex() + 11 { - string [string] buff = currentClassBuffOrder()[i % 11]; - string buffDescription; - foreach buffName in buff { - buffDescription = buff[buffName]; - tooltip_table.listAppend(listMake(boldIfValuable(buffName), buffDescription)); - } - } - - buffer tooltip_text; - tooltip_text.append(HTMLGenerateTagWrap("div", "DSH beard cycle", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); - tooltip_text.append(HTMLGenerateSimpleTableLines(tooltip_table)); - - if (!lookupItem("daylight shavings helmet").equipped()) - description.listAppend(HTMLGenerateSpanFont("Equip the helmet first.", "red")); - else - description.listAppend(HTMLGenerateSpanFont("Your equipped helmet will buff you.", "blue")); - - string beardCycleList = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Full beard cycle", "r_tooltip_outer_class"); - description.listAppend(beardCycleList); - - if ($effect[Toiletbrush Moustache].have_effect() < 2 && $effect[Barbell Moustache].have_effect() < 2 && $effect[Grizzly Beard].have_effect() < 2 && $effect[Surrealist's Moustache].have_effect() < 2 && $effect[Musician's Musician's Moustache].have_effect() < 2 && $effect[Gull-Wing Moustache].have_effect() < 2 && $effect[Space Warlord's Beard].have_effect() < 2 && $effect[Pointy Wizard Beard].have_effect() < 2 && $effect[Cowboy Stache].have_effect() < 2 && $effect[Friendly Chops].have_effect() < 2 && $effect[Spectacle Moustache].have_effect() < 2) { - task_entries.listAppend(ChecklistEntryMake("__item daylight shavings helmet", url, ChecklistSubentryMake("Daylight Shavings Helmet buff available", "", description), -11)); - } - else { - optional_task_entries.listAppend(ChecklistEntryMake("__item daylight shavings helmet", url, ChecklistSubentryMake("Daylight Shavings Helmet buff charging", "", description), 8)); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2021/Emotion Chip.ash b/Source/relay/TourGuide/Items of the Month/2021/Emotion Chip.ash deleted file mode 100644 index fce0e561..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Emotion Chip.ash +++ /dev/null @@ -1,97 +0,0 @@ -//Emotion Chip -RegisterResourceGenerationFunction("IOTMEmotionChipGenerateResource"); -void IOTMEmotionChipGenerateResource(ChecklistEntry [int] resource_entries) -{ - string url = invSearch("emotion chip"); - - // User does not have emotionally chipped or replica emotionally chipped, but we think they should, and we flag it. - if (!lookupSkill("Emotionally Chipped").have_skill() && !lookupSkill("replica Emotionally Chipped").have_skill() && __iotms_usable[$item[emotion chip]]) { - resource_entries.listAppend(ChecklistEntryMake("__skill feel excitement", url, ChecklistSubentryMake("Emotion Chip Usable", "", "Feel new emotions and use your shiny chip!")).ChecklistEntrySetIDTag("Use emotion chip")); - return; - } - - // Exit out of the tile if they have neither skill and we don't actually think they should, either - if (!lookupSkill("Emotionally Chipped").have_skill() && !lookupSkill("replica Emotionally Chipped").have_skill() && !__iotms_usable[$item[emotion chip]]) return; - - // Otherwise, feel your feelings and get your emotions in check. - ChecklistSubentry getEmotions() { - // Title - string main_title = "Emotion chip feelings"; - // Entries - string [int] description; - string [int] emotions; - - int emotionEnvy = clampi(3 - get_property_int("_feelEnvyUsed"), 0, 3); - if (emotionEnvy > 0 && $skill[Feel Envy].skill_is_usable()) - { - emotions.listAppend(emotionEnvy + " Envys left. Forces the monster to drop all items, but leaves killing it up to you."); - } - int emotionExcitement = clampi(3 - get_property_int("_feelExcitementUsed"), 0, 3); - if (emotionExcitement > 0 && $skill[Feel Excitement].skill_is_usable()) - { - emotions.listAppend(emotionExcitement + " Excitement left. 20 advs of +25 Mus/Mys/Mox."); - } - int emotionHatred = clampi(3 - get_property_int("_feelHatredUsed"), 0, 3); - if (emotionHatred > 0 && $skill[Feel Hatred].skill_is_usable()) - { - emotions.listAppend(emotionHatred + " Hatreds left. 50-turn banish."); - - resource_entries.listAppend(ChecklistEntryMake("__skill feel hatred", "", ChecklistSubentryMake(pluralise(emotionHatred, "Feel Hatred", "Feels Hatreds"), "", "Free run, 50-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Emotion chip feel hatred banish")); - } - int emotionLonely = clampi(3 - get_property_int("_feelLonelyUsed"), 0, 3); - if (emotionLonely > 0 && $skill[Feel Lonely].skill_is_usable()) - { - emotions.listAppend(emotionLonely + " Lonelys left. 20 advs of -5% Combat."); - } - int emotionLost = clampi(3 - get_property_int("_feelLostUsed"), 0, 3); - if (emotionLost > 0 && $skill[Feel Lost].skill_is_usable()) - { - emotions.listAppend(emotionLost + " Losts left. 20 advs of a weird Teleportitis buff."); - } - int emotionNervous = clampi(3 - get_property_int("_feelNervousUsed"), 0, 3); - if (emotionNervous > 0 && $skill[Feel Nervous].skill_is_usable()) - { - emotions.listAppend(emotionNervous + " Nervouses left. 20 advs of passive damage."); - } - int emotionNostalgic = clampi(3 - get_property_int("_feelNostalgicUsed"), 0, 3); - monster nostalgicMonster = (get_property_monster("lastCopyableMonster")); - if (emotionNostalgic > 0 && $skill[Feel Nostalgic].skill_is_usable()) - { - emotions.listAppend(emotionNostalgic + " Nostalgias left. Copy a drop table. Can currently feel nostalgic for: " + HTMLGenerateSpanFont(nostalgicMonster, "blue")); - } - int emotionPeaceful = clampi(3 - get_property_int("_feelPeacefulUsed"), 0, 3); - if (emotionPeaceful > 0 && $skill[Feel Peaceful].skill_is_usable()) - { - emotions.listAppend(emotionPeaceful + " Peacefuls left. 20 advs of +2 elemental resist."); - } - int emotionPride = clampi(3 - get_property_int("_feelPrideUsed"), 0, 3); - if (emotionPride > 0 && $skill[Feel Pride].skill_is_usable()) - { - emotions.listAppend(emotionPride + " Prides left. Triple stat gain from current fight."); - } - int emotionSuperior = clampi(3 - get_property_int("_feelSuperiorUsed"), 0, 3); - if (emotionSuperior > 0 && $skill[Feel Superior].skill_is_usable()) - { - emotions.listAppend(emotionSuperior + " Superiors left. +1 PvP Fight if used as killshot."); - } - int emotionDisappointed = clampi(3 - get_property_int("_feelDisappointedUsed"), 0, 3); - if (emotionDisappointed > 0 && $skill[Feel Disappointed].skill_is_usable()) - { - emotions.listAppend(emotionDisappointed + " Disappointments left. Your therapist has a lot of feelings about this one."); - } - return ChecklistSubentryMake(main_title, description, emotions); - } - - ChecklistEntry entry; - entry.image_lookup_name = "__item emotion chip"; - entry.tags.id = "emotion chip resource"; - - ChecklistSubentry emotions = getEmotions(); - if (emotions.entries.count() > 0) { - entry.subentries.listAppend(emotions); - } - - if (entry.subentries.count() > 0) { - resource_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2021/Familiar Scrapbook.ash b/Source/relay/TourGuide/Items of the Month/2021/Familiar Scrapbook.ash deleted file mode 100644 index 1589abc2..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Familiar Scrapbook.ash +++ /dev/null @@ -1,29 +0,0 @@ -//Familiar scrapbook -RegisterResourceGenerationFunction("IOTMFamiliarScrapbookGenerateResource"); -void IOTMFamiliarScrapbookGenerateResource(ChecklistEntry [int] resource_entries) -{ - // Title - string main_title = "Familiar scraps"; - string [int] description; - - // Entries - int familiar_scraps = get_property_int("scrapbookCharges"); - int familiar_scrap_banishes = familiar_scraps / 100; - - if (available_amount($item[familiar scrapbook]) > 0) { - if (familiar_scraps < 100) { - description.listAppend(familiar_scraps + " /100 scraps until a banish is available."); - } - else - { - description.listAppend("Free run, 100-turn banish for 100 scraps.|"+familiar_scraps + " scraps collected."); - } - - description.listAppend("Charge up your familiar scrapbook by letting familiars act in combat."); - if (!have_equipped($item[familiar scrapbook])) - description.listAppend(HTMLGenerateSpanFont("Equip the familiar scrapbook first", "red")); - - string url = invSearch("familiar scrapbook"); - resource_entries.listAppend(ChecklistEntryMake("__item familiar scrapbook", url, ChecklistSubentryMake(familiar_scraps / 100 + " scrapbook banishes available", "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Familiar scrapbook boring pictures banish")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2021/Industrial Fire Extinguisher.ash b/Source/relay/TourGuide/Items of the Month/2021/Industrial Fire Extinguisher.ash deleted file mode 100644 index 7a5cfab4..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Industrial Fire Extinguisher.ash +++ /dev/null @@ -1,65 +0,0 @@ -//Industrial fire extinguisher -RegisterResourceGenerationFunction("IOTMFireExtinguisherGenerateResource"); -void IOTMFireExtinguisherGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[industrial fire extinguisher]]) return; - - string [int] description; - string [int] options; - - // Entries - int extinguisher_charge = get_property_int("_fireExtinguisherCharge"); - boolean extinguisher_refill = get_property_boolean("_fireExtinguisherRefilled"); - boolean is_on_fire = my_path().id == 43; // Path 43 is Wildfire. - - string url = "inventory.php?ftext=industrial+fire+extinguisher"; - description.listAppend("Extinguish the fires in your life!"); - if (extinguisher_charge >= 5) - { - description.listAppend(HTMLGenerateSpanOfClass("Blast the Area (5% charge):", "r_bold") + " 1 turn of passive damage."); - description.listAppend(HTMLGenerateSpanOfClass("Foam 'em Up (5% charge):", "r_bold") + " Stun!"); - if (extinguisher_charge >= 10) - description.listAppend(HTMLGenerateSpanOfClass("Foam Yourself (10% charge):", "r_bold") + " 1 turn of +30 Hot Resist."); - description.listAppend(HTMLGenerateSpanOfClass("Polar Vortex (10% charge):", "r_bold") + " Hugpocket duplicator, usable more than once per fight."); - } - - - if (__misc_state["in run"] && is_on_fire && !get_property_boolean("_fireExtinguisherRefilled") ) - { - string description = "Tank refill available"; - resource_entries.listAppend(ChecklistEntryMake("__item fireman's helmet", "place.php?whichplace=wildfire_camp&action=wildfire_captain", ChecklistSubentryMake("Tank refill available", "", description)).ChecklistEntrySetIDTag("Tank refill resource")); - } - - if (!lookupItem("industrial fire extinguisher").equipped()) - description.listAppend(HTMLGenerateSpanFont("Equip the fire extinguisher first.", "red")); - - if (__misc_state["in run"] && my_path().id != 25 && extinguisher_charge >= 20) // Path 25 is Community Service. - { - if (!get_property_boolean("fireExtinguisherBatHoleUsed") && !__quest_state["Level 4"].finished) - { - options.listAppend(HTMLGenerateSpanOfClass("Bat Hole:", "r_bold") + " Unlock next zone for free."); - } - if (!get_property_boolean("fireExtinguisherHaremUsed") && !__quest_state["Level 5"].finished) - { - options.listAppend(HTMLGenerateSpanOfClass("Cobb's Knob Harem:", "r_bold") + " Get harem outfit for free."); - } - if (!get_property_boolean("fireExtinguisherCyrptUsed") && !__quest_state["Level 7"].finished) - { - options.listAppend(HTMLGenerateSpanOfClass("The Cyrpt:", "r_bold") + " -10 Evilness in one zone."); - } - if (!get_property_boolean("fireExtinguisherChasmUsed") && !__quest_state["Level 9"].finished) - { - options.listAppend(HTMLGenerateSpanOfClass("Smut Orc Logging Camp:", "r_bold") + " +66% Blech House progress."); - } - if (!get_property_boolean("fireExtinguisherDesertUsed") && !locationAvailable($location[The Upper Chamber]) == true) - { - options.listAppend(HTMLGenerateSpanOfClass("Arid, Extrawhatever Desert:", "r_bold") + " Ultrahydrated (15 advs)."); - } - - if (options.count() > 0) - description.listAppend(HTMLGenerateSpanOfClass("Zone-specific skills (20% charge):", "r_bold") + " 1/ascension special options in the following zones:|*-" + options.listJoinComponents("|*-")); - } - if ((is_on_fire && !get_property_boolean("_fireExtinguisherRefilled") || extinguisher_charge >= 5)) { - resource_entries.listAppend(ChecklistEntryMake("__item industrial fire extinguisher", url, ChecklistSubentryMake(extinguisher_charge + "% fire extinguisher available", "", description)).ChecklistEntrySetIDTag("industrial fire extinguisher skills resource")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2021/Miniature Crystal Ball.ash b/Source/relay/TourGuide/Items of the Month/2021/Miniature Crystal Ball.ash deleted file mode 100644 index 32c79f8a..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Miniature Crystal Ball.ash +++ /dev/null @@ -1,66 +0,0 @@ -// Miniature Crystal ball -RegisterTaskGenerationFunction("IOTMCrystalBallGenerateTasks"); -void IOTMCrystalBallGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - string title; - - title = "Miniature crystal ball monster prediction(s)"; - string image_name = "__item packaged miniature crystal ball"; - string crystalBall = (get_property("crystalBallPredictions")); - string url; - url = "inventory.php?ponder=1"; - string [int] description; - description.listAppend("The future foretells... dickstabbing!"); - - // Adding replica handling for LOL - int ballsEquipped = lookupItem("miniature crystal ball").equipped_amount() + lookupItem("replica miniature crystal ball").equipped_amount(); - - if (__iotms_usable[$item[miniature crystal ball]]) - { - if (ballsEquipped == 0) //when mcb is not equipped - { - if (crystalBall != "") - { - string [int] predictionsSection; - predictionsSection.listAppend(HTMLGenerateSpanOfClass("Predictions:", "r_bold")); - string[] predictions = crystalBall.split_string("[|]"); - foreach i in (predictions) { - string[] predictions_split = predictions[i].split_string(":"); - predictionsSection.listAppend(predictions_split[1] + " - " + predictions_split[2]); - } - description.listAppend(predictionsSection.listJoinComponents("|*")); - description.listAppend("" + HTMLGenerateSpanFont("Equip the miniature crystal ball first!", "red") + ""); - url = "inventory.php?ponder=1"; - task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(title, description), -11)); - } - else - { - description.listAppend("Equip the miniature crystal ball to predict a monster!"); - url = invSearch("miniature crystal ball"); - optional_task_entries.listAppend(ChecklistEntryMake("__item quantum of familiar", url, ChecklistSubentryMake(title, description))); - } - } - else //when mcb is equipped - { - if (crystalBall != "") - { - string [int] predictionsSection; - predictionsSection.listAppend(HTMLGenerateSpanOfClass("Predictions:", "r_bold")); - string[] predictions = crystalBall.split_string("[|]"); - foreach i in (predictions) { - string[] predictions_split = predictions[i].split_string(":"); - predictionsSection.listAppend(predictions_split[1] + " - " + predictions_split[2]); - } - description.listAppend(predictionsSection.listJoinComponents("|*")); - description.listAppend("" + HTMLGenerateSpanFont("Miniature crystal ball equipped!", "blue") + ""); - task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(title, description), -11)); - } - else - { - description.listAppend("Adventure in a snarfblat to predict a monster!"); - description.listAppend("" + HTMLGenerateSpanFont("Miniature crystal ball equipped!", "blue") + ""); - task_entries.listAppend(ChecklistEntryMake("__item quantum of familiar", url, ChecklistSubentryMake(title, description), -11)); - } - } - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2021/Potted Power Plant.ash b/Source/relay/TourGuide/Items of the Month/2021/Potted Power Plant.ash deleted file mode 100644 index 22b8cf59..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Potted Power Plant.ash +++ /dev/null @@ -1,57 +0,0 @@ -//Power Plant -RegisterResourceGenerationFunction("IOTMPowerPlantGenerateResource"); -void IOTMPowerPlantGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupItem("potted power plant").have()) - return; - - // cannot use plant batteries in g-lover. if the user is at d7 of g-lover they probably - // should pick them but i don't want to enable this tile only if it's >d7. - if (my_path().id == PATH_G_LOVER) return; - - // Title - string [int] description; - string batteriesToHarvest = (get_property("_pottedPowerPlant")); - // Entries - if (batteriesToHarvest != "0,0,0,0,0,0,0") - { - string main_title = "Power plant batteries"; - string [int] harvest; - harvest.listAppend("Harvest your potted power plant batteries."); - resource_entries.listAppend(ChecklistEntryMake("__item potted power plant", "inv_use.php?pwd=" + my_hash() + "&whichitem=10738", ChecklistSubentryMake(main_title, "", harvest), 1)); - } - - int batteryTotalCharge; - string url; - url = "inventory.php?ftext=battery+("; - for i from 1 to 6 - { - batteryTotalCharge += i*available_amount(to_item(10738+i)); - } - if (batteriesToHarvest != "0,0,0,0,0,0,0") { - description.listAppend("(Harvest your batteries for a more accurate count.)"); - } - if (batteryTotalCharge > 3) - { - description.listAppend("Make " + HTMLGenerateSpanOfClass(batteryTotalCharge / 4, "r_bold") + " 9-volt batteries to Shockingly Lick."); - description.listAppend("Alternatively, make " + HTMLGenerateSpanOfClass(batteryTotalCharge / 5, "r_bold") + " lantern batteries for a Lick and +100% item drops."); - description.listAppend("Alternatively, make " + HTMLGenerateSpanOfClass(batteryTotalCharge / 6, "r_bold") + " car batteries for a Lick and +100% item and meat drops."); - } - else if (__misc_state["in run"]) - { - description.listAppend("Can't do much with so few batteries, but you can still use them as expensive potions. Maybe save them?"); - } - int shockingLicksAvailable = get_property_int("shockingLickCharges"); - if (shockingLicksAvailable > 0) { - string title; - title = HTMLGenerateSpanFont((get_property_int("shockingLickCharges")) + " Shocking Licks available", "orange"); - description.listAppend(HTMLGenerateSpanFont("This free kill is also a yellow ray!", "orange")); - description.listAppend("Still have " + HTMLGenerateSpanOfClass(batteryTotalCharge, "r_bold") + " charge worth of batteries."); - resource_entries.listAppend(ChecklistEntryMake("__item eternal car battery", url, ChecklistSubentryMake(title, "", description), 0).ChecklistEntrySetCombinationTag("batteries available").ChecklistEntrySetIDTag("Shocking lick free kill")); - } - else if (shockingLicksAvailable == 0 && batteryTotalCharge > 0) - { - resource_entries.listAppend(ChecklistEntryMake("__item battery (aaa)", url, ChecklistSubentryMake("Power plant battery charge: " + (batteryTotalCharge), "", description), 0).ChecklistEntrySetCombinationTag("batteries available").ChecklistEntrySetIDTag("Shocking lick free kill")); - } - -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2021/Short Order Cook.ash b/Source/relay/TourGuide/Items of the Month/2021/Short Order Cook.ash deleted file mode 100644 index 54858836..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Short Order Cook.ash +++ /dev/null @@ -1,18 +0,0 @@ -//Shortest-Order Cook -RegisterResourceGenerationFunction("IOTMShortCookGenerateResource"); -void IOTMShortCookGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["in run"]) return; - if (!lookupFamiliar("Shorter-Order Cook").familiar_is_usable()) return; - if (my_path().id == PATH_G_LOVER) return; // no cook in glover - - int shartCookCharge = get_property_int("_shortOrderCookCharge"); - string [int] description; - string url = "familiar.php"; - string subtitle = "also, use your cook to feed XP to another familiar"; - if (shartCookCharge < 11) - { - description.listAppend("Use the short cook to get a +10 famwt potion."); - resource_entries.listAppend(ChecklistEntryMake("__familiar shorter-order cook", url, ChecklistSubentryMake(shartCookCharge + "/11 Shorter-Order Cook charge", subtitle, description), 8)); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2021/Underground Fireworks Shop.ash b/Source/relay/TourGuide/Items of the Month/2021/Underground Fireworks Shop.ash deleted file mode 100644 index e96111e7..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Underground Fireworks Shop.ash +++ /dev/null @@ -1,66 +0,0 @@ -//Underground Fireworks Shop -RegisterTaskGenerationFunction("IOTMUndergroundFireworksShopGenerateTasks"); -void IOTMUndergroundFireworksShopGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (__misc_state["in run"] && __misc_state["can eat just about anything"] && available_amount($item[Clan VIP Lounge key]) > 0 && get_property("_fireworksShop").to_boolean() && my_path().id != PATH_G_LOVER) - { - if ($effect[Ready to Eat].have_effect() > 0) - { - string [int] description; - description.listAppend(HTMLGenerateSpanFont("5x food statgain on the next thing you eat!", "red")); - description.listAppend(HTMLGenerateSpanFont("Don't waste it on fire crackers!", "red")); - task_entries.listAppend(ChecklistEntryMake("__effect Ready to Eat", "", ChecklistSubentryMake("Ready to Eat!", "", description), -11)); - } - if ($effect[Everything Looks Red].have_effect() == 0 && my_class() != $class[pig skinner]) - { - string [int] description; - string url = "clan_viplounge.php?action=fwshop&whichfloor=2"; - description.listAppend(HTMLGenerateSpanFont("5x food statgain on the next thing you eat.", "red")); - optional_task_entries.listAppend(ChecklistEntryMake("__item red rocket", url, ChecklistSubentryMake("Fire a red rocket", "", description), 8)); - } - if ($effect[Everything Looks Blue].have_effect() == 0 && my_class() != $class[jazz agent]) - { - string [int] description; - string url = "clan_viplounge.php?action=fwshop&whichfloor=2"; - description.listAppend(HTMLGenerateSpanFont("More MP than your body has room for!", "blue")); - optional_task_entries.listAppend(ChecklistEntryMake("__item blue rocket", url, ChecklistSubentryMake("Fire a blue rocket", "", description), 8)); - } - if ($effect[Everything Looks Yellow].have_effect() == 0 && my_class() != $class[cheese wizard]) - { - string [int] description; - string url = "clan_viplounge.php?action=fwshop&whichfloor=2"; - description.listAppend(HTMLGenerateSpanFont("Best yellow ray!", "orange")); - optional_task_entries.listAppend(ChecklistEntryMake("__item yellow rocket", url, ChecklistSubentryMake("Fire a yellow rocket", "", description), 8)); - } - } -} - -//FIXME: these do not track properly and will remain even when purchased, may fix eventually - -RegisterResourceGenerationFunction("IOTMUndergroundFireworksShopGenerateResource"); -void IOTMUndergroundFireworksShopGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id == PATH_G_LOVER) return; // none of this stuff has G in it! - - // Adding a way to get this to yank out the tile if you're in standard. - if (!lookupItem("fedora-mounted fountain").is_unrestricted()) return; - - if (!get_property_boolean("_fireworksShopEquipmentBought") && available_amount($item[Clan VIP Lounge key]) > 0 && get_property("_fireworksShop").to_boolean() && my_path() != $path[Legacy of Loathing]) - { - string [int] description; - description.listAppend("Can buy one of the following (1000 meat):"); - description.listAppend("Catherine Wheel: +3 exp back item"); - description.listAppend("Oversized sparkler: +20% item drop club"); - description.listAppend("Rocket boots: +100% initiative accessory"); - resource_entries.listAppend(ChecklistEntryMake("__item oversized sparkler", "clan_viplounge.php?action=fwshop&whichfloor=2", ChecklistSubentryMake("Explosive equipment", description), 8).ChecklistEntrySetIDTag("Clan fireworks equipment resource")); - } - if (!get_property_boolean("_fireworksShopHatBought") && available_amount($item[Clan VIP Lounge key]) > 0 && my_path() != $path[Legacy of Loathing]) - { - string [int] description; - description.listAppend("Can buy one of the following (500 meat):"); - description.listAppend("Fedora-mounted fountain: +20 ML hat"); - description.listAppend("Sombrero-mounted sparkler: +5% combat hat"); - description.listAppend("Porkpie-mounted popper: -5% combat hat"); - resource_entries.listAppend(ChecklistEntryMake("__item fedora-mounted fountain", "clan_viplounge.php?action=fwshop&whichfloor=2", ChecklistSubentryMake("Dangerous hats", description), 8).ChecklistEntrySetIDTag("Clan fireworks hat resource")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2021/Vampire Vintner.ash b/Source/relay/TourGuide/Items of the Month/2021/Vampire Vintner.ash deleted file mode 100644 index eeac8c5d..00000000 --- a/Source/relay/TourGuide/Items of the Month/2021/Vampire Vintner.ash +++ /dev/null @@ -1,87 +0,0 @@ -//Vampire Vintner -RegisterTaskGenerationFunction("IOTMVampireVintnerGenerateTasks"); -void IOTMVampireVintnerGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__misc_state["in run"] || !lookupFamiliar("vampire vintner").familiar_is_usable()) return; - - // For some reason, Vintner leaked into subsequent standards. Unfortunately, the wine isn't standard, so... - if (!lookupItem("1950 vampire vintner wine").is_unrestricted()) return; - - int vintnerFightsLeft = clampi(14 - get_property_int("vintnerCharge"), 0, 14); - int vintnerWineLevel = get_property_int("vintnerWineLevel"); - string url = "familiar.php"; - - string [int] description; - string [int] wineDescription; - string wineType = (get_property("vintnerWineType")); - description.listAppend("Use certain damage types to get premium wines:"); - description.listAppend(HTMLGenerateSpanFont("Hot damage:", "red") + " +item% wine."); - description.listAppend(HTMLGenerateSpanFont("Cold damage:", "blue") + " +meat% wine."); - description.listAppend(HTMLGenerateSpanFont("Familiar damage:", "orange") + " +fam xp and +ML wine."); - - if ($item[1950 vampire vintner wine].available_amount() == 1 && $item[1950 vampire vintner wine].item_is_usable()) - { - url = "inventory.php?ftext=vintner+wine"; - wineDescription.listAppend(HTMLGenerateSpanFont("Can't charge another vintner wine until you use this one.", "red")); - switch (wineType) - { - case "hot": - wineDescription.listAppend(HTMLGenerateSpanFont("Hot wine: grants +" + vintnerWineLevel * 3 + " hot damage and +" + vintnerWineLevel * 5 + "% item drops.", "red")); break; - case "cold": - wineDescription.listAppend(HTMLGenerateSpanFont("Cold wine: grants +" + vintnerWineLevel * 3 + " cold damage and +" + vintnerWineLevel * 5 + "% meat drops.", "blue")); break; - case "stench": - wineDescription.listAppend(HTMLGenerateSpanFont("Stench wine: grants +" + vintnerWineLevel * 3 + " stench damage and +" + vintnerWineLevel + " familiar weight.", "green")); break; - case "spooky": - wineDescription.listAppend(HTMLGenerateSpanFont("Spooky wine: grants +" + vintnerWineLevel * 4 + " spooky damage and +" + vintnerWineLevel * 2 + "% spell critical.", "grey")); break; - case "sleaze": - wineDescription.listAppend(HTMLGenerateSpanFont("Sleaze wine: grants +" + vintnerWineLevel * 3 + " sleaze damage and +" + vintnerWineLevel * 5 + "% pickpocket chance.", "purple")); break; - case "physical": - wineDescription.listAppend(HTMLGenerateSpanFont("Physical wine: grants +" + vintnerWineLevel * 2 + "% critical hit and +" + vintnerWineLevel * 10 + "% initiative.", "black")); break; - case "familiar": - wineDescription.listAppend(HTMLGenerateSpanFont("Familiar wine: grants +" + vintnerWineLevel + " familiar experience and +" + vintnerWineLevel * 3 + " ML.", "purple")); break; - } - optional_task_entries.listAppend(ChecklistEntryMake("__item 1950 vampire vintner wine", url, ChecklistSubentryMake("Drink your vampire vintner wine", wineDescription))); - } - else if (vintnerFightsLeft > 1) - { - optional_task_entries.listAppend(ChecklistEntryMake("__familiar vampire vintner", url, ChecklistSubentryMake(vintnerFightsLeft + " Vintner combats remaining", "", description))); - } - else if (vintnerFightsLeft == 1) - { - description.listAppend(HTMLGenerateSpanFont("Vintner will make wine next combat.", "purple")); - task_entries.listAppend(ChecklistEntryMake("__familiar vampire vintner", url, ChecklistSubentryMake("Vintner wine soon", "", description), -11)); - } -} -RegisterResourceGenerationFunction("IOTMVampireVintnerGenerateResource"); -void IOTMVampireVintnerGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["in run"]) return; - int vintnerWineLevel = get_property_int("vintnerWineLevel"); - string [int] description; - string [int] wineDescription; - string url = "inventory.php?ftext=vintner+wine"; - string wineType = (get_property("vintnerWineType")); - - if ($item[1950 vampire vintner wine].available_amount() == 1 && $item[1950 vampire vintner wine].item_is_usable()) - { - wineDescription.listAppend(HTMLGenerateSpanFont("Can't charge another vintner wine until you use this one.", "red")); - switch (wineType) - { - case "hot": - wineDescription.listAppend(HTMLGenerateSpanFont("Hot wine: grants +" + vintnerWineLevel * 3 + " hot damage and +" + vintnerWineLevel * 5 + "% item drops.", "red")); break; - case "cold": - wineDescription.listAppend(HTMLGenerateSpanFont("Cold wine: grants +" + vintnerWineLevel * 3 + " cold damage and +" + vintnerWineLevel * 5 + "% meat drops.", "blue")); break; - case "stench": - wineDescription.listAppend(HTMLGenerateSpanFont("Stench wine: grants +" + vintnerWineLevel * 3 + " stench damage and +" + vintnerWineLevel + " familiar weight.", "green")); break; - case "spooky": - wineDescription.listAppend(HTMLGenerateSpanFont("Spooky wine: grants +" + vintnerWineLevel * 4 + " spooky damage and +" + vintnerWineLevel * 2 + "% spell critical.", "grey")); break; - case "sleaze": - wineDescription.listAppend(HTMLGenerateSpanFont("Sleaze wine: grants +" + vintnerWineLevel * 3 + " sleaze damage and +" + vintnerWineLevel * 5 + "% pickpocket chance.", "purple")); break; - case "physical": - wineDescription.listAppend(HTMLGenerateSpanFont("Physical wine: grants +" + vintnerWineLevel * 2 + "% critical hit and +" + vintnerWineLevel * 10 + "% initiative.", "black")); break; - case "familiar": - wineDescription.listAppend(HTMLGenerateSpanFont("Familiar wine: grants +" + vintnerWineLevel + " familiar experience and +" + vintnerWineLevel * 3 + " ML.", "purple")); break; - } - resource_entries.listAppend(ChecklistEntryMake("__item 1950 vampire vintner wine", url, ChecklistSubentryMake("Drink your vampire vintner wine", wineDescription), -11)); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash b/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash deleted file mode 100644 index 01780ffa..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Autumnaton.ash +++ /dev/null @@ -1,118 +0,0 @@ -//Autumnaton -RegisterTaskGenerationFunction("IOTMAutumnatonGenerateTasks"); -void IOTMAutumnatonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - # if (!__misc_state["in run"]) return; // Turned off because TES likes this tile to appear in aftercore - if (!get_property_boolean("hasAutumnaton")) return; // Don't show if they don't actually have Fall-E - if (!$item[autumn dollar].is_unrestricted()) return; // Remove from standard-restricted paths - if (my_path() == $path[Legacy of Loathing]) return; // Cannot use fall-e in LoL - if (my_path().id == PATH_G_LOVER) return; // Cannot use fall-e in G-Lover - if (in_bad_moon()) return; // Cannot use fall-e in Bad Moon - - int autobotsToday = get_property_int("_autumnatonQuests"); - int turncountWhereAutobotReturns = get_property_int("autumnatonQuestTurn"); - - if (get_property("autumnatonUpgrades").contains_text("leftleg1")) { - autobotsToday -= 1; - } - if (get_property("autumnatonUpgrades").contains_text("rightleg1")) { - autobotsToday -= 1; - } - - int autobotsReturnTime = autobotsToday; - - if (autobotsToday < 1) { - autobotsReturnTime = 11; - } - else { - autobotsReturnTime = autobotsToday * 11; - } - - string url; - string [int] description; - string [int] [int] targets; - - description.listAppend("Autobot grabs items from a zone you've previously visited."); - - // Autobot on expedition - if (lookupItem("autumn-aton").available_amount() > 0) - { - string main_title = "Use your autumn-aton"; - description.listAppend("Next use will take " + HTMLGenerateSpanOfClass(autobotsReturnTime, "r_bold") + " adventures."); - task_entries.listAppend(ChecklistEntryMake("__item autumn-aton", "inv_use.php?pwd=" + my_hash() + "&whichitem=10954", ChecklistSubentryMake(main_title, "", description), -11)); - } - else if (turncountWhereAutobotReturns > total_turns_played()) - { - string main_title = "Autumn-aton on a mission"; - string autobotZone = get_property("autumnatonQuestLocation"); - description.listAppend("Will return in " + HTMLGenerateSpanOfClass(turncountWhereAutobotReturns +1 - total_turns_played(), "r_bold") + " adventures."); - description.listAppend(HTMLGenerateSpanOfClass("Currently exploring: ", "r_bold") + autobotZone); - optional_task_entries.listAppend(ChecklistEntryMake("__item autumn-aton", url, ChecklistSubentryMake("Autumn-aton on a mission", description), 8)); - } - else if (turncountWhereAutobotReturns <= total_turns_played()) - { - string main_title = "Autumn-aton returns next adventure"; - string autobotZone = get_property("autumnatonQuestLocation"); - description.listAppend("Next mission takes " + HTMLGenerateSpanOfClass(autobotsReturnTime, "r_bold") + " adventures."); - description.listAppend(HTMLGenerateSpanOfClass("Currently exploring: ", "r_bold") + autobotZone); - task_entries.listAppend(ChecklistEntryMake("__item autumn-aton", url, ChecklistSubentryMake(main_title, description), -11)); - } - - if (!get_property("autumnatonUpgrades").contains_text("cowcatcher")) { - description.listAppend("Visit mid underground for +1 autumn item (Cyrpt zone, Daily Dungeon?)"); - } - if (!get_property("autumnatonUpgrades").contains_text("leftarm1")) { - description.listAppend("Visit low indoor for +1 item (Haunted Pantry?)"); - } - if (!get_property("autumnatonUpgrades").contains_text("rightarm1")) { - description.listAppend("Visit mid outdoor for +1 item (Smut Orc Camp?)"); - } - if (!get_property("autumnatonUpgrades").contains_text("leftleg1")) { - description.listAppend("Visit low underground for -11 cooldown (Ratbats?)"); - } - if (!get_property("autumnatonUpgrades").contains_text("rightleg1")) { - description.listAppend("Visit mid indoor for -11 cooldown (Haunted Library?)"); - } - - if (__misc_state["in run"] && my_path().id != 25) - { - if (locationAvailable($location[sonofa beach]) == true && get_property("sidequestLighthouseCompleted") == "none" && available_amount($item[barrel of gunpowder]) < 5) - { - targets.listAppend(listMake("barrel of gunpowder", "Sonofa Beach")); - } - if (locationAvailable($location[twin peak]) == false && get_property_int("chasmBridgeProgress") < 30) - { - targets.listAppend(listMake("bridge parts", "The Smut Orc Logging Camp")); - } - if (get_property_int("hiddenBowlingAlleyProgress") + available_amount($item[bowling ball]) < 6) - { - targets.listAppend(listMake("bowling balls", "The Hidden Bowling Alley")); - } - if (get_property_int("twinPeakProgress") < 14 && available_amount($item[jar of oil]) < 1 && available_amount($item[bubblin' crude]) < 12) - { - targets.listAppend(listMake("bubblin' crude", "Oil Peak")); - } - // gnasirProgress is a weird property, please read the mafia wiki for clarification: - // https://wiki.kolmafia.us/index.php/Quest_Tracking_Preferences#gnasirProgress - if (get_property_int("desertExploration") < 100 && available_amount($item[killing jar]) < 1 && (get_property_int("gnasirProgress") & 4) == 0) - { - targets.listAppend(listMake("killing jar", "The Haunted Library")); - } - if (locationAvailable($location[the oasis]) == true && get_property_int("desertExploration") < 100) - { - targets.listAppend(listMake("drum machine", "An Oasis")); - } - if (__quest_state["Level 11 Ron"].mafia_internal_step < 5) - { - targets.listAppend(listMake("glark cables", "The Red Zeppelin")); - } - if (targets.count() > 0) - { - buffer tooltip_text; - tooltip_text.append(HTMLGenerateTagWrap("div", "Potential Targets", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); - tooltip_text.append(HTMLGenerateSimpleTableLines(targets)); - string potentialTargets = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Potential Autumnaton Targets", "r_tooltip_outer_class"); - description.listAppend(potentialTargets); - } - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2022/Combat Lover Locket.ash b/Source/relay/TourGuide/Items of the Month/2022/Combat Lover Locket.ash deleted file mode 100644 index d16672b2..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Combat Lover Locket.ash +++ /dev/null @@ -1,98 +0,0 @@ -//Combat lover's locket -RegisterResourceGenerationFunction("IOTMCombatLoversLocketGenerateResource"); -void IOTMCombatLoversLocketGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupItem("combat lover's locket").have()) return; - { - // Title - string title = "Combat lover's locket reminiscence"; - string [int] options; - string [int] description; - string url = "inventory.php?reminisce=1"; - string locketType = (get_property("locketPhylum")); - string locketEnchant; - switch (get_property("locketPhylum")) - { - case "beast": - locketEnchant = "+10% Crit Chance and +20 Muscle"; break; - case "bug": - locketEnchant = "+25% Weapon Damage and +25% max MP"; break; - case "constellation": - locketEnchant = "+10% Spell Crit and +20 Mysticality"; break; - case "construct": - locketEnchant = "+3 Moxie exp and +25 Spell Damage"; break; - case "demon": - locketEnchant = HTMLGenerateSpanFont("+25 Hot", "red") + " and +50% Gear drops"; break; - case "dude": - locketEnchant = HTMLGenerateSpanFont("+25 Cold", "cold") + " and +50% Moxie"; break; - case "elemental": - locketEnchant = HTMLGenerateSpanFont("+3 Hot res", "red") + " and " + HTMLGenerateSpanFont("+25 Stench Spell", "dark green"); break; - case "elf": - locketEnchant = "+5 exp and +75% Candy drops"; break; - case "fish": - locketEnchant = "+50% Meat Drops and " + HTMLGenerateSpanFont("+25 Spooky Spell", "grey"); break; - case "goblin": - locketEnchant = HTMLGenerateSpanFont("+25 Stench", "dark green") + " and +50% Mysticality"; break; - case "hippy": - locketEnchant = HTMLGenerateSpanFont("+3 Stench res", "dark green") + " and +10 DR"; break; - case "hobo": - locketEnchant = "+3 Mysticality exp and " + HTMLGenerateSpanFont("+25 Hot Spell", "red"); break; - case "horror": - locketEnchant = HTMLGenerateSpanFont("+3 Spooky res", "grey") + " and +50 HP"; break; - case "humanoid": - locketEnchant = "+25% Spell Damage and +20 Moxie"; break; - case "mer-kin": - locketEnchant = "+25% Item Drops and " + HTMLGenerateSpanFont("+25 Sleaze Spell", "purple"); break; - case "orc": - locketEnchant = HTMLGenerateSpanFont("+3 Sleaze res", "purple") + " and +25 MP"; break; - case "penguin": - locketEnchant = "+3 Muscle exp and " + HTMLGenerateSpanFont("+25 Cold Spell", "blue"); break; - case "pirate": - locketEnchant = "+50% Booze Drops and " + HTMLGenerateSpanFont("+25 Sleaze", "purple"); break; - case "plant": - locketEnchant = "+50% Initiative and +50% max HP"; break; - case "slime": - locketEnchant = HTMLGenerateSpanFont("+3 Cold res", "cold") + " and +50 DA"; break; - case "undead": - locketEnchant = HTMLGenerateSpanFont("+25 Spooky", "grey") + " and +50% Muscle"; break; - case "weird": - locketEnchant = "+50% Food Drops and +25 Weapon Damage"; break; - } - - description.listAppend(HTMLGenerateSpanOfClass("Current enchantment: ", "r_bold") + locketType); - description.listAppend(HTMLGenerateSpanFont(locketEnchant, "blue") + ""); - - // Entries - int monstersReminisced = clampi(3 - count(split_string(get_property("_locketMonstersFought"), ",")), 0, 3); - if (get_property("_locketMonstersFought") == "") { - resource_entries.listAppend(ChecklistEntryMake("__item combat lover's locket", url, ChecklistSubentryMake("" + "3 Combat lover's locket reminiscences", "", description)).ChecklistEntrySetIDTag("Locket fax resource")); - } - else { - if (monstersReminisced > 0) - { - if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) { - options.listAppend(HTMLGenerateSpanOfClass("Fax replacements", "r_bold") + ""); - options.listAppend("Black crayon scalers, any phylum"); - options.listAppend("Frat warrior outfit, if no numberology"); - options.listAppend("Mountain man"); - options.listAppend("Ninja snowman assassin"); - options.listAppend("Swarm of ghuol whelps"); - options.listAppend("Sausage goblin"); - options.listAppend("Baa'baa'bu'ran"); - options.listAppend("Forest spirit (for a machete, with some free crafts)"); - options.listAppend(HTMLGenerateSpanOfClass("Map replacements:", "r_bold") + ""); - options.listAppend("Astronomer OR camel's toe OR skinflute"); - options.listAppend("Lobsterfrogman"); - options.listAppend("Beanbat"); - options.listAppend("Dairy goat"); - options.listAppend("Blur"); - options.listAppend("Lynyrd skinner"); - } - if (options.count() > 0) { - description.listAppend("Rain Man the IotM:|*" + options.listJoinComponents("|*")); - } - resource_entries.listAppend(ChecklistEntryMake("__item combat lover's locket", url, ChecklistSubentryMake(pluralise(monstersReminisced, "Combat lover's locket reminiscence", "Combat lover's locket reminiscences"), "", description), 5).ChecklistEntrySetIDTag("Locket fax resource")); - } - } - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2022/Cookbookbat.ash b/Source/relay/TourGuide/Items of the Month/2022/Cookbookbat.ash deleted file mode 100644 index 535e5987..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Cookbookbat.ash +++ /dev/null @@ -1,95 +0,0 @@ -RegisterTaskGenerationFunction("IOTMCookbookbatGenerateTasks"); -void IOTMCookbookbatGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!lookupFamiliar("Cookbookbat").familiar_is_usable()) return; - string url = "familiar.php"; - string [int] description; - string cbbIngredient = (get_property("_cookbookbatQuestIngredient")); - string cbbTarget = (get_property("_cookbookbatQuestMonster")); - string cbbZone = (get_property("_cookbookbatQuestLastLocation")); - int cbbResetTimer = get_property_int("_cookbookbatCombatsUntilNewQuest"); - string main_title = HTMLGenerateSpanFont("Cookbookbat hunt", "black"); - description.listAppend(HTMLGenerateSpanOfClass(cbbResetTimer, "r_bold") + " fights until new hunt"); - int cbbIngredientDrop = 11 - get_property_int("cookbookbatIngredientsCharge"); - description.listAppend(HTMLGenerateSpanOfClass(cbbIngredientDrop, "r_bold") + " wins until 3x ingredient"); - - if (cbbTarget != "" && cbbIngredient != "") { - description.listAppend("Hunt: " + HTMLGenerateSpanFont(cbbTarget, "blue")); - description.listAppend("Zone: " + HTMLGenerateSpanFont(cbbZone, "purple")); - description.listAppend("Reward: 3x " +HTMLGenerateSpanFont(cbbIngredient, "green")); - location questLocation = get_property("_cookbookbatQuestLastLocation").to_location(); - - if (my_familiar() == lookupFamiliar("cookbookbat")) { - task_entries.listAppend(ChecklistEntryMake("__familiar cookbookbat", questLocation.getClickableURLForLocation(), ChecklistSubentryMake(main_title, description), -11, boolean [location] {questLocation:true}).ChecklistEntrySetIDTag("cookbookbat hunt")); - } - else if (my_familiar() != lookupFamiliar("cookbookbat")) { - optional_task_entries.listAppend(ChecklistEntryMake("__familiar cookbookbat", questLocation.getClickableURLForLocation(), ChecklistSubentryMake(main_title, description), 10, boolean [location] {questLocation:true}).ChecklistEntrySetIDTag("cookbookbat hunt")); - } - } - if (cbbTarget == "" && cbbIngredient == "" && my_familiar() == lookupFamiliar("cookbookbat")) { - task_entries.listAppend(ChecklistEntryMake("__familiar cookbookbat", url, ChecklistSubentryMake("Cookbookbat charging", description), -11)); - } -} - -RegisterResourceGenerationFunction("IOTMCookbookbatGenerateResource"); -void IOTMCookbookbatGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("Cookbookbat").familiar_is_usable()) return; - - // Look up amount for the three constituent items for the bookbat foods - int wheys = lookupItem("10968").available_amount(); - int vegs = lookupItem("10969").available_amount(); - int yeasts = lookupItem("10967").available_amount(); - - // Do not generate a tile if you can't eat stuff or don't have any constituent items - if (!__misc_state["can eat just about anything"] && (wheys + vegs + yeasts) < 1) - return; - - string [int] description; - string url = "craft.php?mode=cook"; - - description.listAppend("Follow the old bat's wise counsel and craft legendary gluten bombs!"); - description.listAppend("You currently have "+wheys.to_string()+" whey, "+vegs.to_string()+" veg, and "+yeasts.to_string()+" yeast."); - - // How many can we make of each food item? - int borisBreadCraftable = floor(yeasts/2); - int roastedVegCraftable = floor(vegs/2); - int focacciaCraftable = roastedVegCraftable > 0 && borisBreadCraftable > 0 ? min(borisBreadCraftable, roastedVegCraftable) : 0; - - // Generating strings for the three most important food items - string borisBread = ""+borisBreadCraftable+"x Boris's Bread: +100% meat"; // yeast + yeast - string roastedVeg = ""+roastedVegCraftable+"x Roasted Vegetable of Jarlsberg: +100% item"; // veg + veg"; - string focaccia = ""+focacciaCraftable+"x Roasted Vegetable Focaccia: +10 Fam XP"; // bread + roast veg"; - - // Here, we're generating a list of what you can make with your loadout. - string [int] pizzaParlorMenu; - pizzaParlorMenu.listAppend("You can make..."); - pizzaParlorMenu.listAppend(borisBread); - pizzaParlorMenu.listAppend(roastedVeg); - pizzaParlorMenu.listAppend(focaccia); - description.listAppend(pizzaParlorMenu.listJoinComponents("|*")); - - string [int][int] pizzaParlorRecipes; - pizzaParlorRecipes.listAppend(listMake("Boris's Bread = yeast + yeast")); - pizzaParlorRecipes.listAppend(listMake("Roasted Vegetable of Jarlsberg = veg + veg")); - pizzaParlorRecipes.listAppend(listMake("Roasted Vegetable Focaccia = bread + roastveg")); - - buffer tooltip_text; - tooltip_text.append(HTMLGenerateTagWrap("div", "Cookbookbat Recipes!", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); - tooltip_text.append(HTMLGenerateSimpleTableLines(pizzaParlorRecipes)); - - description.listAppend(HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Important Recipes", "r_tooltip_outer_class")); - - int cbbIngredientDrop = 11 - get_property_int("cookbookbatIngredientsCharge"); - int cbbResetTimer = get_property_int("_cookbookbatCombatsUntilNewQuest"); - description.listAppend(HTMLGenerateSpanOfClass(cbbIngredientDrop, "r_bold") + " wins until 3x ingredient"); - description.listAppend(HTMLGenerateSpanOfClass(cbbResetTimer, "r_bold") + " fights until new hunt"); - - int cookings_remaining = clampi(5 - get_property_int("_cookbookbatCrafting"), 0, 5); - if (cookings_remaining > 0) - { - description.listAppend(HTMLGenerateSpanOfClass(cookings_remaining, "r_bold") + " free cooks: Unstable fulminate, potions, and more."); - } - - resource_entries.listAppend(ChecklistEntryMake("__familiar cookbookbat", url, ChecklistSubentryMake("Pizza party with the Cookbookbat!", "", description)).ChecklistEntrySetIDTag("Cookbookbat Resource")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash b/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash deleted file mode 100644 index a39051eb..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash +++ /dev/null @@ -1,84 +0,0 @@ -//Cosmic Bowling Ball -RegisterTaskGenerationFunction("IOTMCosmicBowlingBallGenerateTasks"); -void IOTMCosmicBowlingBallGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!get_property_boolean("hasCosmicBowlingBall") == true) return; - if (!$item[cosmic bowling ball].is_unrestricted()) return; // Remove from standard-restricted paths - if (my_path() == $path[Legacy of Loathing]) return; - if (my_path().id == PATH_G_LOVER) return; // you can technically use it to bank buffs but the buffs don't work - - int bowlingUses = get_property_int("_cosmicBowlingSkillsUsed"); - int bowlingCooldown2 = bowlingUses * 2 + 5; - int bowlingCooldown = get_property_int("cosmicBowlingBallReturnCombats"); - boolean bowlingSupernag = get_property_boolean("tourGuideBowlingBallSupernag"); - - string url; - if (bowlingCooldown == 1) - { - string [int] description; - string main_title = "Cosmic bowling ball usable"; - description.listAppend(HTMLGenerateSpanFont("You can bowl again next turn!", "blue")); - description.listAppend("Next use has " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " duration."); - task_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake("Cosmic bowling ball returns next combat", "", description), -11)); - } - - if (bowlingCooldown < 0 && bowlingSupernag) - { - string [int] description; - string main_title = "Cosmic bowling ball usable"; - description.listAppend(HTMLGenerateSpanFont("You can bowl again -- right now!", "blue")); - description.listAppend("Next use has " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " duration."); - task_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake("Cosmic bowling ball is in your inventory!", "", description), -11)); - } -} - - -RegisterResourceGenerationFunction("IOTMCosmicBowlingBallGenerateResource"); -void IOTMCosmicBowlingBallGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!get_property_boolean("hasCosmicBowlingBall") == true) return; - if (my_path() == $path[Legacy of Loathing]) return; - if (my_path().id == PATH_G_LOVER) return; // not generating tiles when nothing works right - if (!$item[cosmic bowling ball].is_unrestricted()) return; - - // Entries - int bowlingUses = get_property_int("_cosmicBowlingSkillsUsed"); - int bowlingCooldown2 = bowlingUses * 2 + 5; - int bowlingCooldown = get_property_int("cosmicBowlingBallReturnCombats"); - string url; - if (bowlingCooldown == -1) - { - string main_title = "Cosmic bowling ball usable"; - string [int] description; - description.listAppend("Hit a strike! Knock the competition down a pin with your hole-y ball."); - description.listAppend("Give yourself an item/meat buff, gain stats in a zone, or banish for the next " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " combats."); - - resource_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", "", ChecklistSubentryMake("Bowl a Curveball with your Cosmic Bowling Ball", "", "Has " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " duration and cooldown."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Cosmic bowling ball banish")); - resource_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake("Cosmic bowling ball use available", "", description)).ChecklistEntrySetCombinationTag("special").ChecklistEntrySetIDTag("Cosmic bowling ball skills")); - } - if (bowlingCooldown > -1) - { - string main_title = HTMLGenerateSpanFont("" + bowlingCooldown, "red") + " combats until cosmic bowling ball returns"; - string [int] description; - Banish banish_entry = BanishByName("Bowl a Curveball"); - int turns_left_of_banish = banish_entry.BanishTurnsLeft(); - if (turns_left_of_banish > 0) - { - description.listAppend("Currently used on " + banish_entry.banished_monster + " for " + pluralise(turns_left_of_banish, "more turn", "more turns") + "."); - } - if (bowlingCooldown == 1) - { - description.listAppend(HTMLGenerateSpanFont("You can bowl again next turn!", "blue")); - description.listAppend("Next use has " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " duration."); - resource_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake("Cosmic bowling ball returns next combat", "", description), -11).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Cosmic bowling ball skills")); - resource_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake(main_title, "", description)).ChecklistEntrySetCombinationTag("special").ChecklistEntrySetIDTag("Cosmic bowling ball skills")); - } - else - { - description.listAppend("Bowling ball in the sky with your diamonds."); - description.listAppend("Next use has " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " duration."); - resource_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake(main_title, "", description)).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Cosmic bowling ball skills")); - resource_entries.listAppend(ChecklistEntryMake("__effect trash-wrapped", url, ChecklistSubentryMake(main_title, "", description)).ChecklistEntrySetCombinationTag("special").ChecklistEntrySetIDTag("Cosmic bowling ball skills")); - } - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2022/Cursed Magnifying Glass.ash b/Source/relay/TourGuide/Items of the Month/2022/Cursed Magnifying Glass.ash deleted file mode 100644 index 1b281f87..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Cursed Magnifying Glass.ash +++ /dev/null @@ -1,73 +0,0 @@ -//2022: cursed magnifying glass -RegisterTaskGenerationFunction("IOTYCursedMagnifyingGlassGenerateTasks"); -void IOTYCursedMagnifyingGlassGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (lookupItem("cursed magnifying glass").available_amount() == 0) return; - - int free_void_fights_left = clampi(5 - get_property_int("_voidFreeFights"), 0, 5); - int cursedGlassCounter = get_property_int("cursedMagnifyingGlassCount"); - string url; - string [int] description; - if (lookupItem("cursed magnifying glass").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the cursed magnifying glass", "red")); - url = invSearch("cursed magnifying glass"); - } - { - if (cursedGlassCounter < 12) - { - url = invSearch("cursed magnifying glass"); - description.listAppend((13 - cursedGlassCounter).pluralise("combat", "combats") + " until next void fight."); - optional_task_entries.listAppend(ChecklistEntryMake("__item cursed magnifying glass", url, ChecklistSubentryMake("Cursed magnifying glass combat", "", description), 8)); - } - - if (cursedGlassCounter == 12) - { - description.listAppend(HTMLGenerateSpanFont("One more fight until you encounter a void.", "blue")); - task_entries.listAppend(ChecklistEntryMake("__item void stone", url, ChecklistSubentryMake("Cursed magnifying glass combat", "", description), -11)); - } - - if (cursedGlassCounter == 13) - { - if (lookupItem("cursed magnifying glass").equipped_amount() == 0) - { - task_entries.listAppend(ChecklistEntryMake("__item void stone", url, ChecklistSubentryMake("Cursed magnifying glass combat", "", description), -11)); - } - else - { - description.listAppend(HTMLGenerateSpanFont("Void combat next adventure, ", "red") + HTMLGenerateSpanFont("magnifying glass equipped", "blue")); - task_entries.listAppend(ChecklistEntryMake("__item void stone", url, ChecklistSubentryMake("Cursed magnifying glass combat", "", description), -11)); - } - } - if (free_void_fights_left > 0) - { - description.listAppend("" + free_void_fights_left + " free void fights remaining."); - } - else if (lookupSkill("Meteor Lore").have_skill() || lookupItem("powerful glove").available_amount() > 0) - { - description.listAppend("No free void fights remaining, but you can replace them with lobsterfrogmen or something."); - } - else - { - description.listAppend("No free void fights remaining, but you can charge it up for tomorrow?"); - } - } -} - -RegisterResourceGenerationFunction("IOTYCursedMagnifyingGlassGenerateResource"); -void IOTYCursedMagnifyingGlassGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (lookupItem("cursed magnifying glass").available_amount() == 0) return; - - int free_void_fights_left = clampi(5 - get_property_int("_voidFreeFights"), 0, 5); - int cursedGlassCounter = get_property_int("cursedMagnifyingGlassCount"); - string url; - string [int] description; - - if (get_property_int("_voidFreeFights") < 5) { - int cursedGlassCounter = get_property_int("cursedMagnifyingGlassCount"); - url = invSearch("cursed magnifying glass"); - description.listAppend((13 - cursedGlassCounter).pluralise("combat", "combats") + " until next void fight."); - - resource_entries.listAppend(ChecklistEntryMake("__item void stone", "", ChecklistSubentryMake(pluralise(free_void_fights_left, "void glass monster", "void glass monsters"), "", description), 8).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Cursed magnifying glass free fight")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2022/Designer Sweatpants.ash b/Source/relay/TourGuide/Items of the Month/2022/Designer Sweatpants.ash deleted file mode 100644 index 310fa4b2..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Designer Sweatpants.ash +++ /dev/null @@ -1,31 +0,0 @@ -//ants -RegisterResourceGenerationFunction("IOTMDesignerSweatpantsResource"); -void IOTMDesignerSweatpantsResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[designer sweatpants]]) return; - - int sweat_o_meter = get_property_int("sweat"); - int booze_sweats_left = clampi(3 - get_property_int("_sweatOutSomeBoozeUsed"), 0, 3); - - string title; - string [int] description; - string url = "inventory.php?ftext=designer+sweatpants"; - - if (sweat_o_meter < 100) { - title = HTMLGenerateSpanFont(sweat_o_meter + "% sweatpants Sweatiness", "purple"); - } else { - title = HTMLGenerateSpanFont("Designer sweatpants: 100% sweaty!", "purple"); - description.listAppend(HTMLGenerateSpanFont("Use up your sweat, maybe!", "purple")); - } - - description.listAppend(HTMLGenerateSpanOfClass("Sweat Flick (1% sweat):", "r_bold") + HTMLGenerateSpanFont(" " + sweat_o_meter + " Sleaze Damage attack", "purple")); - description.listAppend(HTMLGenerateSpanOfClass("Sweat Spray (3% sweat):", "r_bold") + HTMLGenerateSpanFont(" recurring Sleaze Damage attack", "purple")); - description.listAppend(HTMLGenerateSpanOfClass("Sweat Flood (5% sweat):", "r_bold") + " 5-turn stun"); - description.listAppend(HTMLGenerateSpanOfClass("Sip Some Sweat (5% sweat):", "r_bold") + " Regain 50 MP"); - description.listAppend(HTMLGenerateSpanOfClass("Sweat Sip (5% sweat):", "r_bold") + " Regain 50 MP"); - description.listAppend(HTMLGenerateSpanOfClass("Drench Yourself In Sweat (15% sweat):", "r_bold") + " +100% Initiative"); - description.listAppend(HTMLGenerateSpanOfClass("Make Sweat-Ade (50% sweat):", "r_bold") + " make a PvP Fight spleen item"); - if (booze_sweats_left > 0) - description.listAppend(HTMLGenerateSpanOfClass("Sweat Out Some Booze (25% sweat):", "r_bold") + HTMLGenerateSpanFont(" -1 Drunkenness. " + booze_sweats_left + " uses left for today.", "orange")); - resource_entries.listAppend(ChecklistEntryMake("__item designer sweatpants", url, ChecklistSubentryMake(title, description), 1).ChecklistEntrySetIDTag("designer sweatpants resource")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2022/Grey Goose.ash b/Source/relay/TourGuide/Items of the Month/2022/Grey Goose.ash deleted file mode 100644 index 6203555c..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Grey Goose.ash +++ /dev/null @@ -1,112 +0,0 @@ -//Grey Goose -RegisterTaskGenerationFunction("IOTMGreyGooseGenerateTasks"); -void IOTMGreyGooseGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - // This tile just posts up a task if your Goose is hefty enough to snag adventures, and you have it equipped. - int gooseDrones = get_property_int("gooseDronesRemaining"); - int gooseWeight = min(floor(sqrt($familiar[Grey Goose].experience)),20); - int gooseExperience = ($familiar[Grey Goose].experience); - string [int] description; - description.listAppend("GOOSO IS LIT."); - - // Originally this was designed to only pop up when goose was equipped, but TES changed that by adding the duping stuff. - // if (my_familiar() != lookupFamiliar("Grey Goose")) return; - - if (gooseDrones > 0) - { - string main_title = HTMLGenerateSpanFont(gooseDrones, "brown") + HTMLGenerateSpanFont(" GOOSO drones deployed", "grey"); - description.listAppend("Automatically duplicates non-conditional drops."); - task_entries.listAppend(ChecklistEntryMake("__familiar grey goose", "", ChecklistSubentryMake(main_title,"",description),-11)); - } - - // Surprisingly, the "class" is called Grey Goo even if the path is Grey You. This is not a typo! - if (my_class() == $class[grey goo] && gooseWeight > 5) - { - string main_title = HTMLGenerateSpanFont("GOOSO is " + gooseWeight + " pounds (" + gooseExperience + " exp)", "grey"); - description.listAppend("Re-Process a bunch of matter to gain a bunch of adventures in Grey You."); - task_entries.listAppend(ChecklistEntryMake("__familiar grey goose", "", ChecklistSubentryMake(main_title, "", description), -11)); - } -} - -RegisterResourceGenerationFunction("IOTMGreyGooseGenerateResource"); -void IOTMGreyGooseGenerateResource(ChecklistEntry [int] resource_entries) -{ - // Properly avoid a goose tile if the user has no familiar - if (!lookupFamiliar("Grey Goose").familiar_is_usable()) return; - - // Title - int gooseWeight = floor(sqrt($familiar[Grey Goose].experience)); - int gooseExperience = ($familiar[Grey Goose].experience); - int famExperienceGain = numeric_modifier("familiar experience") +1; - int famExpNeededForNextPound = ((gooseWeight +1) ** 2 - gooseExperience); - int famExpNeededForTwoPounds = ((gooseWeight +2) ** 2 - gooseExperience); - int horribleFamExpCalculation = ceil((36 - gooseExperience) / famExperienceGain); - int horribleFamExpCalculationForGreyYou = ceil((196 - gooseExperience) / famExperienceGain); - int horribleFamExpCalculationForStandard = ceil((400 - gooseExperience) / famExperienceGain); - int newGooseExp = gooseExperience + famExperienceGain; - string [int] description; - string [int] stathelp; - string url = "familiar.php"; - if (gooseWeight < 6) - { - if ((gooseWeight +1) **2 > newGooseExp) - { - description.listAppend("Currently have " + HTMLGenerateSpanOfClass(gooseWeight, "r_bold") + " weight (" + HTMLGenerateSpanOfClass(gooseExperience, "r_bold") + " experience), currently gain " + HTMLGenerateSpanOfClass(famExperienceGain, "r_bold") + " fam exp per fight. (Will become " + HTMLGenerateSpanFont(newGooseExp, "red") +")"); - } - else - { - description.listAppend("Currently have " + HTMLGenerateSpanOfClass(gooseWeight, "r_bold") + " weight (" + HTMLGenerateSpanOfClass(gooseExperience, "r_bold") + " experience), currently gain " + HTMLGenerateSpanOfClass(famExperienceGain, "r_bold") + " fam exp per fight. (Will become " + HTMLGenerateSpanFont(newGooseExp, "blue") +")"); - } - description.listAppend("" + HTMLGenerateSpanOfClass((CEIL(famExpNeededForNextPound / famExperienceGain)), "r_bold") + " combats until next pound, or " + HTMLGenerateSpanOfClass((CEIL(horribleFamExpCalculation)), "r_bold") + " combats for 6 weight."); - resource_entries.listAppend(ChecklistEntryMake("__familiar Grey Goose", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Grey goose skills charging", "grey"), "", description), -2)); - } - if (gooseWeight >= 6) - { - if ((gooseWeight +1) **2 > newGooseExp) - { - description.listAppend("Currently have " + HTMLGenerateSpanOfClass(gooseWeight, "r_bold") + " weight (" + HTMLGenerateSpanOfClass(gooseExperience, "r_bold") + " experience), currently gain " + HTMLGenerateSpanOfClass(famExperienceGain, "r_bold") + " fam exp per fight. (Will become " + HTMLGenerateSpanFont(newGooseExp, "red") +")"); - } - else - { - description.listAppend("Currently have " + HTMLGenerateSpanOfClass(gooseWeight, "r_bold") + " weight (" + HTMLGenerateSpanOfClass(gooseExperience, "r_bold") + " experience), currently gain " + HTMLGenerateSpanOfClass(famExperienceGain, "r_bold") + " fam exp per fight. (Will become " + HTMLGenerateSpanFont(newGooseExp, "blue") +")"); - } - description.listAppend("" + HTMLGenerateSpanOfClass(famExpNeededForNextPound, "r_bold") + " famxp needed for next pound or " + HTMLGenerateSpanOfClass(famExpNeededForTwoPounds, "r_bold") + " for the one after that."); - if (famExperienceGain < famExpNeededForNextPound) - description.listAppend(HTMLGenerateSpanFont("Insufficient famxp for next fight.", "red") + ""); - description.listAppend("Can emit " + HTMLGenerateSpanOfClass(gooseWeight -5, "r_bold") + " drones to duplicate items."); - - //boring in-run nonsense - if (__misc_state["in run"] && gooseWeight > 5) - { - if (my_class() == $class[grey goo] && gooseWeight > 5 && my_level() < 11) - { - description.listAppend("Can generate " + HTMLGenerateSpanOfClass((gooseWeight -5) ** 2, "r_bold") + " mainstat."); - description.listAppend("" + HTMLGenerateSpanOfClass("GREY YOU: " + (CEIL(famExpNeededForNextPound / famExperienceGain)), "r_bold") + " combats until next pound, or " + HTMLGenerateSpanOfClass((CEIL(horribleFamExpCalculationForGreyYou)), "r_bold") + " combats for 14 weight."); - } - else if (__misc_state["in run"] && gooseWeight > 5 && my_level() < 11) - { - #description.listAppend("Can generate " + HTMLGenerateSpanOfClass((gooseWeight -5) ** 3, "r_bold") + " substats."); - float mainstat_gain = ((gooseWeight -5) ** 3) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); - float mainstat_gain_for_four_hundred = ((15) ** 3) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); - description.listAppend("Can generate " + HTMLGenerateSpanOfClass(mainstat_gain.roundForOutput(0), "r_bold") + " substats. (" + HTMLGenerateSpanOfClass((gooseWeight -5) ** 3, "r_bold") +" base)."); - description.listAppend("" + HTMLGenerateSpanOfClass("STAT GOOSO: " + (CEIL(famExpNeededForNextPound / famExperienceGain)), "r_bold") + " combats until next pound, or " + HTMLGenerateSpanOfClass((CEIL(horribleFamExpCalculationForStandard)), "r_bold") + " combats for 20 weight."); - } - #resource_entries.listAppend(ChecklistEntryMake("__familiar grey goose", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Grey goose skills ready!", "grey"), "", stathelp))); - } - if (!get_property_boolean("_meatifyMatterUsed")) { - description.listAppend("Can meatify matter for " + HTMLGenerateSpanOfClass((gooseWeight -5) ** 4, "r_bold") + " meat."); - } - if (!__misc_state["in run"]) - { - if (famExperienceGain >= 39) //from 25 to 64 - description.listAppend(HTMLGenerateSpanFont("Can GOOSO 3 drops per fight!", "green") + ""); - else if (famExperienceGain >= 24) //from 25 to 49 - description.listAppend(HTMLGenerateSpanFont("Can GOOSO 2 drops per fight!", "blue") + ""); - else if (famExperienceGain >= 11) //from 25 to 36 - description.listAppend(HTMLGenerateSpanFont("Can GOOSO 1 drop per fight!", "purple") + ""); - else if (famExperienceGain < 11) //cannot gooso - description.listAppend(HTMLGenerateSpanFont("Cannot GOOSO any drops per fight!", "red") + ""); - } - resource_entries.listAppend(ChecklistEntryMake("__familiar Grey Goose", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Grey goose skills ready!", "grey"), "", description), -2)); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2022/June Cleaver.ash b/Source/relay/TourGuide/Items of the Month/2022/June Cleaver.ash deleted file mode 100644 index 05f09064..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/June Cleaver.ash +++ /dev/null @@ -1,128 +0,0 @@ -//June cleaver -RegisterTaskGenerationFunction("IOTMJuneCleaverGenerateTasks"); -void IOTMJuneCleaverGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!lookupItem("June cleaver").have()) return; - - string url = "inventory.php?ftext=june+cleaver"; - string [int] description; - string main_title = "June Cleaver dream ready!"; - - int juneCleaverCharge = (get_property_int("_juneCleaverFightsLeft")); - int juneCleaverEncounters = (get_property_int("_juneCleaverEncounters")); - int juneCleaverSkips = clampi(5 - get_property_int("_juneCleaverSkips"), 0, 5); - - //cleaver dream charging - if (juneCleaverCharge == 0) - { - description.listAppend("Cleaver dream ready!"); - description.listAppend("" + juneCleaverSkips + " dream skips remaining for today."); - //cleaver dream queue - string [int] possibleDreams; - if (!get_property("juneCleaverQueue").contains_text("1467")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Poetic Justice", "r_bold") + ", +5 advs, +250 mox, +125 mys"); - } - if (!get_property("juneCleaverQueue").contains_text("1468")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Aunts not Ants", "r_bold") + ", +150 mox, +250 mus, or +exp buff"); - } - if (!get_property("juneCleaverQueue").contains_text("1469")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Beware of Aligator", "r_bold") + ", +ML buff, booze, or 1500 meat"); - } - if (!get_property("juneCleaverQueue").contains_text("1470")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Teacher's Pet", "r_bold") + ", +famxp accessory or +250 mus"); - } - if (!get_property("juneCleaverQueue").contains_text("1471")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Lost and Found", "r_bold") + ", +meat potion, +100 mus, +250 mys"); - } - if (!get_property("juneCleaverQueue").contains_text("1472")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Summer Days", "r_bold") + ", noncom potion or +250 mox"); - } - if (!get_property("juneCleaverQueue").contains_text("1473")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Bath Time", "r_bold") + ", +150 mus or resist buff"); - } - if (!get_property("juneCleaverQueue").contains_text("1474")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Delicious Sprouts", "r_bold") + ", big exp food, +250 mys, +125 mus"); - } - if (!get_property("juneCleaverQueue").contains_text("1475")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Hypnotic Master", "r_bold") + ", +rest accessory or +250 mus"); - } - if (possibleDreams.count() > 0) - description.listAppend(HTMLGenerateSpanOfClass("Possible dreams (not in any order):", "r_bold") + "|*" + possibleDreams.listJoinComponents("|*")); - - if (lookupItem("june cleaver").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the June cleaver", "red")); - } - task_entries.listAppend(ChecklistEntryMake("__item June Cleaver", url, ChecklistSubentryMake(main_title, description), -11).ChecklistEntrySetIDTag("June cleaver dreams")); - } -} - -RegisterResourceGenerationFunction("IOTMJuneCleaverGenerateResource"); -void IOTMJuneCleaverGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupItem("June cleaver").have()) return; - - string url = "inventory.php?ftext=june+cleaver"; - string [int] description; - string main_title = "You can be a June Cleaver"; - - int juneCleaverCharge = (get_property_int("_juneCleaverFightsLeft")); - int juneCleaverEncounters = (get_property_int("_juneCleaverEncounters")); - int juneCleaverSkips = clampi(5 - get_property_int("_juneCleaverSkips"), 0, 5); - - if (juneCleaverCharge == 0) - description.listAppend("Cleaver dream ready!"); - else if (juneCleaverCharge > 0) - description.listAppend("" + juneCleaverCharge + " combats left until next dream."); - description.listAppend("" + juneCleaverSkips + " dream skips remaining for today."); - //cleaver dream queue - string [int] possibleDreams; - if (!get_property("juneCleaverQueue").contains_text("1467")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Poetic Justice", "r_bold") + ", +5 advs, +250 mox, +125 mys"); - } - if (!get_property("juneCleaverQueue").contains_text("1468")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Aunts not Ants", "r_bold") + ", +150 mox, +250 mus, or +exp buff"); - } - if (!get_property("juneCleaverQueue").contains_text("1469")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Beware of Aligator", "r_bold") + ", +ML buff, booze, or 1500 meat"); - } - if (!get_property("juneCleaverQueue").contains_text("1470")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Teacher's Pet", "r_bold") + ", +famxp accessory or +250 mus"); - } - if (!get_property("juneCleaverQueue").contains_text("1471")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Lost and Found", "r_bold") + ", +meat potion, +100 mus, +250 mys"); - } - if (!get_property("juneCleaverQueue").contains_text("1472")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Summer Days", "r_bold") + ", noncom potion or +250 mox"); - } - if (!get_property("juneCleaverQueue").contains_text("1473")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Bath Time", "r_bold") + ", +150 mus or resist buff"); - } - if (!get_property("juneCleaverQueue").contains_text("1474")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Delicious Sprouts", "r_bold") + ", big exp food, +250 mys, +125 mus"); - } - if (!get_property("juneCleaverQueue").contains_text("1475")) - { - possibleDreams.listAppend(HTMLGenerateSpanOfClass("Hypnotic Master", "r_bold") + ", +rest accessory or +250 mus"); - } - if (possibleDreams.count() > 0) - description.listAppend(HTMLGenerateSpanOfClass("Possible dreams (not in any order):", "r_bold") + "|*" + possibleDreams.listJoinComponents("|*")); - - resource_entries.listAppend(ChecklistEntryMake("__item June Cleaver", url, ChecklistSubentryMake(main_title, description)).ChecklistEntrySetIDTag("June cleaver dreams")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2022/Jurassic Parka.ash b/Source/relay/TourGuide/Items of the Month/2022/Jurassic Parka.ash deleted file mode 100644 index ac4f8d2b..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Jurassic Parka.ash +++ /dev/null @@ -1,70 +0,0 @@ -//Jurassic parka -RegisterTaskGenerationFunction("IOTMJurassicParkaGenerateTasks"); -void IOTMJurassicParkaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - // Task-based nag for using the parka. Instruct the user to swap modes or equip parka if needed. - if (!__iotms_usable[$item[Jurassic Parka]]) return; - - // Fondeluge is the only skill strictly better than Jurassic acid; don't show this tile if you happen to have it - if (lookupSkill("Fondeluge").have_skill()) return; - if (__misc_state["in run"] && available_amount($item[jurassic parka]) > 0 && my_path().id != PATH_COMMUNITY_SERVICE) - { - string [int] description; - string url = "inventory.php?ftext=jurassic+parka"; - - // TODO: Perhaps a centralized YR supernag would be better? Not sure, tbh. - if ($effect[everything looks yellow].have_effect() == 0) - { - if (lookupItem("jurassic parka").equipped_amount() == 0) - { - description.listAppend(HTMLGenerateSpanFont("Equip your Jurassic Parka!", "red")); - } - else description.listAppend(HTMLGenerateSpanFont("Parka equipped.", "orange")); - if (get_property("parkaMode") != "dilophosaur") - { - description.listAppend(HTMLGenerateSpanFont("Change your parka to dilophosaur mode!", "red")); - } - else description.listAppend(HTMLGenerateSpanFont("Dilophosaur mode enabled.", "orange")); - task_entries.listAppend(ChecklistEntryMake("__item jurassic parka", url, ChecklistSubentryMake("Parka yellow ray is ready; spit some acid!", "", description), -11)); - } - } -} - -RegisterResourceGenerationFunction("IOTMJurassicParkaGenerateResource"); -void IOTMJurassicParkaGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[Jurassic Parka]]) return; - if (!__misc_state["in run"]) return; - if (my_path().id == PATH_G_LOVER) return; // cannot use parka in g-lover - - string url; - string parkaMode = get_property("parkaMode"); - string parkaEnchant; - string [int] description; - - url = invSearch("jurassic parka"); - - int spikos_left = clampi(5 - get_property_int("_spikolodonSpikeUses"), 0, 5); - - // Title - string main_title = "Jurassic Parka"; - description.listAppend("You're the dinosaur now, dawg."); - - switch (get_property("parkaMode")) - { - case "kachungasaur": - parkaEnchant = "+100% HP, +50% meat, +2 Cold res."; break; - case "dilophosaur": - parkaEnchant = "+20 Sleaze and Sleaze Spell, +2 Stench res, YR free kill."; break; - case "spikolodon": - parkaEnchant = "+ML, +2 Sleaze res, NC forcing ability."; break; - case "ghostasaurus": - parkaEnchant = "+10 DR, +50 MP, +2 Spooky res."; break; - case "pterodactyl": - parkaEnchant = "-5% Combat Frequency, +50% Initiative, +2 Hot res."; break; - } - description.listAppend(HTMLGenerateSpanOfClass("Current enchantment: ", "r_bold") + parkaMode); - description.listAppend(HTMLGenerateSpanFont(parkaEnchant, "blue") + ""); - description.listAppend(HTMLGenerateSpanOfClass(spikos_left, "r_bold") + " spikolodon spikes available."); - resource_entries.listAppend(ChecklistEntryMake("__item jurassic parka", "inventory.php?action=jparka", ChecklistSubentryMake(main_title, "", description))); -} diff --git a/Source/relay/TourGuide/Items of the Month/2022/Mayday Supply Package.ash b/Source/relay/TourGuide/Items of the Month/2022/Mayday Supply Package.ash deleted file mode 100644 index f3375c36..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Mayday Supply Package.ash +++ /dev/null @@ -1,12 +0,0 @@ -// MayDay Package -RegisterResourceGenerationFunction("IOTMMayDayContractGenerateResource"); -void IOTMMayDayContractGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[MayDay™ supply package].available_amount() > 0) #&& in_ronin() && $item[MayDay™ supply package].item_is_usable()) - { - string [int] description; - string url = invSearch("MayDay"); - description.listAppend("Use for 30 advs of +100% init as well as useful seeded drops (formerly ten bucks)"); - resource_entries.listAppend(ChecklistEntryMake("__item MayDay™ supply package", url, ChecklistSubentryMake(pluralise($item[MayDay™ supply package]), "", description))); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2022/Model Train Set.ash b/Source/relay/TourGuide/Items of the Month/2022/Model Train Set.ash deleted file mode 100644 index b126ad15..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Model Train Set.ash +++ /dev/null @@ -1,206 +0,0 @@ -string [string, string] stationDescriptions; - -int trainSetReconfigurableIn() { - int trainPosition = get_property_int("trainsetPosition"); - int whenTrainsetWasConfigured = get_property_int("lastTrainsetConfiguration"); - if (whenTrainsetWasConfigured == trainPosition || - trainPosition - whenTrainsetWasConfigured >= 40) { - return 0; - } else { - return 40 - (trainPosition - whenTrainsetWasConfigured); - } -} - -boolean stationConfigured(string station) { - return contains_text(get_property("trainsetConfiguration"), station); -} - -boolean oreConfiguredWhenNotNeeded() { - boolean oreConfigured = stationConfigured("ore_hopper"); - string oreNeeded = get_property("trapperOre"); - boolean haveAllOreNeeded = __quest_state["Level 8"].state_boolean["Past mine"] || - (oreNeeded != "" && to_item(oreNeeded).available_amount() >= 3) || - (to_item("asbestos ore").available_amount() >= 3 && - to_item("chrome ore").available_amount() >= 3 && - to_item("linoleum ore").available_amount() >= 3); - return __misc_state["in run"] && oreConfigured && haveAllOreNeeded; -} - -boolean loggingMillConfiguredWhenNotNeeded() { - boolean loggingMillConfigured = stationConfigured("logging_mill"); - int fastenersNeeded = __quest_state["Level 9"].state_int["bridge fasteners needed"]; - int lumberNeeded = __quest_state["Level 9"].state_int["bridge lumber needed"]; - boolean haveAllPartsNeeded = __quest_state["Level 9"].mafia_internal_step > 1 || - (fastenersNeeded == 0 && lumberNeeded == 0); - return __misc_state["in run"] && loggingMillConfigured && haveAllPartsNeeded; -} - -boolean statsConfiguredWhenNotNeeded() { - boolean statsConfigured = stationConfigured("viewing_platform") || - (stationConfigured("brawn_silo") && my_primestat() == $stat[muscle]) || - (stationConfigured("brain_silo") && my_primestat() == $stat[mysticality]) || - (stationConfigured("groin_silo") && my_primestat() == $stat[moxie]); - boolean haveAllStatsNeeded = my_level() >= 13; - return __misc_state["in run"] && statsConfigured && haveAllStatsNeeded; -} - -boolean shouldNag() { - return trainSetReconfigurableIn() == 0 && - (oreConfiguredWhenNotNeeded() || - loggingMillConfiguredWhenNotNeeded() || - statsConfiguredWhenNotNeeded() || - stationConfigured("empty")); -} - -RegisterTaskGenerationFunction("IOTMModelTrainSetGenerateTasks"); -void IOTMModelTrainSetGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[lookupItem("model train set")]) return; - - string url = "campground.php?action=workshed"; - string [int] description; - string main_title = "Model train set progress"; - - int trainPosition = get_property_int("trainsetPosition"); - int whenTrainsetWasConfigured = get_property_int("lastTrainsetConfiguration"); - string[int] stations = split_string(get_property("trainsetConfiguration"), ","); - - if (count(stations) < 8) { - description.listAppend("We can't tell how your trainset is configured. Click this tile to fix."); - task_entries.listAppend(ChecklistEntryMake("__item toy crazy train", url, ChecklistSubentryMake(main_title, description), -11).ChecklistEntrySetIDTag("Model train set")); - return; - } - - if (oreConfiguredWhenNotNeeded()) { - description.listAppend(HTMLGenerateSpanFont("Have ore configured when it's not needed!", "red")); - } - if (loggingMillConfiguredWhenNotNeeded()) { - description.listAppend(HTMLGenerateSpanFont("Have lumber mill configured when it's not needed!", "red")); - } - if (statsConfiguredWhenNotNeeded()) { - description.listAppend(HTMLGenerateSpanFont("Have stats configured when they're not needed!", "red")); - } - if (stationConfigured("empty")) { - description.listAppend(HTMLGenerateSpanFont("Have an empty station configured!", "red")); - } - - int reconfigurableIn = trainSetReconfigurableIn(); - if (reconfigurableIn == 0) - { - HTMLGenerateSpanFont("Train set reconfigurable!", "blue"); - } - else { - description.listAppend("Train set reconfigurable in " + HTMLGenerateSpanOfClass(reconfigurableIn.to_string() + " combats.", "r_bold")); - } - - string[string] nextStation = stationDescriptions[stations[trainPosition % 8]]; - description.listAppend("Next station: " + HTMLGenerateSpanOfClass(nextStation["name"], "r_bold") + " - " + nextStation["description"]); - - string [int][int] tooltipTable; - for i from trainPosition to trainPosition + 7 { - string[string] station = stationDescriptions[stations[i % 8]]; - tooltipTable.listAppend(listMake(HTMLGenerateSpanOfClass(station["name"], "r_bold"), station["description"])); - } - buffer tooltipText; - tooltipText.append(HTMLGenerateTagWrap("div", "Train station cycle", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); - tooltipText.append(HTMLGenerateSimpleTableLines(tooltipTable)); - string trainCycleList = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltipText, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Full train cycle", "r_tooltip_outer_class"); - description.listAppend(trainCycleList); - - ChecklistEntry[int] whereToAddTile = optional_task_entries; - int priority = 8; - - if (shouldNag()) { - whereToAddTile = task_entries; - priority = -11; - } - - whereToAddTile.listAppend(ChecklistEntryMake("__item toy crazy train", url, ChecklistSubentryMake(main_title, description), priority).ChecklistEntrySetIDTag("Model train set")); -} - -stationDescriptions = { - "unknown": { - "name": "Unknown", - "description": "We don't recognize that train station!", - }, - "empty": { - "name": "Empty station", - "description": HTMLGenerateSpanFont("Train set isn't fully configured!", "red"), - }, - "meat_mine": { - "name": "Meat Mine", - "description": "Bonus meat", - }, - "tower_fizzy": { - "name": "Fizzy Tower", - "description": "MP regen", - }, - "viewing_platform": { - "name": "Viewing Platform", - "description": "Gain extra stats", - }, - "tower_frozen": { - "name": "Frozen Tower", - "description": HTMLGenerateSpanFont("Hot", "red") + " res, " + HTMLGenerateSpanFont("Cold", "blue") + " dmg", - }, - "spooky_graveyard": { - "name": "Spooky Graveyard", - "description": HTMLGenerateSpanFont("Stench", "green") + " res, " + HTMLGenerateSpanFont("Spooky", "grey") + " dmg", - }, - "logging_mill": { - "name": "Logging Mill", - "description": "Bridge parts or stats", - }, - "candy_factory": { - "name": "Candy Factory", - "description": "Pick up random candy", - }, - "coal_hopper": { - "name": "Coal Hopper", - "description": "Double power of next station", - }, - "tower_sewage": { - "name": "Sewage Tower", - "description": HTMLGenerateSpanFont("Cold", "blue") + " res, " + HTMLGenerateSpanFont("Stench", "green") + " dmg", - }, - "oil_refinery": { - "name": "Oil Refinery", - "description": HTMLGenerateSpanFont("Spooky", "grey") + " res, " + HTMLGenerateSpanFont("Sleaze", "purple") + " dmg", - }, - "oil_bridge": { - "name": "Oil Bridge", - "description": HTMLGenerateSpanFont("Sleaze", "purple") + " res, " + HTMLGenerateSpanFont("Hot", "red") + " dmg", - }, - "water_bridge": { - "name": "Bridge Over Troubled Water", - "description": "Increase ML", - }, - "groin_silo": { - "name": "Groin Silo", - "description": "Gain moxie", - }, - "grain_silo": { - "name": "Grain Silo", - "description": "Get base booze", - }, - "brain_silo": { - "name": "Brain Silo", - "description": "Gain mysticality", - }, - "brawn_silo": { - "name": "Brawn Silo", - "description": "Gain muscle", - }, - "prawn_silo": { - "name": "Prawn Silo", - "description": "Acquire more food", - }, - "trackside_diner": { - "name": "Trackside Diner", - "description": "Serves the last food you found", - }, - "ore_hopper": { - "name": "Ore Hopper", - "description": "Get some ore", - } -}; diff --git a/Source/relay/TourGuide/Items of the Month/2022/Oliver's Place.ash b/Source/relay/TourGuide/Items of the Month/2022/Oliver's Place.ash deleted file mode 100644 index 4df55c93..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Oliver's Place.ash +++ /dev/null @@ -1,16 +0,0 @@ -RegisterResourceGenerationFunction("IOTMOliversPlaceGenerateResource"); -void IOTMOliversPlaceGenerateResource(ChecklistEntry [int] resource_entries) -{ - // Only generate if they actually have Oliver's Place - if (!get_property_boolean("ownsSpeakeasy")) return; - - int free_oliver_fights_left = 3 - get_property_int("_speakeasyFreeFights"); - string url = "place.php?whichplace=speakeasy"; - string [int] description; - - if (free_oliver_fights_left > 0) { - description.listAppend("Consider dragging wanderers into the speakeasy."); - - resource_entries.listAppend(ChecklistEntryMake("__item Marltini", "", ChecklistSubentryMake(pluralise(free_oliver_fights_left, "Oliver's Tavern fight", "Oliver's Tavern fights"), "", description), 9).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Oliver's Tavern free fights")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2022/Tiny Stillsuit.ash b/Source/relay/TourGuide/Items of the Month/2022/Tiny Stillsuit.ash deleted file mode 100644 index 70025394..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Tiny Stillsuit.ash +++ /dev/null @@ -1,211 +0,0 @@ -//Tiny stillsuit -RegisterTaskGenerationFunction("IOTMTinyStillsuitGenerateTasks"); -void IOTMTinyStillsuitGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!lookupItem("tiny stillsuit").have()) return; - int fam_sweat_o_meter = get_property_int("familiarSweat"); - - string title; - string [int] description; - string url = "inventory.php?action=distill&pwd=" + my_hash(); - - int sweatCalcSweat; - int sweatAdvs = round(to_int(get_property("familiarSweat"))**0.4); - - // Adding a few conditions to turn off the supernag. - boolean canGuzzleSweat = (availableDrunkenness() > 0); - boolean inStillsuitPath = (!__misc_state["familiars temporarily blocked"] && my_path() != $path[A Shrunken Adventurer am I]); - - // TODO: Turn this into an actual math function instead of an else-if lol - if (fam_sweat_o_meter >= 358) { - sweatCalcSweat = 449; - } - else if (fam_sweat_o_meter >= 279) { - sweatCalcSweat = 358; - } - else if (fam_sweat_o_meter >= 211) { - sweatCalcSweat = 279; - } - else if (fam_sweat_o_meter >= 155) { - sweatCalcSweat = 211; - } - else if (fam_sweat_o_meter >= 108) { - sweatCalcSweat = 155; - } - else if (fam_sweat_o_meter >= 71) { - sweatCalcSweat = 108; - } - else if (fam_sweat_o_meter >= 43) { - sweatCalcSweat = 71; - } - else if (fam_sweat_o_meter >= 23) { - sweatCalcSweat = 43; - } - else if (fam_sweat_o_meter >= 10) { - sweatCalcSweat = 23; - } - else if (fam_sweat_o_meter < 10) { - sweatCalcSweat = 10; - } - - if (fam_sweat_o_meter > 449) { - description.listAppend("" + HTMLGenerateSpanOfClass(sweatAdvs, "r_bold") + " advs when guzzling now (costs 1 liver)."); - description.listAppend("You should probably guzzle your sweat now."); - } - else { - description.listAppend(HTMLGenerateSpanOfClass(fam_sweat_o_meter + "/" + sweatCalcSweat, "r_bold") + " drams of stillsuit sweat for next adventure."); - description.listAppend("" + HTMLGenerateSpanOfClass(sweatCalcSweat - fam_sweat_o_meter, "r_bold") + " more sweat until +1 more adventure. (" + (1+ (sweatCalcSweat - fam_sweat_o_meter)/3) + " combats on current familiar)"); - } - - // Still generate the "warning, not generating sweat" supernag so long as familiars aren't blocked - if ($item[tiny stillsuit].item_amount() == 1 && !__misc_state["familiars temporarily blocked"]) { - title = HTMLGenerateSpanFont("Equip the stillsuit", "purple"); - description.listAppend("" + HTMLGenerateSpanFont("Not collecting sweat from any familiar right now.", "red") + ""); - url = "familiar.php"; - task_entries.listAppend(ChecklistEntryMake("__item tiny stillsuit", url, ChecklistSubentryMake(title, description), -11).ChecklistEntrySetIDTag("tiny stillsuit task")); - } - else if ($item[tiny stillsuit].equipped_amount() == 1) { - description.listAppend("" + HTMLGenerateSpanFont("Currently collecting sweat from current familiar!", "purple") + ""); - } else { - description.listAppend("" + HTMLGenerateSpanFont("Currently collecting sweat on a different familiar!", "fuchsia") + ""); - } - title = HTMLGenerateSpanFont(sweatAdvs + " adv stillsuit sweat booze", "purple"); - - // However, if the user is in a path where they can't use stillsuit or cannot drink the distillate right now, do not show this supernag. - if (!inStillsuitPath || !canGuzzleSweat) return; - - if (__misc_state["in run"] && sweatAdvs > 6) { - task_entries.listAppend(ChecklistEntryMake("__item tiny stillsuit", url, ChecklistSubentryMake(title, description), -11).ChecklistEntrySetIDTag("tiny stillsuit task")); - } - else if (!__misc_state["in run"] && sweatAdvs > 10) { - task_entries.listAppend(ChecklistEntryMake("__item tiny stillsuit", url, ChecklistSubentryMake(title, description), -11).ChecklistEntrySetIDTag("tiny stillsuit task")); - } -} - -RegisterResourceGenerationFunction("IOTMTinyStillsuitGenerateResource"); -void IOTMTinyStillsuitGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupItem("tiny stillsuit").have()) return; - - int fam_sweat_o_meter = get_property_int("familiarSweat"); - int sweatAdvs = round(to_int(get_property("familiarSweat"))**0.4); -# int nextSweatDrams = (sweatAdvs+0.51) ** 2.5;# - fam_sweat_o_meter; - - string title; - string [int] description; - string url = "inventory.php?action=distill&pwd=" + my_hash(); - int sweatCalcSweat; - - description.listAppend("Two gross tastes that taste horrible together."); - //an amish paradise is as primitive as can be - - if (fam_sweat_o_meter >= 358) { - sweatCalcSweat = 449; - } - else if (fam_sweat_o_meter >= 279) { - sweatCalcSweat = 358; - } - else if (fam_sweat_o_meter >= 211) { - sweatCalcSweat = 279; - } - else if (fam_sweat_o_meter >= 155) { - sweatCalcSweat = 211; - } - else if (fam_sweat_o_meter >= 108) { - sweatCalcSweat = 155; - } - else if (fam_sweat_o_meter >= 71) { - sweatCalcSweat = 108; - } - else if (fam_sweat_o_meter >= 43) { - sweatCalcSweat = 71; - } - else if (fam_sweat_o_meter >= 23) { - sweatCalcSweat = 43; - } - else if (fam_sweat_o_meter >= 10) { - sweatCalcSweat = 23; - } - else if (fam_sweat_o_meter < 10) { - sweatCalcSweat = 10; - } - - if (fam_sweat_o_meter > 358) { - description.listAppend("" + HTMLGenerateSpanOfClass("11", "r_bold") + " advs when guzzling now (costs 1 liver)."); - description.listAppend("You should probably guzzle your sweat now."); - } - else if (fam_sweat_o_meter > 10) { - description.listAppend("" + HTMLGenerateSpanOfClass(sweatAdvs, "r_bold") + " advs when guzzling now (costs 1 liver)."); - description.listAppend("" + HTMLGenerateSpanOfClass(sweatCalcSweat - fam_sweat_o_meter, "r_bold") + " more sweat until +1 more adventure. (" + (1+ (sweatCalcSweat - fam_sweat_o_meter)/3) + " combats on current familiar)"); - } - else { - description.listAppend("" + HTMLGenerateSpanFont("Not enough sweat to guzzle.", "red") + ""); - description.listAppend("" + HTMLGenerateSpanOfClass(sweatCalcSweat - fam_sweat_o_meter, "r_bold") + " more sweat until +1 more adventure. (" + (1+ (sweatCalcSweat - fam_sweat_o_meter)/3) + " combats on current familiar)"); - } - - if ($item[tiny stillsuit].item_amount() == 1) { - description.listAppend("" + HTMLGenerateSpanFont("Not collecting sweat from any familiar right now.", "red") + ""); - url = "familiar.php"; - } - else if ($item[tiny stillsuit].equipped_amount() == 1) { - description.listAppend("" + HTMLGenerateSpanFont("Currently collecting sweat from current familiar!", "purple") + ""); - } else { - description.listAppend("" + HTMLGenerateSpanFont("Currently collecting sweat on a different familiar!", "fuchsia") + ""); - } - - title = HTMLGenerateSpanFont(fam_sweat_o_meter + "/" + sweatCalcSweat + " drams of stillsuit sweat", "purple"); - - //sweat chart - string [int][int] tooltip_table; - - // These are the mappings for drams needed for certain adv thresholds. - static string[int] advDramsTable = { - 3:"10", - 4:"23", - 5:"43", - 6:"71", - 7:"108", - 8:"155", - 9:"211", - 10:"279", - 11:"358", - 12:"449", - 13:"553", - 14:"670", - 15:"801", - 16:"946", - 17:"1106", - 18:"1282",}; - - foreach advs, drams in advDramsTable { - // Only append it if the user hasn't yet reached that # of drams - if (drams.to_int() > fam_sweat_o_meter) { - tooltip_table.listAppend(listMake(advs.to_string(), drams+" drams (" + (drams.to_int() - fam_sweat_o_meter) + " more sweat)" )); - } - } - - if (fam_sweat_o_meter > 553) { - tooltip_table.listAppend(listMake("> 13", "... yknow, you should probably just drink it, buddy")); - } - - buffer tooltip_text; - tooltip_text.append(HTMLGenerateTagWrap("div", "Sweat to Advs Conversion Table", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); - tooltip_text.append(HTMLGenerateSimpleTableLines(tooltip_table)); - - string stillSweatTooltip = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Sweat/Advs conversion", "r_tooltip_outer_class"); - description.listAppend(stillSweatTooltip); - - //famtype chart - string [int][int] tooltip_table2; - tooltip_table2.listAppend(listMake("Cubeling / Stomping Boots", "+item")); - tooltip_table2.listAppend(listMake("Levitating Potato / Candy Carnie / Flan", "+item and +food")); - tooltip_table2.listAppend(listMake("Star Starfish / Emilio / Globmule / Waifuton", "+item and +sleaze")); - - buffer tooltip_text2; - tooltip_text2.append(HTMLGenerateTagWrap("div", "Stillsuit buff target", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); - tooltip_text2.append(HTMLGenerateSimpleTableLines(tooltip_table2)); - - string stillSweatTypeTooltip = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text2, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Suggested Stillsuit Familiars", "r_tooltip_outer_class"); - description.listAppend(stillSweatTypeTooltip); - resource_entries.listAppend(ChecklistEntryMake("__item tiny stillsuit", url, ChecklistSubentryMake(title, description), -2).ChecklistEntrySetIDTag("tiny stillsuit resource")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2022/Unbreakable Umbrella.ash b/Source/relay/TourGuide/Items of the Month/2022/Unbreakable Umbrella.ash deleted file mode 100644 index a57c070d..00000000 --- a/Source/relay/TourGuide/Items of the Month/2022/Unbreakable Umbrella.ash +++ /dev/null @@ -1,37 +0,0 @@ -//Unbreakable Umbrella -RegisterResourceGenerationFunction("IOTMUnbreakableUmbrellaGenerateResource"); -void IOTMUnbreakableUmbrellaGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id == PATH_G_LOVER) return; // no umbrella in glover - item unbrella = lookupItem("unbreakable umbrella"); - if (!unbrella.have()) return; - if (!__misc_state["in run"] && $item[unbreakable umbrella].equipped_amount() == 0) return; - string url; - string unbrellaMode = get_property("umbrellaState"); - string unbrellaEnchant; - string [int] description; - url = invSearch("unbreakable umbrella"); - // Title - string main_title = "Umbrella machine " + HTMLGenerateSpanFont("B", "red") + "roke"; - description.listAppend("Understanda" + HTMLGenerateSpanFont("B", "red") + "le have a nice day."); - - switch (get_property("umbrellaState")) - { - case "broken": - int modifiedML = round(numeric_modifier("monster level") * 1.25,0); - unbrellaEnchant = "+25% ML. Unbrella-boosted ML will be " + modifiedML + "."; break; - case "forward-facing": - unbrellaEnchant = "+25 DR shield"; break; - case "bucket style": - unbrellaEnchant = "+25% item drops"; break; - case "pitchfork style": - unbrellaEnchant = "+25 Weapon Damage"; break; - case "constantly twirling": - unbrellaEnchant = "+25 Spell Damage"; break; - case "cocoon": - unbrellaEnchant = "-10% Combat Frequency"; break; - } - description.listAppend(HTMLGenerateSpanOfClass("Current enchantment: ", "r_bold") + unbrellaMode); - description.listAppend(HTMLGenerateSpanFont(unbrellaEnchant, "blue") + ""); - resource_entries.listAppend(ChecklistEntryMake("__item unbreakable umbrella", "inventory.php?action=useumbrella&pwd=" + my_hash(), ChecklistSubentryMake(main_title, "", description))); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2023/2002 Catalog.ash b/Source/relay/TourGuide/Items of the Month/2023/2002 Catalog.ash deleted file mode 100644 index 2e0d71b4..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/2002 Catalog.ash +++ /dev/null @@ -1,169 +0,0 @@ -//2002 Mr. Store -RegisterTaskGenerationFunction("IOTM2002MrStoreGenerateTasks"); -void IOTM2002MrStoreGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - { int nextVHSTurn = get_property_int("spookyVHSTapeMonsterTurn") + 8; - int nextVHSTimer = (nextVHSTurn - total_turns_played()); - - string image_name = get_property("spookyVHSTapeMonster"); - string [int] description; - string [int] warnings; - - // Adding a few warnings for the sake of it - boolean [string] holidayTracker = getHolidaysToday(); - - if (holidayTracker["El Dia de Los Muertos Borrachos"] == true || holidayTracker["Feast of Boris"] == true) { - warnings[1] = 'Be careful -- Borrachos & Feast of Boris wanderers can show up instead of your VHS wanderer!'; - } - - if (get_property_int("breathitinCharges") > 0) { - warnings[2] = 'Breathitin is active; avoid putting your VHS wanderer outdoors, the wanderer is already free!'; - } - - if (nextVHSTurn <= total_turns_played() && (image_name != "")) - { - description.listAppend(HTMLGenerateSpanFont("Free fight + YR!", "black")); - - // Only show warnings if it's right about to happen - foreach i, warning in warnings { - description.listAppend(HTMLGenerateSpanFont("|* ➾ "+warning, "red")); - } - task_entries.listAppend(ChecklistEntryMake("__monster " + image_name, "", ChecklistSubentryMake("Spooky VHS: " + get_property("spookyVHSTapeMonster") + HTMLGenerateSpanFont(" now", "red"), "", description), -11)); - } - else if (nextVHSTurn -1 == total_turns_played() && (image_name != "")) - { - description.listAppend(HTMLGenerateSpanFont("Free fight + YR next turn!", "black")); - task_entries.listAppend(ChecklistEntryMake("__monster " + image_name, "", ChecklistSubentryMake("Spooky VHS: " + get_property("spookyVHSTapeMonster") + HTMLGenerateSpanFont(" in 1 more adv", "blue"), "", description), -11)); - } - else if (image_name != "") - { - description.listAppend(nextVHSTimer + " adventures until your free fight YR VHS fight."); - optional_task_entries.listAppend(ChecklistEntryMake("__monster " + image_name, "", ChecklistSubentryMake("Spooky VHS: " + get_property("spookyVHSTapeMonster") + "", "", description), 10)); - } - } -} - -RegisterResourceGenerationFunction("IOTM2002MrStoreGenerateResource"); -void IOTM2002MrStoreGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[2002 Mr. Store Catalog]]) return; - - int Mr2002Credits = get_property_int("availableMrStore2002Credits"); - - string main_title = (Mr2002Credits + " 2002 Mr. Store credits"); - string [int] description; - - // Use the right item ID depending on if you are using a replica or a non-replica - string active2002ID = lookupItem("Replica 2002 Mr. Store Catalog").available_amount() > 0 ? "11280" : "11257"; - - string url = "inv_use.php?pwd=" + my_hash() + "&which=3&whichitem="+active2002ID; - - if (Mr2002Credits > 0) { - description.listAppend("Spend credits on prehistoric IotMs!"); - - string [int] options; - if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) - { - if ($item[Flash Liquidizer Ultra Dousing Accessory].available_amount() == 0) - { - options.listAppend(HTMLGenerateSpanOfClass("Flash Liquidizer Ultra Dousing Accessory:", "r_bold") + " +3 BLARTpockets"); - } - if ($item[pro skateboard].available_amount() == 0) - { - options.listAppend(HTMLGenerateSpanOfClass("Pro skateboard:", "r_bold") + " +1 duplicate"); - } - if ($item[letter from carrie bradshaw].available_amount() == 0 && $item[red-soled high heels].available_amount() == 0) - { - options.listAppend(HTMLGenerateSpanOfClass("Letter from Carrie Bradshaw:", "r_bold") + " +50% booze drop accessory"); - } - if ($item[Loathing Idol Microphone].available_amount() < 69420) - { - options.listAppend(HTMLGenerateSpanOfClass("Loathing Idol Microphone:", "r_bold") + " +100% init, +50% items, +5% combat; 4 uses"); - } - if ($item[Spooky VHS Tape].available_amount() < 69420) - { - options.listAppend(HTMLGenerateSpanOfClass("Spooky VHS Tape:", "r_bold") + " wandering freekill YR of the monster you used it on; try GROPs!"); - } - } - if (options.count() > 0) - description.listAppend("Possible purchases:|*" + options.listJoinComponents("|*")); - } - int availableVHSes = available_amount($item[Spooky VHS Tape]); - - // List out the mics from least to most charged - item [int] listOfMics = listMake($item[Loathing Idol Microphone (25% charged)],$item[Loathing Idol Microphone (50% charged)],$item[Loathing Idol Microphone (75% charged)],$item[Loathing Idol Microphone]); - int totalIdolCharge; - - foreach i, micItem in listOfMics { - // Add # of charge based on index of the above list to the total charge. - totalIdolCharge += i*available_amount(micItem); - } - - boolean McTwistUsed = get_property_boolean("_epicMcTwistUsed"); - int FLUDAdousesLeft = clampi(3 - get_property_int("_douseFoeUses"), 0, 3); - - // Ascension stuff - if (!__misc_state["in run"] || - my_path().id == PATH_COMMUNITY_SERVICE || - availableVHSes + totalIdolCharge + FLUDAdousesLeft == 0) - return; - - // Generate useful VHS copy list - string [int] optionsVHS; - - if (__quest_state["Level 12"].state_int["hippies left on battlefield"] > 5) optionsVHS.listAppend("War monsters; especially GROPs"); - if (!__quest_state["Level 7"].state_boolean["cranny finished"]) optionsVHS.listAppend("Giant swarm of ghuol whelps"); - if (!__quest_state["Level 8"].state_boolean["Mountain climbed"]) optionsVHS.listAppend("Ninja snowman assassin"); - if ($item[amulet of extreme plot significance].available_amount() == 0) optionsVHS.listAppend("Quiet Healer"); - if ($item[mohawk wig].available_amount() == 0) optionsVHS.listAppend("Burly Sidekick"); - - if (availableVHSes > 0 && $item[Spooky VHS Tape].item_is_usable()) - { - string VHSDescription = "Have " + availableVHSes + " VHS tapes."; - if (optionsVHS.count() > 0) { - VHSDescription += " Use to free-copy into delay & guarantee drops from:|*"+optionsVHS.listJoinComponents("|*"); - } - description.listAppend(VHSDescription); - } - if (totalIdolCharge > 0) - { - description.listAppend("Have " + totalIdolCharge + " Loathing Idol microphone uses. (50% item, 5% com, or 100% init.)"); - } - - string [int] optionsMcTwist; - - if ($item[goat cheese].available_amount() < 2 && !__quest_state["Level 8"].state_boolean["Past mine"]) - optionsMcTwist.listAppend(HTMLGenerateFutureTextByLocationAvailability("a dairy goat", $location[the goatlet])); - if (__quest_state["Level 9"].state_int["twin peak progress"] < 15) - optionsMcTwist.listAppend(HTMLGenerateFutureTextByLocationAvailability("a hedge trimmer monster", $location[Twin Peak])); - if (!__quest_state["Level 7"].state_boolean["nook finished"]) - optionsMcTwist.listAppend(HTMLGenerateFutureTextByLocationAvailability("an evil eye monster", $location[the defiled nook])); - if (__quest_state["Level 12"].state_int["hippies left on battlefield"] > 5) - optionsMcTwist.listAppend(HTMLGenerateFutureTextByLocationAvailability("a green ops soldier", $location[the battlefield (frat uniform)])); - - if (available_amount($item[pro skateboard]) > 0 && McTwistUsed == False) { - string mcTwistDescription = "Can Epic McTwist to double drops!"; - if (optionsMcTwist.count() > 0) { - mcTwistDescription += " Consider using on: "+optionsMcTwist.listJoinComponents(", ", "or ") + "."; - } - - description.listAppend(mcTwistDescription); - } - string [int] optionsFLUDA; - - if ($item[goat cheese].available_amount() < 2 && !__quest_state["Level 8"].state_boolean["Past mine"]) - optionsFLUDA.listAppend(HTMLGenerateFutureTextByLocationAvailability("goat cheese", $location[the goatlet])); - if (!__quest_state["Level 12"].state_boolean["Orchard Finished"] && my_path().id != PATH_2CRS) - optionsFLUDA.listAppend(HTMLGenerateFutureTextByLocationAvailability("filthworm sweat glands", $location[the battlefield (frat uniform)])); - - - if (available_amount($item[Flash Liquidizer Ultra Dousing Accessory]) > 0 && FLUDAdousesLeft > 0) { - string fludaDescription = "Can waterpocket " + FLUDAdousesLeft + " more foes with FLUDA."; - if (optionsFLUDA.count() > 0) { - fludaDescription += " Try stealing some "+optionsFLUDA.listJoinComponents(", ", "or ")+"."; - } - description.listAppend(fludaDescription); - } - - resource_entries.listAppend(ChecklistEntryMake("__item mr. accessaturday", url, ChecklistSubentryMake(main_title, description), 8)); -} diff --git a/Source/relay/TourGuide/Items of the Month/2023/A Guide to Burning Leaves.ash b/Source/relay/TourGuide/Items of the Month/2023/A Guide to Burning Leaves.ash deleted file mode 100644 index 0aa709bc..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/A Guide to Burning Leaves.ash +++ /dev/null @@ -1,304 +0,0 @@ -// TILE SPEC: -// - Remind the user to spend their leaves. -// - Advise the user of top leafy options. -// - Add leafy free fights to the freefightcombinationtag - -Record LeafyFight -{ - int leafCost; - monster summonedMonster; - string scaling; - int leavesDropped; - string extraDrops; -}; - -LeafyFight LeafyFightMake(int cost, monster summonedMonster, string scaling, int leavesDropped, string itemDropped) -{ - LeafyFight summon; - - summon.leafCost = cost; - summon.summonedMonster = summonedMonster; - summon.scaling = scaling; - summon.leavesDropped = leavesDropped; - summon.extraDrops = itemDropped; - - return summon; -} - -Record LeafySummon -{ - int leafCost; - item summonedItem; - string description; - boolean meltingStatus; - string prefName; -}; - -LeafySummon LeafySummonMake(int cost, item summonedItem, string desc, boolean melts, string prefName) -{ - LeafySummon summon; - - summon.leafCost = cost; - summon.summonedItem = summonedItem; - summon.description = desc; - summon.meltingStatus = melts; - summon.prefName = prefName; - - return summon; -} - -void listAppend(LeafyFight [int] list, LeafyFight entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(LeafySummon [int] list, LeafySummon entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -RegisterResourceGenerationFunction("IOTMBurningLeavesGenerateResource"); -void IOTMBurningLeavesGenerateResource(ChecklistEntry [int] resource_entries) -{ - // Don't generate these tiles if they cannot actually use their leaves - if (!__iotms_usable[$item[A Guide to Burning Leaves]]) return; - - string url = "campground.php?preaction=burningleaves"; - - // Make two tiles for spending leaves - int leafCount = $item[inflammable leaf].item_amount(); - string [int] itemsDescription; - string [int] monstersDescription; - - // To use these, if you do "aftercoreStuff[##]" it'll return true if it's in the list or false if not - boolean [int] aftercoreStuff = $ints[99,222,1111,6666,11111]; - boolean [int] inRunStuff = $ints[42,43,44,66]; - - if ($item[inflammable leaf].have()) { - - LeafySummon [int] leafySummons; - // leafySummons.listAppend(LeafySummonMake(#leafcost, $item[leafsummon], "tile desc", t/f(melts), "name of summon check pref")); - leafySummons.listAppend(LeafySummonMake(37, $item[autumnic bomb], "potion; prismatic stinging (25 turns)", false, "")); - leafySummons.listAppend(LeafySummonMake(42, $item[impromptu torch], "weapon; +2 mus/fight", true, "")); - leafySummons.listAppend(LeafySummonMake(43, $item[flaming fig leaf], "pants; +2 mox/fight", true, "")); - leafySummons.listAppend(LeafySummonMake(44, $item[smoldering drape], "cape; +2 mys/fight, +20% stat", true, "")); - leafySummons.listAppend(LeafySummonMake(50, $item[distilled resin], "potion; generate +1 leaf/fight (100 turns)", false, "")); - leafySummons.listAppend(LeafySummonMake(66, $item[autumnal aegis], "shield; +250 DA, +2 all res", false, "")); - leafySummons.listAppend(LeafySummonMake(69, $item[lit leaf lasso], "combat item; lasso leaf freebies for extra end-of-combat triggers", false, "_leafLassosCrafted")); - leafySummons.listAppend(LeafySummonMake(74, $item[forest canopy bed], "bed; +5 free rests, stats via rests", false, "")); - leafySummons.listAppend(LeafySummonMake(99, $item[autumnic balm], "potion; +2 all res (100 turns)", false, "")); - leafySummons.listAppend(LeafySummonMake(222, $item[day shortener], "spend 5 turns for a +turn item", false, "_leafDayShortenerCrafted")); - leafySummons.listAppend(LeafySummonMake(1111, $item[coping juice], "copium for the masses", false, "")); - leafySummons.listAppend(LeafySummonMake(6666, $item[smoldering leafcutter ant egg], "mosquito & leaves familiar", false, "_leafAntEggCrafted")); - leafySummons.listAppend(LeafySummonMake(11111, $item[super-heated leaf], "burn leaves into your skiiiin", false, "_leafTattooCrafted")); - - // Make a big summons table for a leaf summoning tile - string [int][int] summonOptions; - - // Header for the item summons table - if (true) - { - string [int] option; - option.listAppend("cost"); - option.listAppend("item"); - option.listAppend("description"); - foreach key, s in option - { - option[key] = HTMLGenerateSpanOfClass(s, "r_bold"); - } - summonOptions.listAppend(option); - } - - // Populate the table - foreach key, summon in leafySummons - { - // Adding some skip conditions for aftercore/in-run options - // if (__misc_state["in run"] && aftercoreStuff[summon.leafCost]) continue; - // if (!__misc_state["in run"] && inRunStuff[summon.leafCost]) continue; - - // Run pref checks & do not generate a row if you cannot summon it anymore - boolean userCanSummon = true; - - if (summon.prefName == "") - userCanSummon = true; - else if (summon.prefName == "_leafLassosCrafted") - userCanSummon = get_property_int("_leafLassosCrafted") < 3; // can make a lasso if you've made <3 - else - userCanSummon = !get_property_boolean(summon.prefName); // prefs are false if non-summoned, true if summoned and you're locked out - - if (!userCanSummon) continue; - - // A handful of conditional exclusions. Enumerated reasons in the comments! - - // The bomb is useful if you aren't able to use crab or short-order cook. Otherwise, not particularly useful. - boolean canUseShorty = lookupFamiliar("Shorter-Order Cook").familiar_is_usable(); - boolean canUseCrab = lookupFamiliar("Imitation Crab").familiar_is_usable(); - - if (canUseShorty || canUseCrab) { - if (summon.leafCost == 37) continue; - } - - // If the user is level 12 or higher, no reason to show fig or torch. Going to still - // show drape if they don't have it, as 20% stat might be useful slot-filler for some - // weird user somewhere. - if (my_level() > 11) { - if ($ints[42,43] contains summon.leafCost) continue; - } - - // If the user has Tao of the Terrapin available, they probably don't need the aegis - if (lookupSkill("Tao of the Terrapin").have_skill()) { - if (summon.leafCost == 66) continue; - } - - // Do not get 2 of any of the equips or other one-use items - if (summon.summonedItem.available_amount() > 0) { - if ($ints[42,43,44,66,74] contains summon.leafCost) continue; - } - - // Do not show the bed if it is already installed either - if (get_campground() contains $item[forest canopy bed]) { - if (summon.leafCost == 74) continue; - } - - // Set the color to gray if you don't have enough leaves - boolean hasEnoughLeaves = leafCount >= summon.leafCost; - string rowColor = hasEnoughLeaves ? "black" : "gray"; - - // Add smaller melting tag to description, if it's melting - string summonDesc = summon.description; - if (summon.meltingStatus) - summonDesc += HTMLGenerateSpanFont(" (melting)", "gray", "0.7em"); - - // Hide aftercore stuff while in-run, and visa versa - if (__misc_state["in run"]) { - if (aftercoreStuff[summon.leafCost]) continue; - } - - if (!__misc_state["in run"]) { - if (inRunStuff[summon.leafCost]) continue; - } - - string [int] option; - // add cost - option.listAppend(summon.leafCost); - option.listAppend(summon.summonedItem.to_string()); - option.listAppend(summonDesc); - foreach key, s in option - { - option[key] = HTMLGenerateSpanFont(s, rowColor); - } - summonOptions.listAppend(option); - } - itemsDescription.listAppend(HTMLGenerateSimpleTableLines(summonOptions)); - resource_entries.listAppend(ChecklistEntryMake("__item inflammable leaf", url, ChecklistSubentryMake(pluralise(leafCount, "leaf to burn for items", "leaves to burn for items"), "", itemsDescription), 14).ChecklistEntrySetIDTag("Burning leaf item summons")); - - // With item summons done, make a seal-esque fights tile - - int fightsRemaining = clampi(5 - get_property_int("_leafMonstersFought"), 0, 5); - - if (fightsRemaining > 0) { - LeafyFight [int] leafyFights; - // leafyFights.listAppend(LeafyFightMake(#leafcost, $monster[leafmonster], "scaling desc", #leafdrops, "extra drops")); - leafyFights.listAppend(LeafyFightMake(11, $monster[flaming leaflet], "11/11/11", 4, "")); - leafyFights.listAppend(LeafyFightMake(111, $monster[flaming monstera], "scaling", 7, "leafy browns")); - - // No particular need to fight leaviathan over monstera in run if the user owns the crown already - if (!(__misc_state["in run"] && $item[flaming leaf crown].have())) { - leafyFights.listAppend(LeafyFightMake(666, $monster[leaviathan], "scaling boss (hard!)", 125, "flaming leaf crown")); - } - - string [int][int] fightOptions; - - // Header for the fight summons table - if (true) - { - string [int] option; - option.listAppend("cost"); - option.listAppend("monster"); - option.listAppend("stats & info"); - foreach key, s in option - { - option[key] = HTMLGenerateSpanOfClass(s, "r_bold"); - } - fightOptions.listAppend(option); - } - - foreach key, summon in leafyFights - { - boolean hasEnoughLeaves = leafCount >= summon.leafCost; - string rowColor = hasEnoughLeaves ? "black" : "gray"; - - // Add smaller melting tag to description, if it's melting - string summonDesc = summon.scaling + "; ~"+summon.leavesDropped+" leaves dropped "; - if (summon.extraDrops != "") - summonDesc += HTMLGenerateSpanFont("(also, drops "+summon.extraDrops+")", "gray", "0.7em"); - - string [int] option; - // add cost - option.listAppend(summon.leafCost); - option.listAppend(summon.summonedMonster.to_string()); - option.listAppend(summonDesc); - foreach key, s in option - { - option[key] = HTMLGenerateSpanFont(s, rowColor); - } - fightOptions.listAppend(option); - } - - int leafletsUserCanSummon = leafCount/11; - - monstersDescription.listAppend(HTMLGenerateSimpleTableLines(fightOptions)); - if (leafCount > 111*fightsRemaining) { - monstersDescription.listAppend("With your "+pluralise(leafCount, "leaf", "leaves")+", you can summon "+fightsRemaining+" monstera, for scaling fights"); - } - else if (leafCount > 11*fightsRemaining) { - monstersDescription.listAppend("With your "+pluralise(leafCount, "leaf", "leaves")+", you can summon "+fightsRemaining+" leaflets, for familiar turns"); - } - else if (leafCount > 11) { - monstersDescription.listAppend("With your "+pluralise(leafCount, "leaf", "leaves")+", you can currently summon "+pluralise(leafletsUserCanSummon,"leaflet","leaflets")+"; save leaves for more!"); - } - else { - monstersDescription.listAppend("With your "+pluralise(leafCount, "leaf", "leaves")+", you cannot currently summon a free fight; save leaves for more!"); - } - - resource_entries.listAppend(ChecklistEntryMake("__monster flaming leaflet", url, ChecklistSubentryMake(pluralise(fightsRemaining, "remaining free burned leaf fight", "remaining free burned leaf fights"), "remember to lasso for +1 fight!", monstersDescription), 13).ChecklistEntrySetIDTag("Burning leaf fight summons")); - - } - - } - - // Make a free fights combo tag for available free leaf fights - int fightsRemaining = clampi(5 - get_property_int("_leafMonstersFought"), 0, 5); - int leafletsUserCanSummon = leafCount/11; - - string [int] description; - ChecklistSubentry [int] subentries; - - if (fightsRemaining > 0) { - - if (leafCount >= 111*fightsRemaining) { - description.listAppend("Have enough leaves for "+fightsRemaining+" flaming monstera"); - } - else if (leafCount >= 11*fightsRemaining) { - description.listAppend("Have enough leaves for "+fightsRemaining+" leaflets"); - } - else if (leafCount >= 8*fightsRemaining) { - description.listAppend("Have enough leaves, if you let the leaflets drop their bounty!"); - } - else { - description.listAppend(HTMLGenerateSpanFont("Can summon "+leafletsUserCanSummon+" of your "+fightsRemaining+" leaflets... get more leaves!", "orange")); - } - - subentries.listAppend(ChecklistSubentryMake(pluralise(fightsRemaining, "free flaming leaflet fight", "free flaming leaflet fights"), "", description)); - TagGroup tags; - tags.id = "Burning Leaves free fights"; - tags.combination = "daily free fight"; - resource_entries.listAppend(ChecklistEntryMake("__item tied-up flaming leaflet", url, subentries, tags, 0)); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2023/August Scepter.ash b/Source/relay/TourGuide/Items of the Month/2023/August Scepter.ash deleted file mode 100644 index 51504e59..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/August Scepter.ash +++ /dev/null @@ -1,289 +0,0 @@ -// August Scepter tile creation. This is... an annoying item. - -// Start by associating skill names with the associated cast check variable -static { - string [string] __augSkillsToVars; - void initializeAugustSkills() { - __augSkillsToVars["Aug. 1st: Mountain Climbing Day!"] = "_aug1Cast"; // turnbloat (+3) - __augSkillsToVars["Aug. 2nd: Find an Eleven-Leaf Clover Day"] = "_aug2Cast"; // lucky! - __augSkillsToVars["Aug. 3rd: Watermelon Day!"] = "_aug3Cast"; // skip, though it could be good for some i guess - __augSkillsToVars["Aug. 4th: Water Balloon Day!"] = "_aug4Cast"; // skip - __augSkillsToVars["Aug. 5th: Oyster Day!"] = "_aug5Cast"; // skip - __augSkillsToVars["Aug. 6th: Fresh Breath Day!"] = "_aug6Cast"; // +com for ninjas - __augSkillsToVars["Aug. 7th: Lighthouse Day!"] = "_aug7Cast"; // +50 item/+100 meat - __augSkillsToVars["Aug. 8th: Cat Day!"] = "_aug8Cast"; // skip - __augSkillsToVars["Aug. 9th: Hand Holding Day!"] = "_aug9Cast"; // mild sniff - __augSkillsToVars["Aug. 10th: World Lion Day!"] = "_aug10Cast"; // banish skill (non-free) - __augSkillsToVars["Aug. 11th: Presidential Joke Day!"] = "_aug11Cast"; // myst stats - __augSkillsToVars["Aug. 12th: Elephant Day!"] = "_aug12Cast"; // mus stats - __augSkillsToVars["Aug. 13th: Left/Off Hander's Day!"] = "_aug13Cast"; // double lewd deck in softcore - __augSkillsToVars["Aug. 14th: Financial Awareness Day!"] = "_aug14Cast"; // skip; extra space? - __augSkillsToVars["Aug. 15th: Relaxation Day!"] = "_aug15Cast"; // skip - __augSkillsToVars["Aug. 16th: Roller Coaster Day!"] = "_aug16Cast"; // -full & +food for spookyraven - __augSkillsToVars["Aug. 17th: Thriftshop Day!"] = "_aug17Cast"; // -1000 meat on your kitchen - __augSkillsToVars["Aug. 18th: Serendipity Day!"] = "_aug18Cast"; // i cannot believe this terrible thing is now meta - __augSkillsToVars["Aug. 19th: Honey Bee Awareness Day!"] = "_aug19Cast"; // skip - __augSkillsToVars["Aug. 20th: Mosquito Day!"] = "_aug20Cast"; // skip - __augSkillsToVars["Aug. 21st: Spumoni Day!"] = "_aug21Cast"; // allstats but skip i think - __augSkillsToVars["Aug. 22nd: Tooth Fairy Day!"] = "_aug22Cast"; // free tooth monster - __augSkillsToVars["Aug. 23rd: Ride the Wind Day!"] = "_aug23Cast"; // mox stats - __augSkillsToVars["Aug. 24th: Waffle Day!"] = "_aug24Cast"; // 3 macros this rules - __augSkillsToVars["Aug. 25th: Banana Split Day!"] = "_aug25Cast"; // skip - __augSkillsToVars["Aug. 26th: Toilet Paper Day!"] = "_aug26Cast"; // skip the sgeea-like, it is not worth it in a post-on-the-trail world - __augSkillsToVars["Aug. 27th: Just Because Day!"] = "_aug27Cast"; // crazy horse for crazy folks - __augSkillsToVars["Aug. 28th: Race Your Mouse Day!"] = "_aug28Cast"; // +10 fam weight melting fam equip; skip if they have pet sweater? - __augSkillsToVars["Aug. 29th: More Herbs, Less Salt Day!"] = "_aug29Cast"; // skip; extra space? - __augSkillsToVars["Aug. 30th: Beach Day!"] = "_aug30Cast"; // +7 adv melting equip; turnbloat - __augSkillsToVars["Aug. 31st: Cabernet Sauvignon Day!"] = "_aug31Cast"; // booze drops + good booze. also, extra space? - } - initializeAugustSkills(); -} - - -// Associate skill names with the thing they give you -static { - string [string] __augSkillsToValue; - void initializeAugustSkills() { - __augSkillsToValue["Aug. 1st: Mountain Climbing Day!"] = "a +adv buff"; - __augSkillsToValue["Aug. 2nd: Find an Eleven-Leaf Clover Day"] = "lucky!"; - __augSkillsToValue["Aug. 3rd: Watermelon Day!"] = "a watermelon"; - __augSkillsToValue["Aug. 4th: Water Balloon Day!"] = "three water balloons"; - __augSkillsToValue["Aug. 5th: Oyster Day!"] = "some oyster eggs"; - __augSkillsToValue["Aug. 6th: Fresh Breath Day!"] = "a +com buff"; - __augSkillsToValue["Aug. 7th: Lighthouse Day!"] = "an item/meat buff"; - __augSkillsToValue["Aug. 8th: Cat Day!"] = "a catfight, meow"; - __augSkillsToValue["Aug. 9th: Hand Holding Day!"] = "a foe's hand held"; - __augSkillsToValue["Aug. 10th: World Lion Day!"] = "roars like a lion"; - __augSkillsToValue["Aug. 11th: Presidential Joke Day!"] = "myst stats"; - __augSkillsToValue["Aug. 12th: Elephant Day!"] = "mus stats"; - __augSkillsToValue["Aug. 13th: Left/Off Hander's Day!"] = "double offhands"; - __augSkillsToValue["Aug. 14th: Financial Awareness Day!"] = "bad meatgain"; - __augSkillsToValue["Aug. 15th: Relaxation Day!"] = "a full heal"; - __augSkillsToValue["Aug. 16th: Roller Coaster Day!"] = "-full & +food%"; - __augSkillsToValue["Aug. 17th: Thriftshop Day!"] = "a 1000 meat coupon"; - __augSkillsToValue["Aug. 18th: Serendipity Day!"] = "a bunch of items"; - __augSkillsToValue["Aug. 19th: Honey Bee Awareness Day!"] = "stalked by bees"; - __augSkillsToValue["Aug. 20th: Mosquito Day!"] = "HP regen"; - __augSkillsToValue["Aug. 21st: Spumoni Day!"] = "stats of all kinds"; - __augSkillsToValue["Aug. 22nd: Tooth Fairy Day!"] = "a free tooth monster"; - __augSkillsToValue["Aug. 23rd: Ride the Wind Day!"] = "mox stats"; - __augSkillsToValue["Aug. 24th: Waffle Day!"] = "three waffles"; - __augSkillsToValue["Aug. 25th: Banana Split Day!"] = "a banana split"; - __augSkillsToValue["Aug. 26th: Toilet Paper Day!"] = "some toilet paper"; - __augSkillsToValue["Aug. 27th: Just Because Day!"] = "three random effects"; - __augSkillsToValue["Aug. 28th: Race Your Mouse Day!"] = "a melting fam equip"; - __augSkillsToValue["Aug. 29th: More Herbs, Less Salt Day!"] = "a food stat enhancer"; - __augSkillsToValue["Aug. 30th: Beach Day!"] = "a +7 adv accessory"; - __augSkillsToValue["Aug. 31st: Cabernet Sauvignon Day!"] = "two bottles of +booze% wine"; - } - initializeAugustSkills(); -} - -// Convert the user's mainstat to an August statgain skill -int mainstatAugustSkill() { - switch (my_primestat()) - { - case $stat[muscle]: - return 12; // "Aug. 12th: Elephant Day!" - case $stat[mysticality]: - return 11; // "Aug. 11th: Presidential Joke Day!" - case $stat[moxie]: - return 23; // "Aug. 23rd: Ride the Wind Day!" - } - return 12; // "return muscle if you can't " -} - -// Helper function to grab the first # in the string -int grabNumber(string s){ - matcher numMatcher = create_matcher("\\d+",s); - if (numMatcher.find()){ - return numMatcher.group(0).to_int(); - } else { - return 0; - } -} - -RegisterResourceGenerationFunction("IOTMAugustScepterGenerateResource"); -void IOTMAugustScepterGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[lookupItem("August Scepter")]) return; - - // Figure out how many of your five skills are still available; no tile if none are there! - int skillsAvailable = 5 - get_property_int("_augSkillsCast"); - if (skillsAvailable < 1) return; - - // A string for demarcation of 30 turn buffs - string buffString = HTMLGenerateSpanFont(" (buff)", "gray", "0.9em"); - - // Similar to calculate the universe, store reasons why things have value while using - // the day as the key. Should make the tile less painful to read, though a bit more - // confusing. Will *definitely* need a little summary text. - string [int] usefulAugustSkills; - - foreach augSkillName, augSkillPref in __augSkillsToVars { - - // Convert text to number. You could argue that I should've just initially stored - // them as ints, but I wanted to store full skill names just in case we see a - // good use case for the full skill names later. - int augSkillNumber = grabNumber(augSkillName); - - // For these particularly mediocre/bad skills, don't even look up the pref. This covers 12/31 skills - if ($ints[3, 4, 5, 8, 14, 15, 19, 20, 21, 25, 26, 29] contains augSkillNumber) continue; - - // Skip the tile-creation logic for that guy if the skill has already been cast. - if (get_property_boolean(augSkillPref)) { - continue; - } - - // Within this foreach, add descriptions for the valuable casts, if they're still - // valuable to the player. - - // LEVELING HELP; gain 50*level mainstats. 12, 11, 23 for 15/31 skills - if (__misc_state["need to level"]) { - - if (augSkillNumber == mainstatAugustSkill()) { - int statsGained = (50 * my_level() * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0)).floor(); - usefulAugustSkills[augSkillNumber] = "+"+statsGained+" mainstat"; - } - - } - - // TURNBLOAT; baywatch (30) + spirit (1) for 17/31 skills - if (my_path() != $path[Slow and Steady]) { - - // Only show mountain effect if they need goat cheese, as there aren't many mountains in-run. - if ($item[goat cheese].available_amount() < 2 && !__quest_state["Level 8"].state_boolean["Past mine"]) { - if (augSkillNumber == 1) { - usefulAugustSkills[1] = "+2-5 turns "+HTMLGenerateSpanFont("(spend turns @ the Goatlet)", "gray", "0.9em"); - } - } - - if (augSkillNumber == 30) { - usefulAugustSkills[30] = "+7 advs rollover accessory "+HTMLGenerateSpanFont("(melting)", "gray", "0.9em"); - } - } - - // +ITEM BUFFS; food/booze/base, with 31, 16, and 7. 20/31 skills - - boolean manorCheck = __quest_state["Level 11 Manor"].mafia_internal_step < 3 && __quest_state["Level 11 Manor"].state_boolean["Can use fast route"]; - string blastingAddendum = manorCheck && $item[blasting soda].available_amount() == 0 ? ""+HTMLGenerateSpanFont("(blasting soda!)", "gray", "0.9em") : ""; - - // I suppose -1 fullness is always good for turnbloat? - if (augSkillNumber == 16) usefulAugustSkills[16] = "-1 fullness, +100% food drop "+blastingAddendum; - - if (manorCheck) { - // Only need booze drop if you don't already have vinegar - if ($item[bottle of Chateau de Vinegar].available_amount() == 0) { - if (augSkillNumber == 31) usefulAugustSkills[31] = "+100% booze drop wine "+HTMLGenerateSpanFont("(chateau de vinegar!)", "gray", "0.9em"); - } - - } - - // +item/meat is always good times - if (augSkillNumber == 7) usefulAugustSkills[7] = "+50% item, +100% meat"+buffString; - - // LUCKY!; 2, but important! 21/31 skills - if (augSkillNumber == 2) usefulAugustSkills[2] = "get Lucky!"; - - // WAFFLES!; 24, but the best guy here. 22/31 - if (augSkillNumber == 24) usefulAugustSkills[24] = "3 waffles, for monster replacement"; - - - // FREE TOOTH MONSTER; lol what the actual heck (22) 24/31 - if (augSkillNumber == 22) usefulAugustSkills[22] = "free fight for teeeeeeeeeeeth"; - - // +COM FOR NINJAS; kind of a crock but why not (6) 25/31 - if (!__quest_state["Level 8"].state_boolean["Mountain climbed"]) { - if (augSkillNumber == 6) usefulAugustSkills[6] = "+10% combat"+buffString; - } - - // HAND HOLDING; we still don't know exactly what this does (9) 26/31 - if (augSkillNumber == 9) usefulAugustSkills[9] = "hold hands for a minor sniff"; - - // LION BANISH; definitely worth calling out; NOT a killbanish (10) 27/31 - if (augSkillNumber == 10) usefulAugustSkills[10] = "non-free reusable banishes"+buffString; - - // OFFHAND DOUBLER; wild stuff folks (13) 28/31 - int usefulOffhands = $item[deck of lewd playing cards].available_amount(); - int protestorsRemaining = clampi(80 - get_property_int("zeppelinProtestors"), 0, 80); - - if (usefulOffhands > 0 && protestorsRemaining > 10) { - // you could probably add a few other things to this, like -ML for goo or big smithsness. but eh. - if (augSkillNumber == 13) usefulAugustSkills[13] = "double offhand enchantments "+HTMLGenerateSpanOfClass("(sleaze ", "r_element_sleaze_desaturated")+"for protestors)"; - } - - // SAVE 1000 MEAT; barely useful, only show if they're strapped (17) 29/31 - - // CRAZY HORSE RETURNS; just because (27) 30/31 - string randomInRainbow = HTMLGenerateSpanOfClass("r", "r_element_hot_desaturated")+HTMLGenerateSpanOfClass("a", "r_element_stench_desaturated")+HTMLGenerateSpanOfClass("n", "r_element_sleaze_desaturated")+HTMLGenerateSpanOfClass("d", "r_element_cold_desaturated")+HTMLGenerateSpanOfClass("o", "r_element_spooky_desaturated")+HTMLGenerateSpanOfClass("m", "r_element_hot_desaturated"); - if (augSkillNumber == 27) usefulAugustSkills[27] = "+3 "+randomInRainbow+" effects"+buffString; - - // +10 FAM WEIGHT; this won't appear in modern standard lol (28) 31/31 - if (__misc_state["free runs usable"] && ($familiar[pair of stomping boots].familiar_is_usable() || ($skill[the ode to booze].skill_is_usable() && $familiar[Frumious Bandersnatch].familiar_is_usable()))) { - if ($item[astral pet sweater].available_amount() == 0) { - if (augSkillNumber == 28) usefulAugustSkills[28] = "+10 weight familiar equipment "+HTMLGenerateSpanFont("(melting)", "gray", "0.9em"); - } - } - } - - string [int][int] table; - string [int] description; - - table.listAppend(listMake(HTMLGenerateSpanOfClass("Day", "r_bold"), HTMLGenerateSpanOfClass("Result", "r_bold"))); - - foreach day, reason in usefulAugustSkills { - table.listAppend(listMake(day.to_string(), reason)); - } - - string table_description = ""; - if (table.count() > 0) - table_description += "|*" + HTMLGenerateSimpleTableLines(table); - - // Summary of the august tile - string summarizeAugust = "Celebrate August tidings; cast skills corresponding to the given day to get valuable benefits."; - - if (table_description != "") - description.listAppend(summarizeAugust + table_description); - else - description.listAppend(summarizeAugust); - - string title = "Cast "+pluralise(skillsAvailable, "August Scepter skill", "August Scepter skills"); - - string subtitle = "all buffs are 30 turns"; - - // Make a big tooltip with all skills & their results listed out and colored - string [int] [int] allSkills; - int todaySkillInt = today_to_string().to_int() % 100; - - allSkills.listAppend(listMake(HTMLGenerateSpanOfClass("Day", "r_bold"), HTMLGenerateSpanOfClass("Gives you...", "r_bold"))); - - - // Have to do this to ensure the tooltip orders appropriately - string [int] allAugustSkills; - - foreach augSkill, augSkillValue in __augSkillsToValue { - allAugustSkills[grabNumber(augSkill)] = augSkill; - } - - // Now that it is correctly iterating in order, color appropriately and build the allSkill table. - foreach augSkillNumber, augSkill in allAugustSkills { - string lineColor = "black"; - string augSkillValue = __augSkillsToValue[augSkill]; - - // Color the "free" skill in blue if they're in aftercore - if (!__misc_state["in run"] && augSkillNumber == todaySkillInt) lineColor = "blue"; - if (get_property_boolean(__augSkillsToVars[augSkill])) lineColor = "gray"; - - allSkills.listAppend(listMake(HTMLGenerateSpanFont(augSkillNumber, lineColor),HTMLGenerateSpanFont(augSkillValue, lineColor))); - } - - // give a tip of the cap to the ol tools here - buffer tooltip; - tooltip.append(HTMLGenerateTagWrap("div", "Well, you asked for it!", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); - tooltip.append(HTMLGenerateSimpleTableLines(allSkills)); - string tooltipEnumerated = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "No, TourGuide, show me ALL the skills.", "r_tooltip_outer_class"); - description.listAppend(tooltipEnumerated); - - resource_entries.listAppend(ChecklistEntryMake("__item August Scepter", "skillz.php", ChecklistSubentryMake(title, subtitle, description), -1).ChecklistEntrySetIDTag("August Scepter resource")); - -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2023/Book of Facts.ash b/Source/relay/TourGuide/Items of the Month/2023/Book of Facts.ash deleted file mode 100644 index c4ff4b43..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/Book of Facts.ash +++ /dev/null @@ -1,92 +0,0 @@ -//Book of FActs -RegisterTaskGenerationFunction("IOTMBookofFactsGenerateTasks"); -void IOTMBookofFactsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - // Exit out of the tile if they have neither skill and we don't actually think they should, either - if (!lookupSkill("Just the Facts").have_skill() && !__iotms_usable[$item[book of facts (dog-eared)]]) return; - - monster habitat_monster = get_property_monster("_monsterHabitatsMonster"); - int fights_left = clampi(get_property_int("_monsterHabitatsFightsLeft"), 0, 5); - string [int] description; - - // If they have an eagle, remind them they can eagle-banish to make it easier to find the habitat guys - string eagleString = lookupFamiliar("Patriotic Eagle").familiar_is_usable() ? "; remember, you can phylum-banish with your Patriotic Eagle to make it easier!" : "." ; - phylum eaglePhylumBanished = $phylum[none]; - - if (get_property("banishedPhyla") != "") - eaglePhylumBanished = get_property("banishedPhyla").split_string(":")[1].to_phylum(); - - if (habitat_monster != $monster[none] && fights_left > 0) - { - description.listAppend("Neaaaar, faaaaaaar, wherever you spaaaaaaar, I believe that the heart does go onnnnn."); - description.listAppend("Appears as a wandering monster in any zone. Try a place with few competing monsters"+eagleString); - - if (eaglePhylumBanished == habitat_monster.phylum) { - description.listAppend(HTMLGenerateSpanFont(`WARNING: {habitat_monster}'s phylum is banished!`, "red")); - } - - if (habitat_monster.is_banished()) { - description.listAppend(HTMLGenerateSpanFont(`WARNING: {habitat_monster} is banished!`, "red")); - } - - optional_task_entries.listAppend(ChecklistEntryMake("__monster " + habitat_monster, "", ChecklistSubentryMake("Fight " + pluralise(fights_left, "more non-native " + habitat_monster, "more non-native " + habitat_monster + "s"), "", description), -4)); - } - - // Moving priority on this down a tiny bit due to in-run mediocrity - int circadianAdv = (get_property_int("_circadianRhythmsAdventures")); - if ($effect[Recalling Circadian Rhythms].have_effect() > 0 && circadianAdv < 10) { - string [int] circadianDescription; - string circadianPhylum = (get_property("_circadianRhythmsPhylum")); - circadianDescription.listAppend("Fight " + (11 - circadianAdv) + " more " + circadianPhylum + "s to get RO advs."); - task_entries.listAppend(ChecklistEntryMake("__item cheap wind-up clock", "", ChecklistSubentryMake("Circadian Rhythms turngen", circadianDescription), -1).ChecklistEntrySetIDTag("Circadian Rhythms turngen")); - } -} - -RegisterResourceGenerationFunction("IOTMBookofFactsGenerateResource"); -void IOTMBookofFactsGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupSkill("Just the Facts").have_skill() && !__iotms_usable[$item[book of facts (dog-eared)]]) return; - string [int] description; - string [int] circadianDescription; - - // Populating different things based on run state & IOTM availability - string constructDescriptor = __iotms_usable[$item[X-32-F snowman crate]] ? " + snojo" : ""; - if (lookupItem("[glitch season reward name]").item_amount() > 0) constructDescriptor += " + glitch"; - string dudeDescriptor = __iotms_usable[$item[Witchess Set]] ? " + witchess" : ""; - if (__iotms_usable[lookupItem("Neverending Party invitation envelope")]) dudeDescriptor += " + NEP"; - string horrorDescriptor = lookupItem("closed-circuit pay phone").have() ? " + shadow rifts" : ""; - - if (!get_property_boolean("_circadianRhythmsRecalled")) { - circadianDescription.listAppend("Can recall Circadian Rhythms to get +11 RO adv."); - circadianDescription.listAppend("Good targets: construct (nightstands"+constructDescriptor+"), dudes (pygmies"+dudeDescriptor+"), horrors (copied tentacles"+horrorDescriptor+")"); - resource_entries.listAppend(ChecklistEntryMake("__item cheap wind-up clock", "", ChecklistSubentryMake("Circadian Rhythms turngen", circadianDescription), 11).ChecklistEntrySetIDTag("Circadian Rhythms turngen")); - } - - int habitatRecallsLeft = clampi(3 - get_property_int("_monsterHabitatsRecalled"), 0, 3); - if (get_property_int("_monsterHabitatsRecalled") < 3) { - description.listAppend("Good targets include monsters you want 6 of:"); - description.listAppend("Fantasy bandit, eldritch tentacle, black crayon orc if the stars align"); - resource_entries.listAppend(ChecklistEntryMake("__item hey deze map", "", ChecklistSubentryMake(pluralise(habitatRecallsLeft, "Habitat recall", "Habitat recalls"), "", description), 8).ChecklistEntrySetIDTag("habitat recalls")); - } - - // TODO: Once mt_rand is exposed, show on-path wishes. Not really doable yet lol - string [int] BOFAdropsDescription; - int BOFApocketwishes = clampi(3 - get_property_int("_bookOfFactsWishes"), 0, 3); - if (get_property_int("_bookOfFactsWishes") < 3) { - BOFAdropsDescription.listAppend("" + BOFApocketwishes + " BOFA wishes available."); - } - - // NOTE: Altering as of 2024 ELG change, as tatters are 40 turns vs the 30 of spring shoes. - // There is a remote chance in some future standard context tatters will be the best option - // for a user with some odd IOTM configurations, which is why I didn't entirely extract - // this, but it at least shouldn't be present if they own the candles or the shoes. - - if (!__iotms_usable[lookupItem("spring shoes")] && $item[roman candelabra].available_amount() == 0) { - int BOFAtatters = clampi(11 - get_property_int("_bookOfFactsTatters"), 0, 11); - if (get_property_int("_bookOfFactsTatters") < 11) { - BOFAdropsDescription.listAppend("" + BOFAtatters + " BOFA tatters available."); - } - } - - resource_entries.listAppend(ChecklistEntryMake("__item book of facts", "", ChecklistSubentryMake(("Miscellaneous valuable BOFA drops"), "", BOFAdropsDescription), 8).ChecklistEntrySetIDTag("bofa tatters")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2023/Candy Cane Sword Cane.ash b/Source/relay/TourGuide/Items of the Month/2023/Candy Cane Sword Cane.ash deleted file mode 100644 index 4997e956..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/Candy Cane Sword Cane.ash +++ /dev/null @@ -1,105 +0,0 @@ -// Candy Cane Sword Cane -RegisterTaskGenerationFunction("IOTMCandyCaneSwordGenerateTasks"); -void IOTMCandyCaneSwordGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - // Initialization. Good use of "lookupItem" for backwards compatibility reasons. - if (!__iotms_usable[lookupItem("candy cane sword cane")]) return; - int ccscEquipped = lookupItem("candy cane sword cane").equipped_amount(); - string ccscEquipStatement = ccscEquipped > 0 ? "Keep your Candy Cane Sword Cane equipped!" : "Equip your Candy Cane Sword Cane!"; - string [int] description; - string [int] describeSupernag; - string [int] options; - - // Added a check for all paths where you do not want the tile at all: - // - Community Service & Grey Goo: irrelevant - // - Avatar of Boris: cannot wield a weapon other than trusty or use a familiar - // - 11,037 Leagues Under the Sea: irrelevant - boolean pathCheck = true; - pathCheck = my_path().id == PATH_SEA ? false : true; - pathCheck = my_path().id == PATH_COMMUNITY_SERVICE ? false : true; - pathCheck = my_path().id == PATH_GREY_GOO ? false : true; - pathCheck = my_path().id == PATH_AVATAR_OF_BORIS ? false : true; - - // Only show when in run, for obvious reasons. - if (__misc_state["in run"] && pathCheck) - { - string url = "inventory.php?ftext=candy+cane+sword+cane"; - // This is the description for the supernag. The supernag is in the task_entries, buried within conditional ifs and only shows up if you're in the zone. - describeSupernag.listAppend(HTMLGenerateSpanFont("You're", "red") + " " + HTMLGenerateSpanFont("in a", "green") + " " + HTMLGenerateSpanFont("candy", "red") + " " + HTMLGenerateSpanFont("cane", "green") + " " + HTMLGenerateSpanFont("sword", "red") + " " + HTMLGenerateSpanFont("cane", "green") + " " + HTMLGenerateSpanFont("noncom", "red") + " " + HTMLGenerateSpanFont("zone!", "green")); - - // This enumerates the useful CCSC adventures - if (!get_property_boolean("_candyCaneSwordLyle")) { - options.listAppend(HTMLGenerateSpanOfClass("Bonus:", "r_bold") + " Lyle's Monorail Buff (+40% init)"); - } - - // Added a check for if they are past black forest - if (!get_property_boolean("candyCaneSwordBlackForest") && __quest_state["Level 11"].mafia_internal_step < 2) { - options.listAppend(HTMLGenerateSpanOfClass("Bonus:", "r_bold") + " The Black Forest (+8 exploration)"); - if (($locations[The Black Forest] contains __last_adventure_location)) { - task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); - } - } - - // Added a check for if they need the loot token. - if (!get_property_boolean("candyCaneSwordDailyDungeon") && __misc_state_int["fat loot tokens needed"] > 0) { - options.listAppend(HTMLGenerateSpanOfClass("Bonus:", "r_bold") + " Daily Dungeon (+1 fat loot token)"); - if (($locations[The Daily Dungeon] contains __last_adventure_location)) { - task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); - } - } - - // Added a check for if they need a curse - if (!get_property_boolean("candyCaneSwordApartmentBuilding") && get_property_int("hiddenApartmentProgress") < 8) { - options.listAppend(HTMLGenerateSpanOfClass("Bonus:", "r_bold") + " Hidden Apartment (+1 Curse)"); - if (($locations[The Hidden Apartment Building] contains __last_adventure_location)) { - task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); - } - } - - // Added a check for if they need bowling alley access by checking the bowling alley progress var - if (!get_property_boolean("candyCaneSwordBowlingAlley") && get_property_int("hiddenBowlingAlleyProgress") < 7) { - options.listAppend(HTMLGenerateSpanOfClass("Bonus:", "r_bold") + " Hidden Bowling Alley (+1 free bowl)"); - if (($locations[The Hidden Bowling Alley] contains __last_adventure_location)) { - task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); - } - } - - // Added a check for if they need shore access - if (!get_property_boolean("candyCaneSwordShore") && !__misc_state["mysterious island available"]) { - options.listAppend(HTMLGenerateSpanOfClass("Alternate:", "r_bold") + " Shore (2 scrips for the price of 1)"); - if (($locations[The Shore\, Inc. Travel Agency] contains __last_adventure_location)) { - task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); - } - } - - // Added a check for if war is finished - if (locationAvailable($location[The Battlefield (Frat Uniform)]) == false && !__quest_state["Level 12"].finished) { - options.listAppend(HTMLGenerateSpanOfClass("Alternate:", "r_bold") + " Hippy Camp (Redirect to the War Start NC)"); - if (($locations[Wartime Hippy Camp,Wartime Frat House] contains __last_adventure_location)) { - task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); - } - } - - // Changed condition to <80 protestors check - if (get_property_int("zeppelinProtestors") < 80) { - options.listAppend(HTMLGenerateSpanOfClass("Alternate: ", "r_bold") + "Zeppelin Protesters " + HTMLGenerateSpanFont("(double Sleaze damage!)", "purple")); - if (($locations[A Mob of Zeppelin Protesters] contains __last_adventure_location)) { - task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); - } - } - - if (options.count() > 0) { - description.listAppend("Ensure your CCSC is equipped for useful NCs:" + options.listJoinComponents("
").HTMLGenerateIndentedText()); - - // Darkened from bright red to maroon as it will be irrelevant for many parts of the run. - if (lookupItem("candy cane sword cane").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the Candy Cane Sword Cane!", "maroon")); - } - - optional_task_entries.listAppend(ChecklistEntryMake("__item Candy cane sword cane", url, ChecklistSubentryMake("Candy Cane Sword Cane NCs", description)).ChecklistEntrySetCombinationTag("CCSC tasks").ChecklistEntrySetIDTag("CCSC")); - } - - } - -} - diff --git a/Source/relay/TourGuide/Items of the Month/2023/Cincho de Mayo.ash b/Source/relay/TourGuide/Items of the Month/2023/Cincho de Mayo.ash deleted file mode 100644 index 6a90dcc8..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/Cincho de Mayo.ash +++ /dev/null @@ -1,87 +0,0 @@ -RegisterResourceGenerationFunction("IOTMCinchoDeMayoGenerateResource"); -void IOTMCinchoDeMayoGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[Cincho de Mayo]]) return; - - // _cinchUsed is a weird preference that actually means distance from 100% you are at in your current cinch. - int freeRests = __misc_state_int["total free rests possible"]; - int freeRestsRemaining = __misc_state_int["free rests remaining"]; - int cinchoRests = get_property_int('_cinchoRests'); - int cinchUsed = get_property_int('_cinchUsed'); - - // Resting when Cincho is full might burn some of the Cincho rests - freeRests = min(freeRests, cinchoRests + freeRestsRemaining); - - // Since the pref is weird, this tells you your current total cinch - int currentCinch = 100 - cinchUsed; - - // Calculating total available cinch requires storing the degradation of rest value - int [int] cinchLevels = listMake(30,30,30,30,30,25,20,15,10,5); - - // Reiterating current state so the while loop can update it - int totalCinch = 100 - cinchUsed; - int rest = cinchoRests; - - // This while loop expands your possible cinch starting at rests you haven't used. - while (rest < freeRests) - { - int cinchAmount = rest >= count(cinchLevels) ? 5 : cinchLevels[rest]; - totalCinch += cinchAmount; - rest += 1; - } - - // This gives you your possible uses of the most powerful skill, Fiesta Exits - int possibleFiestaExits = floor(totalCinch/60); - - // return if there is no cinch remaining for the homeboys - if (totalCinch == 0) return; - - string [int] description; - string [int] cinchUses; - - // If not equipped, link to the inventory. - string url = "inventory.php?ftext=cincho"; - - // If equipped, link to skills. - if ($item[Cincho de Mayo].equipped_amount() == 1) { - url = 'skills.php'; - - // ... unless you have <60 cinch lol - if (totalCinch < 60) { - url = 'campground.php'; - } - } - - // For each use, check that there's enough cinch remaining to use it before appending. - if (totalCinch > 25) { - cinchUses.listAppend("Dispense Salt & Lime (25%): Add stats to your next drink."); - cinchUses.listAppend("Party Soundtrack (25%): 30 advs of +5 fam weight."); - } - - if (totalCinch > 5) { - cinchUses.listAppend("Confetti Extravaganza (5%): 2x stats, in-combat"); - cinchUses.listAppend("Projectile Piñata (5%): 50 damage, complex candy, in-combat"); - cinchUses.listAppend("Party Foul (5%): 100"+HTMLGenerateSpanOfClass(" sleaze ", "r_element_sleaze")+"damage, stun, in-combat"); - } - - // This should always be true because there's no way to have <5 cinch and not hit the return on line 33. - // Still including it as a conditional for the tile build as a failsafe I guess. - if (cinchUses.count() > 0) - description.listAppend("Use your Cincho de Mayo to cast skills in exchange for cinch; when you're out of cinch, take a free rest!?"); - - // Doing this one outside of the large list append, because it's more important. - if (totalCinch > 60) { - description.listAppend(""+HTMLGenerateSpanOfClass("Fiesta Exit (60%)", "r_element_sleaze")+": Force a NC on your next adventure. "+`You have {possibleFiestaExits} more possible, with {totalCinch % 60}% cinch leftover`); - } - - // Merge the list components together. - description.listAppend("|*"+ cinchUses.listJoinComponents("
|*")); - - description.listAppend(`You have {totalCinch}% more cinch available, accounting for your {pluralise(freeRestsRemaining,"remaining free rest","remaining free rests")}.`); - - if (lookupItem("June cleaver").have() && !lookupItem("mother's necklace").have()) { - description.listAppend("You do "+HTMLGenerateSpanOfClass("not", "r_element_hot")+" have a mother's necklace yet, so you're missing 5 free rests. Be careful of overusing the combat skills!"); - } - - resource_entries.listAppend(ChecklistEntryMake("__item cincho de mayo", url, ChecklistSubentryMake(`{currentCinch}% belt cinch`, "", description), 3).ChecklistEntrySetIDTag("Cincho de Mayo resource")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2023/Closed Circuit Pay Phone.ash b/Source/relay/TourGuide/Items of the Month/2023/Closed Circuit Pay Phone.ash deleted file mode 100644 index 7ec2db13..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/Closed Circuit Pay Phone.ash +++ /dev/null @@ -1,176 +0,0 @@ -//shadow phone -QuestState parseRufusQuestState() { - /* - Below description from Veracity's PR introducing Rufus quest tracking: - https://github.com/kolmafia/kolmafia/pull/1613 - > "unstarted" -> we have not accepted a quest - > "started" -> we have accepted a quest but not yet fulfilled the requirement - > "step1" -> we have fulfilled the requirement but not called Rufus back yet to report our success - > (Calling Rufus back and fulfilling the quest sends us back to "unstarted".) - - This works nicely with TourGuide's QuestState tracking so we can parse right out of it. - */ - QuestState state = QuestState("questRufus"); - - // Because mafia_internal_step tracking is confusing, and the quest never actually gets - // marked as finished, let's add a boolean to track whether we've done the objective - // (but not yet called Rufus back) - state.state_boolean["quest objective fulfilled"] = state.mafia_internal_step == 2; - - return state; -} - -record ShadowBrickLocation { - string zoneName; - string extraItems; - boolean canAccess; -}; - -string getShadowBrickLocationTooltip() { - ShadowBrickLocation [int] shadowBrickLocations = { - new ShadowBrickLocation( - "Cemetary", - "(also has bread, stick)", - can_adventure($location[Shadow Rift (The Misspelled Cemetary)]) - ), - new ShadowBrickLocation( - "Hidden City", - "(also has sinew, nectar)", - can_adventure($location[Shadow Rift (The Hidden City)]) - ), - new ShadowBrickLocation( - "Pyramid", - "(also has sausage, sinew)", - can_adventure($location[Shadow Rift (The Ancient Buried Pyramid)]) - ) - }; - - string [int][int] shadowBricksTable; - foreach index, brickLocation in shadowBrickLocations { - string formattedLocationName = brickLocation.canAccess ? - HTMLGenerateSpanOfClass(brickLocation.zoneName, "r_bold") : - HTMLGenerateSpanOfClass(HTMLGenerateSpanFont(brickLocation.zoneName, "gray"), "r_bold"); - shadowBricksTable.listAppend(listMake(formattedLocationName, brickLocation.extraItems)); - } - - string shadowBricksTooltip = HTMLGenerateSimpleTableLines(shadowBricksTable); - return HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(shadowBricksTooltip, "r_tooltip_inner_class") + "Shadow Brick locations", "r_tooltip_outer_class"); -} - -RegisterTaskGenerationFunction("IOTMClosedCircuitPayPhoneGenerateTasks"); -void IOTMClosedCircuitPayPhoneGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - if (!lookupItem("closed-circuit pay phone").have()) - return; - - if (my_path().id == PATH_G_LOVER) return; // cannot use payphone in g-lover - - string url = "inv_use.php?pwd=" + my_hash() + "&which=3&whichitem=11169"; - QuestState state = parseRufusQuestState(); - - ChecklistEntry [int] whereToAddRufusQuestTile; - string rufusImage = "__item closed-circuit pay phone"; - string rufusQuestTitle; - string rufusQuestTarget = get_property("rufusQuestTarget"); - string [int] rufusQuestDescription; - int rufusQuestPriority; - int shadowRiftFightsDoableRightNow = $effect[Shadow Affinity].have_effect(); - - int shadowLodestones = available_amount($item[Rufus's shadow lodestone]); - if (shadowLodestones > 0) { - rufusQuestDescription.listAppend(HTMLGenerateSpanFont("Have " + pluralise($item[Rufus's shadow lodestone]) + ".", "purple")); - } - - int riftAdvsUntilNC = get_property_int("encountersUntilSRChoice"); - if (shadowRiftFightsDoableRightNow > 0) { - rufusQuestDescription.listAppend(HTMLGenerateSpanFont("" + shadowRiftFightsDoableRightNow + " Shadow Rift free fights", "purple")); - } - rufusQuestDescription.listAppend(HTMLGenerateSpanFont(riftAdvsUntilNC + " encounters until NC/boss.", "black")); - - if (state.state_boolean["quest objective fulfilled"]) { - // We've fulfilled the quest objective but still need to call Rufus - rufusQuestDescription.listAppend(HTMLGenerateSpanFont("Call Rufus and get a lodestone", "black")); - rufusQuestTitle = "Rufus quest done"; - rufusQuestPriority = -11; - whereToAddRufusQuestTile = task_entries; - } - else if (state.started && riftAdvsUntilNC == 0) { - rufusQuestDescription.listAppend("Looking for " + HTMLGenerateSpanFont(rufusQuestTarget, "blue")); - rufusQuestTitle = "Shadow Rift NC up next"; - rufusQuestPriority = -11; - rufusImage = "__item shadow bucket"; - whereToAddRufusQuestTile = task_entries; - } - else if (state.started) { - rufusQuestTitle = "Rufus quest in progress"; - rufusQuestPriority = 999; - whereToAddRufusQuestTile = optional_task_entries; - } - else if (!state.started) { - boolean calledRufusToday = get_property_boolean("_shadowAffinityToday"); - string textColor = calledRufusToday ? "black" : "blue"; - string callRufusMessage = calledRufusToday ? "Optionally call Rufus again for another (turn-taking) quest." : "Haven't called Rufus yet today."; - rufusQuestDescription.listAppend(HTMLGenerateSpanFont(callRufusMessage, textColor)); - rufusQuestTitle = "Rufus quest doable now"; - rufusQuestPriority = 999; - whereToAddRufusQuestTile = optional_task_entries; - } - - rufusQuestDescription.listAppend(getShadowBrickLocationTooltip()); - - whereToAddRufusQuestTile.listAppend(ChecklistEntryMake(rufusImage, url, ChecklistSubentryMake(rufusQuestTitle, "", rufusQuestDescription), rufusQuestPriority)); - - if ($effect[Shadow Affinity].have_effect() > 0 && riftAdvsUntilNC != 0 && !state.state_boolean["quest objective fulfilled"]) { - int riftAdvsUntilNC = get_property_int("encountersUntilSRChoice"); - string [int] affinityDescription; - if (shadowLodestones > 0) { - affinityDescription.listAppend(HTMLGenerateSpanFont("Have " + pluralise($item[Rufus's shadow lodestone]) + ".", "purple")); - } - affinityDescription.listAppend(HTMLGenerateSpanFont("Shadow Rift fights are free!", "purple")); - affinityDescription.listAppend(HTMLGenerateSpanFont(riftAdvsUntilNC + " encounters until NC/boss.", "black")); - affinityDescription.listAppend(HTMLGenerateSpanFont("(don't use other free kills in there)", "black")); - task_entries.listAppend(ChecklistEntryMake("__effect Shadow Affinity", url, ChecklistSubentryMake(shadowRiftFightsDoableRightNow + " Shadow Rift free fights", "", affinityDescription), -11)); - } -} - -void showShadowBrickFreeKills(ChecklistEntry [int] resource_entries) { - int shadowBricks = available_amount($item[shadow brick]); - int shadowBrickUsesLeft = clampi(13 - get_property_int("_shadowBricksUsed"), 0, 13); - if ($item[shadow brick].available_amount() > 0) { - string header = $item[shadow brick].pluralise().capitaliseFirstLetter(); - if (shadowBrickUsesLeft < shadowBricks) { - if (shadowBrickUsesLeft == 0) - header += " (not usable today)"; - else - header += " (" + shadowBrickUsesLeft + " usable today)"; - } - resource_entries.listAppend(ChecklistEntryMake("__item shadow brick", "", ChecklistSubentryMake(header, "", "Win a fight without taking a turn.")).ChecklistEntrySetCombinationTag("free instakill")); - } -} - -RegisterResourceGenerationFunction("IOTMClosedCircuitPayPhoneGenerateResource"); -void IOTMClosedCircuitPayPhoneGenerateResource(ChecklistEntry [int] resource_entries) { - // Shadow bricks don't depend on having the IOTM - showShadowBrickFreeKills(resource_entries); - - if (!lookupItem("closed-circuit pay phone").have()) - return; - - if (my_path().id == PATH_G_LOVER) return; // cannot use payphone in g-lover - - string url = "inv_use.php?pwd=" + my_hash() + "&which=3&whichitem=11169"; - - int shadowLodestones = available_amount($item[Rufus's shadow lodestone]); - - if (shadowLodestones > 0) { - string [int] lodestoneDescription; - lodestoneDescription.listAppend("30 advs of +100% init, +100% item, +200% meat, -10% combat."); - lodestoneDescription.listAppend("Triggers on next visit to any Shadow Rift."); - resource_entries.listAppend(ChecklistEntryMake("__item Rufus's shadow lodestone", url, ChecklistSubentryMake(shadowLodestones + " Rufus's shadow lodestones", lodestoneDescription), 5)); - } - - if (!get_property_boolean("_shadowAffinityToday")) { - string [int] affinityDescription; - affinityDescription.listAppend("Call Rufus to get 11+ free Shadow Rift combats."); - resource_entries.listAppend(ChecklistEntryMake("__effect Shadow Affinity", url, ChecklistSubentryMake("Shadow Affinity free fights", "", affinityDescription), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Shadow affinity free fights")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2023/Cursed Monkey Paw.ash b/Source/relay/TourGuide/Items of the Month/2023/Cursed Monkey Paw.ash deleted file mode 100644 index 4b59fa6d..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/Cursed Monkey Paw.ash +++ /dev/null @@ -1,361 +0,0 @@ -record MonkeyWish { - // If the wish is an item, set that here. Otherwise, use $item[none]. - item theItem; - - // If the wish is an effect, set that here. Otherwise, use $effect[none]. - effect theEffect; - - // If you want additional description text other than the item/effect name, - // set that here. - string additionalDescription; - - // A boolean value indicating whether the wish is useful at all. - boolean shouldDisplay; - - // A boolean value indicating whether the wish is currently accessible - // (since the paw will prevent wishes you can't access). - boolean currentlyAccessible; -}; - -string showWish(MonkeyWish wish) { - string color = wish.currentlyAccessible ? "black" : "gray"; - string wishStr; - string additionalDescription = wish.additionalDescription != "" ? - `: {wish.additionalDescription}` : - ""; - if (wish.theItem != $item[none]) { - wishStr = `{wish.theItem.name}{additionalDescription}`; - } else if (wish.theEffect != $effect[none]) { - wishStr = `{wish.theEffect.name}{additionalDescription}`; - } else { - wishStr = "Unknown item/effect. Report to TourGuide devs >:("; - } - return HTMLGenerateSpanFont(wishStr, color); -} - -string [int] showWishes(MonkeyWish [int] wishes) { - string [int] currentWishes = {}; - string [int] futureWishes = {}; - // My kingdom for polymorphic filter :| - foreach index, wish in wishes { - if (!wish.shouldDisplay) continue; - - if (wish.currentlyAccessible) { - currentWishes.listAppend(showWish(wish)); - } else { - futureWishes.listAppend(showWish(wish)); - } - } - string [int] allWishes = {}; - allWishes.listAppendList(currentWishes); - allWishes.listAppendList(futureWishes); - return allWishes; -} - -record MonkeySkill { - int fingerCount; - skill theSkill; - string description; -}; - -RegisterResourceGenerationFunction("IOTMCursedMonkeysPawGenerateResource"); -void IOTMCursedMonkeysPawGenerateResource(ChecklistEntry [int] resource_entries) { - if (!lookupItem("cursed monkey's paw").have()) return; - - string url; - string [int] description; - url = "main.php?action=cmonk&pwd=" + my_hash() + ""; - description.listAppend("Return to monke. Wish for items or effects:"); - - MonkeyWish [int] inRunWishes = { - new MonkeyWish( - $item[sonar-in-a-biscuit], - $effect[none], - "", - get_property("questL04Bat") != "finished" && - !locationAvailable($location[The Boss Bat's Lair]), - locationAvailable($location[Guano Junction]) - ), - new MonkeyWish( - $item[enchanted bean], - $effect[none], - "", - !__quest_state["Level 10"].state_boolean["beanstalk grown"] && - available_amount($item[enchanted bean]) < 1, - locationAvailable($location[The Beanbat Chamber]) - ), - new MonkeyWish( - $item[none], - $effect[Knob Goblin Perfume], - "", - !__quest_state["Level 5"].finished && - available_amount($item[Knob Goblin perfume]) < 1, - true - ), - new MonkeyWish( - $item[Knob Goblin harem veil], - $effect[none], - "", - !__quest_state["Level 5"].finished && - available_amount($item[Knob Goblin harem veil]) < 1, - locationAvailable($location[Cobb's Knob Harem]) - ), - new MonkeyWish( - $item[Knob Goblin harem pants], - $effect[none], - "", - !__quest_state["Level 5"].finished && - available_amount($item[Knob Goblin harem pants]) < 1, - locationAvailable($location[Cobb's Knob Harem]) - ), - new MonkeyWish( - $item[stone wool], - $effect[none], - "", - !locationAvailable($location[The Hidden Park]) && - available_amount($item[stone wool]) < 2, - locationAvailable($location[The Hidden Temple]) - ), - new MonkeyWish( - $item[amulet of extreme plot significance], - $effect[none], - "", - !locationAvailable($location[The Castle In The Clouds In The Sky (Ground Floor)]) && - available_amount($item[amulet of extreme plot significance]) < 1, - locationAvailable($location[The Penultimate Fantasy Airship]) - ), - new MonkeyWish( - $item[mohawk wig], - $effect[none], - "", - !__quest_state["Level 10"].finished && - available_amount($item[mohawk wig]) < 1, - locationAvailable($location[The Penultimate Fantasy Airship]) - ), - new MonkeyWish( - $item[book of matches], - $effect[none], - "", - my_ascensions() != get_property_int("hiddenTavernUnlock") && - $item[book of matches].available_amount() < 1, - locationAvailable($location[The Hidden Park]) - ), - new MonkeyWish( - $item[rusty hedge trimmers], - $effect[none], - "", - get_property_int("twinPeakProgress") < 13, - locationAvailable($location[Twin Peak]) - ), - new MonkeyWish( - $item[killing jar], - $effect[none], - "", - !__quest_state["Level 11 Desert"].state_boolean["Killing Jar Given"] && - get_property_int("desertExploration") < 100 && - available_amount($item[killing jar]) < 1, - locationAvailable($location[The Haunted Library]) - ), - new MonkeyWish( - $item[none], - $effect[Dirty Pear], - HTMLGenerateSpanFont("double sleaze damage", "purple"), - get_property_int("zeppelinProtestors") < 80, - true - ), - new MonkeyWish( - $item[none], - $effect[Painted-On Bikini], - HTMLGenerateSpanFont("+100 sleaze damage", "purple"), - get_property_int("zeppelinProtestors") < 80, - true - ), - new MonkeyWish( - $item[glark cable], - $effect[none], - "", - __quest_state["Level 11 Ron"].mafia_internal_step < 5, - locationAvailable($location[The Red Zeppelin]) - ), - new MonkeyWish( - $item[short writ of habeas corpus], - $effect[none], - "", - !__quest_state["Level 11 Hidden City"].finished, - locationAvailable($location[The Hidden Park]) - ), - new MonkeyWish( - $item[lion oil], - $effect[none], - "", - $item[mega gem].available_amount() < 1 && - $item[lion oil].available_amount() < 1, - locationAvailable($location[Whitey's Grove]) - ), - new MonkeyWish( - $item[bird rib], - $effect[none], - "", - $item[mega gem].available_amount() < 1 && - $item[bird rib].available_amount() < 1, - locationAvailable($location[Whitey's Grove]) - ), - new MonkeyWish( - $item[drum machine], - $effect[none], - "", - get_property_int("desertExploration") < 100 && - $item[drum machine].available_amount() < 1, - locationAvailable($location[The Oasis]) - ), - new MonkeyWish( - $item[shadow brick], - $effect[none], - "", - get_property_int("_shadowBricksUsed") + available_amount($item[shadow brick]) < 13, - true - ), - new MonkeyWish( - $item[green smoke bomb], - $effect[none], - "", - !__quest_state["Level 12"].finished && - __quest_state["Level 12"].state_string["Side seemingly fighting for"] != "hippy", - __quest_state["Level 12"].state_boolean["War in progress"] && - get_property_int("hippiesDefeated") >= 400 - ), - new MonkeyWish( - $item[star chart], - $effect[none], - "", - !__quest_state["Level 13"].state_boolean["Richard's star key used"] && - $item[Richard's star key].available_amount() < 1 && - $item[star chart].available_amount() < 1, - locationAvailable($location[The Hole In The Sky]) - ), - new MonkeyWish( - $item[none], - $effect[Frosty], - "init/item/meat", - !__quest_state["Level 13"].state_boolean["digital key used"] && - $item[digital key].available_amount() < 1 && - get_property("8BitScore") < 10000, - true - ), - new MonkeyWish( - $item[none], - $effect[Staying Frosty], - HTMLGenerateSpanFont("cold damage race", "blue"), - !__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && - __quest_state["Level 13"].state_string["Elemental damage race type"] == "cold", - true - ), - new MonkeyWish( - $item[none], - $effect[Dragged Through the Coals], - HTMLGenerateSpanFont("hot damage race", "red"), - !__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && - __quest_state["Level 13"].state_string["Elemental damage race type"] == "hot", - true - ), - new MonkeyWish( - $item[none], - $effect[Bored Stiff], - HTMLGenerateSpanFont("spooky damage race", "gray"), - !__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && - __quest_state["Level 13"].state_string["Elemental damage race type"] == "spooky", - true - ), - new MonkeyWish( - $item[none], - $effect[Sewer-Drenched], - HTMLGenerateSpanFont("stench damage race", "green"), - !__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && - __quest_state["Level 13"].state_string["Elemental damage race type"] == "stench", - true - ), - new MonkeyWish( - $item[none], - $effect[Fifty Ways to Bereave Your Lover], - HTMLGenerateSpanFont("sleaze damage race", "purple"), - !__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && - __quest_state["Level 13"].state_string["Elemental damage race type"] == "sleaze" && - get_property_int("zeppelinProtestors") > 79, - true - ), - new MonkeyWish( - $item[lowercase N], - $effect[none], - "summon the nagamar", - !__quest_state["Level 13"].state_boolean["king waiting to be freed"] && - // This accounts for being on a path that needs the wand as well - // as whether you already have one. See State.ash - __misc_state["wand of nagamar needed"] && - $item[lowercase N].available_amount() < 1 && - $item[ruby W].available_amount() > 0 && - $item[metallic A].available_amount() > 0 && - $item[heavy D].available_amount() > 0, - locationAvailable($location[The Valley of Rof L'm Fao]) - ) - }; - - MonkeyWish [int] aftercoreWishes = { - new MonkeyWish( - $item[bag of foreign bribes], - $effect[none], - "", - locationAvailable($location[The Ice Hotel]), - true - ) - }; - - int monkeyWishesLeft = clampi(5 - get_property_int("_monkeyPawWishesUsed"), 0, 5); - string [int] options; - if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) { - options.listAppendList(showWishes(inRunWishes)); - } - if (!__misc_state["in run"]) { - options.listAppendList(showWishes(aftercoreWishes)); - if (count(options) == 0) { - options.listAppend("The poors will have to settle for wishing effects."); - } - } - - if (count(options) > 0) { - description.listAppend("Possible wishes:" + options.listJoinComponents("
").HTMLGenerateIndentedText()); - } - - MonkeySkill [int] monkeySkills = { - new MonkeySkill(5, $skill[Monkey Slap], "killbanish"), - new MonkeySkill(4, $skill[Monkey Tickle], "delevel"), - new MonkeySkill(3, $skill[Evil Monkey Eye], "spooky delevel"), - new MonkeySkill(2, $skill[Monkey Peace Sign], "heal"), - new MonkeySkill(1, $skill[Monkey Point], "Olfaction-lite") - // No need for 0 (physical damage), tile is invisible anyway - }; - - string imageName; - foreach index, monkeySkill in monkeySkills { - description.listAppend(HTMLGenerateSpanOfClass(pluralise(monkeySkill.fingerCount, "finger", "fingers") + ": ", "r_bold") + monkeySkill.description); - if (monkeySkill.fingerCount == monkeyWishesLeft) { - imageName = `__skill {monkeySkill.theSkill.name}`; - } - } - - if (monkeyWishesLeft > 0) { - resource_entries.listAppend(ChecklistEntryMake(imageName, url, ChecklistSubentryMake(pluralise(monkeyWishesLeft, "monkey's paw wish", `monkey's paw wishes`), "", description)).ChecklistEntrySetIDTag("Monkey wishes")); - } - - // Banish combination tag for the monkey slap, if you've got it. - if (monkeyWishesLeft == 5) { - string [int] description; - string url; - url = "main.php"; - description.listAppend("Turn-taking repeat-use banish. Lasts until you use it again!"); - if ($item[cursed monkey's paw].equipped_amount() == 0) { - description.listAppend("Equip your cursed monkey paw first."); - url = "inventory.php?ftext=cursed+monkey"; - } - resource_entries.listAppend(ChecklistEntryMake("__skill monkey slap", "", ChecklistSubentryMake("Monkey Slap usable", "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Cursed monkey paw banish")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2023/Jill of all Trades.ash b/Source/relay/TourGuide/Items of the Month/2023/Jill of all Trades.ash deleted file mode 100644 index 8eb7c010..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/Jill of all Trades.ash +++ /dev/null @@ -1,49 +0,0 @@ -// TILE SPEC: -// - Remind the user to get a halloween map. -// - Remind the user to get an LED candle. -// - Recommend halloween monsters for habitation. - -// CANNOT DO YET: -// - Add halloween fights to freebies combination tag; need better mafia tracking... - -RegisterResourceGenerationFunction("IOTMJillv2GenerateResource"); -void IOTMJillv2GenerateResource(ChecklistEntry [int] resource_entries) -{ - familiar bigJillyStyle = lookupFamiliar("Jill-of-All-Trades"); - if (!bigJillyStyle.familiar_is_usable()) return; - - int mapsDropped = get_property_int("_mapToACandyRichBlockDrops"); - - string url = "familiar.php"; - if (bigJillyStyle == my_familiar()) - url = ""; - - // Initial chance is 35% with a masssive dropoff (multiply by 5% per map dropped) - float estimatedMapProbability = 35 * (0.05 ** clampi(mapsDropped, 0, 3)); // confirmed by cannonfire to stop decreasing after 3rd time - - // Convert to turns - float turnsToMap = 1/(estimatedMapProbability/100); - - string [int] description; - if (mapsDropped == 0) { - description.listAppend("You haven't gotten a map to halloween town yet! Try using your Jill for a map at ~"+round(estimatedMapProbability)+"% chance, or approximately "+round(turnsToMap,1)+" turns."); - } - else if (mapsDropped < 2) { // The third map drop chance is less than 1 in a thousand - not something that is particularly useful to hunt for - description.listAppend("You have a map; the next map is at a ~"+round(estimatedMapProbability)+"% chance, or approximately "+round(turnsToMap,1)+" turns."); - } - - int habitatRecallsLeft = clampi(3 - get_property_int("_monsterHabitatsRecalled"), 0, 3); - if (!lookupSkill("Just the Facts").have_skill() && !__iotms_usable[$item[book of facts (dog-eared)]]) habitatRecallsLeft = 0; - if (habitatRecallsLeft > 0) - description.listAppend("Halloween monsters make excellent targets for Recall Habitat from BoFA."); - - // Adding a small exception here to not generate this if they weirdly acquired LED through other means (like casual or a pull or something) - if (!get_property_boolean("ledCandleDropped") && $item[LED Candle].item_amount() < 1) { - description.listAppend("Fight a dude for an LED candle, to tune your Jill!"); - } - - // If we have nothing to say, do not display the tile - if (count(description) == 0) return; - - resource_entries.listAppend(ChecklistEntryMake("__familiar jill-of-all-trades", url, ChecklistSubentryMake("Celebrating the Jillenium", "", description)).ChecklistEntrySetIDTag("Jill of All Trades tile")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2023/Patriotic Eagle.ash b/Source/relay/TourGuide/Items of the Month/2023/Patriotic Eagle.ash deleted file mode 100644 index 24779392..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/Patriotic Eagle.ash +++ /dev/null @@ -1,150 +0,0 @@ -//Patriotic Eagle -RegisterTaskGenerationFunction("IOTMPatrioticEagleGenerateTasks"); -void IOTMPatrioticEagleGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!lookupFamiliar("Patriotic Eagle").familiar_is_usable()) return; - - monster RWB_monster = get_property_monster("rwbMonster"); - - if (RWB_monster != $monster[none]) { - int fights_left = clampi(get_property_int("rwbMonsterCount"), 0, 2); - - // Use ezan's weird location-finding-thing - location [int] possible_appearance_locations = RWB_monster.getPossibleLocationsMonsterCanAppearInNaturally().listInvert(); - - // Make the entry a bit more explicitly for readability - ChecklistEntry entry; - - entry.url = possible_appearance_locations[0].getClickableURLForLocation(); - entry.image_lookup_name = "__monster " + RWB_monster; - entry.tags.id = "RWB monster copies"; - entry.importance_level = -1; - - string [int] description; - - description.listAppend("Copied by your eagle's blast. Will appear when you adventure in " + possible_appearance_locations.listJoinComponents(", ", "or") + "."); - - phylum eaglePhylumBanished = $phylum[none]; - - if (get_property("banishedPhyla") != "") - eaglePhylumBanished = get_property("banishedPhyla").split_string(":")[1].to_phylum(); - - if (RWB_monster.phylum == eaglePhylumBanished) { - description.listAppend(HTMLGenerateSpanFont("WARNING! This monster will not appear, it's banished by your eagle screech!", "red")); - } - - entry.subentries.listAppend(ChecklistSubentryMake("Fight " + pluralise(fights_left, "more " + RWB_monster, "more " + RWB_monster + "s"), "", description)); - - if (fights_left > 0 && possible_appearance_locations.count() > 0) - optional_task_entries.listAppend(entry); - } - - // Extra nag from TES re: setting your global pledge. - string [int] description2; - - if (__misc_state["in run"] && ($effect[Citizen of a Zone].have_effect() == 0)) { - description2.listAppend("Haunted Kitchen: +100% init"); - description2.listAppend("Haunted Library/Laundry: +30% item"); - description2.listAppend("Batrat/Ninja Snowmen/Frat Battlefield: +50% meat"); - task_entries.listAppend(ChecklistEntryMake("__familiar Patriotic Eagle", "familiar.php", ChecklistSubentryMake("Pledge to a zone!", description2), -5).ChecklistEntrySetIDTag("Patriotic Eagle familiar pledge reminder")); - } - -} - -RegisterResourceGenerationFunction("IOTMPatrioticEagleGenerateResource"); -void IOTMPatrioticEagleGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("Patriotic Eagle").familiar_is_usable()) return; - - phylum eaglePhylumBanished = $phylum[none]; - - if (get_property("banishedPhyla") != "") - eaglePhylumBanished = get_property("banishedPhyla").split_string(":")[1].to_phylum(); - - int screechRecharge = get_property_int("screechCombats"); - - string title; - string [int] description; - - if (screechRecharge > 0) { - title = (screechRecharge + " combats (or freeruns) until your Patriotic Eagle can screech again."); - } else { - title = "Patriotic Eagle can screech and banish an entire phylum!"; - description.listAppend(HTMLGenerateSpanFont("SCREEEE", "red") + HTMLGenerateSpanFont("EEEEE", "grey") + HTMLGenerateSpanFont("EEEEE!,", "blue")); - } - - // Color the pledge zones by zone availability - string [int] itemPledges; - itemPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Library", $location[the haunted library])); - itemPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Laundry Room", $location[the haunted laundry room])); - itemPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Whitey's Grove", $location[Whitey's Grove])); - - string [int] meatPledges; - meatPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Ninja Snowmen Lair", $location[Lair of the Ninja Snowmen])); - meatPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Hidden Hospital", $location[The Hidden Hospital])); - meatPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Bathroom", $location[The Haunted Bathroom])); - meatPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("the Oasis", $location[the oasis])); - - string [int] initPledges; - initPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Kitchen", $location[the haunted kitchen])); - initPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Oil Peak", $location[oil peak])); - initPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Oliver's Tavern", $location[an unusually quiet barroom brawl])); - - if ($effect[Citizen of A Zone].have_effect() == 0) { - description.listAppend(HTMLGenerateSpanFont("Pledge ", "red") + HTMLGenerateSpanFont("allegiance ", "grey") + HTMLGenerateSpanFont("to a zone!", "blue")); - if (itemPledges.count() > 0) description.listAppend("|*"+HTMLGenerateSpanOfClass("+30% item: ", "r_bold") + itemPledges.listJoinComponents(", ", "or ") + "."); - if (meatPledges.count() > 0) description.listAppend("|*"+HTMLGenerateSpanOfClass("+50% meat: ", "r_bold") + meatPledges.listJoinComponents(", ", "or ") + "."); - if (initPledges.count() > 0) description.listAppend("|*"+HTMLGenerateSpanOfClass("+100% init: ", "r_bold") + initPledges.listJoinComponents(", ", "or ") + "."); - } - - // Making option frames for the phylums you want to banish, with if statements that should remove them - // when you have completed the task. Additionally, the location availability should ensure these show - // in gray if you cannot access the zone. - - string [int] dudeOptions; - if ( __quest_state["Level 11"].mafia_internal_step < 2) - dudeOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Black Forest (2/5)", $location[The Black Forest])); - if (__quest_state["Level 9"].state_int["twin peak progress"] < 15) - dudeOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Twin Peak (5/8)", $location[Twin Peak])); - if (!__quest_state["Level 11 Palindome"].state_boolean["dr. awkward's office unlocked"]) - dudeOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Whitey's Grove (1/4)", $location[Whitey's Grove])); - - string [int] beastOptions; - if (__quest_state["Level 11 Hidden City"].state_boolean["need machete for liana"]) - beastOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Hidden Park (1/4)", $location[The Hidden Park])); - if (!__quest_state["Level 11 Palindome"].state_boolean["dr. awkward's office unlocked"]) - beastOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Palindome (3/7)", $location[Inside the Palindome])); - if (!$location[The Castle in the Clouds in the Sky (Basement)].locationAvailable()) - beastOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Airship (2/7)", $location[The Penultimate Fantasy Airship])); - - string [int] constructOptions; - if (!__quest_state["Level 11 Palindome"].state_boolean["dr. awkward's office unlocked"]) - constructOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Whitey's Grove (1/4)", $location[Whitey's Grove])); - if (!$location[The Castle in the Clouds in the Sky (Basement)].locationAvailable()) - constructOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Airship (1/7)", $location[The Penultimate Fantasy Airship])); - - string [int] undeadOptions; - if (!$location[The Haunted Bathroom].locationAvailable()) - undeadOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Library (1/3)", $location[The Haunted Library])); - if (__quest_state["Level 11 Ron"].mafia_internal_step <= 4) - undeadOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Red Zeppelin (1/5)", $location[The Red Zeppelin])); - if (__quest_state["Level 11 Manor"].mafia_internal_step < 4) - undeadOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Wine Cellar (1/3)", $location[The Haunted Wine Cellar])); - if (__quest_state["Level 11 Manor"].mafia_internal_step < 4) - undeadOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Boiler (1/3)", $location[The Haunted Boiler Room])); - if (!__quest_state["Level 11 Pyramid"].finished) - undeadOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Pyramid Middle (1/3)", $location[The Middle Chamber])); - - - string [int] options; - { - if (dudeOptions.count() > 0) options.listAppend(HTMLGenerateSpanOfClass("Dude: ", "r_bold") + dudeOptions.listJoinComponents(", ")); - if (beastOptions.count() > 0) options.listAppend(HTMLGenerateSpanOfClass("Beast: ", "r_bold") + beastOptions.listJoinComponents(", ")); - if (constructOptions.count() > 0) options.listAppend(HTMLGenerateSpanOfClass("Construct: ", "r_bold") + constructOptions.listJoinComponents(", ")); - if (undeadOptions.count() > 0) options.listAppend(HTMLGenerateSpanOfClass("Undead: ", "r_bold") + undeadOptions.listJoinComponents(", ")); - } - if (options.count() > 0) - description.listAppend("Screech these phylums away to banish a fraction of monsters from a relevant zone:" + options.listJoinComponents("
").HTMLGenerateIndentedText()); - - resource_entries.listAppend(ChecklistEntryMake("__familiar Patriotic Eagle", "familiar.php", ChecklistSubentryMake(title, description), 8).ChecklistEntrySetIDTag("Patriotic Eagle familiar resource")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2023/Rock Garden.ash b/Source/relay/TourGuide/Items of the Month/2023/Rock Garden.ash deleted file mode 100644 index d4e7f68e..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/Rock Garden.ash +++ /dev/null @@ -1,92 +0,0 @@ -string gravelMessage(int gravels) -{ - return HTMLGenerateSpanOfClass(gravels, "r_bold") + "x groveling gravel (free kill*)"; -} - -string whetStoneMessage(int whetStones) -{ - return HTMLGenerateSpanOfClass(whetStones, "r_bold") + "x whet stone (+1 adv on food)"; -} - -string milestoneMessage(int milestones) -{ - int desertProgress = get_property_int("desertExploration"); - return HTMLGenerateSpanOfClass(milestones, "r_bold") + "x milestone (+5% desert progress), " + (100 - desertProgress) + "% remaining"; -} - -// Prompt to harvest your garden in run when useful items are growing in it -RegisterTaskGenerationFunction("IOTMRockGardenGenerateTasks"); -void IOTMRockGardenGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - string [int] description; - string url = "campground.php"; - - int gardenGravels = __campground[$item[groveling gravel]]; - int gardenMilestones = __campground[$item[milestone]]; - int gardenWhetstones = __campground[$item[whet stone]]; - - if (!__iotms_usable[lookupItem("packet of rock seeds")] || - !__misc_state["in run"] || - my_path().id == PATH_COMMUNITY_SERVICE || - gardenGravels + gardenMilestones + gardenWhetstones == 0) - return; - - int desertProgress = get_property_int("desertExploration"); - - if (gardenGravels > 0) - { - description.listAppend(gravelMessage(gardenGravels)); - } - - if (gardenWhetstones > 0) - { - description.listAppend(whetStoneMessage(gardenWhetstones)); - } - - if (gardenMilestones > 0 && desertProgress < 100) - { - description.listAppend(milestoneMessage(gardenMilestones)); - } - - task_entries.listAppend(ChecklistEntryMake("__item rock garden guide", url, ChecklistSubentryMake("Harvest your rock garden", "", description)).ChecklistEntrySetIDTag("rock garden task")); -} - -// Prompt to use garden resources when they're helpful -RegisterResourceGenerationFunction("IOTMRockGardenGenerateResource"); -void IOTMRockGardenGenerateResource(ChecklistEntry [int] resource_entries) { - string [int] description; - string url = "campground.php"; - - if (!get_property_boolean("_molehillMountainUsed") && available_amount($item[molehill mountain]) > 0) - { - resource_entries.listAppend(ChecklistEntryMake("__item molehill mountain", url = "inventory.php?ftext=molehill+mountain", ChecklistSubentryMake("Molehill moleman", "", "Free scaling fight."), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Molehill free fight")); - } - - int availableGravels = available_amount($item[groveling gravel]); - int availableMilestones = available_amount($item[milestone]); - int availableWhetStones = available_amount($item[whet stone]); - - // Ascension stuff - if (!__misc_state["in run"] || - my_path().id == PATH_COMMUNITY_SERVICE || - availableGravels + availableMilestones + availableWhetstones == 0) - return; - - int desertProgress = get_property_int("desertExploration"); - - if (availableGravels > 0 && $item[groveling gravel].item_is_usable()) - { - description.listAppend(gravelMessage(availableGravels)); - } - - if (availableWhetStones > 0 && $item[whet stone].item_is_usable() && (__misc_state["can eat just about anything"])) - { - description.listAppend(whetStoneMessage(availableWhetStones)); - } - - if (availableMilestones > 0 && $item[milestone].item_is_usable() && desertProgress < 100) - { - description.listAppend(milestoneMessage(availableMilestones)); - } - - resource_entries.listAppend(ChecklistEntryMake("__item rock garden guide", url, ChecklistSubentryMake("Rock garden resources", "", description)).ChecklistEntrySetIDTag("rock garden resource")); -} diff --git a/Source/relay/TourGuide/Items of the Month/2023/SIT Course Certificate.ash b/Source/relay/TourGuide/Items of the Month/2023/SIT Course Certificate.ash deleted file mode 100644 index 422ddeae..00000000 --- a/Source/relay/TourGuide/Items of the Month/2023/SIT Course Certificate.ash +++ /dev/null @@ -1,64 +0,0 @@ -boolean hasAnySkillOf(string [int] skillNames) { - foreach i in skillNames { - string skillName = skillNames[i]; - if (lookupSkill(skillName).have_skill()) { - return true; - } - } - return false; -} - -RegisterTaskGenerationFunction("IOTMSITCertificateGenerateTasks"); -void IOTMSITCertificateGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - // Don't generate a tile if the user doesn't have SIT. - if (!lookupItem("S.I.T. Course Completion Certificate").have()) return; - - // Cannot use S.I.T. in G-Lover - if (my_path().id == PATH_G_LOVER) return; - - boolean completedSITToday = get_property_boolean("_sitCourseCompleted"); - - // Don't generate a tile if the user has completed SIT already today. - if (completedSITToday) return; - - string [int] description; - string url = "inv_use.php?pwd=" + my_hash() + "&which=3&whichitem=11116"; - string main_title = "S.I.T. Course Enrollment"; - string subtitle = ""; - - string [int] miscPhrases = { - "Don't play hooky!", - "You already paid for it.", - "This one time in college...", - "Bright college days, oh, carefree days that fly.", // <3 tom lehrer - "No child of mine is leaving here without a degree!", - "Make like a tree and leaf (through your papers).", - }; - - string [int] skillNames = {"Psychogeologist", "Insectologist", "Cryptobotanist"}; - - if (hasAnySkillOf(skillNames)) { - // If they already have a skill, generate an optional task or a less-shiny supernag - if (lookupSkill("Psychogeologist").have_skill()) subtitle = "you have ML; consider Insectology, for meat?"; - if (lookupSkill("Insectologist").have_skill()) subtitle = "you have Meat; consider Psychogeology, for ML?"; - if (lookupSkill("Cryptobotanist").have_skill()) subtitle = "you have Init; consider Insectology, for meat?"; - - if (__misc_state["in run"]) { - // If in-run, generate a supernag - description.listAppend("Try changing your S.I.T. course to accumulate different items."); - task_entries.listAppend(ChecklistEntryMake("__item S.I.T. Course Completion Certificate", url, ChecklistSubentryMake(main_title, subtitle, description), -11).ChecklistEntrySetIDTag("S.I.T. Course Completion Certificate")); - } - else { - // If not, generate an optional task - main_title = "Could change your S.I.T. skill, for new items..."; - optional_task_entries.listAppend(ChecklistEntryMake("__item S.I.T. Course Completion Certificate", url, ChecklistSubentryMake(main_title, subtitle, description), 1).ChecklistEntrySetIDTag("S.I.T. Course Completion Certificate")); - } - } - else { - // If they don't have a skill, generate a supernag. - string miscPhrase = miscPhrases[random(count(miscPhrases))]; - description.listAppend(HTMLGenerateSpanFont(miscPhrase + " Take your S.I.T. course!", "red")); - task_entries.listAppend(ChecklistEntryMake("__item S.I.T. Course Completion Certificate", url, ChecklistSubentryMake(main_title, subtitle, description), -11).ChecklistEntrySetIDTag("S.I.T. Course Completion Certificate")); - } - -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2024/Apriling Band Helmet.ash b/Source/relay/TourGuide/Items of the Month/2024/Apriling Band Helmet.ash deleted file mode 100644 index 45b79d34..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/Apriling Band Helmet.ash +++ /dev/null @@ -1,69 +0,0 @@ -// Apriling band helmet -RegisterResourceGenerationFunction("IOTMAprilingBandHelmetGenerateResource"); -void IOTMAprilingBandHelmetGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (available_amount($item[apriling band helmet]) < 1) - return; - - string [int] description; - - //battle of the bands - int aprilingBandConductorTimer = get_property_int("nextAprilBandTurn"); - string url = "inventory.php?pwd=" + my_hash() + "&action=apriling"; - - if (aprilingBandConductorTimer <= total_turns_played()) { - description.listAppend(HTMLGenerateSpanFont("You can change your tune!", "blue")); - if ($effect[Apriling Band Patrol Beat].have_effect() > 0) { - description.listAppend(HTMLGenerateSpanFont("-10% Combat Frequency", "blue")); - description.listAppend("+10% Combat Frequency"); - description.listAppend("+25% booze, +50% food, +100% candy"); - } - if ($effect[Apriling Band Battle Cadence].have_effect() > 0) { - description.listAppend("-10% Combat Frequency"); - description.listAppend(HTMLGenerateSpanFont("+10% Combat Frequency", "blue")); - description.listAppend("+25% booze, +50% food, +100% candy"); - } - if ($effect[Apriling Band Celebration Bop].have_effect() > 0) { - description.listAppend("+10% Combat Frequency"); - description.listAppend("-10% Combat Frequency"); - description.listAppend(HTMLGenerateSpanFont("+25% booze, +50% food, +100% candy", "blue")); - } - } - else { - description.listAppend((aprilingBandConductorTimer - total_turns_played()) + " adventures until you can change your tune."); - } - resource_entries.listAppend(ChecklistEntryMake("__item apriling band helmet", url, ChecklistSubentryMake("Apriling band helmet buff", "", description), 8)); - - int aprilingBandSaxUsesLeft = clampi(3 - get_property_int("_aprilBandSaxophoneUses"), 0, 3); - int aprilingBandQuadTomUsesLeft = clampi(3 - get_property_int("_aprilBandTomUses"), 0, 3); - int aprilingBandTubaUsesLeft = clampi(3 - get_property_int("_aprilBandTubaUses"), 0, 3); - int aprilingBandPiccoloUsesLeft = clampi(3 - get_property_int("_aprilBandPiccoloUses"), 0, 3); - int instrumentUses = get_property_int("_aprilBandSaxophoneUses") + - get_property_int("_aprilBandTomUses") + - get_property_int("_aprilBandTubaUses") + - get_property_int("_aprilBandPiccoloUses"); - - string [int] instrumentDescription; - - int aprilingBandInstrumentsAvailable = clampi(2 - get_property_int("_aprilBandInstruments"), 0, 2); - if (aprilingBandInstrumentsAvailable > 0) { - instrumentDescription.listAppend(HTMLGenerateSpanFont("Can pick " + aprilingBandInstrumentsAvailable + " more instruments!", "green")); - } - - if (instrumentUses < 6) { - string url = "inventory.php?ftext=apriling"; - if (aprilingBandSaxUsesLeft > 0 && available_amount($item[apriling band saxophone]) > 0) { - instrumentDescription.listAppend(`Can play the Sax {aprilingBandSaxUsesLeft} more times. {HTMLGenerateSpanFont("LUCKY!", "green")}`); - } - if (aprilingBandQuadTomUsesLeft > 0 && available_amount($item[apriling band quad tom]) > 0) { - instrumentDescription.listAppend(`Can play the Quad Toms {aprilingBandQuadTomUsesLeft} more times. {HTMLGenerateSpanFont("Sandworm!", "orange")}`); - } - if (aprilingBandTubaUsesLeft > 0 && available_amount($item[apriling band tuba]) > 0) { - instrumentDescription.listAppend(`Can play the Tuba {aprilingBandTubaUsesLeft} more times. {HTMLGenerateSpanFont("SNEAK!", "grey")}`); - } - if (aprilingBandPiccoloUsesLeft > 0 && available_amount($item[apriling band piccolo]) > 0) { - instrumentDescription.listAppend(`Can play the Piccolo {aprilingBandPiccoloUsesLeft} more times. {HTMLGenerateSpanFont("+40 fxp", "purple")}`); - } - resource_entries.listAppend(ChecklistEntryMake("__item apriling band helmet", url, ChecklistSubentryMake("Apriling band instruments", "", instrumentDescription), 8)); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2024/Chest Mimic.ash b/Source/relay/TourGuide/Items of the Month/2024/Chest Mimic.ash deleted file mode 100644 index e85f85a4..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/Chest Mimic.ash +++ /dev/null @@ -1,33 +0,0 @@ -//2024 -//Chest Mimic -RegisterResourceGenerationFunction("IOTMChestMimicGenerateResource"); -void IOTMChestMimicGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("Chest Mimic").familiar_is_usable()) return; - - // Title - int famExperienceGain = numeric_modifier("familiar experience") + 1; - int chestExperience = ($familiar[chest mimic].experience); - int famExpNeededForNextEgg = (50 - (chestExperience % 50)); - string fightsForNextEgg; - if (famExperienceGain > 0) { - fightsForNextEgg = pluralise(ceil(to_float(famExpNeededForNextEgg) / famExperienceGain), "fight", "fights"); - } - else { - fightsForNextEgg = "cannot get"; - } - int mimicEggsLeft = clampi(11 - get_property_int("_mimicEggsObtained"), 0, 11); - - string [int] description; - string url = "familiar.php"; - description.listAppend(`Currently have {HTMLGenerateSpanOfClass(chestExperience, "r_bold")} experience, currently gain {HTMLGenerateSpanOfClass(famExperienceGain, "r_bold")} fam exp per fight.`); - description.listAppend(`Need {HTMLGenerateSpanOfClass(famExpNeededForNextEgg, "r_bold")} more famxp for next egg. ({fightsForNextEgg})`); - description.listAppend(`Can lay {HTMLGenerateSpanOfClass(mimicEggsLeft, "r_bold")} more eggs today.`); - - resource_entries.listAppend(ChecklistEntryMake("__familiar chest mimic", url, ChecklistSubentryMake("Chest mimic fxp", "", description), -2)); - if ($item[mimic egg].available_amount() > 0) { - string header = $item[mimic egg].pluralise().capitaliseFirstLetter(); - string url = `inv_use.php?pwd={my_hash()}&whichitem=11542`; - resource_entries.listAppend(ChecklistEntryMake("__item mimic egg", url, ChecklistSubentryMake(header, "", "Fight some copies"), -1).ChecklistEntrySetCombinationTag("fax and copies")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2024/Everfull Dart Holster.ash b/Source/relay/TourGuide/Items of the Month/2024/Everfull Dart Holster.ash deleted file mode 100644 index 2b8217dc..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/Everfull Dart Holster.ash +++ /dev/null @@ -1,51 +0,0 @@ -//Everfull Dart Holster via TES -RegisterTaskGenerationFunction("IOTMEverfullDartsGenerateTasks"); -void IOTMEverfullDartsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[$item[everfull dart holster]]) return; - - string [int] description; - string url = "inventory.php?ftext=everfull+dart_holster"; - - if ($effect[everything looks red].have_effect() == 0) { - int dartCooldown = 50; - if (get_property("everfullDartPerks").contains_text("You are less impressed by bullseyes")) { - dartCooldown -= 10; - } - if (get_property("everfullDartPerks").contains_text("Bullseyes do not impress you much")) { - dartCooldown -= 10; - } - description.listAppend(HTMLGenerateSpanFont(`Shoot a bullseye! ({dartCooldown} ELR)`, "red")); - if (lookupItem("everfull dart holster").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the dart holster first.", "red")); - } - else { - description.listAppend(HTMLGenerateSpanFont("Dart holster equipped", "blue")); - } - task_entries.listAppend(ChecklistEntryMake("__item everfull dart holster", url, ChecklistSubentryMake("Everfull Darts free kill available!", "", description), -11)); - } -} - -RegisterResourceGenerationFunction("IOTMEverfullDartsGenerateResource"); -void IOTMEverfullDartsGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__iotms_usable[$item[everfull dart holster]] || !__misc_state["in run"]) return; - - string [int] description; - string url = "inventory.php?ftext=everfull+dart_holster"; - - int dartSkill = get_property_int("dartsThrown"); - if (dartSkill < 401) { - int dartsNeededForNextPerk = floor(sqrt(dartSkill) + 1) ** 2 - dartSkill; - description.listAppend(`Current dart skill: {dartSkill}`); - description.listAppend(`{HTMLGenerateSpanFont(dartsNeededForNextPerk, "blue")} darts needed for next Perk`); - - if (lookupItem("everfull dart holster").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the dart holster first.", "red")); - } - else { - description.listAppend(HTMLGenerateSpanFont("Dart holster equipped", "blue")); - } - resource_entries.listAppend(ChecklistEntryMake("__item everfull dart holster", url, ChecklistSubentryMake("🍑🎯 Everfull Dart Holster charging", "", description), 11)); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2024/Mayam Calendar.ash b/Source/relay/TourGuide/Items of the Month/2024/Mayam Calendar.ash deleted file mode 100644 index 0db314c6..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/Mayam Calendar.ash +++ /dev/null @@ -1,106 +0,0 @@ -record MayamSymbol { - // Which ring the symbol is in - int ring; - - // Printable name for the symbol - string friendlyName; - - // What mafia calls the symbol - string mafiaName; - - // The player-friendly description of the symbol - string description; -}; - -void addToBothDescriptions(string [int] description1, string [int] description2, string text) { - description1.listAppend(text); - description2.listAppend(text); -} - -//Mayam calendar -RegisterResourceGenerationFunction("IOTMMayamCalendarGenerateResource"); -void IOTMMayamCalendarGenerateResource(ChecklistEntry [int] resource_entries) -{ - // Adding this prior to the check if the user has stinkbombs. - if ($item[stuffed yam stinkbomb].available_amount() > 0 ) - { - resource_entries.listAppend(ChecklistEntryMake("__item stuffed yam stinkbomb", "", ChecklistSubentryMake(pluralise($item[stuffed yam stinkbomb]), "", "Free run/banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Haunted doghouse banish")); - } - - if (available_amount($item[mayam calendar]) < 1) - return; - - MayamSymbol [int] mayamSymbols = { - new MayamSymbol(1, "A yam", "yam1", "craftable ingredient"), - new MayamSymbol(1, "Sword", "sword", `+{min(150, 10 * my_level())} mus stats`), - new MayamSymbol(1, "Vessel", "vessel", "+1000 MP"), - new MayamSymbol(1, "Fur", "fur", "+100 Fxp"), - new MayamSymbol(1, "Chair", "chair", "+5 free rests"), - new MayamSymbol(1, "Eye", "eye", "+30% item for 100 advs"), - new MayamSymbol(2, "Another yam", "yam2", "craftable ingredient"), - new MayamSymbol(2, "Lightning", "lightning", `+{min(150, 10 * my_level())} mys stats`), - new MayamSymbol(2, "Bottle", "bottle", "+1000 HP"), - new MayamSymbol(2, "Wood", "wood", "+4 bridge parts"), - new MayamSymbol(2, "Meat", "meat", `+{min(150, 10 * my_level())} meat`), - new MayamSymbol(3, "A third yam", "yam3", "craftable ingredient"), - new MayamSymbol(3, "Eyepatch", "eyepatch", `+{min(150, 10 * my_level())} mox stats`), - new MayamSymbol(3, "Wall", "wall", "+2 res for 100 advs"), - new MayamSymbol(3, "Cheese", "cheese", "+1 goat cheese"), - new MayamSymbol(4, "A fourth yam", "yam4", "yep."), - new MayamSymbol(4, "Clock", "clock", "+5 advs"), - new MayamSymbol(4, "Explosion", "explosion", "+5 fites") - }; - - string [int] description, hoverDescription; - - int templeResetAscension = get_property_int("lastTempleAdventures"); - addToBothDescriptions(description, hoverDescription, "Happy Mayam New Year!"); - - ChecklistEntry entry; - entry.url = "inv_use.php?pwd=" + my_hash() + "&which=99&whichitem=11572"; - entry.image_lookup_name = "mayam calendar"; - entry.tags.id = "Mayam Calendar"; - entry.importance_level = 8; - - if (!get_property("_mayamSymbolsUsed").contains_text("yam4") || - !get_property("_mayamSymbolsUsed").contains_text("clock") || - !get_property("_mayamSymbolsUsed").contains_text("explosion") || - my_ascensions() > templeResetAscension) - { - description.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); - hoverDescription.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); - - int[int] rings = {1, 2, 3, 4}; - foreach ring in rings { - string ringOrdinal = capitaliseFirstLetter(substring(int_to_ordinal(ring + 1), 1)); - hoverDescription.listAppend(HTMLGenerateSpanOfClass(`{ringOrdinal} ring:`, "r_bold")); - - string [int] unusedSymbols; - foreach index, mayamSymbol in mayamSymbols { - if (mayamSymbol.ring == ring + 1 && !get_property("_mayamSymbolsUsed").contains_text(mayamSymbol.mafiaName)) { - hoverDescription.listAppend(`- {HTMLGenerateSpanOfClass(mayamSymbol.friendlyName, "r_bold")}: {mayamSymbol.description}`); - unusedSymbols.listAppend(mayamSymbol.friendlyName); - } - } - description.listAppend(`{HTMLGenerateSpanOfClass(`{ringOrdinal} ring:`, "r_bold")} {unusedSymbols.listJoinComponents(", ")}`); - hoverDescription.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); - } - description.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); - - string [int] resonances; - resonances.listAppend(HTMLGenerateSpanOfClass("15-turn banisher", "r_bold") + ": Vessel + Yam + Cheese + Explosion"); - resonances.listAppend(HTMLGenerateSpanOfClass("Yam and swiss", "r_bold") + ": Yam + Meat + Cheese + Yam"); - resonances.listAppend(HTMLGenerateSpanOfClass("+55% meat accessory", "r_bold") + ": Yam + Meat + Eyepatch + Yam"); - resonances.listAppend(HTMLGenerateSpanOfClass("+100% Food drops", "r_bold") + ": Yam + Yam + Cheese + Clock"); - - addToBothDescriptions(description, hoverDescription, HTMLGenerateSpanOfClass("Cool Mayam combos!", "r_bold") + resonances.listJoinComponents("
").HTMLGenerateIndentedText()); - - if (my_ascensions() > templeResetAscension) { - addToBothDescriptions(description, hoverDescription, HTMLGenerateSpanFont("Temple reset available!", "r_bold") + ""); - } - - entry.subentries.listAppend(ChecklistSubentryMake("Mayam Calendar", "", description)); - entry.subentries_on_mouse_over.listAppend(ChecklistSubentryMake("Mayam Calendar", "", hoverDescription)); - resource_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2024/Mini Kiwi.ash b/Source/relay/TourGuide/Items of the Month/2024/Mini Kiwi.ash deleted file mode 100644 index 1cf6f97c..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/Mini Kiwi.ash +++ /dev/null @@ -1,34 +0,0 @@ -// Mini-Kiwi -RegisterResourceGenerationFunction("IOTMMiniKiwiGenerateResource"); -void IOTMMiniKiwiGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("Mini Kiwi").familiar_is_usable()) return; - - // This familiar sucks. It's really bad. Still, fine to have a tile, I guess. - int miniKiwiCount = $item[mini kiwi].available_amount(); - float kiwiWeight = effective_familiar_weight($familiar[Mini Kiwi]) + weight_adjustment(); - float kiwiModifier = $item[aviator goggles].available_amount() > 0 ? 0.75 : 0.50; - - // Calculating the chance of a kiwi per fight; weight * your modifier - int kiwiChance = to_int(min(kiwiWeight * kiwiModifier,100.0)); - boolean kiwiSpiritsBought = get_property_boolean("_miniKiwiIntoxicatingSpiritsBought"); - int miniKiwiBikiniCount = $item[mini kiwi bikini].available_amount(); - - // Tile setup stuff - string [int] description; - string url = "familiar.php"; // Could send to the kwiki mart, but don't care enough. - string header = pluralise(miniKiwiCount, "mini kiwi available", "mini kiwis available"); - - description.listAppend(`At {to_int(kiwiWeight)} weight, you have a {kiwiChance}% chance of a mini kiwi each fight.`); - - if (!kiwiSpiritsBought) { - description.listAppend('|*Consider purchasing mini kiwi intoxicating spirits, for 3 kiwis.'); - } - - if (miniKiwiBikiniCount < 1 && get_property_int("zeppelinProtestors") < 80) { - description.listAppend('|*Consider purchasing mini kiwi bikinis, for the Zeppelin sleaze test.'); - } - - resource_entries.listAppend(ChecklistEntryMake("__familiar mini kiwi", url, ChecklistSubentryMake(header, "", description), 10)); - -} diff --git a/Source/relay/TourGuide/Items of the Month/2024/Peace Turkey.ash b/Source/relay/TourGuide/Items of the Month/2024/Peace Turkey.ash deleted file mode 100644 index 133acc1f..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/Peace Turkey.ash +++ /dev/null @@ -1,26 +0,0 @@ -RegisterResourceGenerationFunction("IOTMPeaceTurkeyGenerateResource"); -void IOTMPeaceTurkeyGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("Peace Turkey").familiar_is_usable()) return; - - // Purkey Title -//still needs a fix for famwt when not active (currently returns 0 but still functions) - int turkeyProc = 24; - if (my_familiar() == lookupFamiliar("peace turkey")); - { - int turkeyProc = 24 + sqrt(effective_familiar_weight($familiar[peace turkey]) + weight_adjustment()); - } - int PeasCount = available_amount($item[whirled peas]); - int PeaSoupCount = available_amount($item[handful of split pea soup]); - string [int] description; - string url = "familiar.php"; - { - description.listAppend("" + PeasCount + " peas available (need to paste them)"); - description.listAppend("" + PeaSoupCount + " peabanishers available"); - resource_entries.listAppend(ChecklistEntryMake("__familiar peace turkey", url, ChecklistSubentryMake(HTMLGenerateSpanFont(turkeyProc +"% Peace Turkey proc", "black"), "", description), 2)); - } - if ($item[handful of split pea soup].available_amount() > 0 ) - { - resource_entries.listAppend(ChecklistEntryMake("__item handful of split pea soup", "", ChecklistSubentryMake(pluralise($item[handful of split pea soup]), "", "Free run/banish. Also have " + PeasCount + " peas."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Purkey banish")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2024/Roman Candelabra.ash b/Source/relay/TourGuide/Items of the Month/2024/Roman Candelabra.ash deleted file mode 100644 index 41e2a3f2..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/Roman Candelabra.ash +++ /dev/null @@ -1,37 +0,0 @@ -//Roman Candelabra -RegisterTaskGenerationFunction("IOTMRomanCandelabraGenerateTasks"); -void IOTMRomanCandelabraGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[roman candelabra].available_amount() == 0) return; - - string url = "inventory.php?ftext=Roman+Candelabra"; - - // Extra runaway nag for spring shoes unhavers - if ($effect[Everything Looks Green].have_effect() == 0 && $item[spring shoes].available_amount() == 0) - { - string [int] description; - description.listAppend(HTMLGenerateSpanFont("Green candle runaway!", "green")); - if (lookupItem("Roman Candelabra").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the Roman Candelabra first.", "red")); - } - else { - description.listAppend(HTMLGenerateSpanFont("Candelbra equipped", "green")); - } - task_entries.listAppend(ChecklistEntryMake("__item Roman Candelabra", url, ChecklistSubentryMake("Roman Candelabra runaway available!", "", description), -11)); - } - - // Purple people beater - if ($effect[Everything Looks Purple].have_effect() == 0) - { - string [int] description; - if (lookupItem("Roman Candelabra").equipped_amount() == 0) - { - description.listAppend(HTMLGenerateSpanFont("Equip the Roman Candelabra, for your purple ray.", "red")); - } - else - { - description.listAppend(HTMLGenerateSpanFont("Candelbra equipped, blow your purple candle!", "purple")); - } - task_entries.listAppend(ChecklistEntryMake("__item Roman Candelabra", url, ChecklistSubentryMake("Roman Candelabra monster chain ready", "", description), -11)); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2024/Sept-Ember Censer.ash b/Source/relay/TourGuide/Items of the Month/2024/Sept-Ember Censer.ash deleted file mode 100644 index a164c463..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/Sept-Ember Censer.ash +++ /dev/null @@ -1,43 +0,0 @@ -// Sept-Ember Censer -RegisterResourceGenerationFunction("IOTMSeptemberCenserGenerateResource"); -void IOTMSeptemberCenserGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[Sept-Ember Censer].available_amount() == 0) return; - - int septEmbers = get_property_int("availableSeptEmbers"); - string [int] description; - float coldResistance = numeric_modifier("cold resistance"); - int mainstatGain = (7 * (coldResistance) ** 1.7) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); - string url = "shop.php?whichshop=september"; - string title = "Sept-Ember Censer"; - int bembershootCount = $item[bembershoot].available_amount(); - int mouthwashCount = $item[Mmm-brr! brand mouthwash].available_amount(); - int structureCount = $item[structural ember].available_amount(); - int hunkCount = $item[embering hunk].available_amount(); - boolean hulkFought = get_property_boolean("_emberingHulkFought"); - boolean structureUsed = get_property_boolean("_structuralEmberUsed"); - - if (septEmbers > 0) - { - description.listAppend(`Have {HTMLGenerateSpanFont(septEmbers, "red")} Sept-Embers to make stuff with!`); - } - - description.listAppend(`1 embers: +5 cold res accessory (You have {HTMLGenerateSpanFont(bembershootCount, "red")})`); - description.listAppend(`2 embers: mmm-brr! mouthwash for {HTMLGenerateSpanFont(mainstatGain, "blue")} mainstat. (You have {HTMLGenerateSpanFont(mouthwashCount, "red")})`); - - if (structureUsed) { - description.listAppend((HTMLGenerateSpanFont("Already used structural ember today", "red"))); - } else { - description.listAppend("4 embers: +5/5 bridge parts (1/day)"); - } - - if (hulkFought) { - description.listAppend((HTMLGenerateSpanFont("Already fought embering hulk today", "red"))); - } else { - description.listAppend("6 embers: embering hulk (1/day)"); - } - - description.listAppend(`(You have {HTMLGenerateSpanFont(hunkCount, "red")} hunks)`); - - resource_entries.listAppend(ChecklistEntryMake("__item sept-ember censer", url, ChecklistSubentryMake(title, "", description), 8)); -} diff --git a/Source/relay/TourGuide/Items of the Month/2024/Spring Shoes.ash b/Source/relay/TourGuide/Items of the Month/2024/Spring Shoes.ash deleted file mode 100644 index 34567afb..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/Spring Shoes.ash +++ /dev/null @@ -1,47 +0,0 @@ -//Spring shoes -RegisterTaskGenerationFunction("IOTMSpringShoesGenerateTasks"); -RegisterResourceGenerationFunction("IOTMSpringShoesGenerateResource"); - -void IOTMSpringShoesGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - // Initialization. Do not generate if you don't have spring shoes. - if (!__iotms_usable[lookupItem("spring shoes")]) return; - - // Added a check for all paths where you do not want the tile at all: - // - Community Service: irrelevant - // - WereProfessor: is not a free run. - - boolean pathCheck = true; - pathCheck = my_path().id == PATH_COMMUNITY_SERVICE ? false : true; - pathCheck = my_path().id == PATH_WEREPROFESSOR ? false : true; - - // Technically, the available_amount here precludes the need for the initialization up top. - if (__misc_state["in run"] && available_amount($item[spring shoes]) > 0 && pathCheck) - { - if ($effect[everything looks green].have_effect() == 0) - { - string [int] description; - string url = "inventory.php?ftext=spring+shoes"; - description.listAppend(HTMLGenerateSpanFont("Free-run away from your problems with the Spring Away skill!", "green")); - if (lookupItem("spring shoes").equipped_amount() == 0) - { - description.listAppend(HTMLGenerateSpanFont("Equip the spring shoes first.", "red")); - } - task_entries.listAppend(ChecklistEntryMake("__item spring shoes", url, ChecklistSubentryMake("Spring shoes runaway available!", "", description), -11)); - } - } -} - -void IOTMSpringShoesGenerateResource(ChecklistEntry [int] resource_entries) -{ - // Initialization. Do not generate if you don't have spring shoes. - if (!__iotms_usable[lookupItem("spring shoes")]) return; - - string [int] banishDescription; - banishDescription.listAppend("All day banish, doesn't end combat"); - if (lookupItem("spring shoes").equipped_amount() == 0) - { - banishDescription.listAppend(HTMLGenerateSpanFont("Equip the spring shoes first.", "red")); - } - resource_entries.listAppend(ChecklistEntryMake("__skill spring shoes", "", ChecklistSubentryMake("Spring Kick", "", banishDescription), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Spring shoes spring kick banish")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2024/TakerSpace.ash b/Source/relay/TourGuide/Items of the Month/2024/TakerSpace.ash deleted file mode 100644 index aeec4b69..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/TakerSpace.ash +++ /dev/null @@ -1,37 +0,0 @@ -//Takerspace -RegisterResourceGenerationFunction("IOTMTakerspaceGenerateResource"); -void IOTMTakerspaceGenerateResource(ChecklistEntry [int] resource_entries) -{ - //you wouldn't download a boat - if (__iotms_usable[lookupItem("TakerSpace letter of Marque")]) return; - - string [int] description; - string url = "campground.php?action=workshed"; - int TSAnchors = get_property_int("takerSpaceAnchor"); - int TSGold = get_property_int("takerSpaceGold"); - int TSMasts = get_property_int("takerSpaceMast"); - int TSRum = get_property_int("takerSpaceRum"); - int TSSilk = get_property_int("takerSpaceSilk"); - int TSSpice = get_property_int("takerSpaceSpice"); - - if (TSAnchors + TSGold + TSMasts + TSRum + TSSilk + TSSpice > 0) - { - description.listAppend(HTMLGenerateSpanOfClass("Spices: ", "r_bold") + "" + TSSpice + ""); - description.listAppend(HTMLGenerateSpanOfClass("Rum: ", "r_bold") + "" + TSRum + ""); - description.listAppend(HTMLGenerateSpanOfClass("Anchors: ", "r_bold") + "" + TSAnchors + ""); - description.listAppend(HTMLGenerateSpanOfClass("Masts: ", "r_bold") + "" + TSMasts + ""); - description.listAppend(HTMLGenerateSpanOfClass("Silk: ", "r_bold") + "" + TSSilk + ""); - description.listAppend(HTMLGenerateSpanOfClass("Gold: ", "r_bold") + "" + TSGold + ""); - - if ($item[pirate dinghy].available_amount() == 0 ) { - description.listAppend(HTMLGenerateSpanFont("Boat: 1 anchor/1 mast/1 silk", "blue")); - } - if ($item[deft pirate hook].available_amount() == 0 ) { - description.listAppend(HTMLGenerateSpanFont("Hook: 1 anchor/1 mast/1 gold", "blue")); - } - if ($item[jolly roger flag].available_amount() == 0 ) { - description.listAppend(HTMLGenerateSpanFont("Flag: 1 rum/1 mast/1 silk/1 gold", "blue")); - } - resource_entries.listAppend(ChecklistEntryMake("__item pirate dinghy", url, ChecklistSubentryMake("Takerspace resources", description), 1)); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash b/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash deleted file mode 100644 index 2693c78f..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash +++ /dev/null @@ -1,29 +0,0 @@ -// Tearaway Pants -RegisterTaskGenerationFunction("IOTMTearawayPantsGenerateTask"); -void IOTMTearawayPantsGenerateTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - // Don't show the tile if you don't have the pants. - if (!__iotms_usable[lookupItem("tearaway pants")]) return; - - // Don't show the tile if you aren't a moxie class. - if (!($classes[disco bandit,accordion thief] contains my_class())) return; - - // I can't believe I'm doing this. I have truly lost control of my life. - QuestState base_quest_state = __quest_state["Guild"]; - if (base_quest_state.finished || !base_quest_state.startable || base_quest_state.mafia_internal_step == 2) return; - - // Do you have the stupid pants equipped? - boolean havePantsEquipped = $slot[pants].equipped_item() == $item[tearaway pants]; - - string [int] description; - - // If equipped, send user to the guild. If not, send them to the inventory. - string url = havePantsEquipped ? "guild.php" : "inventory.php?ftext=tearaway+pants"; - string header = "Tear away your tearaway pants!"; - - if (havePantsEquipped) description.listAppend(`Visit the Department of Shadowy Arts and Crafts to unlock the guild!`); - if (!havePantsEquipped) description.listAppend(`Visit the Department of Shadowy Arts and Crafts with your pants equipped to unlock the guild!`); - - optional_task_entries.listAppend(ChecklistEntryMake("__item tearaway pants", url, ChecklistSubentryMake(header, "", description), 0)); - -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2024/VIP Photobooth.ash b/Source/relay/TourGuide/Items of the Month/2024/VIP Photobooth.ash deleted file mode 100644 index c13e00a6..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/VIP Photobooth.ash +++ /dev/null @@ -1,35 +0,0 @@ -// Clan VIP Photo booth -RegisterResourceGenerationFunction("IOTMVIPPhotoBoothGenerateResource"); -void IOTMVIPPhotoBoothGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (available_amount($item[Clan VIP Lounge key]) < 1) - return; - - string [int] description; - string url = "inventory.php?ftext=sheriff"; - - int photosLeft = clampi(3 - get_property_int("_photoBoothEffects"), 0, 3); - if (photosLeft > 0) - { - description.listAppend(HTMLGenerateSpanFont("Get your photo taken:", "black")); - description.listAppend(HTMLGenerateSpanFont("photobooth west: +50% init, +noncom%", "black")); - description.listAppend(HTMLGenerateSpanFont("photobooth tower: +com%", "black")); - description.listAppend(HTMLGenerateSpanFont("photobooth space: this sucks", "black")); - - resource_entries.listAppend(ChecklistEntryMake("__item expensive camera", url, ChecklistSubentryMake(photosLeft + " clan photos takeable", description), 8)); - } - //this here town ain't big enough for the two of us - int sheriffings = clampi(3 - get_property_int("_assertYourAuthorityCast"), 0, 3); - if (sheriffings > 0) - { - if (lookupItem("sheriff badge").equipped_amount() == 1 && lookupItem("sheriff moustache").equipped_amount() == 1 && lookupItem("sheriff pistol").equipped_amount() == 1) - { - description.listAppend(HTMLGenerateSpanFont("Assert your authority!", "blue")); - } - else - { - description.listAppend(HTMLGenerateSpanFont("Equip your sheriff gear first.", "red")); - } - resource_entries.listAppend(ChecklistEntryMake("__item badge of authority", url, ChecklistSubentryMake(sheriffings + " Sheriff Authority free kill(s)", description), 5)); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2024/bat wings.ash b/Source/relay/TourGuide/Items of the Month/2024/bat wings.ash deleted file mode 100644 index f0fea134..00000000 --- a/Source/relay/TourGuide/Items of the Month/2024/bat wings.ash +++ /dev/null @@ -1,93 +0,0 @@ -// Bat Wings -RegisterTaskGenerationFunction("IOTMRomanBatWingsTasks"); -void IOTMRomanBatWingsTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[bat wings].available_amount() == 0) return; - - string [int] description; - string url; - // 25 bridge parts - int bridgeProg = get_property_int("chasmBridgeProgress"); - { - if (bridgeProg >= 25 && !locationAvailable($location[Oil Peak])) - { - if (lookupItem("bat wings").equipped_amount() == 0) { - url = "inventory.php?ftext=bat+wings"; - description.listAppend(HTMLGenerateSpanFont("Equip the bat wings first.", "red")); - } - else { - url = "place.php?whichplace=orc_chasm"; - description.listAppend(HTMLGenerateSpanFont("Leap across the bridge!", "blue")); - } - task_entries.listAppend(ChecklistEntryMake("__item miniature suspension bridge", url, ChecklistSubentryMake("Bat wings to cross the chasm!", "", description), -11)); - } - } -} - -RegisterResourceGenerationFunction("IOTMBatWingsGenerateResource"); -void IOTMBatWingsGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (available_amount($item[bat wings]) < 1) - return; - - string [int] description; - string url = "inventory.php?ftext=bat+wings"; - - //save the city of gotpork, battyman! - int batWingSwoopsLeft = clampi(11 - get_property_int("_batWingsSwoopUsed"), 0, 11); - int batWingRestsLeft = clampi(11 - get_property_int("_batWingsRestUsed"), 0, 11); - int batWingCauldronsLeft = clampi(11 - get_property_int("_batWingsCauldronUsed"), 0, 11); - int batWingFreeFlapsLeft = clampi(5 - get_property_int("_batWingsFreeFights"), 0, 5); - int bridge = get_property_int("chasmBridgeProgress"); - - if (lookupItem("bat wings").equipped_amount() == 0) - { - description.listAppend(HTMLGenerateSpanFont("Equip your bat wings.", "red")); - } - else - { - description.listAppend(HTMLGenerateSpanFont("Nanananananananana Battyman!", "purple")); - } - if (!$location[The Castle in the Clouds in the Sky (Basement)].locationAvailable()) { - description.listAppend(HTMLGenerateSpanFont("This saves turns in the Airshit!", "blue")); - } - if (batWingSwoopsLeft == 0) - { - description.listAppend(HTMLGenerateSpanFont("0 Swoop Evilpockets left.", "red")); - } - else - { - description.listAppend("Swoop Evilpockets: " + (HTMLGenerateSpanOfClass(batWingSwoopsLeft, "r_bold")) + " left."); - } - if (batWingRestsLeft == 0) - { - description.listAppend(HTMLGenerateSpanFont("0 Bat Rests left.", "red")); - } - else - { - description.listAppend("Rest +1000 HP/MP: " + (HTMLGenerateSpanOfClass(batWingRestsLeft, "r_bold")) + " left."); - } - if (batWingFreeFlapsLeft == 0) - { - description.listAppend(HTMLGenerateSpanFont("0 Free Flaps left.", "red")); - } - else - { - description.listAppend("Free flaps: " + (HTMLGenerateSpanOfClass(batWingFreeFlapsLeft, "r_bold")) + " left."); - } - - if (bridge >= 25 && !locationAvailable($location[Oil Peak])) { - description.listAppend("You can skip the rest of the bridge!"); - } - if (($locations[A Mob of Zeppelin Protesters] contains __last_adventure_location)) { - description.listAppend("This does... something useful!"); - } - - boolean guanoBat = get_property_boolean("batWingsGuanoJunction"); - - if (!guanoBat) { - description.listAppend("Visit the Bat Hole zones to unlock the Beanbat Chamber and get a bean"); - } - - resource_entries.listAppend(ChecklistEntryMake("__item bat wings", url, ChecklistSubentryMake("Bat Wings functions", "", description), 8)); -} diff --git a/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash b/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash deleted file mode 100644 index 383b0c1b..00000000 --- a/Source/relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash +++ /dev/null @@ -1,21 +0,0 @@ -//allied radio backpack -RegisterResourceGenerationFunction("IOTTAlliedRadioBackpackGenerateResource"); -void IOTTAlliedRadioBackpackGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[allied radio backpack].available_amount() == 0) return; - - string url = "inventory.php?action=requestdrop&pwd=" + my_hash(); - int radioDropsLeft = clampi(3 - get_property_int("_alliedRadioDropsUsed"), 0, 3); - boolean usedIntel = get_property_boolean("_alliedRadioMaterielIntel"); - string [int] description; - string title = HTMLGenerateSpanFont(radioDropsLeft + " Allied Radio Drops", "black"); - - if (radioDropsLeft > 0) - { - description.listAppend("Request an airdrop!"); - description.listAppend("|*" + HTMLGenerateSpanOfClass("SNIPER SUPPORT", "r_bold") + " for a sneak!"); - if (!usedIntel) description.listAppend("|*" + HTMLGenerateSpanOfClass("MATERIAL INTEL", "r_bold") + " for +100% item! "+HTMLGenerateSpanFont("(10 turns)", "gray", "0.9em")); - description.listAppend("|*" + HTMLGenerateSpanOfClass("FUEL or RATIONS", "r_bold") + " for weak turngen!"); - resource_entries.listAppend(ChecklistEntryMake("__item allied radio backpack", url, ChecklistSubentryMake(title, "", description))); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2025/April Shower Thoughts Calendar.ash b/Source/relay/TourGuide/Items of the Month/2025/April Shower Thoughts Calendar.ash deleted file mode 100644 index 7e8641c0..00000000 --- a/Source/relay/TourGuide/Items of the Month/2025/April Shower Thoughts Calendar.ash +++ /dev/null @@ -1,42 +0,0 @@ -//shower thoughts -RegisterTaskGenerationFunction("IOTMAprilShowerThoughtsGenerateTasks"); -void IOTMAprilShowerThoughtsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[April Shower Thoughts shield].available_amount() == 0) return; - string url = "inventory.php?action=shower&pwd=" + my_hash(); - string [int] description; - - boolean showerGlobs = get_property_boolean("_aprilShowerGlobsCollected"); - if (showerGlobs == false) { - description.listAppend("Collect globs"); - task_entries.listAppend(ChecklistEntryMake("__item April Shower Thoughts shield", url, ChecklistSubentryMake("Shower for Globs", "", description), -11)); - } - if (lookupItem("april shower thoughts shield").equipped_amount() == 1) - { - string main_title = HTMLGenerateSpanFont("April Shower Powers", "black"); - boolean showerNEYR = get_property_boolean("_aprilShowerNorthernExplosion"); - if (showerNEYR == false) { - description.listAppend(HTMLGenerateSpanFont("Northern Explosion YR available", "blue")); - task_entries.listAppend(ChecklistEntryMake("__item april shower thoughts shield", "", ChecklistSubentryMake(main_title, description), -11).ChecklistEntrySetIDTag("april shower thoughts calendar tasks")); - } - } -} - -RegisterResourceGenerationFunction("IOTMAprilShowerThoughtsGenerateResource"); -void IOTMAprilShowerThoughtsGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[April Shower Thoughts shield].available_amount() == 0) return; - string url = "shop.php?whichshop=showerthoughts"; - string [int] description; - - string main_title = HTMLGenerateSpanFont("April Shower Powers", "black"); - boolean showerNEYR = get_property_boolean("_aprilShowerNorthernExplosion"); - if (showerNEYR == false) { - description.listAppend(HTMLGenerateSpanFont("Northern Explosion YR available", "blue")); - } - int globCount = available_amount($item[glob of wet paper]); - { - description.listAppend("Craft your shower thoughts, with your "+pluralise(globCount,"glob","globs")+"!"); - } - resource_entries.listAppend(ChecklistEntryMake("__item april shower thoughts shield", url, ChecklistSubentryMake(main_title, description), 10).ChecklistEntrySetIDTag("april shower thoughts calendar resource")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2025/Cooler Yeti.ash b/Source/relay/TourGuide/Items of the Month/2025/Cooler Yeti.ash deleted file mode 100644 index 0f520674..00000000 --- a/Source/relay/TourGuide/Items of the Month/2025/Cooler Yeti.ash +++ /dev/null @@ -1,58 +0,0 @@ -//cooler yeti -RegisterTaskGenerationFunction("IOTMCoolerYetiGenerateTasks"); -void IOTMCoolerYetiGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!lookupFamiliar("Cooler Yeti").familiar_is_usable()) return; - if (my_familiar() != lookupFamiliar("Cooler Yeti")) return; - string url = "familiar.php"; - string [int] description; - - int yetiExperience = ($familiar[cooler yeti].experience); - int famExpNeededFor400 = (400 - yetiExperience); - string fightsForYeti; - - if (!get_property_boolean("_coolerYetiAdventures")) { - if (yetiExperience >= 400) { - description.listAppend("" + HTMLGenerateSpanFont("Doublebooze ready!", "blue")); - string url = "main.php?talktoyeti=1"; - task_entries.listAppend(ChecklistEntryMake("__item dreadsylvanian cold-fashioned", url, ChecklistSubentryMake("Yeti booze time", description), -11).ChecklistEntrySetIDTag("cooler yeti booze time")); - } - } -} - -RegisterResourceGenerationFunction("IOTMCoolerYetiGenerateResource"); -void IOTMCoolerYetiGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!lookupFamiliar("Cooler Yeti").familiar_is_usable()) return; - - // Title - int famExperienceGain = numeric_modifier("familiar experience") + 1; - int yetiExperience = ($familiar[cooler yeti].experience); - int famExpNeededFor400 = (400 - yetiExperience); - string [int] description; - string url = "familiar.php"; - string fightsForYeti; - string title = HTMLGenerateSpanFont("Cooler Yeti fxp", "blue"); - if (famExperienceGain > 0) { - fightsForYeti = pluralise(ceil(to_float(famExpNeededFor400) / famExperienceGain), "fight", "fights"); - } - else { - fightsForYeti = "cannot get"; - } - if (!get_property_boolean("_coolerYetiAdventures")) { - if (yetiExperience >= 400) { - description.listAppend(HTMLGenerateSpanOfClass("Doubles next booze adv", "r_bold") + " costs 400 fxp."); - url = "main.php?talktoyeti=1"; - } - } - if (yetiExperience >= 225) { - description.listAppend(HTMLGenerateSpanOfClass("100 advs of +100% item/meat", "r_bold") + " costs 225 fxp."); - } - - description.listAppend(`Currently have {HTMLGenerateSpanOfClass(yetiExperience, "r_bold")} experience, currently gain {HTMLGenerateSpanOfClass(famExperienceGain, "r_bold")} fam exp per fight.`); - if (yetiExperience < 400) { - description.listAppend(`Need {HTMLGenerateSpanOfClass(famExpNeededFor400, "r_bold")} more famxp for doublebooze. ({fightsForYeti})`); - } - - resource_entries.listAppend(ChecklistEntryMake("__familiar cooler yeti", url, ChecklistSubentryMake(title, "", description), -1)); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2025/CyberRealm.ash b/Source/relay/TourGuide/Items of the Month/2025/CyberRealm.ash deleted file mode 100644 index a0a76f21..00000000 --- a/Source/relay/TourGuide/Items of the Month/2025/CyberRealm.ash +++ /dev/null @@ -1,126 +0,0 @@ -//CyberRealm -RegisterTaskGenerationFunction("IOTYCyberRealmGenerateTasks"); -void IOTYCyberRealmGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[server room key].available_amount() < 1) return; - - int CyberFree = get_property_int("_cyberFreeFights"); - int zone1Turns = get_property_int("_cyberZone1Turns"); - int zone2Turns = get_property_int("_cyberZone2Turns"); - int zone3Turns = get_property_int("_cyberZone3Turns"); - int CyberZoneLeft = zone1turns + zone2turns + zone3turns; - string [int] description; - string url = "place.php?whichplace=CyberRealm"; - string image_name = "__skill stats+++"; - - if ($item[familiar-in-the-middle wrapper].equipped_amount() == 1) { - description.listAppend(HTMLGenerateSpanFont("FITMW equipped. Extra 1 per fight.", "blue")); - } - else if ($item[familiar-in-the-middle wrapper].equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip your FITMW for an extra 1 per fight.", "red")); - } - - #if (zone1Turns < 20) - { - if (zone1Turns < 9) { - description.listAppend(9 - zone1Turns + " combats until Zone 1 Eleres test."); - } - else if (zone1Turns == 9) - { - description.listAppend(HTMLGenerateSpanFont("Get 11 eleres for the Cyberzone 1 test", "blue")); - image_name = "__skill overclock(10)"; - } - else if (zone1Turns < 19) - { - description.listAppend(19 - zone1Turns + " combats until Zone 1 reward."); - } - else if (zone1Turns == 19) - { - description.listAppend(HTMLGenerateSpanFont("Cyberzone 1 reward!", "green")); - image_name = "__skill sleep(5)"; - } - else if (zone1Turns > 19) { - description.listAppend(HTMLGenerateSpanFont("Cyberzone 1 finished.", "grey")); - } - } - - #if (zone2Turns < 20) - { - if (zone2Turns < 9) { - description.listAppend(9 - zone2Turns + " combats until Zone 2 Eleres test."); - } - else if (zone2Turns == 9) - { - description.listAppend(HTMLGenerateSpanFont("Get 11 eleres for the Cyberzone 2 test", "blue")); - image_name = "__skill overclock(10)"; - } - else if (zone2Turns < 19) - { - description.listAppend(19 - zone2Turns + " combats until Zone 2 reward."); - } - else if (zone2Turns == 19) - { - description.listAppend(HTMLGenerateSpanFont("Cyberzone 2 reward!", "green")); - image_name = "__skill sleep(5)"; - } - else if (zone2Turns > 19) { - description.listAppend(HTMLGenerateSpanFont("Cyberzone 2 finished.", "grey")); - } - } - - #if (zone3Turns < 20) - { - if (zone3Turns < 9) { - description.listAppend(9 - zone3Turns + " combats until Zone 3 Eleres test."); - } - else if (zone3Turns == 9) - { - description.listAppend(HTMLGenerateSpanFont("Get 11 eleres for the Cyberzone 3 test", "blue")); - image_name = "__skill overclock(10)"; - } - else if (zone3Turns < 19) - { - description.listAppend(19 - zone3Turns + " combats until Zone 3 reward."); - } - else if (zone3Turns == 19) - { - description.listAppend(HTMLGenerateSpanFont("Cyberzone 3 reward!", "green")); - image_name = "__skill sleep(5)"; - } - else if (zone3Turns > 19) { - description.listAppend(HTMLGenerateSpanFont("Cyberzone 3 finished.", "grey")); - } - } - - if (($locations[Cyberzone 1,Cyberzone 2,Cyberzone 3] contains __last_adventure_location)) - { - description.listAppend(HTMLGenerateSpanFont("Have " + (10 - CyberFree) + " free fights left!", "green")); - task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(60 - CyberZoneLeft + " CyberRealm adventures!", "", description), -11)); - } - else - { - if (get_property_int("_cyberFreeFights") < 10 && lookupSkill("OVERCLOCK(10)").have_skill()) { - description.listAppend(HTMLGenerateSpanFont("Have " + (10 - CyberFree) + " free fights left!", "green")); - } - else { - description.listAppend(HTMLGenerateSpanFont("No free fights left", "red")); - } - optional_task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(60 - CyberZoneLeft + " CyberRealm adventures!", "", description), 10)); - } -} - -RegisterResourceGenerationFunction("IOTYCyberRealmGenerateResource"); -void IOTYCyberRealmGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[server room key].available_amount() < 1) return; - - int CyberFree = clampi(10 - get_property_int("_cyberFreeFights"), 0, 10); - string url; - string [int] description; - - if (get_property_int("_cyberFreeFights") < 10 && lookupSkill("OVERCLOCK(10)").have_skill()) { - string url = "place.php?whichplace=CyberRealm"; - description.listAppend("Hack into the system!"); - resource_entries.listAppend(ChecklistEntryMake("__skill stats+++", url, ChecklistSubentryMake(pluralise(CyberFree, "CyberRealm fight", "CyberRealm fights"), "", description), 8).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("CyberRealm free fight")); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/2025/Leprecondo.ash b/Source/relay/TourGuide/Items of the Month/2025/Leprecondo.ash deleted file mode 100644 index c91e83ce..00000000 --- a/Source/relay/TourGuide/Items of the Month/2025/Leprecondo.ash +++ /dev/null @@ -1,50 +0,0 @@ -//leprecondo -RegisterTaskGenerationFunction("IOTMLeprecondoGenerateTasks"); -void IOTMLeprecondoGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[leprecondo].available_amount() == 0) return; - string url = "inv_use.php?pwd=" + my_hash() + "&which=99&whichitem=11861"; - string [int] description; - - int lepCondoChanges = clampi(3 - get_property_int("_leprecondoRearrangements"), 0, 3); - string lepCondoSetup = (get_property("leprecondoInstalled")); - if (lepCondoSetup == "0,0,0,0") { - description.listAppend("Decorate the Leprecondo"); - task_entries.listAppend(ChecklistEntryMake("__item leprecondo", url, ChecklistSubentryMake("Decorate your Leprecondo", "", description), -11)); - } -} - -RegisterResourceGenerationFunction("IOTMLeprecondoGenerateResource"); -void IOTMLeprecondoGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[leprecondo].available_amount() == 0) return; - string url = "inv_use.php?pwd=" + my_hash() + "&which=99&whichitem=11861"; - string [int] description; - - int lepCondoChanges = clampi(3 - get_property_int("_leprecondoRearrangements"), 0, 3); - string lepCondoCurrent = (get_property("leprecondoCurrentNeed")); - string lepCondoCycle = (get_property("leprecondoNeedOrder")); - string lepCondoSetup = (get_property("leprecondoInstalled")); - description.listAppend("Current setup: " + lepCondoSetup + "."); - if (lepCondoChanges > 0) { - description.listAppend(HTMLGenerateSpanFont("Can redecorate " + lepCondoChanges + " more times today.", "green")); - } - description.listAppend("Need cycle: " + lepCondoCycle + "."); - description.listAppend("Current need: " + lepCondoCurrent + "."); - - int nextCondoTurn = get_property_int("leprecondoLastNeedChange"); - - if (nextCondoTurn +5 <= turns_played()) { - description.listAppend(HTMLGenerateSpanFont("Condo trigger time!", "blue")); - } - else { - description.listAppend(HTMLGenerateSpanFont("Condo trigger in " + (nextCondoTurn +5 - turns_played()) + " advs.", "blue")); - } - int punchOutChanges = (get_property_int("preworkoutPowderUses")); - if (punchOutChanges > 0) - { - resource_entries.listAppend(ChecklistEntryMake("__item orange boxing gloves", "", ChecklistSubentryMake(pluralise(get_property_int("preworkoutPowderUses"), "Condo Punch", "Condo Punches"), "", "Free run/banish.")).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("condo punch banish")); - } - - resource_entries.listAppend(ChecklistEntryMake("__item leprecondo", url, ChecklistSubentryMake("Leprecondo stuff", description), 11)); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2025/McHugeLarge Ski Set.ash b/Source/relay/TourGuide/Items of the Month/2025/McHugeLarge Ski Set.ash deleted file mode 100644 index bcd93269..00000000 --- a/Source/relay/TourGuide/Items of the Month/2025/McHugeLarge Ski Set.ash +++ /dev/null @@ -1,51 +0,0 @@ - -//Ski set -RegisterTaskGenerationFunction("IOTMSkiSetGenerateTasks"); -void IOTMSkiSetGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[McHugeLarge duffel bag].available_amount() < 1) return; - - if ($item[McHugeLarge duffel bag].available_amount() > 0 && $item[McHugeLarge right ski].available_amount() == 0) - { - task_entries.listAppend(ChecklistEntryMake("__item McHugeLarge duffel bag", "inventory.php?ftext=McHugeLarge+duffel+bag", ChecklistSubentryMake("McHugeLarge duffel bag", "", "Open it!"), -10).ChecklistEntrySetIDTag("McHugeLarge duffel bag resource")); - } -} - - -RegisterResourceGenerationFunction("IOTMSkiSetGenerateResource"); -void IOTMSkiSetGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[McHugeLarge duffel bag].available_amount() < 1) return; - - int skiAvalanchesLeft = clampi(3 - get_property_int("_mcHugeLargeAvalancheUses"), 0, 3); - int skiSlashesLeft = clampi(3 - get_property_int("_mcHugeLargeSlashUses"), 0, 3); - string [int] description; - string url = "inventory.php?ftext=McHugeLarge"; - - if (skiAvalanchesLeft > 0) - { - description.listAppend(HTMLGenerateSpanOfClass(skiSlashesLeft + " avalanches", "r_bold") + " left. Sneak!"); - //fixme: currently not supported by sneako tile - if (lookupItem("McHugeLarge left ski").equipped_amount() == 1) - { - description.listAppend(HTMLGenerateSpanFont("|*LEFT SKI equipped!", "blue")); - } - else if (lookupItem("McHugeLarge left ski").equipped_amount() == 0) - { - description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT SKI first.", "red")); - } - } - if (skiSlashesLeft > 0) - { - description.listAppend(HTMLGenerateSpanOfClass(skiSlashesLeft + " slashes", "r_bold") + " left. Track a monster."); - if (lookupItem("McHugeLarge left pole").equipped_amount() == 1) - { - description.listAppend(HTMLGenerateSpanFont("|*LEFT POLE equipped!", "blue")); - } - else if (lookupItem("McHugeLarge left pole").equipped_amount() == 0) - { - description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT POLE first.", "red")); - } - } - resource_entries.listAppend(ChecklistEntryMake("__item McHugeLarge duffel bag", url, ChecklistSubentryMake("McHugeLarge ski set skills", description), 1)); -} diff --git a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash b/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash deleted file mode 100644 index 3896128e..00000000 --- a/Source/relay/TourGuide/Items of the Month/2025/Mobius Ring.ash +++ /dev/null @@ -1,113 +0,0 @@ -// mobius ring -RegisterTaskGenerationFunction("IOTMMobiusRingGenerateTasks"); -void IOTMMobiusRingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - item mobRing = $item[Möbius ring]; - if (mobRing.available_amount() == 0) return; - - // Native game prefs. Note that my_paradoxicity() also exists! - int lastMobiusTurn = get_property_int("_lastMobiusStripTurn"); - int countMobiusNCs = get_property_int("_mobiusStripEncounters"); - int countTimeCops = get_property_int("_timeCopsFoughtToday"); - - // Is it equipped? - boolean mobEquipped = mobRing.equipped_amount() == 1; - - // There are clearly better ways to do this, but I'm tired and this - // is "fine." After 17 NCs, they'll all be 76 turns between, so cap - // inputs to 17. - - int [int] turnsBetweenNCs = {1:4, 2:7, 3:13, 4:19, 5:25, 6:31, 7:41, 8:41, 9:41, 10:41, 11:41, 12:51, 13:51, 14:51, 15:51, 16:51, 17:76}; - int turnsSinceLastNC = total_turns_played() - lastMobiusTurn; - int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - (lastMobiusTurn == 0 ? my_turncount() : turnsSinceLastNC)); - int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] + turnsUntilNextNC); - - // This is sort of a dumb way to do this too, but alas. - int [int] timeCopRate = { - 0:2, 1:2, 2:2, 3:2, 4:2, - 5:4, 6:4, 7:4, 8:4, 9:4, - 10:8, 11:8, 12:8, 13:8, 14:8, - 15:16, 16:16, 17:16, 18:16, 19:19, - 20:32}; - int currentTimeCopRate = timeCopRate[min(my_paradoxicity(), 20)]; - - // First, a generic time cop counter task. Low priority if you have - // freebies left, high priority if you don't. - string url = "inventory.php?ftext=bius+ring"; - string [int] copDescription; - string copSubTitle = "Forecast is "+currentTimeCopRate+"% chance of cops"; - string copTitle = HTMLGenerateSpanFont(pluralise(min(11-countTimeCops, 0), "free Time Cops fought today", "free Time Cops fought today"), "black"); - boolean copsNoLongerFree = countTimeCops > 11; - int priority = 10; - - if (mobEquipped) { - if (!copsNoLongerFree) { - copDescription.listAppend(HTMLGenerateSpanFont("Ring equipped, it's Möbing time!", "blue")); - optional_task_entries.listAppend(ChecklistEntryMake("__monster time cop", "", ChecklistSubentryMake(copTitle, copSubtitle, copDescription), priority).ChecklistEntrySetIDTag("morb ring cop task")); - } - if (copsNoLongerFree) - { - copDescription.listAppend(HTMLGenerateSpanFont("Möbius ring equipped, danger!", "red")); - priority = -11; - task_entries.listAppend(ChecklistEntryMake("__monster time cop", "", ChecklistSubentryMake(copTitle, copSubtitle, copDescription), priority).ChecklistEntrySetIDTag("morb ring cop task")); - } - } - - // Next, a supernag if you happen to have an NC available. (Demote from - // a supernag if you already have 11 free cops fought, though.) - string [int] ncDescription; - string ncTitle = "Möbius non-combat available!"; - string ncSubtitle = "Currently @ " + my_paradoxicity() + " paradoxicity"; - int ncPriority = copsNoLongerFree ? 0 : -11; - - if (mobEquipped) ncDescription.listAppend("Keep your Möbius ring equipped for an NC"); - if (!mobEquipped) ncDescription.listAppend(HTMLGenerateSpanFont("Equip your Möbius ring for a shot at a Paradoxicity NC!", "red")); - - if(turnsUntilNextNC == 0) task_entries.listAppend(ChecklistEntryMake("__item Möbius ring", "", ChecklistSubentryMake(ncTitle, ncSubtitle, ncDescription), ncPriority).ChecklistEntrySetIDTag("morb ring nc task")); - -} - -RegisterResourceGenerationFunction("IOTMMobiusRingGenerateResource"); -void IOTMMobiusRingGenerateResource(ChecklistEntry [int] resource_entries) -{ - item mobRing = $item[Möbius ring]; - if (mobRing.available_amount() == 0) return; - - // Native game prefs. Note that my_paradoxicity() also exists! - int lastMobiusTurn = get_property_int("_lastMobiusStripTurn"); - int countMobiusNCs = get_property_int("_mobiusStripEncounters"); - int countTimeCops = get_property_int("_timeCopsFoughtToday"); - - // Is it equipped? - boolean mobEquipped = mobRing.equipped_amount() == 1; - - // There are clearly better ways to do this, but I'm tired and this - // is "fine." After 17 NCs, they'll all be 76 turns between, so cap - // inputs to 17. - - int [int] turnsBetweenNCs = {1:4, 2:7, 3:13, 4:19, 5:25, 6:31, 7:41, 8:41, 9:41, 10:41, 11:41, 12:51, 13:51, 14:51, 15:51, 16:51, 17:76}; - int turnsSinceLastNC = total_turns_played() - lastMobiusTurn; - int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - (lastMobiusTurn == 0 ? my_turncount() : turnsSinceLastNC)); - int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] + turnsUntilNextNC); - - // This is sort of a dumb way to do this too, but alas. - int [int] timeCopRate = { - 0:2, 1:2, 2:2, 3:2, 4:2, - 5:4, 6:4, 7:4, 8:4, 9:4, - 10:8, 11:8, 12:8, 13:8, 14:8, - 15:16, 16:16, 17:16, 18:16, 19:19, - 20:32}; - int currentTimeCopRate = timeCopRate[min(my_paradoxicity(), 20)]; - - string [int] description; - string url = "inventory.php?ftext=bius+ring"; - string title = HTMLGenerateSpanFont(pluralise(turnsUntilNextNC, " turn", " turns") + " to your next Möbius NC", "black"); - - if (turnsUntilNextNC == 0) description.listAppend(HTMLGenerateSpanFont("You can encounter NC #" + (countMobiusNCs+1) +" right now!", "blue")); - if (turnsUntilNextNC > 0) description.listAppend("You have "+pluralise(turnsUntilNextNC, " turn", " turns")+" turns to NC #" +(countMobiusNCs+1)+ "."); - description.listAppend("|*You have at least "+pluralise(turnsUntilNextNextNC, " turn", " turns")+" until NC #"+(countMobiusNCs+2)+"."); - description.listAppend("" + countTimeCops +"/11 free time cops today. (currently @ "+currentTimeCopRate+"% rate)"); - if(countTimeCops > 11) description.listAppend(HTMLGenerateSpanFont("No free time cops remain; be careful wearing your ring!", "red")); - if(my_paradoxicity() < 13) description.listAppend("Boost to 13 Paradoxicity for +100% item & +50% booze drop!"); - resource_entries.listAppend(ChecklistEntryMake("__item Möbius ring", url, ChecklistSubentryMake(title, "", description), 0)); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash b/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash deleted file mode 100644 index c2da9ce6..00000000 --- a/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash +++ /dev/null @@ -1,20 +0,0 @@ -//peridot of peril -RegisterTaskGenerationFunction("IOTMPeridotGenerateTasks"); -void IOTMPeridotGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[peridot of peril].available_amount() == 0) return; - string url = "inventory.php?ftext=peridot+of+peril"; - string [int] description; - - if (lookupItem("peridot of peril").equipped_amount() == 1) - { - description.listAppend(HTMLGenerateSpanFont("PERIDOT POWER!", "green")); - string main_title = HTMLGenerateSpanFont("Peridot picking power", "green"); - task_entries.listAppend(ChecklistEntryMake("__item peridot of peril", "", ChecklistSubentryMake(main_title, description), -11).ChecklistEntrySetIDTag("peridot task")); - } - else if (lookupItem("peridot of peril").equipped_amount() == 0 && (__misc_state["in run"])) - { - description.listAppend(HTMLGenerateSpanFont("Equip the peridot to map monsters", "red")); - optional_task_entries.listAppend(ChecklistEntryMake("__item peridot of peril", "", ChecklistSubentryMake("Peridot picking power", description), 10).ChecklistEntrySetIDTag("peridot task")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash b/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash deleted file mode 100644 index 822f85e2..00000000 --- a/Source/relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash +++ /dev/null @@ -1,51 +0,0 @@ -//prismatic beret -RegisterResourceGenerationFunction("IOTMPrismaticBeretGenerateResource"); -void IOTMPrismaticBeretGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[prismatic beret].available_amount() == 0) return; - - string url = "inventory.php?ftext=prismatic+beret"; - int busksLeft = clampi(5 - get_property_int("_beretBuskingUses"), 0, 5); - string [int] description; - string title = HTMLGenerateSpanFont(busksLeft + " Prismatic Beret Busks", "purple"); - - int hatpower; - int pantspower; - int shartpower; - int total = 0; - item thing; - item shart2; - foreach shart in $slots[shirt] { - shart2 = equipped_item(shart); - if (shart2 != $item[none]) - shartpower += get_power(shart2); - } - foreach it in $slots[hat] { - thing = equipped_item(it); - if (thing != $item[none]) - hatpower += get_power(thing); - } - - foreach it in $slots[pants] { - thing = equipped_item(it); - if (thing != $item[none]) - pantspower += get_power(thing); - } - - if (busksLeft > 0) - { - if (lookupSkill("tao of the terrapin").have_skill()) total += hatpower*2 + pantspower*2; - if ($effect[Hammertime].have_effect() > 0) total += pantspower*3; - description.listAppend("Gain buffs based on current equipment Power"); - description.listAppend("Currently " + (HTMLGenerateSpanFont(shartpower+total, "blue")) + " Power"); - - if (lookupItem("prismatic beret").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("Equip the beret to busk!", "red")); - } - if (lookupFamiliar("mad hatrack").familiar_is_usable() && $item[sane hatrack].is_unrestricted()) { - description.listAppend(HTMLGenerateSpanFont("(You can put it on your hatrack)", "blue")); - } - - resource_entries.listAppend(ChecklistEntryMake("__item prismatic beret", url, ChecklistSubentryMake(title, "", description))); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/Items of the Month import.ash b/Source/relay/TourGuide/Items of the Month/Items of the Month import.ash deleted file mode 100644 index b1c8cc63..00000000 --- a/Source/relay/TourGuide/Items of the Month/Items of the Month import.ash +++ /dev/null @@ -1,171 +0,0 @@ -// Misc -import "relay/TourGuide/Items of the Month/Misc/Gardens.ash"; -import "relay/TourGuide/Items of the Month/Misc/Horsery.ash"; -import "relay/TourGuide/Items of the Month/Misc/Libram.ash"; -import "relay/TourGuide/Items of the Month/Misc/Tomes.ash"; - -// Time-Twitching Tower -import "relay/TourGuide/Items of the Month/Time-Twitching Tower/Tea Tree.ash"; - -// 2009 -import "relay/TourGuide/Items of the Month/2009/Sugar.ash"; - -// 2010 -import "relay/TourGuide/Items of the Month/2010/Crown of Thrones.ash"; - -// 2011 -import "relay/TourGuide/Items of the Month/2011/Plastic Vampire Fangs.ash"; - -// 2013 -import "relay/TourGuide/Items of the Month/2013/Smithsness.ash"; -import "relay/TourGuide/Items of the Month/2013/Psychoanalytic.ash"; - -// 2014 -import "relay/TourGuide/Items of the Month/2014/DNA.ash"; -import "relay/TourGuide/Items of the Month/2014/Grimstone.ash"; -import "relay/TourGuide/Items of the Month/2014/Speakeasy.ash"; -import "relay/TourGuide/Items of the Month/2014/SpringBreakBeach.ash"; - -// 2015 -import "relay/TourGuide/Items of the Month/2015/Barrel God.ash"; -import "relay/TourGuide/Items of the Month/2015/Deck of Every Card.ash"; -import "relay/TourGuide/Items of the Month/2015/Haunted Doghouse.ash"; -import "relay/TourGuide/Items of the Month/2015/Machine Elf.ash"; -import "relay/TourGuide/Items of the Month/2015/Mayo Clinic.ash"; - -// 2016 -import "relay/TourGuide/Items of the Month/2016/Clan Floundry.ash"; -import "relay/TourGuide/Items of the Month/2016/Detective School.ash"; -import "relay/TourGuide/Items of the Month/2016/Gingerbread City.ash"; -import "relay/TourGuide/Items of the Month/2016/Intergnat.ash"; -import "relay/TourGuide/Items of the Month/2016/Protonic Accelerator Pack.ash"; -import "relay/TourGuide/Items of the Month/2016/Snojo.ash"; -import "relay/TourGuide/Items of the Month/2016/Source Terminal.ash"; -import "relay/TourGuide/Items of the Month/2016/Telegraph Office.ash"; -import "relay/TourGuide/Items of the Month/2016/Thanksgarden.ash"; -import "relay/TourGuide/Items of the Month/2016/Time-Spinner.ash"; -import "relay/TourGuide/Items of the Month/2016/Witchess.ash"; - -// 2017 -import "relay/TourGuide/Items of the Month/2017/Asdon Martin.ash"; -import "relay/TourGuide/Items of the Month/2017/GenieBottle.ash"; -import "relay/TourGuide/Items of the Month/2017/KGBriefcase.ash"; -import "relay/TourGuide/Items of the Month/2017/Meteor Lore.ash"; -import "relay/TourGuide/Items of the Month/2017/New You.ash"; -import "relay/TourGuide/Items of the Month/2017/Portable Pantogram.ash"; -import "relay/TourGuide/Items of the Month/2017/Space Jellyfish.ash"; -import "relay/TourGuide/Items of the Month/2017/Spacegate.ash"; -import "relay/TourGuide/Items of the Month/2017/Tunnel of Love.ash"; -import "relay/TourGuide/Items of the Month/2017/XO Skeleton.ash"; - -// 2018 -import "relay/TourGuide/Items of the Month/2018/Garbage Tote.ash"; -import "relay/TourGuide/Items of the Month/2018/Zatara.ash"; -// Missing: Pokefam -// Missing: FantasyRealm -import "relay/TourGuide/Items of the Month/2018/God Lobster.ash"; -import "relay/TourGuide/Items of the Month/2018/BoomBox.ash"; -import "relay/TourGuide/Items of the Month/2018/Cat Burglar.ash"; -import "relay/TourGuide/Items of the Month/2018/Bastille Battalion.ash"; -import "relay/TourGuide/Items of the Month/2018/Neverending Party.ash"; -import "relay/TourGuide/Items of the Month/2018/Latte.ash"; -import "relay/TourGuide/Items of the Month/2018/Voting Booth.ash"; -import "relay/TourGuide/Items of the Month/2018/Boxing Daycare.ash"; - -// 2019 -import "relay/TourGuide/Items of the Month/2019/Kramco Sausage-o-Matic.ash"; -import "relay/TourGuide/Items of the Month/2019/Lil Doctor Bag.ash"; -import "relay/TourGuide/Items of the Month/2019/Vampire Cloak.ash"; -// Missing: PirateRealm -import "relay/TourGuide/Items of the Month/2019/May Saber.ash"; -import "relay/TourGuide/Items of the Month/2019/Rune Spoon.ash"; -import "relay/TourGuide/Items of the Month/2019/Beach Comb.ash"; -import "relay/TourGuide/Items of the Month/2019/Getaway Campsite.ash"; -import "relay/TourGuide/Items of the Month/2019/Pocket Professor.ash"; -import "relay/TourGuide/Items of the Month/2019/Eight Days a Week Pills.ash"; -import "relay/TourGuide/Items of the Month/2019/Pizza Cube.ash"; -import "relay/TourGuide/Items of the Month/2019/Red Nosed Snapper.ash"; - -// 2020 -import "relay/TourGuide/Items of the Month/2020/Bird-a-Day Calendar.ash"; -import "relay/TourGuide/Items of the Month/2020/Powerful Glove.ash"; -import "relay/TourGuide/Items of the Month/2020/Better Shrooms and Gardens.ash"; -// Missing: Left-Hand Man -import "relay/TourGuide/Items of the Month/2020/Guzzlr.ash"; -// Missing: Iunion -import "relay/TourGuide/Items of the Month/2020/Melodramedary.ash"; -import "relay/TourGuide/Items of the Month/2020/Spinmaster Lathe.ash"; -import "relay/TourGuide/Items of the Month/2020/Cargo Cultist Shorts.ash"; -import "relay/TourGuide/Items of the Month/2020/Comprehensive Cartography.ash"; -import "relay/TourGuide/Items of the Month/2020/Superhero Cape.ash"; -import "relay/TourGuide/Items of the Month/2020/Box O Ghosts.ash"; - -// 2021 -import "relay/TourGuide/Items of the Month/2021/Miniature Crystal Ball.ash"; -import "relay/TourGuide/Items of the Month/2021/Emotion Chip.ash"; -import "relay/TourGuide/Items of the Month/2021/Potted Power Plant.ash"; -import "relay/TourGuide/Items of the Month/2021/Backup Camera.ash"; -import "relay/TourGuide/Items of the Month/2021/Short Order Cook.ash"; -import "relay/TourGuide/Items of the Month/2021/Familiar Scrapbook.ash"; -import "relay/TourGuide/Items of the Month/2021/Underground Fireworks Shop.ash"; -// Missing: Candles -import "relay/TourGuide/Items of the Month/2021/Industrial Fire Extinguisher.ash"; -import "relay/TourGuide/Items of the Month/2021/Vampire Vintner.ash"; -import "relay/TourGuide/Items of the Month/2021/Daylight Shavings Helmet.ash"; -import "relay/TourGuide/Items of the Month/2021/Cold Medicine Cabinet.ash"; - -// 2022 -import "relay/TourGuide/Items of the Month/2022/Cursed Magnifying Glass.ash"; -import "relay/TourGuide/Items of the Month/2022/Cosmic Bowling Ball.ash"; -import "relay/TourGuide/Items of the Month/2022/Combat Lover Locket.ash"; -import "relay/TourGuide/Items of the Month/2022/Grey Goose.ash"; -import "relay/TourGuide/Items of the Month/2022/Unbreakable Umbrella.ash"; -import "relay/TourGuide/Items of the Month/2022/Mayday Supply Package.ash"; -import "relay/TourGuide/Items of the Month/2022/June Cleaver.ash"; -import "relay/TourGuide/Items of the Month/2022/Designer Sweatpants.ash"; -import "relay/TourGuide/Items of the Month/2022/Tiny Stillsuit.ash"; -import "relay/TourGuide/Items of the Month/2022/Jurassic Parka.ash"; -import "relay/TourGuide/Items of the Month/2022/Autumnaton.ash"; -import "relay/TourGuide/Items of the Month/2022/Cookbookbat.ash"; -import "relay/TourGuide/Items of the Month/2022/Oliver's Place.ash"; -import "relay/TourGuide/Items of the Month/2022/Model Train Set.ash"; - -// 2023 -import "relay/TourGuide/Items of the Month/2023/Rock Garden.ash"; -import "relay/TourGuide/Items of the Month/2023/SIT Course Certificate.ash"; -import "relay/TourGuide/Items of the Month/2023/Closed Circuit Pay Phone.ash"; -import "relay/TourGuide/Items of the Month/2023/Cursed Monkey Paw.ash"; -import "relay/TourGuide/Items of the Month/2023/Cincho de Mayo.ash"; -import "relay/TourGuide/Items of the Month/2023/2002 Catalog.ash"; -import "relay/TourGuide/Items of the Month/2023/Patriotic Eagle.ash"; -import "relay/TourGuide/Items of the Month/2023/August Scepter.ash"; -import "relay/TourGuide/Items of the Month/2023/Book of Facts.ash"; -import "relay/TourGuide/Items of the Month/2023/Jill of all Trades.ash"; -import "relay/TourGuide/Items of the Month/2023/A Guide to Burning Leaves.ash"; -import "relay/TourGuide/Items of the Month/2023/Candy Cane Sword Cane.ash"; - -// 2024 -import "relay/TourGuide/Items of the Month/2024/Chest Mimic.ash"; -import "relay/TourGuide/Items of the Month/2024/Spring Shoes.ash"; -import "relay/TourGuide/Items of the Month/2024/Everfull Dart Holster.ash"; -import "relay/TourGuide/Items of the Month/2024/Apriling Band Helmet.ash"; -import "relay/TourGuide/Items of the Month/2024/Mayam Calendar.ash"; -import "relay/TourGuide/Items of the Month/2024/Roman Candelabra.ash"; -import "relay/TourGuide/Items of the Month/2024/Mini Kiwi.ash"; -import "relay/TourGuide/Items of the Month/2024/Tearaway Pants.ash"; -import "relay/TourGuide/Items of the Month/2024/Sept-Ember Censer.ash"; -import "relay/TourGuide/Items of the Month/2024/bat wings.ash"; -import "relay/TourGuide/Items of the Month/2024/VIP Photobooth.ash"; -import "relay/TourGuide/Items of the Month/2024/Peace Turkey.ash"; -import "relay/TourGuide/Items of the Month/2024/TakerSpace.ash"; - -// 2024 -import "relay/TourGuide/Items of the Month/2025/CyberRealm.ash"; -import "relay/TourGuide/Items of the Month/2025/McHugeLarge Ski Set.ash"; -import "relay/TourGuide/Items of the Month/2025/Leprecondo.ash"; -import "relay/TourGuide/Items of the Month/2025/April Shower Thoughts Calendar.ash"; -import "relay/TourGuide/Items of the Month/2025/Peridot.ash"; -import "relay/TourGuide/Items of the Month/2025/Prismatic Beret.ash"; -import "relay/TourGuide/Items of the Month/2025/Cooler Yeti.ash"; -import "relay/TourGuide/Items of the Month/2025/Allied Radio Backpack.ash"; -import "relay/TourGuide/Items of the Month/2025/Mobius Ring.ash"; \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/Misc/Gardens.ash b/Source/relay/TourGuide/Items of the Month/Misc/Gardens.ash deleted file mode 100644 index d797148f..00000000 --- a/Source/relay/TourGuide/Items of the Month/Misc/Gardens.ash +++ /dev/null @@ -1,110 +0,0 @@ -void generateGardenEntry(ChecklistEntry [int] resource_entries, boolean [item] garden_source_items, boolean [item] garden_creatable_items) -{ - ChecklistSubentry [int] subentries; - string image_name = ""; - foreach it in garden_source_items - { - if (it.available_amount() == 0) continue; - if (image_name.length() == 0) - image_name = "__item " + it; - subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", "")); - } - if (subentries.count() > 0) - { - ChecklistSubentry subentry = subentries[subentries.count() - 1]; //hacky - TagGroup tags; - tags.id = "Campground garden possible creations"; //differenciate by "kind of garden" ? - - - int [item] creatable_items = garden_creatable_items.creatable_items(); - string [int] output_list; - foreach it in creatable_items - { - int amount = creatable_items[it]; - - if (it.to_slot() != $slot[none] && it.available_amount() > 0) //already have one - continue; - output_list.listAppend(pluralise(amount, it)); - } - if (output_list.count() > 0) - { - subentry.entries.listAppend("Can create " + output_list.listJoinComponents(", ", "or") + "."); - } - resource_entries.listAppend(ChecklistEntryMake(image_name, "", subentries, 8)); - } -} - - -RegisterResourceGenerationFunction("IOTMGardensGenerateResource"); -void IOTMGardensGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["in run"] || !in_ronin()) - return; - - //Garden items: - if (true) - { - boolean [item] garden_creatable_items; - garden_creatable_items[$item[pumpkin juice]] = true; - if (__misc_state["can eat just about anything"]) - garden_creatable_items[$item[pumpkin pie]] = true; - if (__misc_state["can drink just about anything"]) - garden_creatable_items[$item[pumpkin beer]] = true; - if (__misc_state_string["yellow ray source"] == 4766.to_item().to_string()) - garden_creatable_items[4766.to_item()] = true; - - generateGardenEntry(resource_entries, $items[pumpkin], garden_creatable_items); - } - if (true) - { - boolean [item] garden_creatable_items; - if (__misc_state["can eat just about anything"]) - garden_creatable_items[$item[peppermint patty]] = true; - if (__misc_state["can drink just about anything"]) - garden_creatable_items[$item[peppermint twist]] = true; - if (__misc_state["free runs usable"]) - garden_creatable_items[$item[peppermint parasol]] = true; - garden_creatable_items[$item[peppermint crook]] = true; - generateGardenEntry(resource_entries, $items[peppermint sprout], garden_creatable_items); - } - if (true) - { - boolean [item] garden_creatable_items; - if (__misc_state["can eat just about anything"]) - garden_creatable_items[$item[skeleton quiche]] = true; - if (__misc_state["can drink just about anything"]) - garden_creatable_items[$item[crystal skeleton vodka]] = true; - if (!__misc_state["mysterious island available"]) - garden_creatable_items[$item[skeletal skiff]] = true; - if (hippy_stone_broken()) - garden_creatable_items[$item[auxiliary backbone]] = true; - generateGardenEntry(resource_entries, $items[skeleton], garden_creatable_items); - } - if (true) - { - generateGardenEntry(resource_entries, $items[handful of barley,cluster of hops,fancy beer bottle,fancy beer label], $items[can of Brütalbräu,can of Drooling Monk,can of Impetuous Scofflaw,bottle of old pugilist,bottle of professor beer,bottle of rapier witbier,artisanal homebrew gift package]); - } - if (true) - { - boolean [item] garden_creatable_items; - - foreach it in $items[snow cleats,snow crab,unfinished ice sculpture,snow mobile,ice bucket,bod-ice,snow belt,ice house,ice nine] - garden_creatable_items[it] = true; - - if (!__quest_state["Level 9"].state_boolean["bridge complete"]) - garden_creatable_items[$item[snow boards]] = true; - - if (!__quest_state["Level 4"].finished) - garden_creatable_items[$item[snow shovel]] = true; - - if (__misc_state["can eat just about anything"]) - garden_creatable_items[$item[snow crab]] = true; - if (__misc_state["can drink just about anything"]) - garden_creatable_items[$item[Ice Island Long Tea]] = true; - if (hippy_stone_broken()) - garden_creatable_items[$item[ice nine]] = true; - - - generateGardenEntry(resource_entries, $items[snow berries, ice harvest], garden_creatable_items); - } -} diff --git a/Source/relay/TourGuide/Items of the Month/Misc/Horsery.ash b/Source/relay/TourGuide/Items of the Month/Misc/Horsery.ash deleted file mode 100644 index 7813866e..00000000 --- a/Source/relay/TourGuide/Items of the Month/Misc/Horsery.ash +++ /dev/null @@ -1,10 +0,0 @@ -RegisterTaskGenerationFunction("IOTMHorseryGenerateTasks"); -void IOTMHorseryGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__iotms_usable[lookupItem("Horsery contract")]) return; - if (get_property("_horsery") == "" && my_meat() >= 500) - { - optional_task_entries.listAppend(ChecklistEntryMake("__item magical pony: Spectrum Dash", "place.php?whichplace=town_right&action=town_horsery", ChecklistSubentryMake("Bring along a horse!", "", "Probably the dark horse.")).ChecklistEntrySetIDTag("Horsery get a horse")); - - } -} diff --git a/Source/relay/TourGuide/Items of the Month/Misc/Libram.ash b/Source/relay/TourGuide/Items of the Month/Misc/Libram.ash deleted file mode 100644 index 882eba9c..00000000 --- a/Source/relay/TourGuide/Items of the Month/Misc/Libram.ash +++ /dev/null @@ -1,103 +0,0 @@ -RegisterResourceGenerationFunction("IOTMLibramGenerateResource"); -void IOTMLibramGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (__misc_state["bookshelf accessible"]) { - int libram_mp_cost = nextLibramSummonMPCost(); - - - string [int] librams_usable; - foreach s in __libram_skills { - if (s.skill_is_usable()) - librams_usable.listAppend(s.to_string()); - } - if (libram_mp_cost <= my_maxmp() && librams_usable.count() > 0) { - ChecklistSubentry subentry; - if (librams_usable.count() == 1) - subentry.header = "Libram"; - else - subentry.header = "Librams"; - subentry.header += " summonable"; - subentry.modifiers.listAppend(libram_mp_cost + "MP cost"); - - string [int] readable_list; - foreach key in librams_usable { - string libram_name = librams_usable[key]; - if (libram_name.stringHasPrefix("Summon ")) - libram_name = libram_name.substring(7); - readable_list.listAppend(libram_name); - } - - subentry.entries.listAppend(readable_list.listJoinComponents(", ", "and") + "."); - - if ($skill[summon taffy].skill_is_usable() && get_property_int("_taffyRareSummons") < 4) { - int rare_summons = get_property_int("_taffyRareSummons"); - subentry.entries.listAppend((4 - rare_summons) + " rare taffies still available."); - float chance = powf(0.5, MAX(0, rare_summons + 1)); - subentry.entries.listAppend("Could try to summon a yellow taffy. (" + (chance * 100.0).roundForOutput(1) + "% chance)"); - } - - resource_entries.listAppend(ChecklistEntryMake("__item libram of divine favors", "campground.php?action=bookshelf", subentry, 7).ChecklistEntrySetIDTag("Bookshelf librams resource")); - } - - - if ($skill[summon brickos].skill_is_usable() && __misc_state["in run"]) { - if (get_property_int("_brickoEyeSummons") <3) { - ChecklistSubentry subentry; - subentry.header = (3 - get_property_int("_brickoEyeSummons")) + " BRICKO™ eye bricks obtainable"; - subentry.entries.listAppend("Cast Summon BRICKOs libram. (" + libram_mp_cost + " mp)"); - resource_entries.listAppend(ChecklistEntryMake("__item bricko eye brick", "campground.php?action=bookshelf", subentry, 9).ChecklistEntrySetIDTag("Bookshelf BRICKO libram resource")); - - } - } - } - - if ((__misc_state["in run"] || true) && availableDrunkenness() >= 0) { - boolean [item] all_possible_bricko_fights = $items[bricko eye brick,bricko airship,bricko bat,bricko cathedral,bricko elephant,bricko gargantuchicken,bricko octopus,bricko ooze,bricko oyster,bricko python,bricko turtle,bricko vacuum cleaner]; - - int bricko_potential_fights_available = 0; - foreach it in $items[bricko eye brick,bricko airship,bricko bat,bricko cathedral,bricko elephant,bricko gargantuchicken,bricko octopus,bricko ooze,bricko oyster,bricko python,bricko turtle,bricko vacuum cleaner] { - bricko_potential_fights_available += it.available_amount(); - } - bricko_potential_fights_available = MIN(10 - get_property_int("_brickoFights"), bricko_potential_fights_available); - if (!in_ronin()) - bricko_potential_fights_available = clampi(10 - get_property_int("_brickoFights"), 0, 10); - if (bricko_potential_fights_available > 0) { - ChecklistSubentry subentry; - TagGroup tags; - tags.id = "BRICKO free fight"; - subentry.header = pluralise(bricko_potential_fights_available, "BRICKO™ fight", "BRICKO™ fights") + " ready"; - - - foreach fight in all_possible_bricko_fights { - int number_available = fight.available_amount(); - if (number_available > 0) { - string line = pluralise(number_available, fight); - - if ($items[rock band flyers,jam band flyers].available_amount() > 0 && !__quest_state["Level 12"].state_boolean["Arena Finished"] && __quest_state["Level 12"].in_progress && get_property_int("flyeredML") < 10000) { - monster m = fight.to_string().to_monster(); //is there a better way to look this up? - line += " (" + m.base_initiative + "% init)"; - } - subentry.entries.listAppend(line); - } - } - - item [int] craftable_fights; - string [int] creatable; - foreach fight in all_possible_bricko_fights { - monster m = fight.to_string().to_monster(); //is there a better way to look this up? - int bricks_needed = get_ingredients_fast(fight)[$item[bricko brick]]; - int monster_level = m.raw_attack; - int number_available = creatable_amount(fight); - if (number_available > 0) { - craftable_fights.listAppend(fight); - creatable.listAppend(pluralise(number_available, fight) + " (" + bricks_needed + " bricks, " + monster_level + "ML)"); - } - } - - if (creatable.count() > 0) - subentry.entries.listAppend("Creatable: (" + $item[bricko brick].available_amount() + " bricks available)" + HTMLGenerateIndentedText(creatable)); - - resource_entries.listAppend(ChecklistEntryMake("__item bricko brick", "inventory.php?ftext=bricko", subentry, tags, 7)); - } - } -} diff --git a/Source/relay/TourGuide/Items of the Month/Misc/Tomes.ash b/Source/relay/TourGuide/Items of the Month/Misc/Tomes.ash deleted file mode 100644 index 4364d598..00000000 --- a/Source/relay/TourGuide/Items of the Month/Misc/Tomes.ash +++ /dev/null @@ -1,244 +0,0 @@ -import "relay/TourGuide/Items of the Month/2013/Smithsness.ash"; -import "relay/TourGuide/Items of the Month/2009/Sugar.ash"; - -RegisterResourceGenerationFunction("IOTMTomesGenerateResource"); -void IOTMTomesGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (true) - { - ChecklistSubentry [int] subentries; - - int tome_count = 0; - - string [skill] tome_summons_property_names; - tome_summons_property_names[$skill[Summon Smithsness]] = "_smithsnessSummons"; - tome_summons_property_names[$skill[summon clip art]] = "_clipartSummons"; - tome_summons_property_names[$skill[Summon Sugar Sheets]] = "_sugarSummons"; - tome_summons_property_names[$skill[Summon Snowcones]] = "_snowconeSummons"; - tome_summons_property_names[$skill[Summon Stickers]] = "_stickerSummons"; - tome_summons_property_names[$skill[Summon Rad Libs]] = "_radlibSummons"; - - int [skill] summons_available; - foreach s in tome_summons_property_names - { - string property_name = tome_summons_property_names[s]; - int value = 0; - if (s.skill_is_usable()) - { - if (in_ronin()) - value = 3 - get_property_int("tomeSummons"); - else - value = 3 - get_property_int(property_name); - if (value > 0) - { - tome_count += 1; - } - } - summons_available[s] = value; - } - if (tome_count == 0) - return; - - if (in_ronin()) - { - int summons_remaining = 3 - get_property_int("tomeSummons"); - subentries.listAppend(ChecklistSubentryMake(pluralise(summons_remaining, "tome summon", "tome summons") + " remaining", "", "")); - } - - - if (summons_available[$skill[Summon Smithsness]] > 0) - { - string [int] description; - - string [int] flask_suggestions; - - string [int] smithereen_suggestions; - smithsnessGenerateSmithereensSuggestions(smithereen_suggestions); - - - string [int] coal_suggestions; - smithsnessGenerateCoalSuggestions(coal_suggestions); - - if (true) - { - int merry_smithsness_currently_available = $item[flaskfull of hollow].available_amount() * 150 + $effect[merry smithsness].have_effect(); - string building_line = "+25 smithsness (150 turns)"; - if (merry_smithsness_currently_available > 0) - building_line += " (" + merry_smithsness_currently_available + " turns currently available)"; - flask_suggestions.listAppend(building_line); - - } - - - if (__misc_state["in run"]) - { - description.listAppend("1 Flaskfull of Hollow" + HTMLGenerateIndentedText(flask_suggestions.listJoinComponents("
"))); - description.listAppend("1 Lump of Brituminous coal" + HTMLGenerateIndentedText(coal_suggestions.listJoinComponents("
"))); - description.listAppend("1 Handful of Smithereens" + HTMLGenerateIndentedText(smithereen_suggestions.listJoinComponents("
"))); - } - else - description.listAppend("Flaskfull of Hollow, Lump of Brituminous coal, and Handful of Smithereens"); - - - string name = "The Smith's Tome"; - if (!in_ronin()) - name = pluralise(summons_available[$skill[Summon Smithsness]], name + " summon", name + " summons"); - subentries.listAppend(ChecklistSubentryMake(name, "", description)); - - } - if (summons_available[$skill[summon clip art]] > 0) - { - string [int] description; - if (__misc_state["in run"]) - { - if ($item[shining halo].available_amount() == 0 && __misc_state["need to level"]) - description.listAppend("Shining halo: +3 stats/fight when unarmed"); - if ($item[frosty halo].available_amount() == 0 && $item[a light that never goes out].available_amount() == 0) - description.listAppend("Frosty halo: 25% items when unarmed"); - if ($item[furry halo].available_amount() == 0) - { - string line = "Furry halo: +5 familiar weight when unarmed"; - if (__misc_state["free runs available"]) - line += " (1 free run/day)"; - description.listAppend(line); - } - if ($item[time halo].available_amount() == 0 && my_daycount() <3 ) - description.listAppend("Time halo: +5 adventures/day"); - - if ($item[bucket of wine].available_amount() == 0 && __misc_state["can drink just about anything"]) - { - if ($skill[the ode to booze].skill_is_usable()) - description.listAppend("Bucket of wine: 28 adventures nightcap with ode"); - else if (!get_property_ascension("hiddenTavernUnlock") && $item[ye olde meade].available_amount() == 0) //just use fog murderers or meade instead, about the same - description.listAppend("Bucket of wine: 18 adventures nightcap"); - } - - if (__misc_state["can eat just about anything"] && __misc_state["need to level"]) - description.listAppend("Ultrafondue: 3 fullness awesome food, +15ML for 30 adventures"); - if (true) - { - string line = "Crystal skull: banish in high monster count zones"; - if ($skill[Summon Smithsness].skill_is_usable() && !__misc_state["in aftercore"]) - line += "|*Smith's Tome has a better one"; - description.listAppend(line); - } - if ($item[borrowed time].available_amount() == 0 && !get_property_boolean("_borrowedTimeUsed") && my_daycount() > 1) - description.listAppend("Borrowed time: 20 adventures on last day"); - - string [int] familiar_suggestions; - if (familiar_is_usable($familiar[he-boulder]) && $item[quadroculars].available_amount() == 0 && !lookupSkill("Disintegrate").have_skill()) - familiar_suggestions.listAppend("He-Boulder 100-turn YR"); - if (familiar_is_usable($familiar[obtuse angel]) && !familiar_is_usable($familiar[Reanimated Reanimator])) - familiar_suggestions.listAppend("+1 angel copy"); - - if (familiar_suggestions.count() > 0) - description.listAppend("Box of familiar jacks: free familiar equipment (" + listJoinComponents(familiar_suggestions, ", ") + ")"); - else - description.listAppend("Box of familiar jacks: free familiar equipment"); - } - - string name = "Tome of Clip Art"; - if (!in_ronin()) - name = pluralise(summons_available[$skill[Summon Clip Art]], name + " summon", name + " summons"); - subentries.listAppend(ChecklistSubentryMake(name, "", description)); - } - if (summons_available[$skill[Summon Sugar Sheets]] > 0) - { - string [int] description; - - SugarGenerateSuggestions(description); - - string name = "Tome of Sugar Shummoning"; - if (!in_ronin()) - name = pluralise(summons_available[$skill[Summon Sugar Sheets]], name + " summon", name + " summons"); - subentries.listAppend(ChecklistSubentryMake(name, "", description)); - } - if (summons_available[$skill[Summon Snowcones]] > 0) - { - string [int] description; - //FIXME check this - - string name = "Tome of Snowcone Summoning"; - if (!in_ronin()) - name = pluralise(summons_available[$skill[Summon Snowcones]], name + " summon", name + " summons"); - subentries.listAppend(ChecklistSubentryMake(name, "", description)); - } - if (summons_available[$skill[Summon Stickers]] > 0) - { - string [int] description; - //FIXME check this - - string name = "Scratch 'n' Sniff Sticker Tome"; - if (!in_ronin()) - name = pluralise(summons_available[$skill[Summon Stickers]], name + " summon", name + " summons"); - subentries.listAppend(ChecklistSubentryMake(name, "", description)); - } - if (summons_available[$skill[Summon Rad Libs]] > 0) - { - string [int] description; - - //FIXME check this - - string name = "Tome of Rad Libs"; - if (!in_ronin()) - name = pluralise(summons_available[$skill[Summon Rad Libs]], name + " summon", name + " summons"); - subentries.listAppend(ChecklistSubentryMake(name, "", description)); - } - - - ChecklistEntry entry = ChecklistEntryMake("__item tome of clip art", "campground.php?action=bookshelf", subentries); - entry.tags.id = "Tomes summons resource"; - if (in_ronin()) - entry.should_indent_after_first_subentry = true; - resource_entries.listAppend(entry); - } -} - -RegisterResourceGenerationFunction("ReplicaBookshelfGenerateResource"); -void ReplicaBookshelfGenerateResource(ChecklistEntry [int] resource_entries) -{ - // You need separate handling because replica tome/librams work differently. Instead of summon skills, you use - // the replica item and receive your daily guys. This relies on three boolean entries: - // _replicaSnowconeTomeUsed - // _replicaResolutionLibramUsed - // _replicaSmithsTomeUsed - - ChecklistSubentry [int] subentries; - string name; - string description; - string url; - - if (__iotms_usable[lookupItem("Tome of Snowcone Summoning")]) { - if (!get_property_boolean("_replicaSnowconeTomeUsed")) { - name = "Use your replica Tome of Snowcone Summoning"; - description = "SNOWCONES: Potential potions for +5 familiar weight, 50% meat, or 25% items."; - url = "inventory.php?ftext=snowcone+summoning"; - subentries.listAppend(ChecklistSubentryMake(name,"",description)); - } - } - - if (__iotms_usable[lookupItem("Libram of Resolutions")]) { - if (!get_property_boolean("_replicaResolutionLibramUsed")) { - name = "Use your replica Libram of Resolutions"; - description = "RESOLUTIONS: Potential potions for +5 familiar weight, 50% meat, or 25% items."; - url = "inventory.php?ftext=libram+of+resolutions"; - subentries.listAppend(ChecklistSubentryMake(name,"",description)); - } - } - - if (__iotms_usable[lookupItem("Smith's Tome")]) { - if (!get_property_boolean("_replicaSmithsTomeUsed")) { - name = "Use your replica Smith's Tome"; - description = "SMITH'S: 6x free-run banishes, with 3 equips as well"; - url = "inventory.php?ftext=smith's+tome"; - subentries.listAppend(ChecklistSubentryMake(name,"",description)); - } - } - - if (subentries.count() > 0) { - - ChecklistEntry entry = ChecklistEntryMake("__item smith's tome", url, subentries); - entry.tags.id = "Replica bookshelf resource"; - resource_entries.listAppend(entry); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/Time-Twitching Tower/Tea Tree.ash b/Source/relay/TourGuide/Items of the Month/Time-Twitching Tower/Tea Tree.ash deleted file mode 100644 index 4757eec3..00000000 --- a/Source/relay/TourGuide/Items of the Month/Time-Twitching Tower/Tea Tree.ash +++ /dev/null @@ -1,135 +0,0 @@ -static -{ - string [item] __tea_tree_teas; - void initialiseTeaTreeTeas() - { - __tea_tree_teas[$item[cuppa Activi tea]] = "adventures, stats"; - __tea_tree_teas[$item[cuppa Alacri tea]] = "+50% init"; - __tea_tree_teas[$item[cuppa Boo tea]] = "+30 spooky damage"; - __tea_tree_teas[$item[cuppa Chari tea]] = "+50% meat"; - __tea_tree_teas[$item[cuppa Craft tea]] = "crafting"; - __tea_tree_teas[$item[cuppa Cruel tea]] = "+5 fights for spleen"; - __tea_tree_teas[$item[cuppa Dexteri tea]] = "+50 moxie"; - __tea_tree_teas[$item[cuppa Feroci tea]] = "+50 muscle"; - __tea_tree_teas[$item[cuppa Flamibili tea]] = "+30 hot damage"; - __tea_tree_teas[$item[cuppa Flexibili tea]] = "+3 moxie stats/fight"; - __tea_tree_teas[$item[cuppa Frost tea]] = "+3 hot res"; - __tea_tree_teas[$item[cuppa Gill tea]] = "fishy"; - __tea_tree_teas[$item[cuppa Impregnabili tea]] = "30 DR"; - __tea_tree_teas[$item[cuppa Improprie tea]] = "+30 sleaze damage"; - __tea_tree_teas[$item[cuppa Insani tea]] = "+3 OCRS modifiers, teleporting(?)"; - __tea_tree_teas[$item[cuppa Irritabili tea]] = "+combat"; - __tea_tree_teas[$item[cuppa Loyal tea]] = "+5 familiar weight"; - __tea_tree_teas[$item[cuppa Mana tea]] = "+30 max MP, ~4 MP regen"; - __tea_tree_teas[$item[cuppa Mediocri tea]] = "+30 ML"; - __tea_tree_teas[$item[cuppa Monstrosi tea]] = "-30 ML"; - __tea_tree_teas[$item[cuppa Morbidi tea]] = "+3 spooky res"; - __tea_tree_teas[$item[cuppa Nas tea]] = "+30 stench damage"; - __tea_tree_teas[$item[cuppa Net tea]] = "+3 stench res"; - __tea_tree_teas[$item[cuppa Neuroplastici tea]] = "+3 myst stat/fight"; - __tea_tree_teas[$item[cuppa Obscuri tea]] = "-combat"; - __tea_tree_teas[$item[cuppa Physicali tea]] = "+3 muscle stats/fight"; - __tea_tree_teas[$item[cuppa Proprie tea]] = "+3 sleaze res"; - __tea_tree_teas[$item[cuppa Royal tea]] = "+1 royalty"; - __tea_tree_teas[$item[cuppa Serendipi Tea]] = "+25% item"; - __tea_tree_teas[$item[cuppa Sobrie tea]] = "-1 drunkenness"; - __tea_tree_teas[$item[cuppa Toast tea]] = "+3 cold res"; - __tea_tree_teas[$item[cuppa Twen tea]] = "+20 various stats"; - __tea_tree_teas[$item[cuppa Uncertain tea]] = "random effect"; - __tea_tree_teas[$item[cuppa Vitali tea]] = "+30 max HP, ~4 HP regen"; - __tea_tree_teas[$item[Cuppa Voraci tea]] = "+1 stomach capacity today"; - __tea_tree_teas[$item[cuppa Wit tea]] = "+50 myst"; - __tea_tree_teas[$item[cuppa Yet tea]] = "+30 cold damage"; - } - initialiseTeaTreeTeas(); -} - -RegisterResourceGenerationFunction("IOTMTeaTreeGenerateResource"); -void IOTMTeaTreeGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!get_property_boolean("_pottedTeaTreeUsed") && __iotms_usable[$item[potted tea tree]]) - { - string [int] options; - //+50% Combat Initiative? - - string [int][int] tea_options; - - - if (__misc_state["in run"]) - { - tea_options.listAppend(listMake("Irritabili", "+combat (30 turns)")); - tea_options.listAppend(listMake("Obscuri", "-combat (30 turns)")); - tea_options.listAppend(listMake("Serendipi", "+25% item (30 turns)")); - tea_options.listAppend(listMake("Chari", "+50% meat (30 turns)")); - tea_options.listAppend(listMake("Mediocri", "+30 ML")); - if (!__misc_state["familiars temporarily blocked"]) - tea_options.listAppend(listMake("Loyal", "+5 familiar weight")); - tea_options.listAppend(listMake("Craft", "Free crafts")); - if (hippy_stone_broken()) - tea_options.listAppend(listMake("Cruel", "+5 PVP fights, spleen")); - } - if (inebriety_limit() > 0) - tea_options.listAppend(listMake("Sobrie", "-1 drunkenness")); - if (fullness_limit() > 0) - tea_options.listAppend(listMake("Voraci", "+1 fullness capacity today")); - - if (!__misc_state["in run"]) - { - tea_options.listAppend(listMake("Royal", "Mall selling, royal leaderboarding")); - tea_options.listAppend(listMake("Gill", "Fishy (30 turns)")); - } - if (!__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && __quest_state["Level 13"].state_string["Elemental damage race type"] != "") - { - // - element type = __quest_state["Level 13"].state_string["Elemental damage race type"].to_element(); - item [element] element_tea_map; - element_tea_map[$element[sleaze]] = $item[cuppa Improprie Tea]; - element_tea_map[$element[spooky]] = $item[cuppa Boo tea]; - element_tea_map[$element[hot]] = $item[cuppa Flamibili tea]; - element_tea_map[$element[stench]] = $item[cuppa Nas tea]; - element_tea_map[$element[cold]] = $item[cuppa Yet tea]; - - item tea = element_tea_map[type]; - string type_class = "r_element_" + type + "_desaturated"; - if (tea != $item[none] && tea.available_amount() == 0) - tea_options.listAppend(listMake(tea.replace_string(" tea", "").replace_string("cuppa ", "").capitaliseFirstLetter(), HTMLGenerateSpanOfClass(__tea_tree_teas[tea], type_class) + " for lair race.")); - } - - if (tea_options.count() > 0) - options.listAppend(HTMLGenerateSimpleTableLines(tea_options)); - resource_entries.listAppend(ChecklistEntryMake("__item potted tea tree", "campground.php?action=teatree", ChecklistSubentryMake("Tea Tree Tea", "", options), 4).ChecklistEntrySetIDTag("Tea tree daily resource")); - } - - if (__misc_state["in run"] && in_ronin()) - { - string image_name = ""; - string url = ""; - string [int] teas_found; - string [int] reasons_found; - boolean one_tea_gives_effect = false; - foreach tea, treason in __tea_tree_teas - { - if (tea.available_amount() == 0) - continue; - string shortened_tea_name = tea.replace_string("cuppa ", "").replace_string(" tea", ""); - teas_found.listAppend(pluralise(tea.available_amount(), shortened_tea_name, shortened_tea_name)); - - reasons_found.listAppend(treason); - if (image_name == "") - image_name = "__item " + tea; - if (!one_tea_gives_effect && tea.to_effect() != $effect[none]) - one_tea_gives_effect = true; - if (tea.spleen > 0) - { - if (url == "") - url = "inventory.php?which=1"; - } - else - url = "inventory.php?which=3"; - } - if (teas_found.count() > 0) - { - resource_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(teas_found.listJoinComponents(", ", "and").capitaliseFirstLetter() + " tea", "", reasons_found.listJoinComponents(", ", "and").capitaliseFirstLetter() + (one_tea_gives_effect ? " (30 turns)" : "")), 8).ChecklistEntrySetIDTag("Tea tree cuppas resource")); - } - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Limit Mode/Batfellow State.ash b/Source/relay/TourGuide/Limit Mode/Batfellow State.ash deleted file mode 100644 index b9f62230..00000000 --- a/Source/relay/TourGuide/Limit Mode/Batfellow State.ash +++ /dev/null @@ -1,201 +0,0 @@ - - -/*zone values: -Bat-Cavern -Somewhere in Gotpork City -Center Park (Low Crime) -Slums (Moderate Crime) -Industrial District (High Crime) -Downtown -*/ -//Bat-Investigation Progress appears to be the amount of progress you advance per fight, which upgrades with upgrades. -Record BatState -{ - string zone; - int funds_available; - int time_left; - - string [string] stats; - boolean [string] upgrades; - /*int hp; - int max_hp; - int hp_regen;*/ - //FIXME more -}; - -BatState __batstate; - -BatState BatStateMake() -{ - BatState state; - //Parse: - state.zone = get_property("batmanZone"); - state.funds_available = get_property_int("batmanFundsAvailable"); - state.time_left = get_property_int("batmanTimeLeft"); - //FIXME upgrades - - foreach key, s in get_property("batmanStats").split_string_alternate(";") - { - string [int] attribution = s.split_string_alternate("="); - if (attribution.count() != 2) - continue; - state.stats[attribution[0]] = attribution[1]; - } - foreach key, s in get_property("batmanUpgrades").split_string_alternate(";") - state.upgrades[s] = true; - __batstate = state; - return state; -} - - -static -{ - location [monster] __batfellow_bosses_to_locations; - - void initialiseBatfellowBosses() - { - __batfellow_bosses_to_locations[$monster[Kudzu]] = $location[Gotpork Conservatory of Flowers]; - __batfellow_bosses_to_locations[$monster[Mansquito]] = $location[Gotpork Municipal Reservoir]; - __batfellow_bosses_to_locations[$monster[Miss Graves]] = $location[Gotpork Gardens Cemetery]; - - __batfellow_bosses_to_locations[$monster[The Plumber]] = $location[Gotpork City Sewers]; - __batfellow_bosses_to_locations[$monster[The Author]] = $location[Porkham Asylum]; - __batfellow_bosses_to_locations[$monster[The Mad Libber]] = $location[The Old Gotpork Library]; - - __batfellow_bosses_to_locations[$monster[Doc Clock]] = $location[Gotpork Clock, Inc.]; - __batfellow_bosses_to_locations[$monster[Mr. Burns]] = $location[Gotpork Foundry]; - __batfellow_bosses_to_locations[$monster[The Inquisitor]] = $location[Trivial Pursuits, LLC]; - } - initialiseBatfellowBosses(); - -} - - -Record BatfellowBossArea -{ - location area; - string short_name; - string image_name; - string zone; - monster boss; - string [int] strategies; - int [item] nc_twenty_five_progress_requirements; - int [item] nc_fifty_progress_requirements; - int [item] nc_reward_items; -}; - -BatfellowBossArea BatfellowBossAreaMake() -{ - BatfellowBossArea area; - return area; -} - -static -{ - BatfellowBossArea [location] __batfellow_bosses; - void initialiseBatfellowBossAreas() - { - BatfellowBossArea area = BatfellowBossAreaMake(); - area.area = $location[Gotpork Conservatory of Flowers]; - area.short_name = "Conservatory"; - area.image_name = "sunflower face"; - area.zone = "Center Park (Low Crime)"; - area.boss = $monster[Kudzu]; - area.nc_twenty_five_progress_requirements[$item[glob of Bat-Glue]] = 1; - area.nc_fifty_progress_requirements[$item[fingerprint dusting kit]] = 3; - area.nc_reward_items[$item[dangerous chemicals]] = 5; - __batfellow_bosses[area.area] = area; - - area = BatfellowBossAreaMake(); - area.area = $location[Gotpork Municipal Reservoir]; - area.short_name = "Reservoir"; - area.image_name = "__item personal raindrop"; //"__item ketchup hound"; - area.zone = "Center Park (Low Crime)"; - area.boss = $monster[Mansquito]; - area.nc_twenty_five_progress_requirements[$item[Bat-Aid™ bandage]] = 1; - area.nc_fifty_progress_requirements[$item[ultracoagulator]] = 3; - area.nc_reward_items[$item[kidnapped orphan]] = 5; - __batfellow_bosses[area.area] = area; - - area = BatfellowBossAreaMake(); - area.area = $location[Gotpork Gardens Cemetery]; - area.short_name = "Cemetery"; - area.image_name = "__item grave robbing shovel"; - area.zone = "Center Park (Low Crime)"; - area.boss = $monster[Miss Graves]; - area.nc_twenty_five_progress_requirements[$item[bat-bearing]] = 1; - area.nc_fifty_progress_requirements[$item[exploding kickball]] = 3; - area.nc_reward_items[$item[incriminating evidence]] = 5; - __batfellow_bosses[area.area] = area; - - - area = BatfellowBossAreaMake(); - area.area = $location[Porkham Asylum]; - area.short_name = "Asylum"; - area.image_name = "__item jet bennie marble"; - area.zone = "Slums (Moderate Crime)"; - area.boss = $monster[The Author]; - area.nc_twenty_five_progress_requirements[$item[bat-o-mite]] = 1; - area.nc_reward_items[$item[high-grade metal]] = 6; - __batfellow_bosses[area.area] = area; - - area = BatfellowBossAreaMake(); - area.area = $location[Gotpork City Sewers]; - area.short_name = "Sewers"; - area.image_name = "__item helmet turtle"; - area.zone = "Slums (Moderate Crime)"; - area.boss = $monster[The Plumber]; - area.nc_twenty_five_progress_requirements[$item[bat-oomerang]] = 1; - area.nc_reward_items[$item[high-grade explosives]] = 6; - __batfellow_bosses[area.area] = area; - - area = BatfellowBossAreaMake(); - area.area = $location[The Old Gotpork Library]; - area.short_name = "Library"; - area.image_name = "__item very overdue library book"; - area.zone = "Slums (Moderate Crime)"; - area.boss = $monster[The Mad Libber]; - area.nc_twenty_five_progress_requirements[$item[bat-jute]] = 1; - area.nc_reward_items[$item[high-tensile-strength fibers]] = 6; - __batfellow_bosses[area.area] = area; - - - area = BatfellowBossAreaMake(); - area.area = $location[Gotpork Clock, Inc.]; - area.short_name = "Clock"; - area.image_name = "__item borrowed time"; - area.zone = "Industrial District (High Crime)"; - area.boss = $monster[Doc Clock]; - area.nc_twenty_five_progress_requirements[$item[exploding kickball]] = 1; - area.nc_reward_items[$item[kidnapped orphan]] = 6; - area.nc_reward_items[$item[high-grade explosives]] = 6; - area.strategies.listAppend("Bat-oomerang the time bandits, to prevent them from stealing time?"); - area.strategies.listAppend("Gain resources from the NC?"); - __batfellow_bosses[area.area] = area; - - area = BatfellowBossAreaMake(); - area.area = $location[Gotpork Foundry]; - area.short_name = "Foundry"; - area.image_name = "__item handful of fire"; - area.zone = "Industrial District (High Crime)"; - area.boss = $monster[Mr. Burns]; - area.nc_twenty_five_progress_requirements[$item[ultracoagulator]] = 1; - area.nc_reward_items[$item[dangerous chemicals]] = 6; - area.nc_reward_items[$item[high-grade metal]] = 6; - area.strategies.listAppend("Gain resources from the NC?"); - __batfellow_bosses[area.area] = area; - - area = BatfellowBossAreaMake(); - area.area = $location[Trivial Pursuits, LLC]; - area.short_name = "Trivial Company"; - area.image_name = "__item Trivial Avocations Card: What?"; - area.zone = "Industrial District (High Crime)"; - area.boss = $monster[The Inquisitor]; - area.nc_twenty_five_progress_requirements[$item[fingerprint dusting kit]] = 1; - area.nc_reward_items[$item[incriminating evidence]] = 6; - area.nc_reward_items[$item[high-tensile-strength fibers]] = 6; - area.strategies.listAppend("Gain resources from the NC?"); - __batfellow_bosses[area.area] = area; - } - initialiseBatfellowBossAreas(); -} diff --git a/Source/relay/TourGuide/Limit Mode/Batfellow.ash b/Source/relay/TourGuide/Limit Mode/Batfellow.ash deleted file mode 100644 index c5ea9b8a..00000000 --- a/Source/relay/TourGuide/Limit Mode/Batfellow.ash +++ /dev/null @@ -1,405 +0,0 @@ - -import "relay/TourGuide/Limit Mode/Batfellow State.ash"; - - -void LimitModeBatfellowGenerateResources(ChecklistEntry [int] resource_entries, BatState state) -{ - if (__setting_debug_mode) - { - string [int] description; - foreach s in $strings[batmanBonusInitialFunds,batmanFundsAvailable,batmanStats,batmanTimeLeft,batmanUpgrades,batmanZone] - { - description.listAppend(s + " = " + get_property(s)); - } - description.listAppend("Dwayne Manor"); - resource_entries.listAppend(ChecklistEntryMake("__item batarang", "", ChecklistSubentryMake("Bat-Properties", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode debug properties")); - - resource_entries.listAppend(ChecklistEntryMake("__item batarang", "", ChecklistSubentryMake("Bat-State", "", state.to_json()), 8).ChecklistEntrySetIDTag("Batfellow mode debug state")); - } - - string [item] item_descriptions; - item_descriptions[$item[bat-oomerang]] = "Deals 20 damage, disarms foes, speeds up sewers."; - item_descriptions[$item[bat-jute]] = "Against a monster with ten or less HP, defeats foe and increases progress that fight.|Speeds up the library."; - item_descriptions[$item[bat-o-mite]] = "Instakill, speeds up asylum."; - - item_descriptions[$item[incriminating evidence]] = "Trade for armour upgrades and progress increasers.";//, which also help with the trivia company and the conservatory."; - item_descriptions[$item[dangerous chemicals]] = "Trade for health upgrades and HP restorers.";//, which also help with the foundry and the reservoir."; - item_descriptions[$item[kidnapped orphan]] = "Trade for attack upgrades and free instakills.";//, which also help with the clock factory and cemetary."; - - - item_descriptions[$item[high-grade metal]] = "make bat-oomeranges (damages)"; - item_descriptions[$item[high-tensile-strength fibers]] = "makes bat-jutes (damages)"; - item_descriptions[$item[high-grade explosives]] = "makes bat-o-mites (kills?)"; - - item_descriptions[$item[experimental gene therapy]] = ""; - item_descriptions[$item[ultracoagulator]] = "restores all HP, speeds up foundry and reservoir"; - item_descriptions[$item[self-defense training]] = ""; - item_descriptions[$item[fingerprint dusting kit]] = "4% progress/fight, speeds up trivia company and conservatory"; - item_descriptions[$item[confidence-building hug]] = ""; - item_descriptions[$item[exploding kickball]] = "skips monster to advance the NC, speeds up clock factory and cemetary"; - item_descriptions[$item[glob of Bat-Glue]] = "stuns for multiple rounds, speeds up conservatory"; - item_descriptions[$item[Bat-Aid™ bandage]] = "restores 20 HP, speeds up reservoir"; - item_descriptions[$item[bat-bearing]] = "stuns foes, deals 15 damage, speeds up cemetary"; - - item [int][int] item_groupings; - item_groupings.listAppend(listMake($item[bat-oomerang], $item[bat-jute], $item[bat-o-mite])); - item_groupings.listAppend(listMake($item[incriminating evidence], $item[dangerous chemicals], $item[kidnapped orphan])); - item_groupings.listAppend(listMake($item[high-grade metal], $item[high-tensile-strength fibers], $item[high-grade explosives])); - - foreach it in item_descriptions - item_groupings.listAppend(listMake(it)); - - /*foreach it in $items[] - { - if (it.available_amount() > 0) - item_groupings.listAppend(listMake(it)); - }*/ - boolean [item] seen_items; - foreach key in item_groupings - { - ChecklistEntry entry; - entry.tags.id = "Batfellow mode item grouping " + key; - foreach key2, it in item_groupings[key] - { - if (seen_items[it]) - continue; - if (it.available_amount() > 0) - { - seen_items[it] = true; - string description = item_descriptions[it]; - if (item_descriptions contains it && description == "") //deliberately ignore, for the three upgrade items - continue; - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", description)); - if (entry.image_lookup_name == "") - entry.image_lookup_name = "__item " + it; - //resource_entries.listAppend(ChecklistEntryMake("__item " + it, "", ChecklistSubentryMake(pluralise(it), "", description), 8)); - } - } - if (entry.subentries.count() > 0) - resource_entries.listAppend(entry); - } -} - - -void LimitModeBatfellowGeneralGenerateTasks(ChecklistEntry [int] task_entries, BatState state) -{ - if (true) - { - string [int] description; - if (state.zone != "Downtown") - { - if (my_hp() == 0) - description.listAppend("Go downtown, visit the hospital?"); - } - else if (my_hp() != my_maxhp()) - description.listAppend("Visit the hospital?"); - if (description.count() > 0) - task_entries.listAppend(ChecklistEntryMake("__item bubblegum heart", "main.php", ChecklistSubentryMake("Heal", "", description), -11).ChecklistEntrySetIDTag("Batfellow mode heal")); - } -} - -void LimitModeBatfellowBossesGenerateTasks(ChecklistEntry [int] task_entries, BatState state) -{ - foreach l, area in __batfellow_bosses - { - if (area.zone != state.zone) - continue; - - int area_progress = -1; - int progress_remaining = clampi(100 - area_progress, 0, 100); - - - string [int] description; - if (progress_remaining > 0) - { - if (area_progress == -1) - description.listAppend("?% progress remaining."); - else - description.listAppend(progress_remaining + "% progress remaining."); - - if (progress_remaining > 10) - { - //description.listAppend("area = " + area.to_json()); - boolean has_fifty_progress = false; - boolean meets_fifty_progress = false; - if (area.nc_fifty_progress_requirements.count() > 0) - { - has_fifty_progress = true; - meets_fifty_progress = true; - foreach it, amount in area.nc_fifty_progress_requirements - { - if (it.available_amount() < amount) - { - meets_fifty_progress = false; - int remaining = MAX(0, amount - it.available_amount()); - description.listAppend("Avoid until you have " + remaining.int_to_wordy() + " more " + (remaining > 1 ? it.plural : it) + ".|(50% progress in NC)"); - } - } - } - if (area.nc_twenty_five_progress_requirements.count() > 0 && !(has_fifty_progress && meets_fifty_progress)) - { - foreach it, amount in area.nc_twenty_five_progress_requirements - { - if (it.available_amount() < amount) - { - int remaining = MAX(0, amount - it.available_amount()); - string line = "Avoid until you have "; - if (has_fifty_progress && !meets_fifty_progress) - line = "Or until you have "; - line += remaining.int_to_wordy() + " more " + (remaining > 1 ? it.plural : it) + ".|(25% progress in NC)"; - description.listAppend(line); - } - } - } - if (area.strategies.count() > 0) - description.listAppend(area.strategies.listJoinComponents("|")); - if (area.nc_reward_items.count() > 0) - { - string [int] rewards; - foreach it, amount in area.nc_reward_items - { - rewards.listAppend(pluralise(amount, it)); - } - description.listAppend("NC reward option gives " + rewards.listJoinComponents(", ", "and") + "."); - } - } - task_entries.listAppend(ChecklistEntryMake(area.image_name, "main.php", ChecklistSubentryMake("Fight in the " + area.short_name, "", description), 8).ChecklistEntrySetIDTag("Batfellow mode progress " + area.short_name)); - } - else - { - task_entries.listAppend(ChecklistEntryMake("__monster " + area.boss, "main.php", ChecklistSubentryMake("Defeat " + area.boss, "", ""), 8).ChecklistEntrySetIDTag("Batfellow mode fight " + area.boss)); - } - } -} - -void LimitModeBatfellowJokesterGenerateTasks(ChecklistEntry [int] task_entries, BatState state) -{ - return; -} - -void LimitModeBatfellowBatCavernGenerateTaskResources(ChecklistEntry [int] task_entries, ChecklistEntry [int] resource_entries, BatState state) -{ - boolean found_tasks = false; - if (state.funds_available > 0) - { - string [string][string] suggested_upgrades; - suggested_upgrades["Suit"] = mapMake(); - suggested_upgrades["Sedan"] = mapMake(); - suggested_upgrades["Cavern"] = mapMake(); - //orphans,evidence,chemicals bat-sedan - //lower combat time - //two that decrease searching - //glue, bearings, bat-aids after every third combat - //orphan/chemical upgrades, but not evidence upgrades? - suggested_upgrades["Suit"]["Improved Cowl Optics"] = "find things?"; - suggested_upgrades["Suit"]["Utility Belt First Aid Kit"] = "bandages every third combat"; - suggested_upgrades["Suit"]["Extra-Swishy Cloak"] = "prevents first hit in combat"; - suggested_upgrades["Suit"]["Hardened Knuckles"] = "double punch damage"; - suggested_upgrades["Suit"]["Steel-Toed Bat-Boots"] = "double kick damage"; - - suggested_upgrades["Sedan"]["Rocket Booster"] = "faster travel time"; - suggested_upgrades["Sedan"]["Street Sweeper"] = "gather evidence while driving"; - suggested_upgrades["Sedan"]["Advanced Air Filter"] = "gather dangerous chemicals while driving"; - suggested_upgrades["Sedan"]["Orphan Scoop"] = "gather orphans while driving"; - suggested_upgrades["Sedan"]["Spotlight"] = "faster progress"; - suggested_upgrades["Sedan"]["Loose Bearings"] = "bearings every third combat"; - - - suggested_upgrades["Cavern"]["Surveillance Network"] = "faster progress"; - suggested_upgrades["Cavern"]["Glue Factory"] = "glue every third combat"; - suggested_upgrades["Cavern"]["Improved 3-D Bat-Printer"] = "cheaper bat-materials"; - suggested_upgrades["Cavern"]["Really Long Winch"] = "instant travel back home"; - suggested_upgrades["Cavern"]["Blueprints Database"] = "faster progress?"; - suggested_upgrades["Cavern"]["Transfusion Satellite"] = "restores 5 hp/fight"; - - - string [int] description; - foreach type in $strings[Suit,Sedan,Cavern] - { - string [int] type_upgrades; - foreach upgrade_name, upgrade_decription in suggested_upgrades[type] - { - if (state.upgrades contains upgrade_name) - continue; - type_upgrades.listAppend(HTMLGenerateSpanOfClass(upgrade_name, "r_bold") + ": " + upgrade_decription); - } - if (type_upgrades.count() == 0) continue; - description.listAppend(HTMLGenerateSpanOfClass(type, "r_bold") + ":|*" + type_upgrades.listJoinComponents("|*")); - } - string url; - if (state.zone == "Bat-Cavern") - url = "place.php?whichplace=batman_cave&action=batman_cave_rnd"; - else - description.listAppend("Travel to the Bat-Cavern first."); - ChecklistEntry entry = ChecklistEntryMake("__item fat stacks of cash", url, ChecklistSubentryMake(pluralise(state.funds_available, "Bat-Research", "Bat-Researches"), "", description), 8); - entry.tags.id = "Batfellow mode bat-research"; - if (state.zone != "Bat-Cavern") - resource_entries.listAppend(entry); - else - { - task_entries.listAppend(entry); - found_tasks = true; - } - } - if (state.zone == "Bat-Cavern" && $items[high-grade metal,high-tensile-strength fibers,high-grade explosives].available_amount() > 0) - { - item [item] fabricator_conversions; - fabricator_conversions[$item[high-grade metal]] = $item[bat-oomerang]; - fabricator_conversions[$item[high-tensile-strength fibers]] = $item[bat-jute]; - fabricator_conversions[$item[high-grade explosives]] = $item[bat-o-mite]; - int cost_per_conversion = 3; - if (state.upgrades["Improved 3-D Bat-Printer"]) - cost_per_conversion = 2; - string [int] craftables; - foreach source, destination in fabricator_conversions - { - int amount_craftable = source.available_amount() / cost_per_conversion; - if (amount_craftable > 0) - { - craftables.listAppend(pluralise(amount_craftable, destination)); - } - } - - string [int] description; - if (craftables.count() > 0) - description.listAppend("Can make " + craftables.listJoinComponents(", ", "and") + "."); - if (description.count() > 0) - { - task_entries.listAppend(ChecklistEntryMake("__item high-grade explosives", "shop.php?whichshop=batman_cave", ChecklistSubentryMake("Bat-Fabricate", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode bat-fabricate")); - found_tasks = true; - } - } - if (!found_tasks && state.zone == "Bat-Cavern") - { - string [int] description; - task_entries.listAppend(ChecklistEntryMake("__item bitchin' meatcar", "place.php?whichplace=batman_cave&action=batman_cave_car", ChecklistSubentryMake("Travel somewhere", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode leave cavern")); - } -} -void LimitModeBatfellowDowntownGenerateTasks(ChecklistEntry [int] task_entries, BatState state) -{ - if (state.zone != "Downtown") - return; - item evidence = $item[incriminating evidence]; - item chemicals = $item[dangerous chemicals]; - item orphans = $item[kidnapped orphan]; - boolean found_tasks = false; - if (orphans.available_amount() > 0) - { - string [int] description; - string [int] options; - int hug_price = 3 + 3 * $item[confidence-building hug].available_amount(); - if (hug_price <= orphans.available_amount()) - options.listAppend("+1 damage upgrades"); - options.listAppend("freekill kickballs"); - description.listAppend(options.listJoinComponents(" / ").capitaliseFirstLetter() + "."); - task_entries.listAppend(ChecklistEntryMake("__item kidnapped orphan", "shop.php?whichshop=batman_orphanage", ChecklistSubentryMake("Turn in orphans", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode orphans")); - found_tasks = true; - } - if (chemicals.available_amount() > 0) - { - string [int] description; - string [int] options; - int hug_price = 3 + 3 * $item[experimental gene therapy].available_amount(); - if (hug_price <= chemicals.available_amount()) - options.listAppend("+10 HP upgrades"); - options.listAppend("HP-restoring ultracoagulators"); - description.listAppend(options.listJoinComponents(" / ").capitaliseFirstLetter() + "."); - task_entries.listAppend(ChecklistEntryMake("__item " + chemicals, "shop.php?whichshop=batman_chemicorp", ChecklistSubentryMake("Turn in chemicals", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode chemicals")); - found_tasks = true; - } - if (evidence.available_amount() > 0) - { - string [int] description; - string [int] options; - int hug_price = 3 + 3 * $item[self-defense training].available_amount(); - if (hug_price <= evidence.available_amount()) - options.listAppend("+armour upgrades"); - options.listAppend("progress-increasing fingerprint dusting kits"); - description.listAppend(options.listJoinComponents(" / ").capitaliseFirstLetter() + "."); - task_entries.listAppend(ChecklistEntryMake("__item " + evidence, "shop.php?whichshop=batman_pd", ChecklistSubentryMake("Turn in evidence", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode evidence")); - found_tasks = true; - } - if (!found_tasks && my_hp() == my_maxhp()) - { - string [int] description; - task_entries.listAppend(ChecklistEntryMake("__item bitchin' meatcar", "place.php?whichplace=batman_downtown&action=batman_downtown_car", ChecklistSubentryMake("Travel somewhere", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode leave downtown")); - } -} - -void LimitModeBatfellowGenerateChecklists(Checklist [int] checklists) -{ - if (limit_mode() != "batman") - return; - - ChecklistEntry [int] task_entries; - ChecklistEntry [int] optional_task_entries; - ChecklistEntry [int] future_task_entries; - ChecklistEntry [int] resource_entries; - - if (true) - { - Checklist task_checklist; - task_checklist = ChecklistMake("Bat-Tasks", task_entries); - checklists.listAppend(task_checklist); - - - Checklist optional_task_checklist; - optional_task_checklist = ChecklistMake("Optional Bat-Tasks", optional_task_entries); - checklists.listAppend(optional_task_checklist); - - Checklist future_task_checklist; - future_task_checklist = ChecklistMake("Future Bat-Tasks", future_task_entries); - checklists.listAppend(future_task_checklist); - - Checklist resources_checklist; - resources_checklist = ChecklistMake("Bat-Resources", resource_entries); - checklists.listAppend(resources_checklist); - } - - BatState bat_state = BatStateMake(); - - - //task_entries.listAppend(ChecklistEntryMake("__item batarang", "", ChecklistSubentryMake("Stop the Jokester", "", "Better living through violence?"), 8)); - - LimitModeBatfellowGenerateResources(resource_entries, bat_state); - LimitModeBatfellowGeneralGenerateTasks(task_entries, bat_state); - - LimitModeBatfellowBossesGenerateTasks(task_entries, bat_state); - - LimitModeBatfellowJokesterGenerateTasks(task_entries, bat_state); - - LimitModeBatfellowBatCavernGenerateTaskResources(task_entries, resource_entries, bat_state); - LimitModeBatfellowDowntownGenerateTasks(task_entries, bat_state); -} - -RegisterResourceGenerationFunction("BatfellowGenerateResource"); -void BatfellowGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[replica bat-oomerang].available_amount() > 0 && mafiaIsPastRevision(16927)) - { - int remaining = clampi(3 - get_property_int("_usedReplicaBatoomerang"), 0, 3); - if (remaining > 0) - resource_entries.listAppend(ChecklistEntryMake("__item replica bat-oomerang", "", ChecklistSubentryMake(pluralise(remaining, "replica bat-oomerang use", "replica bat-oomerang uses"), "", "Free instakill."), 5).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Batfellow bat-oomerang free kill i'm jealous")); - } - if ($item[The Jokester's Gun].available_amount() > 0 && mafiaIsPastRevision(16986) && !get_property_boolean("_firedJokestersGun")) - { - int importance = 0; - string [int] description; - description.listAppend("Free instakill."); - if ($item[The Jokester's Gun].equipped_amount() == 0) - { - string line = "Equip it"; - if (!$item[The Jokester's Gun].can_equip()) - { - line += ", once you can. (need 50 moxie)"; - importance = 8; - } - else - line += " first."; - description.listAppend(line); - } - else - description.listAppend("Fire the Jokester's Gun skill in combat."); - resource_entries.listAppend(ChecklistEntryMake("__item The Jokester's Gun", "", ChecklistSubentryMake("The Jokester's Gun firing", "", description), importance).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Batfellow jokester gun free kill")); - } -} diff --git a/Source/relay/TourGuide/Limit Mode/Spelunking.ash b/Source/relay/TourGuide/Limit Mode/Spelunking.ash deleted file mode 100644 index 1bf10734..00000000 --- a/Source/relay/TourGuide/Limit Mode/Spelunking.ash +++ /dev/null @@ -1,1013 +0,0 @@ -/* -Random notes: --Having both a torch and mining helmet equipped will drop items from both, but not sure if at the same time. - -Relevant URLs: -http://forums.kingdomofloathing.com/vb/showthread.php?p=4721915#post4721915 -http://forums.kingdomofloathing.com/vb/showthread.php?p=4713383#post4713383 -http://forums.kingdomofloathing.com/vb/showthread.php?p=4717434#post4717434 -http://forums.kingdomofloathing.com/vb/showthread.php?p=4730373#post4730373 -http://forums.kingdomofloathing.com/vb/showpost.php?p=4749602&postcount=19 -*/ - -//should we record spelunkyUpgrades here? may not use them -Record SpelunkingStatus -{ - boolean [location] areas_unlocked; - boolean altar_unlocked; - boolean noncombat_due_next_adventure; - boolean sticky_bombs_unlocked; - int turns_left; - int gold; - int bombs; - int ropes; - int keys; - int sacrifices; - string buddy; -}; - -location SpelunkingLookupLocationStatusName(string entry) -{ - if (entry == "Burial Ground") - return $location[The Ancient Burial Ground]; - if (entry == "LOLmec's Lair") - return $location[LOLmec's Lair]; - if (entry == "Hell") - return $location[Hell]; - if (entry == "Yomama's Throne") - return $location[Yomama's Throne]; - return ("The " + entry).to_location(); -} - -SpelunkingStatus SpelunkingParseStatus() -{ - //spelunkyStatus(user, now 'Turns: 3, Gold: 150, Bombs: 2, Ropes: 0, Keys: 0, Buddy: A Helpful Guy, Unlocks: , Jungle, Burial Ground, Spider Hole, Sticky Bombs', default ) - //spelunkyStatus(user, now 'Turns: 10, Gold: 209, Bombs: 6, Ropes: 3, Keys: 0, Buddy: , Unlocks: Jungle, Ice Caves, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit', default ) - SpelunkingStatus spelunking_status; - spelunking_status.areas_unlocked[$location[The Mines]] = true; - - boolean past_unlocks = false; - string [int] status_split = get_property("spelunkyStatus").split_string(", "); - - spelunking_status.sacrifices = get_property_int("spelunkySacrifices"); - foreach key, entry in status_split - { - if (entry == "Non-combat Due") - { - spelunking_status.noncombat_due_next_adventure = true; - continue; - } - if (entry.stringHasPrefix("Unlocks:")) - { - past_unlocks = true; - entry = entry.replace_string("Unlocks: ", ""); - } - if (past_unlocks) - { - if (entry == "Sticky Bombs") //this is treated as an "Unlocks" - spelunking_status.sticky_bombs_unlocked = true; - else if (entry == "Altar") - spelunking_status.altar_unlocked = true; - else - { - location l = SpelunkingLookupLocationStatusName(entry); - if (l != $location[none]) - spelunking_status.areas_unlocked[l] = true; - } - } - - if (entry.contains_text(": ")) - { - string [int] split_entry = entry.split_string(": "); //hopefully, there isn't one that has a : inside of it... FIXME - if (split_entry.count() < 2) - continue; - string header = split_entry[0]; - if (header == "Turns") - spelunking_status.turns_left = split_entry[1].to_int_silent(); - else if (header == "Gold") - spelunking_status.gold = split_entry[1].to_int_silent(); - else if (header == "Bombs") - spelunking_status.bombs = split_entry[1].to_int_silent(); - else if (header == "Ropes") - spelunking_status.ropes = split_entry[1].to_int_silent(); - else if (header == "Keys") - spelunking_status.keys = split_entry[1].to_int_silent(); - else if (header == "Buddy") - spelunking_status.buddy = split_entry[1].replace_string("A ", ""); - else - { - if (__setting_debug_mode) - { - print_html("Unknown entry type \"" + entry + "\""); - } - } - } - } - return spelunking_status; -} - -void SpelunkingGenerateNCInformation(SpelunkingStatus spelunking_status, ChecklistEntry [int] task_entries, ChecklistEntry [int] future_task_entries) -{ - - ChecklistEntry entry; - entry.image_lookup_name = "__item sunken chest"; - entry.tags.id = "Spelunky mode general NC info"; - entry.should_indent_after_first_subentry = true; - - string first_entry_title = ""; - boolean very_important = false; - if (spelunking_status.noncombat_due_next_adventure) - { - very_important = true; - first_entry_title = "Non-combat next adventure"; - entry.url = "place.php?whichplace=spelunky"; - } - else - { - int turns_left = clampi(3 - get_property_int("spelunkyWinCount"), 0, 3); - first_entry_title = "Non-combat after " + pluraliseWordy(turns_left, "combat", "combats"); - } - int phase = get_property_int("spelunkyNextNoncombat"); - entry.subentries.listAppend(ChecklistSubentryMake(first_entry_title, "", "Next phase is " + phase.int_to_wordy() + ".")); - - - location [int] shopping_areas; - location [int] crate_areas; - location [int] tombstone_areas; - - location [int] evaluation_order; - evaluation_order.listAppend($location[The Snake Pit]); - evaluation_order.listAppend($location[The Mines]); - evaluation_order.listAppend($location[The Spider Hole]); - evaluation_order.listAppend($location[The Ancient Burial Ground]); - evaluation_order.listAppend($location[The Jungle]); - evaluation_order.listAppend($location[The Beehive]); - evaluation_order.listAppend($location[the crashed u. f. o.]); - evaluation_order.listAppend($location[The Ice Caves]); - evaluation_order.listAppend($location[The City of Goooold]); - evaluation_order.listAppend($location[The Temple Ruins]); - - //FIXME Some of these gold listings are inaccurate, I think. - foreach key, l in evaluation_order - { - if (!spelunking_status.areas_unlocked[l]) - continue; - string [int] description; - if (l == $location[the mines]) - { - if (phase == 1) - { - description.listAppend("20 gold."); - if ($item[pot].available_amount() == 0) - description.listAppend("A pot. (deals 20 damage, gives 10 gold once when thrown)"); - } - else if (phase == 2) - { - shopping_areas.listAppend(l); - continue; - } - else if (phase == 3) - { - // - if (!spelunking_status.areas_unlocked[$location[the snake pit]] && spelunking_status.bombs > 0 && !spelunking_status.areas_unlocked[$location[the spider hole]]) - { - description.listAppend("Unlock the Snake Pit, at the cost of a bomb.|Blocks out the Spider Hole."); - } - if (!spelunking_status.areas_unlocked[$location[the spider hole]] && spelunking_status.bombs > 0 && !spelunking_status.areas_unlocked[$location[the snake pit]]) - { - description.listAppend("Unlock the Spider Hole, at the cost of a rope.|Leads to sticky bombs. Blocks out the Snake Pit."); - } - - string [int] damage_avoidance; - if ($item[trusty whip].available_amount() > 0) - { - string line = "take 0 or 5 damage"; - if ($item[trusty whip].equipped_amount() == 0) - line += " (equip whip first)"; - damage_avoidance.listAppend(line); - } - if ($slot[off-hand].equipped_item() != $item[none]) - damage_avoidance.listAppend("sacrifice an off-hand"); - - if (damage_avoidance.count() == 0) - damage_avoidance.listAppend("take 10 damage"); - description.listAppend(damage_avoidance.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); - } - } - else if (l == $location[the jungle]) - { - if (phase == 1) - { - shopping_areas.listAppend(l); - continue; - } - else if (phase == 2) - { - tombstone_areas.listAppend(l); - continue; - } - else if (phase == 3) - { - if (!spelunking_status.areas_unlocked[$location[The Beehive]] && spelunking_status.bombs > 0 && !spelunking_status.areas_unlocked[$location[The Ancient Burial Ground]]) - { - string line = "Unlock the Beehive, at the cost of a bomb"; - if (!spelunking_status.sticky_bombs_unlocked) - line += " and 15 damage"; - - line += ".|Blocks out the Ancient Burial Ground."; - description.listAppend(line); - } - if (!spelunking_status.areas_unlocked[$location[The Ancient Burial Ground]] && spelunking_status.ropes > 0 && !spelunking_status.areas_unlocked[$location[The Beehive]]) - { - string line = "Unlock the Ancient Burial Ground, at the cost of a rope"; - if ($item[yellow cape].available_amount() == 0 && $item[jetpack].available_amount() == 0) - line += " and 15 damage"; - line += "."; - - if ($item[yellow cape].equipped_amount() == 0 && $item[jetpack].equipped_amount() == 0) - { - if ($item[jetpack].available_amount() > 0) - line += " (equip jetpack first)"; - else if ($item[yellow cape].available_amount() > 0) - line += " (equip yellow cape first)"; - } - line += "|Useful for a different-phase Clown Crown. Blocks out the Beehive."; - description.listAppend(line); - } - - if ($item[spring boots].available_amount() > 0) - { - string line = "Nothing."; - if ($item[spring boots].equipped_amount() == 0) - line += " (equip spring boots first)"; - description.listAppend(line); - } - else - description.listAppend("Take 30 damage."); - } - } - else if (l == $location[The Ice Caves]) - { - if (phase == 1) - { - shopping_areas.listAppend(l); - continue; - } - else if (phase == 2) - { - string line = "+50-60 gold"; - if ($item[cursed coffee cup].available_amount() > 0) - { - line += ", restore 30 HP."; - if ($item[cursed coffee cup].equipped_amount() == 0) - line += " (equip cursed coffee cup first)"; - } - else - line += "."; - description.listAppend(line); - - if ($item[torch].available_amount() > 0) - { - line = ""; - if (spelunking_status.buddy.length() == 0) - line = "Gain a spelunking buddy."; - else - line = "Gain 60-70 gold."; - - if ($item[torch].equipped_amount() == 0) - line += " (equip a torch first)"; - description.listAppend(line); - } - } - else if (phase == 3) - { - if (!spelunking_status.altar_unlocked) - { - description.listAppend("Unlock the Altar, take 10 damage.|Blocks out U.F.O."); - } - if (!spelunking_status.areas_unlocked[$location[The Crashed U. F. O.]] && spelunking_status.ropes >= 3 && !spelunking_status.altar_unlocked) - description.listAppend("Unlock the Crashed U. F. O., at the cost of three ropes.|Blocks out altar."); - description.listAppend("Take 30 damage."); - } - } - else if (l == $location[The Temple Ruins]) - { - if (phase == 1) - { - crate_areas.listAppend(l); - continue; - } - else if (phase == 2) - { - if (spelunking_status.buddy == "Resourceful Kid") - { - description.listAppend("+250 gold."); - } - else if ($item[jetpack].available_amount() > 0) - { - string line = "+250 gold."; - if ($item[jetpack].equipped_amount() == 0 && !($item[spring boots].equipped_amount() > 0 && $item[yellow cape].equipped_amount() > 0)) - line += " (equip jetpack first)"; - description.listAppend(line); - } - else if ($items[spring boots,yellow cape].items_missing().count() == 0) - { - string line = "+250 gold."; - string [int] items_to_equip; - foreach it in $items[spring boots,yellow cape] - { - if (it.equipped_amount() == 0) - items_to_equip.listAppend(it); - } - if (items_to_equip.count() > 0) - line += " (equip " + items_to_equip.listJoinComponents(", ", "and") + " first)"; - description.listAppend(line); - - } - else - { - description.listAppend("+250 gold, lose all HP."); - } - } - else if (phase == 3) - { - if (spelunking_status.keys > 0 && !spelunking_status.areas_unlocked[$location[The City of Goooold]]) - { - description.listAppend("Unlock The City of Goooold, at the cost of one key."); - } - else - description.listAppend("Take 40 damage."); - } - } - else if ($locations[the snake pit,the beehive,the crashed u. f. o.] contains l) - { - crate_areas.listAppend(l); - continue; - } - else if (l == $location[The Spider Hole]) - { - boolean no_period = false; - string line = "15-20 gold"; - if ($item[cursed coffee cup].available_amount() > 0) - { - //line += " and " + (MIN(my_maxhp() - my_hp(), 30)) + " HP."; - line += " and restore 30 HP."; //consistency - if ($item[cursed coffee cup].equipped_amount() == 0) - { - line += " (equip the cursed coffee cup first)"; - no_period = true; - } - } - if (!no_period) - line += "."; - description.listAppend(line); - - if ($item[sturdy machete].available_amount() > 0) - { - if (spelunking_status.buddy.length() == 0) - line = "A buddy."; - else - line = "30?-40 gold."; //???? - if ($item[sturdy machete].equipped_amount() == 0) - line += " (equip a sturdy machete first)"; - description.listAppend(line); - } - if ($item[torch].available_amount() > 0) - { - line = "30-50 gold."; - if ($item[torch].equipped_amount() == 0) - line += " (equip a torch first)"; - description.listAppend(line); - } - } - else if (l == $location[The Ancient Burial Ground]) - { - tombstone_areas.listAppend(l); - continue; - } - else if (l == $location[The City of Goooold]) - { - if (spelunking_status.keys > 0) - description.listAppend("+150 gold, at the cost of a key."); - if (spelunking_status.bombs > 0) - description.listAppend("+80-100 gold, at the cost of a bomb."); - description.listAppend("+60 gold, but take 20 damage."); - } - entry.subentries.listAppend(ChecklistSubentryMake(l, "", description)); - } - if (shopping_areas.count() > 0) - { - string [int] description; - description.listAppend("Shopkeeper."); - - string [int] possible_inventory; - possible_inventory.listAppend("bombs"); - possible_inventory.listAppend("ropes"); - possible_inventory.listAppend("a key"); - foreach it in $items[spelunking fedora,boomerang,sturdy machete,heavy pickaxe,spiked boots,spring boots,mining helmet,X-ray goggles,yellow cape,shotgun,jetpack] - { - if (it.available_amount() == 0) - possible_inventory.listAppend(it); - } - description.listAppend("Could have " + possible_inventory.listJoinComponents(", ", "or") + "."); - entry.subentries.listAppend(ChecklistSubentryMake(shopping_areas.listJoinComponents(", ", "or"), "", description)); - } - if (crate_areas.count() > 0) - { - string [int] drops; - drops.listAppend("3 ropes"); - drops.listAppend("3 bombs"); - foreach it in $items[heavy pickaxe,jetpack,sturdy machete,spring boots] - { - //seen crate give duplicate spring boots before - drops.listAppend(it); - } - entry.subentries.listAppend(ChecklistSubentryMake(crate_areas.listJoinComponents(", ", "or"), "", "Crate. Gives " + drops.listJoinComponents(", ", "or") + ".")); - //Usually drops ropes/bombs? - } - if (tombstone_areas.count() > 0) - { - string [int] description; - - description.listAppend("20-30? gold or a skeleton buddy."); //highest seen for me is 27 - - if ($item[heavy pickaxe].available_amount() > 0 && $item[Shotgun].available_amount() == 0) - { - string line = "Shotgun"; - if ($item[heavy pickaxe].equipped_amount() == 0) - line += " (equip heavy pickaxe first)"; - line += "."; - description.listAppend(line); - } - - if ($item[x-ray goggles].available_amount() > 0 && $item[The Clown Crown].available_amount() == 0) - { - string line = "The Clown Crown"; - if ($item[x-ray goggles].equipped_amount() == 0) - line += " (equip x-ray goggles first)"; - line += "."; - description.listAppend(line); - } - entry.subentries.listAppend(ChecklistSubentryMake(tombstone_areas.listJoinComponents(", ", "or"), "", description)); - } - - - if (very_important) - { - task_entries.listAppend(entry); - string secondary_description = "Scroll up for full description."; - ChecklistEntry pop_up_reminder_entry = ChecklistEntryMake(entry.image_lookup_name, "", ChecklistSubentryMake(entry.subentries[0].header, "", secondary_description), -11); - pop_up_reminder_entry.tags.id = entry.tags.id + " popup"; - pop_up_reminder_entry.only_show_as_extra_important_pop_up = true; - pop_up_reminder_entry.container_div_attributes["onclick"] = "navbarClick(0, 'Tasks_checklist_container')"; - pop_up_reminder_entry.container_div_attributes["class"] = "r_clickable"; - - task_entries.listAppend(pop_up_reminder_entry); - } - else - future_task_entries.listAppend(entry); -} - -string [item] SpelunkingGenerateEquipmentDescriptions(SpelunkingStatus spelunking_status) -{ - string [item] equipment_descriptions; - - equipment_descriptions[$item[trusty whip]] = "3-6 damage."; - equipment_descriptions[$item[sturdy machete]] = "3-6 damage, +5 weapon damage."; - equipment_descriptions[$item[shotgun]] = "6-12 damage, +10 ranged damage."; - equipment_descriptions[$item[boomerang]] = "3-6 damage, delevels."; - equipment_descriptions[$item[plasma rifle]] = "9-18 damage, +20 ranged damage."; - - equipment_descriptions[$item[Bananubis's Staff]] = "3-6 damage, -6 gold drops, raises a skeleton buddy"; - if (spelunking_status.buddy != "") - equipment_descriptions[$item[Bananubis's Staff]] += " later"; - equipment_descriptions[$item[Bananubis's Staff]] += "."; - if (spelunking_status.buddy.length() == 0) - { - if (spelunking_status.sacrifices < 3 && !spelunking_status.areas_unlocked[$location[the crashed u. f. o.]]) - equipment_descriptions[$item[Bananubis's Staff]] += "|Use this now if you want a buddy to sacrifice."; - else - equipment_descriptions[$item[Bananubis's Staff]] += "|Use this now if you want a skeleton buddy. (for +stat sacrificing or Yomama)"; - } - - equipment_descriptions[$item[crumbling skull]] = "Can throw for 20 damage.|Afterward, can find another."; - equipment_descriptions[$item[8042]] = "Can throw for 30 damage.|Afterward, can find another."; - equipment_descriptions[$item[pot]] = "2 DR, can throw for 20 damage/10 gold."; - equipment_descriptions[$item[heavy pickaxe]] = "+5 all attributes"; - equipment_descriptions[$item[torch]] = "Deals 8-10 damage first round of combat.|Finds random bombs/ropes/gold.|Can be thrown for 100 damage.|Can be thrown at Yomama for recurring damage."; - equipment_descriptions[$item[The Joke Book of the Dead]] = "-6 gold drops, +5 weapon damage, 5 DR."; - equipment_descriptions[$item[cursed coffee cup]] = "-2 gold drops, restores HP after combat."; - - equipment_descriptions[$item[spelunking fedora]] = "+5 stats."; - equipment_descriptions[$item[mining helmet]] = "2 DR, finds random ropes/bombs/gold."; - equipment_descriptions[$item[X-ray goggles]] = "-5 moxie, +5 gold drops."; - equipment_descriptions[$item[The Clown Crown]] = "-6 gold drops."; - - //Note: Both the yellow cape and jetpack affect both boots. How to? - item [int] boots_available; - foreach it in $items[spring boots,spiked boots] - { - if (it.available_amount() > 0) - boots_available.listAppend(it); - } - - equipment_descriptions[$item[yellow cape]] = "+5 moxie"; - if (boots_available.count() > 0) - equipment_descriptions[$item[yellow cape]] += ", improves " + boots_available.listJoinComponents(", ", "and"); - equipment_descriptions[$item[yellow cape]] += "."; - - equipment_descriptions[$item[jetpack]] = "+10 moxie"; - if (boots_available.count() > 0) - equipment_descriptions[$item[jetpack]] += ", improves " + boots_available.listJoinComponents(", ", "and"); - equipment_descriptions[$item[jetpack]] += "."; - - equipment_descriptions[$item[spring boots]] = "Avoids enemy attacks."; - equipment_descriptions[$item[spiked boots]] = "Deals "; - if ($item[jetpack].equipped_amount() > 0) - equipment_descriptions[$item[spiked boots]] += "14-15"; - else if ($item[yellow cape].equipped_amount() > 0) - equipment_descriptions[$item[spiked boots]] += "8-10"; - else - equipment_descriptions[$item[spiked boots]] += "4-5"; - equipment_descriptions[$item[spiked boots]] += " damage first round of combat."; - if ($item[jetpack].available_amount() > 0) - { - if ($item[jetpack].equipped_amount() == 0) - equipment_descriptions[$item[spiked boots]] += " (equip jetpack for more)"; - } - else if ($item[yellow cape].available_amount() > 0 && $item[yellow cape].equipped_amount() == 0) - equipment_descriptions[$item[spiked boots]] += " (equip yellow cape for more)"; - - return equipment_descriptions; -} - -void SpelunkingGenerateEquipmentEntries(Checklist [int] checklists, SpelunkingStatus spelunking_status) -{ - /*ChecklistEntry [int] equipment_entries; - - if (true) - { - Checklist equipment_checklist; - equipment_checklist = ChecklistMake("Equipment", equipment_entries); - checklists.listAppend(equipment_checklist); - }*/ - - string [item] equipment_descriptions = SpelunkingGenerateEquipmentDescriptions(spelunking_status); - - - item [slot][int] equipment_per_slot; - - foreach it in $items[trusty whip,sturdy machete,shotgun,boomerang,plasma rifle,Bananubis's Staff,crumbling skull,8042,pot,heavy pickaxe,torch,The Joke Book of the Dead,cursed coffee cup,spelunking fedora,mining helmet,X-ray goggles,The Clown Crown,yellow cape,jetpack,spring boots,spiked boots] - { - if (it.available_amount() == 0) - continue; - - if (!(equipment_per_slot contains it.to_slot())) - { - item [int] blank_entries; - equipment_per_slot[it.to_slot()] = blank_entries; - } - equipment_per_slot[it.to_slot()].listAppend(it); - } - - slot [int] slot_evaluation_order; - slot_evaluation_order.listAppend($slot[weapon]); - slot_evaluation_order.listAppend($slot[off-hand]); - slot_evaluation_order.listAppend($slot[hat]); - slot_evaluation_order.listAppend($slot[back]); - slot_evaluation_order.listAppend($slot[acc1]); - foreach s in equipment_per_slot - { - if (!($slots[weapon,off-hand,hat,back,acc1] contains s)) - slot_evaluation_order.listAppend(s); - } - - foreach key, s in slot_evaluation_order - { - if (!(equipment_per_slot contains s)) - continue; - - string slot_name = s.slot_to_plural_string().capitaliseFirstLetter(); - - /*ChecklistEntry entry; - entry.subentries.listAppend(ChecklistSubentryMake(slot_name, "", "")); - entry.should_indent_after_first_subentry = true; - boolean have_something_to_unequip = false;*/ - - ChecklistEntry [int] checklist_entries; - - foreach key2 in equipment_per_slot[s] - { - item it = equipment_per_slot[s][key2]; - string header = it.capitaliseFirstLetter(); - if (it.available_amount() > 1) - header = pluralise(it); - string description; - - description = equipment_descriptions[it]; - - /*if (it.equipped_amount() == 0) - have_something_to_unequip = true; - - if (entry.image_lookup_name.length() == 0) - entry.image_lookup_name = "__item " + it; - - entry.subentries.listAppend(ChecklistSubentryMake(header, "", description));*/ - ChecklistEntry entry = ChecklistEntryMake("__item " + it, "", ChecklistSubentryMake(header, "", description)); - entry.tags.id = "Spelunky mode equipment " + it.name; - if (it.equipped_amount() > 0) - { - entry.should_highlight = true; - if (it.to_slot() != $slot[none]) - entry.url = "place.php?whichplace=spelunky"; - } - else if (it.to_slot() != $slot[none]) - { - //this is an interesting idea, but it violates our rule that clicking guide never modifies significant state - //in other words, guide should feel "safe" to click on - //I mean, you should never feel safe around guide. save yourself! - //But, it seems useful enough to be worth doing... - entry.url = "inv_equip.php?pwd=" + my_hash() + "&which=2&action=equip&whichitem=" + it.to_int(); - //KoLmafia/sideCommand?cmd=uneffect+effect&pwd=hash - //entry.url = "KoLmafia/sideCommand?pwd=" + my_hash() + "&cmd=equip+" + it.replace_string(" ", "+"); - //entry.url = "inventory.php?which=2"; - } - checklist_entries.listAppend(entry); - - } - /*if (have_something_to_unequip) - entry.url = "inventory.php?which=2"; - equipment_entries.listAppend(entry);*/ - - - - if (true) - { - Checklist c; - c = ChecklistMake(slot_name, checklist_entries); - checklists.listAppend(c); - } - } -} - - -void LimitModeSpelunkingGenerateChecklists(Checklist [int] checklists) -{ - if (limit_mode() != "spelunky") - return; - ChecklistEntry [int] task_entries; - ChecklistEntry [int] optional_task_entries; - ChecklistEntry [int] future_task_entries; - ChecklistEntry [int] resource_entries; - - if (true) - { - Checklist task_checklist; - task_checklist = ChecklistMake("Tasks", task_entries); - checklists.listAppend(task_checklist); - - - Checklist optional_task_checklist; - optional_task_checklist = ChecklistMake("Optional Tasks", optional_task_entries); - checklists.listAppend(optional_task_checklist); - - Checklist future_task_checklist; - future_task_checklist = ChecklistMake("Future Tasks", future_task_entries); - checklists.listAppend(future_task_checklist); - - Checklist resources_checklist; - resources_checklist = ChecklistMake("Resources", resource_entries); - checklists.listAppend(resources_checklist); - } - - string spelunking_url = "place.php?whichplace=spelunky"; - - - SpelunkingStatus spelunking_status = SpelunkingParseStatus(); - - - if (spelunking_status.turns_left == 0) - { - string [int] description; - - string [int] accomplishments; - if (spelunking_status.gold > 0) - accomplishments.listAppend("earned " + spelunking_status.gold + " gold"); - if (spelunking_status.sacrifices > 0) - accomplishments.listAppend("sacrificed " + pluraliseWordy(spelunking_status.sacrifices, "noble friend", "noble friends")); //is this really an... accomplishment? - if (accomplishments.count() > 0) - description.listAppend("You " + accomplishments.listJoinComponents(", ", "and") + "."); - - task_entries.listAppend(ChecklistEntryMake("__item spelunking fedora", "place.php?whichplace=spelunky&action=spelunky_quit", ChecklistSubentryMake("Ride off into the sunset", "", description)).ChecklistEntrySetIDTag("Spelunky mode results")); - return; - } - - SpelunkingGenerateNCInformation(spelunking_status, task_entries, future_task_entries); - - - if (my_hp() == 0) - { - task_entries.listAppend(ChecklistEntryMake("__effect beaten up", spelunking_url, ChecklistSubentryMake("Heal", "", "Probably at your tent. (costs a turn)"), -11).ChecklistEntrySetIDTag("Spelunky mode heal")); - } - - if ($item[jetpack].available_amount() > 0 && $item[yellow cape].equipped_amount() > 0 && !spelunking_status.noncombat_due_next_adventure) - { - task_entries.listAppend(ChecklistEntryMake("__item jetpack", "inv_equip.php?pwd=" + my_hash() + "&which=2&action=equip&whichitem=" + $item[jetpack].to_int(), ChecklistSubentryMake("Equip jetpack", "", "More efficient than the yellow cape."), -11).ChecklistEntrySetIDTag("Spelunky mode jetpack")); - } - - if (get_property("spelunkyUpgrades").contains_text("N")) - { - int unlocks_found = 0; - string upgrades_string = get_property("spelunkyUpgrades"); - for i from 0 to upgrades_string.length() - 1 - { - if (upgrades_string.char_at(i) == "Y") - unlocks_found += 1; - } - - int unlocks_remaining = clampi(9 - unlocks_found, 0, 9); - - int after_this_remaining = MAX(0, unlocks_remaining - 1); - - if (after_this_remaining > 0) - future_task_entries.listAppend(ChecklistEntryMake("__item heavy pickaxe", "", ChecklistSubentryMake("Spelunk " + pluraliseWordy(after_this_remaining, "more time", "more times") + " after this", "", "Unlock all the starting bonuses.")).ChecklistEntrySetIDTag("Spelunky mode unlock bonuses")); - } - - if (spelunking_status.altar_unlocked && spelunking_status.buddy != "") - { - string [int] description; - //spelunking_status.sacrifices - if (spelunking_status.buddy == "Resourceful Kid") - description.listAppend("He's just a kid! Don't do it!"); - else if (spelunking_status.buddy == "Helpful Guy") - description.listAppend("But, he's really helpful... a loyal companion at your side! Could you betray him?"); - else if (spelunking_status.buddy == "Skeleton") - { - description.listAppend("A skeleton probably won't mind. They're just magic, right?|Still, it is a betrayal..."); - } - else if (spelunking_status.buddy == "Golden Monkey") - description.listAppend("Animal sacrifice... is it really worth it?"); - else - description.listAppend("But, will you betray your friend?"); - - string [int] results; - - if (spelunking_status.sacrifices == 0) - results.listAppend("cursed coffee cup"); - else if (spelunking_status.sacrifices == 1) - { - item next_item; - if ($item[x-ray goggles].available_amount() == 0) - next_item = $item[x-ray goggles]; - else if ($item[spiked boots].available_amount() == 0) - next_item = $item[spiked boots]; - else if ($item[jetpack].available_amount() == 0) - next_item = $item[jetpack]; - else - next_item = $item[8042]; - results.listAppend(next_item); - } - else if (spelunking_status.sacrifices == 2) - results.listAppend("The Joke Book of the Dead (used for unlocking Hell/fighting ghost)"); - - - if (spelunking_status.sacrifices == 0) - results.listAppend("+10 to all stats"); - else if (spelunking_status.sacrifices == 1) - results.listAppend("+5 to all stats"); - else if (spelunking_status.sacrifices >= 2) - results.listAppend("+1 to all stats"); - - if ($item[cursed coffee cup].available_amount() > 0) - { - string line = "30 HP restoration"; - if ($item[cursed coffee cup].equipped_amount() == 0) - line += " (equip cursed coffee cup first)"; - } - - if ($item[Bananubis's Staff].available_amount() > 0) - description.listAppend("Consider repeatedly summoning/sacrificing skeletons for extra stats. (Bananubis's Staff)"); - - if (results.count() > 0) - description.listAppend("Gives " + results.listJoinComponents(", ", "and") + "."); - - if (spelunking_status.sacrifices < 2) - description.listAppend("Part of unlocking Hell."); //where else would you go? - - if (spelunking_status.sacrifices > 0) - description.listAppend(pluraliseWordy(spelunking_status.sacrifices, "sacrifice", "sacrifices").capitaliseFirstLetter() + " so far."); - optional_task_entries.listAppend(ChecklistEntryMake("__item Cloaca-Cola-issue combat knife", spelunking_url, ChecklistSubentryMake("Possibly sacrifice " + spelunking_status.buddy.to_lower_case() + " at the altar", "", description)).ChecklistEntrySetIDTag("Spelunky mode sacrifice")); - //place.php?whichplace=spelunky&action=spelunky_side6 - } - - - - if ($item[the joke book of the dead].available_amount() > 0) - { - string url; - string [int] description; - string [int] tasks; - description.listAppend("If you haven't already."); - - if ($item[the joke book of the dead].equipped_amount() == 0) - { - tasks.listAppend("after equipping " + $item[the joke book of the dead]); - url = "inventory.php?ftext=joke+book+of+the+dead"; - } - tasks.listAppend("click on the ghost"); - description.listAppend(tasks.listJoinComponents(", ").capitaliseFirstLetter() + "."); - description.listAppend("Gives ten more turns on victory."); - - - string [int] ideas; - foreach it in $items[spring boots,boomerang,spelunking fedora] - { - if (it.equipped_amount() == 0) - ideas.listAppend(it); - } - if (spelunking_status.buddy != "Skeleton") - ideas.listAppend("skeleton"); - ideas.listAppend("ropes"); - - - - description.listAppend("Defeating it involves... " + ideas.listJoinComponents(", ") + "?"); - - optional_task_entries.listAppend(ChecklistEntryMake("__item ghost trap", url, ChecklistSubentryMake("Possibly attack the ghost", "", description)).ChecklistEntrySetIDTag("Spelunky mode ghost fight")); - } - - if (spelunking_status.areas_unlocked[$location[the city of Goooold]] && $item[Bananubis's Staff].available_amount() == 0) - { - string [int] description; - description.listAppend("Part of unlocking Hell, and the staff can give stats via sacrifices."); - if (spelunking_status.sticky_bombs_unlocked) - description.listAppend("Throw two bombs."); - else - { - string [int] tasks; - if ($item[spring boots].available_amount() == 0) - tasks.listAppend("acquire spring boots"); - else if ($item[spring boots].equipped_amount() == 0) - tasks.listAppend("equip spring boots"); - tasks.listAppend("rope until spring boots activate"); - tasks.listAppend("throw a bomb"); - tasks.listAppend("throw a bomb or attack or whatever will kill him"); - description.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "?"); - description.listAppend("Or acquire sticky bombs."); - } - description.listAppend("Appears after defeating five mummies in the area."); - optional_task_entries.listAppend(ChecklistEntryMake("__item Bananubis's Staff", spelunking_url, ChecklistSubentryMake("Defeat Bananubis", "", description)).ChecklistEntrySetIDTag("Spelunky mode defeat Bananubis")); - } - - if (spelunking_status.areas_unlocked[$location[LOLmec's lair]] && !spelunking_status.areas_unlocked[$location[Hell]]) - { - //defeat LOLMec - string [int] description; - description.listAppend("If you haven't already."); - if (spelunking_status.bombs < 10) - description.listAppend("Collect ten bombs first."); - else - { - string line = "Throw ten bombs."; - if (!spelunking_status.sticky_bombs_unlocked && spelunking_status.bombs >= 20) - line += " Or twenty."; - description.listAppend(line); - if (!spelunking_status.sticky_bombs_unlocked) - { - if (!spelunking_status.areas_unlocked[$location[the snake pit]]) - description.listAppend("Possibly acquire sticky bombs from the spider queen."); - - string [int] ideas; - foreach it in $items[spring boots,shotgun,spelunking fedora,8042] - { - if (it.equipped_amount() == 0) - ideas.listAppend(it); - } - if (spelunking_status.buddy != "Skeleton") - ideas.listAppend("skeleton"); - ideas.listAppend("ropes"); - - - - description.listAppend("Umm... " + ideas.listJoinComponents(", ") + "?"); - } - } - optional_task_entries.listAppend(ChecklistEntryMake("__item LOLmec statuette", spelunking_url, ChecklistSubentryMake("Defeat LOLmec", "", description)).ChecklistEntrySetIDTag("Spelunky mode defeat LOLmec")); - } - - if (spelunking_status.areas_unlocked[$location[Yomama's Throne]]) - { - string [int] description; - description.listAppend("If you haven't already."); - description.listAppend("Umm... throw a bomb, throw a torch, stagger with ropes? Spring boots? Fedora?|Or defeat him another way. Skeleton buddy might help."); - optional_task_entries.listAppend(ChecklistEntryMake("__item huge gold coin", spelunking_url, ChecklistSubentryMake("Defeat Yomama", "", description)).ChecklistEntrySetIDTag("Spelunky mode defeat Yomama")); - } - - if (!spelunking_status.areas_unlocked[$location[the temple ruins]]) - { - } - else if (!spelunking_status.areas_unlocked[$location[Hell]] && $items[Bananubis's Staff,The Joke Book of the Dead,The Clown Crown].items_missing().count() == 0) - { - if (spelunking_status.keys == 0) - { - optional_task_entries.listAppend(ChecklistEntryMake("__item Clan VIP Lounge key", "", ChecklistSubentryMake("Acquire a key", "", "For unlocking Hell.")).ChecklistEntrySetIDTag("Spelunky mode unlock hell way 1 step 1")); // This is just a guess, I have very little idea what is going on here - } - else - { - string [int] description; - string [int] tasks; - string url; - url = spelunking_url; - - foreach it in $items[Bananubis's Staff,The Joke Book of the Dead,The Clown Crown] - { - if (it.equipped_amount() == 0) - { - tasks.listAppend("equip " + it); - url = "inventory.php?which=2"; - } - } - tasks.listAppend("click on LOLmec's lair"); - if (tasks.count() > 0) - description.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - description.listAppend(HTMLGenerateSpanFont("Only do this if you've defeated LOLmec already.", "red")); - optional_task_entries.listAppend(ChecklistEntryMake("__item Clan VIP Lounge key", url, ChecklistSubentryMake("Unlock Hell", "", description)).ChecklistEntrySetIDTag("Spelunky mode unlock hell way 1 step 2")); - } - } - else if (!spelunking_status.areas_unlocked[$location[Hell]] && !(spelunking_status.areas_unlocked[$location[the crashed u. f. o.]])) - { - string [int] description; - string [int] tasks; - if ($item[Bananubis's Staff].available_amount() == 0) - { - tasks.listAppend("acquire Bananubis's Staff"); - } - if ($item[The Joke Book of the Dead].available_amount() == 0) - { - tasks.listAppend("sacrifice buddies for the Joke Book of the Dead"); - } - if ($item[x-ray goggles].available_amount() == 0) - { - tasks.listAppend("acquire x-ray goggles"); - } - if ($item[The Clown Crown].available_amount() == 0) - { - tasks.listAppend("acquire the Clown Crown from the jungle/burial ground NCs"); - } - if (!spelunking_status.areas_unlocked[$location[LOLmec's lair]]) - tasks.listAppend("unlock LOLmec's lair"); - tasks.listAppend("defeat LOLmec"); - if (spelunking_status.keys == 0) - tasks.listAppend("acquire a key"); - - description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - optional_task_entries.listAppend(ChecklistEntryMake("__item handful of fire", "", ChecklistSubentryMake("Unlock Hell", "", description)).ChecklistEntrySetIDTag("Spelunky mode unlock hell way 2")); - } - - if (true) - { - string [int] description; - if (__setting_debug_mode && false) - { - //spelunkyNextNoncombat,spelunkyWinCount,spelunkyUpgrades,spelunkySacrifices - foreach s in $strings[spelunkyStatus] - { - description.listAppend(s + " = \"" + get_property(s) + "\""); - } - description.listAppend("spelunking_status = " + spelunking_status.to_json()); - } - - string [int] areas_to_adventure_in; - areas_to_adventure_in.listAppend("Mines: if the other areas are too difficult."); - //snake pit - marginal? - if (spelunking_status.areas_unlocked[$location[the spider hole]] && !spelunking_status.sticky_bombs_unlocked) - areas_to_adventure_in.listAppend("The Spider Hole: to unlock sticky bombs."); - //burial ground - if (spelunking_status.areas_unlocked[$location[the jungle]] && $item[torch].available_amount() == 0) - areas_to_adventure_in.listAppend("Jungle: chance a torch from tikimen. Throwing rocks works well here."); - //beehive - //UFO - //ice caves - unlocking temple ruins...? - if (spelunking_status.areas_unlocked[$location[The City of Goooold]] && $item[Bananubis's Staff].available_amount() == 0) - areas_to_adventure_in.listAppend("City of Goooold: defeat boss for Bananubis's staff. Part of unlocking Hell."); - //temple ruins - if (spelunking_status.areas_unlocked[$location[the temple ruins]] && !spelunking_status.areas_unlocked[$location[lolmec's lair]]) - areas_to_adventure_in.listAppend("Temple ruins: unlock LOLmec's lair."); - //lolmec's lair - //yomama's lair - if (spelunking_status.areas_unlocked[$location[hell]] && !spelunking_status.areas_unlocked[$location[yomama's throne]]) - areas_to_adventure_in.listAppend("Hell: unlock Yomama's throne after seven combats won."); - - if (spelunking_status.areas_unlocked[$location[the temple ruins]]) - areas_to_adventure_in.listAppend("Temple ruins: to collect gold."); - else - areas_to_adventure_in.listAppend("Somewhere: to collect gold."); - if (areas_to_adventure_in.count() > 0) - description.listAppend("Adventure in:|*" + areas_to_adventure_in.listJoinComponents("|*
")); - - //description.listAppend("Usual combat strategy:|*Throw a bomb or rope if they're powerful (and you can afford it), then attack. Try to avoid taking damage, or heal it with a cursed coffee cup."); - task_entries.listAppend(ChecklistEntryMake("__item heavy pickaxe", spelunking_url, ChecklistSubentryMake("Spelunk!", "", description)).ChecklistEntrySetIDTag("Spelunky mode general")); - } - - SpelunkingGenerateEquipmentEntries(checklists, spelunking_status); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Main.ash b/Source/relay/TourGuide/Main.ash deleted file mode 100644 index 2a53a9a3..00000000 --- a/Source/relay/TourGuide/Main.ash +++ /dev/null @@ -1,371 +0,0 @@ -import "relay/TourGuide/Settings.ash" -import "relay/TourGuide/Support/Library.ash" -import "relay/TourGuide/Support/IOTMs.ash" -import "relay/TourGuide/Sections/User Preferences.ash" -import "relay/TourGuide/Support/Statics.ash" -import "relay/TourGuide/Support/Statics 2.ash" -import "relay/TourGuide/Support/List.ash" -import "relay/TourGuide/Sections/Globals.ash" -import "relay/TourGuide/Sections/Data.ash" -import "relay/TourGuide/Support/Counter.ash" -import "relay/TourGuide/Support/Library 2.ash" -import "relay/TourGuide/State.ash" -import "relay/TourGuide/Missing Items.ash" -import "relay/TourGuide/Support/Math.ash" -import "relay/TourGuide/Tasks.ash" -import "relay/TourGuide/Limit Mode/Spelunking.ash" -import "relay/TourGuide/Daily Resources.ash" -import "relay/TourGuide/Strategy.ash" -import "relay/TourGuide/Sections/Messages.ash" -import "relay/TourGuide/Sections/Checklists.ash" -import "relay/TourGuide/Sections/Location Bar.ash" -import "relay/TourGuide/Sections/API.ash" -import "relay/TourGuide/Sections/Navigation Bar.ash" -import "relay/TourGuide/Sections/Tests.ash" -import "relay/TourGuide/Sections/CSS.ash" -import "relay/TourGuide/Sections/Contextual Menu.ash" -import "relay/TourGuide/Items of the Month/Items of the Month import.ash" -import "relay/TourGuide/Paths/Paths import.ash" - -void runMain(string relay_filename) -{ - string [string] form_fields = form_fields(); - if (form_fields["API status"] != "") - { - string [string] api_response = generateAPIResponse(); - write(api_response.to_json()); - return; - } - - boolean output_body_tag_only = false; - if (form_fields["body tag only"] != "") - { - output_body_tag_only = true; - } - else if (form_fields["set user preferences"] != "") - { - processSetUserPreferences(form_fields); - return; - } - else if (form_fields.count() > 0) - print_html("Form fields: " + form_fields.to_json()); - - - PageInit(); - ChecklistInit(); - contextMenuInit(); - setUpCSSStyles(); - - - Checklist [int] ordered_output_checklists; - generateChecklists(ordered_output_checklists); - - string guide_title = "TourGuide"; - if (isAprilFools()) { - guide_title = "Glup Shitto Stole Rogue V's Targeting Computer"; - } - if (limit_mode() == "batman") - guide_title = "Bat-Guide"; - - PageSetTitle(guide_title); - - if (__setting_use_kol_css) - PageWriteHead(HTMLGenerateTagPrefix("link", mapMake("rel", "stylesheet", "type", "text/css", "href", "/images/styles.css"))); - - PageWriteHead(HTMLGenerateTagPrefix("meta", mapMake("name", "viewport", "content", "width=device-width"))); - - - if (relay_filename.to_lower_case() == "relay_guide.ash") - PageSetBodyAttribute("onload", "GuideInit('relay_Guide.ash'," + __setting_horizontal_width + ");"); - else - PageSetBodyAttribute("onload", "GuideInit('" + relay_filename + "'," + __setting_horizontal_width + ");"); //not escaped - - boolean drunk = $item[beer goggles].equipped_amount() > 0; - - if (drunk) - PageWrite(HTMLGenerateTagPrefix("div", mapMake("style", "-webkit-filter:blur(4.0px) brightness(1.01);"))); //FIXME make this animated - - boolean buggy = (my_familiar() == $familiar[software bug] || $item[iShield].equipped_amount() > 0); - if (buggy) - { - //Ideally we'd want to layer over a mosaic filter, giving a Cinepak look, but pixel manipulation techniques are limited in HTML. - string chosen_font; - //chosen_font = "'Comic Sans MS', cursive, sans-serif;"; //DO NOT USE - //chosen_font = "'Courier New', Courier, monospace;"; - chosen_font = "'Helvetica Neue',Arial, Helvetica, sans-serif;font-weight:300;"; - PageWrite(HTMLGenerateTagPrefix("div", mapMake("style", "font-family:" + chosen_font))); - //PageWrite(HTMLGenerateTagPrefix("div", mapMake("style", ""))); - // - } - - boolean displaying_navbar = false; - if (__setting_show_navbar) - { - if (ordered_output_checklists.count() > 1) - displaying_navbar = true; - } - if (displaying_navbar) - { - buffer navbar = generateNavbar(ordered_output_checklists); - PageWrite(navbar); - } - - boolean displaying_location_bar = __setting_show_location_bar; - if (displaying_location_bar) - { - buffer location_bar = generateLocationBar(displaying_navbar); - if (location_bar.length() == 0) - displaying_location_bar = false; - else - PageWrite(location_bar); - } - - - int max_width_setting = __setting_horizontal_width; - - string bottom_margin; - float bottom_offset = (__setting_navbar_height_in_em - 0.05) * (displaying_navbar.to_int() + displaying_location_bar.to_int()); - if (bottom_offset > 0.0) - bottom_margin = "margin-bottom:" + bottom_offset + "em;"; - - string horizontal_container_styles = "position:relative;max-width:" + max_width_setting + "px;" + bottom_margin; - if (isAprilFools()) { - horizontal_container_styles += "transform: rotate3d(1, 1.5, 0.2, 30deg); transform-origin: 10px top"; - } - PageWrite(HTMLGenerateTagPrefix("div", mapMake("class", "r_centre", "id", "Guide_horizontal_container", "style", horizontal_container_styles))); //centre holding container - - - - if (true) - { - //Buttons. - string [string] base_image_map; - base_image_map["width"] = "12"; - base_image_map["height"] = "12"; - base_image_map["class"] = "r_button"; - - //position:fixed holding container for the Close button: - string [string] image_map = mapCopy(base_image_map); - image_map["src"] = __close_image_data; - image_map["onclick"] = "buttonCloseClicked(event)"; - image_map["style"] = "left:5px;top:5px;"; - image_map["id"] = "button_close_box"; - image_map["alt"] = "Close"; - image_map["title"] = image_map["alt"]; - PageWrite(HTMLGenerateTagWrap("div", HTMLGenerateTagPrefix("img", image_map), string [string] {"id":"close_button_position_reference", "style":"position:fixed;z-index:5;width:100%;max-width:" + max_width_setting + "px;"})); - - //Hacky layout, sorry: - image_map = mapCopy(base_image_map); - image_map["width"] = "12"; - image_map["height"] = "12"; - image_map["class"] = "r_button"; - image_map["src"] = __refresh_image_data; - image_map["id"] = "button_refresh"; - image_map["onclick"] = "document.location.reload(true)"; - image_map["style"] = "right:5px;top:5px;"; - image_map["alt"] = "Refresh"; - image_map["title"] = image_map["alt"]; - PageWrite(HTMLGenerateTagWrap("div", HTMLGenerateTagPrefix("img", image_map), string [string] {"id":"refresh_button_position_reference", "style":"position:fixed;z-index:5;width:100%;max-width:" + max_width_setting + "px;"})); - - //position:absolute holding container, so we can absolutely position these, absolutely: - PageWrite(HTMLGenerateTagPrefix("div", mapMake("id", "top_buttons_position_reference", "style", "position:absolute;" + "width:100%;max-width:" + max_width_setting + "px;"))); - - image_map = mapCopy(base_image_map); - image_map["src"] = __new_window_image_data; - image_map["id"] = "button_new_window"; - image_map["onclick"] = "buttonNewWindowClicked(event)"; - image_map["style"] = "right:30px;top:5px;"; - image_map["alt"] = "Open in new window"; - image_map["title"] = image_map["alt"]; - PageWrite(HTMLGenerateTagPrefix("img", image_map)); - - image_map = mapCopy(base_image_map); - image_map["src"] = __left_arrow_image_data; - image_map["id"] = "button_arrow_right_left"; - image_map["onclick"] = "buttonRightLeftClicked(event)"; - image_map["style"] = "right:55px;top:5px;"; - image_map["alt"] = "Show chat pane"; - image_map["title"] = image_map["alt"]; - PageWrite(HTMLGenerateTagPrefix("img", image_map)); - - image_map = mapCopy(base_image_map); - image_map["src"] = __right_arrow_image_data; - image_map["id"] = "button_arrow_right_right"; - image_map["onclick"] = "buttonRightRightClicked(event)"; - image_map["style"] = "right:55px;top:5px;"; - image_map["alt"] = "Hide chat pane"; - image_map["title"] = image_map["alt"]; - PageWrite(HTMLGenerateTagPrefix("img", image_map)); - - image_map = mapCopy(base_image_map); - image_map["id"] = "button_global_settings"; - image_map["onclick"] = "callSettingsContextualMenu(event)"; - image_map["oncontextmenu"] = "callSettingsContextualMenu(event)"; - image_map["style"] = "right:5px;top:30px;visibility:visible;"; - image_map["alt"] = "Global Settings"; - //image_map["title"] = image_map["alt"]; //useless here - image_map["aria-hidden"] = "true"; - image_map["focusable"] = "false"; - image_map["data-prefix"] = "fas"; - image_map["data-icon"] = "cog"; - image_map["class"] = image_map["class"] + " svg-inline--fa fa-cog fa-w-16"; - image_map["role"] = "img"; - image_map["xmlns"] = "http://www.w3.org/2000/svg"; - image_map["viewBox"] = "0 0 512 512"; - remove image_map["width"]; - PageWrite(HTMLGenerateTagWrap("svg", 'Global SettingsGlobal Settings', image_map)); //https://fontawesome.com/license - - image_map = mapCopy(base_image_map); - image_map["id"] = "button_expand_all"; - image_map["onclick"] = "buttonExpandAllClicked(event)"; - image_map["style"] = "right:30px;top:30px;"; - image_map["alt"] = "Expand all"; - //image_map["title"] = image_map["alt"]; //useless here - image_map["aria-hidden"] = "true"; - image_map["focusable"] = "false"; - image_map["data-prefix"] = "fas"; - image_map["data-icon"] = "angle-double-down"; - image_map["role"] = "img"; - image_map["class"] = image_map["class"] + " svg-inline--fa fa-angle-double-down fa-w-10"; - image_map["xmlns"] = "http://www.w3.org/2000/svg"; - image_map["viewBox"] = "0 50 320 400"; - remove image_map["width"]; - PageWrite(HTMLGenerateTagWrap("svg", 'Expand allExpand all', image_map)); //https://fontawesome.com/license - - PageWrite(""); - } - - if (true) - { - //Holding container: - string style = ""; - style += "padding-top:5px;padding-bottom:0.25em;"; - if (!__setting_fill_vertical) - style += "background-color:" + __setting_page_background_colour + ";"; - if (!__setting_side_negative_space_is_dark && !__setting_fill_vertical) - { - style += "border:1px solid;border-top:1px solid;border-bottom:1px solid;"; - style += "border-color:" + __setting_line_colour + ";"; - } - PageWrite(HTMLGenerateTagPrefix("div", mapMake("id", "Guide_body", "style", style))); - } - - buffer information_cache; - - string player_name = my_name().to_lower_case().HTMLEscapeString(); - if (player_name == "") - player_name = "anonymous"; - information_cache.append(HTMLGenerateTagWrap("div", player_name, string [string] {"id":"player_name"})); - - information_cache.append(HTMLGenerateTagWrap("div", gameday_to_int(), string [string] {"id":"in_game_day"})); - - information_cache.append(HTMLGenerateTagWrap("div", my_ascensions(), string [string] {"id":"ascension_count"})); - - PageWrite(HTMLGenerateTagWrap("div", information_cache, string [string] {"id":"ASH_information_cache", "style":"display:none;"})); - - if (true) - { - // Head text - - // Title - string titleStyles = "font-weight:bold; font-size:1.5em;"; - if (isAprilFools()) { - titleStyles = titleStyles + "background-image: linear-gradient(-225deg,#231557 0%,#44107a 15%,#ff1361 30%,#fff800 60%);background-size: auto auto;background-clip: border-box;background-size: 200% auto;color: #fff;background-clip: text;text-fill-color: transparent;-webkit-background-clip: text;-webkit-text-fill-color: transparent;display: inline-block"; - } - PageWrite(HTMLGenerateSpanOfStyle(guide_title, titleStyles)); - - // Day + Turn Count - if (__misc_state["in run"] && playerIsLoggedIn()) { - PageWrite(HTMLGenerateDivOfClass("Day " + my_daycount() + ". " + pluralise(my_turncount(), "turn", "turns") + " played.", "r_bold")); - } - // Path - if (my_path() != "" && my_path() != "None" && playerIsLoggedIn()) { - PageWrite(HTMLGenerateDivOfClass(my_path(), "r_bold")); - } - // Random Message (which we'll have to remove :c ) - PageWrite(HTMLGenerateDivOfStyle(generateRandomMessage(), "padding-left:20px;padding-right:20px;")); - PageWrite(HTMLGenerateTagWrap("div", "", mapMake("id", "extra_words_at_top"))); - // Example mode - if (__misc_state["Example mode"]) { - PageWrite("
"); - PageWrite(HTMLGenerateDivOfStyle("Example ascension", "text-align:center; font-weight:bold;")); - } - } - - - outputChecklists(ordered_output_checklists); - - - if (true) - { - //Gray text at the bottom: - string line; - line = HTMLGenerateTagWrap("span", "
Automatic refreshing disabled.", mapMake("id", "refresh_status")); - line += HTMLGenerateTagWrap("a", "
Created by the almighty Ezandora", generateMainLinkMap("showplayer.php?who=1557284")); - line += "
Forked and maintained by the ASS team"; - line += "
" + __version; - - PageWrite(HTMLGenerateTagWrap("div", line, mapMake("style", "font-size:0.777em;color:gray;margin-top:-12px;", "id", "Guide_foot"))); - } - boolean matrix_enabled = false; - if (my_path().id == PATH_THE_SOURCE || $familiars[dataspider,Baby Bugged Bugbear] contains my_familiar()) - { - matrix_enabled = !PreferenceGetBoolean("matrix disabled"); - if (true) - { - //We support disabling this feature, largely because it causes someone's browser to crash. Probably bad RAM. - //I personally consider that to be a path-appropriate feature, but... - string [string] image_map; - image_map["width"] = "16"; - image_map["height"] = "16"; - image_map["class"] = "r_button"; - image_map["id"] = "button_refresh"; - image_map["style"] = "position:relative;top:-16px;left:3px;visibility:visible;"; - if (matrix_enabled) - { - image_map["src"] = __red_pill_image; - image_map["onclick"] = "setMatrixStatus(true)"; - image_map["alt"] = "Matrix enabled"; - } - else - { - image_map["src"] = __blue_pill_image; - image_map["onclick"] = "setMatrixStatus(false)"; - image_map["alt"] = "Matrix disabled"; - } - image_map["title"] = image_map["alt"]; - PageWrite(HTMLGenerateDivOfStyle(HTMLGenerateTagPrefix("img", image_map), "max-height:0px;width:100%;text-align:left;")); - } - } - - //Contextual menu - PageWrite(HTMLGenerateTagWrap("div", generateContextualMenu(), string [string] {"class":"menu"})); - - PageWrite(""); - PageWrite(""); - - if (__setting_fill_vertical) - { - PageWrite(HTMLGenerateTagWrap("div", "", mapMake("id", "color_fill", "class", "r_vertical_fill", "style", "z-index:-1;background-color:" + __setting_page_background_colour + ";max-width:" + __setting_horizontal_width + "px;"))); //Color fill - PageWrite(HTMLGenerateTagWrap("div", "", mapMake("id", "vertical_border_lines", "class", "r_vertical_fill", "style", "z-index:-11;border-left:1px solid;border-right:1px solid;border-color:" + __setting_line_colour + ";width:" + (__setting_horizontal_width) + "px;"))); //Vertical border lines, empty background - } - PageWriteHead(""); - - if (matrix_enabled) - { - PageWrite(HTMLGenerateTagPrefix("div", mapMake("style", "opacity:0;visibility:hidden;background:black;position:fixed;top:0;left:0;z-index:303;width:100%;height:100%;", "id", "matrix_canvas_holder", "onclick", "matrixStopAnimation();", "onmousemove", "matrixStopAnimation();"))); - PageWrite(HTMLGenerateTagWrap("canvas", "", mapMake("width", "1", "height", "1", "id", "matrix_canvas", "style", ""))); - PageWrite(""); - PageWrite(HTMLGenerateTagPrefix("img", mapMake("src", __matrix_glyphs, "id", "matrix_glyphs", "style", "display:none;"))); - } - - if (drunk) - PageWrite(""); - if (buggy) - PageWrite(""); - - if (output_body_tag_only) - write(PageGenerateBodyContents()); - else - PageGenerateAndWriteOut(); -} diff --git a/Source/relay/TourGuide/Missing Items.ash b/Source/relay/TourGuide/Missing Items.ash deleted file mode 100644 index d7f4deca..00000000 --- a/Source/relay/TourGuide/Missing Items.ash +++ /dev/null @@ -1,199 +0,0 @@ -import "relay/TourGuide/Support/Checklist.ash"; -import "relay/TourGuide/QuestState.ash"; - -void generateMissingItems(Checklist [int] checklists) -{ - ChecklistEntry [int] items_needed_entries; - - if (!__misc_state["in run"]) - return; - if (my_path().id == PATH_COMMUNITY_SERVICE) - return; - - //thought about using getClickableURLForLocationIfAvailable for these, but our location detection is very poor, and there are corner cases regardless - - if (__misc_state["wand of nagamar needed"]) { - ChecklistSubentry [int] subentries; - - subentries.listAppend(ChecklistSubentryMake("Wand of Nagamar", "", "")); - - Record WandComponentSource { - item component; - int drop_rate; - monster monster_dropped_from; - location location_dropped_from; - }; - void listAppend(WandComponentSource [int] list, WandComponentSource entry) { - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; - } - - WandComponentSource [int] component_sources; - - if (__misc_state_int["ruby w needed"] > 0) { - WandComponentSource source; - source.component = $item[ruby w]; - source.drop_rate = 30; - source.monster_dropped_from = $monster[W imp]; - if (__quest_state["Level 6"].finished) - source.location_dropped_from = $location[Pandamonium Slums]; - else - source.location_dropped_from = $location[the dark neck of the woods]; - component_sources.listAppend(source); - } - - if (__misc_state_int["metallic a needed"] > 0) { - WandComponentSource source; - source.component = $item[metallic a]; - source.drop_rate = 30; - source.monster_dropped_from = $monster[MagiMechTech MechaMech]; - source.location_dropped_from = $location[The Penultimate Fantasy Airship]; - component_sources.listAppend(source); - } - - if (__misc_state_int["lowercase n needed"] > 0 && __misc_state_int["lowercase n available"] == 0) { - WandComponentSource source; - source.component = $item[lowercase n]; - source.drop_rate = 30; - source.monster_dropped_from = $monster[XXX pr0n]; - source.location_dropped_from = $location[The Valley of Rof L\'m Fao]; - component_sources.listAppend(source); - } - - if (__misc_state_int["heavy d needed"] > 0) { - WandComponentSource source; - source.component = $item[heavy d]; - source.drop_rate = 40; - source.monster_dropped_from = $monster[Alphabet Giant]; - source.location_dropped_from = $location[The Castle in the Clouds in the Sky (Basement)]; - component_sources.listAppend(source); - } - - foreach key, source in component_sources { - if (source.component.available_amount() > 0) - continue; - string modifier_text = ""; - if (!in_bad_moon()) - modifier_text = "Clover or "; - if (source.drop_rate > 0 && source.drop_rate < 100) { - int drop_rate_inverse = ceil(100.0 / source.drop_rate.to_float() * 100.0 - 100.0); - modifier_text += "+" + drop_rate_inverse + "% item"; - } - - string [int] description; - if (!in_bad_moon()) - description.listAppend("Clover the castle basement."); - description.listAppend(source.monster_dropped_from + " - " + source.location_dropped_from + " - " + source.drop_rate + "% drop"); - subentries.listAppend(ChecklistSubentryMake(source.component, modifier_text, description)); - } - - if (subentries.count() == 1) - subentries[0].entries.listAppend("Can create it."); - else if (!__misc_state["can use clovers"]) - subentries[0].entries.listAppend("Either meatpaste together, or find after losing to the naughty sorceress. (" + (in_bad_moon() ? "probably faster" : "usually slower") + ")"); - - ChecklistEntry entry = ChecklistEntryMake("__item wand of nagamar", $location[the castle in the clouds in the sky (basement)].getClickableURLForLocation(), subentries); - entry.tags.id = "Wand of Nagamar reminder"; - entry.should_indent_after_first_subentry = true; - - items_needed_entries.listAppend(entry); - } - - if (my_path().id != PATH_LOW_KEY_SUMMER) //keys are in their own section in this path - SLevel13DoorGenerateMissingItems(items_needed_entries); - - if ($item[lord spookyraven\'s spectacles].available_amount() == 0 && __quest_state["Level 11 Manor"].state_boolean["Can use fast route"] && !__quest_state["Level 11 Manor"].finished) - items_needed_entries.listAppend(ChecklistEntryMake("__item lord spookyraven's spectacles", $location[the haunted bedroom].getClickableURLForLocation(), ChecklistSubentryMake("Lord Spookyraven's spectacles", "", "Found in Haunted Bedroom")).ChecklistEntrySetIDTag("Lord spookyraven spectacles reminder")); - - if ($item[enchanted bean].available_amount() == 0 && !__quest_state["Level 10"].state_boolean["beanstalk grown"]) { - items_needed_entries.listAppend(ChecklistEntryMake("__item enchanted bean", $location[The Beanbat Chamber].getClickableURLForLocation(), ChecklistSubentryMake("Enchanted bean", "", "Found in the beanbat chamber.")).ChecklistEntrySetIDTag("Enchanted bean reminder")); - } - - if (__quest_state["Level 13"].state_boolean["shadow will need to be defeated"]) { - //Let's see - //5 gauze garters + filthy poultices - //Or... - //red pixel potion (not worth farming, but if they have it...) - //red potion - //extra-strength red potion (they might find it) - - } - if (__quest_state["Level 11 Palindome"].state_boolean["Need instant camera"]) { - item camera = 7266.to_item(); - if (camera != $item[none]) { - if (my_path().id != PATH_SEA) items_needed_entries.listAppend(ChecklistEntryMake("__item " + camera, $location[the haunted bedroom].getClickableURLForLocation(), ChecklistSubentryMake("Disposable instant camera", "", "Found in the Haunted Bedroom.")).ChecklistEntrySetIDTag("Instant camera reminder")); - } - } - - if ($item[electric boning knife].available_amount() == 0 && __quest_state["Level 13"].state_boolean["wall of bones will need to be defeated"] && my_path().id != PATH_POCKET_FAMILIARS) { - string [int] description; - description.listAppend("Found from an NC on the ground floor of the castle in the clouds in the sky."); - boolean can_towerkill = false; - if ($skill[garbage nova].skill_is_usable()) { - description.listAppend("Ignore this, you can towerkill with Garbage Nova."); - can_towerkill = true; - } else if (!in_bad_moon()) - description.listAppend("Or towerkill."); - if (!can_towerkill && !__quest_state["Level 13"].state_boolean["past tower level 2"] && $location[the castle in the clouds in the sky (top floor)].locationAvailable()) - description.listAppend("Don't collect this right now; wait until you're at the wall of bones.|(probability of appearing increases)"); - items_needed_entries.listAppend(ChecklistEntryMake("__item electric boning knife", $location[the castle in the clouds in the sky (ground floor)].getClickableURLForLocation(), ChecklistSubentryMake("Electric boning knife", "-combat", description)).ChecklistEntrySetIDTag("Electric boning knife reminder")); - } - if ($item[beehive].available_amount() == 0 && __quest_state["Level 13"].state_boolean["wall of skin will need to be defeated"] && my_path().id != PATH_POCKET_FAMILIARS) { - string [int] description; - - description.listAppend("Found from an NC in the black forest."); - - if (get_property_int("blackForestProgress") >= 1) - description.listAppend(listMake("Head toward the blackberry patch", "Head toward the buzzing sound", "Keep going", "Almost... there...").listJoinComponents(__html_right_arrow_character)); - else - description.listAppend("Not available yet."); - if (!in_bad_moon()) - description.listAppend("Or towerkill."); - - items_needed_entries.listAppend(ChecklistEntryMake("__item beehive", $location[the black forest].getClickableURLForLocation(), ChecklistSubentryMake("Beehive", "-combat", description)).ChecklistEntrySetIDTag("Beehive reminder")); - } - - if (!__quest_state["Level 13"].state_boolean["past races"]) { - ChecklistSubentry subentry = ChecklistSubentryMake("Sources", "", "For the lair races."); - string [int] sources; - if (!__quest_state["Level 13"].state_boolean["Init race completed"]) { - subentry.modifiers.listAppend("+init"); - sources.listAppend("init"); - //subentries.listAppend(ChecklistSubentryMake("+init sources", "+init", "For the lair races.")); - } - if (!__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "") { - // - subentry.modifiers.listAppend("+" + __quest_state["Level 13"].state_string["Stat race type"]); - sources.listAppend(__quest_state["Level 13"].state_string["Stat race type"]); - } - if (!__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && __quest_state["Level 13"].state_string["Elemental damage race type"] != "") { - // - string type = __quest_state["Level 13"].state_string["Elemental damage race type"]; - string type_class = "r_element_" + type + "_desaturated"; - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+" + type + " damage", type_class)); - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+" + type + " spell damage", type_class)); - sources.listAppend(type); - } - string [int] relevant_elements; - foreach s in $strings[nsChallenge3,nsChallenge4,nsChallenge5] { - element e = get_property_element(s); - if (e == $element[none]) continue; - if (numeric_modifier(e + " resistance") >= 7) - continue; - string type_class = "r_element_" + e; - string type_class_desaturated = "r_element_" + e + "_desaturated"; - relevant_elements.listAppend(HTMLGenerateSpanOfClass("+" + e, type_class) + " resistance"); - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+" + e, type_class_desaturated) + " res"); - } - if (relevant_elements.count() > 0) - subentry.entries.listAppend(relevant_elements.listJoinComponents(", ", "and").capitaliseFirstLetter() + " for the hedge maze."); - - subentry.header = sources.listJoinComponents(", ", "and").capitaliseFirstLetter() + " sources"; - if (subentry.modifiers.count() > 0) - items_needed_entries.listAppend(ChecklistEntryMake("__item vial of patchouli oil", "", subentry).ChecklistEntrySetIDTag("NS lair pre-door challenges reminder")); - } - - checklists.listAppend(ChecklistMake("Required Items", items_needed_entries)); -} diff --git a/Source/relay/TourGuide/Paths/Actually Ed the Undying.ash b/Source/relay/TourGuide/Paths/Actually Ed the Undying.ash deleted file mode 100644 index de8aac9b..00000000 --- a/Source/relay/TourGuide/Paths/Actually Ed the Undying.ash +++ /dev/null @@ -1,388 +0,0 @@ - -RegisterTaskGenerationFunction("PathActuallyEdtheUndyingGenerateTasks"); -void PathActuallyEdtheUndyingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) return; - - int skills_available = MIN(15, my_level()) - MIN(15, my_level()) / 3 + get_property_int("edPoints"); //assumption - - skills_available = MIN(21, skills_available); - - int skills_have = 0; - foreach s in lookupSkillsInt($ints[17000,17001,17002,17003,17004,17005,17006,17007,17008,17009,17010,17011,17012,17013,17014,17015,17016,17017,17018,17019,17020]) - { - if (s.skill_is_usable()) - skills_have += 1; - } - //FIXME describe what the next three skills do...? - - if (skills_available > skills_have) - { - string image_name = "__skill wisdom of thoth"; - string [int] description; - description.listAppend("At least " + pluraliseWordy(skills_available - skills_have, "skill", "skills") + " available."); - - skill [int] desired_skill_order; - - if (get_property_int("edPoints") >= 5 && get_property("sleazeAirportAlways").to_boolean()) - { - desired_skill_order.listAppend($skill[Fist of the Mummy]); - desired_skill_order.listAppend($skill[Howl of the Jackal]); - desired_skill_order.listAppend($skill[Roar of the Lion]); - desired_skill_order.listAppend($skill[Prayer of Seshat]); - desired_skill_order.listAppend($skill[Wisdom of Thoth]); - desired_skill_order.listAppend($skill[Power of Heka]); - desired_skill_order.listAppend($skill[Hide of Sobek]); - desired_skill_order.listAppend($skill[Blessing of Serqet]); - desired_skill_order.listAppend($skill[Shelter of Shed]); - desired_skill_order.listAppend($skill[Bounty of Renenutet]); - - - desired_skill_order.listAppend($skill[Storm of the Scarab]); - desired_skill_order.listAppend($skill[Purr of the Feline]); - desired_skill_order.listAppend($skill[Lash of the Cobra]); - desired_skill_order.listAppend($skill[Wrath of Ra]); - - desired_skill_order.listAppend($skill[Curse of the Marshmallow]); - desired_skill_order.listAppend($skill[Curse of Indecision]); - desired_skill_order.listAppend($skill[Curse of Yuck]); - desired_skill_order.listAppend($skill[Curse of Heredity]); - desired_skill_order.listAppend($skill[Curse of Fortune]); - desired_skill_order.listAppend($skill[Curse of Vacation]); - - desired_skill_order.listAppend($skill[Curse of Stench]); - } - else - { - desired_skill_order.listAppend($skill[Fist of the Mummy]); - desired_skill_order.listAppend($skill[Prayer of Seshat]); - desired_skill_order.listAppend($skill[Wisdom of Thoth]); - desired_skill_order.listAppend($skill[Power of Heka]); - desired_skill_order.listAppend($skill[Hide of Sobek]); - desired_skill_order.listAppend($skill[Blessing of Serqet]); - desired_skill_order.listAppend($skill[Shelter of Shed]); - desired_skill_order.listAppend($skill[Bounty of Renenutet]); - - - desired_skill_order.listAppend($skill[Howl of the Jackal]); - desired_skill_order.listAppend($skill[Roar of the Lion]); - desired_skill_order.listAppend($skill[Storm of the Scarab]); - desired_skill_order.listAppend($skill[Purr of the Feline]); - desired_skill_order.listAppend($skill[Lash of the Cobra]); - desired_skill_order.listAppend($skill[Wrath of Ra]); - - desired_skill_order.listAppend($skill[Curse of the Marshmallow]); - desired_skill_order.listAppend($skill[Curse of Indecision]); - desired_skill_order.listAppend($skill[Curse of Yuck]); - desired_skill_order.listAppend($skill[Curse of Heredity]); - desired_skill_order.listAppend($skill[Curse of Fortune]); - desired_skill_order.listAppend($skill[Curse of Vacation]); - - desired_skill_order.listAppend($skill[Curse of Stench]); - } - skill [int] suggestions; - foreach key, s in desired_skill_order - { - if (s.have_skill()) - continue; - suggestions.listAppend(s); - if (suggestions.count() >= skills_available - skills_have) - break; - } - description.listAppend("Maybe " + suggestions.listJoinComponents(", ", "and") + "."); - optional_task_entries.listAppend(ChecklistEntryMake(image_name, "place.php?whichplace=edbase&action=edbase_book", ChecklistSubentryMake("Buy Undying skills", "", description), 11).ChecklistEntrySetIDTag("UNDYING path buy skills")); - } - - if (my_level() >= 13 && QuestState("questL13Final").finished) - { - if ($item[7965].available_amount() > 0 || $item[2334].available_amount() > 0) //holy macguffins - { - string [int] description; - description.listAppend("Finishes the path."); - if (availableSpleen() > 0) - description.listAppend("May want to fill your " + availableSpleen() + " extra spleen first."); - task_entries.listAppend(ChecklistEntryMake("Pyramid", "place.php?whichplace=edbase&action=edbase_altar", ChecklistSubentryMake("Put back the Holy MacGuffin", "", description), -10).ChecklistEntrySetIDTag("UNDYING path quest end path")); - } - else - { - //tutorial.php - string [int] modifiers; - string [int] description; - string url = "tutorial.php"; - - if (!$monster[warehouse janitor].is_banished()) - modifiers.listAppend("banish janitor"); - - description.listAppend("Adventure in the Secret Government Warehouse, use the items you find."); - - int progress_remaining = clampi(40 - get_property_int("warehouseProgress"), 0, 40); - if ($item[warehouse inventory page].available_amount() > 0 && $item[warehouse map page].available_amount() > 0) - { - description.listClear(); - description.listAppend("Use warehouse inventory page."); - url = "inventory.php?ftext=warehouse+inventory+page"; - } - else if (progress_remaining > 0) - { - if ($skill[Lash of the Cobra].have_skill()) - { - description.listAppend("Use lash of the cobra on the clerk and guard."); - } - else - { - modifiers.listAppend("+item"); - } - } - string [int] items_available; - foreach it in $items[warehouse inventory page,warehouse map page] - { - if (it.available_amount() > 0) - items_available.listAppend(pluraliseWordy(it)); - } - if (items_available.count() > 0) - { - description.listAppend(items_available.listJoinComponents(", ", "and").capitaliseFirstLetter() + " available."); - } - - string line;// = pluraliseWordy(progress_remaining, "remaining aisle", "remaining aisles").capitaliseFirstLetter() + "."; - if (progress_remaining <= 0) - line += "MacGuffin next turn"; - else - line += "Fight " + progress_remaining + " more combats"; - if (progress_remaining > 1) - { - int page_pairs_remaining = ceil(progress_remaining.to_float() / 8.0); - - /*string [int] bring_me_the_red_pages; - - int first_value = -1; - boolean identical_twins = false; - foreach it in $items[warehouse inventory page,warehouse map page] - { - int pages_remaining = page_pairs_remaining - it.available_amount(); - if (pages_remaining > 0) - { - if (first_value == -1) - first_value = pages_remaining; - else if (first_value == pages_remaining) - { - identical_twins = true; - bring_me_the_red_pages.listAppend(it); - continue; - } - bring_me_the_red_pages.listAppend(pluraliseWordy(pages_remaining, it)); - } - } - - if (identical_twins) - line += bring_me_the_red_pages.listJoinComponents("/"); - else - line += bring_me_the_red_pages.listJoinComponents(", ", "and");*/ - - line += " or collect "; - line += pluraliseWordy(page_pairs_remaining, "more page pair", "more page pairs"); - } - line += "."; - description.listAppend(line); - - task_entries.listAppend(ChecklistEntryMake("__item 2334", url, ChecklistSubentryMake("Retrieve the Holy MacGuffin", modifiers, description), $locations[The Secret Council Warehouse]).ChecklistEntrySetIDTag("UNDYING path quest final steps")); - } - } -} - -RegisterResourceGenerationFunction("PathActuallyEdtheUndyingGenerateResource"); -void PathActuallyEdtheUndyingGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) return; - item ka = $item[Ka coin]; - if (ka.available_amount() > 0) - { - string [int] description; - - string [int][int] ka_table; - - int haunches_edible = clampi(availableSpleen() / 5, 0, 7); - if (haunches_edible > $item[mummified beef haunch].available_amount()) - { - int haunches_want = haunches_edible - $item[mummified beef haunch].available_amount(); - //15 ka coin - string name; - if (haunches_want > 1) - name = pluralise(haunches_want, $item[mummified beef haunch]); - else - name = "mummified beef haunch"; - ka_table.listAppend(listMake(name, 15, "best spleen consumable")); - } - if ($item[linen bandages].available_amount() == 0 && $item[cotton bandages].available_amount() == 0 && $item[silk bandages].available_amount() == 0) - { - //linen bandages, 1 ka coin - ka_table.listAppend(listMake("linen bandages", 1, "when beaten up outside a fight")); - } - - //seven talisman of Renenutet (1 ka coin) - //talisman of Horus (5 ka coin, +combat) - int talismen_of_horus_wanted = 0; - if (!__quest_state["Level 8"].state_boolean["Mountain climbed"]) - talismen_of_horus_wanted += 2; - if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) - talismen_of_horus_wanted += 2; - if (talismen_of_horus_wanted == 0) //where else do you need +combat? pirate's cove? - talismen_of_horus_wanted = 1; - if ($item[talisman of Horus].available_amount() < talismen_of_horus_wanted) - { - ka_table.listAppend(listMake("talisman of Horus", 5, "+combat potion")); - } - ka_table.listAppend(listMake("talisman of Renenutet", 1, "+lots item for one combat")); - //body upgrades: - string [int][int] skill_upgrade_order; - skill_upgrade_order.listAppend(listMake("Extra Spleen", 5, "+5 spleen")); - skill_upgrade_order.listAppend(listMake("Another Extra Spleen", 10, "+5 spleen")); - skill_upgrade_order.listAppend(listMake("Yet Another Extra Spleen", 15, "+5 spleen")); - skill_upgrade_order.listAppend(listMake("Still Another Extra Spleen", 20, "+5 spleen")); - skill_upgrade_order.listAppend(listMake("Replacement Stomach", 30, "+5 stomach")); //fortune cookie - skill_upgrade_order.listAppend(listMake("Just One More Extra Spleen", 25, "+5 spleen")); - skill_upgrade_order.listAppend(listMake("Okay Seriously, This is the Last Spleen", 30, "+5 spleen")); - skill_upgrade_order.listAppend(listMake("Replacement Liver", 30, "can drink")); - skill_upgrade_order.listAppend(listMake("Upgraded Legs", 10, "+50% init")); - skill_upgrade_order.listAppend(listMake("More Legs", 20, "+50% init")); - skill_upgrade_order.listAppend(listMake("Elemental Wards", 10, "+1 all res")); - skill_upgrade_order.listAppend(listMake("More Elemental Wards", 20, "+2 all res")); - skill_upgrade_order.listAppend(listMake("Tougher Skin", 10, "+100 DA")); - skill_upgrade_order.listAppend(listMake("Even More Elemental Wards", 30, "+3 all res")); - skill_upgrade_order.listAppend(listMake("Upgraded Spine", 20, "+50% moxie")); - skill_upgrade_order.listAppend(listMake("Upgraded Arms", 20, "+50% muscle")); - skill_upgrade_order.listAppend(listMake("Armor Plating", 10, "+10 DR")); //marginal - //skill_upgrade_order.listAppend(listMake("Bone Spikes", 20)); - //skill_upgrade_order.listAppend(listMake("Arm Blade", 20)); - //skill_upgrade_order.listAppend(listMake("Healing Scarabs")); //only useful if it prevents beaten up from non-combats? - - foreach key in skill_upgrade_order - { - string [int] l = skill_upgrade_order[key]; - skill s = l[0].lookupSkill(); - int ka_cost = l[1].to_int_silent(); - string reason = l[2]; - if (s == $skill[none]) - break; - if (s.have_skill()) continue; - - - /*string line = "Could upgrade your body with " + s + "."; - if (ka_cost > ka.available_amount()) - line = HTMLGenerateSpanFont(line, "grey"); - description.listAppend(line);*/ - ka_table.listAppend(listMake(s, ka_cost, reason)); - break; - } - - if (ka_table.count() > 0) - { - foreach key in ka_table - { - int ka_needed = ka_table[key][1].to_int_silent(); - if (ka_needed > ka.available_amount()) - { - foreach key2 in ka_table[key] - { - ka_table[key][key2] = HTMLGenerateSpanFont(ka_table[key][key2], "grey"); - } - } - } - description.listAppend(HTMLGenerateSimpleTableLines(ka_table)); - } - - string url = ""; - string [int] places_to_farm_ka; - if (getHolidaysToday()["Halloween"]) - { - places_to_farm_ka.listAppend("trick or treating"); - url = "place.php?whichplace=town"; - } - if (__misc_state["spooky airport available"]) - { - places_to_farm_ka.listAppend("laboratory on conspiracy island"); - if (url.length() == 0) url = $location[the secret government laboratory].getClickableURLForLocation(); - } - if (__misc_state["hot airport available"]) - { - places_to_farm_ka.listAppend("smooch army HQ"); - if (url.length() == 0) url = $location[The SMOOCH Army HQ].getClickableURLForLocation(); - } - if (__misc_state["mysterious island available"] && !__quest_state["Level 12"].in_progress && my_level() < 9) //we test if we're under level 9 and the level 12 quest isn't in progress. maybe they ate a lot of hot dogs. it could happen! - { - places_to_farm_ka.listAppend("The Hippy Camp"); - if (url.length() == 0) url = $location[The Hippy Camp].getClickableURLForLocation(); - } - if (!__misc_state["mysterious island available"] && my_basestat($stat[mysticality]) < 40) - { - places_to_farm_ka.listAppend("sleazy back alley (last resort)"); - } - - if (places_to_farm_ka.count() > 0) - description.listAppend("Could farm ka in the " + places_to_farm_ka.listJoinComponents(", ", "or") + "."); - - resource_entries.listAppend(ChecklistEntryMake("__item ka coin", url, ChecklistSubentryMake(ka.pluralise(), "", description), 6).ChecklistEntrySetIDTag("UNDYING path spend ka coin")); - } - - if (true) - { - ChecklistSubentry [int] subentries; - string image_name = ""; - string [item] path_relevant_items; - - path_relevant_items[$item[talisman of Renenutet]] = "+lots% item in a single combat"; - path_relevant_items[$item[talisman of Horus]] = "+lots% combat potion"; - path_relevant_items[$item[ancient cure-all]] = "SGEEA-equivalent?"; - foreach s in $strings[linen bandages,cotton bandages,silk bandages] - { - if (lookupItem(s).available_amount() > 0) - { - path_relevant_items[lookupItem(s)] = "heal at zero HP"; - break; - } - } - foreach it, reason in path_relevant_items - { - if (it.available_amount() > 0) - { - subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", reason.capitaliseFirstLetter() + ".")); - if (image_name.length() == 0) - image_name = "__item " + it; - } - } - if (subentries.count() > 0) - resource_entries.listAppend(ChecklistEntryMake(image_name, "", subentries, 6).ChecklistEntrySetIDTag("UNDYING path ed special items resource")); - } - - if ($skill[Lash of the cobra].have_skill() && mafiaIsPastRevision(15553)) - { - int lashes_remaining = 30 - get_property_int("_edLashCount"); - if (lashes_remaining > 0) - { - string [int] description; - string [int] stealables; - //Stuff: - //snake +ML - //badge of authority (HC) - //warehouse - //barret, aerith - //pygmy witch lawyers - //filthworms - //war hippy drill sergeant - //war outfit (if wrath of ra not available) - //pirate outfit? specific monsters left - //hot wings from p imp / g imp - //beanbats (if unlocked, else batrats/ratbats, else guano junction) - //skeletons in the nook - //topiary animals in twin peak - //dusken raider ghost (if oil needed) - //oil cartel(?) - if (stealables.count() > 0) - description.listAppend("Steals a random item:|*" + stealables.listJoinComponents("|*")); - else - description.listAppend("Steals a random item."); - - resource_entries.listAppend(ChecklistEntryMake("__item cool whip", "", ChecklistSubentryMake(pluralise(lashes_remaining, "lash", "lashes") + " of the cobra left", "", description), 6).ChecklistEntrySetIDTag("UNDYING path cobra lash resource")); - } - } -} diff --git a/Source/relay/TourGuide/Paths/Avatar of Jarlsberg.ash b/Source/relay/TourGuide/Paths/Avatar of Jarlsberg.ash deleted file mode 100644 index f9f70e82..00000000 --- a/Source/relay/TourGuide/Paths/Avatar of Jarlsberg.ash +++ /dev/null @@ -1,90 +0,0 @@ -boolean PathJarlsbergGenerateStaff(ChecklistEntry entry, item staff, string property_name, string description, boolean always_output) -{ - if (staff.available_amount() == 0) - return false; - - - int uses_remaining = MAX(0, 5 - get_property_int(property_name)); - if (uses_remaining > 0 || always_output) - { - string title; - title = staff; - if (uses_remaining != 0) - { - title = uses_remaining + " " + staff.to_string().replace_string("Staff of the ", ""); - if (staff == $item[Staff of the Standalone Cheese]) - { - if (uses_remaining == 1) - title += " staff banish"; - else - title += " staff banishes"; - } - else - { - if (uses_remaining == 1) - title += " use"; - else - title += " uses"; - } - } - //description = pluraliseWordy(uses_remaining, "use remains", "uses remain").capitaliseFirstLetter() + ".|" + description; - entry.subentries.listAppend(ChecklistSubentryMake(title, "", description)); - if (entry.image_lookup_name == "") - entry.image_lookup_name = "__item " + staff; - return true; - } - return false; -} - - -RegisterResourceGenerationFunction("PathJarlsbergGenerateResource"); -void PathJarlsbergGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_AVATAR_OF_JARLSBERG) return; - - ChecklistEntry entry; - entry.tags.id = "Jarlsberg path staff resource"; - - - //wizard staff: - //Show uses: - //_jiggleCheesedMonsters split by | - - PathJarlsbergGenerateStaff(entry, $item[Staff of the All-Steak], "_jiggleSteak", "+300% items.", false); - - if (true) - { - string olfacted_monster = get_property("_jiggleCreamedMonster"); - boolean always_output = false; - string cream_line = "Monster olfaction"; - if (olfacted_monster != "") - { - always_output = true; - cream_line += "|Following a " + olfacted_monster.HTMLEscapeString() + "."; - } - PathJarlsbergGenerateStaff(entry, $item[Staff of the Cream of the Cream], "_jiggleCream", cream_line, always_output); - } - if (true) - { - //I must capture the avatar (of jarlsberg) to regain my honor - string [int] banished_monsters = split_string_alternate(get_property("_jiggleCheesedMonsters"), "\\|"); - boolean always_output = false; - string cheese_line = ""; - if (get_property("_jiggleCheesedMonsters") != "") - { - cheese_line += "Monsters banished: " + banished_monsters.listJoinComponents(", ", "and").HTMLEscapeString() + "."; - always_output = true; - } - - ChecklistEntry entry2; - boolean should_add = PathJarlsbergGenerateStaff(entry2, $item[Staff of the Standalone Cheese], "_jiggleCheese", cheese_line, always_output); - entry2.tags.id = "Jarlsberg path staff banish"; - entry2.tags.combination = "banish"; - if (should_add) - resource_entries.listAppend(entry2); - } - PathJarlsbergGenerateStaff(entry, $item[Staff of the Staff of Life], "_jiggleLife", "Restores all HP.", false); - - if (entry.subentries.count() > 0) - resource_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Paths/Avatar of Shadows over Loathing.ash b/Source/relay/TourGuide/Paths/Avatar of Shadows over Loathing.ash deleted file mode 100644 index cd82ae57..00000000 --- a/Source/relay/TourGuide/Paths/Avatar of Shadows over Loathing.ash +++ /dev/null @@ -1,117 +0,0 @@ -RegisterTaskGenerationFunction("PathShadowsOverLoathingGenerateTasks"); -void PathShadowsOverLoathingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (lookupSkill("Free-For-All").have_skill()) { - if ($effect[Everything Looks Red].have_effect() > 0) return; - string [int] description; - string main_title = HTMLGenerateSpanFont("Free-For-All castable", "red"); - description.listAppend("Free instakill (25 adv cooldown)"); - task_entries.listAppend(ChecklistEntryMake("__item orange boxing gloves", "", ChecklistSubentryMake(main_title, "", description), -11)); - } - else if (lookupSkill("Fondeluge").have_skill()) { - if ($effect[Everything Looks Yellow].have_effect() > 0) return; - string [int] description; - string main_title = HTMLGenerateSpanFont("Fondeluge castable", "orange"); - description.listAppend("Free YR (50 adv cooldown)"); - task_entries.listAppend(ChecklistEntryMake("__skill fondeluge", "", ChecklistSubentryMake(main_title, "", description), -11)); - } - else if (lookupSkill("Motif").have_skill()) { - if ($effect[Everything Looks Blue].have_effect() > 0) return; - string [int] description; - string main_title = HTMLGenerateSpanFont("Motif castable", "blue"); - description.listAppend("Olfact (25 adv cooldown)"); - task_entries.listAppend(ChecklistEntryMake("__skill Motif", "", ChecklistSubentryMake(main_title, "", description), -11)); - } -} - -record CursedItem { - item theItem; - monster boss; - string description; - boolean shouldDisplay; - boolean valuableToGooseDupe; -}; - -void showCursedItemsResourceTile(ChecklistEntry [int] resource_entries) { - CursedItem [int] cursedItems = { - new CursedItem( - $item[cursed goblin cape], - $monster[goblin king's shadow], - "-15% combat!", - __quest_state["Knob Goblin King"].finished != true, - false - ), - new CursedItem( - $item[cursed bat paw], - $monster[two-headed shadow bat], - "+25 ML", - __quest_state["Boss Bat"].finished != true, - true - ), - new CursedItem( - $item[cursed dragon wishbone], - $monster[shadowboner shadowdagon], - "+50% item", - __quest_state["Cyrpt"].finished != true, - true - ), - new CursedItem( - $item[cursed blanket], - $monster[shadow of groar], - "+3 res", - __quest_state["Trapper"].finished != true, - false - ), - new CursedItem( - $item[cursed machete], - $monster[corruptor shadow], - "+50% meat", - __quest_state["Level 11 Hidden City"].finished != true, - false - ), - new CursedItem( - $item[cursed medallion], - $monster[shadow of the 1960s], - "+100% init", - __quest_state["Island War"].finished != true, - false - ) - }; - - string [int] description; - foreach index, cursedItem in cursedItems { - if (cursedItem.shouldDisplay) { - string goose = cursedItem.valuableToGooseDupe ? "🦢 " : ""; - description.listAppend(`{goose}{HTMLGenerateSpanOfClass(cursedItem.boss.name, "r_bold")}: {cursedItem.description}`); - } - } - - if (count(description) > 0) { - resource_entries.listAppend(ChecklistEntryMake("__monster shadow prism", "", ChecklistSubentryMake("Cursed boss drops", "consider duping the items with 🦢", description), 2).ChecklistEntrySetIDTag("Avatar of Shadows Over Loathing cursed items resource")); - } -} - -void showDecurseResourceTile(ChecklistEntry [int] resource_entries) { - int fastenersNeeded = __quest_state["Level 9"].state_int["bridge fasteners needed"]; - int lumberNeeded = __quest_state["Level 9"].state_int["bridge lumber needed"]; - boolean needBridgeParts = __quest_state["Level 9"].mafia_internal_step == 1 && // Bridge not complete yet - (fastenersNeeded > 0 || lumberNeeded > 0 ); // And we need some parts - boolean shouldDecurseBatPaw = my_level() >= 12 && - __quest_state["Cyrpt"].finished == true && - __quest_state["Typical Tavern"].finished == true && - needBridgeParts && - $item[uncursed bat paw].available_amount() < 1; - - if (shouldDecurseBatPaw) { - string description = `{HTMLGenerateSpanOfClass("cursed bat paw", "r_bold")} to get -ML for bridge parts!`; - resource_entries.listAppend(ChecklistEntryMake("__item uncursed bat paw", "", ChecklistSubentryMake("Useful items to decurse", "", description), 0).ChecklistEntrySetIDTag("Avatar of Shadows Over Loathing decurse resource")); - } -} - -RegisterResourceGenerationFunction("PathShadowsOverLoathingGenerateResource"); -void PathShadowsOverLoathingGenerateResource(ChecklistEntry [int] resource_entries) { - if (my_path() != $path[Avatar of Shadows Over Loathing]) return; - - showCursedItemsResourceTile(resource_entries); - showDecurseResourceTile(resource_entries); -} diff --git a/Source/relay/TourGuide/Paths/Avatar of Sneaky Pete.ash b/Source/relay/TourGuide/Paths/Avatar of Sneaky Pete.ash deleted file mode 100644 index 6ab22e9e..00000000 --- a/Source/relay/TourGuide/Paths/Avatar of Sneaky Pete.ash +++ /dev/null @@ -1,288 +0,0 @@ - - -RegisterResourceGenerationFunction("PathSneakyPeteGenerateResource"); -void PathSneakyPeteGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_AVATAR_OF_SNEAKY_PETE || !mafiaIsPastRevision(13785)) return; - - - ChecklistEntry entry; - entry.tags.id = "Sneaky Pete path skills resource"; - entry.importance_level = 1; - - if (true) - { - int total_free_peel_outs_available = 10; - if (get_property("peteMotorbikeTires") == "Racing Slicks") - total_free_peel_outs_available += 20; - - int free_peel_outs_available = MAX(0, total_free_peel_outs_available - get_property_int("_petePeeledOut")); - - if ($skill[Peel Out].skill_is_usable() && free_peel_outs_available > 0) - { - if (entry.image_lookup_name.length() == 0) - entry.image_lookup_name = "__skill Easy Riding"; - - ChecklistSubentry subentry = ChecklistSubentryMake(pluralise(free_peel_outs_available, "peel out", "peel outs"), "10 MP/cast", listMakeBlankString()); - - if (get_property("peteMotorbikeMuffler") == "Extra-Smelly Muffler") - { - subentry.entries.listAppend("Free runaway/banish in-combat."); - TagGroup tags; - tags.id = "Sneaky Pete path peel out banish"; - tags.combination = "banish"; - resource_entries.listAppend(ChecklistEntryMake("__skill Easy Riding", "", subentry, tags)); - } - else - { - subentry.entries.listAppend("Free runaway in-combat."); - entry.subentries.listAppend(subentry); - } - } - } - - if ($skill[Fix Jukebox].skill_is_usable() && get_property_int("_peteJukeboxFixed") < 3) - { - int uses_remaining = MAX(0, 3 - get_property_int("_peteJukeboxFixed")); - - string [int] description; - description.listAppend("+300% item, one combat."); - description.listAppend("+10 audience love."); - - if (entry.image_lookup_name.length() == 0) - entry.image_lookup_name = "__effect jukebox hero"; - - string [int] targets; - //√banshee, √a batrat for sonar, √harem girl (contested), √burly sidekick, √quiet healer, √filthworms, √f'c'le without natural dancer, √a-boo clues - if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && !__quest_state["Level 11 Desert"].state_boolean["Killing Jar Given"] && $item[killing jar].available_amount() == 0) - targets.listAppend("Haunted Library - Banshee - Killing Jar to speed up desert exploration."); - if (__quest_state["Level 4"].state_int["areas unlocked"] + $item[sonar-in-a-biscuit].available_amount() < 3) - targets.listAppend("Batrat/Ratbat - Sonar-in-a-biscuit."); - - if (!have_outfit_components("Knob Goblin Elite Guard Uniform") && !have_outfit_components("Knob Goblin Harem Girl Disguise") && !__quest_state["Level 5"].finished) - targets.listAppend("Harem Girl - disguise for quest. (20% drop)"); - - if (!__quest_state["Level 10"].finished && $item[mohawk wig].available_amount() == 0 && $item[s.o.c.k.].available_amount() == 0) - targets.listAppend("Burly Sidekick (Mohawk wig) - speed up top floor of castle."); - if ($item[amulet of extreme plot significance].available_amount() == 0 && !__quest_state["Level 10"].finished && !$location[The Castle in the Clouds in the Sky (Ground floor)].locationAvailable() && $item[s.o.c.k.].available_amount() == 0) - targets.listAppend("Quiet Healer (amulet of extreme plot significance) - speed up castle basement."); - if (!__quest_state["Level 12"].state_boolean["Orchard Finished"]) - targets.listAppend("Filthworms."); - - if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0 && $item[a-boo clue].available_amount() < 3) - targets.listAppend("A-Boo Peak - a-boo clues. (15% drop)"); - - if (targets.count() > 0) - description.listAppend("Potential targets:|*" + targets.listJoinComponents("
|*")); - - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(uses_remaining, "jukebox fix", "jukebox fixes"), "25 MP", description)); - } - - if ($skill[Jump Shark].skill_is_usable() && get_property_int("_peteJumpedShark") < 3) - { - int uses_remaining = MAX(0, 3 - get_property_int("_peteJumpedShark")); - - string [int] description; - description.listAppend((10 * my_level()) + " muscle/mysticality/moxie. (increases with level)"); - description.listAppend("+10 audience hate."); - - if (entry.image_lookup_name.length() == 0) - entry.image_lookup_name = "__skill jump shark"; - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(uses_remaining, "shark jump", "shark jumps"), "25 MP", description)); - } - - - if (entry.subentries.count() > 0) - resource_entries.listAppend(entry); -} - -RegisterTaskGenerationFunction("PathSneakyPeteGenerateTasks"); -void PathSneakyPeteGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_AVATAR_OF_SNEAKY_PETE || !mafiaIsPastRevision(13785)) return; - - - if (true) - { - string [int] parts_not_upgraded; - int motorcycle_upgrades_have = 0; - - foreach s in $strings[peteMotorbikeTires,peteMotorbikeGasTank,peteMotorbikeHeadlight,peteMotorbikeCowling,peteMotorbikeMuffler,peteMotorbikeSeat] - { - if (get_property(s) != "") - motorcycle_upgrades_have += 1; - else - parts_not_upgraded.listAppend(s); - } - int motorcycle_upgrades_available = MIN(6, my_level() / 2); - - if (motorcycle_upgrades_have < motorcycle_upgrades_available) - { - string [int] description; - description.listAppend(pluralise(motorcycle_upgrades_available - motorcycle_upgrades_have, "upgrade", "upgrades") + " available."); - - string [int] upgrades; - foreach key in parts_not_upgraded - { - string property_name = parts_not_upgraded[key]; - - string name = ""; - string [int] options; - - if (property_name == "peteMotorbikeSeat") - { - name = "Seat"; - - options.listAppend("regenerate 5-6 HP/MP"); - options.listAppend("find meat after combat (marginal)"); - options.listAppend("-30 ML (harmful)"); - } - else if (property_name == "peteMotorbikeCowling") - { - name = "Cowling"; - if (__quest_state["Level 7"].state_int["alcove evilness"] > 26 || __quest_state["Level 7"].state_int["cranny evilness"] > 26 || __quest_state["Level 7"].state_int["niche evilness"] > 26 || __quest_state["Level 7"].state_int["nook evilness"] > 26) - options.listAppend("faster cyrpt"); - if (__quest_state["Level 12"].finished) - options.listAppend("passive +damage/round"); - else - options.listAppend("passive +damage/round and +3 war kills"); - options.listAppend("+5 stats/fight"); - } - else if (property_name == "peteMotorbikeGasTank") - { - name = "Gas tank"; - - if (!knoll_available() && !__misc_state["desert beach available"]) - options.listAppend("desert beach access"); - if (!__misc_state["mysterious island available"]) - options.listAppend("mysterious island access"); - options.listAppend("+50% combat initiative"); - } - else if (property_name == "peteMotorbikeHeadlight") - { - name = "Headlight"; - - if ($skill[Flash Headlight].skill_is_usable()) - { - options.listAppend("yellow ray from flash headlight"); - options.listAppend("prismatic damage from flash headlight"); - } - else - { - options.listAppend("yellow ray (need flash headlight)"); - options.listAppend("prismatic damage (need flash headlight)"); - } - if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"]) - options.listAppend("+2% desert exporation"); - } - else if (property_name == "peteMotorbikeMuffler") - { - name = "Muffler"; - if ($skill[Rev Engine].skill_is_usable()) - { - options.listAppend("+combat% from rev engine"); - options.listAppend("-combat% from rev engine"); - } - else - { - options.listAppend("+X% combat from rev engine (need skill)"); - options.listAppend("-X% combat from rev engine (need skill)"); - } - if ($skill[Peel Out].skill_is_usable()) - options.listAppend("peel out banishes"); - else - options.listAppend("peel out banishes (need skill)"); - } - else if (property_name == "peteMotorbikeTires") - { - name = "Tires"; - if ($skill[Peel Out].skill_is_usable()) - options.listAppend("extra free runs with peel out"); - else - options.listAppend("extra free runs (need peel out)"); - if ($skill[Pop Wheelie].skill_is_usable()) - options.listAppend("pop wheelie does more damage"); - else - options.listAppend("pop wheelie does more damage (need skill)"); - - if (!__quest_state["Level 8"].state_boolean["Mountain climbed"]) - options.listAppend("near-instant level 8 quest completion"); - } - - if (name != "") - { - upgrades.listAppend(HTMLGenerateSpanOfClass(name, "r_bold") + " - " + options.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); - //upgrades.listAppend(HTMLGenerateSpanOfClass(name, "r_bold") + "|*" + options.listJoinComponents("|*")); - } - } - description.listAppendList(upgrades); - - - optional_task_entries.listAppend(ChecklistEntryMake("__skill Easy Riding", "main.php?action=motorcycle", ChecklistSubentryMake("Upgrade your bike", "", description), 11).ChecklistEntrySetIDTag("Sneaky Pete path upgrade motorcycle")); - } - } - - if ($skill[Check Mirror].skill_is_usable()) - { - boolean have_intrinsic = false; - foreach s in $strings[1553,Pompadour,Cowlick,Fauxhawk] - { - effect e = s.lookupEffect(); - if (e == $effect[none]) - { - have_intrinsic = true; //can't track - continue; - } - if (e.have_effect() == 2147483647) - have_intrinsic = true; - } - if (!have_intrinsic) - { - string [int] description; - - description.listAppend("One adventure cost for an intrinsic."); - string [int] options; - options.listAppend("+3 all resistances (slicked-back do)"); - options.listAppend("+3 stats/fight (best, pompadour)"); - if (my_audience() >= 20) - options.listAppend("+50% meat (cowlick)"); - else - options.listAppend(HTMLGenerateSpanFont("+50% meat (requires 20 love)", "grey")); - if (my_audience() <= -20) - options.listAppend("+50% init (fauxhawk)"); - else - options.listAppend(HTMLGenerateSpanFont("+50% init (requires 20 hate)", "grey")); - - //description.listAppend("Potential options:|*|*|*+|*"); - description.listAppend("Potential options:|*" + options.listJoinComponents("|*")); - optional_task_entries.listAppend(ChecklistEntryMake("__skill Check Mirror", "skills.php", ChecklistSubentryMake("Check mirror", "", description), 11).ChecklistEntrySetIDTag("Sneaky Pete path mirror")); - } - } - int audience_max = 30; - if ($item[Sneaky Pete's leather jacket].equipped_amount() > 0 || $item[Sneaky Pete's leather jacket (collar popped)].equipped_amount() > 0) - { - audience_max = 50; - } - if ($skill[Throw Party].skill_is_usable() && my_audience() == audience_max && !get_property_boolean("_petePartyThrown")) - task_entries.listAppend(ChecklistEntryMake("__item party hat", "skills.php", ChecklistSubentryMake("Throw a party!", "", "Drinks."), -11).ChecklistEntrySetIDTag("Sneaky Pete path party andience")); - if ($skill[Incite Riot].skill_is_usable() && my_audience() == -audience_max && !get_property_boolean("_peteRiotIncited")) - task_entries.listAppend(ChecklistEntryMake("__item fire", "skills.php", ChecklistSubentryMake("Incite a riot", "", "Breaking the law, breaking the law."), -11).ChecklistEntrySetIDTag("Sneaky Pete path riot audience")); - - //sneakyPetePoints first - int skills_available = MIN(30, MIN(15, my_level()) + get_property_int("sneakyPetePoints")); - - int skills_have = 0; - //foreach s in lookupSkills("Catchphrase,Mixologist,Throw Party,Fix Jukebox,Snap Fingers,Shake It Off,Check Hair,Cocktail Magic,Make Friends,Natural Dancer,Rev Engine,Born Showman,Pop Wheelie,Rowdy Drinker,Peel Out,Easy Riding,Check Mirror,Riding Tall,Biker Swagger,Flash Headlight,Insult,Live Fast,Incite Riot,Jump Shark,Animal Magnetism,Smoke Break,Hard Drinker,Unrepentant Thief,Brood,Walk Away From Explosion") - foreach s in lookupSkillsInt($ints[15027,15019,15012,15028,15001,15007,15017,15008,15016,15004,15020,15025,15031,15021,15024,15023,15009,15002,15010,15015,15013,15011,15018,15014,15006,15026,15005,15003,15032,15030]) - { - if (s.skill_is_usable()) - skills_have += 1; - } - - if (skills_available > skills_have) - { - string [int] description; - description.listAppend("At least " + pluraliseWordy(skills_available - skills_have, "skill", "skills") + " available."); - optional_task_entries.listAppend(ChecklistEntryMake("__skill Natural Dancer", "da.php?place=gate3", ChecklistSubentryMake("Buy Sneaky Pete skills", "", description), 11).ChecklistEntrySetIDTag("Sneaky Pete path new skills")); - } -} diff --git a/Source/relay/TourGuide/Paths/Avatar of West of Loathing.ash b/Source/relay/TourGuide/Paths/Avatar of West of Loathing.ash deleted file mode 100644 index f3900aa4..00000000 --- a/Source/relay/TourGuide/Paths/Avatar of West of Loathing.ash +++ /dev/null @@ -1,203 +0,0 @@ - -RegisterResourceGenerationFunction("PathAvatarOfWestOfLoathingGenerateResource"); -void PathAvatarOfWestOfLoathingGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING && !($classes[snake oiler,beanslinger,cow puncher] contains my_class())) return; - - //Oils: - string image_name = ""; - ChecklistSubentry [int] subentries; - - if (mafiaIsPastRevision(16881) && $skill[Extract Oil].have_skill()) - { - int oils_extracted = get_property_int("_oilExtracted"); - int oils_remaining = clampi(15 - oils_extracted, 0, 15); - if (oils_extracted < 15) - { - string description; - if (oils_extracted >= 5) - { - int percentage_left = clampi(100 - (oils_extracted - 5) * 10, 0, 100); - description = percentage_left + "% chance."; - } - item monster_oil_type = lookupAWOLOilForMonster(last_monster()); - if (monster_oil_type != $item[none]) - { - if (description != "") - description += " "; - description += monster_oil_type.capitaliseFirstLetter() + " against " + last_monster() + "."; - } - if (image_name == "") - image_name = "__item Snake oil"; - subentries.listAppend(ChecklistSubentryMake(pluralise(oils_remaining, "extractable oil", "extractable oils"), "", description)); - } - } - float [int] subentries_sort_value; - - string [item] tonic_descriptions; - tonic_descriptions[$item[Eldritch oil]] = "craftable"; - tonic_descriptions[$item[Unusual oil]] = "+50% item (20 turns), craftable"; - tonic_descriptions[$item[Skin oil]] = "+100% moxie (20 turns), craftable"; - tonic_descriptions[$item[Snake oil]] = "+venom/medicine, craftable"; - - tonic_descriptions[$item[patent alacrity tonic]] = "+100% init (20 turns)"; //eldritch + unusual - tonic_descriptions[$item[patent sallowness tonic]] = "+30 ML (50 turns)"; //eldritch + skin - tonic_descriptions[$item[patent avarice tonic]] = "+50% meat (30 turns)"; //skin + unusual - tonic_descriptions[$item[patent invisibility tonic]] = "-15% combat (30 turns)"; //eldritch + snake - tonic_descriptions[$item[patent aggression tonic]] = "+15% combat (30 turns)"; //unusual + snake - tonic_descriptions[$item[patent preventative tonic]] = "+3 all res (30 turns)"; //skin + snake - - foreach it in tonic_descriptions - { - if (it.available_amount() == 0 && it.creatable_amount() == 0) - continue; - - string description = tonic_descriptions[it]; - if (image_name == "") - image_name = "__item " + it; - string name; - if (it.available_amount() > 0) - name = pluralise(it); - if (it.creatable_amount() > 0) - { - if (it.available_amount() != 0) - name += " (" + it.creatable_amount() + " craftable)"; - else - name = pluralise(it.creatable_amount(), "craftable " + it, "craftable " + it.plural); - } - if (it.available_amount() == 0) - { - subentries_sort_value[subentries.count()] = 1.0; - name = HTMLGenerateSpanFont(name, "grey"); - description = HTMLGenerateSpanFont(description, "grey"); - } - else - { - subentries_sort_value[subentries.count()] = 0.0; - } - subentries.listAppend(ChecklistSubentryMake(name, "", description)); - } - sort subentries by subentries_sort_value[index]; - if (subentries.count() > 0) - resource_entries.listAppend(ChecklistEntryMake(image_name, "", subentries, 2).ChecklistEntrySetIDTag("West Loathing path oils resource")); - - - //Should we display beancannon in aftercore? I guess we could suggest a cheap source of it...? Maybe another time. - if ($skill[Beancannon].have_skill() && in_ronin()) - { - string [int] banish_sources; - int banish_count = 0; - int equipped_amount = 0; - foreach it in __beancannon_source_items - { - if (it.available_amount() == 0) - continue; - banish_count += it.available_amount(); - string description = it; - if (it.available_amount() > 1) - description = it.pluralise(); - equipped_amount += it.equipped_amount(); - banish_sources.listAppend(description); - } - if (banish_count > 0 || !in_ronin()) - { - string [int] description; - if (banish_sources.count() > 0) - description.listAppend("From " + banish_sources.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - string url = ""; - if (equipped_amount == 0) - { - description.listAppend("Equip one before banishing."); - url = "inventory.php?which=2"; - } - string title = pluralise(banish_count, "beancannon banish", "beancannon banishes"); - if (!in_ronin()) - title = "Beancannon banishes"; - resource_entries.listAppend(ChecklistEntryMake("__skill beancannon", url, ChecklistSubentryMake(title, "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("West Loathing path beancannon banish")); - } - } - - if ($skill[Long Con].have_skill() && mafiaIsPastRevision(16812) && get_property_int("_longConUsed") < 5) - { - int uses_remaining = clampi(5 - get_property_int("_longConUsed"), 0, 5); - string [int] description; - string line = "Olfaction."; - description.listAppend(line); - resource_entries.listAppend(ChecklistEntryMake("__effect Greaser Lightnin'", "", ChecklistSubentryMake(pluralise(uses_remaining, "long con", "long cons") + " remaining", "", description), 8).ChecklistEntrySetIDTag("West Loathing path long con resource")); - } -} - - -RegisterTaskGenerationFunction("PathAvatarOfWestOfLoathingGenerateTasks"); -void PathAvatarOfWestOfLoathingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) - return; - string skill_url; - ChecklistSubentry [int] skill_subentries; - - int [class] class_points; - class_points[my_class()] = my_level(); - class_points[$class[Cow Puncher]] += get_property_int("awolPointsCowpuncher"); - class_points[$class[Beanslinger]] += get_property_int("awolPointsBeanslinger"); - class_points[$class[Snake Oiler]] += get_property_int("awolPointsSnakeoiler"); - - item [class] tale_for_class; - tale_for_class[$class[Cow Puncher]] = $item[Tales of the West: Cow Punching]; - tale_for_class[$class[Beanslinger]] = $item[Tales of the West: Beanslinging]; - tale_for_class[$class[Snake Oiler]] = $item[Tales of the West: Snake Oiling]; - - boolean [class] have_advanced_skills_for_class; - if ($skill[Unleash Cowrruption].have_skill() || $skill[[18008]Hard Drinker].have_skill() || $skill[Walk: Cautious Prowl].have_skill()) - have_advanced_skills_for_class[$class[Cow Puncher]] = true; - if ($skill[Beancannon].have_skill() || $skill[Prodigious Appetite].have_skill() || $skill[Walk: Prideful Strut].have_skill()) - have_advanced_skills_for_class[$class[Beanslinger]] = true; - if ($skill[Long Con].have_skill() || $skill[Tolerant Constitution].have_skill() || $skill[Walk: Leisurely Amble].have_skill()) - have_advanced_skills_for_class[$class[Snake Oiler]] = true; - float priority = 0; - foreach c in class_points - { - int total_points_available = class_points[c]; - if (total_points_available == 0) - continue; - - int class_skills_learned = 0; - foreach key, s in __skills_by_class[c] - { - if (s.have_skill()) - class_skills_learned += 1; - } - if (class_skills_learned >= 10) - continue; - - int skills_left_to_learn = total_points_available - class_skills_learned; - if (skills_left_to_learn <= 0) - continue; - - int limit = 7; //theoretically, they might be unable to learn the advanced skills, so only make this a priority if we're under that or know we have advanced skills - if (have_advanced_skills_for_class[c]) - limit = 10; - if (class_skills_learned < limit) - priority = -11; - item tale = tale_for_class[c]; - - string title = "Learn a " + c + " skill"; - if (skills_left_to_learn > 1) - title = "Learn " + skills_left_to_learn.int_to_wordy() + " " + c + " skills"; - if (skill_url == "") - { - skill_url = "inv_use.php?pwd=" + my_hash() + "&whichitem=" + tale.to_int(); - } - skill_subentries.listAppend(ChecklistSubentryMake(title, "", "Use " + tale + ".")); - } - - if (skill_subentries.count() > 0) - { - task_entries.listAppend(ChecklistEntryMake("__item tales of the west: beanslinging", skill_url, skill_subentries, priority).ChecklistEntrySetIDTag("West Loathing path new skills")); - } - - if (my_class() == $class[Cow Puncher] && $item[corrupted marrow].available_amount() > 0 && $item[corrupted marrow].to_effect().have_effect() < 100 && in_ronin()) - { - task_entries.listAppend(ChecklistEntryMake("__effect Cowrruption", "inventory.php?ftext=corrupted+marrow", ChecklistSubentryMake("Use corrupted marrow", "", "+200% weapon damage/spell damage"), -11).ChecklistEntrySetIDTag("West Loathing path cow puncher corrupted marrow")); - } -} diff --git a/Source/relay/TourGuide/Paths/Bad Moon.ash b/Source/relay/TourGuide/Paths/Bad Moon.ash deleted file mode 100644 index ce81f7f2..00000000 --- a/Source/relay/TourGuide/Paths/Bad Moon.ash +++ /dev/null @@ -1,544 +0,0 @@ - -import "relay/TourGuide/QuestState.ash" -import "relay/TourGuide/Support/LocationAvailable.ash" - -Record BadMoonAdventure -{ - int encounter_id; - string category; - string description; - string conditions_to_finish; - boolean has_additional_requirements_not_yet_met; - location [int] locations; -}; - -BadMoonAdventure BadMoonAdventureMake(int encounter_id, location [int] locations, string category, string description, string conditions_to_finish, boolean has_additional_requirements_not_yet_met) -{ - BadMoonAdventure adventure; - adventure.encounter_id = encounter_id; - adventure.category = category; - adventure.description = description; - adventure.conditions_to_finish = conditions_to_finish; - adventure.has_additional_requirements_not_yet_met = has_additional_requirements_not_yet_met; - adventure.locations = locations; - return adventure; -} - -BadMoonAdventure BadMoonAdventureMake(int encounter_id, location l, string category, string description, string conditions_to_finish, boolean has_additional_requirements_not_yet_met) -{ - location [int] locations; - locations.listAppend(l); - return BadMoonAdventureMake(encounter_id, locations, category, description, conditions_to_finish, has_additional_requirements_not_yet_met); -} - -void listAppend(BadMoonAdventure [int] list, BadMoonAdventure entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - - -/* -Categories: -DAMAGE1 -DAMAGE2 -ELEMENTALDAMAGE1 - +10 elemental damage, -2 DR -ELEMENTALDAMAGE2 - +20 elemental damage, - ~2 HP/round -DAMAGE_REDUCTION - +DR, -8 weapon damage -Familiar Hatchlings - -ITEM_DROP -ITEMS -meat -MEAT_DROP -RESIST1 -RESIST2 -SKILLS -STAT1 - +20 one stat, -5 two other stats -STAT2 - +40 one stat, -50% familiar weight -STAT3 - +50% one stat, -50% other stat -*/ -static -{ - BadMoonAdventure [int] __static_bad_moon_adventures; - BadMoonAdventure [location] __static_bad_moon_adventures_by_location; - void initialiseStaticBadMoonAdventures() - { - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(2, $location[The Haunted Pantry], "STAT1", "+20 myst, -5 muscle/moxie", "", false)); //FIXME is there a conditional on this? - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(3, $location[The Sleazy Back Alley], "STAT1", "+20 moxie, -5 myst/muscle", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(4, $location[Cobb's Knob Treasury], "STAT2", "+40 muscle, -50% familiar weight", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(5, $location[Cobb's Knob Kitchens], "STAT2", "+40 myst, -50% familiar weight", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(6, $location[Cobb's Knob Harem], "STAT2", "+40 moxie, -50% familiar weight", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(7, $location[The Orcish Frat House], "STAT3", "+50% muscle, -50% myst", "", false)); - // __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(8, $location[Frat House In Disguise], "STAT3", "+50% muscle, -50% moxie", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(8, fratHouseInDisguise(), "STAT3", "+50% muscle, -50% moxie", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(9, $location[The Hippy Camp], "STAT3", "+50% myst, -50% moxie", "", false)); - // __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(10, $location[Hippy Camp In Disguise], "STAT3", "+50% myst, -50% muscle", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(10, hippyCampInDisguise(), "STAT3", "+50% myst, -50% muscle", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(11, $location[The Obligatory Pirate's Cove], "STAT3", "+50% moxie, -50% muscle", "", false)); - //12 is gone? was: The Obligatory Pirate's Cove (In Disguise) //retired - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(15, $location[The Haunted Kitchen], "ELEMENTALDAMAGE1", "+10 " + HTMLGenerateElementSpanDesaturated($element[hot]) + " damage, -2 DR", "", false)); - //__static_bad_moon_adventures.listAppend(BadMoonAdventureMake(17, $location[The Haunted Library], "ELEMENTALDAMAGE1", "+10 " + HTMLGenerateElementSpanDesaturated($element[spooky]) + " damage, -2 DR", "", false)); //retired - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(18, $location[Guano Junction], "ELEMENTALDAMAGE1", "+10 " + HTMLGenerateElementSpanDesaturated($element[stench]) + " damage, -2 DR", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(20, $location[The Icy Peak], "ELEMENTALDAMAGE2", "+20 " + HTMLGenerateElementSpanDesaturated($element[cold]) + " damage, ~2 HP lost/round", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(28, $location[Tower Ruins], "RESIST1", "+2 " + HTMLGenerateElementSpanDesaturated($element[spooky], "res") + ", 2x damage from stench/hot", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(32, $location[Cobb's Knob Laboratory], "ITEM_DROP", "+50% item, -5 stats/fight", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(33, $location[The Haunted Bathroom], "ITEM_DROP", "+100% item, -20 all stats", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(34, $location[The Unquiet Garves], "MEAT_DROP", "+50% meat, -50% init", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(35, $location[The VERY Unquiet Garves], "MEAT_DROP", "+200% meat, -50% item", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(38, $location[the spooky forest], "meat", "1000 meat", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(41, $location[south of the border], "meat", "4000 meat, beaten up", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(43, $location[Noob Cave], "Familiar Hatchlings", "Black cat hatchling, 14 drunkenness", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(46, $location[A Barroom Brawl], "Familiar Hatchlings", "Leprechaun hatchling, one drunkenness", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(47, $location[The Hidden Temple], "ITEMS", "Loaded dice", "", false)); - __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(48, $location[The Haunted Conservatory], "Familiar Hatchlings", "Potato sprout", "", false)); - } - initialiseStaticBadMoonAdventures(); -} - -//FIXME make this work in scripts that aren't guide -//We should probably have an "invalidate caches" message that happens whenever state may have changed. -//Maybe a global variable in the library that's incremented by one, and caches check themselves against that. -//Querying that variable would be through a function, so it automatically increments by one if the turncount changes. - -BadMoonAdventure [int] __all_bad_moon_adventures_cache; -int __all_bad_moon_adventures_cache_on_turn = -1; -BadMoonAdventure [int] AllBadMoonAdventures() -{ - if (__all_bad_moon_adventures_cache.count() > 0 && __all_bad_moon_adventures_cache_on_turn == my_turncount()) - return __all_bad_moon_adventures_cache; - BadMoonAdventure [int] adventures; - - foreach key, adventure in __static_bad_moon_adventures - { - adventures.listAppend(adventure); - } - - adventures.listAppend(BadMoonAdventureMake(39, $location[the degrassi knoll garage], "meat", "2000 meat, -myst debuff", "finish meatcar guild quest", !QuestState("questG01Meatcar").finished)); - adventures.listAppend(BadMoonAdventureMake(40, $location[the bat hole entrance], "meat", "3000 meat, -moxie debuff", "open boss bat's lair", __quest_state["Level 4"].state_int["areas unlocked"] < 3)); - - adventures.listAppend(BadMoonAdventureMake(1, $location[the Outskirts of Cobb's Knob], "STAT1", "+20 muscle, -5 myst/moxie", "find encryption key", $item[knob goblin encryption key].available_amount() == 0 && !$location[cobb's knob kitchens].locationAvailable())); - //adventures.listAppend(BadMoonAdventureMake(13, $location[The Haunted Billiards Room], "DAMAGE1", "+10 damage, -2 DR", "open the Haunted Library", !$location[the haunted library].locationAvailable())); //retired - //adventures.listAppend(BadMoonAdventureMake(14, $location[The Goatlet], "ELEMENTALDAMAGE1", "+10 " + HTMLGenerateElementSpanDesaturated($element[cold]) + " damage, -2 DR", "unlock the eXtreme Slope", !$location[the extreme slope].locationAvailable())); //retired - adventures.listAppend(BadMoonAdventureMake(16, $location[Pandamonium Slums], "ELEMENTALDAMAGE1", "+10 " + HTMLGenerateElementSpanDesaturated($element[sleaze]) + " damage, -2 DR", "get Steel Margarita", !QuestState("questM10Azazel").finished)); - //adventures.listAppend(BadMoonAdventureMake(19, $location[The Castle in the Clouds in the Sky (somewhere)], "DAMAGE2", "+20 melee damage, ~2 HP lost/round", "completed trash quest", REPLACEMEB)); //retired - //adventures.listAppend(BadMoonAdventureMake(21, $location[Oasis], "ELEMENTALDAMAGE2", "+20 " + HTMLGenerateElementSpanDesaturated($element[hot]) + " damage, ~2 HP lost/round", "find worm-riding hooks", REPLACEMEB)); //seems retired - adventures.listAppend(BadMoonAdventureMake(22, $location[The Hole in the Sky], "ELEMENTALDAMAGE2", "+20 " + HTMLGenerateElementSpanDesaturated($element[sleaze]) + " damage, ~2 HP lost/round", "make Richard's star key", $item[richard's star key].available_amount() == 0)); - //adventures.listAppend(BadMoonAdventureMake(23, $location[The Haunted Ballroom], "ELEMENTALDAMAGE2", "+20 " + HTMLGenerateElementSpanDesaturated($element[spooky]) + " damage, ~2 HP lost/round", "open Spookyraven basement", !$location[the haunted wine cellar].locationAvailable())); //retired - //adventures.listAppend(BadMoonAdventureMake(24, $location[The Black Forest], "ELEMENTALDAMAGE2", "+20 " + HTMLGenerateElementSpanDesaturated($element[stench]) + " damage, ~2 HP lost/round", "open black market", !black_market_available())); //retired - adventures.listAppend(BadMoonAdventureMake(25, $location[Inside the Palindome], "RESIST1", "+2 " + HTMLGenerateElementSpanDesaturated($element[cold], "res") + ", 2x damage from hot/spooky", "defeat Dr. Awkward", !QuestState("questL11Palindome").finished)); - //adventures.listAppend(BadMoonAdventureMake(26, $location[REPLACEME], "RESIST1", "+2 " + HTMLGenerateElementSpanDesaturated($element[hot], "res") + ", 2x damage from stench/sleaze", "REASONWHYNOTREPLACEME", REPLACEMEB)); //Pot-Unlucky - UNKNOWN //retired - adventures.listAppend(BadMoonAdventureMake(27, $location[The Valley of Rof L'm Fao], "RESIST1", "+2 " + HTMLGenerateElementSpanDesaturated($element[sleaze], "res") + ", 2x damage from cold/spooky", "acquire facsimile dictionary", $item[facsimile dictionary].available_amount() == 0)); - //adventures.listAppend(BadMoonAdventureMake(29, $location[The Arid, Extra-Dry Desert], "RESIST1", "+2 " + HTMLGenerateElementSpanDesaturated($element[stench], "res") + ", 2x damage from cold/sleaze", "need to have ultrahydrated", $effect[ultrahydrated].have_effect() > 0)); //retired - adventures.listAppend(BadMoonAdventureMake(30, $location[the Beanbat Chamber], "RESIST2", "+1 all res, -10% stats", "plant beanstalk", !__quest_state["Level 10"].state_boolean["beanstalk grown"])); - //adventures.listAppend(BadMoonAdventureMake(31, $location[The Haunted Wine Cellar], "RESIST2", "+2 all res, -20% stats", "defeat Lord Spookyraven", !__quest_state["Level 11 Manor"].finished)); //retired - adventures.listAppend(BadMoonAdventureMake(36, $location[8-bit realm], "DAMAGE_REDUCTION", "+4 DR, -8 damage", "acquire digital key", $item[digital key].available_amount() == 0)); - adventures.listAppend(BadMoonAdventureMake(37, $location[The Penultimate Fantasy Airship], "DAMAGE_REDUCTION", "+8 DR, -8 damage", "unlock castle", $item[s.o.c.k.].available_amount() == 0)); - QuestState white_citadel_quest = QuestState("questG02Whitecastle"); - adventures.listAppend(BadMoonAdventureMake(42, $location[whitey's grove], "meat", "5000 meat, -20% stats debuff", "finish white citadel quest? (this needs spading)", !(!white_citadel_quest.started || white_citadel_quest.finished))); - //adventures.listAppend(BadMoonAdventureMake(45, $location[The Arid, Extra-Dry Desert], "ITEMS", "anticheese", "need to not have ultrahydrated", $effect[ultrahydrated].have_effect() == 0)); //is this still here? //retired - - adventures.listAppend(BadMoonAdventureMake(44, $location[the spooky forest], "SKILLS", "torso awareness, -50% muscle debuff", "unlock hidden temple", !get_property_ascension("lastTempleUnlock"))); - - __all_bad_moon_adventures_cache = adventures; - __all_bad_moon_adventures_cache_on_turn = my_turncount(); - - return adventures; -} -BadMoonAdventure [string][int] AllBadMoonAdventuresByCategory() -{ - BadMoonAdventure [string][int] result; - foreach key, adventure in AllBadMoonAdventures() - { - if (!(result contains adventure.category)) - { - BadMoonAdventure [int] blank; - result[adventure.category] = blank; - } - result[adventure.category].listAppend(adventure); - } - return result; -} - -BadMoonAdventure [int] BadMoonAdventuresForLocation(location l) -{ - BadMoonAdventure [int] result; - foreach key, adventure in AllBadMoonAdventures() - { - foreach key, l2 in adventure.locations - { - if (l == l2) - { - result.listAppend(adventure); - break; - } - } - } - return result; -} - -RegisterTaskGenerationFunction("PathBadMoonGenerateTasks"); -void PathBadMoonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!in_bad_moon()) - return; - if (my_turncount() == 0 && !haveSeenBadMoonEncounter(43) && $item[black kitten].available_amount() == 0 && !$familiar[black cat].have_familiar()) - { - string [int] description; - description.listAppend("For a black cat run. So cute!"); - description.listAppend("Adventure in the noob cave " + HTMLGenerateSpanFont("once", "red") + "."); - description.listAppend(HTMLGenerateSpanFont("Will cost 14 drunkenness.", "red")); - optional_task_entries.listAppend(ChecklistEntryMake("__familiar black cat", "", ChecklistSubentryMake("Possibly adopt a black kitten", "", description)).ChecklistEntrySetIDTag("Bad moon path black cat familiar masochist oh god no why")); - } - - //Finding familiars - +item, +meat, +stats - - if (my_familiar() != $familiar[black cat]) - { - if (!$familiar[blood-faced volleyball].have_familiar() && !$familiar[smiling rat].have_familiar()) - { - string [int] description; - string url; - - string [int] tasks; - if ($item[blood-faced volleyball].available_amount() > 0) - { - tasks.listAppend("use blood-faced volleyball"); - url = "inventory.php?ftext=blood-faced+volleyball"; - } - else - { - int trinkets_needed = 0; - if ($item[volleyball].available_amount() == 0) - { - string line = "collect a volleyball"; - if ($effect[bloody hand].have_effect() == 0 && $item[seal tooth].available_amount() == 0) - { - line += " and seal tooth"; - trinkets_needed += 1; - } - line += " from the hermit"; - tasks.listAppend(line); - url = "hermit.php"; - trinkets_needed += 1; - } - if ($effect[bloody hand].have_effect() == 0) - { - if ($item[seal tooth].available_amount() == 0 && $item[volleyball].available_amount() > 0) - { - tasks.listAppend("collect a seal tooth from the hermit"); - url = "hermit.php"; - trinkets_needed += 1; - } - tasks.listAppend("use seal tooth to acquire a bloody hand (ow!)"); - if (url != "" && $item[seal tooth].available_amount() > 0) - url = "inventory.php?ftext=seal+tooth"; - } - int trinkets_missing = MAX(0, trinkets_needed - $items[worthless trinket,worthless gewgaw,worthless knick-knack].available_amount()); - if (trinkets_missing > 0) - { - tasks.listPrepend("collect " + pluralise(trinkets_missing, $item[worthless trinket]) + " (use chewing gum)"); - if ($item[chewing gum on a string].available_amount() == 0) - url = "shop.php?whichshop=generalstore"; - else - url = "inventory.php?ftext=chewing+gum+on+a+string"; - if ($item[hermit permit].available_amount() == 0) - { - tasks.listPrepend("buy hermit permit"); - url = "shop.php?whichshop=generalstore"; - } - } - - tasks.listAppend("use volleyball"); - if (url != "" && $item[volleyball].available_amount() > 0 && $effect[bloody hand].have_effect() > 0) - url = "inventory.php?ftext=volleyball"; - - tasks.listAppend("use blood-faced volleyball"); - } - description.listAppend(tasks.listJoinComponents(", ").capitaliseFirstLetter() + "."); - optional_task_entries.listAppend(ChecklistEntryMake("__familiar blood-faced volleyball", url, ChecklistSubentryMake("Adopt a blood-faced volleyball", "", description)).ChecklistEntrySetIDTag("Bad moon path volleyball familiar")); - } - if (!$familiar[Leprechaun].have_familiar()) - { - string [int] description; - string url; - if ($item[leprechaun hatchling].available_amount() > 0) - { - description.listAppend("Use a leprechaun hatchling."); - url = "inventory.php?ftext=leprechaun+hatchling"; - } - else if (!haveSeenBadMoonEncounter(46) && $location[a barroom brawl].locationAvailable()) - { - description.listAppend("Find in a barroom brawl."); - url = $location[a barroom brawl].getClickableURLForLocation(); - } - if (description.count() > 0) - optional_task_entries.listAppend(ChecklistEntryMake("__familiar Leprechaun", url, ChecklistSubentryMake("Adopt a leprechaun", "", description), $locations[a barroom brawl]).ChecklistEntrySetIDTag("Bad moon path leprechaun familiar")); - } - if (!$familiar[baby gravy fairy].have_familiar()) - { - string [int] description; - string [int] modifiers; - string url; - - if ($item[pregnant mushroom].available_amount() > 0) - { - description.listAppend("Use a pregnant mushroom."); - url = "inventory.php?ftext=pregnant+mushroom"; - } - else if ($item[pregnant mushroom].creatable_amount() > 0) - { - description.listAppend("Create and use a pregnant mushroom."); - url = "craft.php?mode=cook"; - } - else - { - boolean need_minus_combat = false; - if ($item[fairy gravy boat].available_amount() == 0) - { - need_minus_combat = true; - description.listAppend("Adventure in the Haiku Dungeon for a fairy gravy boat.|Second choice in the NC."); - url = $location[the haiku dungeon].getClickableURLForLocation(); - } - if ($item[Knob mushroom].available_amount() == 0) - { - need_minus_combat = true; - description.listAppend("Find a knob mushroom somewhere.|Probably the haiku dungeon. First choice in the NC.|The cobb's knob kitchens are also an option. (?)"); - url = $location[the haiku dungeon].getClickableURLForLocation(); - } - if (need_minus_combat) - modifiers.listAppend("-combat"); - } - - optional_task_entries.listAppend(ChecklistEntryMake("__familiar baby gravy fairy", url, ChecklistSubentryMake("Adopt a baby gravy fairy", modifiers, description)).ChecklistEntrySetIDTag("Bad moon path fairy familiar")); - } - if (!$familiar[cocoabo].have_familiar() && $item[cocoa egg].available_amount() + $item[cocoa egg].creatable_amount() > 0) - { - //thanks harumph - string [int] description; - string url; - if ($item[cocoa egg].available_amount() == 0) - { - description.listAppend("Cook two cocoa eggshell fragments together twice, then cook two large cocoa eggshell fragments together.|Then use the cocoa egg."); - url = "craft.php?mode=cook"; - } - else - { - description.listAppend("Use a cocoa egg."); - url = "inventory.php?ftext=cocoa+egg"; - } - optional_task_entries.listAppend(ChecklistEntryMake("__familiar cocoabo", url, ChecklistSubentryMake("Adopt a cocoabo", "", description)).ChecklistEntrySetIDTag("Bad moon path cocoabo familiar")); - - } - } - //FIXME do we want the init semi-rare potion? it's only +100%... but, that might save a lot of turns? -} - -RegisterResourceGenerationFunction("PathBadMoonGenerateResource"); -void PathBadMoonGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!in_bad_moon()) - return; - - if (in_bad_moon() && !get_property_boolean("styxPixieVisited")) - { - string [int] description; - description.listAppend("Rubdown: +25% muscle, +5 DR, +10 damage."); - description.listAppend("Mind: +25% mysticality, +10-15 mp regen, +15 spell damage."); - description.listAppend("Colonge: +20% items, +25% moxie, +40% meat."); - resource_entries.listAppend(ChecklistEntryMake("__effect Hella Smooth", "heydeze.php?place=styx", ChecklistSubentryMake("Styx pixie buff", "", description), 10).ChecklistEntrySetIDTag("Bad moon path styx pixie resource")); - } - - if ($item[ghost key].available_amount() > 0 && __misc_state["in run"]) - { - string url = ""; - if ($location[the haunted bedroom].locationAvailable()) - url = $location[the haunted bedroom].getClickableURLForLocation(); - - string [int] description; - - if (__misc_state["need to level"]) - { - string target_nightstand = ""; - if (my_primestat() == $stat[muscle]) - target_nightstand = "simple"; - else if (my_primestat() == $stat[mysticality]) - target_nightstand = "ornate"; - else if (my_primestat() == $stat[moxie]) - target_nightstand = "rustic"; - description.listAppend("? mainstat from a " + target_nightstand + " nightstand."); //wiki says 200, but I saw 87 at level nine in bad moon - } - description.listAppend("1000 meat from a mahogany nightstand."); - resource_entries.listAppend(ChecklistEntryMake("__item ghost key", url, ChecklistSubentryMake(pluralise($item[ghost key]), "", description), 10).ChecklistEntrySetIDTag("Bad moon path ghost key resource")); - - } -} - -void PathBadMoonGenerateCategoryChecklistEntry(BadMoonAdventure [string][int] adventures_by_category, ChecklistEntry [int] bad_moon_adventures_entries, string [int] categories, string image_name, string header, string [int] initial_d_escription) -{ - string [int][int] description_active; - string [int][int] description_inactive; - - string url; - boolean [location] relevant_locations; - foreach key1, category in categories - { - foreach key2, adventure in adventures_by_category[category] - { - if (haveSeenBadMoonEncounter(adventure.encounter_id)) - continue; - - string [int] line; - line.listAppend(adventure.locations.listJoinComponents(" / ")); - - string line2 = adventure.description; - - - boolean greyed_out = false; - if (adventure.has_additional_requirements_not_yet_met) - { - line2 += ".|Need to " + adventure.conditions_to_finish + "."; - //line = HTMLGenerateSpanFont(line, "grey"); - greyed_out = true; - } - else - line2 += "."; - line.listAppend(line2); - - if (!greyed_out) - { - boolean have_open_location = false; - foreach key, l in adventure.locations - { - if (l.locationAvailable()) - { - if (url == "") - url = l.getClickableURLForLocation(); - have_open_location = true; - } - /*if (__setting_debug_mode) - { - Error unable_to_find_location; - l.locationAvailable(unable_to_find_location); - if (unable_to_find_location.was_error) - print_html("\"" + l + "\" unknown to locationAvailable"); - - }*/ - } - if (!have_open_location) - { - //line = HTMLGenerateSpanFont(line, "grey"); - greyed_out = true; - } - } - - if (greyed_out) - { - foreach key, value in line - { - line[key] = HTMLGenerateSpanFont(value, "grey"); - } - description_inactive.listAppend(line); - } - else - { - foreach key, l in adventure.locations - relevant_locations[l] = true; - description_active.listAppend(line); - } - } - } - string [int] description; - - description.listAppendList(initial_d_escription); //deja vu! - foreach key in description_inactive - { - description_active.listAppend(description_inactive[key]); - } - if (description_active.count() + description.count() > 0) - { - description.listAppend(HTMLGenerateSimpleTableLines(description_active)); - bad_moon_adventures_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(header, "", description), relevant_locations).ChecklistEntrySetIDTag("Bad moon path " + header + " special advs")); - } -} - -void PathBadMoonGenerateCategoryChecklistEntry(BadMoonAdventure [string][int] adventures_by_category, ChecklistEntry [int] bad_moon_adventures_entries, string [int] categories, string image_name, string header) -{ - PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, categories, image_name, header, listMakeBlankString()); -} - -RegisterChecklistGenerationFunction("PathBadMoonGenerateChecklists"); -void PathBadMoonGenerateChecklists(ChecklistCollection checklist_collection) -{ - if (!in_bad_moon()) - return; - - ChecklistEntry [int] bad_moon_adventures_entries = checklist_collection.lookup("Bad Moon Adventures").entries; - - - //badMoonEncounter01 to badMoonEncounter48 - //umm... that's a lot... - //each area has up to one encounter, but many areas may have the same encounter (frat house/hippy camp) - - /* - They're all classified under different areas, though. - - Things to mention: - √lots of meat, -something - √+X% item, -something - √+X% meat, -something - √+2 elemental resistance, 2x damage from two other elements - √+resistance all elements, all attributes -% - √+20 mainstat, -5 other stats - √+40 mainstat, -50% familiar weight (black cat!) - √items, -something (√black kitten and terrarium, √torso awareness, anticheese (irrelevant), √leprechaun, loaded dice (irrelevant), √potato sprout (irrelevant?) - - Maybe: - √+50% stat, -50% other stat - √+20 elemental damage, -~2 damage/round (g-g-g-ghosts!) - √+10 elemental damage, -2 DR (g-g-g-ghosts!) - - ???: - +DR, -8 weapon damage - */ - - BadMoonAdventure [string][int] adventures_by_category = AllBadMoonAdventuresByCategory(); - - PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("meat"), "__item dense meat stack", "Meat"); - if (my_familiar() != $familiar[black cat]) - PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("Familiar hatchlings"), "__item Familiar-Gro™ Terrarium", "Familiar hatchlings"); - PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("ITEM_DROP"), "__item Mr. Cheeng's spectacles", "Item buffs"); - PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("MEAT_DROP"), "__item old leather wallet", "Meat buffs"); - - string [int] elemental_damage_ordering = listMake("ELEMENTALDAMAGE1", "ELEMENTALDAMAGE2"); - if (my_level() >= 10) - elemental_damage_ordering = listMake("ELEMENTALDAMAGE2", "ELEMENTALDAMAGE1"); //don't encourage the +20 buffs until later - PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("RESIST1", "RESIST2"), "__item yak anorak", "Elemental resist buffs"); - PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("STAT2", "STAT1", "STAT3"), "__effect Phorcefullness", "Stat buffs"); - PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, elemental_damage_ordering, "__item oversized snowflake", "Elemental damage buffs", listMake("For defeating ghosts.")); - - if (!$skill[12].have_skill() && !haveSeenBadMoonEncounter(44) && $location[the hidden temple].locationAvailable()) // Torso Aware(g)ness - { - string [int] description; - description.listAppend("Spooky forest."); - - if ($item[grue egg omelette].available_amount() == 0 && $item[spooky mushroom].available_amount() == 0 && ($item[strange leaflet].available_amount() == 0 || $item[grue egg].available_amount() == 0)) - { - description.listAppend("Farm a spooky mushroom (for grue omelette) while you're there: " + listMake("Explore the stream", "March to the marsh").listJoinComponents(__html_right_arrow_character)); - } - else - description.listAppend("Farm spices (for spicy burritos) while you're there: " + listMake("Brave the dark thicket", "Follow the even darker path", "Take the scorched path", "Investigate the moist crater").listJoinComponents(__html_right_arrow_character)); - - bad_moon_adventures_entries.listAppend(ChecklistEntryMake("__item "Humorous" T-shirt", $location[the spooky forest].getClickableURLForLocation(), ChecklistSubentryMake("Torso Awareness", "", description), $locations[the spooky forest]).ChecklistEntrySetIDTag("Bad moon path torso awareness")); - } - - /* - FIXME - "Tower Ruins" unknown to locationAvailable - "The Orcish Frat House" unknown to locationAvailable - "Frat House (Frat Disguise)" unknown to locationAvailable - "The Hippy Camp" unknown to locationAvailable - "Hippy Camp (Hippy Disguise)" unknown to locationAvailable - */ -} diff --git a/Source/relay/TourGuide/Paths/Bugbear Invasion.ash b/Source/relay/TourGuide/Paths/Bugbear Invasion.ash deleted file mode 100644 index cde78b63..00000000 --- a/Source/relay/TourGuide/Paths/Bugbear Invasion.ash +++ /dev/null @@ -1,536 +0,0 @@ - -RegisterTaskGenerationFunction("PathBugbearInvasionGenerateTasks"); -void PathBugbearInvasionGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_BUGBEAR_INVASION) - return; - if (!__misc_state["in run"]) - return; - - - //task_entries.listAppend(ChecklistEntryMake("bugbear", "place.php?whichplace=bugbearship", ChecklistSubentryMake("Bugbears!", "", "I have no idea."))); - - /* - Properties: - statusEngineering - statusGalley - statusMedbay - statusMorgue - statusNavigation - statusScienceLab - statusSonar - statusSpecialOps - statusWasteProcessing - mothershipProgress - - Possible values for status: - [number] - Number of biodata collected. - unlocked - area unlocked, but floor not open in mothership...? - open - area unlocked, area available - cleared - maybe? - - mothershipProgress: 0 at start - 1 when unlocked science lab, morgue, and special ops - 2 when unlocked engineering, navigation, galley - 3 when unlocked bridge - - */ - //Let's see... first you need a key-o-tron to access the mothership. - //With that, you can collect biometric data for each area. - //Then there's mothershipProgress for each zone and tasks for each zone. - - boolean defiled_nook_open = true; - if (get_property_int("cyrptNookEvilness") == 0 && __quest_state["Level 7"].started) - defiled_nook_open = false; - - location [int] location_evaluation_order; - location_evaluation_order.listAppend($location[Medbay]); - location_evaluation_order.listAppend($location[Waste Processing]); - location_evaluation_order.listAppend($location[Sonar]); - location_evaluation_order.listAppend($location[Science Lab]); - location_evaluation_order.listAppend($location[Morgue]); - location_evaluation_order.listAppend($location[Special Ops]); - location_evaluation_order.listAppend($location[Engineering]); - location_evaluation_order.listAppend($location[Navigation]); - location_evaluation_order.listAppend($location[Galley]); - - - string [location] property_names_for_areas; - property_names_for_areas[$location[Engineering]] = "statusEngineering"; //does not seem to track battlesuit types fought - property_names_for_areas[$location[Galley]] = "statusGalley"; - property_names_for_areas[$location[Medbay]] = "statusMedbay"; - property_names_for_areas[$location[Morgue]] = "statusMorgue"; - property_names_for_areas[$location[Navigation]] = "statusNavigation"; - property_names_for_areas[$location[Science Lab]] = "statusScienceLab"; - property_names_for_areas[$location[Sonar]] = "statusSonar"; - property_names_for_areas[$location[Special Ops]] = "statusSpecialOps"; - property_names_for_areas[$location[Waste Processing]] = "statusWasteProcessing"; - - string [location] image_name_for_location; - image_name_for_location[$location[Engineering]] = "__monster " + $monster[liquid metal bugbear]; - image_name_for_location[$location[Galley]] = "__monster " + $monster[trendy bugbear chef]; - image_name_for_location[$location[Medbay]] = "__monster " + $monster[anesthesiologist bugbear]; - image_name_for_location[$location[Morgue]] = "__monster " + $monster[bugbear mortician]; - image_name_for_location[$location[Navigation]] = "__monster " + $monster[N-space Virtual Assistant]; - image_name_for_location[$location[Science Lab]] = "__monster " + $monster[bugbear scientist]; - image_name_for_location[$location[Sonar]] = "__monster " + $monster[batbugbear]; - image_name_for_location[$location[Special Ops]] = "__monster " + $monster[Black Ops Bugbear]; - image_name_for_location[$location[Waste Processing]] = "__monster " + $monster[scavenger bugbear]; - - - string [location] printable_names_for_areas; - printable_names_for_areas[$location[Engineering]] = "the engineering room"; - printable_names_for_areas[$location[Galley]] = "the galley"; - printable_names_for_areas[$location[Medbay]] = "the medbay"; - printable_names_for_areas[$location[Morgue]] = "the morgue"; - printable_names_for_areas[$location[Navigation]] = "the navigation room"; - printable_names_for_areas[$location[Science Lab]] = "the science lab"; - printable_names_for_areas[$location[Sonar]] = "the sonar room"; - printable_names_for_areas[$location[Special Ops]] = "the special ops room"; - printable_names_for_areas[$location[Waste Processing]] = "the waste processing room"; - - int [location] minimum_mothership_progress_for_area; - minimum_mothership_progress_for_area[$location[Engineering]] = 2; - minimum_mothership_progress_for_area[$location[Galley]] = 2; - minimum_mothership_progress_for_area[$location[Navigation]] = 2; - minimum_mothership_progress_for_area[$location[Morgue]] = 1; - minimum_mothership_progress_for_area[$location[Science Lab]] = 1; - minimum_mothership_progress_for_area[$location[Special Ops]] = 1; - minimum_mothership_progress_for_area[$location[Medbay]] = 0; - minimum_mothership_progress_for_area[$location[Sonar]] = 0; - minimum_mothership_progress_for_area[$location[Waste Processing]] = 0; - - if ($item[key-o-tron].available_amount() == 0) - { - if ($item[key-o-tron].creatable_amount() > 0) - { - task_entries.listAppend(ChecklistEntryMake("__item key-o-tron", "inv_use.php?pwd=" + my_hash() + "&whichitem=5683", ChecklistSubentryMake("Create key-o-tron", "", "Use 5 BURTs."), -11).ChecklistEntrySetIDTag("Bugbear invasion path make key")); - } - else - { - string url = ""; - int burts_needed = clampi(5 - $item[BURT].available_amount(), 0, 5); - string [int] description; - description.listAppend("To make a key-o-tron."); - - string [int] source_locations_available; - string [int] source_locations_unavailable; - //Possible areas: - - boolean [location] unavailable_locations_to_show = $locations[The Sleazy Back Alley,The Spooky Forest,cobb's knob Laboratory,The Defiled Nook,Lair of the Ninja Snowmen,The Penultimate Fantasy Airship,The Haunted Gallery,The Battlefield (Frat Uniform)]; - - boolean [location] relevant_locations = $locations[The Sleazy Back Alley,The Spooky Forest,The Bat Hole Entrance,The Batrat and Ratbat Burrow,Guano Junction,The Beanbat Chamber,cobb's knob Laboratory,Lair of the Ninja Snowmen,The Penultimate Fantasy Airship,The Haunted Gallery,The Battlefield (Frat Uniform),The Orcish Frat House (Bombed Back to the Stone Age),The Hippy Camp (Bombed Back to the Stone Age)].makeConstantLocationArrayMutable(); //FIXME the battlefield (hippy uniform)? - relevant_locations[$location[the very unquiet garves]] = true; - - if (defiled_nook_open) - relevant_locations[$location[the defiled nook]] = true; - else - relevant_locations[$location[The VERY Unquiet Garves]] = true; - - //FIXME always URL in areas we have olfacted...? - foreach l in relevant_locations - { - string place = l.to_string(); - - if (!l.locationAvailable()) - { - if (unavailable_locations_to_show contains l) - source_locations_unavailable.listAppend(HTMLGenerateSpanFont(place, "grey")); - } - else - { - source_locations_available.listAppend(place); - string place_url = l.getClickableURLForLocation(); - if (place_url.length() != 0) - url = place_url; - } - } - string line = "Places to collect them:|*" + source_locations_available.listJoinComponents("|*"); - if (source_locations_unavailable.count() > 0) - line += "|*" + source_locations_unavailable.listJoinComponents("|*"); - description.listAppend(line); - - task_entries.listAppend(ChecklistEntryMake("__item key-o-tron", url, ChecklistSubentryMake("Collect " + int_to_wordy(burts_needed) + " more BURT" + ((burts_needed) > 1 ? "s" : ""), "", description)).ChecklistEntrySetIDTag("Bugbear invasion path key-o-tron")); - } - } - else - { - // - location [location][int] locations_relevant_to_acquire_biodata; - int [location] biodata_amount_needed_for_area; - - - biodata_amount_needed_for_area[$location[Engineering]] = 9; - biodata_amount_needed_for_area[$location[Galley]] = 9; - biodata_amount_needed_for_area[$location[Medbay]] = 3; - biodata_amount_needed_for_area[$location[Morgue]] = 6; - biodata_amount_needed_for_area[$location[Navigation]] = 9; - biodata_amount_needed_for_area[$location[Science Lab]] = 6; - biodata_amount_needed_for_area[$location[Sonar]] = 3; - biodata_amount_needed_for_area[$location[Special Ops]] = 6; - biodata_amount_needed_for_area[$location[Waste Processing]] = 3; - - monster [location] bugbears_to_hunt_for_location; - - bugbears_to_hunt_for_location[$location[Engineering]] = $monster[Battlesuit Bugbear Type]; - bugbears_to_hunt_for_location[$location[Galley]] = $monster[trendy bugbear chef]; - bugbears_to_hunt_for_location[$location[Medbay]] = $monster[hypodermic bugbear]; - bugbears_to_hunt_for_location[$location[Morgue]] = $monster[bugaboo]; - bugbears_to_hunt_for_location[$location[Navigation]] = $monster[ancient unspeakable bugbear]; - bugbears_to_hunt_for_location[$location[Science Lab]] = $monster[bugbear scientist]; - bugbears_to_hunt_for_location[$location[Sonar]] = $monster[batbugbear]; - bugbears_to_hunt_for_location[$location[Special Ops]] = $monster[Black Ops Bugbear]; - bugbears_to_hunt_for_location[$location[Waste Processing]] = $monster[scavenger bugbear]; - - foreach l in property_names_for_areas - { - locations_relevant_to_acquire_biodata[l] = listMakeBlankLocation(); - } - - locations_relevant_to_acquire_biodata[$location[waste processing]].listAppend($location[the sleazy back alley]); - locations_relevant_to_acquire_biodata[$location[Medbay]].listAppend($location[the Spooky Forest]); - locations_relevant_to_acquire_biodata[$location[Sonar]].listAppend($location[The Bat Hole Entrance]); - locations_relevant_to_acquire_biodata[$location[Sonar]].listAppend($location[The Batrat and Ratbat Burrow]); - locations_relevant_to_acquire_biodata[$location[Sonar]].listAppend($location[Guano Junction]); - locations_relevant_to_acquire_biodata[$location[Sonar]].listAppend($location[The Beanbat Chamber]); - - locations_relevant_to_acquire_biodata[$location[Science Lab]].listAppend($location[cobb's knob laboratory]); - - - locations_relevant_to_acquire_biodata[$location[Special Ops]].listAppend($location[Lair of the Ninja Snowmen]); - locations_relevant_to_acquire_biodata[$location[Engineering]].listAppend($location[The Penultimate Fantasy Airship]); - locations_relevant_to_acquire_biodata[$location[Navigation]].listAppend($location[The Haunted Gallery]); - - if (!__quest_state["Level 12"].finished) - { - locations_relevant_to_acquire_biodata[$location[Galley]].listAppend($location[The Battlefield (Frat Uniform)]); - } - else - { - //FIXME determine which side won - locations_relevant_to_acquire_biodata[$location[Galley]].listAppend($location[The Orcish Frat House (Bombed Back to the Stone Age)]); - locations_relevant_to_acquire_biodata[$location[Galley]].listAppend($location[The Hippy Camp (Bombed Back to the Stone Age)]); - } - - if (defiled_nook_open) - locations_relevant_to_acquire_biodata[$location[Morgue]].listAppend($location[the defiled nook]); - else - locations_relevant_to_acquire_biodata[$location[Morgue]].listAppend($location[The VERY Unquiet Garves]); - - string url = ""; - boolean do_not_override_url = false; - - string [int] description; - boolean [location] relevant_locations; - foreach l, biodata_needed in biodata_amount_needed_for_area - { - string biodata_have_string = get_property(property_names_for_areas[l]); - if (!biodata_have_string.is_integer()) - continue; - int biodata_have = biodata_have_string.to_int_silent(); - if (biodata_have >= biodata_needed) - continue; - int biodata_remaining = MAX(0, biodata_needed - biodata_have); - - //FIXME check if we have an area open - location [int] areas_we_can_adventure_in; - foreach key, l2 in locations_relevant_to_acquire_biodata[l] - { - areas_we_can_adventure_in.listAppend(l2); - relevant_locations[l2] = true; - - string this_url = l2.getClickableURLForLocation(); - if (this_url != "" && !do_not_override_url && l2.locationAvailable()) - url = this_url; - if (get_property_monster("olfactedMonster") == bugbears_to_hunt_for_location[l]) - { - do_not_override_url = true; - } - } - if (areas_we_can_adventure_in.count() > 0 && l.turns_spent == 0) - { - - boolean tracking_works = true; - if ($locations[the Penultimate Fantasy Airship,Lair of the Ninja Snowmen] contains l && biodata_remaining == biodata_needed) - tracking_works = false; - boolean at_least_one_area_open = false; - foreach key, l in areas_we_can_adventure_in - { - if (l.locationAvailable()) - at_least_one_area_open = true; - } - string line; - line += "Fight " + int_to_wordy(biodata_remaining); - - if (!tracking_works) - line += " total "; - else - line += " more "; - line += bugbears_to_hunt_for_location[l] + " in"; - - if (areas_we_can_adventure_in.count() == 1) - { - line += " " + areas_we_can_adventure_in.listJoinComponents("") + "."; - line += "|Unlocks " + l + "."; - } - else - { - line += ": |*" + areas_we_can_adventure_in.listJoinComponents("|*"); - line += "|*
Unlocks " + l + "."; - } - if (!tracking_works) - line += "|Umm... unless you already did that. (no tracking)"; - if (!at_least_one_area_open) - line = HTMLGenerateSpanFont(line, "grey"); - description.listAppend(line); - } - } - if (description.count() > 0) - { - if ($item[crayon shavings].available_amount() > 0) - description.listPrepend($item[crayon shavings].available_amount().int_to_wordy().capitaliseFirstLetter() + " crayon shavings available for copying bugbears."); - if ($item[bugbear detector].available_amount() > 0 && $item[bugbear detector].equipped_amount() == 0) - description.listPrepend(HTMLGenerateSpanFont("Equip bugbear detector first.", "red")); - task_entries.listAppend(ChecklistEntryMake("__item software glitch", url, ChecklistSubentryMake("Collect biodata", "", description), relevant_locations).ChecklistEntrySetIDTag("Bugbear invasion path collect biodata")); - } - } - int mothership_progress = get_property_int("mothershipProgress"); - - if (true) - { - ChecklistEntry entry; - entry.url = "place.php?whichplace=bugbearship"; - entry.image_lookup_name = "bugbear"; - entry.tags.id = "Bugbear invasion path quest mothership"; - foreach key, l in location_evaluation_order - { - string property_name = property_names_for_areas[l]; - if (get_property(property_name) != "open" && !(get_property(property_name).is_integer() && l.turns_spent > 0)) - continue; - - if (mothership_progress < minimum_mothership_progress_for_area[l]) - continue; - if (entry.image_lookup_name == "bugbear" && image_name_for_location[l] != "") - entry.image_lookup_name = image_name_for_location[l]; - - string [int] modifiers; - string [int] description; - if (l == $location[medbay]) - { - modifiers.listAppend("olfact anesthesiologist bugbear"); - description.listAppend("Fight anesthesiologist bugbears to summon and defeat the robo-surgeon."); - description.listAppend("Banishes won't help...?"); - } - else if (l == $location[sonar]) - { - modifiers.listAppend("-combat"); - description.listAppend("Run -combat, look for the machine."); - description.listAppend("Set Pinging machine to 2."); - description.listAppend("Set Whurming machine to 4."); - description.listAppend("Set Boomchucking machine to 8."); - } - else if (l == $location[waste processing]) - { - if ($item[bugbear communicator badge].available_amount() > 0) - { - if ($item[bugbear communicator badge].equipped_amount() == 0) - { - description.listAppend("Equip the bugbear communicator badge."); - } - else - { - description.listAppend("Adventure once to finish the area."); - } - } - else - { - modifiers.listAppend("olfact creepy eye-stalk tentacle monster"); - modifiers.listAppend("+item"); - description.listAppend("Acquire and use handfuls of juicy garbage."); - if ($item[handful of juicy garbage].available_amount() > 0) - { - task_entries.listAppend(ChecklistEntryMake("__item handful of juicy garbage", "inventory.php?ftext=handful+of+juicy+garbage", ChecklistSubentryMake("Use handful of juicy garbage", "", "Might find a bugbear communicator badge."), -11).ChecklistEntrySetIDTag("Bugbear invasion path juicy garbage")); - } - } - } - else if (l == $location[science lab]) - { - //FIXME want tracking for scientists trapped - modifiers.listAppend("+item"); - description.listAppend("Collect quantum nanopolymer spider webs from spiderbugbears, use them on the poor innocent scientists."); - if ($item[quantum nanopolymer spider web].available_amount() > 0) - description.listAppend(pluraliseWordy($item[quantum nanopolymer spider web]).capitaliseFirstLetter() + " available."); - } - else if (l == $location[morgue]) - { - //FIXME want tracking of parts - if ($item[bugbear autopsy tweezers].available_amount() > 0) - modifiers.listAppend("-combat"); - if ($item[bugbear autopsy tweezers].available_amount() < 5) - { - if (!$monster[bugaboo].is_banished()) - modifiers.listAppend("banish bugaboos OR olfact bugbear morticians"); - description.listAppend("Collect bugbear autopsy tweezers from bugbear morticians."); - } - - if ($item[bugbear autopsy tweezers].available_amount() > 0) - description.listAppend("Run -combat to use the tweezers on the choice adventure."); - } - else if (l == $location[special ops]) - { - boolean [item] relevant_equipment = $items[fire,uv monocular,rain-doh green lantern,fluorescent lightbulb]; - item [int] items_to_equip; - foreach it in relevant_equipment - { - if (it.available_amount() > 0 && it.equipped_amount() == 0) - items_to_equip.listAppend(it); - } - if (items_to_equip.count() > 0) - description.listAppend(HTMLGenerateSpanFont("Equip your " + items_to_equip.listJoinComponents(", ", "and") + ".", "red")); - if ($item[uv monocular].available_amount() == 0 && $item[uv monocular].creatable_amount() > 0) - description.listAppend("Could create the UV Monocular with your BURTs."); - - description.listAppend("Search in darkness."); - - if ($item[flaregun].available_amount() > 0) - description.listAppend("Shoot a flare in the choice adventure if you haven't."); - } - else if (l == $location[Engineering]) - { - //FIXME want tracking on liquid metal bugbears - modifiers.listAppend("+item"); - if (!$monster[Battlesuit Bugbear Type].is_banished()) - { - modifiers.listAppend("banish " + $monster[Battlesuit Bugbear Type]); - } - description.listAppend("Collect drone self-destruct chips from drones, use them on liquid metal bugbears."); - if ($item[drone self-destruct chip].available_amount() > 0) - description.listAppend(pluraliseWordy($item[drone self-destruct chip]).capitaliseFirstLetter() + " available."); - } - else if (l == $location[Navigation]) - { - if ($effect[N-Spatial vision].have_effect() > 0) - { - string method_to_remove = ""; - //FIXME write this - if ($skill[disco nap].skill_is_usable() && $skill[adventurer of leisure].skill_is_usable()) - method_to_remove = "disco nap."; - else if ($item[bugbear purification pill].available_amount() > 0) - method_to_remove = "bugbear purification pill."; - else if ($item[bugbear purification pill].creatable_amount() > 0) - method_to_remove = "bugbear purification pill. (make from BURTs)"; - else if ($item[soft green echo eyedrop antidote].available_amount() > 0) - method_to_remove = "soft green echo eyedrop antidote. (probably not worth it)"; - - if (method_to_remove != "") - description.listAppend("Remove N-Spatial vision with " + method_to_remove); - else - description.listAppend("Avoid adventuring here until N-Spatial vision is gone."); - } - else - { - if (!$monster[ancient unspeakable bugbear].is_banished()) - { - modifiers.listAppend("banish ancient unspeakable bugbears OR olfact n-space virtual assistants"); //zero space. Zee-roh spaa ce. Spac-uh. - } - description.listAppend("Defeat ~ten total N-space assistants."); - } - } - else if (l == $location[Galley]) - { - //FIXME tracking ML defeated, cavebugbear attack - modifiers.listAppend("+ML"); - if (!$monster[trendy bugbear chef].is_banished()) - { - modifiers.listAppend("banish trendy bugbear chefs OR olfact angry cavebugbears"); - } - description.listAppend("Defeat 5k ML worth of angry cavebugbears."); - if ($item[pacification grenade].creatable_amount() + $item[pacification grenade].available_amount() > 0) - description.listAppend("Can " + ($item[pacification grenade].available_amount() == 0 ? "make and " : "") + "throw a pacification grenade if they become too difficult."); - } - - entry.subentries.listAppend(ChecklistSubentryMake("Clear " + printable_names_for_areas[l], modifiers, description)); - if ($locations[Medbay,Waste Processing,Sonar,Science Lab,Morgue,Special Ops,Engineering,Navigation,Galley] contains __last_adventure_location) - entry.should_highlight = true; - } - if (entry.subentries.count() > 0) - task_entries.listAppend(entry); - } - - if (mothership_progress >= 3) - { - // - boolean other_quests_completed = true; - for i from 2 to 12 - { - if (!__quest_state["Level " + i].finished) - other_quests_completed = false; - } - if (other_quests_completed && my_level() >= 13) - { - ChecklistEntry entry; - if ($item[jeff goldblum larva].available_amount() == 0) - { - //hacky: - entry = ChecklistEntryMake("council", "place.php?whichplace=town", ChecklistSubentryMake("Visit the Council of Loathing", "", "Obtain Jeff Goldblum larva.")); - } - else - { - //no tracking for bridge captain defeated? - entry = ChecklistEntryMake("bugbear", "place.php?whichplace=bugbearship", ChecklistSubentryMake("Fight the Bugbear Captain", "", listMake("On the bridge.", "Then free the king. Maybe."))); - } - entry.tags.id = "Bugbear invastion path quest final steps"; - task_entries.listAppend(entry); - } - } -} - -RegisterResourceGenerationFunction("PathBugbearInvasionGenerateResource"); -void PathBugbearInvasionGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_BUGBEAR_INVASION) - return; - if (!__misc_state["in run"]) - return; - if ($item[crayon shavings].available_amount() > 0) - { - resource_entries.listAppend(ChecklistEntryMake("__item crayon shavings", "", ChecklistSubentryMake(pluralise($item[crayon shavings].available_amount(), "crayon shaving copy", "crayon shaving copies") + " available", "", "Bugbears only.")).ChecklistEntrySetIDTag("Bugbear invasion path crayon shaving resource")); - } - if ($item[BURT].available_amount() > 0) - { - string [int] description; - - string [item] item_reason; - item_reason[$item[pacification grenade]] = "trades speed for survivability in the galley"; - item_reason[$item[key-o-tron]] = "collects biodata"; - item_reason[$item[bugbear detector]] = "find the elusive creature"; - item_reason[$item[uv monocular]] = "useful in special ops"; - item_reason[$item[bugbear purification pill]] = "removes a negative effect"; - if (get_property("statusNavigation") != "cleared" && !($skill[disco nap].skill_is_usable() && $skill[adventurer of leisure].skill_is_usable())) - item_reason[$item[bugbear purification pill]] += " (useful in Navigation)"; - item [int] relevant_items; - relevant_items.listAppend($item[bugbear purification pill]); - if (get_property("statusGalley") != "cleared") - relevant_items.listAppend($item[pacification grenade]); - relevant_items.listAppend($item[key-o-tron]); - relevant_items.listAppend($item[bugbear detector]); - if (get_property("statusSpecialOps") != "cleared") - relevant_items.listAppend($item[uv monocular]); - - int [item] amount_wanted; - amount_wanted[$item[pacification grenade]] = -1; - - foreach key, it in relevant_items - { - if (it.available_amount() > 0 && amount_wanted[it] != -1) - continue; - string line = it + " - "; - line += item_reason[it] + "."; - - if (it.creatable_amount() == 0) - line = HTMLGenerateSpanFont(line, "grey"); - description.listAppend(line); - } - resource_entries.listAppend(ChecklistEntryMake("__item BURT", "inv_use.php?pwd=" + my_hash() + "&whichitem=5683", ChecklistSubentryMake(pluralise($item[BURT]) + " available", "", description), 8).ChecklistEntrySetIDTag("Bugbear invasion path BURT resource")); - } -} diff --git a/Source/relay/TourGuide/Paths/Community Service.ash b/Source/relay/TourGuide/Paths/Community Service.ash deleted file mode 100644 index 6178d095..00000000 --- a/Source/relay/TourGuide/Paths/Community Service.ash +++ /dev/null @@ -1,236 +0,0 @@ -RegisterTaskGenerationFunction("PathCommunityServiceGenerateTasks"); -void PathCommunityServiceGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_COMMUNITY_SERVICE) - return; - if (!__misc_state["in run"]) - return; - boolean [item] blacklist; - - /*string [int] service_display_order = {0:"Coil Wire", - 1:"", - 2:"", - 3:"", - 4:"", - 5:"", - 6:"", - 7:"", - 8:"", - 9:"", - 10:"" - };*/ - boolean [string] services_performed = listInvert(get_property("csServicesPerformed").split_string_alternate(",")); - string [int] choice_id_order = { - "Coil Wire", //flat - "Donate Blood", - "Feed The Children (But Not Too Much)", - "Build Playground Mazes", - "Feed Conspirators", - "Breed More Collies", - "Reduce Gazelle Population", - "Make Sausage", - "Be a Living Statue", - "Make Margaritas", - "Clean Steam Tunnels" - }; - //the spreadsheet we were using does +item before the stat tests, but I'm moving it after them, because cold-filtered water is ten turns, and the +item test doesn't give anything that helps with stats - //and technically, muscle gives bag of grain - string [int] service_display_order = { - "Coil Wire", //flat - "Feed The Children (But Not Too Much)", //muscle - "Feed Conspirators", //moxie - "Donate Blood", //hp - "Build Playground Mazes", //myst - "Make Margaritas", //item/booze - "Reduce Gazelle Population", //melee - "Make Sausage", //spell - "Clean Steam Tunnels", //hot res - "Breed More Collies", //familiar weight - "Be a Living Statue", //-combat - }; - /*string [string] service_names_to_property = {"Donate Blood":"REPLACEME" - "Feed The Children (But Not Too Much)":"Muscle", - "Build Playground Mazes":"Mysticality", - "Feed Conspirators":"Moxie", - "Breed More Collies":"Familiar Weight", - "Reduce Gazelle Population":"REPLACEME", - "Make Sausage":"REPLACEME", - "Be a Living Statue":"REPLACEME", - "Make Margaritas":"REPLACEME", - "Clean Steam Tunnels":"Hot Resistance", - };*/ - //None, HP, muscle, mysticality, moxie, familiar weight, melee damage, spell damage, noncombat, booze drop, hot res - //list in ideal order to finish the path as you are(?) - int REPLACEME = 10000; - foreach key, service_name in service_display_order - { - string [int] modifiers; - string [int] description; - int turns = PathCommunityServiceEstimateTurnsTakenForTask(service_name); - string service_lookup_name = service_name; - if (service_lookup_name == "Feed The Children (But Not Too Much)") - service_lookup_name = "Feed The Children"; - if (services_performed[service_lookup_name]) continue; - - boolean [string] numeric_modifiers; - string short_test_description; - boolean prefer_negative = false; - string image_name = ""; - if (service_name == "Donate Blood") - { - image_name = "__item blood-drive sticker"; - modifiers.listAppend("HP"); - modifiers.listAppend("muscle"); - short_test_description = "HP"; - numeric_modifiers = $strings[Buffed HP Maximum,Maximum HP,Muscle,Muscle Percent]; - } - else if (service_name == "Coil Wire") - { - image_name = "__item a ten-percent bonus"; - } - else if (service_name == "Make Margaritas") - { - image_name = "__item emergency margarita"; - modifiers.listAppend("item"); - modifiers.listAppend("booze drop"); - short_test_description = "item drop, booze drop"; - numeric_modifiers = $strings[Item Drop,Booze Drop]; - } - else if (service_name == "Feed The Children (But Not Too Much)" || service_name == "Build Playground Mazes" || service_name == "Feed Conspirators") - { - stat using_stat; - if (service_name == "Feed The Children (But Not Too Much)") - { - using_stat = $stat[muscle]; - image_name = "__item bag of grain"; - } - else if (service_name == "Build Playground Mazes") - { - using_stat = $stat[mysticality]; - image_name = "__item pocket maze"; - } - else if (service_name == "Feed Conspirators") - { - using_stat = $stat[moxie]; - image_name = "__item shady shades"; - } - modifiers.listAppend("+" + using_stat); - short_test_description = using_stat; - numeric_modifiers[using_stat.to_string()] = true; - numeric_modifiers[using_stat + " Percent"] = true; - int basestat = my_basestat(using_stat); - boolean relevant_thrall_active = false; - if (my_thrall() == $thrall[Elbow Macaroni] && using_stat == $stat[muscle]) - { - basestat = my_basestat($stat[mysticality]); - relevant_thrall_active = true; - } - if (my_thrall() == $thrall[Penne Dreadful] && using_stat == $stat[moxie]) - { - basestat = my_basestat($stat[mysticality]); - relevant_thrall_active = true; - } - - turns = 60 - (my_buffedstat(using_stat) - basestat) / 30; - if (turns > 1) - { - //turns saved = (buffed - base) / 30 - //59 = (buffed - base) / 30 - //1770 = buffed - base - //buffed = 1770 + base - int needed_buffed_stat = 1770 + basestat; - float percentage = to_float(needed_buffed_stat - my_buffedstat(using_stat)) / to_float(basestat) * 100.0; - description.listAppend("Need to buff " + using_stat + " to " + needed_buffed_stat + " (+" + (needed_buffed_stat - my_buffedstat(using_stat)) + " / +" + percentage.round() + "% from here)"); - if (relevant_thrall_active) - { - } - else if (using_stat != $stat[mysticality] && my_primestat() == $stat[mysticality] && $item[oil of expertise].to_effect().have_effect() == 0) - { - description.listAppend("Possibly use oil of expertise to equalise basestats." + ($items[cherry,oil of expertise].available_amount() == 0 ? "|Can get a cherry from novelty tropical skeleton in the skeleton store. Run +234% item." : "")); - if (my_class() == $class[pastamancer]) description.listAppend("Or use pastamancer thralls."); - } - } - } - else if (service_name == "Reduce Gazelle Population") - { - image_name = "__item weird gazelle steak"; - modifiers.listAppend("+weapon damage, +weapon damage percent"); - short_test_description = "melee damage, melee damage percent"; - numeric_modifiers = $strings[Weapon Damage,Weapon Damage Percent]; - if ($skill[Bow-Legged Swagger].have_skill() && $effect[Bow-Legged Swagger].have_effect() == 0 && !get_property_boolean("_bowleggedSwaggerUsed")) - { - description.listAppend("Cast Bow-Legged Swagger for twice effectiveness."); - } - } - else if (service_name == "Make Sausage") - { - image_name = "__item sausage without a cause"; - modifiers.listAppend("+spell damage, +spell damage percent"); - short_test_description = "spell damage"; - numeric_modifiers = $strings[Spell Damage,Spell Damage Percent]; - } - else if (service_name == "Clean Steam Tunnels") - { - image_name = "__item vintage smart drink"; - //FIXME red - modifiers.listAppend("+hot resistance"); - short_test_description = "hot resistance"; - numeric_modifiers = $strings[Hot Resistance]; - } - else if (service_name == "Breed More Collies") - { - image_name = "__item squeaky toy rose"; - modifiers.listAppend("+familiar weight"); - short_test_description = "familiar weight"; - numeric_modifiers = $strings[Familiar Weight]; - } - else if (service_name == "Be a Living Statue") - { - image_name = "__item silver face paint"; - modifiers.listAppend("-combat"); - short_test_description = "-combat"; - numeric_modifiers = $strings[Combat Rate]; - prefer_negative = true; - } - - turns = clampi(turns, 1, 60); - if (short_test_description != "") - description.listAppend("Buff " + short_test_description + "."); - - - - - description.listAppend(pluralise(turns, "turn", "turns") + "."); - task_entries.listAppend(ChecklistEntryMake(image_name, "council.php", ChecklistSubentryMake(service_name, modifiers, description)).ChecklistEntrySetIDTag("Community service path " + service_lookup_name)); - } - //equaliser potions - /*if (true) - { - item [int] hp_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Buffed HP Maximum", 150.0, blacklist); //what a strange lookup name - item [int] hp_potions_2 = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Maximum HP", 150.0, blacklist); //something else? - - item [int] muscle_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Muscle", 0.0, blacklist); - item [int] muscle_percent_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Muscle Percent", 0.0, blacklist); - - - string [int] relevant_potions_output; - foreach key, it in hp_potions - { - relevant_potions_output.listAppend(it + " (+" + it.to_effect().numeric_modifier("Buffed HP Maximum").roundForOutput(0) + ")"); - } - - task_entries.listAppend(ChecklistEntryMake("__item helmet turtle", "council.php", ChecklistSubentryMake("Perform HP service", "+hp", relevant_potions_output.listJoinComponents(", ", "and")))); - } - - - foreach s in $strings[Buffed HP Maximum,Muscle,Muscle Percent,Moxie,Moxie Percent,Mysticality,Mysticality Percent,Weapon Damage,Weapon Damage Percent,spell damage, spell damage percent,Combat Rate,hot resistance] - { - item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier(s, -100000.0, blacklist); //what a strange lookup name - string [int] relevant_potions_output; - foreach key, it in relevant_potions - { - relevant_potions_output.listAppend(it + " (+" + it.to_effect().numeric_modifier(s).roundForOutput(0) + ")"); - } - task_entries.listAppend(ChecklistEntryMake("__item helmet turtle", "council.php", ChecklistSubentryMake("Perform " + s + " service", "", relevant_potions_output.listJoinComponents(", ", "and")))); - }*/ -} diff --git a/Source/relay/TourGuide/Paths/Dark Gift.ash b/Source/relay/TourGuide/Paths/Dark Gift.ash deleted file mode 100644 index 6e657cd1..00000000 --- a/Source/relay/TourGuide/Paths/Dark Gift.ash +++ /dev/null @@ -1,24 +0,0 @@ - -RegisterResourceGenerationFunction("PathDarkGiftGenerateResource"); -void PathDarkGiftGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_VAMPIRE) - return; - - int banishes_left = clampi(10 - get_property_int("_balefulHowlUses"), 0, 10); - if (banishes_left > 0 && lookupSkill("Baleful Howl").skill_is_usable()) - { - string url; - string [int] description; - description.listAppend("Free run/banish."); - description.listAppend("There's a lot of them, so you might just want to use them as a free run?"); - Banish banish_entry = BanishByName("Baleful Howl"); - int turns_left_of_banish = banish_entry.BanishTurnsLeft(); - if (turns_left_of_banish > 0) - { - //is this relevant? we don't describe this for pantsgiving - description.listAppend("Currently used on " + banish_entry.banished_monster + " for " + pluralise(turns_left_of_banish, "more turn", "more turns") + "."); - } - resource_entries.listAppend(ChecklistEntryMake("__skill Baleful Howl", url, ChecklistSubentryMake(pluralise(banishes_left, "baleful howl", "baleful howls"), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Dark gyffte path baleful howl banish")); - } -} diff --git a/Source/relay/TourGuide/Paths/Explosions.ash b/Source/relay/TourGuide/Paths/Explosions.ash deleted file mode 100644 index a2aecbcc..00000000 --- a/Source/relay/TourGuide/Paths/Explosions.ash +++ /dev/null @@ -1,30 +0,0 @@ - -RegisterResourceGenerationFunction("PathExplosionsGenerateResource"); -void PathExplosionsGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_EXPLOSIONS) - return; - item isotopes = lookupItem("rare Meat isotope"); - if (isotopes.have()) - { - string [int] description; - int isotope_amount = isotopes.available_amount(); - if (isotope_amount >= 5) - { - description.listAppend("Space chowder - for eating or hippy-fighting war."); - description.listAppend("Space wine - for drinking or frat-fighting war."); - } - if (isotope_amount >= 10 && !$item[antique accordion].have() && my_class() != $class[accordion thief]) - description.listAppend("antique accordion - casting AT buffs."); - if (isotope_amount >= 25 && !lookupItem("signal jammer").have()) - description.listAppend("signal jammer - deals with those troublesome wandering skeletons. Equipped this in non-delay-burning areas."); - if (isotope_amount >= 25 && !lookupItem("space shield").have() && ($item[digital key].have() || $item[white pixel].available_amount() >= 30)) - description.listAppend("space shield - wear this everywhere that is adventure.php, prevents invader bullets"); - - - //if (isotope_amount >= 10 && !lookupItem("low-pressure oxygen tank").have()) - //description.listAppend("low-pressure oxygen tank - prevents HP damage at end of fight, but you probably want to ignore this."); - - resource_entries.listAppend(ChecklistEntryMake("__item rare Meat isotope", "shop.php?whichshop=exploathing", ChecklistSubentryMake(pluralise(isotopes), "", description), 5).ChecklistEntrySetIDTag("Exploathing path rare meat isotope shop")); - } -} diff --git a/Source/relay/TourGuide/Paths/Fall of the Dinosaurs.ash b/Source/relay/TourGuide/Paths/Fall of the Dinosaurs.ash deleted file mode 100644 index c69a0cc2..00000000 --- a/Source/relay/TourGuide/Paths/Fall of the Dinosaurs.ash +++ /dev/null @@ -1,21 +0,0 @@ -RegisterResourceGenerationFunction("PathDinoFallGenerateResource"); -void PathDinoFallGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_FALL_OF_THE_DINOSAURS) - return; - - // #10944 = Dinodollar, the currency in the Dinostaur (good joke!) - item dd = lookupItem("10944"); - - int repellantsAvailable = (dd.available_amount() - (dd.available_amount() % 5))/5; - - if (dd.available_amount() > 0) - { - string [int] description; - if (lookupItem("10941").available_amount() == 0) - description.listAppend("Dino DNAde™: +300% to all stats, good for survival & the tower"); - - description.listAppend("Dinosaur Repellent: You can purchase " + repellantsAvailable.to_string() + " freeruns!"); - resource_entries.listAppend(ChecklistEntryMake("__item Dinodollar", "shop.php?whichshop=dino", ChecklistSubentryMake(pluralise(dd) + " available", "", description), 3).ChecklistEntrySetIDTag("The Dinostaur")); - } -} diff --git a/Source/relay/TourGuide/Paths/G-Lover.ash b/Source/relay/TourGuide/Paths/G-Lover.ash deleted file mode 100644 index 8908586d..00000000 --- a/Source/relay/TourGuide/Paths/G-Lover.ash +++ /dev/null @@ -1,19 +0,0 @@ - -RegisterResourceGenerationFunction("PathGLoverGenerateResource"); -void PathGLoverGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_G_LOVER) - return; - - item g = lookupItem("9909"); - if (g.available_amount() > 0) - { - string [int] description; - if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0 && !__quest_state["Level 9"].finished && lookupItems("a-boo glue,glued a-boo clue").available_amount() * 30 < __quest_state["Level 9"].state_int["a-boo peak hauntedness"]) - description.listAppend("A-Boo glue: lets you use one a-boo clue."); - if (!__quest_state["Level 9"].state_boolean["Peak Jar Completed"] && !__quest_state["Level 9"].finished && $item[jar of oil].available_amount() == 0 && g.available_amount() >= 3) - description.listAppend("Crude oil congealer: lets you create a jar of oil."); - description.listAppend("Food, drink, +100% spleen item for fifty turns."); - resource_entries.listAppend(ChecklistEntryMake("__item g", "shop.php?whichshop=glover", ChecklistSubentryMake(pluralise(g) + " available", "", description), 3).ChecklistEntrySetIDTag("G-lover path G shop")); - } -} diff --git a/Source/relay/TourGuide/Paths/Gelatinous Noob.ash b/Source/relay/TourGuide/Paths/Gelatinous Noob.ash deleted file mode 100644 index 6024d4b7..00000000 --- a/Source/relay/TourGuide/Paths/Gelatinous Noob.ash +++ /dev/null @@ -1,364 +0,0 @@ -static -{ - item [skill][int] __gelatinous_items_that_give_skill; - - string [int] __gelatinous_skill_ids_to_descriptions {23001:"+1 hot res", 23002:"+1 hot res", 23003:"+2 hot res", 23004:"+2 hot res", 23005:"+3 hot res", 23006:"+1 cold res", 23007:"+1 cold res", 23008:"+2 cold res", 23009:"+2 cold res", 23010:"+3 cold res", 23011:"+1 stench res", 23012:"+1 stench res", 23013:"+2 stench res", 23014:"+2 stench res", 23015:"+3 stench res", 23016:"+1 spooky res", 23017:"+1 spooky res", 23018:"+2 spooky res", 23019:"+2 spooky res", 23020:"+3 spooky res", 23021:"+1 sleaze res", 23022:"+1 sleaze res", 23023:"+2 sleaze res", 23024:"+2 sleaze res", 23025:"+3 sleaze res", 23026:"+30 DA", 23027:"+40 DA", 23028:"+50 DA", 23029:"+60 DA", 23030:"+70 DA", 23031:"+5 DR", 23032:"+5 DR", 23033:"+10 DR", 23034:"+10 DR", 23035:"+20 DR", 23036:"+10% init", 23037:"+20% init", 23038:"+30% init", 23039:"+40% init", 23040:"+50% init", 23041:"+3 stats/fight", 23042:"+3 stats/fight", 23043:"+5 stats/fight", 23044:"+5 stats/fight", 23045:"+7 stats/fight", 23046:"+1 adv/absorbed item", 23047:"+1 adv/absorbed item", 23048:"+2 adv/absorbed item", 23049:"+2 adv/absorbed item", 23050:"+3 adv/absorbed item", 23051:"+5 stats/absorbed item", 23052:"+10 stats/absorbed item", 23053:"+15 stats/absorbed item", 23054:"+20 stats/absorbed item", 23055:"+25 stats/absorbed item", 23056:"+20% HP", 23057:"+30% HP", 23058:"+40% HP", 23059:"+50% HP", 23060:"+100% HP", 23061:"+20% MP", 23062:"+30% MP", 23063:"+40% MP", 23064:"+50% MP", 23065:"+100% MP", 23066:"+20% item", 23067:"+20% item", 23068:"+30% item", 23069:"+40% item", 23070:"+50% item", 23071:"+10% pickpocket", 23072:"+20% pickpocket", 23073:"+30% pickpocket", 23074:"+40% pickpocket", 23075:"+50% pickpocket", 23076:"+30% meat", 23077:"+40% meat", 23078:"+50% meat", 23079:"+60% meat", 23080:"+70% meat", 23081:"+5 muscle", 23082:"+10 muscle", 23083:"+15 muscle", 23084:"+20 muscle", 23085:"+25 muscle", 23086:"+5 myst", 23087:"+10 myst", 23088:"+15 myst", 23089:"+20 myst", 23090:"+25 myst", 23091:"+5 moxie", 23092:"+10 moxie", 23093:"+15 moxie", 23094:"+20 moxie", 23095:"+25 moxie", 23096:"+7 damage", 23097:"+9 damage", 23098:"+11 damage", 23099:"+13 damage", 23100:"+15 damage", 23101:"+3 Hot Damage", 23102:"+5 Hot Damage", 23103:"+7 Hot Damage", 23104:"+9 Hot Damage", 23105:"+11 Hot Damage", 23106:"+3 Cold Damage", 23107:"+5 Cold Damage", 23108:"+7 Cold Damage", 23109:"+9 Cold Damage", 23110:"+11 Cold Damage", 23111:"+3 Stench Damage", 23112:"+5 Stench Damage", 23113:"+7 Stench Damage", 23114:"+9 Stench Damage", 23115:"+11 Stench Damage", 23116:"+3 Spooky Damage", 23117:"+5 Spooky Damage", 23118:"+7 Spooky Damage", 23119:"+9 Spooky Damage", 23120:"+11 Spooky Damage", 23121:"+3 Sleaze Damage", 23122:"+5 Sleaze Damage", 23123:"+7 Sleaze Damage", 23124:"+9 Sleaze Damage", 23125:"+11 Sleaze Damage", 23301:"-combat buff", 23302:"-combat buff", 23303:"-combat buff", 23304:"+combat buff", 23305:"+combat buff", 23306:"+combat buff"}; - int [int] __gelatinous_evaluation_order {0:23301, 1:23302, 2:23303, 3:23304, 4:23305, 5:23306, 6:23046, 7:23047, 8:23048, 9:23049, 10:23050, 11:23051, 12:23052, 13:23053, 14:23054, 15:23055, 16:23041, 17:23042, 18:23043, 19:23044, 20:23045, 21:23066, 22:23067, 23:23068, 24:23069, 25:23070, 26:23076, 27:23077, 28:23078, 29:23079, 30:23080, 31:23026, 32:23027, 33:23028, 34:23029, 35:23030, 36:23031, 37:23032, 38:23033, 39:23034, 40:23035, 41:23036, 42:23037, 43:23038, 44:23039, 45:23040, 46:23056, 47:23057, 48:23058, 49:23059, 50:23060, 51:23061, 52:23062, 53:23063, 54:23064, 55:23065, 56:23071, 57:23072, 58:23073, 59:23074, 60:23075, 61:23001, 62:23002, 63:23003, 64:23004, 65:23005, 66:23006, 67:23007, 68:23008, 69:23009, 70:23010, 71:23011, 72:23012, 73:23013, 74:23014, 75:23015, 76:23016, 77:23017, 78:23018, 79:23019, 80:23020, 81:23021, 82:23022, 83:23023, 84:23024, 85:23025, 86:23081, 87:23082, 88:23083, 89:23084, 90:23085, 91:23086, 92:23087, 93:23088, 94:23089, 95:23090, 96:23091, 97:23092, 98:23093, 99:23094, 100:23095, 101:23096, 102:23097, 103:23098, 104:23099, 105:23100, 106:23101, 107:23102, 108:23103, 109:23104, 110:23105, 111:23106, 112:23107, 113:23108, 114:23109, 115:23110, 116:23111, 117:23112, 118:23113, 119:23114, 120:23115, 121:23116, 122:23117, 123:23118, 124:23119, 125:23120, 126:23121, 127:23122, 128:23123, 129:23124, 130:23125}; - - int [int] __gelatinous_skill_raw_modifier_number {23001:1, 23002:1, 23003:2, 23004:2, 23005:3, 23006:1, 23007:1, 23008:2, 23009:2, 23010:3, 23011:1, 23012:1, 23013:2, 23014:2, 23015:3, 23016:1, 23017:1, 23018:2, 23019:2, 23020:3, 23021:1, 23022:1, 23023:2, 23024:2, 23025:3, 23026:30, 23027:40, 23028:50, 23029:60, 23030:70, 23031:5, 23032:5, 23033:10, 23034:10, 23035:20, 23036:10, 23037:20, 23038:30, 23039:40, 23040:50, 23041:3, 23042:3, 23043:5, 23044:5, 23045:7, 23046:1, 23047:1, 23048:2, 23049:2, 23050:3, 23051:5, 23052:10, 23053:15, 23054:20, 23055:25, 23056:20, 23057:30, 23058:40, 23059:50, 23060:100, 23061:20, 23062:30, 23063:40, 23064:50, 23065:100, 23066:20, 23067:20, 23068:30, 23069:40, 23070:50, 23071:10, 23072:20, 23073:30, 23074:40, 23075:50, 23076:30, 23077:40, 23078:50, 23079:60, 23080:70, 23081:5, 23082:10, 23083:15, 23084:20, 23085:25, 23086:5, 23087:10, 23088:15, 23089:20, 23090:25, 23091:5, 23092:10, 23093:15, 23094:20, 23095:25, 23096:7, 23097:9, 23098:11, 23099:13, 23100:15, 23101:3, 23102:5, 23103:7, 23104:9, 23105:11, 23106:3, 23107:5, 23108:7, 23109:9, 23110:11, 23111:3, 23112:5, 23113:7, 23114:9, 23115:11, 23116:3, 23117:5, 23118:7, 23119:9, 23120:11, 23121:3, 23122:5, 23123:7, 23124:9, 23125:11}; -} -void initialiseGelatinousStatics() -{ - if (__gelatinous_items_that_give_skill.count() > 0) - return; - foreach it in $items[] - { - if (!it.item_is_pvp_stealable() && !(it.gift && it.discardable) && !(lookupItems("interesting clod of dirt,dirty bottlecap,discarded button") contains it)) continue; - - if ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3] contains it.to_slot()) //familiar equipment fine - continue; - if ($items[map to Madness Reef,map to the Marinara Trench,map to Anemone Mine,map to the Dive Bar,map to the Skate Park, glass of "milk", cup of "tea", thermos of "whiskey", Lucky Lindy, Bee's Knees, Sockdollager, Ish Kabibble, Hot Socks, Phonus Balonus, Flivver, Sloppy Jalopy] contains it) //' - continue; - - int lookup = it.descid.to_int_silent() % 125 + 23001; - int item_id = it.to_int(); - //Hardcoded: - if (item_id == 9353) - lookup = 23302; - else if (item_id == 9349) - lookup = 23304; - else if (item_id == 9357) - lookup = 23301; - else if (item_id == 9359) - lookup = 23306; - else if (item_id == 9361) - lookup = 23305; - else if (item_id == 9354) - lookup = 23303; - skill s = lookup.to_skill(); - if (!(__gelatinous_items_that_give_skill contains s)) - __gelatinous_items_that_give_skill[s] = listMakeBlankItem(); - __gelatinous_items_that_give_skill[s].listAppend(it); - } - - -} - - -RegisterTaskGenerationFunction("PathGelatinousNoobGenerateTasks"); -void PathGelatinousNoobGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_GELATINOUS_NOOB) return; - - int total_absorptions = 2 + MIN(13, my_level()); - int absorptions_used = get_property_int("_noobSkillCount"); - //int absorptions_used = my_absorbs(); //FIXME next point release, 17.7 - int absorptions_left = total_absorptions - absorptions_used; - if (!mafiaIsPastRevision(17821)) //tracking - absorptions_left = 0; - if (absorptions_left > 0) - { - initialiseGelatinousStatics(); - string [int] description; - - - if (true) - { - boolean [item] blocklist; - - if (__quest_state["Level 9"].state_int["peak tests remaining"] > 0) - blocklist[$item[rusty hedge trimmers]] = true; - if ($item[goat cheese].available_amount() <= 3 && !__quest_state["Level 8"].state_boolean["Past mine"]) - { - blocklist[$item[goat cheese]] = true; - blocklist[$item[goat cheese pizza]] = true; - } - foreach it in $items[print screen button,spooky-gro fertilizer,cuppa obscuri tea] - blocklist[it] = true; - if (__quest_state["Pirate Quest"].state_boolean["hot wings relevant"] && $item[hot wing].available_amount() <= 3) - blocklist[$item[hot wing]] = true; - - //Collect a list for each grouping: - - int [int][int] first_level_group_evaluation_indices; - for grouping_index from 23125 to 23001 by -5 - { - int [int] group_indices; - for i from grouping_index to grouping_index - 4 by -1 - { - group_indices.listAppend(i); - } - first_level_group_evaluation_indices[grouping_index] = group_indices; - } - first_level_group_evaluation_indices[23301] = listMake(23303, 23302, 23301); - first_level_group_evaluation_indices[23304] = listMake(23306, 23305, 23304); - - string [int][int] grouping_to_relevant_items; - - skill [int][int] grouping_to_group_skills; - skill [int] grouping_to_relevant_items_skill; - boolean [int] grouping_should_grey_out; - //for grouping_index from 23125 to 23001 by -5 - foreach grouping_index in first_level_group_evaluation_indices - { - int [int] group_indices = first_level_group_evaluation_indices[grouping_index]; - - skill [int] group_skills; - //for i from grouping_index to grouping_index - 4 by -1 - foreach key2, i in group_indices - { - skill s = i.to_skill(); - if (s.have_skill()) continue; - group_skills.listAppend(s); - } - //print_html("group_skills = " + group_skills.to_json()); - grouping_to_group_skills[grouping_index] = group_skills; - //The ideal here is, we want to find a list of items for the best skill in the group. - //If that's not possible, we do the second best skill, etc. We also list the best pull, but only if it's relevant - item pullable_item = $item[none]; - item [int] relevant_items; - boolean on_first = true; - foreach key, s in group_skills - { - if (key > 0) - on_first = false; - foreach key2, it in __gelatinous_items_that_give_skill[s] - { - if (blocklist contains it) - continue; - if (it.available_amount() == 0 && it.creatable_amount() == 0 && (it.npc_price() == 0 || it.npc_price() > my_meat())) - { - if (pulls_remaining() > 0 && !it.gift && key == 0 && it.is_unrestricted()) - { - if (pullable_item == $item[none] || (it.historical_price() < pullable_item.historical_price() && it.historical_price() > 0)) - pullable_item = it; - } - continue; - } - relevant_items.listAppend(it); - } - if (relevant_items.count() > 0) - { - grouping_to_relevant_items_skill[grouping_index] = s; - break; - } - } - boolean should_grey_out = false; - if (grouping_to_relevant_items_skill[grouping_index] == $skill[none]) - { - grouping_to_relevant_items_skill[grouping_index] = group_skills[0]; - should_grey_out = true; - } - grouping_should_grey_out[grouping_index] = should_grey_out; - string [int] relevant_items_out; - //sort relevant_items by (value.historical_price() <= 0 ? 999999999 : value.historical_price()); - //NPC price is more relevant in-run, since cost of acquisition. - sort relevant_items by (value.npc_price() > 0 ? value.npc_price() : (value.historical_price() <= 0 ? 999999999 : value.historical_price())); - if (relevant_items[0].npc_price() > 0 && relevant_items[0].npc_price() <= 1000) //something cheap and obtainable? ignore the rest - { - //examples: fermenting powder, herbs, pickled egg - relevant_items_out.listAppend(relevant_items[0]); - } - else - { - foreach key, it in relevant_items - { - if (key > 2) break; - relevant_items_out.listAppend(it); - } - } - if (pulls_remaining() > 0 && (!on_first || relevant_items.count() == 0) && pullable_item != $item[none]) - { - string line = pullable_item + " (pull"; - if (!should_grey_out) - line += " for +" + __gelatinous_skill_raw_modifier_number[group_skills[0].to_int()]; - line += ")"; - line = HTMLGenerateSpanFont(line, "gray"); - relevant_items_out.listPrepend(line); - } - grouping_to_relevant_items[grouping_index] = relevant_items_out; - } - - foreach key, s_id in __gelatinous_evaluation_order - { - if (s_id % 5 != 0 && s_id != 23301 && s_id != 23304) continue; - skill s = s_id.to_skill(); - int grouping_index = s_id; - - string [int] relevant_items = grouping_to_relevant_items[grouping_index]; - skill [int] group_skills = grouping_to_group_skills[grouping_index]; - skill relevant_items_skill = grouping_to_relevant_items_skill[grouping_index]; - - //print_html("s = " + s + " group_skills = " + group_skills.to_json() + ", relevant_items = " + relevant_items.to_json()); - - //description.listAppend(relevant_items_skill + ": " + __gelatinous_skill_ids_to_descriptions[relevant_items_skill.to_int()]); - string extra_data; - if (lookupFamiliar("robortender").familiar_is_usable()) - { - phylum [int] phylums_to_run_against; - if (grouping_index == 23301) - { - if (!lookupSkill("bendable knees").have_skill() && lookupItem("bottle of gregnadigne").available_amount() == 0) - phylums_to_run_against.listAppend($phylum[humanoid]); - if (!lookupSkill("retractable toes").have_skill() && lookupItem("cocktail mushroom").available_amount() == 0) - phylums_to_run_against.listAppend($phylum[goblin]); - if (!lookupSkill("ink gland").have_skill() && lookupItem("shot of granola liqueur").available_amount() == 0) - phylums_to_run_against.listAppend($phylum[hippy]); - } - if (grouping_index == 23304) - { - if (!lookupSkill("frown muscles").have_skill() && lookupItem("bottle of novelty hot sauce").available_amount() == 0) - phylums_to_run_against.listAppend($phylum[demon]); - if (!lookupSkill("anger glands").have_skill() && lookupItem("limepatch").available_amount() == 0) - phylums_to_run_against.listAppend($phylum[pirate]); - if (!lookupSkill("powerful vocal chords").have_skill() && lookupItem("baby oil shooter").available_amount() == 0) - phylums_to_run_against.listAppend($phylum[orc]); - } - if (phylums_to_run_against.count() > 0) - extra_data += "Run robortender against " + phylums_to_run_against.listJoinComponents(", ", "and"); - } - - string line = HTMLGenerateSpanOfClass(__gelatinous_skill_ids_to_descriptions[relevant_items_skill.to_int()], "r_bold"); - if (relevant_items.count() > 0 || extra_data != "") - { - if (relevant_items.count() > 0) - line += ": " + relevant_items.listJoinComponents(", ", "or"); - if (extra_data != "") - line += "|*" + extra_data; - line += "."; - if (grouping_should_grey_out[grouping_index]) - line = HTMLGenerateSpanFont(line, "gray"); - description.listAppend(line); - } - - } - description.listAppend("Or equipment, for their buffs." + (combat_rate_modifier() > -25 ? "|*Bram's choker, ring of conflict, duonoculars, rusted shootin' iron, or red shoe especially." : "")); - if (lookupSkill("Large Intestine").have_skill()) - description.listAppend("Or potted cactus, for +5 adventures."); - //foreach s in __gelatinous_items_that_give_skill - /*foreach key, s_id in __gelatinous_evaluation_order - { - skill s = s_id.to_skill(); - if (s.have_skill()) continue; - - string [int] relevant_items; - item pullable_item = $item[none]; - boolean should_grey_out = false; - foreach key, it in __gelatinous_items_that_give_skill[s] - { - if (blocklist contains it) - continue; - if (it.available_amount() == 0 && it.creatable_amount() == 0 && (it.npc_price() == 0 || it.npc_price() > my_meat())) - { - if (pulls_remaining() > 0 && !it.gift) - { - if (pullable_item == $item[none] || (it.historical_price() < pullable_item.historical_price() && it.historical_price() > 0)) - pullable_item = it; - } - continue; - } - relevant_items.listAppend(it); - } - if (pullable_item != $item[none] && relevant_items.count() == 0) - { - if (relevant_items.count() == 0) - should_grey_out = true; - relevant_items.listAppend(HTMLGenerateSpanFont(pullable_item + " (pull)", "gray")); - } - string line = HTMLGenerateSpanOfClass(__gelatinous_skill_ids_to_descriptions[s.to_int()], "r_bold"); - if (relevant_items.count() > 0) - line += ": " + relevant_items.listJoinComponents(", ", "or") + "."; - else - should_grey_out = true; - if (should_grey_out) - line = HTMLGenerateSpanFont(line, "gray"); - description.listAppend(line); - }*/ - } - optional_task_entries.listAppend(ChecklistEntryMake("__familiar Gelatinous Cubeling", "inventory.php", ChecklistSubentryMake("Absorb " + pluralise(absorptions_left, "item", "items"), "", description), -1).ChecklistEntrySetIDTag("Gelatinous noob path absorption suggestions")); - } - - if (lookupFamiliar("Robortender").have_familiar()) - { - - string url = ""; - - if (my_familiar() != lookupFamiliar("Robortender")) - url = "familiar.php"; - phylum [int] phylums_to_run_against; - location [int] suggested_locations; - string [int] matchup_type; - boolean have_minus = false; - boolean have_plus = false; - if (!lookupSkill("bendable knees").have_skill() && lookupItem("bottle of gregnadigne").available_amount() == 0) - { - phylums_to_run_against.listAppend($phylum[humanoid]); - suggested_locations.listAppend($location[the old landfill]); - matchup_type.listAppend("-"); - have_minus = true; - } - if (!lookupSkill("retractable toes").have_skill() && lookupItem("cocktail mushroom").available_amount() == 0) - { - phylums_to_run_against.listAppend($phylum[goblin]); - suggested_locations.listAppend($location[the outskirts of cobb's knob]); - matchup_type.listAppend("-"); - have_minus = true; - } - if (!lookupSkill("ink gland").have_skill() && lookupItem("shot of granola liqueur").available_amount() == 0) - { - phylums_to_run_against.listAppend($phylum[hippy]); - suggested_locations.listAppend($location[The Hippy Camp]); - matchup_type.listAppend("-"); - have_minus = true; - } - if (!lookupSkill("frown muscles").have_skill() && lookupItem("bottle of novelty hot sauce").available_amount() == 0) - { - phylums_to_run_against.listAppend($phylum[demon]); - suggested_locations.listAppend($location[the dark heart of the woods]); - matchup_type.listAppend("+"); - have_plus = true; - } - if (!lookupSkill("anger glands").have_skill() && lookupItem("limepatch").available_amount() == 0) - { - phylums_to_run_against.listAppend($phylum[pirate]); - suggested_locations.listAppend($location[the obligatory pirate's cove]); - matchup_type.listAppend("+"); - have_plus = true; - } - if (!lookupSkill("powerful vocal chords").have_skill() && lookupItem("baby oil shooter").available_amount() == 0) - { - phylums_to_run_against.listAppend($phylum[orc]); - suggested_locations.listAppend($location[The Orcish Frat House]); - matchup_type.listAppend("+"); - have_plus = true; - } - - string [int] skill_types; - if (have_minus) - skill_types.listAppend("-combat"); - if (have_plus) - skill_types.listAppend("+combat"); - string [int] description; - description.listAppend("Collect components for " + skill_types.listJoinComponents(", ", "and") + " skills."); - if (suggested_locations.count() > 0) - { - string [int] locations_out; - foreach key, l in suggested_locations - { - locations_out.listAppend(l + " (" + matchup_type[key] + ")"); - } - description.listAppend("Could look in " + locations_out.listJoinComponents(", ", "and") + "."); - if (url == "") - url = suggested_locations[0].getClickableURLForLocation(); - } - if (phylums_to_run_against.count() > 0) - { - string [int] phylums_out; - foreach key, p in phylums_to_run_against - { - phylums_out.listAppend(p + " (" + matchup_type[key] + ")"); - } - optional_task_entries.listAppend(ChecklistEntryMake("__familiar Robortender", url, ChecklistSubentryMake("Run robortender against " + phylums_out.listJoinComponents(", ", "and"), "", description), 5).ChecklistEntrySetIDTag("Gelatinous noob path robortender familiar")); - } - } -} diff --git a/Source/relay/TourGuide/Paths/Grey Goo.ash b/Source/relay/TourGuide/Paths/Grey Goo.ash deleted file mode 100644 index 0d23fef3..00000000 --- a/Source/relay/TourGuide/Paths/Grey Goo.ash +++ /dev/null @@ -1,10 +0,0 @@ -RegisterTaskGenerationFunction("PathGreyGooGenerateTasks"); -void PathGreyGooGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_GREY_GOO) - return; - - if (my_daycount() >= 3) { - task_entries.listAppend(ChecklistEntryMake("astral gash", "place.php?whichplace=greygoo", ChecklistSubentryMake("Ascend", "", "Prism appeared. Ascend whenever."),-10).ChecklistEntrySetIDTag("Grey goo path prism open")); - } -} diff --git a/Source/relay/TourGuide/Paths/Heavy Rains.ash b/Source/relay/TourGuide/Paths/Heavy Rains.ash deleted file mode 100644 index 14f6efb1..00000000 --- a/Source/relay/TourGuide/Paths/Heavy Rains.ash +++ /dev/null @@ -1,232 +0,0 @@ - -RegisterTaskGenerationFunction("PathHeavyRainsGenerateTasks"); -void PathHeavyRainsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_HEAVY_RAINS) return; - - item thunder_item = $item[thunder thigh]; - item rain_item = $item[aquaconda brain]; - item lightning_item = $item[lightning milk]; - - boolean [item] all_skill_items; - all_skill_items[thunder_item] = true; - all_skill_items[rain_item] = true; - all_skill_items[lightning_item] = true; - - if (thunder_item.available_amount() + rain_item.available_amount() + lightning_item.available_amount() > 0) - { - //Let's learn skills: - skill [item][int] skills_for_item; - - skills_for_item[thunder_item] = listMakeBlankSkill(); - skills_for_item[rain_item] = listMakeBlankSkill(); - skills_for_item[lightning_item] = listMakeBlankSkill(); - - skills_for_item[thunder_item].listAppend($skill[Thunder Clap]); - skills_for_item[thunder_item].listAppend($skill[Thundercloud]); - skills_for_item[thunder_item].listAppend($skill[Thunder Bird]); - skills_for_item[thunder_item].listAppend($skill[Thunderheart]); - skills_for_item[thunder_item].listAppend($skill[Thunderstrike]); - skills_for_item[thunder_item].listAppend($skill[Thunder Down Underwear]); - skills_for_item[thunder_item].listAppend($skill[Thunder Thighs]); - - skills_for_item[rain_item].listAppend($skill[Rain Man]); - skills_for_item[rain_item].listAppend($skill[Rainy Day]); - skills_for_item[rain_item].listAppend($skill[Make it Rain]); - skills_for_item[rain_item].listAppend($skill[Rain Dance]); - skills_for_item[rain_item].listAppend($skill[Rainbow]); - skills_for_item[rain_item].listAppend($skill[Rain Coat]); - skills_for_item[rain_item].listAppend($skill[Rain Delay]); - - skills_for_item[lightning_item].listAppend($skill[Lightning Strike]); - skills_for_item[lightning_item].listAppend($skill[Clean-Hair Lightning]); - skills_for_item[lightning_item].listAppend($skill[Ball Lightning]); - skills_for_item[lightning_item].listAppend($skill[Sheet Lightning]); - skills_for_item[lightning_item].listAppend($skill[[16025]Lightning Bolt]); - skills_for_item[lightning_item].listAppend($skill[Lightning Rod]); - skills_for_item[lightning_item].listAppend($skill[Riding the Lightning]); - - string [skill] description_for_skill; - - description_for_skill[$skill[Thunder Clap]] = "Turn-costing banish. (lasts 40 turns, no stats, no items, no meat)"; - description_for_skill[$skill[Thundercloud]] = "Water depth increasing effect"; - description_for_skill[$skill[Thunderheart]] = "+100% HP, surviving"; - description_for_skill[$skill[Thunderstrike]] = "Monster stunning"; - description_for_skill[$skill[Thunder Thighs]] = "Thunder regen, passive"; - description_for_skill[$skill[Thunder Bird]] = "Monster deleveling"; - if (in_hardcore()) - description_for_skill[$skill[Thunder Down Underwear]] = "safety pants (if you want to)"; - - - description_for_skill[$skill[Rain Man]] = "Fax any monster repeatedly"; - description_for_skill[$skill[Rainy Day]] = "Water depth increasing effect"; - if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) - description_for_skill[$skill[Make it Rain]] = "+300% meat for a single turn (nuns)"; - description_for_skill[$skill[Rain Dance]] = "+20% item effect"; - description_for_skill[$skill[Rain Delay]] = "passive, +3 resist all"; - - description_for_skill[$skill[Lightning Strike]] = "Kills monster, gain stats/drops, makes adventure not use a turn (effective free run/hipster)"; - description_for_skill[$skill[Ball Lightning]] = "Yellow ray (100 turn cooldown)"; - description_for_skill[$skill[Riding the Lightning]] = "passive, +100% max MP"; - - - description_for_skill[$skill[Sheet Lightning]] = "+100% spell damage effect"; - //description_for_skill[$skill[Thunder Down Underwear]] = "Summon once/day pants: +100 DA/HP, HP regen"; - //description_for_skill[$skill[Rain Coat]] = "Summons once/day shirt: +40% init, +10% item, +2 resist all"; - //description_for_skill[$skill[Lightning Rod]] = "Summons once/day weapon: +200% spell damage"; - - - int [item] available_skills_for_item; - int [item] max_available_skills_for_item; - - foreach it in skills_for_item - { - foreach key in skills_for_item[it] - { - skill s = skills_for_item[it][key]; - if (s.skill_is_usable()) - continue; - max_available_skills_for_item[it] += 1; - available_skills_for_item[it] = MIN(max_available_skills_for_item[it], it.available_amount()); - } - } - - //available_skills_for_item[thunder_item] = 7; - //available_skills_for_item[rain_item] = 7; - //available_skills_for_item[lightning_item] = 7; - - - string [int] description; - - string [int] available_skill_types; - - string [int] items_to_use_description; - - string [item] item_to_typename; - item_to_typename[thunder_item] = "thunder"; - item_to_typename[rain_item] = "rain"; - item_to_typename[lightning_item] = "lightning"; - - string url = ""; - string [item] item_to_url; - - item_to_url[thunder_item] = "inv_use.php?which=3&whichitem=7648&pwd=" + my_hash(); - item_to_url[rain_item] = "inv_use.php?which=3&whichitem=7647&pwd=" + my_hash(); - foreach it in all_skill_items - { - if (available_skills_for_item[it] > 0) - { - available_skill_types.listAppend(item_to_typename[it]); - items_to_use_description.listAppend(pluralise(available_skills_for_item[it], it)); - - if (url.length() == 0) - url = item_to_url[it]; - } - } - - url = "inventory.php?which=3"; //mafia won't remove the skill glands quite properly (needs to happen when you click the NC option, not at inv_use.php) - - description.listAppend("Use " + items_to_use_description.listJoinComponents(", ", "and") + "."); - - - foreach it in all_skill_items - { - if (available_skills_for_item[it] == 0) - continue; - - int other_count = 0; - string [int] relevant_descriptions; - foreach key in skills_for_item[it] - { - skill s = skills_for_item[it][key]; - if (s.skill_is_usable()) - continue; - if (!(description_for_skill contains s)) - { - other_count += 1; - continue; - } - relevant_descriptions.listAppend(s + ": " + description_for_skill[s]); - } - if (other_count > 0) - { - if (relevant_descriptions.count() > 0) - relevant_descriptions.listAppend("Or " + pluraliseWordy(other_count, "other skill", "other skills") + "."); - else - relevant_descriptions.listAppend(pluraliseWordy(other_count, "possible skill", "possible skills").capitaliseFirstLetter() + "."); - } - - description.listAppend(HTMLGenerateSpanOfClass(item_to_typename[it].capitaliseFirstLetter() + ":", "r_bold") + HTMLGenerateIndentedText(relevant_descriptions.listJoinComponents("
"))); - } - - if (available_skill_types.count() > 0) - task_entries.listAppend(ChecklistEntryMake("__familiar personal raincloud", url, ChecklistSubentryMake("Learn " + available_skill_types.listJoinComponents(", ", "and") + " skills", "", description), -10).ChecklistEntrySetIDTag("Heavy rains path new skills")); - } -} - -RegisterResourceGenerationFunction("PathHeavyRainsGenerateResource"); -void PathHeavyRainsGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_HEAVY_RAINS) return; - - //resource_entries.listAppend(ChecklistEntryMake("__item gym membership card", "inventory.php?ftext=gym+membership+card", ChecklistSubentryMake(pluralise($item[gym membership card]), "", description), importance_level_item)); - - - int fishbone_amount = $item[freshwater fishbone].available_amount(); - - if (fishbone_amount >= 5) //only show if there's something to buy - { - int [item] fishbone_item_costs; - string [item] fishbone_item_descriptions; - - //Are these worth suggesting? - //fishbone_item_descriptions[$item[fishbone facemask]] = "-30 ML"; - //fishbone_item_costs[$item[fishbone facemask]] = 5; - //fishbone_item_descriptions[$item[fishbone fins]] = "survivability"; - //fishbone_item_costs[$item[fishbone fins]] = 20; - - fishbone_item_descriptions[$item[fishbone bracers]] = "+100% spell damage"; - fishbone_item_costs[$item[fishbone bracers]] = 5; - - - fishbone_item_descriptions[$item[fishbone corset]] = "-water depth"; - fishbone_item_costs[$item[fishbone corset]] = 10; - - - fishbone_item_descriptions[$item[fishbone kneepads]] = "+60% init"; - fishbone_item_costs[$item[fishbone kneepads]] = 15; - - fishbone_item_descriptions[$item[fishbone catcher's mitt]] = "-washaway"; - fishbone_item_costs[$item[fishbone catcher's mitt]] = 30; - - string [int] description; - foreach it in fishbone_item_costs - { - if (it == $item[none]) - continue; - int cost = fishbone_item_costs[it]; - - - int amount_needed = 1; - if (it.to_slot() == $slot[acc1] || it.to_slot() == $slot[acc2] || it.to_slot() == $slot[acc3]) - amount_needed = 3; - - int creatable = 0; - if (fishbone_item_costs[it] != 0) - creatable = MIN(amount_needed, fishbone_amount / fishbone_item_costs[it]); - - if (it.available_amount() >= amount_needed || creatable == 0) - continue; - int amount_to_make = MIN(creatable, amount_needed - it.available_amount()); - - description.listAppend(pluralise(amount_to_make, it) + ": " + fishbone_item_descriptions[it]); - } - resource_entries.listAppend(ChecklistEntryMake("__item freshwater fishbone", "shop.php?whichshop=fishbones", ChecklistSubentryMake(pluralise($item[freshwater fishbone]), "", description), 7).ChecklistEntrySetIDTag("Heavy rains path fishbone shop")); - } - - if ($item[catfish whiskers].available_amount() > 0) - { - //should we add in area suggestions? - resource_entries.listAppend(ChecklistEntryMake("__item catfish whiskers", "inventory.php?ftext=catfish+whiskers", ChecklistSubentryMake(pluralise($item[catfish whiskers]), "", "40 turns of -washaway"), 7).ChecklistEntrySetIDTag("Heavy rains path catfish whiskers resource")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Paths/KOLHS.ash b/Source/relay/TourGuide/Paths/KOLHS.ash deleted file mode 100644 index de0373d3..00000000 --- a/Source/relay/TourGuide/Paths/KOLHS.ash +++ /dev/null @@ -1,162 +0,0 @@ - -RegisterTaskGenerationFunction("PathKOLHSGenerateTasks"); -void PathKOLHSGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_KOLHS) - return; - - item [string][int] items_wanted_in_classes; - effect [string] relevant_intrinsic; - items_wanted_in_classes["Art Class"] = listMakeBlankItem(); - relevant_intrinsic["Art Class"] = $effect[greaser lightnin']; - items_wanted_in_classes["Art Class"].listAppend($item[quasireligious sculpture]); - items_wanted_in_classes["Art Class"].listAppend($item[Sticky clay homunculus]); - items_wanted_in_classes["Art Class"].listAppend($item[Modeling claymore]); - items_wanted_in_classes["Art Class"].listAppend($item[Giant eraser]); - - items_wanted_in_classes["Shop Class"] = listMakeBlankItem(); - relevant_intrinsic["Shop Class"] = $effect[Jamming with the Jocks]; - items_wanted_in_classes["Shop Class"].listAppend($item[miniature suspension bridge]); - items_wanted_in_classes["Shop Class"].listAppend($item[world's most dangerous birdhouse]); - items_wanted_in_classes["Shop Class"].listAppend($item[deathchucks]); - if ($skill[Spirit of Rigatoni].have_skill() && my_primestat() == $stat[mysticality]) - items_wanted_in_classes["Shop Class"].listAppend($item[Staff of the Lunch Lady]); - - items_wanted_in_classes["Chemistry Class"] = listMakeBlankItem(); - items_wanted_in_classes["Chemistry Class"].listAppend($item[grains of salt]); - items_wanted_in_classes["Chemistry Class"].listAppend($item[Dirty stinkbomb]); - items_wanted_in_classes["Chemistry Class"].listAppend($item[Sodium pentasomething]); - items_wanted_in_classes["Chemistry Class"].listAppend($item[superwater]); - items_wanted_in_classes["Chemistry Class"].listAppend($item[Yellowcake bomb]); - - string [item] class_item_description; - class_item_description[$item[giant eraser]] = "free runaway"; - class_item_description[$item[grains of salt]] = "+3 adventures from a food"; - class_item_description[$item[Dirty stinkbomb]] = "banisher"; - class_item_description[$item[Sodium pentasomething]] = "+20 ML for 20 turns potion"; - class_item_description[$item[superwater]] = "50 turns of ultrahydrated"; - class_item_description[$item[Yellowcake bomb]] = "75-turn yellow-ray"; - class_item_description[$item[quasireligious sculpture]] = "-4.5 evil in cyrpt"; - class_item_description[$item[Sticky clay homunculus]] = "monster copier without daily limit"; - class_item_description[$item[Modeling claymore]] = "clears battlefield a bit"; - class_item_description[$item[miniature suspension bridge]] = "10 planks for the chasm bridge"; - class_item_description[$item[world's most dangerous birdhouse]] = "instakill"; - class_item_description[$item[deathchucks]] = "free banisher"; - class_item_description[$item[Staff of the Lunch Lady]] = "chefstaff"; - - ChecklistSubentry subentry; - subentry.header = "Kingdom of Loathing High School"; - - int adventures_used = get_property_int("_kolhsAdventures"); - int adventures_remaining = 40 - adventures_used; - int bell_ring_ring_ring = get_property_int("_kolhsSavedByTheBell"); - int ring_ring_ring_ring_left = 3 - bell_ring_ring_ring; - int priority = 0; - if (adventures_remaining > 0) - { - priority = -11; - if ($effect[jamming with the jocks].have_effect() == 0 && $effect[greaser lightnin'].have_effect() == 0 && $effect[Nerd is the Word].have_effect() == 0) - subentry.entries.listAppend("Acquire intrinsic in halls - use a moxie, muscle, or mysticality combat skill."); - if ($effect[jamming with the jocks].have_effect() > 0) - subentry.entries.listAppend("Adventure in shop class."); - if ($effect[greaser lightnin'].have_effect() > 0) - subentry.entries.listAppend("Adventure in art class."); - if ($effect[Nerd is the Word].have_effect() > 0) - subentry.entries.listAppend("Adventure in chemistry class."); - subentry.entries.listAppend(pluralise(adventures_remaining, "adventure", "adventures") + " left in school."); - } - else if (ring_ring_ring_ring_left > 0) - { - subentry.entries.listAppend(pluralise(ring_ring_ring_ring_left, "bell ring", "bell rings") + " left."); - if ($item[Yearbook Club Camera].available_amount() == 0) - subentry.entries.listAppend("Could acquire a yearbook camera. (Yearbook Club)"); - else if (get_property_boolean("yearbookCameraPending") && my_daycount() > 1) - subentry.entries.listAppend("Could turn yesterday's photograph... if you took it yesterday..."); - - subentry.entries.listAppend("Choir club for a +100% meat, +50% item buff.|It's important to sing every day!"); - - if (__misc_state["need to level"]) - { - if (my_primestat() == $stat[muscle]) - { - subentry.entries.listAppend("Gym - 50 turns of +2 mainstat/fight."); - } - else if (my_primestat() == $stat[mysticality]) - { - subentry.entries.listAppend("Undead Poets Society - 50 turns of +2 mainstat/fight."); - } - else if (my_primestat() == $stat[moxie]) - { - subentry.entries.listAppend("Bleachers - 50 turns of +2 mainstat/fight."); - } - } - - string class_can_make_things_in; - boolean [item] potential_items_creatable; - string [item] creatable_item_descriptions; - if ($effect[jamming with the jocks].have_effect() > 0) - { - class_can_make_things_in = "Shop Class"; - } - if ($effect[greaser lightnin'].have_effect() > 0) - { - class_can_make_things_in = "Art Class"; - } - if ($effect[Nerd is the Word].have_effect() > 0) - { - class_can_make_things_in = "Chemistry Class"; - } - if (class_can_make_things_in != "") - { - string [int] sorts_of_things; - foreach key, it in items_wanted_in_classes[class_can_make_things_in] - { - if (it.creatable_amount() > 0) - { - string line = pluralise(it.creatable_amount(), it); - if (class_item_description contains it) - line += " - " + class_item_description[it] + "."; - sorts_of_things.listAppend(line); - } - } - string line = class_can_make_things_in + " - make all sorts of things"; - if (sorts_of_things.count() > 0) - line += ":|*" + sorts_of_things.listJoinComponents("|*"); - else - line += "."; - subentry.entries.listAppend(line); - } - } - - if (adventures_remaining <= 0) - { - if ($item[Yearbook Club Camera].available_amount() > 0 && !get_property_boolean("yearbookCameraPending") && get_property("yearbookCameraTarget") != "" && get_property_int("yearbookCameraUpgrades") < 21) - { - string line = "Could take a picture of a " + get_property("yearbookCameraTarget") + "."; //"mine worker" is a seen value - if ($item[Yearbook Club Camera].equipped_amount() == 0) - line += "|Equip the yearbook club camera first."; - subentry.entries.listAppend(line); - } - } - - if (subentry.entries.count() > 0) - task_entries.listAppend(ChecklistEntryMake("high school", "place.php?whichplace=KOLHS", listMake(subentry), priority, $locations[the hallowed halls, shop class, chemistry class, art class]).ChecklistEntrySetIDTag("KoLHS path school time")); - - - foreach it in $items[can of the cheapest beer,bottle of fruity "wine",single swig of vodka] - { - if (it.available_amount() > 0 && my_inebriety() < 8) //is this eight or nine or - { - int importance = -11; - string [int] description; - description.listAppend("Next one won't show up until you do."); - if (__campground[$item[portable mayo clinic]] > 0) - { - importance = -10; - description.listAppend("Or drink via the mayo clinic."); - } - task_entries.listAppend(ChecklistEntryMake("__item " + it, "", ChecklistSubentryMake("Drink " + it, "", description), importance).ChecklistEntrySetIDTag("KoLHS path booze for minors")); - break; - } - } -} diff --git a/Source/relay/TourGuide/Paths/Legacy of Loathing.ash b/Source/relay/TourGuide/Paths/Legacy of Loathing.ash deleted file mode 100644 index fc96a296..00000000 --- a/Source/relay/TourGuide/Paths/Legacy of Loathing.ash +++ /dev/null @@ -1,37 +0,0 @@ -RegisterTaskGenerationFunction("PathLegacyOfLoathingGenerateTasks"); -void PathLegacyOfLoathingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - - // Variables re: replicas available and path currency available. - int replicasAvailable = $item[replica mr. accessory].available_amount(); - int momsCreditCardAvailable = $item[replica ten dollars].available_amount(); - int momsCreditCardUsed = $path[legacy of loathing].points; - - // Only generate tile if the user has replicas and is in-path. - if (replicasAvailable + momsCreditCardAvailable == 0) return; - if (my_path() != $path[Legacy of Loathing]) return; - - ChecklistEntry entry; - string [int] description; - - entry.url = "shop.php?whichshop=mrreplica"; - entry.image_lookup_name = "__item replica mr. accessory"; - entry.tags.id = "Replicas available reminder"; - entry.importance_level = -11; - - - description.listAppend("Use all your replicas for shiny old treasures!"); - - if (momsCreditCardAvailable > 0) { - if (momsCreditCardUsed < 19) { - int usableDollars = min(19-momsCreditCardUsed, momsCreditCardAvailable); - description.listAppend(`You also have {usableDollars} usable replica ten dollars for more progression; try using those?`); - entry.url = "inventory.php?ftext=replica+ten+dollars"; - } - } - - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(replicasAvailable, "replica Mr. Accessory","replica Mr. Accessories"), "", description)); - - task_entries.listAppend(entry); - -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Paths/License to Adventure.ash b/Source/relay/TourGuide/Paths/License to Adventure.ash deleted file mode 100644 index 427fb730..00000000 --- a/Source/relay/TourGuide/Paths/License to Adventure.ash +++ /dev/null @@ -1,114 +0,0 @@ -RegisterTaskGenerationFunction("PathLicenseToAdventureGenerateTasks"); -void PathLicenseToAdventureGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_LICENSE_TO_ADVENTURE) - return; - if (lookupItem("Victor's Spoils").available_amount() > 0 && !get_property_boolean("_victorSpoilsUsed")) - { - task_entries.listAppend(ChecklistEntryMake("__item victor's spoils", "inventory.php?ftext=victor's+spoils", ChecklistSubentryMake("Use Victor's Spoils", "", "Gives eleven adventures."), 3).ChecklistEntrySetIDTag("License to adventure victor's spoils")); - } - - int lair_progress = get_property_int("_villainLairProgress"); - if (lair_progress < 999 && mafiaIsPastRevision(18065)) //revision is a guess - { - //_villainLairColorChoiceUsed, _villainLairDoorChoiceUsed, _villainLairSymbologyChoiceUsed - //_villainLairCanLidUsed, _villainLairFirecrackerUsed, _villainLairWebUsed - string [int] description; - string [int] modifiers; - description.listAppend("Prevents disavowed debuff. Costs quite a few turns, though, so consider skipping if you're leaderboarding."); - description.listAppend("Progress: " + lair_progress + " minions."); - - if (!get_property_boolean("bondSymbols") && get_property_boolean("_villainLairSymbologyChoiceUsed")) - description.listAppend("May want to learn LI-11's Universal Symbology Guide first, saves fifteen turns."); - - item [int] items_to_throw; - if (!get_property_boolean("_villainLairCanLidUsed") && $item[razor-sharp can lid].item_amount() > 0) - items_to_throw.listAppend($item[razor-sharp can lid]); - if (!get_property_boolean("_villainLairFirecrackerUsed")) - { - if ($item[Knob Goblin firecracker].item_amount() > 0) - items_to_throw.listAppend($item[Knob Goblin firecracker]); - else if (!$location[cobb's knob barracks].locationAvailable()) - description.listAppend("Farm a Knob Goblin Firecracker from the Outskirts of Cobb's Knob first, but only while you're still on that quest."); - } - if (!get_property_boolean("_villainLairWebUsed") && $item[spider web].item_amount() > 0) - items_to_throw.listAppend($item[spider web]); - if (lookupItem("can of Minions-Be-Gone").item_amount() > 0) - description.listAppend("Use " + pluralise(lookupItem("can of Minions-Be-Gone")) + "."); - - if (items_to_throw.count() > 0) - description.listAppend("Use " + items_to_throw.listJoinComponents(", ", "and") + " in combat at the lair."); - - if (lair_progress >= 5 && (!get_property_boolean("_villainLairColorChoiceUsed") || !get_property_boolean("_villainLairDoorChoiceUsed") || !get_property_boolean("_villainLairSymbologyChoiceUsed"))) - { - //I think there might be an in-game bug here? Someone noted seeing an NC first turn, even though CDMspading has it at five minions minimum? - modifiers.listAppend("-combat"); - description.listAppend("Run -combat to speed up acquiring choices."); - } - task_entries.listAppend(ChecklistEntryMake("__item victor's spoils", "", ChecklistSubentryMake("Adventure in the Villain's Lair", modifiers, description), 3, lookupLocations("Super Villain's Lair")).ChecklistEntrySetIDTag("License to adventure path villain's lair disavowed")); - } - - int social_capital_available = licenseToAdventureSocialCapitalAvailable(); - if (social_capital_available > 0) - { - int bond_points = get_property_int("bondPoints"); - string [int] description; - - //FIXME bond_points values are guesses - if (!get_property_boolean("bondJetpack") && social_capital_available >= 3) - { - description.listAppend("Short-Range Jetpack: saves quite a few turns"); - } - if (!get_property_boolean("bondSymbols") && social_capital_available >= 3) - { - description.listAppend("Universal Symbology Guide: if you're doing the lairs"); - } - if (!get_property_boolean("bondBridge") && social_capital_available >= 3 && bond_points >= 3) - { - description.listAppend("Portable Pocket Bridge: speeds up level nine quest"); - } - if (!get_property_boolean("bondWar") && social_capital_available >= 3 && bond_points >= 5) - { - description.listAppend("Trained Sniper, Felicity Snuggles: speeds up war"); - } - if (!get_property_boolean("bondItem3") && social_capital_available >= 4 && bond_points >= 7) - { - description.listAppend("Electromagnetic Ring: +30% item"); - } - if (!get_property_boolean("bondDrunk2") && social_capital_available >= 3) - { - description.listAppend("Soberness Injection Pen: +2 max drunkenness"); - } - if (!get_property_boolean("bondDrunk1") && social_capital_available >= 2) - { - description.listAppend("Belt-Implanted Still: +1 max drunkenness"); - } - if (!get_property_boolean("bondItem2") && social_capital_available >= 2) - { - description.listAppend("Sticky Climbing Gloves: +20% item"); - } - if (!get_property_boolean("bondAdv") && social_capital_available >= 1) - { - description.listAppend("Super-Accurate Spy Watch: +11 adventures/rollover"); - } - if (!get_property_boolean("bondMartiniTurn") && social_capital_available >= 1) - { - description.listAppend("Exotic Bartender, Barry L. Eagle: +1 adv/drink"); - } - if (!get_property_boolean("bondItem1") && social_capital_available >= 1) - { - description.listAppend("Master Art Thief, Sly Richard: +10% item"); - } - if (!get_property_boolean("bondInit") && social_capital_available >= 1) - { - description.listAppend("Jet-Powered Skis: +30% init"); - } - if (!get_property_boolean("bondSpleen") && social_capital_available >= 5 && bond_points >= 9) - { - description.listAppend("Robo-Speen: +2 max spleen."); - } - - - optional_task_entries.listAppend(ChecklistEntryMake("__item briefcase", "place.php?whichplace=town_right&action=town_bondhq", ChecklistSubentryMake("Spend " + social_capital_available + " social capital", "", description), 3).ChecklistEntrySetIDTag("License to adventure path bond points shop")); - } -} diff --git a/Source/relay/TourGuide/Paths/Low Key.ash b/Source/relay/TourGuide/Paths/Low Key.ash deleted file mode 100644 index 5862eab2..00000000 --- a/Source/relay/TourGuide/Paths/Low Key.ash +++ /dev/null @@ -1,36 +0,0 @@ - -RegisterLowKeyGenerationFunction("PathLowKeyGenerateKeys"); -void PathLowKeyGenerateKeys(ChecklistEntry [int] low_key_entries) { - - if (my_path().id != PATH_LOW_KEY_SUMMER) return; - if (__quest_state["Lair"].state_boolean["past keys"]) return; - - //LKS-specific keys - foreach index, key in LKS_keys { - if (key.was_used || key.it.available_amount() > 0) continue; - - string url; - - // Entries - string [int] description; - - // Set unlock messages or delay messages - if (!key.zone.locationAvailable()) { - description.listAppend("Unlock " + key.zone + " by " + key.condition_for_unlock); - url = key.pre_unlock_url; - } else { - int delayLeft = 11 - key.zone.turns_spent; - if (delayLeft > 0) - description.listAppend("Delay for " + pluralise(delayLeft, "turn", "turns") + " in " + key.zone + " to find key."); - else - description.listAppend("Find key on next turn in " + key.zone); - - url = key.zone.getClickableURLForLocation(); - } - - low_key_entries.listAppend(ChecklistEntryMake("__item " + key.it.name, url, ChecklistSubentryMake(key.it.name.capitaliseFirstLetter(), key.enchantment, description), boolean [location] {key.zone:true}).ChecklistEntrySetIDTag("Low key summer path " + key.it.name)); - } - - //base keys - SLevel13DoorGenerateMissingItems(low_key_entries); -} diff --git a/Source/relay/TourGuide/Paths/Nuclear Autumn.ash b/Source/relay/TourGuide/Paths/Nuclear Autumn.ash deleted file mode 100644 index 2566c03f..00000000 --- a/Source/relay/TourGuide/Paths/Nuclear Autumn.ash +++ /dev/null @@ -1,158 +0,0 @@ - -RegisterTaskGenerationFunction("PathNuclearAutumnGenerateTasks"); -void PathNuclearAutumnGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_NUCLEAR_AUTUMN) - return; - string url = "place.php?whichplace=falloutshelter"; - - ChecklistSubentry [int] subentries; - - if (get_property_int("falloutShelterLevel") >= 2 && (my_turncount() >= 50 || get_property_boolean("falloutShelterChronoUsed"))) - { - if ($item[Rad-Pro (1 oz.)].to_effect().have_effect() <= 1 && my_meat() >= 500 && $item[lead umbrella].equipped_amount() == 0) - { - url = "shop.php?whichshop=vault1"; - if ($item[Rad-Pro (1 oz.)].available_amount() > 0) - url = "inventory.php?ftext=rad-pro"; //FIXME - subentries.listAppend(ChecklistSubentryMake("Use rad-pro", "", "Protect from radiation.")); - } - } - - if (get_property_int("falloutShelterLevel") >= 8 && !get_property_boolean("falloutShelterCoolingTankUsed")) - { - subentries.listAppend(ChecklistSubentryMake("Use cooling tank", "", "Gain 300 rads.")); - } - if (get_property_int("falloutShelterLevel") >= 5 && !get_property_boolean("falloutShelterChronoUsed")) - { - subentries.listAppend(ChecklistSubentryMake("Use chronodynamics laboratory", "", "Increase rads gained.")); - } - if (get_property_int("falloutShelterLevel") >= 4 && $item[wrist-boy].available_amount() == 0 && my_meat() >= 5000) - { - subentries.listAppend(ChecklistSubentryMake("Acquire wrist-boy", "", "Unlocks buff records.")); - url = "shop.php?whichshop=vault2"; - } - - if (subentries.count() > 0) - task_entries.listAppend(ChecklistEntryMake("__item rad", url, subentries, 0).ChecklistEntrySetIDTag("Nuclear autumn path shelter action suggestion")); -} - -RegisterResourceGenerationFunction("PathNuclearAutumnGenerateResource"); -void PathNuclearAutumnGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_NUCLEAR_AUTUMN) return; - - item rad = $item[rad]; - if (rad.available_amount() > 0) - { - int [skill] skill_rad_cost; - - foreach s in $skills[Boiling Tear Ducts,Projectile Salivary Glands,Translucent Skin,Skunk Glands,Throat Refrigerant,Internal Soda Machine] - skill_rad_cost[s] = 30; - foreach s in $skills[Steroid Bladder,Magic Sweat,Flappy Ears,Self-Combing Hair,Intracranial Eye,Mind Bullets,Extra Kidney,Extra Gall Bladder] - skill_rad_cost[s] = 60; - foreach s in $skills[Extra Muscles,Adipose Polymers,Metallic Skin,Hypno-Eyes,Extra Brain,Squid Glands,Extremely Punchable Face,Magnetic Ears,Firefly Abdomen,Bone Springs] - skill_rad_cost[s] = 90; - foreach s in $skills[Sucker Fingers,Backwards Knees] - skill_rad_cost[s] = 120; - - string [skill] skill_descriptions; - skill_descriptions[$skill[Extra Gall Bladder]] = "+100% adventures from food"; - skill_descriptions[$skill[Extra Kidney]] = "+100% Adventures from booze"; - skill_descriptions[$skill[Internal Soda Machine]] = "Restore MP for meat"; - skill_descriptions[$skill[Squid Glands]] = "-10% combat buff"; - skill_descriptions[$skill[Steroid Bladder]] = "+50% muscle buff"; - skill_descriptions[$skill[Extra Muscles]] = "+50% muscle passive"; - skill_descriptions[$skill[Self-Combing Hair]] = "+50% moxie buff"; - skill_descriptions[$skill[Hypno-Eyes]] = "+50% moxie passive"; - skill_descriptions[$skill[Intracranial Eye]] = "+50% myst buff"; - skill_descriptions[$skill[Extra Brain]] = "+50% myst passive"; - skill_descriptions[$skill[Extremely Punchable Face]] = "+30 ML buff"; - skill_descriptions[$skill[Magnetic Ears]] = "15% item buff"; - skill_descriptions[$skill[Sucker Fingers]] = "15% item passive"; - skill_descriptions[$skill[Firefly Abdomen]] = "+10% combat buff"; - skill_descriptions[$skill[Throat Refrigerant]] = "Cold damage spell"; - skill_descriptions[$skill[Flappy Ears]] = "+2 all res buff"; - skill_descriptions[$skill[Metallic Skin]] = "+2 all res passive"; - skill_descriptions[$skill[Bone Springs]] = "+20% init buff"; - skill_descriptions[$skill[Backwards Knees]] = "+20% init passive"; - skill_descriptions[$skill[Magic Sweat]] = "+100 DA, +10 DR buff"; - skill_descriptions[$skill[Adipose Polymers]] = "+100 DA, +10 DR passive"; - skill_descriptions[$skill[Mind Bullets]] = "stunning spell"; - - skill [int] desired_skill_order; - - desired_skill_order.listAppend($skill[Extra Gall Bladder]); //Passive - +100% adventures from food - desired_skill_order.listAppend($skill[Extra Kidney]); //Passive - +100% Adventures from booze - desired_skill_order.listAppend($skill[Internal Soda Machine]); //Passive - Spend 20 meat to recover 10 MP - - desired_skill_order.listAppend($skill[Squid Glands]); //-10% combat rate buff - if (my_primestat() == $stat[muscle]) - { - desired_skill_order.listAppend($skill[Steroid Bladder]); //Buff - +50% Muscle - desired_skill_order.listAppend($skill[Extra Muscles]); //Passive - +50% Muscle - } - else if (my_primestat() == $stat[moxie]) - { - desired_skill_order.listAppend($skill[Self-Combing Hair]); //Buff - +50% Moxie - desired_skill_order.listAppend($skill[Hypno-Eyes]); //Passive - +50% Moxie - } - else if (my_primestat() == $stat[Mysticality]) - { - desired_skill_order.listAppend($skill[Intracranial Eye]); //Buff - +50% Mysticality - desired_skill_order.listAppend($skill[Extra Brain]); //Passive - +50% Mysticality - } - - desired_skill_order.listAppend($skill[Extremely Punchable Face]); //+30 ML buff - desired_skill_order.listAppend($skill[Magnetic Ears]); //15% item buff - desired_skill_order.listAppend($skill[Sucker Fingers]); //15% item passive - desired_skill_order.listAppend($skill[Firefly Abdomen]); //+10% combat rate buff - - desired_skill_order.listAppend($skill[Throat Refrigerant]); //Combat - Cold damage - desired_skill_order.listAppend($skill[Flappy Ears]); //Buff - +2 resistance to all elements - desired_skill_order.listAppend($skill[Metallic Skin]); //Passive - +2 resistance to all elements - - - desired_skill_order.listAppend($skill[Bone Springs]); //+20% init buff - desired_skill_order.listAppend($skill[Backwards Knees]); //+20% init passive - - desired_skill_order.listAppend($skill[Magic Sweat]); //Buff - Damage Absorption +100 - Damage Reduction: 10 - desired_skill_order.listAppend($skill[Adipose Polymers]); //Passive - Damage Absorption +100 - Damage Reduction: 10 - desired_skill_order.listAppend($skill[Mind Bullets]); //Combat - Stuns opponent - desired_skill_order.listAppend($skill[Self-Combing Hair]); //Buff - +50% Moxie - desired_skill_order.listAppend($skill[Hypno-Eyes]); //Passive - +50% Moxie - desired_skill_order.listAppend($skill[Steroid Bladder]); //Buff - +50% Muscle - desired_skill_order.listAppend($skill[Extra Muscles]); //Passive - +50% Muscle - desired_skill_order.listAppend($skill[Intracranial Eye]); //Buff - +50% Mysticality - desired_skill_order.listAppend($skill[Extra Brain]); //Passive - +50% Mysticality - - //desired_skill_order.listAppend($skill[Boiling Tear Ducts]); //Combat - Hot damage - //desired_skill_order.listAppend($skill[Projectile Salivary Glands]); //Combat - Sleaze damage - //desired_skill_order.listAppend($skill[Translucent Skin]); //Combat - Spooky damage - //desired_skill_order.listAppend($skill[Skunk Glands]); //Combat - Stench damage - - string [int] description; - - boolean [skill] already_displayed_skill; - foreach key, s in desired_skill_order - { - if (s.have_skill()) - continue; - if (($skills[Magnetic Ears,Sucker Fingers,Extremely Punchable Face,Firefly Abdomen,Bone Springs,Squid Glands,Backwards Knees] contains s) && get_property_int("falloutShelterLevel") < 6) //not yet - continue; - if (already_displayed_skill[s]) - continue; - already_displayed_skill[s] = true; - string line = s + ": " + skill_descriptions[s]; - if (skill_rad_cost[s] > $item[rad].available_amount()) - line = HTMLGenerateSpanFont(line, "gray"); - description.listAppend(line); - } - - resource_entries.listAppend(ChecklistEntryMake("__item rad", "shop.php?whichshop=mutate", ChecklistSubentryMake(pluralise(rad) + " available", "", description), 8).ChecklistEntrySetIDTag("Nuclear autumn path rad shop")); - } - if (get_property_int("falloutShelterLevel") >= 3 && !get_property_boolean("_falloutShelterSpaUsed")) - { - //FIXME sync with above - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Paths/Paths import.ash b/Source/relay/TourGuide/Paths/Paths import.ash deleted file mode 100644 index b36457d1..00000000 --- a/Source/relay/TourGuide/Paths/Paths import.ash +++ /dev/null @@ -1,25 +0,0 @@ -import "relay/TourGuide/Paths/Actually Ed the Undying.ash"; -import "relay/TourGuide/Paths/Avatar of Jarlsberg.ash"; -import "relay/TourGuide/Paths/Avatar of Sneaky Pete.ash"; -import "relay/TourGuide/Paths/Avatar of West of Loathing.ash"; -import "relay/TourGuide/Paths/Bad Moon.ash"; -import "relay/TourGuide/Paths/Bugbear Invasion.ash"; -import "relay/TourGuide/Paths/Community Service.ash"; -import "relay/TourGuide/Paths/Heavy Rains.ash"; -import "relay/TourGuide/Paths/KOLHS.ash"; -import "relay/TourGuide/Paths/Way of the Surprising Fist.ash"; -import "relay/TourGuide/Paths/The Source.ash"; -import "relay/TourGuide/Paths/Zombie Slayer.ash"; -import "relay/TourGuide/Paths/Nuclear Autumn.ash"; -import "relay/TourGuide/Paths/Gelatinous Noob.ash"; -import "relay/TourGuide/Paths/License to Adventure.ash"; -import "relay/TourGuide/Paths/G-Lover.ash"; -import "relay/TourGuide/Paths/Dark Gift.ash"; -import "relay/TourGuide/Paths/Explosions.ash"; -//missing plumber -import "relay/TourGuide/Paths/Low Key.ash"; -import "relay/TourGuide/Paths/Grey Goo.ash"; -import "relay/TourGuide/Paths/Fall of the Dinosaurs.ash"; -import "relay/TourGuide/Paths/Avatar of Shadows over Loathing.ash"; -import "relay/TourGuide/Paths/Legacy of Loathing.ash"; -import "relay/TourGuide/Paths/WereProfessor.ash"; \ No newline at end of file diff --git a/Source/relay/TourGuide/Paths/The Source.ash b/Source/relay/TourGuide/Paths/The Source.ash deleted file mode 100644 index beaadf97..00000000 --- a/Source/relay/TourGuide/Paths/The Source.ash +++ /dev/null @@ -1,154 +0,0 @@ -RegisterTaskGenerationFunction("PathTheSourceGenerateTasks"); -void PathTheSourceGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_THE_SOURCE) return; - if (!mafiaIsPastRevision(16944)) - return; - - /* - questM26Oracle - sourceOracleTarget - sourceAgentsDefeated - sourceEnlightenment - sourcePoints - */ - - int enlightenment = get_property_int("sourceEnlightenment"); - int learned_skill_count = 0; - foreach s in lookupSkills("Overclocked,Bullet Time,True Disbeliever,Code Block,Disarmament,Big Guns,Humiliating Hack,Source Kick,Reboot,Restore,Data Siphon") - { - if (s.have_skill()) - learned_skill_count += 1; - } - if (enlightenment > 0 && learned_skill_count < 11) - { - string [int] description; - - skill [int] desired_skill_order; - if (get_property_int("sourcePoints") < 3) //once you have three, you can always go the hack-siphon-kick route - desired_skill_order.listAppend($skill[Big Guns]); //tons of damage - desired_skill_order.listAppend($skill[Humiliating Hack]); //delevel a bunch - desired_skill_order.listAppend($skill[Data Siphon]); //restore MP from attacks - desired_skill_order.listAppend($skill[Source Kick]); //also a lot of damage...? - desired_skill_order.listAppend($skill[Overclocked]); //+init - - desired_skill_order.listAppend($skill[Restore]); //restore HP - desired_skill_order.listAppend($skill[Bullet Time]); //dodge 3 ranged - desired_skill_order.listAppend($skill[True Disbeliever]); //dodge 3 hack - desired_skill_order.listAppend($skill[Code Block]); //dodge 3 melee - - desired_skill_order.listAppend($skill[Disarmament]); //something - desired_skill_order.listAppend($skill[Reboot]); //removes latency - desired_skill_order.listAppend($skill[Big Guns]); //tons of damage - - foreach key, s in desired_skill_order - { - if (!s.have_skill()) - { - description.listAppend("Maybe " + s + " next."); - break; - } - } - - task_entries.listAppend(ChecklistEntryMake("ringing phone", "place.php?whichplace=manor1&action=manor1_sourcephone_ring", ChecklistSubentryMake("Learn source skill", "", description), -11).ChecklistEntrySetIDTag("Source path new skills")); - } - - if (enlightenment + learned_skill_count < 11) - { - boolean later = false; - string title = ""; - string [int] description; - string url = ""; - string target = get_property("sourceOracleTarget"); - location target_location = target.to_location(); - if ($item[no spoon].available_amount() > 0) - { - title = "Return to the Oracle"; - url = "place.php?whichplace=town_wrong&action=townwrong_oracle"; - } - else if (target == "" || !QuestState("questM26Oracle").started) - { - title = "Visit the Oracle"; - url = "place.php?whichplace=town_wrong&action=townwrong_oracle"; - string line = "If you want another source skill."; - if (learned_skill_count > 0) - line += " (have " + learned_skill_count + " so far.)"; - description.listAppend(line); - } - else if (target_location != $location[none]) - { - title = "Oracle Quest"; - url = target_location.getClickableURLForLocation(); - if (!target_location.locationAvailable()) - { - later = true; - title += " later"; - if (target_location == $location[the skeleton store]) - { - later = false; - title = "Start the skeleton store quest"; - description.listAppend("Visit the meatsmith."); - url = "shop.php?whichshop=meatsmith&action=talk"; - } - else if (target_location == $location[madness bakery]) - { - later = false; - title = "Start the madness bakery quest"; - description.listAppend("Visit the Armory and Leggery."); - url = "shop.php?whichshop=armory&action=talk"; - } - else if (target_location == $location[the overgrown lot]) - { - later = false; - title = "Start the Galaktik quest"; - description.listAppend("Visit Doc Galaktik."); - url = "shop.php?whichshop=doc&action=talk"; - } - description.listAppend("Unlock " + target_location + " first."); - } - else - { - description.listAppend("Adventure in " + target_location + "."); - description.listAppend("No spoon unappears after eleven combat turns."); - } - } - - if (title != "") - { - ChecklistEntry entry = ChecklistEntryMake("__item cookie cookie", url, ChecklistSubentryMake(title, "", description), -1); - entry.tags.id = "Source path oracle main quest"; - if (target_location != $location[none] && target_location == __last_adventure_location) - entry.should_highlight = true; - if (later) - future_task_entries.listAppend(entry); - else - optional_task_entries.listAppend(entry); - } - } - - int source_interval = get_property_int("sourceInterval"); - if (source_interval == 200 || source_interval == 400) - { - string [int] description; - CopiedMonstersGenerateDescriptionForMonster("source agent", description, true, false); - - task_entries.listAppend(ChecklistEntryMake("__item software glitch", "", ChecklistSubentryMake("Source agent now or soon", "", description), -11).ChecklistEntrySetIDTag("Source path source agent fight now")); - } - else if (source_interval > 0) - { - string [int] description; - int turns = (source_interval - 400) / 200; - if (get_property_int("sourceAgentsDefeated") > 0) - description.listAppend(pluralise(get_property_int("sourceAgentsDefeated"), "agent", "agents") + " defeated so far."); - if (QuestState("questM26Oracle").in_progress) - description.listAppend("Oracle quests won't advance the counter."); - optional_task_entries.listAppend(ChecklistEntryMake("__item software glitch", "", ChecklistSubentryMake("Source agent after ~" + pluralise(turns, "won combat", "won combats"), "", description)).ChecklistEntrySetIDTag("Source path source agent fight later")); - } -} - -RegisterResourceGenerationFunction("PathTheSourceGenerateResource"); -void PathTheSourceGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_THE_SOURCE) - return; -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Paths/Way of the Surprising Fist.ash b/Source/relay/TourGuide/Paths/Way of the Surprising Fist.ash deleted file mode 100644 index 4d1b7082..00000000 --- a/Source/relay/TourGuide/Paths/Way of the Surprising Fist.ash +++ /dev/null @@ -1,40 +0,0 @@ -//Some simple suggestions for this forgotten path: -RegisterResourceGenerationFunction("PathWOTSFGenerateResource"); -void PathWOTSFGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) - return; - //Meat: - if (have_outfit_components("Knob Goblin Harem Girl Disguise") && !get_property_boolean("_treasuryHaremMeatCollected") && locationAvailable($location[Cobb's Knob Barracks])) - { - resource_entries.listAppend(ChecklistEntryMake("meat", "cobbsknob.php", ChecklistSubentryMake("Cobb's Knob treasury meat", "", "Wear harem girl disguise, adventure once for 500 meat."), 5).ChecklistEntrySetIDTag("Surprising fist path knob harem meat")); - } - //Skills: - string [int] fist_teaching_properties = split_string_alternate("fistTeachingsBarroomBrawl,fistTeachingsBatHole,fistTeachingsConservatory,fistTeachingsFratHouse,fistTeachingsFunHouse,fistTeachingsHaikuDungeon,fistTeachingsMenagerie,fistTeachingsNinjaSnowmen,fistTeachingsPokerRoom,fistTeachingsRoad,fistTeachingsSlums", ","); - location [string] teaching_properties_to_locations; - teaching_properties_to_locations["fistTeachingsBarroomBrawl"] = $location[A Barroom Brawl]; - teaching_properties_to_locations["fistTeachingsBatHole"] = $location[The Bat Hole Entrance]; - teaching_properties_to_locations["fistTeachingsConservatory"] = $location[The Haunted Conservatory]; - teaching_properties_to_locations["fistTeachingsFratHouse"] = $location[The Orcish Frat House]; - teaching_properties_to_locations["fistTeachingsFunHouse"] = $location[The "Fun" House]; - teaching_properties_to_locations["fistTeachingsHaikuDungeon"] = $location[The Haiku Dungeon]; - teaching_properties_to_locations["fistTeachingsMenagerie"] = $location[Cobb's Knob Menagerie\, Level 2]; - teaching_properties_to_locations["fistTeachingsNinjaSnowmen"] = $location[Lair of the Ninja Snowmen]; - teaching_properties_to_locations["fistTeachingsPokerRoom"] = $location[The Poker Room]; - teaching_properties_to_locations["fistTeachingsRoad"] = $location[The Road to the White Citadel]; - teaching_properties_to_locations["fistTeachingsSlums"] = $location[Pandamonium Slums]; - - string [int] missing_areas; - foreach key in fist_teaching_properties - { - string property = fist_teaching_properties[key]; - if (!get_property_boolean(property)) - { - location place = teaching_properties_to_locations[property]; - missing_areas.listAppend(place.HTMLGenerateFutureTextByLocationAvailability()); - } - } - if (missing_areas.count() > 0) - resource_entries.listAppend(ChecklistEntryMake("__item Teachings of the Fist", "", ChecklistSubentryMake("Teachings of the Fist", "", "Found in " + missing_areas.listJoinComponents(", ", "and") + "."), 5).ChecklistEntrySetIDTag("Surprising fist path find fist skills")); - -} diff --git a/Source/relay/TourGuide/Paths/WereProfessor.ash b/Source/relay/TourGuide/Paths/WereProfessor.ash deleted file mode 100644 index 008ddef3..00000000 --- a/Source/relay/TourGuide/Paths/WereProfessor.ash +++ /dev/null @@ -1,185 +0,0 @@ - -RegisterResourceGenerationFunction("PathWereProfessorGenerateResource"); -void PathWereProfessorGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_WEREPROFESSOR) return; - - // Smashed scientific equipment - location [int] scientific_locations = { - $location[Noob Cave], - $location[The Haunted Pantry], - $location[Madness Bakery], - $location[The Thinknerd Warehouse], - $location[Vanya's Castle], - $location[The Old Landfill], - $location[Cobb's Knob Laboratory], - $location[Cobb's Knob Menagerie, Level 1], - $location[Cobb's Knob Menagerie, Level 2], - $location[Cobb's Knob Menagerie, Level 3], - $location[The Haunted Laboratory], - $location[The Castle in the Clouds in the Sky (Top Floor)], - $location[The Hidden Hospital] - }; - - string [int] scientific_locations_description; - scientific_locations_description.listAppend("Found in a free non-combat on 7th adventure in a zone."); - if ($effect[Mild-Mannered Professor].have_effect() > 0) scientific_locations_description.listAppend(HTMLGenerateSpanFont("Can only be found as a Beast", "red")); - - location [int] scientific_locations_options; - foreach key, loc in scientific_locations { - boolean obtained_equipment = false; - foreach nc_key, nc in loc.locationSeenNoncombats() { - if (nc == "The Antiscientific Method") obtained_equipment = true; - } - if (!obtained_equipment) scientific_locations_options.listAppend(loc); - } - - int scientific_locations_sort(location loc) { - int score = 0; - // +1 for each turn spent, up to 6 - // -30 if location is inaccessible - // +3 if location is a quest one and the relevant quest is not yet done - // +10 if location is the last adventured location - - int turns_spent = loc.turns_spent; - score += min(6, loc.turns_spent); - if (!loc.locationAvailable()) score -= 30; - - if (loc == $location[Vanya's Castle]) score += 3; // should always get that one in the optimal scenario - if (loc == $location[The Castle in the Clouds in the Sky (Top Floor)] && !__quest_state["Level 10"].finished) score += 3; - if (loc == $location[The Hidden Hospital] && !__quest_state["Level 11 Hidden City"].state_boolean["Hospital finished"]) score += 3; - - if (__last_adventure_location == loc) score += 10; - return score; - } - - sort scientific_locations_options by -scientific_locations_sort(value); - - string [int] loc_descriptions; - - foreach key, loc in scientific_locations_options { - int turns_spent = loc.turns_spent; - string scientific_locations_option = loc.HTMLGenerateFutureTextByLocationAvailability(); - if (turns_spent < 6) scientific_locations_option += " - " + pluralise(6 - turns_spent, "turn left", "turns left"); - else scientific_locations_option += " - drops next turn"; - loc_descriptions.listAppend(scientific_locations_option); - } - - if (scientific_locations_options.count() > 0) { - if (scientific_locations_options.count() > 3) { - scientific_locations_description.listAppend("Drop locations:" + (loc_descriptions[0] + "
" + HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(loc_descriptions.listJoinComponents("
").HTMLGenerateIndentedText(), "r_tooltip_inner_class") + "All locations", "r_tooltip_outer_class")).HTMLGenerateIndentedText()); - } - else scientific_locations_description.listAppend("Drop locations:" + loc_descriptions.listJoinComponents("
").HTMLGenerateIndentedText()); - - resource_entries.listAppend(ChecklistEntryMake("__item smashed scientific equipment", "", ChecklistSubentryMake("Obtain smashed scientific equipment", "", scientific_locations_description))); - } - - // Owned smashed scientific equipment - if (have($item[smashed scientific equipment])) { - string [int] smashed_equipment_description; - string [int] craftable_items; - - if ($effect[Savage Beast].have_effect() > 0) smashed_equipment_description.listAppend("Wait until you are a Professor to craft stuff."); - - // Science-producting hats -- TODO: ignore if have all Stomach/Liver upgrades (pending Mafia support) - if (!have($item[biphasic molecular oculus]) && !have($item[triphasic molecular oculus])) craftable_items.listAppend("biphasic molecular oculus (more Research Points)"); - if (have($item[biphasic molecular oculus])) craftable_items.listAppend("triphasic molecular oculus (more Research Points)"); - // Exoskeletons - if (!have($item[high-tension exoskeleton]) && !have($item[ultra-high-tension exoskeleton]) && !have($item[irresponsible-tension exoskeleton])) craftable_items.listAppend("high-tension exoskeleton (avoid attacks)"); - if (have($item[high-tension exoskeleton])) craftable_items.listAppend("ultra-high-tension exoskeleton (avoid attacks)"); - if (have($item[ultra-high-tension exoskeleton])) craftable_items.listAppend("irresponsible-tension exoskeleton (avoid attacks)"); - // Initiative, consider if no Spring Shoes available (since they do the same thing) and cannot equip Parka (protection from the jump) - if (!(__misc_state["Torso aware"] && have($item[Jurassic Parka])) && !have($item[spring shoes]) && !have($item[motion sensor])) craftable_items.listAppend("motion sensor (+100% initiative accessory)"); - - if (craftable_items.count() > 0) { - smashed_equipment_description.listAppend("Consider crafting:" + craftable_items.listJoinComponents("
").HTMLGenerateIndentedText()); - } - - resource_entries.listAppend(ChecklistEntryMake("__item smashed scientific equipment", "shop.php?whichshop=wereprofessor_tinker", ChecklistSubentryMake(pluralise($item[smashed scientific equipment]) + " available", "", smashed_equipment_description))); - } -} - -RegisterTaskGenerationFunction("PathWereProfessorGenerateTasks"); -void PathWereProfessorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($effect[Mild-Mannered Professor].have_effect() > 0) { - boolean should_nag = false; - - string [int] professor_tips; - - // Too high ML! - if (monster_level_adjustment() > 25) { - should_nag = true; - professor_tips.listAppend(HTMLGenerateSpanFont(`Reduce ML, elemental-aligned monsters will kill you at the start of combat with +{monster_level_adjustment()} ML.`, "red")); - } - - boolean wearing_quest_outfit = false; - if (is_wearing_outfit("Knob Goblin Harem Girl Disguise")) wearing_quest_outfit = true; - if (is_wearing_outfit("Knob Goblin Elite Guard Uniform")) wearing_quest_outfit = true; - if (is_wearing_outfit("eXtreme Cold-Weather Gear")) wearing_quest_outfit = true; - if (is_wearing_outfit("War Hippy Fatigues")) wearing_quest_outfit = true; - if (is_wearing_outfit("Frat Warrior Fatigues")) wearing_quest_outfit = true; - - // Equip research equipment. TODO: don't show it if we have 2250 points total; don't nag it if we have all of stomach and liver skills - foreach it in $items[biphasic molecular oculus,triphasic molecular oculus] { - if (have(it) && it.equipped_amount() == 0) { - if (!wearing_quest_outfit) { - should_nag = true; - professor_tips.listAppend(HTMLGenerateSpanFont(`Equip your {it} to do advanced research.`, "red")); - } - else professor_tips.listAppend(`Equip your {it} to do advanced research.`); - } - } - - // Equip attack avoidance pants - foreach it in $items[high-tension exoskeleton,ultra-high-tension exoskeleton,irresponsible-tension exoskeleton] { - if (have(it) && it.equipped_amount() == 0) { - professor_tips.listAppend(`Equip your {it} to avoid enemy attacks.`); - } - } - - // Equip something to avoid the jump - if (initiative_modifier() < 100 && $item[Jurassic Parka].equipped_amount() == 0) { - if (__misc_state["Torso aware"] && have($item[Jurassic Parka])) { - should_nag = true; - professor_tips.listAppend(HTMLGenerateSpanFont("Equip your Jurassic Parka to avoid enemies getting the jump and instakilling you.", "red")); - } - else { - professor_tips.listAppend(`Increase your initiative (currently {initiative_modifier()}%) to avoid enemies getting the jump and instakilling you.`); - } - } - - // Buy stuff - string [int] stuff_to_buy; - if (get_property_int("_cloversPurchased") < 3) stuff_to_buy.listAppend("11-leaf clovers"); - if (!__misc_state["desert beach available"]) { - if (!knoll_available()) stuff_to_buy.listAppend("desert bus pass"); - else stuff_to_buy.listAppend("bitchin' meatcar components"); - } - if (knoll_available() && !have($item[detuned radio])) stuff_to_buy.listAppend("detuned radio"); - if (__quest_state["Level 11"].mafia_internal_step >= 2) { // Black Market open - if (__quest_state["Level 11"].mafia_internal_step == 2 && !have($item[forged identification documents])) stuff_to_buy.listAppend("forged identification documents"); - if (!__quest_state["Level 11 Desert"].state_boolean["Black Paint Given"] && !have($item[can of black paint])) stuff_to_buy.listAppend("can of black paint"); - if (__quest_state["Level 11 Ron"].mafia_internal_step <= 4 && !have($item[red zeppelin ticket])) stuff_to_buy.listAppend("Red Zeppelin ticket"); - } - if (!have($item[UV-resistant compass])) stuff_to_buy.listAppend("UV-resistant compass"); - if (!have($item[dinghy plans]) && !__misc_state["mysterious island available"]) stuff_to_buy.listAppend("dinghy plans"); - if (!have($item[dingy planks]) && !__misc_state["mysterious island available"]) stuff_to_buy.listAppend("dingy planks"); - if (__quest_state["Level 11 Manor"].mafia_internal_step < 4 && !have($item[Dramatic™ range]) && !get_property_boolean("hasRange")) stuff_to_buy.listAppend("Dramatic™ range"); - - if (stuff_to_buy.count() > 0) { - professor_tips.listAppend("Buy stuff before you become a Beast again: " + stuff_to_buy.listJoinComponents(", ", "or") + "."); - } - - int priority = 12; - ChecklistEntry [int] tips_location = optional_task_entries; - if (should_nag) { - priority = -11; - tips_location = task_entries; - } - - if (professor_tips.count() > 0) { - tips_location.listAppend(ChecklistEntryMake("WereProfessor", "", ChecklistSubentryMake("You are a Professor", professor_tips), priority)); - } - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Paths/Zombie Slayer.ash b/Source/relay/TourGuide/Paths/Zombie Slayer.ash deleted file mode 100644 index 96ed777d..00000000 --- a/Source/relay/TourGuide/Paths/Zombie Slayer.ash +++ /dev/null @@ -1,57 +0,0 @@ - -RegisterTaskGenerationFunction("PathZombieSlayerGenerateTasks"); -void PathZombieSlayerGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_ZOMBIE_SLAYER) - return; - //zombiePoints is the number of points "permed" on the character, not how many they have at the moment - //Let's see.. I think this means we can infer how many points they have to spend, right? You start with zombiePoints + 1, then gain one for each level you have, minus how many hunter brains you have, minus whether you've fought the right hunter yet... but, we can't know that information. Hmm. So, no, no reminder. Alas. - //We could, however, suggest they eat a hunter brain. - //ashq string out; foreach s in $skills[] if (s.class == $class[zombie master]) out += ", " + s; print(out); - if ($item[hunter brain].available_amount() > 0 && availableFullness() >= 1) - { - int zombie_skills_have = 0; - foreach s in $skills[Infectious Bite, Bite Minion, Lure Minions, Undying Greed, Hunter's Sprint, Insatiable Hunger, Devour Minions, Indefatigable, Skullcracker, Neurogourmet, Ravenous Pounce, Distracting Minion, Plague Claws, Flesh Mob, Elemental Obliviousness, Vigor Mortis, Virulence, Bilious Burst, Unyielding Flesh, Corpse Pile, Howl of the Alpha, Summon Minion, Zombie Chow, Smash & Graaagh, Scavenge, Meat Shields, Summon Horde, His Master's Voice, Ag-grave-ation, Disquiet Riot, Zombie Maestro, Recruit Zombie] - { - if (s.have_skill()) - zombie_skills_have += 1; - } - if (zombie_skills_have < 30) - { - //probably should suggest eat X hunter brains but - optional_task_entries.listAppend(ChecklistEntryMake("__item hunter brain", "inventory.php?ftext=hunter+brain", ChecklistSubentryMake("Eat a hunter brain", "", "Gain a skill point."), -1).ChecklistEntrySetIDTag("Zombie slayer path skill points")); - } - } - -} - -RegisterResourceGenerationFunction("PathZombieSlayerGenerateResource"); -void PathZombieSlayerGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_path().id != PATH_ZOMBIE_SLAYER) return; - - if ($item[right bear arm].available_amount() > 0 && $item[left bear arm].available_amount() > 0) - { - int bear_hugs_remaining = clampi(10 - get_property_int("_bearHugs"), 0, 10); - - if (bear_hugs_remaining > 0) - { - string url; - string [int] description; - description.listAppend("Converts monster to zombies. Ideally, use against group monsters."); - string [int] items_to_equip; - foreach it in $items[right bear arm,left bear arm] - { - if (it.equipped_amount() == 0) - items_to_equip.listAppend(it); - } - if (items_to_equip.count() > 0) - { - url = "inventory.php?which=2"; - description.listAppend("Equip " + items_to_equip.listJoinComponents(", ", "and") + "."); - } - resource_entries.listAppend(ChecklistEntryMake("__item right bear arm", url, ChecklistSubentryMake(pluralise(bear_hugs_remaining, "bear hug", "bear hugs"), "", description), 8).ChecklistEntrySetIDTag("Zombie slayer path bear arms hugs")); - - } - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Plants.ash b/Source/relay/TourGuide/Plants.ash deleted file mode 100644 index d7295374..00000000 --- a/Source/relay/TourGuide/Plants.ash +++ /dev/null @@ -1,371 +0,0 @@ -//FIXME this should be customizable. But an interface for that would be tricky... - -record PlantSuggestion -{ - location loc; - string plant_name; - string details; - - boolean no_stat_remove; //for +ML plants mainly -}; - -PlantSuggestion PlantSuggestionMake(location loc, string plant_name, string details) -{ - PlantSuggestion result; - result.loc = loc; - result.plant_name = plant_name; - result.details = details; - return result; -} - - -void listAppend(PlantSuggestion [int] list, PlantSuggestion entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - - -PlantSuggestion [int] __plants_suggested_locations; - -record Plant -{ - string name; - string image_lookup_name; //auto-generated - string zone_effect; - string terrain; - boolean territorial; -}; - -Plant PlantMake(string name, string zone_effect, string terrain, boolean territorial) -{ - Plant result; - result.name = name; - result.image_lookup_name = "Plant " + name; - result.zone_effect = zone_effect; - result.terrain = terrain; - result.territorial = territorial; - return result; -} -Plant [string] __plant_properties; -string [int] __plant_output_order; //MUST contain all plants - - -void finaliseSetUpFloristState() -{ - if (!__iotms_usable[$item[Order of the Green Thumb Order Form]]) - return; - - //Set up suggestions: - //We can have this as either plants keeping track of a bunch of locations, or locations keeping track of a bunch of plants. - //Keeping it the same as get_florist_plants makes it mentally easier to track, I guess. - - - __plant_properties["Rabid Dogwood"] = PlantMake("Rabid Dogwood", "+30 ML", "outdoor", true); - __plant_properties["Rutabeggar"] = PlantMake("Rutabeggar", "+25% item", "outdoor", true); - __plant_properties["Rad-ish Radish"] = PlantMake("Rad-ish Radish", "+5 moxie stats/fight", "outdoor", true); - - __plant_properties["War Lily"] = PlantMake("War Lily", "+30 ML", "indoor", true); - __plant_properties["Stealing Magnolia"] = PlantMake("Stealing Magnolia", "+25% item", "indoor", true); - __plant_properties["Canned Spinach"] = PlantMake("Canned Spinach", "+5 muscle stats/fight", "indoor", true); - - __plant_properties["Blustery Puffball"] = PlantMake("Blustery Puffball", "+30 ML", "underground", true); - __plant_properties["Horn of Plenty"] = PlantMake("Horn of Plenty", "+25% item", "underground", true); - __plant_properties["Wizard's Wig"] = PlantMake("Wizard's Wig", "+5 myst stats/fight", "underground", true); - __plant_properties["Shuffle Truffle"] = PlantMake("Shuffle Truffle", "+25% init", "underground", false); - - - __plant_output_order = split_string("Rabid Dogwood,Rutabeggar,Rad-ish Radish,Artichoker,Smoke-ra,Skunk Cabbage,Deadly Cinnamon,Celery Stalker,Lettuce Spray,Seltzer Watercress,War Lily,Stealing Magnolia,Canned Spinach,Impatiens,Spider Plant,Red Fern,BamBOO!,Arctic Moss,Aloe Guv'nor,Pitcher Plant,Blustery Puffball,Horn of Plenty,Wizard's Wig,Shuffle Truffle,Dis Lichen,Loose Morels,Foul Toadstool,Chillterelle,Portlybella,Max Headshroom,Spankton,Kelptomaniac,Crookweed,Electric Eelgrass,Duckweed,Orca Orchid,Sargassum,Sub-Sea Rose,Snori,Up Sea Daisy", ","); - - //Go through all potentials: - boolean [string] plants_used; - if (true) - { - string [int] internal_plants_used = split_string_alternate(get_property("_floristPlantsUsed"), ","); - foreach key in internal_plants_used - plants_used[internal_plants_used[key]] = true; - } - //Shuffle Truffle - underground, init: - if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"]) - { - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the defiled alcove], "Shuffle Truffle", "+2.5% modern zmobie")); - } - //Horn of Plenty - underground, +item: - if (__quest_state["Level 7"].state_boolean["nook needs speed tricks"] && $location[the defiled nook].item_drop_modifier_for_location() < 400.0) - { - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the defiled nook], "Horn of Plenty", "Evil eye, 20% drop.")); - } - if (!__quest_state["Level 11"].finished && $location[the middle chamber].item_drop_modifier_for_location() < 400.0) - { - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the middle chamber], "Horn of Plenty", "Tomb ratchets, 20% drop.")); - } - if (__quest_state["Level 4"].state_int["areas unlocked"] + $item[sonar-in-a-biscuit].available_amount() < 3) - { - string description = "Sonars-in-a-biscuit, 15% drop."; - if (!__quest_state["Level 7"].state_boolean["nook finished"]) //FIXME test if that plant is planted already - description += " Or ignore in favor of the defiled nook?"; - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the batrat and ratbat burrow], "Horn of Plenty", description)); - } - //Intentionally ignored: +item plants in the orchard. Normally you'd plant in the upper chamber instead, since both of these quests often happen on the same day? And there's three zones to plant in - way too complicated. - if (!__quest_state["Level 12"].finished && __misc_state["need to level"] && __quest_state["Level 12"].state_int["frat boys left on battlefield"] != 0 && __quest_state["Level 12"].state_int["hippies left on battlefield"] != 0) - { - location battlefield_zone = $location[the battlefield (hippy uniform)]; - if (__quest_state["Level 12"].state_int["frat boys left on battlefield"] > __quest_state["Level 12"].state_int["hippies left on battlefield"]) - battlefield_zone = $location[the battlefield (frat uniform)]; - if (my_primestat() == $stat[moxie]) - __plants_suggested_locations.listAppend(PlantSuggestionMake(battlefield_zone, "Rad-ish Radish", "")); - else - __plants_suggested_locations.listAppend(PlantSuggestionMake(battlefield_zone, "Rabid Dogwood", "")); - } - if (__misc_state["need to level mysticality"]) - { - //Wizard's Wig - underground, +5 myst stats/fight: - //in SC, can reach level 7 first, so ignore this one: - //if (!__quest_state["Level 4"].finished) - //__plants_suggested_locations.listAppend(PlantSuggestionMake($location[The Boss Bat's Lair], "Wizard's Wig", "")); - if (!__quest_state["Level 7"].state_boolean["niche finished"]) - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[The Defiled Niche], "Wizard's Wig", "")); - } - //Blustery Puffball - underground, +ML: - if (__quest_state["Level 7"].state_int["cranny evilness"] > 25 + 3) - { - PlantSuggestion ps = PlantSuggestionMake($location[the defiled cranny], "Blustery Puffball", "More beeps from swarm of ghuol whelps."); - ps.no_stat_remove = true; - __plants_suggested_locations.listAppend(ps); - } - //Canned Spinach - indoor, +5 muscle stats/fight: - if (my_primestat() == $stat[muscle] && __misc_state["need to level"]) - { - //castle? - if ($item[Spookyraven gallery key].available_amount() > 0 && !__misc_state["Stat gain from NCs reduced"]) - { - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the haunted gallery], "Canned Spinach", "While powerlevelling.")); - } - } - - //Stealing Magnolia - indoor, +item: - //War Lily - indoor, +ML: - if (__misc_state["need to level"]) - { - if ((my_path().id != PATH_PICKY || my_primestat() == $stat[moxie]) && $location[The Castle in the Clouds in the Sky (Ground Floor)].turnsAttemptedInLocation() < 11) //nightmare in picky - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[The castle in the clouds in the sky (ground floor)], "War Lily", "")); - //Haunted bedroom? - } - //Rad-ish Radish - outdoor, +5 moxie stats/fight: - if (__misc_state["need to level moxie"]) - { - //you wouldn't plant +30ML at airship - because oil peak may need it today. FIXME suggest if oil peak done/planted? HCO I guess? I dunno - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[The Spooky Forest], "Rad-ish Radish", "")); - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[The Penultimate Fantasy Airship], "Rad-ish Radish", "")); - } - //Rutabeggar - outdoor, +item: - if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0) - { - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[a-boo peak], "Rutabeggar", "A-boo clue, 15% drop.")); - } - - //Rabid Dogwood - outdoor, +ML: - if (__quest_state["Level 9"].state_float["oil peak pressure"] > 0 && monster_level_adjustment() < 100) - { - PlantSuggestion ps = PlantSuggestionMake($location[oil peak], "Rabid Dogwood", ""); - ps.no_stat_remove = true; - __plants_suggested_locations.listAppend(ps); - } - if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && __misc_state["need to level"]) //you spend a lot of turns in the desert - __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the arid, extra-dry desert], "Rabid Dogwood", "")); - - //Now, go through results, and remove all plants that are already in that location: - - string [location][int] current_plants = get_florist_plants(); - boolean [location][string] current_plants_used; //inverse of current_plants, used for quick searching - foreach l in current_plants - { - foreach key in current_plants[l] - { - string plant = current_plants[l][key]; - current_plants_used[l][plant] = true; - } - } - - int [int] keys_removing; - foreach key in __plants_suggested_locations - { - PlantSuggestion suggestion = __plants_suggested_locations[key]; - - boolean should_remove = false; - if (current_plants_used[suggestion.loc][suggestion.plant_name] || plants_used[suggestion.plant_name]) - { - should_remove = true; - } - else - { - if (suggestion.plant_name == "Rad-ish Radish" || suggestion.plant_name == "Canned Spinach" || suggestion.plant_name == "Wizard's Wig") //+stat plants - { - boolean area_has_ml_plant = false; - if (current_plants_used[suggestion.loc]["Rabid Dogwood"]) - area_has_ml_plant = true; - if (current_plants_used[suggestion.loc]["War Lily"]) - area_has_ml_plant = true; - if (current_plants_used[suggestion.loc]["Blustery Puffball"]) - area_has_ml_plant = true; - if (area_has_ml_plant) - should_remove = true; - } - - //opposite: - if (suggestion.plant_name == "Rabid Dogwood" || suggestion.plant_name == "War Lily" || suggestion.plant_name == "Blustery Puffball") - { - boolean area_has_stat_plant = false; - if (current_plants_used[suggestion.loc]["Rad-ish Radish"]) - area_has_stat_plant = true; - if (current_plants_used[suggestion.loc]["Canned Spinach"]) - area_has_stat_plant = true; - if (current_plants_used[suggestion.loc]["Wizard's Wig"]) - area_has_stat_plant = true; - if (area_has_stat_plant && !suggestion.no_stat_remove) - should_remove = true; - } - - } - - if (should_remove) - keys_removing.listAppend(key); - } - foreach key in keys_removing - { - remove __plants_suggested_locations[keys_removing[key]]; - } -} - -void generateFloristFriar(Checklist [int] checklists) -{ - if (!__iotms_usable[$item[Order of the Green Thumb Order Form]]) - return; - if (!__misc_state["in run"]) //currently, these suggestions are in-run only - return; - ChecklistEntry [int] florist_entries; - - ChecklistSubentry [int] subentries; - foreach key in __plant_output_order - { - string plant_name = __plant_output_order[key]; - if (!(__plant_properties contains plant_name)) - continue; - Plant plant = __plant_properties[plant_name]; - - ChecklistSubentry subentry; - subentry.header = plant_name + ", " + plant.terrain; - subentry.modifiers.listAppend(plant.zone_effect); - - //See if we suggested this plant anywhere: - foreach key in __plants_suggested_locations - { - PlantSuggestion suggestion = __plants_suggested_locations[key]; - if (suggestion.plant_name == plant_name) - { - //we did - string suggestion_text = suggestion.loc; - if (suggestion.details != "") - suggestion_text += " (" + suggestion.details + ")"; - if (!locationAvailable(suggestion.loc)) - subentry.entries.listAppend(HTMLGenerateSpanOfClass(suggestion_text, "r_future_option")); - else - subentry.entries.listAppend(suggestion_text); - } - } - - string image_name = plant.image_lookup_name; - if (subentry.entries.count() > 0) - { - subentries.listAppend(subentry); - } - } - if (subentries.count() > 0) - { - florist_entries.listAppend(ChecklistEntryMake("plant up sea daisy", "place.php?whichplace=forestvillage&action=fv_friar", subentries).ChecklistEntrySetIDTag("Florist friar plant reminder")); - } - - checklists.listAppend(ChecklistMake("Florist Friar", florist_entries)); -} - -//Does not return colour formatting for elemental damage; will need to add that yourself. -string getPlantDescription(string plant_name) -{ - switch (plant_name) - { - case "Rabid Dogwood": - case "War Lily": - case "Blustery Puffball": - return "+30 ML"; - case "Rutabeggar": - case "Stealing Magnolia": - case "Horn of Plenty": - return "+25% item"; - case "Aloe Guv'nor": - return "HP regen"; - case "Artichoker": - return "delevel"; - case "Canned Spinach": - return "5 muscle/fight"; - case "Crookweed": - return "+60% meat"; - case "Dis Lichen": - return "delevel"; - case "Duckweed": - return "hiding"; - case "Electric Eelgrass": - return "block"; - case "Impatiens": - return "+25% init"; - case "Kelptomaniac": - return "+40% item"; - case "Lettuce Spray": - return "HP regen"; - case "Max Headshroom": - return "MP regen"; - case "Orca Orchid": - return "attack"; - case "Pitcher Plant": - return "MP regen"; - case "Portlybella": - return "HP regen"; - case "Rad-ish Radish": - return "5 moxie/fight"; - case "Red Fern": - return "delevel"; - case "Seltzer Watercress": - return "MP regen"; - case "Shuffle Truffle": - return "+25% init"; - case "Smoke-ra": - return "block"; - case "Snori": - return "HP/MP regen"; - case "Spankton": - return "delevel"; - case "Spider Plant": - return "poison"; - case "Up Sea Daisy": - return "30 stats/fight"; - case "Wizard's Wig": - return "5 myst/fight"; - case "Arctic Moss": - case "Sub-Sea Rose": - case "Chillterelle": - return "cold attack"; - case "Celery Stalker": - case "BamBOO!": - return "spooky attack"; - case "Deadly Cinnamon": - return "hot attack"; - case "Loose Morels": - return "sleaze attack"; - case "Sargassum": - case "Skunk Cabbage": - case "Foul Toadstool": - return "stench attack"; - } - return ""; -} diff --git a/Source/relay/TourGuide/Pulls.ash b/Source/relay/TourGuide/Pulls.ash deleted file mode 100644 index 18cb7e78..00000000 --- a/Source/relay/TourGuide/Pulls.ash +++ /dev/null @@ -1,1131 +0,0 @@ -import "relay/TourGuide/QuestState.ash" -import "relay/TourGuide/Support/Checklist.ash" - -boolean [item] __pulls_reasonable_to_buy_in_run; - -int pullable_amount(item it, int maximum_total_wanted) -{ - boolean buyable_in_run = false; - if (__pulls_reasonable_to_buy_in_run contains it) - buyable_in_run = true; - if (it.tradeable && it.historical_price() > 0 && it.historical_price() < 75000) - buyable_in_run = true; - if (maximum_total_wanted == 0) - maximum_total_wanted = __misc_state_int["pulls available"] + it.available_amount(); - if (__misc_state["Example mode"]) //simulate pulls - { - if (buyable_in_run) - return min(__misc_state_int["pulls available"], maximum_total_wanted); - else - return min(__misc_state_int["pulls available"], min(storage_amount(it) + it.available_amount(), maximum_total_wanted)); - } - - int amount = storage_amount(it); - if (buyable_in_run) - amount = 20; - int total_amount = amount + it.available_amount(); - - if (total_amount > maximum_total_wanted) - { - amount = maximum_total_wanted - it.available_amount(); - } - - // Code by MadCarew to limit your pull # to just 1, not > 1. - if (in_ronin() && amount > 0 ) - { - // Hooray for removing already-pulled stuff! - string ronin_storage_pulls = get_property("_roninStoragePulls"); - string[int] already_pulled = split_string(ronin_storage_pulls, ","); - int requested_item = it.to_int(); - - boolean already_pulled_this_item = false; - foreach key in already_pulled { - if (already_pulled[key] == requested_item) already_pulled_this_item = true; - } - amount = already_pulled_this_item ? 0 : 1; - } - - return min(__misc_state_int["pulls available"], amount); -} - -int pullable_amount(item it) -{ - return pullable_amount(it, 0); -} - - -//generic pull item -record GPItem -{ - //Either item OR alternate_name - item it; - string alternate_name; - string alternate_image_name; - - string reason; - int max_wanted; -}; - -GPItem GPItemMake(item it, string reason, int max_wanted) -{ - GPItem result; - result.it = it; - result.reason = reason; - result.max_wanted = max_wanted; - return result; -} - -GPItem GPItemMake(item it, string reason) -{ - return GPItemMake(it, reason, 1); -} - -GPItem GPItemMake(string alternate_name, string alternate_image_name, string reason) -{ - GPItem result; - result.alternate_name = alternate_name; - result.alternate_image_name = alternate_image_name; - result.reason = reason; - result.max_wanted = 1; - return result; -} - -void listAppend(GPItem [int] list, GPItem entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - - -void generatePullList(Checklist [int] checklists) -{ - // Start out pull list generation with some general bookkeeping - ChecklistEntry [int] pulls_entries; - - // Return in the event that the user has no pulls available - int pulls_available = __misc_state_int["pulls available"]; - if (pulls_available <= 0) - return; - if (pulls_available > 0) - pulls_entries.listAppend(ChecklistEntryMake("special subheader", "", ChecklistSubentryMake(pluralise(pulls_available, "pull", "pulls") + " remaining")).ChecklistEntrySetIDTag("Pulls special subheader")); - - // Establish your base lists & variables - item [int] pullable_list_item; - int [int] pullable_list_max_wanted; - string [int] pullable_list_reason; - GPItem [int] pullable_item_list; - boolean combat_items_usable = true; - boolean combat_skills_usable = true; - - // Set a single path-related variable - if (my_path().id == PATH_POCKET_FAMILIARS) - combat_items_usable = false; - combat_skills_usable = false; - - // ===================================================================== - // ------ SECTION #1: 3+ TURNS ----------------------------------------- - // ===================================================================== - - // Pulls in this category are highly valuable turnsave pulls that can - // either bypass certain quests entirely or save entire chunks of - // quests. Everything here is stupid valuable. Ordering is: - // 1. Free kills - // 2. Free runs - // 3. Copiers - // 4. Quest-y pulls - - boolean canUseHeavySpleeners = availableSpleen() >= 2 && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_COMMUNITY_SERVICE; - - // Breathitin is virtually always good. Absurdly nice pull. - if (canUseHeavySpleeners) - pullable_item_list.listAppend(GPItemMake($item[Breathitin™], "5 outdoor free kills for 2 spleen", 7)); - - // Bat-oomerang is a great freekill pull - if (combat_items_usable && $item[replica bat-oomerang].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[replica bat-oomerang], "3 daily free kills", 1)); - - // Carnivorous Potted Plant is frustrating when you have lots of offhands, but it's - // unambiguously good... so long as you have enough combats left. Going to say - // that after 250 turns spent, it's unlikely you want this. - pullable_item_list.listAppend(GPItemMake($item[carnivorous potted plant], "offhand; +25 ML, 4% chance of turning any given combat free", 1)); - - // Part of me kind of wants to make one pull tile that concatenates the 3 battery - // types, but this is good enough. - - if (combat_skills_usable) { - pullable_item_list.listAppend(GPItemMake($item[battery (car)], "1 yellow ray + freekill|30 turns of 100% item/meat", 2)); - pullable_item_list.listAppend(GPItemMake($item[battery (lantern)], "1 yellow ray + freekill|30 turns of 100% item", 2)); - pullable_item_list.listAppend(GPItemMake($item[battery (9-volt)], "1 yellow ray + freekill", 2)); - } - - boolean freeRunFamiliarUsable = familiar_is_usable($familiar[pair of stomping boots]) || ($skill[the ode to booze].skill_is_usable() && familiar_is_usable($familiar[Frumious Bandersnatch])); - - // This is a catch-all for familiar weight pulls, which are only useful if the user can use boots/bander - if (!__misc_state["familiars temporarily blocked"] && $familiar[pair of stomping boots].is_unrestricted() && freeRunFamiliarUsable) { - - // Sort of a pain, but if they have it, it's a nice +4 runs... - if ($item[snow suit].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[snow suit], "+20 familiar weight for a while, +4 free runs (boots/bander)", 1)); - - // If they've got a free-run fam, this is a dope pull - if ($item[repaid diaper].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[repaid diaper], "+3 free runs (boots/bander)", 1)); - - // If they've got a free-run fam, this is a dope pull - if ($item[silver face paint].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[silver face paint], "+4 free runs (boots/bander)|only lasts 1 turn; extend w/ wool or PYEC?", 1)); - } - - // Generic free-run based pulls - if (__misc_state["free runs usable"]) { - - // GAP & navel are still good pulls, even now! Priority is GAP > navel > parasol, if you own all. - int storagePants = pullable_amount($item[greatest american pants]); - int storageNavel = pullable_amount($item[navel ring of navel gazing]); - int totalGAPandNavel = $items[greatest american pants, navel ring of navel gazing].available_amount(); - - if (storagePants > 0) { - pullable_item_list.listAppend(GPItemMake($item[greatest american pants], "3+ free runaways|item, mox, DA buff", 1)); - } - else if (storageNavel > 0) { - pullable_item_list.listAppend(GPItemMake($item[navel ring of navel gazing], "3+ free runaways|easier fights", 1)); - } - else if (storagePants + storageNavel + totalGAPandNavel == 0) { - pullable_item_list.listAppend(GPItemMake($item[peppermint parasol], "3+ free runaways", 1)); - } - - if (!get_property_boolean("_blankoutUsed") && $item[bottle of blank-out].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[bottle of blank-out], "5 free runaways|flee your problems", 1)); - - } - - // Rain-Doh & Spooky Putty; 5 copies is roughly 3+ turns in value, even without going in delay. - if ($item[empty rain-doh can].available_amount() == 0 && $item[can of rain-doh].available_amount() == 0 && $item[can of rain-doh].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[can of rain-doh], "5 copies/day|everything really", 1)); - - if ($items[empty rain-doh can,can of rain-doh,spooky putty monster].available_amount() == 0 && $item[spooky putty sheet].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[spooky putty sheet], "5 copies/day", 1)); - - // Extro: the modern stuffer/blaster lol. - if (canUseHeavySpleeners) pullable_item_list.listAppend(GPItemMake($item[Extrovermectin™], "3 copies (as wanderers) for 2 spleen", 7)); - - // Stuffers and blasters are still good, though blaster is strictly inferior to a breath - if (availableSpleen() >= 2 && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_COMMUNITY_SERVICE) - { - pullable_item_list.listAppend(GPItemMake($item[turkey blaster], "Burns five turns of delay in last adventured area. Costs spleen, limited uses/day.", MIN(3 - get_property_int("_turkeyBlastersUsed"), MIN(availableSpleen() / 2, 3)))); - - if (!__quest_state["Level 12"].finished && __quest_state["Level 12"].state_int["frat boys left on battlefield"] >= 936 && __quest_state["Level 12"].state_int["hippies left on battlefield"] >= 936) - { - pullable_item_list.listAppend(GPItemMake($item[stuffing fluffer], "Saves eight turns if you use two at the start of fighting in the war.", 2)); - } - } - - // Homebodyl is a pretty good pull if the user doesn't have free crafts. - boolean hasAnyFreeCrafts = false; - - if ($item[recording of Inigo's Incantation of Inspiration].available_amount() > 0) { - hasAnyFreeCrafts = true; - } - else if ($item[cuppa Craft tea].available_amount() > 0) { - hasAnyFreeCrafts = true; - } - else if ($skill[rapid prototyping].skill_is_usable()) { - hasAnyFreeCrafts = true; - } - else if (lookupSkill("Expert Corner-Cutter").skill_is_usable()) { - hasAnyFreeCrafts = true; - } - else if (get_property_int("homebodylCharges") > 0 || $item[Homebodyl™].available_amount() > 0) { - hasAnyFreeCrafts = true; - } - - if (!hasAnyFreeCrafts) - pullable_item_list.listAppend(GPItemMake($item[Homebodyl™], "11 free crafts for 2 spleen", 1)); - - // Hero key generators save 3+ turns apiece, but if you have a zap wand, you should pull accessories instead - if (__misc_state_int["fat loot tokens needed"] > 0) { - - string [int] hero_key_selections; // general summary hero selection variable - string [int] which_pies; // if it's pie time - string [int] which_accessories; // if it's wand time - string line; - string description; - - // If they have an easy way to get a wand (or have a wand, or are in shrunken adv) suggest hero accessories instead of pies - if (my_path() == $path[A Shrunken Adventurer am I] || __iotms_usable[lookupItem("diabolic pizza cube")] || __misc_state["zap wand owned"]) { - if ($items[boris's key,boris's key lime pie].available_amount() == 0) which_accessories.listAppend("Boris' Ring"); - if ($items[jarlsberg's key,jarlsberg's key lime pie].available_amount() == 0) which_accessories.listAppend("Jarlsberg's Earring"); - if ($items[sneaky pete's key,sneaky pete's key lime pie].available_amount() == 0) which_accessories.listAppend("Sneaky Pete's Breath Spray"); - if (which_accessories.count() > 0) - line += which_accessories.listJoinComponents(", ")+" ... get a wand and zap them!"; - hero_key_selections.listAppend(line); - - // If they're pulling accessories, should also probably pull PYEC - pullable_item_list.listAppend(GPItemMake($item[Platinum Yendorian Express Card], "recharge your zap wand, extend some effects")); - } - else if (__misc_state["can eat just about anything"] && availableFullness() > 0) - { - if ($items[boris's key,boris's key lime pie].available_amount() == 0 && $item[boris's key lime pie].item_is_usable()) - which_pies.listAppend("Boris"); - if ($items[jarlsberg's key,jarlsberg's key lime pie].available_amount() == 0 && $item[jarlsberg's key lime pie].item_is_usable()) - which_pies.listAppend("Jarlsberg"); - if ($items[sneaky pete's key,sneaky pete's key lime pie].available_amount() == 0 && $item[sneaky pete's key lime pie].item_is_usable()) - which_pies.listAppend("Sneaky Pete"); - if (which_pies.count() > 0) - line += which_pies.listJoinComponents("/") + "'s "; - line += "key lime pie"; - if (which_pies.count() > 1) - line += "s"; - hero_key_selections.listAppend(line); - - } - - if (hero_key_selections.count() > 0) { - description = hero_key_selections.listJoinComponents(", "); - pullable_item_list.listAppend(GPItemMake("Hero Key Generators", "Boris's key", description)); - } - } - - // Being able to skip HITS entirely is pretty strong, much like Whitey's skip. - int starChartsNeeded = MAX(1 - $item[star chart].available_amount(), 0); - int starsNeeded = MAX(8 - $item[star].available_amount(), 0); - int linesNeeded = MAX(7 - $item[line].available_amount(), 0); - - boolean haveStarKey = __quest_state["Level 13"].state_boolean["Richard\'s star key used"] || $item[richard\'s star key].available_amount() > 0; - - if (!haveStarKey) { - // First, if they don't have a star chart, recommend a chart or a greasy desk bell. - if (starChartsNeeded > 0) { - if ($item[greasy desk bell].is_unrestricted()) { - pullable_item_list.listAppend(GPItemMake($item[greasy desk bell], "get a star chart + 2 stars & 2 lines|free (but difficult) fight", 1)); - } - else { - pullable_item_list.listAppend(GPItemMake($item[star chart], "for Richard's Star Key", 1)); - } - } - - // Next, suggest star pops - if (__misc_state["can eat just about anything"] && my_path() != $path[A Shrunken Adventurer am I]) { - if (availableFullness() > 0 ) { - string starPopDesc = "3-4 stars & lines"; - if (starsNeeded < 4 && linesNeeded < 4) starPopDesc += ", will finish your key"; - if (starsNeeded > 3 && linesNeeded > 3) starPopDesc += ", of the "+starsNeeded+" stars & "+linesNeeded+" lines you still need"; - pullable_item_list.listAppend(GPItemMake($item[star pop], starPopDesc)); - } - - // Next, suggest star KLPs; if we've already suggested star pops, don't suggest KLPs, as they're strictly worse - if (availableFullness() > 3 && !$item[star pop].is_unrestricted()) { - string starKLPDesc = "2-4 stars & lines"; - if (starsNeeded < 3 && linesNeeded < 3) starKLPDesc += ", will finish your key"; - if (starsNeeded > 2 && linesNeeded > 2) starKLPDesc += ", of the "+starsNeeded+" stars & "+linesNeeded+" lines you still need"; - pullable_item_list.listAppend(GPItemMake($item[star key lime pie], starKLPDesc)); - } - } - } - - - // Wet stew is just an eternally great pull, Whitey's sucks - if (!__quest_state["Level 11 Palindome"].finished && $item[mega gem].available_amount() == 0 && ($item[wet stew].available_amount() + $item[wet stunt nut stew].available_amount() + $item[wet stew].creatable_amount() == 0) && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) - pullable_item_list.listAppend(GPItemMake($item[wet stew], "make into wet stunt nut stew|skip whitey's grove", 1)); - - // While a machete is quest-relevant, it's a 4-7 turn pull; that's absurd value. - if (!__quest_state["Level 11 Hidden City"].finished && !__quest_state["Level 11"].finished && (get_property_int("hiddenApartmentProgress") < 1 || get_property_int("hiddenBowlingAlleyProgress") < 1 || get_property_int("hiddenHospitalProgress") < 1 || get_property_int("hiddenOfficeProgress") < 1) && __misc_state["can equip just about any weapon"] && my_path().id != PATH_POCKET_FAMILIARS) - { - boolean have_machete = false; - foreach it in __dense_liana_machete_items - { - if (it.available_amount() > 0 && it.is_unrestricted()) - have_machete = true; - } - if (!have_machete) - { - if (my_basestat($stat[muscle]) < 62 && $item[machetito].is_unrestricted()) - { - //machetito - pullable_item_list.listAppend(GPItemMake($item[machetito], "Machete for dense liana", 1)); - } - else if ($item[muculent machete].is_unrestricted() && my_path().id != PATH_G_LOVER) //my_basestat($stat[muscle]) < 62 && - { - //muculent machete, also gives +5% meat, op ti mal - pullable_item_list.listAppend(GPItemMake($item[muculent machete], "Machete for dense liana", 1)); - } - else - { - //antique machete - pullable_item_list.listAppend(GPItemMake($item[antique machete], "Machete for dense liana", 1)); - } - } - } - - // As with machete, these are just flat-out great pulls, quest relevant or not - // 2025 UPDATE: ... or, well, they were. lol. - // if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && !have_outfit_components("eXtreme Cold-Weather Gear")) - // { - // item [int] missing_ninja_components = items_missing($items[ninja carabiner, ninja crampons, ninja rope]); - // if (missing_ninja_components.count() > 0) - // { - // string description = missing_ninja_components.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; - - // if (numeric_modifier("cold resistance") < 5.0) - // description += "|Will require five " + HTMLGenerateSpanOfClass("cold", "r_element_cold") + " resist to use properly."; - // pullable_item_list.listAppend(GPItemMake("Ninja peak climbing", "__item " + missing_ninja_components[0], description)); - // } - // } - - // Literally just 3 straight turnsave to pull scrips if you need em, lol - string [int] scrip_reasons; - int scrip_needed = 0; - if (!__misc_state["mysterious island available"] && $item[dinghy plans].available_amount() == 0) - { - scrip_needed += 3; - scrip_reasons.listAppend("mysterious island"); - } - if ($item[uv-resistant compass].available_amount() == 0 && $item[ornate dowsing rod].available_amount() == 0 && __misc_state["can equip just about any weapon"] && !__quest_state["Level 11 Desert"].state_boolean["Desert Explored"]) - { - scrip_needed += 1; - scrip_reasons.listAppend($item[uv-resistant compass].to_string()); - } - if (scrip_needed > 0 && my_path().id != PATH_COMMUNITY_SERVICE && my_path().id != PATH_EXPLOSIONS) - { - pullable_item_list.listAppend(GPItemMake($item[Shore Inc. Ship Trip Scrip], "Saves three turns each. (One per day?)|" + scrip_reasons.listJoinComponents(", ", "and").capitaliseFirstLetter() + ".", scrip_needed)); - } - - // Zepp mob, if done via faceroll, is 40+ turns. This stuff is massive value in ignoring that. - if (my_path().id != PATH_SEA && __quest_state["Level 11 Ron"].mafia_internal_step <= 2 && __quest_state["Level 11 Ron"].state_int["protestors remaining"] > 1) - { - item [int] missing_freebird_components = items_missing( __misc_state["Torso aware"] ? $items[lynyrdskin cap,lynyrdskin tunic,lynyrdskin breeches,lynyrd musk] : $items[lynyrdskin cap,lynyrdskin breeches,lynyrd musk] ); - - // In softcore, you are -almost- always going to prefer sleaze route in modern standard. - // However, for the sake of completionism, I will do a short and sweet sleaze calc; if - // the user is over the line of 262 sleaze, they should just pull a dang lewd deck. - - int projectedSleaze = 31; // assuming war outfit + kicks + ghost of a necklace - - if (__iotms_usable[$item[Jurassic Parka]]) projectedSleaze += 40; - if (__iotms_usable[$item[June Cleaver]]) projectedSleaze += 50; - if (__iotms_usable[$item[tiny stillsuit]]) projectedSleaze += 40; - if (__iotms_usable[$item[cursed monkey's paw]]) projectedSleaze += 200; - if (__iotms_usable[$item[designer sweatpants]]) projectedSleaze += 120; - - if (missing_freebird_components.count() > 0 && projectedSleaze < 262) - { - string description = missing_freebird_components.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; - if (__misc_state["Torso aware"]) - { - if ($strings[Wombat,Blender,Packrat] contains my_sign() && my_path().id != PATH_ZOMBIE_SLAYER) // gnome trainer may be available - description += "|Plus five clovers. Skips protestors in five turns? Or become torso aware and pull the tunic first."; - else - description += "|Plus five clovers. Skips the entire Zeppelin Mob in five turns?"; - } - else - description += "|Plus four clovers. Skips the entire Zeppelin Mob in ~four turns?"; - pullable_item_list.listAppend(GPItemMake("Weird copperhead NC strategy", "__item " + missing_freebird_components[0], description)); - } - - if (my_path().id != PATH_GELATINOUS_NOOB && projectedSleaze > 100) - pullable_item_list.listAppend(GPItemMake($item[deck of lewd playing cards], "+138 sleaze damage equip for Zeppelin Mob", 1)); - - } - - // Gravy Boat used to be an unreasonable pull, but in 37 evil per zone era, this is a good one now - if (__quest_state["Level 7"].in_progress) - { - pullable_item_list.listAppend(GPItemMake($item[gravy boat], "Wear to save 3-4 turns in the cyrpt.")); - - } - - // ===================================================================== - // ------ SECTION #2: 1-2 TURNS ---------------------------------------- - // ===================================================================== - - // Not as valuable as the section #1 pulls, but better than average. In - // general, these pulls should be considered above quest misses and - // are less related to explicit in-run findings. - - // Generic free-run based pulls, but these are less valuable than those in section #1 - if (__misc_state["free runs usable"]) - { - // Middle finger ring is straight up good! - if (my_path().id != PATH_ZOMBIE_SLAYER && combat_skills_usable) // can't use due to MP cost in zombie slayer - pullable_item_list.listAppend(GPItemMake($item[mafia middle finger ring], "1 free 80-turn banish, per day", 1)); - - // I did not realize vivala mask gave a 10-turn banish until Legacy of Loathing. I was unfamiliar with its game. - if ($item[v for vivala mask].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[v for vivala mask], "1 free 10-turn banish, per day", 1)); - } - - // Generic free-kill based pulls, but less valuable than tier 1 pulls - int pills_pullable = clampi(20 - get_property_int("_powerPillUses"), 0, 20); - if (pills_pullable > 0 && ($familiar[ms. puck man].have_familiar() || $familiar[puck man].have_familiar())) - { - pullable_item_list.listAppend(GPItemMake($item[power pill], "1 free kill, with your puck", pills_pullable)); - } - - if (combat_items_usable) { - // Shadow bricks are pretty much fine as a pull; certainly better than writs/GSBs - pullable_item_list.listAppend(GPItemMake($item[shadow brick], "1 free kill", 13)); - - // Powdered Madness is expensive but fine - pullable_item_list.listAppend(GPItemMake($item[powdered madness], "1 free kill",5)); - - // Groveling Gravel is worse, but it's... fine - pullable_item_list.listAppend(GPItemMake($item[groveling gravel], "1 free kill|destroys item drops, buyer beware!",5)); - } - - // NC forcers are great! Clara's is nice because it's 2 in a 2-day run. - if ($item[Clara's Bell].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[Clara's Bell], "Forces a non-combat, once/day.", 1)); - - // ... but one stench jelly is also fine! - if (availableSpleen() > 0 && $item[stench jelly].item_is_usable() && my_path().id != PATH_LIVE_ASCEND_REPEAT) - pullable_item_list.listAppend(GPItemMake($item[stench jelly], "Skips ahead to an NC, saves 2-3 turns each.", 20)); - - // Quest-y pull; just save searching for an NC, like an NC forcer, but also save the turn spent! - if (my_path().id != PATH_SEA && !get_property_ascension("lastTempleUnlock") && $item[spooky-gro fertilizer].item_amount() == 0 && $item[spooky-gro fertilizer].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[spooky-gro fertilizer], "Saves 2-ish turns while unlocking temple.")); - - if (my_path().id != PATH_COMMUNITY_SERVICE && $item[11-leaf clover].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[11-leaf clover], "Various turn saving applications|Zeppelin Mob, Wand of Nagamar, etc.")); - - // If you can't hit 25% combat, all of these are actually pretty dope... - if (!__misc_state["can reasonably reach -25% combat"]) - { - if ((my_primestat() == $stat[moxie] || my_basestat($stat[moxie]) >= 35) && $item[iFlail].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[iFlail], "-combat, +11 ML, +5 familiar weight")); - if (__misc_state["Torso aware"] && $item[xiblaxian stealth vest].item_is_usable()) //FIXME exclusiveness with camouflage T-shirt. probably should pull camou if we're over muscle stat, otherwise stealth vest, or whichever we have - pullable_item_list.listAppend(GPItemMake($item[xiblaxian stealth vest], "-combat shirt")); - if ($item[duonoculars].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[duonoculars], "-combat, +5 ML")); - if ($item[ring of conflict].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[ring of conflict], "-combat")); - if (($item[red shoe].can_equip() || my_path().id == PATH_GELATINOUS_NOOB) && $item[red shoe].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[red shoe], "-combat")); - } - - // ... but even if you CAN hit 25% combat, invisibility tonic is actually pretty great - if (my_path().id != PATH_LIVE_ASCEND_REPEAT) { - pullable_item_list.listAppend(GPItemMake($item[patent invisibility tonic], "30 turns of -15% combat|If you route 30 turns of NC hunting together, this is solid value")); - } - - // If they have grey goose, they should (perhaps) consider pulling some of the familiar XP gear - if ($familiar[grey goose].familiar_is_usable() && my_path() != $path[Legacy of Loathing]) { - int extraVestXP = $item[tiny stillsuit].available_amount() > 0 ? 1 : 2; - pullable_item_list.listAppend(GPItemMake($item[grey down vest], "Equip for +"+extraVestXP+" goose XP over your next best option")); - - if ($item[teacher's pen].available_amount() < 3) { - pullable_item_list.listAppend(GPItemMake($item[teacher's pen], "Equip for +2 goose XP per fight")); - } - - } - - // Speaking of goose, Claw of the Infernal Seal is a nice pull for 5 free-ish fights - if (my_class() == $class[seal clubber] && $item[Claw of the Infernal Seal].available_amount() == 0) { - pullable_item_list.listAppend(GPItemMake($item[Claw of the Infernal Seal], "Fight 5 more free seals per day|Familiar turns, XP, and other fight-advanced goodies")); - } - - // Sure, why not; pocket wishes are fine - if ($item[pocket wish].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[pocket wish], "Save turns with meat/item wishes, monster summons, and more", 20)); - - // If nuns is still needed, recommend pulling an inhaler. - if (!__quest_state["Level 12"].state_boolean["Nuns Finished"] && my_path().id != PATH_2CRS) { - pullable_item_list.listAppend(GPItemMake($item[Mick's IcyVapoHotness Inhaler], "10 turns of +200% meat|Worth anywhere from 1-3 turns on the nuns war sidequest")); - } - - // One copy is kind of marginal but it's fine to include right at the end. - if ($familiar[Intergnat].familiar_is_usable() && $item[infinite BACON machine].item_is_usable()) - { - pullable_item_list.listAppend(GPItemMake($item[infinite BACON machine], "One copy/day with ~seven turns of your intergnat.", 1)); - } - - // Speaking of one copy, fine, we'll suggest a 4-d camera - if (combat_items_usable) { - pullable_item_list.listAppend(GPItemMake($item[4-d camera], "Use in a fight to copy a monster", 1)); - } - - // ===================================================================== - // ------ SECTION #3: QUEST MISSES ------------------------------------- - // ===================================================================== - - // Most pulls in here can be (relatively) painlessly routed into your - // run. However, if you don't have them, they're good pulls, just not - // universally valuable like the 1/2 tier pulls. A few of these end - // up being better than pulls above if you miss them, too. - - // I have not included the following 3 pulls because although they sort - // of belong, the logic is complex enough that I didn't want to hassle - - // - QUEST MISS: tangle of rat tails - // - QUEST MISS: sonar-in-a-biscuit - // - QUEST MISS: disposable instant camera - - if (__quest_state["Level 10"].mafia_internal_step >= 8) - { - if (__quest_state["Level 10"].mafia_internal_step == 8 && $item[amulet of extreme plot significance].available_amount() == 0) - { - pullable_item_list.listAppend(GPItemMake($item[amulet of extreme plot significance], "Speeds up castle basement.", 1)); - } - if (!__quest_state["Level 10"].finished && $item[mohawk wig].available_amount() == 0 && (!lookupSkill("Comprehensive Cartography").skill_is_usable() || $item[model airship].available_amount() == 0)) - { - pullable_item_list.listAppend(GPItemMake($item[mohawk wig], "Speeds up top floor of castle.", 1)); - } - } - - if (!__quest_state["Level 9"].state_boolean["bridge complete"]) - { - int boxes_needed = MIN(__quest_state["Level 9"].state_int["bridge fasteners needed"], __quest_state["Level 9"].state_int["bridge lumber needed"]) / 5; - - boxes_needed = MIN(6, boxes_needed); //bridge! farming? - - if (__iotms_usable[lookupItem("model train set")]) boxes_needed = 0; // you REALLY do not need to pull this if you have a train lol - - if (boxes_needed > 0 && $item[smut orc keepsake box].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[smut orc keepsake box], "Skip a few turns in building your smut orc bridge.", boxes_needed)); - } - - if (__quest_state["Level 9"].state_int["peak tests remaining"] > 0) - { - int trimmers_needed = clampi(__quest_state["Level 9"].state_int["peak tests remaining"], 0, 4); - if (trimmers_needed > 0) - pullable_item_list.listAppend(GPItemMake($item[rusty hedge trimmers], "Speed up twin peak, burn delay.|Saves ~2 turns each", trimmers_needed)); - } - - if (__quest_state["Level 11"].mafia_internal_step < 2) - pullable_item_list.listAppend(GPItemMake($item[blackberry galoshes], "Speed up Black Forest by 2-3 turns", 1)); - - //OUTFITS: √War outfit - if (!__quest_state["Level 12"].finished && (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues"))) - { - item [int] missing_hippy_components = missing_outfit_components("War Hippy Fatigues"); - item [int] missing_frat_components = missing_outfit_components("Frat Warrior Fatigues"); - pullable_item_list.listAppend(GPItemMake("Island War Outfit", "__item round purple sunglasses", "Hippy: " + missing_hippy_components.listJoinComponents(", ", "and") + ".|Frat boy: " + missing_frat_components.listJoinComponents(", ", "and") + ".")); - } - - // These are technically 1 turn if you're using clovers, less if you use other resource uses. - if (!__quest_state["Level 8"].state_boolean["Past mine"] && __quest_state["Level 8"].state_string["ore needed"] != "" && !$skill[unaccompanied miner].skill_is_usable()) - { - item ore_needed = __quest_state["Level 8"].state_string["ore needed"].to_item(); - - // Adding a trainset switch here, as you can just get this with trainset if you have it - if (ore_needed != $item[none] && ore_needed.available_amount() < 3 && !__iotms_usable[lookupItem("model train set")]) - { - pullable_item_list.listAppend(GPItemMake(ore_needed, "Level 8 quest.", 3)); - } - } - - if (!have_outfit_components("Knob Goblin Elite Guard Uniform") && !__quest_state["Level 5"].finished) - { - item [int] missing_outfit_components = missing_outfit_components("Knob Goblin Harem Girl Disguise"); - - string entry = missing_outfit_components.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; - entry += " Level 5 quest."; - if (missing_outfit_components.count() > 0) - pullable_item_list.listAppend(GPItemMake("Knob Goblin Harem Girl Disguise", "__item " + missing_outfit_components[0], entry)); - } - - - if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && __quest_state["Level 11 Desert"].state_int["Desert Exploration"] < 95) - { - if (!__quest_state["Level 11 Desert"].state_boolean["Wormridden"] && $item[drum machine].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[drum machine], "30% desert exploration with pages.", 1)); - if (!__quest_state["Level 11 Desert"].state_boolean["Killing Jar Given"] && $location[the haunted bedroom].locationAvailable()) - pullable_item_list.listAppend(GPItemMake($item[killing jar], "15% desert exploration.", 1)); - if (!__quest_state["Level 11 Desert"].state_boolean["Black Paint Given"] && my_path().id == PATH_NUCLEAR_AUTUMN) - pullable_item_list.listAppend(GPItemMake($item[can of black paint], "15% desert exploration.", 1)); - - // Adding milestone, as it's valuable enough to warrant a mention. - pullable_item_list.listAppend(GPItemMake($item[milestone], "5% desert exploration; can use as many as you get!", 10)); - } - - if (!__quest_state["Level 10"].state_boolean["beanstalk grown"] && $item[enchanted bean].available_amount() == 0) { - pullable_item_list.listAppend(GPItemMake($item[enchanted bean], "Grow it in the Nearby Plains for the Level 10 quest", 1)); - } - - int hospital_progress = get_property_int("hiddenHospitalProgress"); - - if (hospital_progress < 7) { - item [int] missingSurgeonComponents; - if (__misc_state["Torso aware"]) - missingSurgeonComponents = items_missing($items[bloodied surgical dungarees,surgical mask,head mirror,half-size scalpel,surgical apron]); - if (!__misc_state["Torso aware"]) - missingSurgeonComponents = items_missing($items[bloodied surgical dungarees,surgical mask,head mirror,half-size scalpel]); - - if (missingSurgeonComponents.count() > 0) - { - string description = "Still need: " + missingSurgeonComponents.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; - pullable_item_list.listAppend(GPItemMake("Surgeon disguise for the Hidden Hospital", "__item " + missingSurgeonComponents[0], description)); - } - - } - - boolean hiddenTavernUnlocked = get_property_ascension("hiddenTavernUnlock"); - - if ($item[book of matches].available_amount() == 0 && !hiddenTavernUnlocked) { - pullable_item_list.listAppend(GPItemMake($item[book of matches], "Unlock Cursed Punch & Bowl of Scorpions for Hidden City turnsaving", 1)); - } - - // Can pull a bowling ball, I guess. - int bowling_progress = get_property_int("hiddenBowlingAlleyProgress"); - int numberOfRollsLeft = 6 - bowling_progress; - int bowlingBallsNeeded = numberOfRollsLeft - $item[bowling ball].available_amount_including_closet(); - int bowlingBallsInInventory = $item[bowling ball].available_amount(); - - if (bowling_progress < 7 && bowlingBallsNeeded > 0) { - pullable_item_list.listAppend(GPItemMake($item[bowling ball], "Could pull a bowling ball for the Hidden Bowling Alley", bowlingBallsNeeded)); - } - - if ($item[electric boning knife].available_amount() == 0 && __quest_state["Level 13"].state_boolean["wall of bones will need to be defeated"] && my_path().id != PATH_POCKET_FAMILIARS) { - if (!$skill[garbage nova].skill_is_usable() && !in_bad_moon() && !__quest_state["Level 13"].state_boolean["past tower level 2"] && $location[the castle in the clouds in the sky (top floor)].locationAvailable()) { - pullable_item_list.listAppend(GPItemMake("Can pull a clusterbomb to crumble the wall of bones", "__ item sleaze clusterbomb", "Unbelievably expensive pull that will save you a few turns if you cannot towerkill the wall of bones")); - } - } - - - // ===================================================================== - // ------ SECTION #4: LEVELING ----------------------------------------- - // ===================================================================== - - // Pulls in this category aren't really measured by turn-value; they're - // measured by how many stats they give the user. Ergo, in cases where - // it's possible, try to include the # of expected stats in the desc - - if (__misc_state["need to level"]) - { - // Best stat pull is the glitch, so put it at the top. But only show it at a critical mass of implementations. - int glitchMonsterStats = MAX(10, 5 * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0 ) * get_property_int("glitchItemImplementationCount") / 4); - - // Below this, you might as well just pull sprout or whatever. - if (glitchMonsterStats > 400) { - string glitchDesc = "Difficult free fight, but massive meat/stat gains!"; - - // Display meat if it actually matters - if (my_meat() < 7500) glitchDesc += "|Will gain "+get_property_int("glitchItemImplementationCount")*5+" meat from your glitch."; - - glitchDesc += "|Will gain "+glitchMonsterStats+" stats from your glitch."; - - if (__iotms_usable[$item[emotion chip]] && clampi(3 - get_property_int("_feelPrideUsed"), 0, 3) > 0) glitchDesc += "|Consider using Feel Pride to get 3x that total of stats."; - - pullable_item_list.listAppend(GPItemMake(lookupItem("[glitch season reward name]"), glitchDesc)); - } - - if (my_primestat() == $stat[muscle]) - { - if ($item[fake washboard].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[fake washboard], "+25% to mainstat gain, offhand.")); - if ($item[red LavaCo Lamp™].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[red LavaCo Lamp™], "+5 adventures, 50 turns of +50% mainstat gain after rollover.")); - } - else if (my_primestat() == $stat[mysticality]) - { - if ($item[basaltamander buckler].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[basaltamander buckler], "+25% to mainstat gain, offhand.")); - if ($item[blue LavaCo Lamp™].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[blue LavaCo Lamp™], "+5 adventures, 50 turns of +50% mainstat gain after rollover.")); - if (my_path().id == PATH_THE_SOURCE) - { - int amount = 3; - if ($item[battle broom].available_amount() > 0) - amount = 2; - pullable_item_list.listAppend(GPItemMake($item[wal-mart nametag], "+4 mainstat/fight", amount)); - } - } - else if (my_primestat() == $stat[moxie]) - { - if ($item[backwoods banjo].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[backwoods banjo], "+20% to mainstat gain, 2h weapon.")); - if ($item[green LavaCo Lamp™].item_is_usable()) - pullable_item_list.listAppend(GPItemMake($item[green LavaCo Lamp™], "+5 adventures, 50 turns of +50% mainstat gain after rollover.")); - if (my_path().id == PATH_THE_SOURCE) - pullable_item_list.listAppend(GPItemMake($item[wal-mart overalls], "+4 mainstat/fight")); - } - - // If the user can use a red rocket, and user doesn't have a cleaver, suggest pulling a guilty sprout - if (__misc_state["in run"] && __misc_state["can eat just about anything"] && available_amount($item[Clan VIP Lounge key]) > 0 && get_property("_fireworksShop").to_boolean() && my_path().id != PATH_G_LOVER) { - if (!__iotms_usable[$item[June Cleaver]]) { - int sproutStats = MAX(0, 4 * 225 * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0)); - pullable_item_list.listAppend(GPItemMake($item[guilty sprout],"Food; gain "+sproutStats+" stats with a red-rocketed sprout!")); - } - } - - // Vamp stats are pretty stupid but they're plausible I guess. - int vampingStats = MIN(500, 4 * my_basestat(my_primestat())) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); - pullable_item_list.listAppend(GPItemMake($item[plastic vampire fangs], "Gain"+vampingStats+" mainstat, once/day; costs a turn!", 1)); - } - - - // ===================================================================== - // ------ SECTION #5: PATH-SPECIFIC ------------------------------------ - // ===================================================================== - - // Pulls in this category are path-specific pulls that are useful in a - // particular challenge path context and not particularly useful in - // other situations. - - if (my_path() == $path[A Shrunken Adventurer am I]) - pullable_item_list.listAppend(GPItemMake("Flat +100 stat potion", "__item bottle of pirate juice", "The tower stat test is really, really tough in this path!|Once at the tower, pull a bottle of pirate juice for moxie, teeny-tiny magic scroll for myst, or a bottle of rhinoceros hormones for muscle.")); - - if (my_path().id == PATH_COMMUNITY_SERVICE) - pullable_item_list.listAppend(GPItemMake($item[pocket wish], "Saves turns on everything in Community Service.", 20)); - - if (my_path().id == PATH_HEAVY_RAINS) - pullable_item_list.listAppend(GPItemMake($item[fishbone catcher's mitt], "offhand, less items washing away", 1)); - - // ===================================================================== - // ------ SECTION #6: TURNBLOAT ---------------------------------------- - // ===================================================================== - - // Pulls in this category are only really worth it if they help you make - // daycount. You probably ignore it in most unrestricted contexts, but - // instead of flat ignoring it I think you just throw these at the - // absolute bottom of the list. - - // Turnbloat does not work in slow and steady, unless you are sweaty bill - if (my_path().id != PATH_SLOW_AND_STEADY) - { - // PANTSGIVING: banishes aren't really turnsaving anymore, you'd only pull it for unrestricted bloat. - pullable_item_list.listAppend(GPItemMake($item[pantsgiving], "5x non-free banishes|+2 stats/fight|+15% items|2 extra fullness (realistically)", 1)); - - // General food/drink constructors - if (__misc_state["can eat just about anything"] && availableFullness() > 0) - { - string [int] food_selections; - - if (availableFullness() >= 5 && my_path() != $path[A Shrunken Adventurer am I]) - { - if (my_level() >= 13 && my_path().id != PATH_G_LOVER) - food_selections.listAppend("hi meins"); - else if ($item[moon pie].is_unrestricted() && $item[moon pie].item_is_usable()) - food_selections.listAppend("moon pies"); - if ($item[fleetwood mac 'n' cheese].item_is_usable()) - food_selections.listAppend("fleetwood mac 'n' cheese" + (my_level() < 8 ? " (level 8)" : "")); - if ($item[karma shawarma].is_unrestricted() && $item[karma shawarma].item_is_usable()) - food_selections.listAppend("karma shawarma? (expensive" + (my_level() < 7 ? ", level 7" : "") + ")"); - } - - // adding the legendary cookbookbat foods; technically, if they have a bander, DDoL is - // also 3 turnsave via freeruns, but that's kind of annoying logic... - if ($item[Deep Dish of Legend].item_is_usable() && storage_amount($item[Deep Dish of Legend]) > 0) - food_selections.listAppend("Deep Dish of Legend" + (my_level() < 5 ? " (level 5)" : "")); - if ($item[Calzone of Legend].item_is_usable() && storage_amount($item[Calzone of Legend]) > 0) - food_selections.listAppend("Calzone of Legend" + (my_level() < 5 ? " (level 5)" : "")); - if ($item[Pizza of Legend].item_is_usable() && storage_amount($item[Pizza of Legend]) > 0) - food_selections.listAppend("Pizza of Legend" + (my_level() < 5 ? " (level 5)" : "")); - - string description; - if (food_selections.count() > 0) - description = food_selections.listJoinComponents(", ") + ", etc."; - pullable_item_list.listAppend(GPItemMake("Food", "Deep Dish of Legend", description)); - } - if (__misc_state["can drink just about anything"] && availableDrunkenness() >= 0 && inebriety_limit() >= 5) - { - string [int] drink_selections; - if ($item[wrecked generator].is_unrestricted() && $item[wrecked generator].item_is_usable()) - drink_selections.listAppend("wrecked generators"); - if ($item[Ice Island Long Tea].is_unrestricted() && $item[Ice Island Long Tea].item_is_usable()) - drink_selections.listAppend("Ice Island Long Tea"); - if ($item[Boris's beer].is_unrestricted() && $item[Boris's beer].item_is_usable()) - drink_selections.listAppend("Boris's beer"); - if ($item[vintage smart drink].is_unrestricted() && $item[vintage smart drink].item_is_usable()) - drink_selections.listAppend("vintage smart drink"); - - string description; - if (drink_selections.count() > 0) - description = drink_selections.listJoinComponents(", ") + ", etc."; - - pullable_item_list.listAppend(GPItemMake("Drink", "gibson", description)); - } - - if ($skill[ancestral recall].have_skill() && my_adventures() < 10) - { - int casts = get_property_int("_ancestralRecallCasts"); - if (casts < 10) - pullable_item_list.listAppend(GPItemMake($item[blue mana], "+3 adventures each.", clampi(10 - casts, 0, 10))); - } - - //unify these... later... - foreach it in $items[License to Chill,etched hourglass] - pullable_item_list.listAppend(GPItemMake(it, "slotless turn generation", 1)); - - boolean canEquipThumbRing = my_basestat($stat[muscle]) > 39; - pullable_item_list.listAppend(GPItemMake($item[mafia thumb ring], "turn generation accessory"+(canEquipThumbRing ? "" : " (need 40 muscle to equip!)"), 1)); - } - - // ===================================================================== - // ------ SECTION #7: MARGINAL GRAVEYARD ------------------------------- - // ===================================================================== - - // Pulls in this category are pretty bad. Most of them are leftover from - // old metas where the were mildly useful. Commenting them out... for - // now, mostly because there's possibly some future use case I'm not - // seeing and it's largely good stuff to at least remember that we - // once considered a good pull. - - // ... however, pre-commenting-out, I will include one meat-generating - // item at the end of the recommendations. It doesn't save turns, - // really, but it's certainly comfortable! - - if (my_meat() < 5000) - { - item meatyItem = $item[gold wedding ring]; - if (storage_amount($item[facsimile dictionary]) > 0) meatyItem = $item[facsimile dictionary]; - pullable_item_list.listAppend(GPItemMake(meatyItem, "Autosells for "+autosell_price(meatyItem)+" meat.|Likely non-optimal.", 1)); - } - - // At best, folder holder represents a minor leveling boost and +/- combat. Better than red shoe, but not dramatically... - // if (true) - // { - // string line = "So many things!"; - // if ($item[over-the-shoulder folder holder].storage_amount() > 0 && $item[over-the-shoulder folder holder].item_is_usable()) - // { - // string [int] description; - // string [item] folder_descriptions; - - // folder_descriptions[$item[folder (red)]] = "+20 muscle"; - // folder_descriptions[$item[folder (blue)]] = "+20 myst"; - // folder_descriptions[$item[folder (green)]] = "+20 moxie"; - // folder_descriptions[$item[folder (magenta)]] = "+15 muscle +15 myst"; - // folder_descriptions[$item[folder (cyan)]] = "+15 myst +15 moxie"; - // folder_descriptions[$item[folder (yellow)]] = "+15 muscle +15 moxie"; - // folder_descriptions[$item[folder (smiley face)]] = "+2 muscle stat/fight"; - // folder_descriptions[$item[folder (wizard)]] = "+2 myst stat/fight"; - // folder_descriptions[$item[folder (space skeleton)]] = "+2 moxie stat/fight"; - // folder_descriptions[$item[folder (D-Team)]] = "+1 stat/fight"; - // folder_descriptions[$item[folder (Ex-Files)]] = "+5% combat"; - // folder_descriptions[$item[folder (skull and crossbones)]] = "-5% combat"; - // folder_descriptions[$item[folder (Knight Writer)]] = "+40% init"; - // folder_descriptions[$item[folder (Jackass Plumber)]] = "+25 ML"; - // folder_descriptions[$item[folder (holographic fractal)]] = "+4 all res"; - // folder_descriptions[$item[folder (barbarian)]] = "stinging damage"; - // folder_descriptions[$item[folder (rainbow unicorn)]] = "prismatic stinging damage"; - // folder_descriptions[$item[folder (Seawolf)]] = "-pressure penalty"; - // folder_descriptions[$item[folder (dancing dolphins)]] = "+50% item (underwater)"; - // folder_descriptions[$item[folder (catfish)]] = "+15 familiar weight (underwater)"; - // folder_descriptions[$item[folder (tranquil landscape)]] = "15 DR / 15 HP & MP regen"; - // folder_descriptions[$item[folder (owl)]] = "+500% item (dreadsylvania)"; - // folder_descriptions[$item[folder (Stinky Trash Kid)]] = "passive stench damage"; - // folder_descriptions[$item[folder (sports car)]] = "+5 adv"; - // folder_descriptions[$item[folder (sportsballs)]] = "+5 PVP fights"; - // folder_descriptions[$item[folder (heavy metal)]] = "+5 familiar weight"; - // folder_descriptions[$item[folder (Yedi)]] = "+50% spell damage"; - // folder_descriptions[$item[folder (KOLHS)]] = "+50% item (KOLHS)"; - - // foreach s in $slots[folder1,folder2,folder3] - // { - // item folder = s.equipped_item(); - // if (folder == $item[none]) continue; - - // if (folder_descriptions contains folder) - // description.listAppend(folder_descriptions[folder]); - // } - // if (description.count() > 0) - // line = description.listJoinComponents(" / "); - // } - // pullable_item_list.listAppend(GPItemMake($item[over-the-shoulder folder holder], line, 1)); - // } - - // As with folder holder, this just isn't really a great pull anymore. Minor back slot is just not useful at all. - - // if (!__misc_state["familiars temporarily blocked"] && ($item[protonic accelerator pack].available_amount() == 0 || $familiar[machine elf].familiar_is_usable())) //if you have a machine elf, it might be worth pulling a bjorn with a protonic pack anyways - // { - // if ($item[Buddy Bjorn].storage_amount() > 0) - // pullable_item_list.listAppend(GPItemMake($item[Buddy Bjorn], "+10ML/+lots MP hat|or +item/+init/+meat/etc", 1)); - // else if ($item[buddy bjorn].available_amount() == 0) - // pullable_item_list.listAppend(GPItemMake($item[crown of thrones], "+10ML/+lots MP hat|or +item/+init/+meat/etc", 1)); - // } - - // At best, this is +5 fam weight; not worth a pull at all. - // if ($item[operation patriot shield].item_is_usable()) - // pullable_item_list.listAppend(GPItemMake($item[operation patriot shield], "+america", 1)); - // pullable_item_list.listAppend(GPItemMake($item[the crown of ed the undying], "Various in-run modifiers. (init, HP, ML/item/meat/etc)", 1)); - // } - - //pullable_item_list.listAppend(GPItemMake($item[haiku katana], "?", 1)); - // if ($item[bottle-rocket crossbow].item_is_usable()) - // pullable_item_list.listAppend(GPItemMake($item[bottle-rocket crossbow], "?", 1)); - - // This never showed up because it had an added false in the condition. I am commenting it out - // because I don't think anyone in unrestricted would ever want to do this? - - // boolean have_super_fairy = false; - // // Pretty sure I deleted the places that use this, but in case I didn't... - // if ((familiar_is_usable($familiar[fancypants scarecrow]) && $item[spangly mariachi pants].available_amount() > 0) || (familiar_is_usable($familiar[mad hatrack]) && $item[spangly sombrero].available_amount() > 0)) - // have_super_fairy = true; - - // if (!have_super_fairy && my_path().id != PATH_HEAVY_RAINS) - // { - // if (familiar_is_usable($familiar[fancypants scarecrow])) - // pullable_item_list.listAppend(GPItemMake($item[spangly mariachi pants], "2x fairy on fancypants scarecrow", 1)); - // else if (familiar_is_usable($familiar[mad hatrack])) - // pullable_item_list.listAppend(GPItemMake($item[spangly sombrero], "2x fairy on mad hatrack", 1)); - // } - - // These all suck now lol - //pullable_item_list.listAppend(GPItemMake($item[jewel-eyed wizard hat], "a wizard is you!", 1)); - //pullable_item_list.listAppend(GPItemMake($item[origami riding crop], "+5 stats/fight, but only if the monster dies quickly", 1)); //not useful? - //pullable_item_list.listAppend(GPItemMake($item[plastic pumpkin bucket], "don't know", 1)); //not useful? - //pullable_item_list.listAppend(GPItemMake($item[packet of mayfly bait], "why let it go to waste?", 1)); - - // Not good enough to use. The untinkering is cute, might unlock an extra battery YR, but not pull-worthy. - // pullable_item_list.listAppend(GPItemMake($item[loathing legion knife], "?", 1)); - - // No idea why you would want this, honestly. - // if ($item[juju mojo mask].item_is_usable()) - // pullable_item_list.listAppend(GPItemMake($item[juju mojo mask], "?", 1)); - - // Technically this is best in slot at certain times of the month but I don't care enough to include it anymore. - // if ($item[jekyllin hide belt].item_is_usable()) - // pullable_item_list.listAppend(GPItemMake($item[jekyllin hide belt], "+variable% item", 3)); - - // There's probably a (very small) case for still including as BIS +ML, but it's barely better than carn plant. - // if (__misc_state["need to level"]) - // { - // pullable_item_list.listAppend(GPItemMake($item[hockey stick of furious angry rage], "+30ML accessory.", 1)); - // } - - // Not useful enough unfortunately. - // pullable_item_list.listAppend(GPItemMake($item[ice sickle], "+15ML 1h weapon|+item/+meat/+init foldables", 1)); - - // No world where you're wasting a pull on +15% item drop on purpose. - // if ($item[buddy bjorn].available_amount() == 0 && $item[camp scout backpack].item_is_usable()) - // pullable_item_list.listAppend(GPItemMake($item[camp scout backpack], "+15% items on back", 1)); - - // Only really useful in their own paths. - // if ($item[boris's helm].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[boris's helm], "+15ML/+5 familiar weight/+init/+mp regeneration/+weapon damage", 1)); - // pullable_item_list.listAppend(GPItemMake($item[Jarlsberg's Pan], "Cook up some cool Jarlsberg potions!", 1)); - - // None of these shirts are particularly cool or good. - // if (__misc_state["Torso aware"]) - // { - // pullable_item_list.listAppend(GPItemMake($item[flaming pink shirt], "+15% items on shirt. (marginal)" + (__misc_state["familiars temporarily blocked"] ? "" : "|Or extra experience on familiar. (very marginal)"), 1)); - // if (__misc_state["need to level"] && $item[Sneaky Pete's leather jacket (collar popped)].available_amount() == 0 && $item[Sneaky Pete's leather jacket].available_amount() == 0) - // { - - // if ($item[Sneaky Pete's leather jacket (collar popped)].storage_amount() + $item[Sneaky Pete's leather jacket].storage_amount() > 0 && $item[Sneaky Pete's leather jacket].item_is_usable()) - // { - // if (my_path().id != PATH_AVATAR_OF_SNEAKY_PETE) - // pullable_item_list.listAppend(GPItemMake($item[Sneaky Pete's leather jacket], "+30ML/+meat/+adv/+init/+moxie shirt", 1)); - // } - // else - // if ($item[cane-mail shirt].item_is_usable()) - // pullable_item_list.listAppend(GPItemMake($item[cane-mail shirt], "+20ML shirt", 1)); - // } - // } - - // Only useful in Grey Goo. Not worth a pull. - // if (__misc_state["spooky airport available"] && __misc_state["need to level"] && __misc_state["can drink just about anything"] && $effect[jungle juiced].have_effect() == 0) - // { - // pullable_item_list.listAppend(GPItemMake($item[jungle juice], "Drink that doubles stat-gain in the deep dark jungle.", 1)); - // } - - // lol absolutely not - //pullable_item_list.listAppend(GPItemMake($item[slimy alveolus], "40 turns of +50ML (" + floor(40 * 50 * __misc_state_float["ML to mainstat multiplier"]) +" mainstat total, cave bar levelling)|1 spleen", 3)); //marginal now. low-skill oil peak/cyrpt? - - //FIXME suggest machetito? - //FIXME suggest super marginal stuff in SCO or S&S - //Ideas: Goat cheese, keepsake box, √spooky-gro fertilizer, harem outfit, perfume, rusty hedge trimmers, bowling ball, surgeon gear, tomb ratchets or tangles, all the other pies - //FIXME suggest ore when we don't have access to free mining - - //FIXME add hat/stuffing fluffer/blank-out - - // Ezan had some cruft here for pulling XP% things for chateau rest improved stats. I removed it because it - // didn't even show and isn't relevant to unrestricted anymore, high or low end. Sorry Ezan. - - // It's cute, but not really useful - // if ($item[Mr. Cheeng's spectacles] != $item[none]) - // pullable_item_list.listAppend(GPItemMake($item[Mr. Cheeng's spectacles], "+15% item, +30% spell damage, acquire random potions in-combat.|Not particularly optimal, but fun.")); - - // ======================================================================================================== - // ------ OK COOL ALL THE PULLS ARE DEALT WITH, NOW LET'S CONCAT THE PULL LIST LADS ----------------------- - // ======================================================================================================== - - boolean currently_trendy = (my_path().id == PATH_TRENDY); - foreach key in pullable_item_list - { - GPItem gp_item = pullable_item_list[key]; - string reason = gp_item.reason; - string [int] reason_list = split_string_alternate(reason, "\\|"); - - if (gp_item.alternate_name != "") - { - pulls_entries.listAppend(ChecklistEntryMake(gp_item.alternate_image_name, "storage.php", ChecklistSubentryMake(gp_item.alternate_name, "", reason_list)).ChecklistEntrySetIDTag("Pull suggestions " + gp_item.alternate_name)); - continue; - } - - - item [int] items; - int [item] related_items = get_related(gp_item.it, "fold"); - if (related_items.count() == 0) - items.listAppend(gp_item.it); - else - { - foreach it in related_items - items.listAppend(it); - } - - - int max_wanted = gp_item.max_wanted; - - int found_total; - foreach key, it in items - { - found_total += it.available_amount(); - } - if (found_total >= max_wanted) - continue; - if (my_path().id == PATH_GELATINOUS_NOOB) - { - boolean allowed = false; - boolean [item] whitelist = $items[gravy boat,blackberry galoshes,machetito,muculent machete,antique machete,Mr. Cheeng's spectacles,buddy bjorn,crown of thrones,navel ring of navel gazing,greatest american pants,plastic vampire fangs,the jokester's gun]; - foreach key, it in items - { - if ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3] contains it.to_slot() && !(whitelist contains it) && !it.discardable && !__items_in_outfits[it]) - { - } - else - allowed = true; - } - if (!allowed) - { - //print_html("Rejecting " + items[0]); - continue; - } - } - - foreach key in items - { - item it = items[key]; - if (currently_trendy && !is_trendy(it)) - continue; - if (!is_unrestricted(it)) - continue; - int actual_amount = pullable_amount(it, max_wanted); - if (actual_amount > 0) - { - string url = "storage.php"; - if (it != $item[none]) - { - if (it.fullness > 0 || it.inebriety > 0) - url = "storage.php?which=1"; - if (it.to_slot() != $slot[none]) - url = "storage.php?which=2"; - } - - if (it.storage_amount() == 0 && (__pulls_reasonable_to_buy_in_run contains it) && it != $item[11-leaf clover] && it != $item[none]) - url = "mall.php"; - - string title = pluralise(actual_amount, it); - if (max_wanted == 1) - title = it; - - pulls_entries.listAppend(ChecklistEntryMake(it, url, ChecklistSubentryMake(title, "", reason_list)).ChecklistEntrySetIDTag("Pull suggestions " + it.name)); - break; - } - } - } - - checklists.listAppend(ChecklistMake("Suggested Pulls", pulls_entries)); -} - -void PullsInit() -{ - //Pulls which are reasonable to buy in the mall, then pull: - __pulls_reasonable_to_buy_in_run = $items[peppermint parasol,slimy alveolus,bottle of blank-out,11-leaf clover,ninja rope,ninja crampons,ninja carabiner,clockwork maid,sonar-in-a-biscuit,knob goblin perfume,chrome ore,linoleum ore,asbestos ore,goat cheese,enchanted bean,dusty bottle of Marsala,dusty bottle of Merlot,dusty bottle of Muscat,dusty bottle of Pinot Noir,dusty bottle of Port,dusty bottle of Zinfandel,ketchup hound,lion oil,bird rib,stunt nuts,drum machine,beer helmet,distressed denim pants,bejeweled pledge pin,reinforced beaded headband,bullet-proof corduroys,round purple sunglasses,wand of nagamar,ng,star crossbow,star hat,star staff,star sword,Star key lime pie,Boris's key lime pie,Jarlsberg's key lime pie,Sneaky Pete's key lime pie,tomb ratchet,tangle of rat tails,swashbuckling pants,stuffed shoulder parrot,eyepatch,Knob Goblin harem veil,knob goblin harem pants,knob goblin elite polearm,knob goblin elite pants,knob goblin elite helm,cyclops eyedrops,mick's icyvapohotness inhaler,large box,marzipan skull,jabañero-flavored chewing gum,handsomeness potion,Meleegra™ pills,pickle-flavored chewing gum,lime-and-chile-flavored chewing gum,gremlin juice,wussiness potion,Mick's IcyVapoHotness Rub,super-spiky hair gel,adder bladder,black no. 2,skeleton,rock and roll legend,wet stew,glass of goat's milk,hot wing,frilly skirt,pygmy pygment,wussiness potion,gremlin juice,adder bladder,Angry Farmer candy,thin black candle,super-spiky hair gel,Black No. 2,Mick's IcyVapoHotness Rub,Frigid ninja stars,Spider web,Sonar-in-a-biscuit,Black pepper,Pygmy blowgun,Meat vortex,Chaos butterfly,Photoprotoneutron torpedo,Fancy bath salts,inkwell,Hair spray,disease,bronzed locust,Knob Goblin firecracker,powdered organs,leftovers of indeterminate origin,mariachi G-string,NG,plot hole,baseball,razor-sharp can lid,tropical orchid,stick of dynamite,barbed-wire fence,smut orc keepsake box,spooky-gro fertilizer,machetito,muculent machete,antique machete,rusty hedge trimmers,Ice Island Long Tea,killing jar,can of black paint,gravy boat,ring of conflict,bram's choker,duonoculars]; -} diff --git a/Source/relay/TourGuide/QuestState.ash b/Source/relay/TourGuide/QuestState.ash deleted file mode 100644 index 5958655c..00000000 --- a/Source/relay/TourGuide/QuestState.ash +++ /dev/null @@ -1,134 +0,0 @@ -import "relay/TourGuide/Support/Library.ash" - -//Quest status stores all/most of our quest information in an internal format that's easier to understand. -record QuestState -{ - string quest_name; - string image_name; - - boolean startable; //can be started, but hasn't yet - boolean started; - boolean in_progress; - boolean finished; - - int mafia_internal_step; //0 for not started. INT32_MAX for finished. This is +1 versus mafia's "step1/step2/stepX" system. "step1" is represented as 2, "step2" as 3, etc. - - boolean [string] state_boolean; - string [string] state_string; - int [string] state_int; - float [string] state_float; - - boolean council_quest; -}; - -QuestState [string] __quest_state; -boolean [string] __misc_state; -string [string] __misc_state_string; -int [string] __misc_state_int; -float [string] __misc_state_float; - -int QuestStateConvertQuestPropertyValueToNumber(string property_value) -{ - int result = 0; - if (property_value == "") - return -1; - if (property_value == "started") - { - result = 1; - } - else if (property_value == "finished") - { - result = INT32_MAX; - } - else if (property_value.contains_text("step")) - { - //lazy: - string theoretical_int = property_value.replace_string(" ", "").replace_string("step", ""); //one revision had a bug that set questL11Worship to "step 4", so remove spaces - int step_value = theoretical_int.to_int_silent(); - - result = step_value + 1; - - if (result < 0) - result = 0; - } - else - { - //unknown - } - return result; -} - -boolean questPropertyPastInternalStepNumber(string quest_property, int number) -{ - return QuestStateConvertQuestPropertyValueToNumber(get_property(quest_property)) >= number; -} - -void QuestStateParseMafiaQuestPropertyValue(QuestState state, string property_value) -{ - state.started = false; - state.finished = false; - state.in_progress = false; - state.mafia_internal_step = QuestStateConvertQuestPropertyValueToNumber(property_value); - - if (state.mafia_internal_step > 0) - state.started = true; - if (state.mafia_internal_step == INT32_MAX) - state.finished = true; - if (state.started && !state.finished) - state.in_progress = true; - - // Adding a new state check that finishes our quests if the user is in CS or GG. - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) - state.finished = true; -} - -boolean QuestStateEquals(QuestState q1, QuestState q2) -{ - //not sure how to do record equality otherwise - if (q1.quest_name != q2.quest_name) - return false; - if (q1.image_name != q2.image_name) - return false; - if (q1.startable != q2.startable) - return false; - if (q1.started != q2.started) - return false; - if (q1.in_progress != q2.in_progress) - return false; - if (q1.finished != q2.finished) - return false; - if (q1.mafia_internal_step != q2.mafia_internal_step) - return false; - - if (q1.state_boolean != q2.state_boolean) - return false; - if (q1.state_string != q2.state_string) - return false; - if (q1.state_int != q2.state_int) - return false; - return true; -} - -void QuestStateParseMafiaQuestProperty(QuestState state, string property_name, boolean allow_quest_log_load) -{ - state.QuestStateParseMafiaQuestPropertyValue(get_property(property_name)); -} - -void QuestStateParseMafiaQuestProperty(QuestState state, string property_name) -{ - QuestStateParseMafiaQuestProperty(state, property_name, true); -} - -QuestState QuestState(string property_name) -{ - QuestState state; - QuestStateParseMafiaQuestProperty(state, property_name); - return state; -} - -QuestState QuestStateFromManualStep(string manual_value) -{ - QuestState state; - state.QuestStateParseMafiaQuestPropertyValue(manual_value); - return state; -} diff --git a/Source/relay/TourGuide/Quests.ash b/Source/relay/TourGuide/Quests.ash deleted file mode 100644 index ec2e9d9c..00000000 --- a/Source/relay/TourGuide/Quests.ash +++ /dev/null @@ -1,92 +0,0 @@ -import "relay/TourGuide/Support/Checklist.ash" -import "relay/TourGuide/Support/LocationAvailable.ash" -import "relay/TourGuide/Quests/Quest import.ash" - - -void QuestsInit() -{ - QPirateInit(); - QLevel2Init(); - QLevel3Init(); - QLevel4Init(); - QLevel5Init(); - QLevel6Init(); - QLevel7Init(); - QLevel8Init(); - QLevel9Init(); - QLevel10Init(); - QLevel11Init(); - QLevel12Init(); - QLevel13Init(); - QNemesisInit(); - QSeaInit(); - QSpaceElvesInit(); - QAzazelInit(); - QUntinkerInit(); - QArtistInit(); - QLegendaryBeatInit(); - QMemoriesInit(); - QWhiteCitadelInit(); - QWizardOfEgoInit(); - QFeloniaInit(); - QGuildInit(); - QSubject37Init(); - QMartyInit(); - QMeatsmithInit(); - QGalaktikInit(); - QOldLandfillInit(); - QMadnessBakeryInit(); - QManorInit(); - Q8BitInit(); -} - - -void QuestsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QLevel2GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel3GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel4GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel5GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel6GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel7GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel8GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel9GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel10GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel11GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel12GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel13GenerateTasks(task_entries, optional_task_entries, future_task_entries); - - QManorGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QPirateGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QNemesisGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QSeaGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QSpaceElvesGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QAzazelGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QGuildGenerateTasks(task_entries, optional_task_entries, future_task_entries); - - QUntinkerGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QArtistGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLegendaryBeatGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QMemoriesGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QWhiteCitadelGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QWizardOfEgoGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QSpookyravenLightsOutGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QFeloniaGenerateTasks(task_entries, optional_task_entries, future_task_entries); - - QAirportGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QSubject37GenerateTasks(task_entries, optional_task_entries, future_task_entries); - QMartyGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QMeatsmithGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QGalaktikGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QOldLandfillGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QMadnessBakeryGenerateTasks(task_entries, optional_task_entries, future_task_entries); - - Q8bitRealmGenerateTasks(task_entries, future_task_entries); -} - -void QuestsGenerateResources(ChecklistEntry [int] resource_entries) -{ - QSpookyravenLightsOutGenerateResource(resource_entries); - QAirportGenerateResource(resource_entries); - Q8bitRealmGenerateResource(resource_entries); -} diff --git a/Source/relay/TourGuide/Quests/8-bit Realm.ash b/Source/relay/TourGuide/Quests/8-bit Realm.ash deleted file mode 100644 index faecc4d1..00000000 --- a/Source/relay/TourGuide/Quests/8-bit Realm.ash +++ /dev/null @@ -1,348 +0,0 @@ -void Q8BitInit() -{ - // This is a convoluted enough keygen method that I'm refactoring it as a quest as - // opposed to a set. This could be wrong! But I think it is a good exercise. - QuestState state; - - // Set the state as "started" if you have the continuum transfunctioner. - if (!state.started && $items[continuum transfunctioner].available_amount() > 0) - state.started = true; - - // Finish this quest if you are in 11,037 Leagues Under the Sea, so the tiles never generate. - if (my_path().id == PATH_SEA) state.finished = true; - - // Finish this quest if you are in community service, so the tiles never generate. - if (my_path().id == PATH_COMMUNITY_SERVICE) state.finished = true; - - // Finish this quest tile if you are in Kingdom of Exploathing, as 8-bit doesn't exist there. - if (my_path().id == PATH_KINGDOM_OF_EXPLOATHING) state.finished = true; - - // Finish this quest tile if you are no longer in-run. Currently commented for testing. - if (!__misc_state["in run"]) state.finished = true; - - boolean haveDigitalKey = $item[digital key].available_amount() > 0; - boolean turnedInDigitalKey = __quest_state["Level 13"].state_boolean["digital key used"]; - - if (haveDigitalKey || turnedInDigitalKey) state.finished = true; - - // Establish basic information for tile generation - state.quest_name = "Digital Key Quest"; - state.image_name = "__item digital key"; // if the bespoke logic fails - // state.image_name = "inexplicable door"; - state.council_quest = true; - - // Total 8-bit score - state.state_int["currentScore"] = get_property_int("8BitScore"); - - // Bonus zone is tracked via the 8BitColor pref; black/red/blue/green are the zone colors - state.state_string["currentColor"] = get_property("8BitColor"); - - if (state.state_string["currentColor"] == "") state.state_string["currentColor"] = "black"; - - __quest_state["Digital Key"] = state; -} - -void Q8bitRealmGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] future_task_entries) -{ - // In 2023, there was a large rework of the 8-bit realm. Instead of needing 30 white - // pixels to generate your Digital Key, you now need a certain amount of score. This - // new tile is an attempt to help users figure out the new 8-bit zone! - - // Read in the information initialized in the quest initializer. - QuestState base_quest_state = __quest_state["Digital Key"]; - - // Do not generate tiles if you do not need the digital key anymore. - if (base_quest_state.finished) { return; } - - // Because I'm doing nested subentries, the broader quest is a ChecklistEntry. - ChecklistEntry entry; - entry.url = "place.php?whichplace=8bit"; - entry.image_lookup_name = base_quest_state.image_name; - entry.tags.id = "Digital Key Pixels 8bit L13"; - entry.should_indent_after_first_subentry = true; - entry.subentries.listAppend(ChecklistSubentryMake(base_quest_state.quest_name)); - entry.should_highlight = $locations[Vanya's Castle, The Fungus Plains, Megalo-City, Hero's Field] contains __last_adventure_location; - - // NOTE: Technically speaking, I think some of this probably -should- be in the Q8BitInit() - // function. However, I like the fact that this lets me read in currentColor as an index - // key on this data; while you can make state.state_int[] and state.state_string[] fields, - // it seems much less straightforward to make int/string fields keyed by a string but with - // proper reference parameters. So instead, I initialize a ton of crap here. Hopefully the - // comments help make everything a bit cleaner and clearer! - - // Make it easier to reference currentColor, as it keys everything else. - string currentColor = base_quest_state.state_string["currentColor"]; - - // Will use the keys of this array as the loop key later. - string [string] helpfulModifier; - - helpfulModifier["black"] = "Initiative"; - helpfulModifier["red"] = "Meat Drop"; - helpfulModifier["blue"] = "Damage Absorption"; - helpfulModifier["green"] = "Item Drop"; - - // I'm using the same math that Beldur did in the 8-bit relay. These are the associated - // values needed to make the expectedPoints equation work; basically, it's the level - // of the modifier you need to see actual point generation increase. - int [string] minimumToAddPoints; - - minimumToAddPoints["black"] = 300; - minimumToAddPoints["red"] = 150; - minimumToAddPoints["blue"] = 300; - minimumToAddPoints["green"] = 100; - - // NOTE: to get to the max point, you add 300 to any of the minimumToAddPoints lol - - // Mapping zones for fun and profit, but mostly to make future things easier. - string [string] zoneMap; - - zoneMap["black"] = "Vanya's Castle"; - zoneMap["red"] = "The Fungus Plains"; - zoneMap["blue"] = "Megalo-City"; - zoneMap["green"] = "Hero's Field"; - - // Storing this so the tile can tell which zone is next. This made me realize that I, like a - // fool, ordered every one of these black/red/blue/green instead of the actual order of - // black/blue/green/red. Sorry, mom. Sorry, college. - string [string] nextColor; - - nextColor["black"] = "blue"; - nextColor["red"] = "black"; - nextColor["blue"] = "green"; - nextColor["green"] = "red"; - - int bonusTurnsRemaining = 5 - get_property("8BitBonusTurns").to_int(); - - // Populate user's modifier for each bonus; iterates through black/red/blue/green - int [string] userModifier; - - foreach key in helpfulModifier - userModifier[key] = numeric_modifier(helpfulModifier[key]); - - // Populate expected points in each zone - int [string] expectedPoints; - int addedBonus; - int denominator; - int rawPoints; - boolean isCurrentZoneBonus; - - foreach key in helpfulModifier - { - isCurrentZoneBonus = (currentColor == key); - addedBonus = (isCurrentZoneBonus ? 100 : 50); - denominator = (isCurrentZoneBonus ? 10 : 20); - rawPoints = min(300, max(0, userModifier[key] - minimumToAddPoints[key])); - - expectedPoints[key] = addedBonus + round(rawPoints/denominator) * 10; - } - - // Figure out if the user is better-suited to adventure elsewhere. - string highestPointColor = currentColor; - - foreach key, value in expectedPoints { - if (value > expectedPoints[currentColor]) { - if (value > expectedPoints[highestPointColor]) { - highestPointColor = key; - } - } - } - - // Now that we have calculated everything, we can finally make the tile! Before the very - // detailed subentry, we have a quick statement of what the quest wants you to do. We - // do this by adding to the subentries[0] guy. - entry.subentries[0].entries.listAppend("Gain "+pluralise(max(10000-base_quest_state.state_int["currentScore"],0), "more point","more points")+" to get your digital key."); - - // OK, now we make our subentry for the bonus zone. - ChecklistSubentry subentry; - - // We have a return up top for a finished quest. As a result, it should only hit !started - // in the right order, even if our finishing reassignment in QuestInit doesn't work. - if (!base_quest_state.started) - { - subentry.header = "Go listen to a crackpot!"; - entry.url = "place.php?whichplace=forestvillage&action=fv_mystic"; - entry.image_lookup_name = "__item continuum transfunctioner"; - subentry.entries.listAppend("Visit the crackpot mystic for your transfunctioner."); - } - else if (base_quest_state.state_int["currentScore"] < 10000) { - - subentry.header = "BONUS ZONE: "+zoneMap[currentColor]+" ("+pluralise(bonusTurnsRemaining, "more fight", "more fights")+")"; - - // Modify the overarching image to match the current zone. - entry.image_lookup_name = zoneMap[currentColor]; - - // Establish easier shorthand for the active bonus modifier. - string activeMod = helpfulModifier[currentColor]; - string neededModifier = to_string(minimumToAddPoints[currentColor]+300); - - // Add nice shorthand text to the subentry w/ the stat to maximize. - if (activeMod == "Initiative") {subentry.modifiers.listAppend("+"+neededModifier+"% init");} - if (activeMod == "Meat Drop") {subentry.modifiers.listAppend("+"+neededModifier+"% meat");} - if (activeMod == "Damage Absorption") {subentry.modifiers.listAppend("+"+neededModifier+" DA");} - if (activeMod == "Item Drop") {subentry.modifiers.listAppend("+"+neededModifier+"% item");} - if (zoneMap[currentColor] != "Megalo-City") {subentry.modifiers.listAppend("outdoor zone");} - - // Give descriptive information about the current zone. - if (expectedPoints[currentColor] == 400) - { - // If the user is at maximum, color the tile a bit and be merry. - subentry.entries.listAppend(HTMLGenerateSpanFont("MAXIMUM POINTS!",currentColor)); - subentry.entries.listAppend("Adventure in "+HTMLGenerateSpanFont(""+zoneMap[currentColor]+"", currentColor)+" for 400 points per turn!"); - } - else - { - // If the user is not at maximum, point out what they need to buff. - subentry.entries.listAppend("Current expected points: "+to_string(expectedPoints[currentColor])); - - string percentCharacter = (activeMod != "Damage Absorption" ? "%" : ""); - string modifierNeededText = to_string(minimumToAddPoints[currentColor]+300 - userModifier[currentColor])+percentCharacter; - - string buffUpLine = "Consider buffing "+HTMLGenerateSpanFont(helpfulModifier[currentColor], currentColor)+" for more points."; - buffUpLine += "|*You need "+modifierNeededText+" more for max points."; - subentry.entries.listAppend(buffUpLine); - } - - // In both cases, show the # of turns remaining of bonus in this zone. - subentry.entries.listAppend("In "+pluralise(bonusTurnsRemaining, "more fight", "more fights")+", bonus zone will be "+HTMLGenerateSpanFont(zoneMap[nextColor[currentColor]],nextColor[currentColor])+"."); - - if (highestPointColor != currentColor) { - subentry.entries.listAppend("Alternate Route:|*"+HTMLGenerateSpanFont("At current stats, you'd earn "+expectedPoints[highestPointColor]+" points per fight at "+zoneMap[highestPointColor]+". Not recommended!","gray")); - } - - // If they don't have the transfunctioner equipped, equip it and change the URL. - if ($item[continuum transfunctioner].equipped_amount() == 0) - { - entry.url = "inventory.php?ftext=continuum+transfunctioner"; - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip your transfunctioner to access the realm.", "red")); - - } - } - - entry.subentries.listAppend(subentry); - - // Add small subentry near the end w/ current score! But only add it if they have their transfunctioner. - if (base_quest_state.started) { - ChecklistSubentry keyCompletionSubentry; - - keyCompletionSubentry.header = "Projected Key Completion"; - keyCompletionSubentry.modifiers.listAppend("Current Score: "+to_string(base_quest_state.state_int["currentScore"])+" of 10000"); - - if (base_quest_state.state_int["currentScore"] < 10000) - { - int pointsLeft = 10000 - base_quest_state.state_int["currentScore"]; - int minimumTurnsToGetKey = ceil(pointsLeft / 400.0); // ceil always rounds up, so any fraction of a leftover turn will add 1 - keyCompletionSubentry.entries.listAppend("If you max your bonus, you'll have your key in "+pluralise(minimumTurnsToGetKey, "more turn", "more turns")+"."); - } - else - { - keyCompletionSubentry.entries.listAppend("Woah, 10000 points??? That's this life's high score!"); - keyCompletionSubentry.entries.listAppend("Visit the Treasure House to claim your hard-earned Digital Key."); - } - entry.subentries.listAppend(keyCompletionSubentry); - } - - // If the user is below level 5, probably have better things to be doing unless they're - // already maxed out at the relevant bonus zone; ergo, shift the tile to "Future Tasks" - - if (my_level() > 5 || expectedPoints[currentColor] == 400) - task_entries.listAppend(entry); - else - future_task_entries.listAppend(entry); - -} - - -void Q8bitRealmGenerateResource(ChecklistEntry [int] resource_entries) -{ - // This resource tile is still valuable for newbies who need/want red pixel potions. Somewhat - // ironically, this is actually more useful post-revamp since newbies have more reason to - // get black pixels. It might be slightly annoying for some speedrunners, but they can just - // hide the tile if they don't like it. - - // ... though even I can't pretend we want this in aftercore, lol - if (!__misc_state["in run"] || !in_ronin()) - return; - - // Comment originally from Ezandora noting good things in the pixel shop: - // - Blue pixel potion - [50,80] MP restore - // - monster bait - +5% combat - // - pixel sword - +15% init - // - red pixel potion - [100,120] HP restore - the shadow knows - // - pixel whip - useful against vampires - - string [item] craftables; - int [item] max_craftables_wanted; - craftables[$item[pixel bread]] = "+50% meat"; - craftables[$item[pixel whiskey]] = "+50% item"; - craftables[$item[blue pixel potion]] = "~65 MP restore"; - craftables[$item[monster bait]] = "+5% combat"; - max_craftables_wanted[$item[monster bait]] = 1; - - // Only generate red pixels if you need them for tower healing. They sell like shit. - if (__quest_state["Level 13"].state_boolean["shadow will need to be defeated"]) - craftables[$item[red pixel potion]] = "~110 HP restore; good for shadow"; - if ($locations[dreadsylvanian castle,the spooky forest,The Haunted Sorority House,The Daily Dungeon] contains __last_adventure_location) //known vampire locations. it's perfectly reasonable to test against the sorority house, here in 2023 - { - craftables[$item[pixel whip]] = "vampire killer"; - max_craftables_wanted[$item[pixel whip]] = 1; - } - - max_craftables_wanted[$item[blue pixel potion]] = 11; - max_craftables_wanted[$item[red pixel potion]] = 4; //4 minimum to out-shadow - - string [int] crafting_list_have; - string [int] crafting_list_cannot; - foreach it, reason in craftables - { - if (it.available_amount() >= MAX(1, max_craftables_wanted[it])) - continue; - string line = it; - - if (max_craftables_wanted[it] != 1 && it.creatable_amount() > 0) - line = pluralise(it.creatable_amount(), it); - line += ": " + reason; - if (it.creatable_amount() == 0) - { - line = HTMLGenerateSpanFont(line, "grey"); - crafting_list_cannot.listAppend(line); - } - else - crafting_list_have.listAppend(line); - } - if (crafting_list_have.count() > 0) - { - string [int] crafting_list = crafting_list_have; - crafting_list.listAppendList(crafting_list_cannot); - string pixels_have = "Craft a few Pixel sundries"; - resource_entries.listAppend(ChecklistEntryMake("__item red pixel potion", "shop.php?whichshop=mystic", ChecklistSubentryMake(pixels_have, "", crafting_list), 10).ChecklistEntrySetIDTag("Crackpot mystic pixel crafting resource")); - } -} - -void Q8bitRealmGenerateMissingItems(ChecklistEntry [int] items_needed_entries) -{ - // This is still helpful, but mostly for KoE, the only remaining path where you need - // to generate white pixels for the digital key. Keep it just for KoE? Heh. - - if (!__misc_state["in run"] && !__misc_state["Example mode"]) - return; - if (__quest_state["Level 13"].state_boolean["digital key used"]) - return; - if (my_path().id == PATH_COMMUNITY_SERVICE) - return; - - if ($item[digital key].available_amount() == 0) { - string url = "place.php?whichplace=8bit"; - if (my_path().id == PATH_KINGDOM_OF_EXPLOATHING) - url = "shop.php?whichshop=exploathing"; - string [int] options; - // I had a change of heart and kept it for normal runs too. Dreams can come true. - if (__quest_state["Digital Key"].state_int["currentScore"] > 9999) { - options.listAppend("Visit 8-bit Realm's Treasure House and claim your key!"); - } else if (my_path().id == PATH_KINGDOM_OF_EXPLOATHING) { - options.listAppend("Go fight invader bullets, or find some way to fight a Ghost."); - } else { - options.listAppend("Visit the 8-bit Realm and max your score to claim a Digital Key."); - } - items_needed_entries.listAppend(ChecklistEntryMake("__item digital key", url, ChecklistSubentryMake("Digital key", "", options)).ChecklistEntrySetIDTag("Council L13 quest tower door digital key")); - } -} diff --git a/Source/relay/TourGuide/Quests/Airport.ash b/Source/relay/TourGuide/Quests/Airport.ash deleted file mode 100644 index 2587cd45..00000000 --- a/Source/relay/TourGuide/Quests/Airport.ash +++ /dev/null @@ -1,1670 +0,0 @@ -void QSleazeAirportBuffJimmyGenerateTasks(ChecklistEntry [int] task_entries, QuestState [string] SBBState) -{ - if (SBBState["questESlMushStash"].in_progress) - { - //jimmy, fun-guy - //run +item, collect 10 pencil thin mushrooms (item) - ChecklistSubentry subentry; - subentry.header = "Pencil-Thin Mush Stash"; - - item item_to_collect = $item[pencil thin mushroom]; - int remaining_of_item = MAX(0, 10 - item_to_collect.item_amount()); - if (SBBState["questESlMushStash"].mafia_internal_step > 2 || remaining_of_item <= 0) - subentry.entries.listAppend("Return to Buff Jimmy."); - else if (SBBState["questESlAudit"].in_progress) - subentry.entries.listAppend("Need to finish Audit-Tory Hallucinations, first."); - else - { - subentry.modifiers.listAppend("+item"); - subentry.entries.listAppend("Adventure in the The Fun-Guy Mansion and collect " + pluraliseWordy(remaining_of_item, "more " + item_to_collect.name, "more " + item_to_collect.plural) + "."); - } - - task_entries.listAppend(ChecklistEntryMake("__item pencil thin mushroom", "place.php?whichplace=airport_sleaze", subentry, $locations[The Fun-Guy Mansion])); - } - else if (SBBState["questESlCheeseburger"].in_progress) - { - //jimmy, diner - //buffJimmyIngredients - need 15(?) - //equip Paradaisical Cheeseburger recipe, olfact Sloppy Seconds Burgers - ChecklistSubentry subentry; - subentry.header = "Paradise Cheeseburger"; - - int remaining_of_item = MAX(0, 15 - get_property_int("buffJimmyIngredients")); - if (SBBState["questESlCheeseburger"].mafia_internal_step > 2 || remaining_of_item <= 0) - subentry.entries.listAppend("Return to Buff Jimmy."); - else - { - subentry.modifiers.listAppend("olfact Burgers"); - subentry.entries.listAppend("Adventure in the Sloppy Seconds Diner and collect " + pluraliseWordy(remaining_of_item, "more ingredient", "more ingredients") + "."); - if ($item[Paradaisical Cheeseburger recipe].available_amount() > 0 && $item[Paradaisical Cheeseburger recipe].equipped_amount() == 0) - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the Paradaisical Cheeseburger recipe.", "red")); - } - - task_entries.listAppend(ChecklistEntryMake("__item hamburger", "place.php?whichplace=airport_sleaze", subentry, $locations[Sloppy Seconds Diner])); - } - else if (SBBState["questESlSalt"].in_progress) - { - //jimmy, yacht - //collect 50 salty sailor salts (item), olfact son of a son of a sailor, run +ML, want fishy - ChecklistSubentry subentry; - subentry.header = "Lost Shaker of Salt"; - - item item_to_collect = $item[salty sailor salt]; - int remaining_of_item = MAX(0, 50 - item_to_collect.item_amount()); - if (SBBState["questESlSalt"].mafia_internal_step > 2 || remaining_of_item <= 0) - subentry.entries.listAppend("Return to Buff Jimmy."); - else - { - subentry.modifiers.listAppend("+ML"); - subentry.modifiers.listAppend("olfact son of a son of a sailor"); - subentry.entries.listAppend("Adventure in The Sunken Party Yacht and collect " + pluraliseWordy(remaining_of_item, "more salt", "more salts") + "."); - if ($effect[fishy].have_effect() == 0) - subentry.entries.listAppend("Try to acquire Fishy effect."); - } - - task_entries.listAppend(ChecklistEntryMake("__item salty sailor salt", "place.php?whichplace=airport_sleaze", subentry, $locations[The Sunken Party Yacht])); - } -} -void QSleazeAirportTacoDanGenerateTasks(ChecklistEntry [int] task_entries, QuestState [string] SBBState) -{ - if (SBBState["questESlAudit"].in_progress) - { - //questESlAudit - //taco dan, fun-guy - //look for 10 Taco Dan's Taco Stand's Taco Receipt (item). requires Sleight of Mind effect from sleight-of-hand mushrooms dropped from area - ChecklistSubentry subentry; - subentry.header = "Audit-Tory Hallucinations"; - - item item_to_collect = $item[Taco Dan's Taco Stand's Taco Receipt]; - int remaining_of_item = MAX(0, 10 - item_to_collect.item_amount()); - if (SBBState["questESlAudit"].mafia_internal_step > 2 || remaining_of_item <= 0) - subentry.entries.listAppend("Return to Taco Dan."); - else - { - if ($effect[sleight of mind].have_effect() == 0 && $item[sleight-of-hand mushroom].available_amount() > 0) - subentry.entries.listAppend(HTMLGenerateSpanFont("Use sleight-of-hand mushroom", "red") + " to acquire receipts."); - subentry.entries.listAppend("Adventure in the The Fun-Guy Mansion and collect " + pluraliseWordy(remaining_of_item, "more receipt", "more receipts") + "."); - } - - task_entries.listAppend(ChecklistEntryMake("__item Taco Dan's Taco Stand's Taco Receipt", "place.php?whichplace=airport_sleaze", subentry, $locations[The Fun-Guy Mansion])); - } - else if (SBBState["questESlCocktail"].in_progress) - { - //taco dan, diner - //tacoDanCocktailSauce - //equip Taco Dan's Taco Stand Cocktail Sauce Bottle, olfact Sloppy Seconds Cocktails - ChecklistSubentry subentry; - subentry.header = "Cocktail as old as Cocktime"; - - int remaining_of_item = MAX(0, 15 - get_property_int("tacoDanCocktailSauce")); - if (SBBState["questESlCocktail"].mafia_internal_step > 2 || remaining_of_item <= 0) - subentry.entries.listAppend("Return to Taco Dan."); - else - { - subentry.modifiers.listAppend("olfact Cocktails"); - subentry.entries.listAppend("Adventure in the Sloppy Seconds Diner and collect " + remaining_of_item.int_to_wordy() + " more sauce."); - if ($item[Taco Dan's Taco Stand Cocktail Sauce Bottle].available_amount() > 0 && $item[Taco Dan's Taco Stand Cocktail Sauce Bottle].equipped_amount() == 0) - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the Taco Dan's Taco Stand Cocktail Sauce Bottle.", "red")); - } - - task_entries.listAppend(ChecklistEntryMake("__item Taco Dan's Taco Stand Cocktail Sauce Bottle", "place.php?whichplace=airport_sleaze", subentry, $locations[Sloppy Seconds Diner])); - } - else if (SBBState["questESlFish"].in_progress) - { - //taco dan, yacht - //tacoDanFishMeat - //collect 300 fish meat, olfact taco fish, run +meat, want fishy - ChecklistSubentry subentry; - subentry.header = "Dirty Fishy Dish"; - - int remaining_of_item = MAX(0, 300 - get_property_int("tacoDanFishMeat")); - if (SBBState["questESlFish"].mafia_internal_step > 2 || remaining_of_item <= 0) - subentry.entries.listAppend("Return to Taco Dan."); - else - { - subentry.modifiers.listAppend("+meat"); - subentry.modifiers.listAppend("olfact taco fish"); - subentry.entries.listAppend("Adventure in The Sunken Party Yacht and collect " + remaining_of_item.int_to_wordy() + " more fish meat."); - if ($effect[fishy].have_effect() == 0) - subentry.entries.listAppend("Try to acquire Fishy effect."); - } - - task_entries.listAppend(ChecklistEntryMake("__item fishy fish", "place.php?whichplace=airport_sleaze", subentry, $locations[The Sunken Party Yacht])); - } -} -void QSleazeAirportBrodenGenerateTasks(ChecklistEntry [int] task_entries, QuestState [string] SBBState) -{ - if (SBBState["questESlBacteria"].in_progress) - { - //broden, fun-guy, brodenBacteria - //+all(?) elemental resistance - //collect 10 bacteria - ChecklistSubentry subentry; - subentry.header = "Cultural Studies"; - - int remaining_of_item = MAX(0, 10 - get_property_int("brodenBacteria")); - if (SBBState["questESlBacteria"].mafia_internal_step > 2 || remaining_of_item <= 0) - subentry.entries.listAppend("Return to Broden."); - else if (SBBState["questESlMushStash"].in_progress) - subentry.entries.listAppend("Need to finish Pencil-Thin Mush Stash, first."); - else if (SBBState["questESlAudit"].in_progress) - subentry.entries.listAppend("Need to finish Audit-Tory Hallucinations, first."); - else - { - subentry.modifiers.listAppend("+elemental resistance"); - subentry.entries.listAppend("Adventure in the The Fun-Guy Mansion and collect " + remaining_of_item.int_to_wordy() + " more bacteria."); - } - - task_entries.listAppend(ChecklistEntryMake("__item chainsaw chain", "place.php?whichplace=airport_sleaze", subentry, $locations[The Fun-Guy Mansion])); - } - else if (SBBState["questESlSprinkles"].in_progress) - { - //broden, diner - //brodenSprinkles - //equip sprinkle shaker, olfact Sloppy Seconds Sundaes - ChecklistSubentry subentry; - subentry.header = "A Light Sprinkle"; - - int remaining_of_item = MAX(0, 15 - get_property_int("brodenSprinkles")); - if (SBBState["questESlSprinkles"].mafia_internal_step > 2 || remaining_of_item <= 0) - subentry.entries.listAppend("Return to Broden."); - else - { - subentry.modifiers.listAppend("olfact Sundaes"); - subentry.entries.listAppend("Adventure in the Sloppy Seconds Diner and collect " + remaining_of_item.int_to_wordy() + " more sprinkles."); - if ($item[sprinkle shaker].available_amount() > 0 && $item[sprinkle shaker].equipped_amount() == 0) - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the sprinkle shaker.", "red")); - } - - task_entries.listAppend(ChecklistEntryMake("__item sprinkle shaker", "place.php?whichplace=airport_sleaze", subentry, $locations[Sloppy Seconds Diner])); - } - else if (SBBState["questESlDebt"].in_progress) - { - //broden, yacht - //collect 15 bike rental broupon (item), olfact drownedbeat, want fishy - ChecklistSubentry subentry; - subentry.header = "Beat Dead the Deadbeats"; - - item item_to_collect = $item[bike rental broupon]; - int remaining_of_item = MAX(0, 15 - item_to_collect.item_amount()); - if (SBBState["questESlDebt"].mafia_internal_step > 2 || remaining_of_item <= 0) - subentry.entries.listAppend("Return to Broden."); - else - { - subentry.modifiers.listAppend("olfact drownedbeat"); - subentry.entries.listAppend("Adventure in The Sunken Party Yacht and collect " + pluraliseWordy(remaining_of_item, "more " + item_to_collect.name, "more " + item_to_collect.plural) + "."); - if ($effect[fishy].have_effect() == 0) - subentry.entries.listAppend("Try to acquire Fishy effect."); - } - - task_entries.listAppend(ChecklistEntryMake("__item fixed-gear bicycle", "place.php?whichplace=airport_sleaze", subentry, $locations[The Sunken Party Yacht])); - } -} - - -void QSleazeAirportUMDGenerateTasks(ChecklistEntry [int] task_entries) -{ - if (!__misc_state["sleaze airport available"]) - return; - if (get_property("umdLastObtained") != "") { // && !__misc_state["in run"] - string umd_date_obtained = get_property("umdLastObtained"); - - int day_in_year_acquired_umd = format_date_time("yyyy-MM-dd", umd_date_obtained, "D").to_int(); - int year_umd_acquired = format_date_time("yyyy-MM-dd", umd_date_obtained, "yyyy").to_int(); - - string todays_date = today_to_string(); - int today_day_in_year = format_date_time("yyyyMMdd", todays_date, "D").to_int(); - int todays_year = format_date_time("yyyyMMdd", todays_date, "yyyy").to_int(); - - //We compute the delta of days since last UMD obtained. If it's seven or higher, they can obtain it. - //If the year is different, more complicated. - //Umm... this will inevitably have an off by one error from me not looking closely enough. - - boolean has_been_seven_days = false; - if (year_umd_acquired != todays_year) { - //Query the number of days in last year, then subtract it from day_in_year_acquired_umd. - - int days_in_last_year = format_date_time("yyyy-MM-dd", todays_year + "-12-31", "D").to_int(); //this may work well past the year 10k. if it doesn't and you track down this bug and it's a problem, hello from eight thousand years ago! - - day_in_year_acquired_umd -= days_in_last_year * (todays_year - year_umd_acquired); //this is technically incorrect due to leap years, but it'll still result in proper checking. do not use for delta code - } - - if (today_day_in_year - day_in_year_acquired_umd >= 7) - has_been_seven_days = true; - if (has_been_seven_days) { - string [int] description; - description.listAppend("Adventure in the Sunken Party Yacht.|Choose the first option from a non-combat that appears every twenty adventures."); - description.listAppend("Found once every seven days."); - if ($effect[fishy].have_effect() == 0) - description.listAppend("Possibly acquire fishy effect first."); - if ($item[clara's bell].available_amount() > 0 && !get_property_boolean("_claraBellUsed")) - description.listAppend("Use clara's bell to instantly acquire. Won't need fishy."); - ChecklistEntry entry = ChecklistEntryMake("__item ultimate mind destroyer", $location[The Sunken Party Yacht].getClickableURLForLocation(), ChecklistSubentryMake("Ultimate Mind Destroyer collectable", "free runs", description), $locations[The Sunken Party Yacht]); - entry.tags.id = "Airport sleaze UMD"; - task_entries.listAppend(entry); - } - } -} - -void QSleazeAirportGenerateTasks(ChecklistEntry [int] task_entries) -{ - /* - questESlMushStash - Jimmy, Fun-Guy - questESlAudit - Taco Dan, Fun-Guy - questESlBacteria - Broden, Fun-Guy, brodenBacteria - - questESlCheeseburger - Jimmy, Sloppy Seconds Diner, buffJimmyIngredients(?) - questESlCocktail - Taco Dan, Sloppy Seconds Diner, tacoDanCocktailSauce - questESlSprinkles - Broden, Sloppy Seconds Diner, brodenSprinkles - - questESlSalt - Jimmy, Sunken Yacht - questESlFish - Taco Dan, Sunken Yacht, tacoDanFishMeat - questESlDebt - Broden, Sunken Yacht - */ - //if (__misc_state["in run"] && !($locations[the sunken party yacht,sloppy seconds diner,the fun-guy mansion] contains __last_adventure_location)) //too many - //return; - QuestState [string] SBBState; - SBBState["questESlMushStash"] = QuestState("questESlMushStash"); - SBBState["questESlCheeseburger"] = QuestState("questESlCheeseburger"); - SBBState["questESlSalt"] = QuestState("questESlSalt"); - SBBState["questESlAudit"] = QuestState("questESlAudit"); - SBBState["questESlCocktail"] = QuestState("questESlCocktail"); - SBBState["questESlFish"] = QuestState("questESlFish"); - SBBState["questESlBacteria"] = QuestState("questESlBacteria"); - SBBState["questESlSprinkles"] = QuestState("questESlSprinkles"); - SBBState["questESlDebt"] = QuestState("questESlDebt"); - - ChecklistEntry [int] subtask_entries; - QSleazeAirportBuffJimmyGenerateTasks(subtask_entries, SBBState); - QSleazeAirportTacoDanGenerateTasks(subtask_entries, SBBState); - QSleazeAirportBrodenGenerateTasks(subtask_entries, SBBState); - - if (subtask_entries.count() > 0) { - //Combine them into one entry, for convenience: - ChecklistEntry final_entry; - boolean first = true; - foreach key, entry in subtask_entries { - if (first) { - final_entry = entry; - first = false; - } else { - foreach key2, subentry in entry.subentries { - final_entry.subentries.listAppend(subentry); - } - if (entry.should_highlight) - final_entry.should_highlight = true; - } - - } - final_entry.tags.id = "Airport sleaze quest group"; - - task_entries.listAppend(final_entry); - } - - QSleazeAirportUMDGenerateTasks(task_entries); -} - -//Conspiracy Island Omega Button -RegisterTaskGenerationFunction("IOTMConspiracyIslandGenerateTasks"); -void IOTMConspiracyIslandGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__misc_state["spooky airport available"]) - return; - //press the button! - ChecklistEntry entry; - entry.url = "place.php?whichplace=airport_spooky_bunker&action=si_controlpanel"; - entry.image_lookup_name = "__item big red button"; - entry.importance_level = 8; - int omegaPower = get_property_int("controlPanelOmega"); - if (!get_property_boolean("_controlPanelUsed")) - { - entry.subentries.listAppend(ChecklistSubentryMake(omegaPower + "% Conspiracy Island Omega power", "", "At 100%, press Omega Button to reset better quests.")); - if (!get_property_boolean("controlPanel8") == false) - entry.subentries.listAppend(ChecklistSubentryMake("", "", "Press 1912 Button.")); - if (!get_property_boolean("controlPanel9") == false) - entry.subentries.listAppend(ChecklistSubentryMake("", "", "Press 0-0Z-E Button.")); - } - if (omegaPower == 100) - entry.subentries.listAppend(ChecklistSubentryMake("100% power! Reset to gain new quests and then uze 0-0Z-E again!")); - if (entry.subentries.count() > 0) - { - optional_task_entries.listAppend(entry); - } -} - -void QSpookyAirportJunglePunGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item encrypted micro-cassette recorder"; - state.quest_name = "Pungle in the Jungle"; - QuestStateParseMafiaQuestProperty(state, "questESpJunglePun"); - - if (!state.in_progress) - return; - item recorder = $item[encrypted micro-cassette recorder]; - - if (recorder.available_amount() == 0) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_spooky"; - - - int puns_remaining = 11 - get_property_int("junglePuns"); - if (state.mafia_internal_step <= 2 && puns_remaining > 0) { - subentry.entries.listAppend("Adventure in The Deep Dark Jungle."); - subentry.modifiers.listAppend("+myst"); - - if (recorder.equipped_amount() == 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + recorder.name + ".", "red")); - url = "inventory.php?ftext=encrypted+micro-cassette+recorder"; - } - - subentry.entries.listAppend(pluraliseWordy(puns_remaining, "pun", "puns").capitaliseFirstLetter() + " remaining."); - } else { - url = "place.php?whichplace=airport_spooky&action=airport2_radio"; - subentry.entries.listAppend("Return to the radio and reply."); - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Deep Dark Jungle]).ChecklistEntrySetIDTag("Airport spooky jungle_pun quest")); -} - -void QSpookyAirportFakeMediumGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__familiar happy medium"; - state.quest_name = "Fake Medium at Large"; - QuestStateParseMafiaQuestProperty(state, "questESpFakeMedium"); - - if (!state.in_progress) - return; - item collar = $item[ESP suppression collar]; - - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_spooky"; - - - if (state.mafia_internal_step == 1 && collar.available_amount() == 0) { - subentry.entries.listAppend("Adventure in The Secret Government Laboratory, find a non-combat every twenty turns."); - if (__misc_state["free runs available"]) - subentry.modifiers.listAppend("free runs"); - if (__misc_state["have hipster"]) - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - - string [int,int] solutions; - - solutions.listAppend(listMake("dust motes float", "star")); - solutions.listAppend(listMake("circle of light", "circle")); - solutions.listAppend(listMake("waves a fly away", "waves")); - solutions.listAppend(listMake("square one", "square")); - solutions.listAppend(listMake("expression only adds to your anxiety", "plus")); - - - subentry.entries.listAppend("The last line of the adventure text gives the solution:|*" + HTMLGenerateSimpleTableLines(solutions)); - - if ($item[Personal Ventilation Unit].equipped_amount() == 0 && $item[Personal Ventilation Unit].available_amount() > 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + $item[Personal Ventilation Unit].name + ".", "red")); - url = $item[Personal Ventilation Unit].invSearch(); - } - } else { - url = "place.php?whichplace=airport_spooky&action=airport2_radio"; - subentry.entries.listAppend("Return to the radio and reply."); - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Secret Government Laboratory]).ChecklistEntrySetIDTag("Airport spooky fake_medium quest")); -} - - -void QSpookyAirportClipperGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item military-grade fingernail clippers"; - state.quest_name = "The Big Clipper"; - QuestStateParseMafiaQuestProperty(state, "questESpClipper"); - - if (!state.in_progress) - return; - item clipper = $item[military-grade fingernail clippers]; - - if (clipper.available_amount() == 0) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_spooky"; - - - int fingernails_remaining = 23 - get_property_int("fingernailsClipped"); - if (state.mafia_internal_step == 1 && fingernails_remaining > 0) { - subentry.entries.listAppend("Adventure in The Mansion of Dr. Weirdeaux, use the military-grade fingernail clippers on the monsters three times per fight."); - - int turns_remaining = ceil(fingernails_remaining.to_float() / 3.0); - - subentry.entries.listAppend(fingernails_remaining + " fingernails / " + pluralise(turns_remaining, "turn", "turns") + " remaining."); - } else { - url = "place.php?whichplace=airport_spooky&action=airport2_radio"; - subentry.entries.listAppend("Return to the radio and reply."); - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Mansion of Dr. Weirdeaux]).ChecklistEntrySetIDTag("Airport spooky clipper quest")); -} - -void QSpookyAirportEveGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item vial of patchouli oil"; //science lab - state.quest_name = "Choking on the Rind"; - QuestStateParseMafiaQuestProperty(state, "questESpEVE"); - - if (!state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_spooky"; - - - if (state.mafia_internal_step < 2) { - subentry.entries.listAppend("Adventure in The Secret Government Laboratory, find a non-combat every twenty turns.|At the choice adventure, choose " + listMake("Left", "Left", "Right", "Left", "Right").listJoinComponents(__html_right_arrow_character) + "."); - if (__misc_state["free runs available"]) - subentry.modifiers.listAppend("free runs"); - if (__misc_state["have hipster"]) - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - - if ($item[Personal Ventilation Unit].equipped_amount() == 0 && $item[Personal Ventilation Unit].available_amount() > 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + $item[Personal Ventilation Unit].name + ".", "red")); - url = $item[Personal Ventilation Unit].invSearch(); - } - } else { - url = "place.php?whichplace=airport_spooky&action=airport2_radio"; - subentry.entries.listAppend("Return to the radio and reply."); - } - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Secret Government Laboratory]).ChecklistEntrySetIDTag("Airport spooky EVE quest")); -} - - - -void QSpookyAirportSmokesGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item pack of smokes"; - state.quest_name = "Everyone's Running Out of Smokes"; - QuestStateParseMafiaQuestProperty(state, "questESpSmokes"); - - if (!state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_spooky"; - - item smokes = $item[pack of smokes]; - - if (state.mafia_internal_step < 2 && smokes.available_amount() < 10) { - subentry.entries.listAppend("Adventure in The Deep Dark Jungle and collect smokes from the smoke monster."); - subentry.modifiers.listAppend("olfact smoke monster"); - - if (smokes != $item[none]) { - subentry.entries.listAppend(pluraliseWordy(clampi(10 - smokes.available_amount(), 0, 10), "more pack of smokes", "more packs of smokes").capitaliseFirstLetter() + " remaining."); - } - } else { - url = "place.php?whichplace=airport_spooky&action=airport2_radio"; - subentry.entries.listAppend("Return to the radio and reply."); - } - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Deep Dark Jungle]).ChecklistEntrySetIDTag("Airport spooky smoke quest")); -} - - -void QSpookyAirportGoreGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item gore bucket"; - state.quest_name = "Gore Tipper"; - QuestStateParseMafiaQuestProperty(state, "questESpGore"); - - if (!state.in_progress) - return; - item bucket = $item[gore bucket]; - - if (bucket.available_amount() == 0) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_spooky"; - - - int gore_remaining = 100 - get_property_int("goreCollected"); - if (state.mafia_internal_step <= 2 && gore_remaining > 0) { - subentry.entries.listAppend("Adventure in The Secret Government Laboratory."); - subentry.modifiers.listAppend("+meat"); - string [int] items_to_equip; - if (bucket.equipped_amount() == 0) { - items_to_equip.listAppend("gore bucket"); - } - if ($item[Personal Ventilation Unit].equipped_amount() == 0 && $item[Personal Ventilation Unit].available_amount() > 0) { - items_to_equip.listAppend("Personal Ventilation Unit"); - } - if (items_to_equip.count() > 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + items_to_equip.listJoinComponents(", ", "and") + ".", "red")); - url = items_to_equip[0].invSearch(); - } - subentry.entries.listAppend(pluralise(gore_remaining, "pound", "pounds") + " remaining."); - } else { - url = "place.php?whichplace=airport_spooky&action=airport2_radio"; - subentry.entries.listAppend("Return to the radio and reply."); - } - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Secret Government Laboratory]).ChecklistEntrySetIDTag("Airport spooky gore quest")); -} - - -void QSpookyAirportOutOfOrderGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item GPS-tracking wristwatch"; - state.quest_name = "Out of Order"; - QuestStateParseMafiaQuestProperty(state, "questESpOutOfOrder"); - - if (!state.in_progress) - return; - item wristwatch = $item[GPS-tracking wristwatch]; - - if (wristwatch.available_amount() == 0) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_spooky"; - - - if (state.mafia_internal_step <= 2 && $item[Project T. L. B.].item_amount() == 0) { - subentry.modifiers.listAppend("+init"); - - if (wristwatch.equipped_amount() == 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + wristwatch.name + ".", "red")); - url = wristwatch.invSearch(); - } else - subentry.entries.listAppend("Adventure in The Deep Dark Jungle."); - } else { - url = "place.php?whichplace=airport_spooky&action=airport2_radio"; - subentry.entries.listAppend("Return to the radio and reply."); - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Deep Dark Jungle]).ChecklistEntrySetIDTag("Airport spooky out_of_order quest")); -} - - -void QSpookyAirportSerumGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item experimental serum P-00"; - state.quest_name = "Serum Sortie"; - QuestStateParseMafiaQuestProperty(state, "questESpSerum"); - - if (!state.in_progress) - return; - item serum = $item[experimental serum P-00]; - - if (serum == $item[none]) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_spooky"; - - - if (state.mafia_internal_step <= 2 && serum.item_amount() < 5) { - if (serum.available_amount() >= 5) { - subentry.entries.listAppend("Pull " + pluralise(5 - serum.item_amount(), serum) + "."); - } else { - subentry.modifiers.listAppend("+item"); - - subentry.entries.listAppend("Adventure in The Mansion of Dr. Weirdeaux, collect " + int_to_wordy(5 - serum.available_amount()) + " more " + serum.plural + "."); - } - } else { - url = "place.php?whichplace=airport_spooky&action=airport2_radio"; - subentry.entries.listAppend("Return to the radio and reply."); - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Mansion of Dr. Weirdeaux]).ChecklistEntrySetIDTag("Airport spooky serum quest")); -} - -void QSpookyAirportWeirdeauxGenerateTasks(ChecklistEntry [int] task_entries) -{ - if (__last_adventure_location != $location[The Mansion of Dr. Weirdeaux] || my_level() >= 256) - return; - if (in_ronin()) - return; - if (QuestState("questESpClipper").in_progress) - return; - - string url = "place.php?whichplace=airport_spooky"; - string [int] description; - string [int] modifiers; - if (!$skill[curse of marinara].have_skill()) { - if (my_class() == $class[sauceror]) { - description.listAppend("Buy curse of marinara from the guild trainer."); - url = "guild.php?place=trainer"; - } else if ($classes[disco bandit,disco bandit,seal clubber,turtle tamer,disco bandit,pastamancer,accordion thief,disco bandit] contains my_class()) { - description.listAppend("Ascend sauceror to buy curse of marinara."); - url = "ascend.php"; - } else - description.listAppend("Become a sauceror at the end of this ascension, to buy curse of marinara."); - } else { - if ($skill[utensil twist].have_skill() && $item[dinsey's pizza cutter].available_amount() > 0) { - string [int] tasks; - if ($item[dinsey's pizza cutter].equipped_amount() == 0) - tasks.listAppend("equip Dinsey's Pizza Cutter"); - tasks.listAppend("cast curse of marinara"); - tasks.listAppend("keep monster stunned"); - tasks.listAppend("cast utensil twist repeatedly in combat"); - - description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - } else { - if ($skill[utensil twist].have_skill()) { - description.listAppend("Possibly acquire Dinsey's pizza cutter by fighting Wart Dinsey as a Pastamancer."); - } else if ($item[dinsey's pizza cutter].available_amount() > 0) { - description.listAppend("Possibly acquire the pastamancer skill Utensil Twist."); - } else { - description.listAppend("Possibly acquire the pastamancer skill Utensil Twist and Dinsey's pizza cutter by fighting Wart Dinsey as a Pastamancer."); - } - //Drunkula's bell - 15% to 20% of your buffed myst as damage? - //right bear arm - Grizzly Scene, once/fight, 50% HP damage - //Staff of the Headmaster's Victuals - chefstaff (requires skill), jiggle does 30% of monster HP - //Great Wolf's lice - reduces monster attack/def by 30%. ??? - //great wolf's right paw, great wolf's left paw - gives Great Slash ability, which deals 1/3rd buffed muscle damage per paw equipped - description.listAppend("Cast curse of marinara at the start of combat, and keep monster stunned."); - string [item] other_relevant_items; - other_relevant_items[$item[drunkula's bell]] = "throw in combat to deal damage"; - other_relevant_items[$item[right bear arm]] = "grizzly scene deals 50% HP damage"; - if ($skill[Spirit of Rigatoni].skill_is_usable()) - other_relevant_items[$item[Staff of the Headmaster's Victuals]] = "jiggle for 30% HP damage"; - other_relevant_items[$item[Great Wolf's lice]] = "throw in combat to deal damage"; - other_relevant_items[$item[great wolf's left paw]] = "great slash skill deals damage"; - other_relevant_items[$item[great wolf's right paw]] = "great slash skill deals damage"; - - string [int] possibilities; - foreach it, desc in other_relevant_items { - if (it.available_amount() == 0) - continue; - string line = it.capitaliseFirstLetter() + " - " + desc + "."; - if (it.to_slot() != $slot[none] && it.equipped_amount() == 0) - line += " (equip)"; - possibilities.listAppend(line); - } - if (possibilities.count() > 0) - description.listAppend("Try:|*" + possibilities.listJoinComponents("|*").capitaliseFirstLetter()); - } - - modifiers.listAppend("+spooky resistance"); - - string [int] blocking_sources; - if (!__misc_state["familiars temporarily blocked"]) - blocking_sources.listAppend("a potato familiar"); - foreach it in $items[Drunkula's ring of haze,Mesmereyes™ contact lenses,attorney's badge,ancient stone head,navel ring of navel gazing] { - if (it.available_amount() == 0) - continue; - if (it.equipped_amount() > 0) - continue; - string line = it; - if (it.equipped_amount() == 0) - line += " (equip)"; - blocking_sources.listAppend(line); - } - if (my_class() == $class[pastamancer]) - blocking_sources.listAppend("spaghetti elemental thrall"); - if (blocking_sources.count() > 0) - description.listAppend("Use sources of blocking, like " + blocking_sources.listJoinComponents(", ", "and") + "."); - } - - //description.listAppend("Or use " + pluralise(clampi(256 - my_level(), 0, 256), "ultimate wad", "ultimate wads") + "."); //reasonable - - task_entries.listAppend(ChecklistEntryMake("__effect Incredibly Hulking", url, ChecklistSubentryMake("Gain " + pluralise(clampi(256 - my_level(), 0, 256), "level", "levels"), modifiers, description), $locations[The Mansion of Dr. Weirdeaux]).ChecklistEntrySetIDTag("Airport spooky weirdeaux")); -} - -void QSpookyAirportGenerateTasks(ChecklistEntry [int] task_entries) -{ - if (!__misc_state["spooky airport available"]) - return; - //if (__misc_state["in run"] && !($locations[the mansion of dr. weirdeaux,the secret government laboratory,the deep dark jungle] contains __last_adventure_location)) //a common strategy is to accept an island quest in-run, then finish it upon prism break to do two quests in a day. so, don't clutter their interface unless they're adventuring there? hmm... - //return; - - QSpookyAirportClipperGenerateTasks(task_entries); - QSpookyAirportEVEGenerateTasks(task_entries); - QSpookyAirportSmokesGenerateTasks(task_entries); - QSpookyAirportSerumGenerateTasks(task_entries); - QSpookyAirportOutOfOrderGenerateTasks(task_entries); - QSpookyAirportFakeMediumGenerateTasks(task_entries); - QSpookyAirportGoreGenerateTasks(task_entries); - QSpookyAirportJunglePunGenerateTasks(task_entries); - QSpookyAirportWeirdeauxGenerateTasks(task_entries); -} - -// - -void QStenchAirportFishTrashGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item trash net"; - state.quest_name = "Teach a Man to Fish Trash"; - QuestStateParseMafiaQuestProperty(state, "questEStFishTrash"); - - if (!state.in_progress) - return; - item trash_net = $item[trash net]; - - if (trash_net.available_amount() == 0) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_stench"; - - - if (state.mafia_internal_step <= 2) { - if (trash_net.equipped_amount() == 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + trash_net + ".", "red")); - url = trash_net.invSearch(); - } else { - int turns_remaining = clampi(get_property_int("dinseyFilthLevel") / 5, 0, 20); - subentry.entries.listAppend("Adventure in Pirates of the Garbage Barges for " + pluraliseWordy(turns_remaining, "more turn", "more turns") + "."); - } - } else { - subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); - state.image_name = "stench airport kiosk"; - url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[pirates of the garbage barges]).ChecklistEntrySetIDTag("Airport stench fish_trash quest")); -} - -void QStenchAirportNastyBearsGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item black picnic basket"; - state.quest_name = "Nasty, Nasty Bears"; - QuestStateParseMafiaQuestProperty(state, "questEStNastyBears"); - - if (!state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_stench"; - - - int bears_left = 8 - get_property_int("dinseyNastyBearsDefeated"); - if (state.mafia_internal_step < 3 && bears_left > 0) { - subentry.entries.listAppend("Adventure in Uncle Gator's Country Fun-Time Liquid Waste Sluice, defeat " + pluraliseWordy(bears_left, "more nasty bear", "more nasty bears") + "."); - - if (__misc_state["have olfaction equivalent"]) - subentry.modifiers.listAppend("olfact nasty bears?"); - } else { - subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); - state.image_name = "stench airport kiosk"; - url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[Uncle Gator's Country Fun-Time Liquid Waste Sluice]).ChecklistEntrySetIDTag("Airport stench nasty_bears quest")); -} - -void QStenchAirportSocialJusticeIGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item ms. accessory"; - state.quest_name = "Social Justice Adventurer I"; - QuestStateParseMafiaQuestProperty(state, "questEStSocialJusticeI"); - - if (!state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_stench"; - - - int adventures_left = 15 - get_property_int("dinseySocialJusticeIProgress"); - if (state.mafia_internal_step < 2 && adventures_left > 0) { - subentry.entries.listAppend("Adventure in Pirates of the Garbage Barges " + pluraliseWordy(adventures_left, "more time", "more times") + "."); - } else { - subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); - state.image_name = "stench airport kiosk"; - url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[Pirates of the Garbage Barges]).ChecklistEntrySetIDTag("Airport stench social_justice_1 quest")); -} - -void QStenchAirportSocialJusticeIIGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__monster black knight"; - state.quest_name = "Social Justice Adventurer II"; - QuestStateParseMafiaQuestProperty(state, "questEStSocialJusticeII"); - - if (!state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_stench"; - - - if (state.mafia_internal_step < 2) { - int adventures_left = clampi(15 - get_property_int("dinseySocialJusticeIIProgress"), 0, 15); - subentry.entries.listAppend("Adventure in Uncle Gator's Country Fun-Time Liquid Waste Sluice " + pluraliseWordy(adventures_left, "more time", "more times") + "."); - } else { - subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); - state.image_name = "stench airport kiosk"; - url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[Uncle Gator's Country Fun-Time Liquid Waste Sluice]).ChecklistEntrySetIDTag("Airport stench social_justice_2 quest")); -} - -void QStenchAirportSuperLuberGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item lube-shoes"; - state.quest_name = "Super Luber"; - QuestStateParseMafiaQuestProperty(state, "questEStSuperLuber"); - - if (!state.in_progress) - return; - item quest_item = $item[lube-shoes]; - - if (quest_item.available_amount() == 0) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_stench"; - - - if (state.mafia_internal_step <= 2) { - if (quest_item.equipped_amount() == 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + quest_item.name + ".", "red")); - url = quest_item.invSearch(); - } else { - subentry.entries.listAppend("Adventure in Barf Mountain, return to the kiosk after riding the rollercoaster."); - subentry.modifiers.listAppend("optional +meat"); - if ($effect[How to Scam Tourists].have_effect() == 0 && $item[How to Avoid Scams].available_amount() > 0) - subentry.entries.listAppend("Use How to Avoid Scams to farm extra meat, if you want."); - - } - } else { - subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); - state.image_name = "stench airport kiosk"; - url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[barf mountain]).ChecklistEntrySetIDTag("Airport stench super_luber quest")); -} - -void QStenchAirportZippityDooDahGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item tea for one"; - state.quest_name = "Whistling Zippity-Doo-Dah"; - QuestStateParseMafiaQuestProperty(state, "questEStZippityDooDah"); - - if (!state.in_progress) - return; - item quest_item = $item[Dinsey mascot mask]; - - if (quest_item.available_amount() == 0) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_stench"; - - int turns_remaining = clampi(15 - get_property_int("dinseyFunProgress"), 0, 15); - - if (state.mafia_internal_step <= 2) { - if (quest_item.equipped_amount() == 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + quest_item.name + ".", "red")); - url = quest_item.invSearch(); - } else { - subentry.entries.listAppend("Adventure in the Toxic Teacups for " + pluraliseWordy(turns_remaining, "more turn", "more turns") + "."); - } - } else { - subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); - state.image_name = "stench airport kiosk"; - url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[the toxic teacups]).ChecklistEntrySetIDTag("Airport stench zippity quest")); -} - -void QStenchAirportWillWorkForFoodGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item complimentary Dinsey refreshments"; - state.quest_name = "Will Work With Food"; - QuestStateParseMafiaQuestProperty(state, "questEStWorkWithFood"); - - if (!state.in_progress) - return; - - item quest_item = $item[complimentary Dinsey refreshments]; - - if (quest_item.available_amount() == 0) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_stench"; - - int tourists_to_feed = clampi(30 - get_property_int("dinseyTouristsFed"), 0, 30); - if (state.mafia_internal_step == 1) { - subentry.entries.listAppend("Adventure in Barf Mountain, use complimentary Dinsey refreshments on garbage/angry tourists."); - subentry.entries.listAppend(pluraliseWordy(tourists_to_feed, "more remains", "more remain").capitaliseFirstLetter() + "."); - subentry.modifiers.listAppend("olfact angry/garbage tourists"); - - } else { - subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); - state.image_name = "stench airport kiosk"; - url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[barf mountain]).ChecklistEntrySetIDTag("Airport stench refreshments quest")); -} - -void QStenchAirportGiveMeFuelGenerateTasks(ChecklistEntry [int] task_entries) -{ - QuestState state; - state.image_name = "__item toxic globule"; - state.quest_name = "Give me fuel"; - QuestStateParseMafiaQuestProperty(state, "questEStGiveMeFuel"); - - if (!state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = state.quest_name; - string url = "place.php?whichplace=airport_stench"; - - if ($item[toxic globule].available_amount() < 20) { - int globules_needed = clampi(20 - $item[toxic globule].available_amount(), 0, 20); - if (!in_ronin()) { - subentry.entries.listAppend("Buy " + pluralise(globules_needed, "more toxic globule", "more toxic globules") + " in the mall."); - url = "mall.php"; - } else { - subentry.modifiers.listAppend("+unknown"); - subentry.entries.listAppend("Adventure in the Toxic Teacups and collect " + pluralise(globules_needed, "more toxic globule", "more toxic globules") + "."); - } - } else { - if ($item[toxic globule].item_amount() < 20) { - int globules_needed = clampi(20 - $item[toxic globule].item_amount(), 0, 20); - subentry.entries.listAppend("Pull " + pluralise(globules_needed, "more toxic globule", "more toxic globules") + "."); - } else { - subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); - state.image_name = "stench airport kiosk"; - url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; - } - } - - task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[the toxic teacups]).ChecklistEntrySetIDTag("Airport stench fuel quest")); -} - -void QStenchAirportGarbageGenerateTasks(ChecklistEntry [int] task_entries) -{ - if (get_property_boolean("_dinseyGarbageDisposed")) - return; - ChecklistSubentry subentry; - subentry.header = "Turn in garbage"; - subentry.entries.listAppend("Maintenance Tunnels Access" + __html_right_arrow_character + "Waste Disposal."); - if ($item[bag of park garbage].item_amount() == 0) { - if ($item[bag of park garbage].available_amount() > 0) - subentry.entries.listAppend("Have one, somewhere..."); - else { - string line = "Fight barf mountain Garbage tourists"; - if (!in_ronin()) - line += " or buy from mall"; - subentry.entries.listAppend(line + "."); - } - } - task_entries.listAppend(ChecklistEntryMake("__item bag of park garbage", "place.php?whichplace=airport_stench&action=airport3_tunnels", subentry).ChecklistEntrySetIDTag("Airport stench garbage")); -} - -void QStenchAirportWartDinseyGenerateTasks(ChecklistEntry [int] task_entries) -{ - if (get_property_ascension("lastWartDinseyDefeated")) - return; - - item dinsey_item; - if (my_class() == $class[seal clubber]) - dinsey_item = $item[Dinsey's oculus]; - else if (my_class() == $class[turtle tamer]) - dinsey_item = $item[Dinsey's radar dish]; - else if (my_class() == $class[pastamancer]) - dinsey_item = $item[Dinsey's pizza cutter]; - else if (my_class() == $class[sauceror]) - dinsey_item = $item[Dinsey's brain]; - else if (my_class() == $class[disco bandit]) - dinsey_item = $item[Dinsey's pants]; - else if (my_class() == $class[accordion thief]) - dinsey_item = $item[Dinsey's glove]; - if (!($classes[seal clubber,turtle tamer,pastamancer,sauceror,disco bandit,accordion thief] contains my_class())) //class-specific items only drop when you're class-specific - return; - - if (last_monster() != $monster[Wart Dinsey]) { - if (dinsey_item == $item[none] || haveAtLeastXOfItemEverywhere(dinsey_item, 1)) - return; - } - boolean [item] keycards = $items[keycard α,keycard β,keycard γ,keycard δ]; - - item [int] missing_keycards; - foreach it in keycards { - if (it.available_amount() == 0) { - missing_keycards.listAppend(it); - } - } - if (missing_keycards.count() > 0) - return; - - - string url = "place.php?whichplace=airport_stench&action=airport3_tunnels"; - string [int] description; - string [int] modifiers; - modifiers.listAppend("+" + MAX(250, $monster[Wart Dinsey].base_initiative) + "% init"); - modifiers.listAppend("+lots all resistance"); - - item mercenary_pistol = $item[mercenary pistol]; - description.listAppend("Run +resistance, deal many sources of non-stench damage to him. (100 damage cap)"); - if (mercenary_pistol.available_amount() > 0) { - string [int] tasks; - if (mercenary_pistol.equipped_amount() == 0) - tasks.listAppend("equip a mercenary pistol"); - item clip = $item[special clip: boneburners]; - if (clip.item_amount() == 0 && $item[special clip: splatterers].item_amount() > 0) - clip = $item[special clip: splatterers]; - if (clip.item_amount() == 0) { - tasks.listAppend("acquire a few clips of " + clip); - } - tasks.listAppend("throw " + clip + " in combat"); - - description.listAppend(tasks.listJoinComponents(", ").capitaliseFirstLetter() + "."); - } else { - description.listAppend("The mercenary pistol is useful for this, if you can acquire one."); - } - description.listAppend("Will acquire a " + dinsey_item + "."); - - task_entries.listAppend(ChecklistEntryMake("__item " + dinsey_item, url, ChecklistSubentryMake("Defeat Wart Dinsey", modifiers, description)).ChecklistEntrySetIDTag("Airport stench Wart_Dinsey")); -} - -void QStenchAirportGenerateTasks(ChecklistEntry [int] task_entries) -{ - if (!__misc_state["stench airport available"]) - return; - //if (__misc_state["in run"] && !($locations[Pirates of the Garbage Barges,Barf Mountain,The Toxic Teacups,Uncle Gator's Country Fun-Time Liquid Waste Sluice] contains __last_adventure_location)) - //return; - QStenchAirportFishTrashGenerateTasks(task_entries); - QStenchAirportNastyBearsGenerateTasks(task_entries); - QStenchAirportSocialJusticeIGenerateTasks(task_entries); - QStenchAirportSocialJusticeIIGenerateTasks(task_entries); - QStenchAirportSuperLuberGenerateTasks(task_entries); - QStenchAirportZippityDooDahGenerateTasks(task_entries); - QStenchAirportGarbageGenerateTasks(task_entries); - QStenchAirportGiveMeFuelGenerateTasks(task_entries); - QStenchAirportWillWorkForFoodGenerateTasks(task_entries); - QStenchAirportWartDinseyGenerateTasks(task_entries); -} - -// - -void QHotAirportLavaCoLampGenerateTasks(ChecklistEntry [int] task_entries) -{ - if (in_ronin()) - return; - - if (__last_adventure_location != $location[LavaCo™ Lamp Factory]) //dave's not here, man - return; - - item [int] missing_lamps = $items[Red LavaCo Lamp™,Green LavaCo Lamp™,Blue LavaCo Lamp™].items_missing(); - - if (missing_lamps.count() == 0) - return; - - string url = "place.php?whichplace=airport_hot"; - string [int] modifiers; - string [int] description; - - - description.listAppend("+5 adventures/+sleepstatgain offhand, useful in ascension."); - - //One at a time: - - item targeting_lamp = missing_lamps[0]; - string [int] colours_missing; - foreach key, it in missing_lamps - colours_missing.listAppend(it.to_string().replace_string(" LavaCo Lamp™", "")); - - string colour = colours_missing[0]; - - item capped_item = to_item("capped " + colour + " lava bottle"); - item uncapped_item = to_item("uncapped " + colour + " lava bottle"); - item lava_glob_item = to_item(colour + " lava globs"); - - - if (capped_item.available_amount() == 0) { - boolean have_all_items = true; - if ($item[SMOOCH bottlecap].available_amount() == 0) { - have_all_items = false; - string line; - line = "Acquire a SMOOCH bottlecap by eating SMOOCH soda"; - if (availableFullness() == 0) - line += " later"; - line += "."; - - description.listAppend(line); - } - //uncapped red lava bottle - if (uncapped_item.available_amount() == 0) { - have_all_items = false; - string [int] subdescription; - if (lava_glob_item.available_amount() == 0) { - subdescription.listAppend("Acquire " + lava_glob_item + " in LavaCo NC: Use the glob dyer" + __html_right_arrow_character + "Dye them " + colour + "."); - } - if ($item[full lava bottle].available_amount() > 0) { - if (lava_glob_item.available_amount() > 0) { - subdescription.listAppend("Use " + lava_glob_item + "."); - url = lava_glob_item.invSearch(); - } - } else { - if ($item[empty lava bottle].item_amount() > 0) { - subdescription.listAppend("Adventure in the LavaCo™ Lamp Factory, use the squirter."); - } else if ($item[empty lava bottle].available_amount() > 0) { - subdescription.listAppend("Acquire an empty lava bottle. (From hagnk's?)"); - } else { - if ($item[New Age healing crystal].item_amount() > 0) { - subdescription.listAppend("Adventure in the LavaCo™ Lamp Factory, use the klin."); - } else - subdescription.listAppend("Acquire New Age healing crystal from the mall or the mine."); - } - } - - description.listAppend("Acquire an " + uncapped_item + ".|*" + subdescription.listJoinComponents("|*")); - } - if (have_all_items) { //capped_item.creatable_amount() > 0) //BUG: capped_item.creatable_amount() > 0 when only having cap - description.listAppend("Make " + capped_item + " (" + uncapped_item + " + SMOOCH bottlecap)"); - url = "craft.php?mode=combine"; - } - } else if ($item[LavaCo™ Lamp housing].available_amount() > 0) { - description.listAppend("Combine " + capped_item + " and LavaCo™ Lamp housing."); - url = "craft.php?mode=combine"; - } - - if ($item[LavaCo™ Lamp housing].available_amount() == 0) { - boolean have_all_items = true; - if ($item[crystalline light bulb].item_amount() == 0) { - have_all_items = false; - - if ($item[glowing New Age crystal].item_amount() > 0) { - description.listAppend("Adventure in the LavaCo™ Lamp Factory, use the bulber."); - } else { - description.listAppend("Acquire glowing New Age crystal. (mall, or healing crystal golem in the mine))"); - } - } - if ($item[heat-resistant sheet metal].item_amount() == 0) { - have_all_items = false; - description.listAppend("Buy heat-resistant sheet metal from the mall."); - } - if ($item[insulated gold wire].item_amount() == 0) { - have_all_items = false; - - - if ($item[insulated gold wire].available_amount() > 0) { - description.listAppend("Acquire insulated gold wire. (in hagnk's?)"); - } else if ($item[insulated gold wire].creatable_amount() > 0) { - description.listAppend("Make insulated gold wire. (thin gold wire + unsmoothed velvet"); - url = "craft.php?mode=combine"; - } else { - if ($item[thin gold wire].available_amount() == 0) { - if ($item[1\,970 carat gold].item_amount() == 0) { - description.listAppend("Acquire 1,970 carat gold by mining in the mine."); - } else { - description.listAppend("Adventure in the LavaCo™ Lamp Factory, use the wire puller."); - } - } - if ($item[unsmoothed velvet].available_amount() == 0) - description.listAppend("Buy unsmoothed velvet in the mall."); - } - } - - if (have_all_items) { - description.listAppend("At the LavaCo™ NC, use the chassis assembler."); - } - } - - - task_entries.listAppend(ChecklistEntryMake("__item " + missing_lamps[0], url, ChecklistSubentryMake("Make a " + colours_missing.listJoinComponents(", ", "and") + " LavaCo Lamp™", modifiers, description), $locations[LavaCo™ Lamp Factory]).ChecklistEntrySetIDTag("Airport hot lavaco_lamp")); -} - -void QHotAirportSuperduperheatedMetalGenerateTasks(ChecklistEntry [int] task_entries) -{ - int metal_sheets = lookupItem("Heat-resistant sheet metal").item_amount(); - string image; - string header; - string [int] description; - - if (!get_property_boolean("_volcanoSuperduperheatedMetal") && (__last_adventure_location == $location[The Bubblin\' Caldera] || !__misc_state["in run"])) { - image = "__item superduperheated metal"; - header = "Get superduperheated metal"; - if (metal_sheets > 0) - description.listAppend("Adventure in the Bubblin' Caldera. ~1/20 chance of superduperheated metal."); - else - description.listAppend("Get some (scraps of) heat-resistant sheet metal in your inventory."); - } else if (__last_adventure_location == $location[The Bubblin\' Caldera] && metal_sheets > 0) { - image = "__item superheated metal"; - header = "Don't waste more Heat-resistant sheet metal"; - description.listAppend("Already got Superduperheated metal today. Closet your Heat-resistant sheet metal (unless you want Superheated metal for the SMOOCH uniform)."); - } - - if (description.count() > 0) - task_entries.listAppend(ChecklistEntryMake(image, "place.php?whichplace=airport_hot", ChecklistSubentryMake(header, "", description), $locations[The Bubblin\' Caldera]).ChecklistEntrySetIDTag("Airport hot superduperheated")); -} - -void QHotAirportWLFBunkerGenerateTasks(ChecklistEntry [int] task_entries) -{ - if (get_property_boolean("_volcanoItemRedeemed")) - return; - - /* - _volcanoItem1, _volcanoItem2, _volcanoItem3 - _volcanoItemCount1, _volcanoItemCount2, _volcanoItemCount3 - */ - int [int] volcano_item_id; - int [int] volcano_item_count; - for i from 1 to 3 { - volcano_item_id [i] = get_property_int("_volcanoItem" + i); // volcano_item_id [1st / 2nd / 3rd] => item ID - volcano_item_count [volcano_item_id [i]] = get_property_int("_volcanoItemCount" + i); // volcano_item_count [item ID] => amount asked - } - string url = "place.php?whichplace=airport_hot"; - string subtitle; - string [int] description; - boolean [location] relevant_locations; - - if (volcano_item_id [1] == 0 && volcano_item_id [2] == 0 && volcano_item_id [3] == 0) { - url = "place.php?whichplace=airport_hot&action=airport4_questhub"; - description.listAppend("Visit the W.L.F. bunker to learn today's accepted items."); - } else { - boolean [item] volcano_item; // rearranged in a format that is compatible with "contains" (also going from ID to $item) - foreach i in volcano_item_id { - if (volcano_item_id [i] == 0) { - description.listAppend("Mafia's parsing of item " + i + " went wrong."); - remove volcano_item_id [i]; - } else - volcano_item [lookupItem(volcano_item_id [i])] = true; - } - - /* - The Bubblin' Caldera - 8517 => SMOOCH bracers - 8522 => superduperheated metal - 8504 => Lavalos core - 8496 => The One Mood Ring - The Velvet / Gold Mine - 8516 => smooth velvet bra - 8425 => New Age healing crystal - 8505 => half-melted hula girl - 8497 => Mr. Choch's bone - LavaCo™ Lamp Factory - 8470 => gooey lava globs - 8523 => fused fuse - 8498 => Mr. Cheeng's 'stache - 8506 => glass ceiling fragments - The SMOOCH Army HQ - 8446 => SMOOCH bottlecap - 8500 => the tongue of Smimmons - 8501 => Raul's guitar pick - 8502 => Pener's crisps - 8503 => signed deuce - Discotheque - 8499 => Saturday Night thermometer*/ - - void WLFBunkerTasks(string [int] map, item it, int amount_normally_asked, string acquisition_text) { - if (!(volcano_item contains it)) - return; - - boolean this_isnt_right = volcano_item_count [it.to_int()] != amount_normally_asked; - - string text; - if (volcano_item_count [it.to_int()] > 1) //"5 (wait that's not right...) the tongues of Smimmons", "3 smooth velvet bras" - text += volcano_item_count [it.to_int()] + (this_isnt_right ? " (wait, that's not right...) " : " ") + it.plural; - else //"Raul's guitar pick", "New Age healing crystal x1 (wait that's not right...)" - text += it.name.capitaliseFirstLetter() + (this_isnt_right ? " x1 (wait, that's not right...)" : ""); - - text += " (have " + it.item_amount() + ")."; - text += "|*" + acquisition_text; - map.listAppend(text); - - remove volcano_item [it]; - } - - string GenerateCommonZoneSpecificNCText(location l) { - return HTMLGenerateSpanOfClass("Win", "r_bold") + " 50 fights in " + l + " on the " + HTMLGenerateSpanOfClass("same day", "r_bold") + " to get the zone's 1/day NC."; - } - - if (true) { - string [int] caldera; - string nc_text = GenerateCommonZoneSpecificNCText($location[The Bubblin' Caldera]); - - caldera.WLFBunkerTasks($item[SMOOCH bracers], 3, "Multi-use 5 ingots of superheated metal (from adventuring in the caldera with heat-resistant sheet metal (from SMOOCH or mall) in inventory, or buy from mall) (each)."); - caldera.WLFBunkerTasks($item[superduperheated metal], 1, get_property_boolean("_volcanoSuperduperheatedMetal") ? "Buy from mall." : "Look at the tile above this one (or buy from mall)."); - caldera.WLFBunkerTasks($item[Lavalos core], 1, nc_text + " Head for the roaring (fight)."); - caldera.WLFBunkerTasks($item[The One Mood Ring], 1, nc_text + " Head for the singing."); - - if (caldera.count() > 0) { - relevant_locations [$location[The Bubblin' Caldera]] = true; - description.listAppend("In " + $location[The Bubblin' Caldera] + ":" + caldera.listJoinComponents("|").HTMLGenerateIndentedText()); - } - } - if (true) { - string [int] VGmine; - string nc_text = GenerateCommonZoneSpecificNCText($location[The Velvet / Gold Mine]); - - VGmine.WLFBunkerTasks($item[smooth velvet bra], 3, "Multi-use 3 pieces of unsmooth velvet (from mining) (each) (or buy from mall)."); - VGmine.WLFBunkerTasks($item[New Age healing crystal], 5, "Fight healing crystal golems or mine (or buy from mall)."); - VGmine.WLFBunkerTasks($item[half-melted hula girl], 1, nc_text + " Check out HR."); - VGmine.WLFBunkerTasks($item[Mr. Choch's bone], 1, nc_text + " Head to the boss's shack (fight)."); - - if (VGmine.count() > 0) { - relevant_locations [$location[The Velvet / Gold Mine]] = true; - description.listAppend("In " + $location[The Velvet / Gold Mine] + ":" + VGmine.listJoinComponents("|").HTMLGenerateIndentedText()); - } - } - if (true) { - string [int] lavaco; - string nc_text = GenerateCommonZoneSpecificNCText($location[LavaCo™ Lamp Factory]); - - lavaco.WLFBunkerTasks($item[gooey lava globs], 5, "Fight lava golems (or buy from mall)."); - lavaco.WLFBunkerTasks($item[fused fuse], 1, "Sabotage the machine at the NC that happens every 10 turns."); - lavaco.WLFBunkerTasks($item[Mr. Cheeng's 'stache], 1, nc_text + " Go into the boss's office (fight)."); - lavaco.WLFBunkerTasks($item[glass ceiling fragments], 1, nc_text + " Go up the stairs."); - - if (lavaco.count() > 0) { - relevant_locations [$location[LavaCo™ Lamp Factory]] = true; - description.listAppend("In " + $location[LavaCo™ Lamp Factory] + ":" + lavaco.listJoinComponents("|").HTMLGenerateIndentedText()); - } - } - if (true) { - string [int] SMOOCH; - string nc_text = GenerateCommonZoneSpecificNCText($location[The SMOOCH Army HQ]) + " Open door #"; - - SMOOCH.WLFBunkerTasks($item[SMOOCH bottlecap], 1, 'Eat ("drink") a SMOOCH soda (or buy from mall).'); - SMOOCH.WLFBunkerTasks($item[the tongue of Smimmons], 1, nc_text + "1."); - SMOOCH.WLFBunkerTasks($item[Raul's guitar pick], 1, nc_text + "2."); - SMOOCH.WLFBunkerTasks($item[Pener's crisps], 1, nc_text + "3."); - SMOOCH.WLFBunkerTasks($item[signed deuce], 1, nc_text + "4."); - - if (SMOOCH.count() > 0) { - relevant_locations [$location[The SMOOCH Army HQ]] = true; - description.listAppend("In " + $location[The SMOOCH Army HQ] + ":" + SMOOCH.listJoinComponents("|").HTMLGenerateIndentedText()); - } - } - description.WLFBunkerTasks($item[Saturday Night thermometer], 1, get_property_boolean("_infernoDiscoVisited") ? "Elevator's already been used today :(" : "Rock a disco style of 3, go to the discotheque's elevator, go to the third floor."); - - if (volcano_item.count() > 0) - description.listAppend(pluralise(volcano_item.count(), "of the items was", "of the items were") + " unregistered."); - if (volcano_item_id.count() - volcano_item.count() > 1) //if - > 1... - subtitle = "One of:"; - } - - task_entries.listAppend(ChecklistEntryMake("__item volcoino", url, ChecklistSubentryMake("Help smash the system!", subtitle, description), relevant_locations).ChecklistEntrySetIDTag("Airport hot WLF quest")); -} - -void QHotAirportGenerateTasks(ChecklistEntry [int] task_entries) -{ - if (!__misc_state["hot airport available"]) - return; - - QHotAirportLavaCoLampGenerateTasks(task_entries); - QHotAirportSuperduperheatedMetalGenerateTasks(task_entries); - QHotAirportWLFBunkerGenerateTasks(task_entries); - - if ($item[lucky gold ring].available_amount() > 0 && !get_property_boolean("_luckyGoldRingVolcoino")) { - string url; - string title = "Adventure with "; - if ($item[lucky gold ring].equipped_amount() == 0) { - title = "Equip "; - url = $item[lucky gold ring].invSearch(); - } - task_entries.listAppend(ChecklistEntryMake("__item lucky gold ring", url, ChecklistSubentryMake(title + " your Lucky Gold Ring", "~1% volcoino/combat", "Can give 1 volcoino per day.")).ChecklistEntrySetIDTag("Airport hot lucky_gold_ring")); - } -} - -void QHotAirportGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["hot airport available"]) - return; - //Elevator: - if (!get_property_boolean("_infernoDiscoVisited")) { - int potential_disco_style_level = 0; - int current_disco_style_level = 0; - item [int] items_to_equip_for_additional_style; - foreach it in $items[smooth velvet pocket square,smooth velvet socks,smooth velvet hat,smooth velvet shirt,smooth velvet hanky,smooth velvet pants] { - if (it.equipped_amount() > 0) - current_disco_style_level += 1; - else if (it.available_amount() > 0) - potential_disco_style_level += 1; - } - potential_disco_style_level += current_disco_style_level; - - string [int] description; - string url = "place.php?whichplace=airport_hot&action=airport4_zone1"; - if (current_disco_style_level == 0) - url = "inventory.php?ftext=smooth+velvet"; - /* - Requires... disco style? (velvet gear) - Floor 1: Gain 100 points in each stat! - Floor 2: Get a temporary boost to Item Drops! - Floor 3: Fight Travoltron! - Floor 4: Reduce your Drunkenness by 1 - Floor 5: Go backwards in time by 5 Adventures! - Floor 6: Get a Volcoino! - */ - Record DiscoFloor - { - int floor_number; - string description; - boolean grey_out; - }; - DiscoFloor DiscoFloorMake(int floor_number, string description, boolean grey_out) - { - DiscoFloor floor; - floor.floor_number = floor_number; - floor.description = description; - floor.grey_out = grey_out; - return floor; - } - DiscoFloor DiscoFloorMake(int floor_number, string description) - { - return DiscoFloorMake(floor_number, description, false); - } - void listAppend(DiscoFloor [int] list, DiscoFloor entry) - { - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; - } - - DiscoFloor [int] floors; - if (__misc_state["need to level"]) - floors.listAppend(DiscoFloorMake(1, "+100 all substats.")); - - floors.listAppend(DiscoFloorMake(2, "+100% item for 20 turns.")); - floors.listAppend(DiscoFloorMake(3, "Fight Travoltron.")); - if (inebriety_limit() > 0) { - if (my_inebriety() == 0) - floors.listAppend(DiscoFloorMake(4, "-1 drunkenness. (drink first)", true)); - else - floors.listAppend(DiscoFloorMake(4, "-1 drunkenness.")); - } - if (my_path().id != PATH_SLOW_AND_STEADY) - floors.listAppend(DiscoFloorMake(5, "+5 adventures, extend effects.")); - floors.listAppend(DiscoFloorMake(6, "Gain a volcoino.")); - - foreach key, floor in floors { - if (floor.floor_number > potential_disco_style_level) - continue; - - string line = "Floor " + floor.floor_number + ": " + floor.description; - if (floor.floor_number > current_disco_style_level || floor.grey_out) { - if (floor.floor_number > current_disco_style_level) - line += " (wear smooth velvet)"; - line = HTMLGenerateSpanFont(line, "grey"); - } - description.listAppend(line); - } - - if (items_to_equip_for_additional_style.count() > 0 && potential_disco_style_level > current_disco_style_level) - description.listAppend("Can equip " + items_to_equip_for_additional_style.listJoinComponents(", ", "and") + " for more style."); - - //fancy tophat, insane tophat, brown felt tophat, isotophat, tiny top hat and cane - if (potential_disco_style_level > 0) - resource_entries.listAppend(ChecklistEntryMake("__item disco ball", url, ChecklistSubentryMake("One elevator ride", "", description), 5).ChecklistEntrySetIDTag("Airport hot disco_elevator resource")); - } -} - -void QColdAirportGenerateTasks(ChecklistEntry [int] task_entries) -{ - if (!__misc_state["cold airport available"]) - return; - string desired_walford_item = get_property("walfordBucketItem").to_lower_case(); - if ($item[Walford's bucket].available_amount() > 0 && QuestState("questECoBucket").in_progress && desired_walford_item != "") { //need quest tracking as well, you keep the bucket. FIXME should we be testing against desired_walford_item? - string title = ""; - string [int] modifiers; - string [int] description; - string url = $location[The Ice Hotel].getClickableURLForLocation(); - int progress = get_property_int("walfordBucketProgress"); - if (progress >= 100) { - url = "place.php?whichplace=airport_cold&action=glac_walrus"; - title = "Talk to Walford"; - description.listAppend("Turn in the quest."); - } else { - title = "Walford's quest"; - - modifiers.listAppend("-combat"); - string [int] options; - - options.listAppend("The Ice Hole" + ($effect[fishy].have_effect() == 0 ? " with fishy" : "") + ". (5% per turn)"); - - string [int] tasks; - string hotel_string = "The Ice Hotel."; - boolean nc_helps_in_hotel = true; - if (desired_walford_item == "milk" || desired_walford_item == "rain") - nc_helps_in_hotel = false; - if (nc_helps_in_hotel) { - if ($item[bellhop's hat].equipped_amount() == 0 && desired_walford_item != "moonbeams") - tasks.listAppend("equip bellhop's hat"); - tasks.listAppend("run -combat"); - } - if (desired_walford_item == "moonbeams" && $slot[hat].equipped_item() != $item[none]) { - tasks.listAppend("unequip your hat"); - } - if (desired_walford_item == "blood") - tasks.listAppend("use tin snips every fight"); - if (desired_walford_item == "chicken" && numeric_modifier("food drop") < 50.0) { - modifiers.listAppend("+50% food drop"); - tasks.listAppend("run +50% food drop"); - } - if (desired_walford_item == "milk" && numeric_modifier("booze drop") < 50.0) { - modifiers.listAppend("+50% booze drop"); - tasks.listAppend("run +50% booze drop"); - } - if (desired_walford_item == "rain") - tasks.listAppend("cast hot spells"); - //FIXME verify all (ice?) - - if (!get_property_boolean("_iceHotelRoomsRaided")) - tasks.listAppend("collect once/day certificates"); - if (tasks.count() > 0) - hotel_string += " " + tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; - - options.listAppend(hotel_string); - - tasks.listClear(); - string vkyea_string = "VYKEA."; - boolean nc_helps_in_vykea = true; - if (desired_walford_item == "blood") - nc_helps_in_vykea = false; - if (nc_helps_in_vykea) { - tasks.listAppend("run -combat"); - } - if (desired_walford_item == "moonbeams" && $slot[hat].equipped_item() != $item[none]) { - tasks.listAppend("unequip your hat"); - } - if (desired_walford_item == "blood") - tasks.listAppend("use tin snips every fight"); - if (desired_walford_item == "bolts" && $item[VYKEA hex key].equipped_amount() == 0) - tasks.listAppend("equip VYKEA hex key"); - if (desired_walford_item == "chum" && meat_drop_modifier() < 250.0) { - modifiers.listAppend("+250% meat"); - tasks.listAppend("run +250% meat"); - } - if (desired_walford_item == "balls" && item_drop_modifier() < 50) { - modifiers.listAppend("+50% item"); - tasks.listAppend("run +50% item"); - } - if (!get_property_boolean("_VYKEALoungeRaided")) - tasks.listAppend("collect once/day certificates"); - - if (tasks.count() > 0) - vkyea_string += " " + tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; - - options.listAppend(vkyea_string); - - tasks.listClear(); - if ($item[Walford's bucket].equipped_amount() == 0) { - url = "inventory.php?ftext=walford's+bucket"; - tasks.listAppend("equip walford's bucket"); - } - tasks.listAppend("adventure on the glacier"); - description.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + ":|*" + options.listJoinComponents("
|*")); - - - description.listAppend(progress + "% done collecting " + desired_walford_item + "."); - } - task_entries.listAppend(ChecklistEntryMake("__item Walford's bucket", url, ChecklistSubentryMake(title, modifiers, description), $locations[The Ice Hotel,VYKEA,The Ice Hole]).ChecklistEntrySetIDTag("Airport cold walford quest")); - } -} - -void QAirportGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - ChecklistEntry [int] chosen_entries = optional_task_entries; - if (__misc_state["in run"]) - chosen_entries = future_task_entries; - - QSleazeAirportGenerateTasks(chosen_entries); - QSpookyAirportGenerateTasks(chosen_entries); - QStenchAirportGenerateTasks(chosen_entries); - QHotAirportGenerateTasks(chosen_entries); - QColdAirportGenerateTasks(chosen_entries); -} - -void QAirportGenerateResource(ChecklistEntry [int] resource_entries) -{ - QHotAirportGenerateResource(resource_entries); -} diff --git a/Source/relay/TourGuide/Quests/Artist.ash b/Source/relay/TourGuide/Quests/Artist.ash deleted file mode 100644 index 6f731e69..00000000 --- a/Source/relay/TourGuide/Quests/Artist.ash +++ /dev/null @@ -1,80 +0,0 @@ - -void QArtistInit() -{ - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questM02Artist"); - - if (!state.started && $items[pail of pretentious paint, pretentious paintbrush, pretentious palette].available_amount() > 0) - QuestStateParseMafiaQuestPropertyValue(state, "started"); - - if (my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_GREY_GOO) //cannot be done - QuestStateParseMafiaQuestPropertyValue(state, "unstarted"); - - state.quest_name = "Pretentious Artist's Quest"; - state.image_name = "__item pretentious palette"; - - state.startable = true; - - __quest_state["Artist"] = state; -} - - -void QArtistGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Artist"]; - if (!base_quest_state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - string active_url = ""; - - boolean output_modifiers = false; - if ($item[pretentious palette].available_amount() == 0) - { - //haunted pantry - if (active_url == "") - active_url = $location[the haunted pantry].getClickableURLForLocation(); - subentry.entries.listAppend("Adventure in the haunted pantry for palette. (25% superlikely)"); - output_modifiers = true; - } - if ($item[pretentious paintbrush].available_amount() == 0) - { - //cobb's knob - if (active_url == "") - active_url = $location[the outskirts of Cobb's Knob].getClickableURLForLocation(); - subentry.entries.listAppend("Adventure in the outskirts of Cobb's Knob for paintbrush. (25% superlikely)"); - output_modifiers = true; - } - if ($item[pail of pretentious paint].available_amount() == 0) - { - //sleazy back alley - if (active_url == "") - active_url = $location[the sleazy back alley].getClickableURLForLocation(); - subentry.entries.listAppend("Adventure in the sleazy back alley for pail of paint. (25% superlikely)"); - output_modifiers = true; - } - - if (output_modifiers) - { - if (__misc_state["free runs available"]) - { - subentry.modifiers.listAppend("free runs"); - } - if (__misc_state["have hipster"]) - { - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - } - } - - if ($item[pretentious palette].available_amount() > 0 && $item[pretentious paintbrush].available_amount() > 0 && $item[pail of pretentious paint].available_amount() > 0) - { - subentry.entries.listAppend("Talk to the pretentious artist."); - active_url = "place.php?whichplace=town_wrong"; - } - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[the sleazy back alley, the outskirts of cobb's knob, the haunted pantry]).ChecklistEntrySetIDTag("Pretentious artist quest")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Azazel.ash b/Source/relay/TourGuide/Quests/Azazel.ash deleted file mode 100644 index 57b033c6..00000000 --- a/Source/relay/TourGuide/Quests/Azazel.ash +++ /dev/null @@ -1,255 +0,0 @@ - -void QAzazelInit() -{ - //questG04Azazel - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questM10Azazel"); - - state.quest_name = "Azazel Quest"; - state.image_name = "steel margarita"; - - if (my_basestat(my_primestat()) >= 12 && __quest_state["Level 6"].finished) - state.startable = true; - - __quest_state["Azazel"] = state; -} - -record AzazelBandMember -{ - string name; - item [int] desired_items; -}; - -AzazelBandMember AzazelBandMemberMake(string name, item [int] desired_items) -{ - AzazelBandMember result; - result.name = name; - result.desired_items = desired_items; - return result; -} - -AzazelBandMember AzazelBandMemberMake(string name, item it1, item it2) -{ - return AzazelBandMemberMake(name, listMake(it1, it2)); -} - -void listAppend(AzazelBandMember [int] list, AzazelBandMember entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void QAzazelGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Azazel"]; - - foreach consumable in $items[steel lasagna,steel margarita,steel-scented air freshener] - { - if (consumable.available_amount() == 0) - continue; - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - string line = "Consume " + consumable; - if ((consumable == $item[steel lasagna] && availableFullness() < 5) || (consumable == $item[steel-scented air freshener] && availableSpleen() < 5)) - line += " once you have enough space"; - line += "."; - subentry.entries.listAppend(line); - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, "", subentry).ChecklistEntrySetIDTag("Azazel steel organ consume")); - return; - } - - if (base_quest_state.finished) - return; - - - if ($skill[Stomach of Steel].skill_is_usable() || $skill[Liver of Steel].skill_is_usable() || $skill[Spleen of Steel].skill_is_usable()) - return; - - if (!__quest_state["Level 6"].finished) - return; - - //We don't suggest or give advice on this quest in-run unless the player spends an adventure in one of the zones. - //If that happens, they're probably sure they want the consumable items. - if (!__misc_state["in aftercore"] && $locations[The Laugh Floor, Infernal Rackets Backstage].turnsAttemptedInLocation() == 0 && $items[Azazel's unicorn,Azazel's lollipop,Azazel's tutu].available_amount() == 0 && !in_bad_moon()) - return; - - - ChecklistEntry entry; - entry.url = "pandamonium.php"; - entry.image_lookup_name = base_quest_state.image_name; - entry.tags.id = "Azazel steel organ quest"; - entry.should_indent_after_first_subentry = true; - entry.should_highlight = $locations[the laugh floor, infernal rackets backstage] contains __last_adventure_location; - - if (true) - { - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - subentry.entries.listAppend("Gives +5 consumable space."); - - if ($item[Azazel's unicorn].available_amount() > 0 && $item[Azazel's lollipop].available_amount() > 0 && $item[Azazel's tutu].available_amount() > 0) - { - subentry.entries.listAppend("Speak to Azazel."); - } - entry.subentries.listAppend(subentry); - } - - boolean need_imp_airs = false; - boolean need_bus_passes = false; - if ($item[Azazel's tutu].available_amount() == 0) - { - //collect 5 cans of imp air and 5 bus passes - ChecklistSubentry subentry; - - subentry.header = "Azazel's tutu"; - - int imp_air_needed = MAX(0, 5 - $item[imp air].available_amount()); - int bus_passes_needed = MAX(0, 5 - $item[bus pass].available_amount()); - if (imp_air_needed == 0 && bus_passes_needed == 0) - { - if ($item[imp air].item_amount() < 5) - subentry.entries.listAppend("Pull imp air."); - if ($item[bus pass].item_amount() < 5) - subentry.entries.listAppend("Pull bus passes."); - subentry.entries.listAppend("Speak to the stranger."); - } - else - { - if (imp_air_needed > 0) - { - string line; - line = "Need " + pluralise(imp_air_needed, $item[imp air]) + ", from the laugh floor."; - if (!in_ronin()) - line += " Or the mall."; - subentry.entries.listAppend(line); - need_imp_airs = true; - } - if (bus_passes_needed > 0) - { - string line; - line = "Need " + pluralise(bus_passes_needed, $item[bus pass]) + ", from backstage."; - if (!in_ronin()) - line += " Or the mall."; - subentry.entries.listAppend(line); - need_bus_passes = true; - } - } - entry.subentries.listAppend(subentry); - } - - - if ($item[Azazel's unicorn].available_amount() == 0) - { - ChecklistSubentry subentry; - - subentry.header = "Azazel's unicorn"; - - int [item] band_items_available; - int band_items_found = 0; - foreach it in $items[comfy pillow,giant marshmallow,booze-soaked cherry,sponge cake,beer-scented teddy bear,gin-soaked blotter paper] - { - if (it.available_amount() > 0) - band_items_found += 1; - band_items_available[it] = it.available_amount(); - } - - //Try to solve the puzzle: - //Hmm... FIXME is there any way to determine which ones we've given to band members? - - AzazelBandMember [int] band_members; - band_members.listAppend(AzazelBandMemberMake("Bognort", $item[giant marshmallow], $item[gin-soaked blotter paper])); - band_members.listAppend(AzazelBandMemberMake("Stinkface", $item[beer-scented teddy bear], $item[gin-soaked blotter paper])); - band_members.listAppend(AzazelBandMemberMake("Flargwurm", $item[booze-soaked cherry], $item[sponge cake])); - band_members.listAppend(AzazelBandMemberMake("Jim", $item[sponge cake], $item[comfy pillow])); - - string [int] quest_completion_instructions; - boolean can_complete_quest = true; - foreach key in band_members - { - AzazelBandMember musician = band_members[key]; - boolean found_item = false; - foreach key2 in musician.desired_items - { - item it = musician.desired_items[key2]; - if (band_items_available[it] > 0) - { - quest_completion_instructions.listAppend("Give " + musician.name + " a " + it + "."); - band_items_available[it] -= 1; - found_item = true; - break; - } - } - if (!found_item) - can_complete_quest = false; - } - - if (can_complete_quest) - { - if (need_bus_passes) - subentry.entries.listAppend("Run +item backstage."); - subentry.entries.listAppend("Talk to Sven.|*" + quest_completion_instructions.listJoinComponents("|*")); - } - else - { - string and_item = ""; - if (need_bus_passes) - and_item = " and +item"; - subentry.entries.listAppend("Run -combat" + and_item + " backstage."); - subentry.entries.listAppend("Need band components."); - subentry.modifiers.listAppend("-combat"); - } - if (need_bus_passes) - { - subentry.modifiers.listAppend("+item"); - subentry.modifiers.listAppend("olfact serialbus"); - } - - entry.subentries.listAppend(subentry); - } - if ($item[Azazel's lollipop].available_amount() == 0) - { - //comedy club - fight on! - ChecklistSubentry subentry; - - subentry.header = "Azazel's lollipop"; - - - if ($item[observational glasses].available_amount() > 0) - { - //talk to mourn - string line = "Talk to Mourn."; - if ($item[observational glasses].equipped_amount() == 0) - line = "Equip the observational glasses, talk to mourn."; - subentry.entries.listAppend(line); - } - else - { - subentry.modifiers.listAppend("+combat"); - string and_item = ""; - if (need_imp_airs) - and_item = " and +item"; - subentry.entries.listAppend("Run +combat" + and_item + " on the laugh floor, find Larry."); - } - - if (need_imp_airs) - { - subentry.modifiers.listAppend("+item"); - subentry.modifiers.listAppend("olfact ch imp"); - } - entry.subentries.listAppend(subentry); - } - - if ((my_path().id == PATH_TEETOTALER || my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_OF_THE_PLUMBER) && availableFullness() < 5) - entry.subentries.listAppend(ChecklistSubentryMake(HTMLGenerateSpanFont("Won't work, need five fullness to eat lasagna.", "red"), "", "")); - - if (my_path().id == PATH_OXYGENARIAN && availableSpleen() < 5) - entry.subentries.listAppend(ChecklistSubentryMake(HTMLGenerateSpanFont("Won't work, need five spleen to consume steel-scented air freshener.", "red"), "", "")); - - optional_task_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Quests/Felonia.ash b/Source/relay/TourGuide/Quests/Felonia.ash deleted file mode 100644 index 99ff4e5d..00000000 --- a/Source/relay/TourGuide/Quests/Felonia.ash +++ /dev/null @@ -1,171 +0,0 @@ - -void QFeloniaInit() -{ - //questM03Bugbear - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questM03Bugbear"); - - state.quest_name = "Felonia"; - state.image_name = "__item knoll mushroom"; - - state.startable = knoll_available(); - - __quest_state["Felonia"] = state; -} - - -void QFeloniaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Felonia"]; - if (!base_quest_state.in_progress) - return; - if (!knoll_available()) - return; - if (__misc_state["familiars temporarily blocked"]) //cannot complete - return; - if (__misc_state["in run"] && $location[the bugbear pen].turnsAttemptedInLocation() == 0) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - string url = "place.php?whichplace=knoll_friendly"; - - if (get_property("lastEncounter") == "Felonia, Queen of the Spooky Gravy Fairies") - { - subentry.header = "Speak to Mayor Zapruder"; - } - else if (base_quest_state.mafia_internal_step == 1) - { - //Acquire annoying pitchfork: - subentry.header = "Tame the Bugbears"; - if ($item[annoying pitchfork].available_amount() == 0) - { - if (!in_ronin()) - { - subentry.entries.listAppend("Acquire annoying pitchfork in the mall."); - url = "mall.php"; - } - else - { - subentry.entries.listAppend("Acquire annoying pitchfork from an annoying spooky gravy fairy in the Bugbear Pens."); - } - } - else - subentry.entries.listAppend("Speak to Mayor Zapruder to give him the annoying pitchfork."); - } - else if (base_quest_state.mafia_internal_step == 2) - { - //Acquire the right mushroom: - subentry.header = "Summon a Mushroom Familiar"; - - if ($item[frozen mushroom].available_amount() > 0 && $item[stinky mushroom].available_amount() > 0 && $item[flaming mushroom].available_amount() > 0) - { - subentry.entries.listAppend("Speak to Mayor Zapruder to give him mushrooms."); - } - else - { - subentry.entries.listAppend("Grow the mushroom Mayor Zapruder wants."); - url = "knoll_mushrooms.php"; - } - } - else if (base_quest_state.mafia_internal_step == 3) - { - //defeat felonia: - subentry.header = "Defeat Felonia"; - - boolean currently_using_a_relevant_familiar = false; - familiar fairy_to_use = $familiar[none]; - foreach f in $familiars[Flaming Gravy Fairy,Frozen Gravy Fairy,Stinky Gravy Fairy,Sleazy Gravy Fairy,spooky gravy fairy] - { - if (f.have_familiar()) - fairy_to_use = f; - if (my_familiar() == f) - currently_using_a_relevant_familiar = true; - } - if ($familiar[spooky gravy fairy].have_familiar()) - fairy_to_use = $familiar[spooky gravy fairy]; - - if (fairy_to_use == $familiar[none]) - { - item [int] fairies_can_grow; - foreach it in $items[pregnant flaming mushroom,pregnant frozen mushroom,pregnant stinky mushroom,pregnant oily golden mushroom,pregnant gloomy black mushroom] - { - fairies_can_grow.listAppend(it); - } - if (fairies_can_grow.count() == 0) - { - subentry.entries.listAppend("Um... try to find a gravy fairy somehow."); - } - else - { - subentry.entries.listAppend("Grow one of " + fairies_can_grow.listJoinComponents(", ", "or") + "."); - } - } - else if (!currently_using_a_relevant_familiar) - { - subentry.entries.listAppend("Bring along a " + fairy_to_use + "."); - url = "familiar.php"; - } - else - { - boolean need_minus_combat = false; - if ($item[inexplicably glowing rock].available_amount() > 0 && $item[spooky glove].available_amount() > 0) - { - string [int] tasks; - if ($item[spooky glove].equipped_amount() == 0) - { - tasks.listAppend("equip the spooky glove"); - url = "inventory.php?ftext=spooky+glove"; - } - tasks.listAppend("defeat Felonia"); - - subentry.entries.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + " in the Spooky Gravy Burrow."); - need_minus_combat = true; - } - else - { - item [int] items_needed; - if ($item[inexplicably glowing rock].available_amount() == 0) - { - items_needed.listAppend($item[inexplicably glowing rock]); - need_minus_combat = true; - } - - if ($item[spooky glove].available_amount() == 0) - { - if ($item[spooky fairy gravy].available_amount() > 0 && $item[small leather glove].available_amount() > 0) - { - url = "craft.php?mode=cook"; - subentry.entries.listAppend("Make and wear a spooky glove. (cook spooky fairy gravy + small leather glove)"); - } - else - { - if ($item[spooky fairy gravy].available_amount() == 0) - { - items_needed.listAppend($item[spooky fairy gravy]); - need_minus_combat = true; - } - if ($item[small leather glove].available_amount() == 0) - { - subentry.modifiers.listAppend("+900% item"); - items_needed.listAppend($item[small leather glove]); - subentry.entries.listAppend("Or buy small leather glove in the mall."); - } - } - } - if (items_needed.count() > 0) - { - subentry.entries.listPrepend("Adventure in the Spooky Gravy Burrow for " + items_needed.listJoinComponents(", ", "and") + "."); - } - } - - if (need_minus_combat) - subentry.modifiers.listPrepend("-combat?"); - } - } - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the bugbear pen,the spooky gravy burrow]).ChecklistEntrySetIDTag("Felonia knoll quest")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Guild.ash b/Source/relay/TourGuide/Quests/Guild.ash deleted file mode 100644 index 202f9b3e..00000000 --- a/Source/relay/TourGuide/Quests/Guild.ash +++ /dev/null @@ -1,138 +0,0 @@ - -void QGuildInit() -{ - if (!($classes[seal clubber,turtle tamer,pastamancer,sauceror,disco bandit,accordion thief] contains my_class())) - return; - if (my_path().id == PATH_POCKET_FAMILIARS) - return; - //questM02Artist - QuestState state; - - if ($classes[seal clubber,turtle tamer] contains my_class()) - QuestStateParseMafiaQuestProperty(state, "questG09Muscle"); - if ($classes[pastamancer,sauceror] contains my_class()) - QuestStateParseMafiaQuestProperty(state, "questG07Myst"); - if ($classes[disco bandit,accordion thief] contains my_class()) - QuestStateParseMafiaQuestProperty(state, "questG08Moxie"); - if (guild_store_available()) - QuestStateParseMafiaQuestPropertyValue(state, "finished"); - - - - //state.quest_name = "Guilded Youth"; - state.quest_name = "Join your guild"; - if (my_class() == $class[seal clubber]) - state.image_name = "__item seal-clubbing club"; - else if (my_class() == $class[turtle tamer]) - state.image_name = "__item helmet turtle"; - else if (my_class() == $class[pastamancer]) - state.image_name = "__item pasta spoon"; - else if (my_class() == $class[sauceror]) - state.image_name = "__item saucepan"; - else if (my_class() == $class[disco bandit]) - state.image_name = "__item disco mask"; - else if (my_class() == $class[accordion thief]) - state.image_name = "__item stolen accordion"; - - if (state.mafia_internal_step < 2 && ($item[11-inch knob sausage].available_amount() > 0 || $item[exorcised sandwich].available_amount() > 0 && $location[the sleazy back alley].noncombat_queue.contains_text("Now's Your Pants!"))) - { - QuestStateParseMafiaQuestPropertyValue(state, "step1"); - } - - state.startable = !(my_path().id == PATH_GREY_GOO && $classes[seal clubber,turtle tamer] contains my_class()); - - __quest_state["Guild"] = state; -} - - -void QGuildGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!($classes[seal clubber,turtle tamer,pastamancer,sauceror,disco bandit,accordion thief] contains my_class())) - return; - if (my_path().id == PATH_POCKET_FAMILIARS) - return; - if (my_path().id == PATH_NUCLEAR_AUTUMN) - return; - QuestState base_quest_state = __quest_state["Guild"]; - if (base_quest_state.finished || !base_quest_state.startable) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - string active_url = ""; - - if (__misc_state["in run"] && my_path().id != PATH_PICKY && !in_bad_moon()) - { - if ($classes[pastamancer,sauceror] contains my_class() && $location[the haunted pantry].turnsAttemptedInLocation() == 0) - return; - if ($classes[disco bandit,accordion thief] contains my_class() && $location[the sleazy back alley].turnsAttemptedInLocation() == 0) - return; - if (!base_quest_state.started && !($classes[seal clubber,turtle tamer] contains my_class())) - return; - } - - boolean [location] relevant_location; - - if (!base_quest_state.started) - { - subentry.entries.listAppend("Talk to your guild chief."); - active_url = "guild.php"; - } - else if (base_quest_state.mafia_internal_step == 1) - { - boolean output_modifiers = false; - if ($classes[seal clubber,turtle tamer] contains my_class()) - { - //cobb's knob - active_url = $location[the outskirts of Cobb's Knob].getClickableURLForLocation(); - relevant_location[$location[the outskirts of Cobb's Knob]] = true; - subentry.entries.listAppend("Adventure in the outskirts of Cobb's Knob to find the sausage."); - output_modifiers = true; - } - if ($classes[pastamancer,sauceror] contains my_class()) - { - //haunted pantry - active_url = $location[the haunted pantry].getClickableURLForLocation(); - relevant_location[$location[the haunted pantry]] = true; - subentry.entries.listAppend("Adventure in the haunted pantry to exorcise the poltersandwich."); - output_modifiers = true; - } - if ($classes[disco bandit,accordion thief] contains my_class()) - { - //sleazy back alley - relevant_location[$location[the sleazy back alley]] = true; - if ($slot[pants].equipped_item() == $item[none]) - { - active_url = "inventory.php?which=2"; - subentry.entries.listAppend("Equip some pants."); - } - else - { - active_url = $location[the sleazy back alley].getClickableURLForLocation(); - subentry.entries.listAppend("Adventure in the sleazy back alley to steal your own pants."); - output_modifiers = true; - } - } - - if (output_modifiers) - { - if (__misc_state["free runs available"]) - { - subentry.modifiers.listAppend("free runs"); - } - if (__misc_state["have hipster"]) - { - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - } - } - } - else if (base_quest_state.mafia_internal_step == 2) - { - subentry.entries.listAppend("Talk to your guild chief."); - active_url = "guild.php"; - } - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, relevant_location).ChecklistEntrySetIDTag("Guild unlock quest")); -} diff --git a/Source/relay/TourGuide/Quests/Intergalaktik.ash b/Source/relay/TourGuide/Quests/Intergalaktik.ash deleted file mode 100644 index c9609b0c..00000000 --- a/Source/relay/TourGuide/Quests/Intergalaktik.ash +++ /dev/null @@ -1,56 +0,0 @@ -void QGalaktikInit() -{ - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questM24Doc"); - - - state.quest_name = "What's Up, Doc?"; - state.image_name = "__item pretty flower"; - - state.startable = true; - - __quest_state["Galaktik"] = state; -} - - -void QGalaktikGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Galaktik"]; - if (!base_quest_state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - string active_url = "place.php?whichplace=town_wrong"; - string image_name = base_quest_state.image_name; - - string [int] missing_item_descriptions; - foreach it in $items[swindleblossom,fraudwort,shysterweed] - { - if (it.available_amount() >= 3) - continue; - missing_item_descriptions.listAppend(pluraliseWordy(3 - it.available_amount(), "more " + it, "more " + it.plural)); - } - - if (missing_item_descriptions.count() > 0) - { - subentry.entries.listAppend("Collect " + missing_item_descriptions.listJoinComponents(", ", "and") + " in the overgrown lot."); - if ($item[brown paper bag mask].available_amount() > 0 && $item[brown paper bag mask].equipped_amount() == 0) - subentry.entries.listAppend("Could equip the brown paper bag mask to meet the Lot's wife, if you haven't already."); - - if (__misc_state["in run"] && __last_adventure_location != $location[the overgrown lot] && !in_bad_moon()) - return; - } - else - { - //shop.php?whichshop=doc&action=talk - active_url = "shop.php?whichshop=doc&action=talk"; - subentry.entries.listAppend("Return to Doc Galaktik."); - //image_name = "__familiar o.a.f."; - } - - optional_task_entries.listAppend(ChecklistEntryMake(image_name, active_url, subentry, $locations[the overgrown lot]).ChecklistEntrySetIDTag("Doc Galaktik flower quest")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Legendary Beat.ash b/Source/relay/TourGuide/Quests/Legendary Beat.ash deleted file mode 100644 index 4eea3327..00000000 --- a/Source/relay/TourGuide/Quests/Legendary Beat.ash +++ /dev/null @@ -1,201 +0,0 @@ -void QLegendaryBeatInit() -{ - if ($item[Map to Professor Jacking's laboratory].available_amount() == 0) - return; - //questI02Beat - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questI02Beat"); - - if (!state.started) - { - QuestStateParseMafiaQuestPropertyValue(state, "started"); - } - - state.quest_name = "Quest for the Legendary Beat"; - state.image_name = "__item the Legendary Beat"; - - if (state.in_progress) - { - //FIXME temporary code - //no way to detect if the legendary beat was found - //if (state.mafia_internal_step < 2 && $location[professor jacking's small-o-fier].turnsAttemptedInLocation() > 0 || $location[professor jacking's huge-a-ma-tron].turnsAttemptedInLocation() > 0) - //state.mafia_internal_step = 2; - } - - __quest_state["Legendary Beat"] = state; -} - -void QLegendaryBeatGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[Map to Professor Jacking's laboratory].available_amount() == 0) - return; - - QuestState base_quest_state = __quest_state["Legendary Beat"]; - if (!base_quest_state.in_progress) - return; - - //FIXME temporary: - if (!($locations[professor jacking's small-o-fier, professor jacking's huge-a-ma-tron] contains __last_adventure_location)) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - //FIXME support for fruit machine sidequest? - - if (base_quest_state.mafia_internal_step == 1 && false) - { - subentry.entries.listAppend("Defeat Professor Jacking."); - } - else if (base_quest_state.mafia_internal_step == 2 || true) - { - //Main quest, in reverse order: - if ($item[can-you-dig-it?].available_amount() > 0 && $effect[stubbly legs].have_effect() > 0) - { - subentry.modifiers.listAppend("-combat"); - //6/7 - string [int] tasks; - if ($item[can-you-dig-it?].equipped_amount() == 0) - tasks.listAppend("equip can-you-dig-it?"); - tasks.listAppend("adventure in Small-O-Fier, find non-combat, dig your way to safety"); - subentry.entries.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - } - else if ($item[can-you-dig-it?].available_amount() > 0 && $effect[smooth legs].have_effect() > 0) - { - //5 - subentry.entries.listAppend("Gaze into the mirror."); - subentry.entries.listAppend("Before you do, though, possibly look for/copy smooth jazz scabie factoids in the Small-O-Fier."); - } - else if ($effect[smooth legs].have_effect() > 0) - { - //4 - if ($effect[literally insane].have_effect() > 0 && $effect[broken dancing].have_effect() > 0 && $item[crazyleg's razor].available_amount() > 0) - subentry.entries.listAppend("Use Crazyleg's razor repeatedly to extend smooth legs effect."); - - subentry.modifiers.listAppend("-combat"); - subentry.modifiers.listAppend("+item"); - subentry.entries.listAppend("Adventure in Small-O-Fier, find ocean non-combat, fight a smooth jazz scabie for can-you-dig-it?"); - - } - else if ($effect[literally insane].have_effect() > 0 && $effect[broken dancing].have_effect() > 0 && $item[crazyleg's razor].available_amount() > 0) - { - //3 - subentry.entries.listAppend("Use Crazyleg's razor. (repeatedly)"); - } - else if ($effect[literally insane].have_effect() + $item[world's most unappetizing beverage].available_amount() > 0 && $effect[broken dancing].have_effect() + $item[squirmy violent party snack].available_amount() > 0 && $item[crazyleg's razor].available_amount() > 0) - { - string [int] tasks; - boolean waiting = false; - if ($effect[literally insane].have_effect() == 0) - { - if (availableDrunkenness() < 1) - { - waiting = true; - tasks.listAppend("wait until you have 1 drunkenness available"); - } - else - tasks.listAppend("drink the world's most unappetizing beverage"); - } - if ($effect[broken dancing].have_effect() == 0) - { - if (availableFullness() < 1) - { - tasks.listAppend("wait until you have 1 fullness available"); - waiting = true; - } - else if (!waiting) - tasks.listAppend("eat a squirmy violent party snack"); - } - subentry.entries.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - } - else - { - boolean need_nc = false; - //Need: - //crazyleg's razor - //literally insane / world's most unappetizing beverage / (hair of the calf and can of depilatory cream) - //broken dancing / squirmy violent party snack / (a dance upon the palate/tiny frozen prehistoric meteorite jawbreaker) - if ($item[crazyleg's razor].available_amount() == 0) - { - subentry.entries.listAppend("Acquire crazyleg's razor.|*Adventure in the Huge-A-Ma-Tron, defeat the Fearsome Wacken."); - } - if ($effect[literally insane].have_effect() + $item[world's most unappetizing beverage].available_amount() > 0) - { - //nothing, have them - } - else if ($item[world's most unappetizing beverage].creatable_amount() > 0) - { - subentry.entries.listAppend("Create the world's most unappetizing beverage."); - } - else - { - //parts: - if ($item[hair of the calf].available_amount() == 0) - { - need_nc = true; - subentry.entries.listAppend("Acquire hair of the calf.|*Adventure in Small-O-Fier, climb up a hair."); - } - if ($item[can of depilatory cream].available_amount() == 0) - { - need_nc = true; - subentry.entries.listAppend("Acquire can of depilatory cream.|*Adventure in Small-O-Fier, find non-combat."); - } - } - - if ($effect[broken dancing].have_effect() + $item[squirmy violent party snack].available_amount() > 0) - { - //nothing, have them - } - else if ($item[squirmy violent party snack].creatable_amount() > 0) - { - subentry.entries.listAppend("Create a squirmy violent party snack."); - } - else - { - //parts: - if ($item[a dance upon the palate].available_amount() == 0) - { - subentry.entries.listAppend("Acquire a dance upon the palate.|*Adventure in Huge-A-Ma-Tron, crouch down and lick the world."); - } - if ($item[tiny frozen prehistoric meteorite jawbreaker].available_amount() == 0) - { - string [int] meteorite_details; - - boolean [item] relevant_fruits = $items[blackberry, cherry, olive, plum, sea blueberry, strawberry]; //cheap ones, not all of them - item chosen_fruit = $item[blackberry]; - foreach it in relevant_fruits - { - if (it.available_amount() > 0) - { - chosen_fruit = it; - break; - } - } - - if (chosen_fruit.available_amount() == 0) - meteorite_details.listAppend("Acquire a " + chosen_fruit + "."); - meteorite_details.listAppend("Put a " + chosen_fruit + " in the fruit machine if you haven't."); - if ($effect[hurricane force].have_effect() == 0) - { - need_nc = true; - meteorite_details.listAppend("Adventure in the Huge-A-Ma-Tron, dance on top of the world."); - } - else - { - meteorite_details.listAppend("Adventure in the Huge-A-Ma-Tron, defeat a loose coalition of yetis, snowmen, and goats."); - } - subentry.entries.listAppend("Acquire a tiny frozen prehistoric meteorite jawbreaker.|*" + meteorite_details.listJoinComponents("|*")); - - - } - } - - if (need_nc) - subentry.modifiers.listAppend("-combat"); - } - } - - task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, "", subentry, $locations[professor jacking's small-o-fier, professor jacking's huge-a-ma-tron]).ChecklistEntrySetIDTag("Legendary beat quest")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Level 10.ash b/Source/relay/TourGuide/Quests/Level 10.ash deleted file mode 100644 index 7995e758..00000000 --- a/Source/relay/TourGuide/Quests/Level 10.ash +++ /dev/null @@ -1,381 +0,0 @@ - -void QLevel10Init() -{ - //questL10Garbage - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL10Garbage"); - - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Castle Quest"; - state.image_name = "castle"; - state.council_quest = true; - - - boolean beanstalk_grown = false; - if ($items[Model airship,Plastic Wrap Immateria,Gauze Immateria,Tin Foil Immateria,Tissue Paper Immateria,S.O.C.K.].available_amount() > 0) - beanstalk_grown = true; - if (state.finished) - beanstalk_grown = true; - if ($location[the penultimate fantasy airship].turnsAttemptedInLocation() > 0) - beanstalk_grown = true; - if (state.mafia_internal_step > 1) - beanstalk_grown = true; - - state.state_boolean["beanstalk grown"] = beanstalk_grown; - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - state.state_boolean["beanstalk grown"] = true; - - if (my_level() >= 10 || my_path().id == PATH_EXPLOSIONS) - state.startable = true; - - __quest_state["Level 10"] = state; - __quest_state["Castle"] = state; -} - - -void QLevel10GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 10"].in_progress) - return; - QuestState base_quest_state = __quest_state["Level 10"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - string image_name = base_quest_state.image_name; - string url = "place.php?whichplace=beanstalk"; - - boolean add_as_future_task = false; - if ($item[s.o.c.k.].available_amount() == 0 && my_path().id != PATH_EXPLOSION) - { - //FIXME delay if ballroom song not set - image_name = "penultimate fantasy airship"; - if (!base_quest_state.state_boolean["beanstalk grown"]) - { - if ($item[enchanted bean].available_amount() == 0) - { - subentry.entries.listAppend("Acquire enchanted bean from a beanbat."); - subentry.modifiers.listAppend("+100% item"); - url = $location[the beanbat chamber].getClickableURLForLocation(); - } - else - { - subentry.entries.listAppend("Grow the beanstalk."); - url = "place.php?whichplace=plains"; - } - } - else - { - int turns_spent = $location[the penultimate fantasy airship].turns_spent; - int turns_delay = -1; - - boolean need_minus_combat = true; - if (turns_spent == -1) - need_minus_combat = true; - else if (turns_spent < 5) - { - need_minus_combat = false; - turns_delay = 5 - turns_spent; - } - else if (turns_spent < 10 && $item[Tissue Paper Immateria].available_amount() > 0) - { - need_minus_combat = false; - turns_delay = 10 - turns_spent; - } - else if (turns_spent < 15 && $item[Tin Foil Immateria].available_amount() > 0) - { - need_minus_combat = false; - turns_delay = 15 - turns_spent; - } - else if (turns_spent < 20 && $item[Gauze Immateria].available_amount() > 0) - { - need_minus_combat = false; - turns_delay = 20 - turns_spent; - } - else if (turns_spent < 25 && $item[Plastic Wrap Immateria].available_amount() > 0) - { - need_minus_combat = false; - turns_delay = 25 - turns_spent; - } - - //boolean need_minus_combat_only_for_model_airship = false; - if ($item[model airship].available_amount() == 0 && turns_spent >= 5) - { - //if (!need_minus_combat) - //need_minus_combat_only_for_model_airship = true; - need_minus_combat = true; - } - - - if (need_minus_combat) - subentry.modifiers.listAppend("-combat"); - else - subentry.modifiers.listAppend("possibly +combat"); - - if (__misc_state["free runs available"]) - subentry.modifiers.listAppend("free runs"); - if (turns_spent < 25) - { - if (__misc_state["have hipster"]) - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - } - - boolean have_more_than_enough_sgeeas = false; - if ($item[soft green echo eyedrop antidote].available_amount() >= 30 || !in_ronin()) - have_more_than_enough_sgeeas = true; - - string [int] things_we_want_item_for; - - if ($skill[Transcendent Olfaction].skill_is_usable() && !have_more_than_enough_sgeeas) - { - string line = "SGEEA"; - if ($item[soft green echo eyedrop antidote].available_amount() > 0) - line += " (have " + $item[soft green echo eyedrop antidote].available_amount() + ")"; - things_we_want_item_for.listAppend(line); - } - - - //immateria: - - item [int] immaterias_missing = $items[Tissue Paper Immateria,Tin Foil Immateria,Gauze Immateria,Plastic Wrap Immateria].items_missing(); - - if (turns_delay != -1 && !need_minus_combat) - { - //subentry.entries.listAppend(pluraliseWordy(turns_delay, "turn", "turns").capitaliseFirstLetter() + " delay until -combat relevant."); - string line = "After " + pluraliseWordy(turns_delay, "turn", "turns") + " delay, "; - if (immaterias_missing.count() == 0) - subentry.entries.listAppend(line + "find Cid."); - else - subentry.entries.listAppend(line + "find " + immaterias_missing.count().int_to_wordy() + " more immateria."); - //subentry.entries.listAppend(line + "find the immateria: " + listJoinComponents(immaterias_missing, ", ", "and")); - } - else - { - if (immaterias_missing.count() == 0) - subentry.entries.listAppend("Find Cid. (-combat)"); - else - { - subentry.entries.listAppend("Find " + immaterias_missing.count().int_to_wordy() + " more immateria. (-combat)"); - //subentry.entries.listAppend("Find the immateria (-combat): " + listJoinComponents(immaterias_missing, ", ", "and")); - } - } - - //FIXME it would be nice to track this - if (turns_spent == -1) - subentry.entries.listAppend("25 total turns of delay."); - else if (turns_spent < 25) - subentry.entries.listAppend(pluralise(25 - turns_spent, "turn", "turns") + " total delay remaining."); - if ($skill[Transcendent Olfaction].skill_is_usable() && !(get_property("olfactedMonster") == "Quiet Healer") && !have_more_than_enough_sgeeas) - subentry.entries.listAppend("Potentially olfact quiet healer for SGEEAs"); - - if ($items[amulet of extreme plot significance,mohawk wig].items_missing().count() > 0 && $familiar[slimeling].familiar_is_usable()) - subentry.modifiers.listAppend("slimeling?"); - - if ($item[model airship].available_amount() == 0) - subentry.entries.listAppend("Acquire model airship from non-combat. (speeds up quest)"); - if ($item[amulet of extreme plot significance].available_amount() == 0) - { - things_we_want_item_for.listAppend("amulet of extreme plot significance"); - subentry.entries.listAppend("Acquire amulet of extreme plot significance (quiet healer, 10% drop) to speed up opening ground floor."); - } - if ($item[mohawk wig].available_amount() == 0) - { - things_we_want_item_for.listAppend("Mohawk wig"); - subentry.entries.listAppend("Acquire mohawk wig (Burly Sidekick, 10% drop) to speed up top floor."); - } - if (things_we_want_item_for.count() > 0) - { - subentry.modifiers.listAppend("+item"); - subentry.entries.listAppend("Potentially run +item for " + listJoinComponents(things_we_want_item_for, ", ", "and") + "."); - } - } - } - else - { - url = "place.php?whichplace=giantcastle"; - if (base_quest_state.mafia_internal_step >= 11) //(get_property("lastEncounter") == "Keep On Turnin' the Wheel in the Sky") - { - url = "place.php?whichplace=town"; - subentry.entries.listAppend("Talk to the council to finish quest."); - } - else if ($location[The Castle in the Clouds in the Sky (Top floor)].locationAvailable()) - { - float turn_estimation = -1.0; - float non_combat_rate = 1.0 - (0.95 + combat_rate_modifier() / 100.0); - if (non_combat_rate < 0.11111111111111) //every nine adventures, minimum - non_combat_rate = 0.11111111111111; - - //FIXME turn estimation for all routes, not just mohawk wig/model airship - - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("Top floor. Run -combat."); - if ($item[mohawk wig].equipped_amount() == 0 && $item[mohawk wig].available_amount() > 0) - { - string line = "Wear your mohawk wig"; - if (!$item[mohawk wig].can_equip()) - { - add_as_future_task = true; - line += ", once you can equip it"; - } - line += "."; - subentry.entries.listAppend(HTMLGenerateSpanFont(line, "red")); - } - if ($item[mohawk wig].available_amount() == 0 && !in_hardcore()) - subentry.entries.listAppend("Potentially pull and wear a mohawk wig."); - if ($item[model airship].available_amount() == 0 && my_path().id != PATH_EXPLOSIONS) - { - if ($item[mohawk wig].available_amount() == 0) //no wig, no airship - subentry.entries.listAppend("Backfarm for a model airship in the fantasy airship. (non-combat option, run -combat)"); - else - subentry.entries.listAppend("Potentially backfarm for a model airship in the fantasy airship. (non-combat option, run -combat)"); //always suggest this - backfarming for model airship is faster than spending time in top floor, I think - } - - if ($item[mohawk wig].available_amount() > 0 && $item[model airship].available_amount() > 0) - { - if (non_combat_rate != 0.0) - turn_estimation = 1.0 / non_combat_rate; - } - - //We don't suggest trying to complete this quest with the record, even if they lack the mohawk wig/model airship - I feel as though that would take quite a number of turns? - //It's a 95% combat location (max nine/ten turns between non-combats), and the non-combats are split between two different sets. - //There might be some internal mechanics to make it faster? Don't know. - image_name = "goggles? yes!"; - - if (turn_estimation != -1.0) - subentry.entries.listAppend("~" + turn_estimation.roundForOutput(1) + " turns left on average."); - - //Check if Shen is going to send them here (and not to the Hole in the Sky before that) - int top_floor_index = 0; - int hole_in_the_sky_index = 0; - foreach index, destination in __quest_state["Level 11 Shen"].state_int.getFutureShenAssignments() { - if (destination == $location[The Castle in the Clouds in the Sky (Top floor)]) - top_floor_index = index; - else if (destination == $location[The Hole in the Sky]) - hole_in_the_sky_index = index; - } - if (top_floor_index > hole_in_the_sky_index) - subentry.entries.listAppend("Hold on before going there; Shen will send you here later."); - } - else if ($location[The Castle in the Clouds in the Sky (Ground floor)].locationAvailable()) - { - int turns_spent = $location[The Castle in the Clouds in the Sky (Ground floor)].turns_spent; - int turns_remaining = 11; - if (turns_spent != -1) - { - turns_remaining = 11 - turns_spent; - subentry.entries.listAppend("Ground floor. Spend " + pluraliseWordy(turns_remaining, "more turn", "more turns") + " here to unlock top floor."); - } - else - subentry.entries.listAppend("Ground floor. Spend eleven turns here to unlock top floor."); - - image_name = "castle stairs up"; - - if (__misc_state["need to level"]) - subentry.entries.listAppend("Possibly acquire the very overdue library book from a non-combat. (stats)"); - - boolean request_minus_combat = false; - if ($item[electric boning knife].available_amount() == 0 && __quest_state["Level 13"].state_boolean["wall of bones will need to be defeated"] && !$skill[garbage nova].skill_is_usable()) - { - request_minus_combat = true; - subentry.modifiers.listAppend("-combat"); - string line = "Try to acquire the electric boning knife if you see it. (foodie NC)"; - string [int] ncs_to_spend_turn_on; - foreach s in $strings[There's No Ability Like Possibility,Putting Off Is Off-Putting,Huzzah!] - { - if (!$location[The Castle in the Clouds in the Sky (Ground floor)].noncombat_queue.contains_text(s)) - { - ncs_to_spend_turn_on.listAppend(s); - } - } - if (ncs_to_spend_turn_on.count() > 0) - line += "|Avoid skipping NCs " + ncs_to_spend_turn_on.listJoinComponents(", ", "and") + " exactly once each, to make the knife appear faster. (don't do this after unlocking the top floor)"; - subentry.entries.listAppend(line); - } - if (!request_minus_combat && CounterWanderingMonsterMayHitNextTurn() && !CounterWanderingMonsterWillHitNextTurn()) - { - request_minus_combat = true; - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("If you seek out and skip NCs here, they can tell you if your wandering monster is up next turn.|Then you can adventure somewhere else for a turn, and burn more delay here."); - } - - if (true) - { - if (__misc_state["have hipster"]) - { - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - } - if (__misc_state["free runs available"]) - subentry.modifiers.listAppend("free runs"); - } - } - else - { - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("Basement. Run -combat."); - - float turn_estimation = -1.0; - float non_combat_rate = 1.0 - (0.95 + combat_rate_modifier() / 100.0); - if (non_combat_rate < 0.11111111111111) //every nine adventures, minimum - non_combat_rate = 0.11111111111111; - if ($item[amulet of extreme plot significance].available_amount() > 0) - { - if ($item[amulet of extreme plot significance].equipped_amount() == 0) - subentry.entries.listAppend("Possibly " + HTMLGenerateSpanFont("wear the amulet of extreme plot significance.", "red") + "|Or search for the non-combat, skip it, equip the amulet, and adventure again."); - - if (non_combat_rate != 0.0) - turn_estimation = 1.0 / non_combat_rate; - - - } - else - { - boolean have_usable_umbrella = (__misc_state["can equip just about any weapon"] && $item[titanium assault umbrella].available_amount() > 0); - - if (!in_hardcore()) - subentry.entries.listAppend("Potentially pull and wear an amulet of extreme plot significance."); - if (have_usable_umbrella && $item[titanium assault umbrella].equipped_amount() == 0) - subentry.entries.listAppend("Equip your titanium assault umbrella."); - if ($item[massive dumbbell].available_amount() == 0) - { - if (have_usable_umbrella) - { - subentry.entries.listAppend("Grab the massive dumbbell from gym if you can't reach the ground floor otherwise."); - - if (non_combat_rate != 0.0) - turn_estimation = (2.0 / 3.0) * (2.0 / non_combat_rate) + (1.0 / 3.0) * (1.0 / non_combat_rate); //1/3rd chance of instant completion with umbrella - } - else - { - subentry.entries.listAppend("Grab the massive dumbbell from gym."); - if (non_combat_rate != 0.0) - { - turn_estimation = 1.0 / non_combat_rate + (1.0 / (non_combat_rate * (2.0 / 3.0))); - } - } - - } - else - { - subentry.entries.listAppend("Place the massive dumbbell in the Open Source dumbwaiter."); - if (non_combat_rate != 0.0) - turn_estimation = 1.0 / (non_combat_rate * (2.0 / 3.0)); - } - } - - if (turn_estimation != -1.0) - subentry.entries.listAppend("~" + turn_estimation.roundForOutput(1) + " turns left on average."); - - image_name = "lift, bro"; - } - } - - ChecklistEntry entry = ChecklistEntryMake(image_name, url, subentry, $locations[the penultimate fantasy airship, the castle in the clouds in the sky (basement), the castle in the clouds in the sky (ground floor), the castle in the clouds in the sky (top floor)]); - entry.tags.id = "Council L10 giant castle quest"; - if (add_as_future_task) - future_task_entries.listAppend(entry); - else - task_entries.listAppend(entry); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Level 11 - Copperhead.ash b/Source/relay/TourGuide/Quests/Level 11 - Copperhead.ash deleted file mode 100644 index c0ed02ec..00000000 --- a/Source/relay/TourGuide/Quests/Level 11 - Copperhead.ash +++ /dev/null @@ -1,430 +0,0 @@ -//Our strategy for the copperhead quest is probably not very good. Largely because it looks complicated and I (Ezandora) made a few guesses. - -void QLevel11CopperheadInit() -{ - if (true) { - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL11Ron"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Zeppelin Quest"; //"Merry-Go-Ron"; - state.image_name = "__item copperhead charm (rampant)"; //__item bitchin ford anglia - - state.state_int["protestors remaining"] = clampi(80 - get_property_int("zeppelinProtestors"), 0, 80); - - state.state_boolean["need protestor speed tricks"] = true; - if (state.mafia_internal_step >= 3) - state.state_int["protestors remaining"] = 0; - if (state.state_int["protestors remaining"] <= 1) - state.state_boolean["need protestor speed tricks"] = false; - - state.state_boolean["should output"] = state.in_progress && __quest_state["Level 11"].state_boolean["have diary"] && (__misc_state["in run"] || $location[the red zeppelin].turns_spent > 0 || __last_adventure_location == $location[a mob of zeppelin protesters]); - - __quest_state["Level 11 Ron"] = state; - } - if (true) { - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL11Shen"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Copperhead Club Quest"; //"Of Mice and Shen"; - state.image_name = "__item copperhead charm"; //"__effect Ancient Annoying Serpent Poison"; - - state.state_boolean["should output"] = state.in_progress && __quest_state["Level 11"].state_boolean["have diary"] && (__misc_state["in run"] || $location[the copperhead club].turns_spent > 0); - - - //other than in exploathing, if mafia_internal_step == 1, we haven't "locked" which items are going to be asked - if (state.state_boolean["should output"] && (state.mafia_internal_step > 1 || my_path().id == PATH_KINGDOM_OF_EXPLOATHING)) { - state.state_int["Shen meetings"] = state.mafia_internal_step / 2; - state.state_int["snakes slain"] = (state.mafia_internal_step - 1) / 2; - - - static boolean have_wrong_predictions; - - int daycount_when_first_met_Shen = get_property_int("shenInitiationDay"); - - //If we are currently looking for a snake - if (state.mafia_internal_step % 2 == 0) { //2, 4 or 6 - state.state_boolean["on an assignment"] = true; - - //Verify if mafia's quest item matches the predicted one. If it doesn't, stop predicting assignments for the rest of the session - if (my_path().id != PATH_KINGDOM_OF_EXPLOATHING) { //we know this path has a hardcoded set of requests - item quest_item = get_property_item("shenQuestItem"); - item predicted_quest_item = __shen_start_day_to_assignments[daycount_when_first_met_Shen] [state.state_int["Shen meetings"]]; - if (quest_item != predicted_quest_item) - have_wrong_predictions = true; - } - } - state.state_int["Shen initiation day"] = have_wrong_predictions ? 0 : daycount_when_first_met_Shen; - } - - __quest_state["Level 11 Shen"] = state; - } -} - -void QLevel11RonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - /* - questL11Ron - Merry-Go-Ron - started - Search for Ron Copperhead on the Red Zeppelin. - step1 - Fight your way through the mob of zeppelin protesters. - step2 - All aboard! All aboard the Red Zeppelin! - step3 - Search the Red Zeppelin for Ron Copperhead. - step4 - Barge into Ron Copperhead's cabin in the Red Zeppelin and beat him up! - finshed - You recovered half of the Talisman o' Nam from Ron Copperhead. Brilliant! - */ - QuestState base_quest_state = __quest_state["Level 11 Ron"]; - if (!base_quest_state.state_boolean["should output"]) - return; - - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - - string url = $location[A Mob of Zeppelin Protesters].getClickableURLForLocation(); - - - if (base_quest_state.mafia_internal_step <= 2 && base_quest_state.state_int["protestors remaining"] <= 1) { - subentry.entries.listAppend("Adventure in the mob of protestors."); - } else if (base_quest_state.mafia_internal_step <= 2) { - //Fight your way through the mob of zeppelin protesters. - subentry.entries.listAppend("Scare away " + pluraliseWordy(base_quest_state.state_int["protestors remaining"], "more protestor", "more protestors") + "."); - subentry.modifiers.listAppend("-combat"); - subentry.modifiers.listAppend("+567% item"); - if (__misc_state["have olfaction equivalent"]) - subentry.modifiers.listAppend("olfact cultists"); - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("sleaze damage", "r_element_sleaze")); - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("sleaze spell damage", "r_element_sleaze")); - //Two olfaction targets here seem to be cultists or lynyrd skinner. - //Cultists seem much better. - //Cigarette lighter is a 15% drop. when used in combat against protestors, removes quite a few - - boolean [item] relevant_lynyrdskin_items; - relevant_lynyrdskin_items[$item[lynyrdskin cap]] = true; - relevant_lynyrdskin_items[$item[lynyrdskin breeches]] = true; - if (__misc_state["Torso aware"]) - relevant_lynyrdskin_items[$item[lynyrdskin tunic]] = true; - - if ($item[lynyrd musk].available_amount() > 0 && $effect[Musky].have_effect() == 0 && $item[lynyrd musk].item_is_usable()) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Use lynyrd musk.", "red")); - url = "inventory.php?ftext=lynyrd+musk"; - } - if ($item[cigarette lighter].available_amount() > 0 && base_quest_state.state_boolean["need protestor speed tricks"] && my_path().id != PATH_POCKET_FAMILIARS) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Use cigarette lighter in-combat.", "red")); - } - if ($item[lynyrd snare].available_amount() > 0 && $items[lynyrdskin cap,lynyrdskin tunic,lynyrdskin breeches].items_missing().count() > 0 && $item[lynyrd snare].item_is_usable() && get_property_int("_lynyrdSnareUses") < 3 && $item[lynyrd snare].item_is_usable()) { - subentry.entries.listAppend("Possibly use the lynyrd snare. (free combat)"); - } - string [int] what_not_not_to_wear; - foreach it in relevant_lynyrdskin_items { - if (it.available_amount() == 0) - continue; - if (it.equipped_amount() > 0) - continue; - what_not_not_to_wear.listAppend(it.to_string().replace_string("lynyrdskin ", "")); - } - - if ($item[pocket wish].have() || ($item[genie bottle].have() && get_property_int("_genieWishesUsed") < 3)) { - int current_sleaze_damage = numeric_modifier("sleaze damage") + numeric_modifier("sleaze spell damage"); - string [int] options; - if ($effect[Fifty Ways to Bereave Your Lover].have_effect() == 0) - options.listAppend("Fifty Ways to Bereave Your Lover for +100 sleaze damage"); - if ($effect[Dirty Pear].have_effect() == 0) - options.listAppend("Dirty Pear for 2x sleaze damage; currently +" + current_sleaze_damage + " total damage"); - string line = "Could wish for sleaze damage"; - if (options.count() > 0) - line += ", like " + options.listJoinComponents(", ", "or"); - line += "."; - subentry.entries.listAppend(line); - } - float sleaze_protestors_cleared = MAX(3.0, sqrt(numeric_modifier("sleaze damage") + numeric_modifier("sleaze spell damage"))); - if (sleaze_protestors_cleared > 3) - subentry.entries.listAppend(HTMLGenerateSpanOfClass("Sleaze", "r_element_sleaze") + " damage will clear " + sleaze_protestors_cleared.roundForOutput(1) + " protestors."); //FIXME do we want to list the amount they'll need to increase that? - - if (what_not_not_to_wear.count() > 0) { - subentry.entries.listAppend("Equip your lynyrdskin " + what_not_not_to_wear.listJoinComponents(", ", "and") + "?"); - url = "inventory.php?ftext=lynyrd"; - } - - if ($skill[Transcendent Olfaction].skill_is_usable() && !(get_property_monster("olfactedMonster") == $monster[Blue Oyster cultist]) && base_quest_state.state_boolean["need protestor speed tricks"]) - subentry.entries.listAppend("Olfact blue oyster cultists for protestor-skipping lighters."); - - if ($item[lynyrd skin].available_amount() > 0 && $skill[armorcraftiness].skill_is_usable()) { - item [int] missing_equipment = relevant_lynyrdskin_items.items_missing(); - if (missing_equipment.count() > 0) { - string [int] missing_equipment_output_string; - foreach key, it in missing_equipment { - missing_equipment_output_string.listAppend(it.to_string().replace_string("lynyrdskin ", "")); - } - string joining_string = "or"; - if (missing_equipment.count() <= $item[lynyrd skin].available_amount()) - joining_string = "and"; - string line = "Craft lynyrdskin " + missing_equipment_output_string.listJoinComponents(", ", joining_string); - - line += "."; - boolean can_likely_freecraft = false; - if ($effect[inigo's incantation of inspiration].have_effect() >= 5) - can_likely_freecraft = true; - if ($item[thor's pliers].available_amount() > 0 && get_property_int("_thorsPliersCrafting") < 10) //FIXME is _thorsPliersCrafting correct? suspect mafia tracks it incorrectly, I saw it at 9 after a run. smithing, probably - can_likely_freecraft = true; - if (get_property_int("homebodylCharges") > 0) - can_likely_freecraft = true; - - //_legionJackhammerCrafting <3 - if ($items[Loathing Legion abacus,Loathing Legion can opener,Loathing Legion chainsaw,Loathing Legion corkscrew,Loathing Legion defibrillator,Loathing Legion double prism,Loathing Legion electric knife,Loathing Legion flamethrower,Loathing Legion hammer,Loathing Legion helicopter,Loathing Legion jackhammer,Loathing Legion kitchen sink,Loathing Legion knife,Loathing Legion many-purpose hook,Loathing Legion moondial,Loathing Legion necktie,Loathing Legion pizza stone,Loathing Legion rollerblades,Loathing Legion tape measure,Loathing Legion tattoo needle,Loathing Legion universal screwdriver,Loathing Legion Knife].available_amount() > 0 && get_property_int("_legionJackhammerCrafting") < 3) { - if ($item[Loathing Legion jackhammer].available_amount() == 0 && !can_likely_freecraft) { - line += " (fold loathing legion knife into jackhammer first)"; - } - can_likely_freecraft = true; - } - - if (!can_likely_freecraft) - line += " (1 adventure, not worth it?)"; - - subentry.entries.listAppend(line); - - } - } - if (!__quest_state["Level 11 Shen"].finished && $item[Flamin' Whatshisname].available_amount() == 0) - subentry.entries.listAppend("Could adventure in the Copperhead Club first for Flamin' Whatshisnames."); - } else if (base_quest_state.mafia_internal_step <= 4) { - //All aboard! All aboard the Red Zeppelin! - subentry.entries.listAppend("Search for Ron in the zeppelin."); - //possibly 50% chance of no progress without a ticket (unconfirmed chat rumour) - - if (my_path().id != PATH_POCKET_FAMILIARS) { - subentry.modifiers.listAppend("+234% item"); - foreach m in $monsters[Red Herring,Red Snapper] { - if (!m.is_banished()) - subentry.modifiers.listAppend("banish " + m); - } - - if (__misc_state["have olfaction equivalent"]) - subentry.modifiers.listAppend("olfact red butler"); - } - - if ($item[red zeppelin ticket].available_amount() == 0) { - if ($item[priceless diamond].available_amount() > 0 && black_market_available()) - subentry.entries.listAppend("Trade in your priceless diamond for a red zeppelin ticket."); - else if (my_meat() >= $item[red zeppelin ticket].npc_price() && my_meat() >= 4000 && black_market_available()) - subentry.entries.listAppend("Purchase a red zeppelin ticket in the black market."); - else if (!__quest_state["Level 11 Shen"].finished && black_market_available()) - subentry.entries.listAppend("Could adventure in the Copperhead Club first for a ticket. (greatly speeds up area)"); - else - subentry.entries.listAppend("No ticket."); - } - - if (my_path().id != PATH_POCKET_FAMILIARS) { - if (get_property_int("_glarkCableUses") < 5) { - if ($skill[Transcendent Olfaction].skill_is_usable() && !(get_property_monster("olfactedMonster") == $monster[red butler])) - subentry.entries.listAppend("Olfact red butlers for glark cables."); - - if ($item[glark cable].available_amount() > 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Use glark cable in-combat.", "red")); - } - subentry.entries.listAppend(get_property_int("_glarkCableUses") + " / 5 glark cables used today (free kills)."); - } else { - subentry.entries.listAppend("Already used all 5 glark cables for the day."); - } - } - - if ($item[priceless diamond].available_amount() > 0 && $item[red zeppelin ticket].available_amount() == 0) { - subentry.modifiers.listClear(); - subentry.entries.listClear(); - subentry.entries.listAppend("Acquire a Red Zeppelin ticket from the black market."); - url = "shop.php?whichshop=blackmarket"; - } - } else if (base_quest_state.mafia_internal_step == 5) { - //Barge into Ron Copperhead's cabin in the Red Zeppelin and beat him up! - subentry.entries.listAppend("Defeat Ron in the zeppelin."); - } - - - - - ChecklistEntry entry = ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[A Mob of Zeppelin Protesters,The Red Zeppelin]); - entry.tags.id = "Council L11 quest copperhead Ron"; - - if (!__misc_state["in run"] || $item[talisman o' namsilat].available_amount() > 0) - optional_task_entries.listAppend(entry); - else - task_entries.listAppend(entry); -} - -void QLevel11ShenGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - /* - questL11Shen - Of Mice and Shen - started - Go to the Copperhead Club and find Shen, the man mentioned in your father's diary. - step1 - (no unique message) - step2 - (no unique message) - step3 - (no unique message) - step4 - (no unique message) - step5 - (no unique message) - step6 - (no unique message) - finished - You retrieved half of the Talisman o' Nam from Shen Copperhead. Nice! - - Guesses: - 1 - Need to meet shen for the first time. - 2 - shen met the first time, go do as he asks - 3 - monster done, now go find shen - 4 - shen met second time, go do as he asks - 5 - second monster done, go now find shen - 6 - shen found, go find the third monster - 7 - third monster defeated, shen find go - finished*/ - - QuestState base_quest_state = __quest_state["Level 11 Shen"]; - if (!base_quest_state.state_boolean["should output"]) - return; - - ChecklistEntry entry; - entry.url = $location[the copperhead club].getClickableURLForLocation(); - entry.image_lookup_name = base_quest_state.image_name; - entry.tags.id = "Council L11 quest copperhead Shen"; - entry.should_highlight = $locations[the copperhead club] contains __last_adventure_location; - - ChecklistSubentry subentry; - entry.subentries.listAppend(subentry); //changes made to subentry past this line will still appear. Done now to make sure this one is above the club subentry. - subentry.header = base_quest_state.quest_name; - - item [int] current_assignments; - if (my_path().id == PATH_EXPLOSIONS) - current_assignments = __shen_exploathing_assignments; - else if (__shen_start_day_to_assignments contains base_quest_state.state_int["Shen initiation day"]) - current_assignments = __shen_start_day_to_assignments[base_quest_state.state_int["Shen initiation day"]]; - - entry.should_highlight = entry.should_highlight || current_assignments.shenAssignmentsJoinLocationsStartingAfter(base_quest_state.state_int["snakes slain"]).listInvert() contains __last_adventure_location; - - - if (base_quest_state.mafia_internal_step <= 1) { //Need to meet shen for the first time. - subentry.entries.listAppend("Adventure in the Copperhead Club and meet Shen."); - subentry.entries.listAppend("This will give you unremovable -5 stat poison."); - if (my_path().id == PATH_EXPLOSIONS) - subentry.entries.listAppend("On this path, he'll always ask for: |*• " + current_assignments.shenAssignmentsJoinLocations().listJoinComponents("|*• ")); - else { - int daycount = my_daycount(); - if (__shen_start_day_to_assignments contains daycount) - subentry.entries.listAppend("If you meet him today, he'll send you to:|*• " + __shen_start_day_to_assignments[daycount].shenAssignmentsJoinLocations().listJoinComponents("|*• ")); - if (__shen_start_day_to_assignments contains ++daycount) - subentry.entries.listAppend("Tomorrow will instead be:|*• " + __shen_start_day_to_assignments[daycount].shenAssignmentsJoinLocations().listJoinComponents("|*• ")); - } - // This used to be true in old metas, but hasn't been true for a while. Commenting it out. - // if (my_daycount() == 1 && my_path().id != PATH_EXPLOSIONS) - // subentry.entries.listAppend("Perhaps wait until tomorrow before starting this; day 2's shen bosses are more favourable."); - } else { - int club_turns_spent = $location[the copperhead club].turns_spent; - int next_guaranteed_meeting = base_quest_state.state_int["Shen meetings"] * 5; - int total_delay_remaining = 15 - (3 - base_quest_state.state_int["Shen meetings"]) - club_turns_spent; - boolean is_disguised = $effect[Crappily Disguised as a Waiter].have_effect() > 0; - string club_hazard = get_property("copperheadClubHazard"); //none, gong, fire, ice - boolean need_diamond = $items[priceless diamond,Red Zeppelin ticket].available_amount() == 0 && __quest_state["Level 11 Ron"].mafia_internal_step < 5 && my_meat() < 5000 && my_path().id != PATH_NUCLEAR_AUTUMN; - boolean need_flaming_whatshisname = __quest_state["Level 11 Ron"].state_boolean["need protestor speed tricks"]; - - string [int] club_modifiers; - club_modifiers.listAppend("+234% item"); - club_modifiers.listAppend("olfact ninja dressed as a waiter"); - if (club_hazard != "gong") - club_modifiers.listAppend("-ML"); //hail of bullets damage is ~9 + your +ML - - string [int] club_entries; - //unnamed cocktail is 15% - //ninja dressed as a waiter has 30% disguise - //waiter dressed as a ninja has 20% disguise - //Behind the 'Stache can have a single state: gong, ice, or lanterns on fire - //ice -> priceless diamond - //fire -> setting unnamed cocktail on fire - //gong -> prevents damage taken (not speed relevant) - //and averages 0.64285714285714 unnamed cocktails per attempt (which takes a turn?) - //so let's see... - //you first want the priceless diamond for the ticket, otherwise you have the 50% chance(?) of losing progress - //soo... run 234% item for the disguise? - //after that, you theoretically want to upgrade cocktails, but... - //to do that, you need a second disguise, which means possibly olfacting? then olfacting the bartender. - - //alternatively, olfact the ninja, then use disguises to collect cocktails - //each one saves up to seven protestors if you see the NC (at -25% combat, the likelyhood is 11.6% per turn) - - string line = "Use crappy waiter disguise (have " + $item[crappy waiter disguise].available_amount() + ") for a free NC (doesn't burn delay)."; - if (club_hazard == "" || club_hazard == "none" || club_hazard == "fire" && !need_flaming_whatshisname || club_hazard == "ice" && !need_diamond) { - if (need_diamond) - line += "|*Bucket: fights may give a priceless diamond."; - else if (need_flaming_whatshisname) - line += "|*Lanterns: fights turn Unnamed cocktails in inventory into Flaming whatshisname."; - else - line += "|*Gong: prevents the start of fight damage."; - } else if (club_hazard == "ice") - club_entries.listAppend("Fight club monsters (not wanderers) for a chance at a priceless diamond."); - else if (club_hazard == "fire") - club_entries.listAppend("Fight club monsters (not wanderers) with an Unnamed cocktail in inventory to turn it into a Flaming Whatshisname."); - line += "|*Steal: gain 1 Unnamed cocktail + 3-4 other things"; - if (club_hazard == "fire" && need_flaming_whatshisname) - line += " (have " + $item[Flamin' Whatshisname].item_amount() + ")"; - line += "."; - club_entries.listAppend(line); - club_entries.listAppend("Potentially save some disguises until the end to maybe save a turn."); - - - - if (base_quest_state.state_boolean["on an assignment"]) { //2, 4 or 6 - location assignment_location = __shen_items_to_locations[get_property_item("shenQuestItem")]; - - if (assignment_location != $location[none]) { - entry.url = assignment_location.getClickableURLForLocation(); - subentry.entries.listAppend("Adventure in " + assignment_location + (assignment_location == $location[The VERY Unquiet Garves] ? " (or the Unquiet Garves, but make a choice and stick to it)" : "") + "."); - } else { - subentry.entries.listAppend("Fight the " + base_quest_state.state_int["Shen meetings"].int_to_position_wordy() + " monster wherever Shen told you to go."); - } - - if (total_delay_remaining - 1 > 0) { - ChecklistSubentry club_subentry; - club_subentry.header = "Back at the club"; - club_subentry.modifiers.listAppendList(club_modifiers); - - if (club_turns_spent < next_guaranteed_meeting) - club_subentry.entries.listAppend("Delay for " + pluralise(next_guaranteed_meeting - club_turns_spent, "more turn", "more turns") + " in the Copperhead Club."); - club_subentry.entries.listAppend((total_delay_remaining - 1) + "-" + total_delay_remaining + " total delay remaining in the club."); - club_subentry.entries.listAppendList(club_entries); - - entry.subentries.listAppend(club_subentry); - } - } else if (club_turns_spent >= next_guaranteed_meeting) { - subentry.entries.listAppend("Meet Shen in the Copperhead Club.|Will meet him next turn."); - } else { - subentry.entries.listAppend("Find Shen in the Copperhead Club."); - if (club_turns_spent == next_guaranteed_meeting - 1) { - subentry.entries.listAppend((is_disguised ? "~25" : "50") + "% chance of finding him next turn."); - if (base_quest_state.state_int["Shen meetings"] == 3) { - if ($item[crappy waiter disguise].item_amount() > 0) - subentry.entries.listAppend("Use waiter disguises to have a chance at getting it early.").HTMLGenerateSpanFont(is_disguised ? "red" : "dark"); - if (is_disguised) - subentry.entries.listAppend("Have a disguise on; give it a go."); - } - } else { - subentry.modifiers.listAppendList(club_modifiers); - - string line; - line += "Can show up in " + (next_guaranteed_meeting - club_turns_spent - 1).pluralise("more turn", "more turns") + ";"; - line += " ensured in " + (next_guaranteed_meeting - club_turns_spent) + "."; - line += "|" + (total_delay_remaining - 1) + "-" + total_delay_remaining + " total delay remaining."; - subentry.entries.listAppend(line); - } - subentry.entries.listAppendList(club_entries); - } - } - - - if (!__misc_state["in run"] || $item[talisman o' namsilat].available_amount() > 0) - optional_task_entries.listAppend(entry); - else - task_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Quests/Level 11 - Desert.ash b/Source/relay/TourGuide/Quests/Level 11 - Desert.ash deleted file mode 100644 index fcbdb1aa..00000000 --- a/Source/relay/TourGuide/Quests/Level 11 - Desert.ash +++ /dev/null @@ -1,245 +0,0 @@ -void QLevel11DesertInit() -{ - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL11Desert"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Desert Quest"; - state.image_name = "Pyramid"; //"__item instant karma"; - - int gnasir_progress = get_property_int("gnasirProgress"); - - state.state_boolean["Stone Rose Given"] = (gnasir_progress & 1) > 0; - state.state_boolean["Black Paint Given"] = (gnasir_progress & 2) > 0; - state.state_boolean["Killing Jar Given"] = (gnasir_progress & 4) > 0; - state.state_boolean["Manual Pages Given"] = (gnasir_progress & 8) > 0; - state.state_boolean["Wormridden"] = (gnasir_progress & 16) > 0; - - state.state_int["Desert Exploration"] = get_property_int("desertExploration"); - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - state.state_int["Desert Exploration"] = 100; - state.state_boolean["Desert Explored"] = (state.state_int["Desert Exploration"] == 100); - if (state.finished) { //in case mafia doesn't detect it properly - state.state_int["Desert Exploration"] = 100; - state.state_boolean["Desert Explored"] = true; - } - - - - boolean have_uv_compass_equipped = false; - - if (!__misc_state["can equip just about any weapon"]) - have_uv_compass_equipped = true; - if ($item[UV-resistant compass].equipped_amount() > 0) - have_uv_compass_equipped = true; - if ($item[ornate dowsing rod].equipped_amount() > 0) - have_uv_compass_equipped = true; - - state.state_boolean["Have UV-Compass eqipped"] = have_uv_compass_equipped; - - __quest_state["Level 11 Desert"] = state; -} - -void QLevel11DesertGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 11 Desert"].in_progress && __quest_state["Level 11"].mafia_internal_step < 3) - return; - QuestState base_quest_state = __quest_state["Level 11 Desert"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - string url = "place.php?whichplace=desertbeach"; - - if (base_quest_state.state_boolean["Desert Explored"]) - return; - - int exploration = base_quest_state.state_int["Desert Exploration"]; - int exploration_remaining = 100 - exploration; - float exploration_per_turn = 1.0; - if ($item[ornate dowsing rod].available_amount() > 0) - exploration_per_turn += 2.0; //FIXME make completely accurate for first turn? not enough information available - else if ($item[uv-resistant compass].available_amount() > 0) - exploration_per_turn += 1.0; - if (my_path().id == PATH_LICENSE_TO_ADVENTURE && get_property_boolean("bondDesert")) - exploration_per_turn += 2.0; - if ($item[survival knife].have() && __misc_state["can equip just about any weapon"] && $effect[ultrahydrated].have_effect() > 0) { - exploration_per_turn += 2.0; - } - - boolean have_blacklight_bulb = (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && get_property("peteMotorbikeHeadlight") == "Blacklight Bulb"); - if (have_blacklight_bulb) - exploration_per_turn += 2.0; - //FIXME deal with ultra-hydrated - - familiar camel = lookupFamiliar("Melodramedary"); - boolean canCamel = camel.familiar_is_usable(); - boolean haveCamel = my_familiar() == camel && camel != $familiar[none]; - if (haveCamel) - exploration_per_turn += 1.0; - - int combats_remaining = exploration_remaining; - combats_remaining = ceil(to_float(exploration_remaining) / exploration_per_turn); - subentry.entries.listAppend(exploration_remaining + "% exploration remaining. (" + pluralise(combats_remaining, "combat", "combats") + ")"); - if ($effect[ultrahydrated].have_effect() == 0 && my_path().id != PATH_G_LOVER) { - if (__last_adventure_location == $location[the arid, extra-dry desert]) { - string [int] description; - description.listAppend("Adventure in the Oasis."); - if ($items[11-leaf clover].available_amount() > 0) - description.listAppend("Potentially clover for 20 turns, versus 5."); - if (!get_property_boolean("fireExtinguisherDesertUsed") && __iotms_usable[$item[industrial fire extinguisher]] && get_property_int("_fireExtinguisherCharge") > 20) - description.listAppend("Or, use 20% fire extinguisher charge in the desert to drink the foam."); - task_entries.listAppend(ChecklistEntryMake("__effect ultrahydrated", "place.php?whichplace=desertbeach", ChecklistSubentryMake("Acquire ultrahydrated effect", "", description), -11).ChecklistEntrySetIDTag("Council L11 quest desert ultrahydrated")); - } - //if (exploration > 0) - //subentry.entries.listAppend("Need ultra-hydrated from The Oasis. (potential clover for 20 turns)"); - } - if (exploration < 10) { - int turns_until_gnasir_found = -1; - if (exploration_per_turn != 0.0) - turns_until_gnasir_found = ceil(to_float(10 - exploration) / exploration_per_turn); - - subentry.entries.listAppend("Find Gnasir after " + pluralise(turns_until_gnasir_found, "turn", "turns") + "."); - } else if (get_property_int("gnasirProgress") == 0 && exploration <= 14 && !$location[the arid, extra-dry desert].noncombat_queue.contains_text("A Sietch in Time")) { - subentry.entries.listAppend("Find Gnasir next turn."); - } else { - boolean need_pages = false; - if (!base_quest_state.state_boolean["Black Paint Given"]) { - if ($item[can of black paint].available_amount() == 0) { - if (black_market_available()) - subentry.entries.listAppend("Buy can of black paint, give it to Gnasir."); - } else - subentry.entries.listAppend("Give can of black paint to Gnasir."); - } - if (!base_quest_state.state_boolean["Stone Rose Given"]) { - if ($item[stone rose].available_amount() > 0) - subentry.entries.listAppend("Give stone rose to Gnasir."); - else { - string line = "Potentially adventure in Oasis for stone rose"; - line += "."; - if (delayRemainingInLocation($location[the oasis]) > 0) { - string hipster_text = ""; - if (__misc_state["have hipster"]) { - hipster_text = " (use " + __misc_state_string["hipster name"] + ")"; - } - line += "|Delay for " + pluralise(delayRemainingInLocation($location[the oasis]), "turn", "turns") + hipster_text + "."; - } - subentry.entries.listAppend(line); - } - } - if (my_path().id == PATH_G_LOVER) { //FIXME todo? - } else if (!base_quest_state.state_boolean["Manual Pages Given"]) { - if ($item[worm-riding manual page].available_amount() == 15) - subentry.entries.listAppend("Give Gnasir the worm-riding manual pages."); - else { - int remaining = 15 - $item[worm-riding manual page].available_amount(); - - subentry.entries.listAppend("Find " + pluralise(remaining, "more worm-riding manual page", "more worm-riding manual pages") + "."); - need_pages = true; - } - - } else if (!base_quest_state.state_boolean["Wormridden"]) { - subentry.modifiers.listAppend("rhythm"); - if ($item[drum machine].available_amount() > 0) { - subentry.entries.listAppend("Use drum machine."); - } - } - if (!base_quest_state.state_boolean["Wormridden"] && $item[drum machine].available_amount() == 0 && my_path().id != PATH_G_LOVER) { - if (base_quest_state.state_boolean["Manual Pages Given"]) - subentry.entries.listAppend("Potentially acquire drum machine from blur. (+234% item), use drum machine."); - else - subentry.entries.listAppend("Potentially acquire drum machine from blur. (+234% item), collect/return pages, then use drum machine."); - subentry.modifiers.listAppend("+234% item"); - } - if (!base_quest_state.state_boolean["Killing Jar Given"]) { - if ($item[killing jar].available_amount() > 0) - subentry.entries.listAppend("Give Gnasir the killing jar."); - else - subentry.entries.listAppend("Potentially find killing jar. (banshee, haunted library, 10% drop, YR?)"); - } - - if (__misc_state["have hipster"]) { - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - - string line = __misc_state_string["hipster name"].capitaliseFirstLetter() + " for free combats"; - if (need_pages) - line += " and manual pages"; - line += "."; - subentry.entries.listAppend(line); - } - } - if ($effect[ultrahydrated].have_effect() == 0 && my_path().id != PATH_G_LOVER) { - if (exploration > 0) - subentry.entries.listAppend("Acquire ultrahydrated effect from oasis. (potential clover for 20 adventures)"); - } - if ($item[desert sightseeing pamphlet].available_amount() > 0) { - if ($item[desert sightseeing pamphlet].available_amount() == 1) - subentry.entries.listAppend("Use your desert sightseeing pamphlet. (+15% exploration)"); - else - subentry.entries.listAppend("Use your desert sightseeing pamphlets. (+15% exploration)"); - } - int campgroundMilestoneCount = __campground[$item[milestone]]; - if (campgroundMilestoneCount > 0) { - string milestonesPlural = campgroundMilestoneCount == 1 ? "" : "s"; - subentry.entries.listAppend(HTMLGenerateSpanFont("Harvest your rock garden milestone" + milestonesPlural + "!", "red")); - } - if ($item[milestone].available_amount() > 0 && $item[milestone].item_is_usable()) { - string milestonesPlural = $item[milestone].available_amount() == 1 ? "" : "s"; - subentry.entries.listAppend("Use your milestone" + mileStonesPlural + ". (+5% exploration each)"); - } - if (!base_quest_state.state_boolean["Have UV-Compass eqipped"] && __quest_state["Level 11 Desert"].state_int["Desert Exploration"] < 99) { - boolean should_output_compass_in_red = true; - string line = ""; - string line_extra = ""; - if ($item[ornate dowsing rod].available_amount() > 0) { - line = "Equip the ornate dowsing rod."; - url = "inventory.php?ftext=ornate+dowsing+rod"; - } else { - if ($item[uv-resistant compass].available_amount() == 0 && !(my_path().id == PATH_LICENSE_TO_ADVENTURE && get_property_boolean("bondDesert")) && my_path().id != PATH_EXPLOSIONS) { - line = "Acquire"; - if (have_blacklight_bulb || haveCamel) { - line = "Possibly acquire"; - should_output_compass_in_red = false; - } - - line += " UV-resistant compass, equip for faster desert exploration. (shore vacation)"; - if ($item[Shore Inc. Ship Trip Scrip].available_amount() > 0) - url = "shop.php?whichshop=shore"; - - if ($item[odd silver coin].available_amount() > 0 || $item[grimstone mask].available_amount() > 0 || get_property("grimstoneMaskPath") != "") { //FIXME check for the correct grimstoneMaskPath - line_extra += "|Or acquire ornate dowsing rod from Paul's Boutique? (5 odd silver coins)"; - } - - } else if ($item[uv-resistant compass].available_amount() > 0) { - line = "Equip the UV-resistant compass."; - url = "inventory.php?ftext=uv-resistant+compass"; - } - } - if (canCamel && !haveCamel) { - if (line == "") - line += "Bring along Melodramedary."; - else - line_extra += "|Or bring along Melodramedary."; - } - if ($item[survival knife].have() && ($item[survival knife].equipped_amount() == 0)) { - if (line == "") - line += "Equip your survival knife (only effective while Ultrahydrated)"; - else - line_extra += "|Equip your survival knife (only effective while Ultrahydrated)"; - } - if (line != "") { - if (should_output_compass_in_red) - line = HTMLGenerateSpanFont(line, "red"); - line += line_extra; - subentry.entries.listAppend(line); - } - - } else { - if (canCamel && !haveCamel) { - subentry.entries.listAppend("Could bring along Melodramedary."); - } - } - task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the arid\, extra-dry desert,the oasis]).ChecklistEntrySetIDTag("Council L11 quest desert exploration")); -} diff --git a/Source/relay/TourGuide/Quests/Level 11 - Hidden City.ash b/Source/relay/TourGuide/Quests/Level 11 - Hidden City.ash deleted file mode 100644 index cb5342c4..00000000 --- a/Source/relay/TourGuide/Quests/Level 11 - Hidden City.ash +++ /dev/null @@ -1,502 +0,0 @@ -boolean [item] __dense_liana_machete_items = $items[antique machete,Machetito,Muculent machete,Papier-mâchéte]; - -int numberOfDenseLianaFoughtInShrine(location shrine) -{ - //need to check the combat names due to wanderers: - int dense_liana_defeated = 0; - string [int] area_combats_seen = shrine.locationSeenCombats(); - foreach key, s in area_combats_seen - { - if (s == "dense liana") - dense_liana_defeated += 1; - } - return dense_liana_defeated; -} - -void QLevel11HiddenCityInit() { - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL11Worship"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Hidden City Quest"; - state.image_name = "Hidden City"; - - state.state_boolean["Hospital finished"] = (get_property_int("hiddenHospitalProgress") >= 8); - state.state_boolean["Bowling alley finished"] = (get_property_int("hiddenBowlingAlleyProgress") >= 8); - state.state_boolean["Apartment finished"] = (get_property_int("hiddenApartmentProgress") >= 8); - state.state_boolean["Office finished"] = (get_property_int("hiddenOfficeProgress") >= 8); - - state.state_boolean["need machete for liana"] = true; - foreach it in __dense_liana_machete_items { - if (it.available_amount() > 0) { - state.state_boolean["need machete for liana"] = false; - break; - } - } - - int lianas_left; - foreach shrine in $locations[a massive ziggurat,an overgrown shrine (northwest),an overgrown shrine (southwest),an overgrown shrine (northeast),an overgrown shrine (southeast)] { - lianas_left += 3 - shrine.numberOfDenseLianaFoughtInShrine(); - } - state.state_int["lianas left"] = lianas_left; - - if (get_property_int("hiddenBowlingAlleyProgress") >= 1 && get_property_int("hiddenHospitalProgress") >= 1 && get_property_int("hiddenApartmentProgress") >= 1 && get_property_int("hiddenOfficeProgress") >= 1 && $location[a massive Ziggurat].numberOfDenseLianaFoughtInShrine() >= 3 && state.mafia_internal_step >= 4) - state.state_int["lianas left"] = 0; - - if (state.state_int["lianas left"] == 0) - state.state_boolean["need machete for liana"] = false; - - if (!__misc_state["can equip just about any weapon"]) { - state.state_boolean["need machete for liana"] = false; - } - - - if (state.finished) { - state.state_boolean["Hospital finished"] = true; - state.state_boolean["Bowling alley finished"] = true; - state.state_boolean["Apartment finished"] = true; - state.state_boolean["Office finished"] = true; - state.state_boolean["need machete for liana"] = false; - } - - __quest_state["Level 11 Hidden City"] = state; -} - - -void generateHiddenAreaUnlockForShrine(string [int] description, location shrine) { - item machete = $item[none]; - - foreach macheteItem in __dense_liana_machete_items { - if (macheteItem.available_amount() > 0) { - machete = macheteItem; - } - } - - boolean hasMachete = machete != $item[none]; - boolean hasMacheteEquipped = machete.equipped_amount() > 0; - int lianaRemaining = MAX(0, 3 - shrine.numberOfDenseLianaFoughtInShrine()); - - if (shrine != $location[a massive ziggurat]) { - description.listAppend("Unlock by visiting " + shrine + "."); - } - - if (lianaRemaining > 0 && shrine.noncombatTurnsAttemptedInLocation() == 0) { - description.listAppend("Fight " + lianaRemaining + " more liana."); - - if (__misc_state["can equip just about any weapon"] && my_path().id != PATH_POCKET_FAMILIARS) { - if (!hasMachete) { - description.listAppend("Acquire a machete first."); - } else if (!hasMacheteEquipped) { - description.listAppend(HTMLGenerateSpanFont("Equip your " + machete + " first.", "red")); - } - } - } -} - -void QLevel11HiddenCityGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 11 Hidden City"].in_progress) - return; - if (__quest_state["Level 11"].mafia_internal_step <3 ) //strange bug where questL11MacGuffin = started, questL11Manor = step1 - return; - - QuestState base_quest_state = __quest_state["Level 11 Hidden City"]; - ChecklistEntry entry; - entry.url = "place.php?whichplace=hiddencity"; - entry.image_lookup_name = base_quest_state.image_name; - entry.tags.id = "Council L11 quest hidden city"; - entry.should_indent_after_first_subentry = true; - entry.should_highlight = $locations[the hidden temple, the hidden apartment building, the hidden hospital, the hidden office building, the hidden bowling alley, the hidden park, a massive ziggurat,an overgrown shrine (northwest),an overgrown shrine (southwest),an overgrown shrine (northeast),an overgrown shrine (southeast)] contains __last_adventure_location; - - if (!__quest_state["Hidden Temple Unlock"].finished) - { - return; - } - else if (!locationAvailable($location[the hidden park])) - { - entry.image_lookup_name = "Hidden Temple"; - entry.url = "place.php?whichplace=woods"; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - subentry.entries.listAppend("Unlock the hidden city via the hidden temple."); - if ($item[the Nostril of the Serpent].available_amount() == 0 && !get_property_ascension("lastTempleButtonsUnlock")) - subentry.entries.listAppend("Need nostril of the serpent."); - if ($item[stone wool].available_amount() > 0 && my_path().id != PATH_G_LOVER) - { - if ($effect[Stone-Faced].have_effect() == 0) - entry.url = "inventory.php?ftext=stone+wool"; - subentry.entries.listAppend(pluralise($item[stone wool]) + " available."); - } - if (my_path().id == PATH_G_LOVER) - { - subentry.modifiers.listAppend("-combat"); - if (__iotms_usable[lookupItem("genie bottle")]) - { - subentry.entries.listAppend("Genie wish for the \"stone-faced\" effect, then adventure in the temple."); - } - } - entry.subentries.listAppend(subentry); - } - else - { - if (true) - { - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - entry.subentries.listAppend(subentry); - } - //8 appears to be "finished"--"got stone triangle" - //7 appears to be "defeated the protector spirit"--"have stone sphere" - //2-6 appears to be "number of bowling balls used + 1" (only for bowling alley) - //1 appears to be "area unlocked" - boolean hidden_tavern_unlocked = get_property_ascension("hiddenTavernUnlock"); - boolean janitors_relocated_to_park = get_property_ascension("relocatePygmyJanitor"); - boolean have_machete = false; - - have_machete = __dense_liana_machete_items.available_amount() > 0; - int bowling_progress = get_property_int("hiddenBowlingAlleyProgress"); - int hospital_progress = get_property_int("hiddenHospitalProgress"); - int apartment_progress = get_property_int("hiddenApartmentProgress"); - int office_progress = get_property_int("hiddenOfficeProgress"); - - if (!base_quest_state.state_boolean["need machete for liana"]) - have_machete = true; - - boolean at_last_spirit = false; - - if (bowling_progress == 8 && hospital_progress == 8 && apartment_progress == 8 && office_progress == 8 || $item[stone triangle].available_amount() == 4) - { - at_last_spirit = true; - ChecklistSubentry subentry; - subentry.header = "Massive Ziggurat"; - //Instead of checking for four stone triangles, we check for the lack of all four stone spheres. That way it should detect properly after you fight the boss (presumably losing stone triangles), and lost? - - int spheres_available = $item[moss-covered stone sphere].available_amount() + $item[dripping stone sphere].available_amount() + $item[crackling stone sphere].available_amount() + $item[scorched stone sphere].available_amount(); - - if (spheres_available > 0) - { - subentry.entries.listAppend("Acquire stone triangles"); - } - else - { - if ($location[a massive ziggurat].numberOfDenseLianaFoughtInShrine() <3 && $location[a massive ziggurat].noncombatTurnsAttemptedInLocation() == 0) - { - generateHiddenAreaUnlockForShrine(subentry.entries,$location[a massive ziggurat]); - } - else - { - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - { - subentry.entries.listAppend("Talk to the protector spectre."); - } - else - { - subentry.modifiers.listAppend("elemental damage"); - subentry.entries.listAppend(`Fight the protector spectre! ({pluralise(3-$location[a massive ziggurat].numberOfDenseLianaFoughtInShrine(), "liana left", "lianas left")})`); - } - } - } - - entry.subentries.listAppend(subentry); - } - if (!at_last_spirit) - { - if ((!janitors_relocated_to_park && !$monster[pygmy janitor].is_banished()) || (!have_machete && my_path().id != PATH_POCKET_FAMILIARS)) - { - ChecklistSubentry subentry; - subentry.header = "Hidden Park"; - - subentry.modifiers.listAppend("-combat"); - if (!have_machete && my_path().id != PATH_POCKET_FAMILIARS) - { - int turns_remaining = MAX(0, 7 - $location[the hidden park].turnsAttemptedInLocation()); - string line; - line += "Adventure for "; - if (turns_remaining == 1) - line += "One More Turn"; - else - line += turns_remaining.int_to_wordy() + " more turns"; - line += " here for antique machete to clear dense lianas."; - if (canadia_available()) - line += "|Or potentially use muculent machete by acquiring forest tears. (kodama, Outskirts of Camp Logging Camp, 30% drop or clover)"; - subentry.entries.listAppend(line); - } - if (!janitors_relocated_to_park) - subentry.entries.listAppend("Potentially relocate janitors to park via non-combat."); - else - subentry.entries.listAppend("Acquire useful items from dumpster with -combat."); - if (__misc_state["have hipster"]) - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - if (__misc_state["free runs available"]) - subentry.modifiers.listAppend("free runs"); - if (my_basestat($stat[muscle]) < 62) - { - string line = "Will need " + (62 - my_basestat($stat[muscle])) + " more muscle to equip machete."; - subentry.entries.listAppend(line); - } - - entry.subentries.listAppend(subentry); - } - } - - if (apartment_progress < 8) { - ChecklistSubentry subentry; - subentry.header = "Hidden Apartment"; - if (apartment_progress == 7 || $item[moss-covered stone sphere].available_amount() > 0) { - subentry.entries.listAppend("Place moss-covered stone sphere in shrine."); - } else if (apartment_progress == 0) { - generateHiddenAreaUnlockForShrine(subentry.entries,$location[an overgrown shrine (Northwest)]); - } else { - int totalTurnsSpent = $location[the hidden apartment building].turns_spent; - - int delayForNextNoncombat; - - if (totalTurnsSpent < 9) { - delayForNextNoncombat = 8 - totalTurnsSpent; - } else { - delayForNextNoncombat = 7 - (totalTurnsSpent - 9) % 8; - } - - string [int] curseSources; - curseSources.listAppend("• Fighting a shaman."); - if (hidden_tavern_unlocked) { - curseSources.listAppend("• Drinking a cursed punch from the tavern."); - } else { - curseSources.listAppend("• " + HTMLGenerateSpanFont("Drinking a cursed punch from the tavern after you unlock it.", "grey")); - } - - if ($effect[thrice-cursed].have_effect() > 0) { - subentry.entries.listAppend("You're thrice-cursed. Fight the protector spirit!"); - } else if ($effect[twice-cursed].have_effect() > 0) { - subentry.entries.listAppend("Need 1 more curse. Get cursed by:" + curseSources.HTMLGenerateIndentedText()); - } else if ($effect[once-cursed].have_effect() > 0) { - subentry.entries.listAppend("Need 2 more curses. Get cursed by:" + curseSources.HTMLGenerateIndentedText()); - } else { - subentry.entries.listAppend("Need 3 more curses. Get cursed by:" + curseSources.HTMLGenerateIndentedText()); - } - - if (delayForNextNoncombat > 0) { - subentry.entries.listAppend("Delay for " + pluralise(delayForNextNoncombat, "turn", "turns") + " to fight spirit."); - } else { - subentry.entries.listAppend("Fight spirit next turn by choosing " + HTMLGenerateSpanOfClass("[Go to the Thrice-Cursed Penthouse]", "r_bold")); - } - - // Warnings - if (my_class() == $class[pastamancer] && my_thrall() == $thrall[Vampieroghi] && my_thrall().level >= 5) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Change your thrall - Vampieroghi will remove curses.", "red")); - } - - if ($effect[Ancient Fortitude].have_effect() > 0 && $effect[thrice-cursed].have_effect() == 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Remove Ancient Fortitude effect - you will not be cursed while that effect is up.", "red")); - } - - if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && $skill[Shake it off].skill_is_usable()) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Avoid using Shake It Off to heal", "red") + ", it'll remove the curse."); - } - - if (__misc_state["have hipster"]) { - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - } - } - entry.subentries.listAppend(subentry); - } - if (office_progress < 8) { - ChecklistSubentry subentry; - subentry.header = "Hidden Office"; - if (office_progress == 7 || $item[crackling stone sphere].available_amount() > 0) { - subentry.entries.listAppend("Place crackling stone sphere in shrine."); - } else if (office_progress == 0){ - generateHiddenAreaUnlockForShrine(subentry.entries,$location[an overgrown shrine (Northeast)]); - } else { - int numberOfFilesFound = $item[McClusky file (page 1)].available_amount() + $item[McClusky file (page 2)].available_amount() + $item[McClusky file (page 3)].available_amount() + $item[McClusky file (page 4)].available_amount() + $item[McClusky file (page 5)].available_amount(); - int numberOfFilesLeft = 5 - numberOfFilesFound; - - boolean hasMcCluskyFile = $item[McClusky file (complete)].available_amount() > 0; - boolean hasBoringBinderClip = $item[Boring binder clip].available_amount() > 0; - - int totalTurnsSpent = $location[the hidden office building].turns_spent; - - int delayForNextNoncombat = (totalTurnsSpent == 0) ? 5 : (4 - (totalTurnsSpent - 1) % 5); - - if (!hasMcCluskyFile && numberOfFilesLeft > 0) { - subentry.entries.listAppend("Kill " + pluralise(numberOfFilesLeft, "more pygmy witch accountant", "more pygmy witch accountants") + " for their files."); - } - - if (delayForNextNoncombat == 0) { - if (hasMcCluskyFile) { - subentry.entries.listAppend("Fight the Ancient protector spirit next turn by choosing " + HTMLGenerateSpanOfClass("[Knock on the boss's office door]", "r_bold")); - } else if (!hasBoringBinderClip) { - subentry.entries.listAppend("Find the binder clip next turn by choosing " + HTMLGenerateSpanOfClass("[Raid the supply cabinet]", "r_bold")); - } else { - subentry.entries.listAppend(HTMLGenerateSpanFont("Don't have the full McClusky files but noncombat is next turn. Consider adventuring in the apartment building.", "red")); - } - } else { - string message = "Delay for " + pluralise(delayForNextNoncombat, "turn", "turns") + " to"; - if (hasBoringBinderClip || hasMcCluskyFile) { - message += " fight spirit."; - } else { - message += " find boring binder clip."; - } - subentry.entries.listAppend(message); - } - - if (__misc_state["have hipster"]) { - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - } - } - entry.subentries.listAppend(subentry); - } - if (hospital_progress < 8) { - - ChecklistSubentry subentry; - subentry.header = "Hidden Hospital"; - - if (hospital_progress == 7 || $item[dripping stone sphere].available_amount() > 0) { - subentry.entries.listAppend("Place dripping stone sphere in shrine."); - } else if (hospital_progress == 0) { - generateHiddenAreaUnlockForShrine(subentry.entries,$location[an overgrown shrine (Southwest)]); - } else { - boolean [item] outfitPieces = $items[bloodied surgical dungarees,surgical mask,head mirror].makeConstantItemArrayMutable(); - - # TODO maybe support it differently, the scalpel will still drop in that case - if (__misc_state["can equip just about any weapon"]) { - outfitPieces[$item[half-size scalpel]] = true; - } - - if (__misc_state["Torso aware"]) { - outfitPieces[$item[surgical apron]] = true; - } - - item [int] ownedOutfitPieces; - item [int] unequippedOutfitPieces; - - string unownedOutfitMessage = "Fight pygmy surgeons to get surgeon gear:"; - foreach outfitPiece in outfitPieces { - if (outfitPiece.available_amount() > 0) { - ownedOutfitPieces.listAppend(outfitPiece); - - if (outfitPiece.equipped_amount() == 0) { - unequippedOutfitPieces.listAppend(outfitPiece); - } - } else { - unownedOutfitMessage += "|* • " + outfitPiece; - } - } - - if (unequippedOutfitPieces.count() > 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip your " + unequippedOutfitPieces.listJoinComponents(", ", "and") + " first.", "red")); - } - - if (ownedOutfitPieces.count() < 5) { - subentry.entries.listAppend(unownedOutfitMessage); - subentry.modifiers.listAppend("olfact surgeon"); - } - - int numberOfEquippedPieces = ownedOutfitPieces.count() - unequippedOutfitPieces.count(); - subentry.entries.listAppend((numberOfEquippedPieces * 10) + "% chance to fight spirit."); - - int totalTurnsSpent = $location[The Hidden Hospital].turns_spent; - subentry.entries.listAppend(HTMLGenerateSpanFont("Alternatively, burn " + (31 - totalTurnsSpent) + " more turns.", "grey")); - } - - entry.subentries.listAppend(subentry); - } - - if (bowling_progress < 8) { - - ChecklistSubentry subentry; - - subentry.header = "Hidden Bowling Alley"; - subentry.modifiers.listAppend("+150% item, olfact bowler"); - - if (bowling_progress == 7 || $item[scorched stone sphere].available_amount() > 0) { - subentry.entries.listAppend("Place scorched stone sphere in shrine."); - } else if (bowling_progress == 0) { - generateHiddenAreaUnlockForShrine(subentry.entries,$location[an overgrown shrine (southeast)]); - } else { - int numberOfRollsLeft = 6 - bowling_progress; - int bowlingBallsNeeded = numberOfRollsLeft - $item[bowling ball].available_amount_including_closet(); - int bowlingBallsInInventory = $item[bowling ball].available_amount(); - - if (bowlingBallsNeeded > 0) { - subentry.entries.listAppend("Find " + bowlingBallsNeeded + " more bowling balls by fighting pygmy bowlers."); - } - - if (numberOfRollsLeft > 0) { - subentry.entries.listAppend("Adventure " + numberOfRollsLeft + " more times with bowling balls to fight spirit."); - } - - if (hidden_tavern_unlocked) { - if (!$monster[drunk pygmy].is_banished()) { - if ($item[bowl of scorpions].item_amount() == 0) { - subentry.entries.listAppend(HTMLGenerateSpanFont("Buy bowl of scorpions from the Hidden Tavern to free run.", "red")); - } else { - subentry.entries.listAppend("Use bowl of scorpions on drunk pygmy for free run."); - } - } - } else { - subentry.entries.listAppend(HTMLGenerateSpanFont("Unlock the hidden tavern for free runs from drunk pygmies.", "grey")); - } - } - - entry.subentries.listAppend(subentry); - } - - if (!at_last_spirit) - { - if ($location[a massive ziggurat].numberOfDenseLianaFoughtInShrine() < 3) { - ChecklistSubentry subentry; - subentry.header = "Massive Ziggurat"; - generateHiddenAreaUnlockForShrine(subentry.entries,$location[a massive ziggurat]); - entry.subentries.listAppend(subentry); - } - - if (!hidden_tavern_unlocked && my_path().id != PATH_G_LOVER && my_path().id != PATH_BEES_HATE_YOU) - { - ChecklistSubentry subentry; - subentry.header = "Hidden Tavern"; - boolean should_output = true; - - if ($item[book of matches].available_amount() > 0) - subentry.entries.listAppend(HTMLGenerateSpanFont("Use book of matches.", "red")); - else - { - if (janitors_relocated_to_park) - subentry.entries.listAppend("Possibly acquire and use book of matches from janitors. (Pygmy janitors, Hidden Park, 20% drop)"); - else - subentry.entries.listAppend("Possibly acquire and use book of matches from janitors. (Pygmy janitors, everywhere in the hidden city, 20% drop)"); - - string [int] tavern_provides; - if (bowling_progress < 7 && __misc_state["free runs usable"]) - tavern_provides.listAppend("Free runs from drunk pygmys."); - if (__misc_state["can drink just about anything"]) - { - if (apartment_progress < 8) - tavern_provides.listAppend("Curses for hidden apartment."); - int adventures_given = 15; - if ($skill[the ode to booze].skill_is_usable()) - adventures_given += 6; - - if (my_path().id != PATH_SLOW_AND_STEADY) - tavern_provides.listAppend("Nightcap drink. (Fog Murderer for " + adventures_given + " adventures)"); - } - if (tavern_provides.count() > 0) - subentry.entries.listAppend("Hidden Tavern provides:|*" + tavern_provides.listJoinComponents("|*")); - else - should_output = false; //don't bother, no reason to... I think? - - } - if (should_output) - entry.subentries.listAppend(subentry); - } - } - } - - if (entry.subentries.count() > 0) { - task_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash b/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash deleted file mode 100644 index 108bfdc8..00000000 --- a/Source/relay/TourGuide/Quests/Level 11 - Hidden Temple.ash +++ /dev/null @@ -1,143 +0,0 @@ -void QLevel11HiddenTempleInit() -{ - QuestState state; - - if (get_property_ascension("lastTempleUnlock")) - QuestStateParseMafiaQuestPropertyValue(state, "finished"); - else if (__quest_state["Level 2"].startable) - { - QuestStateParseMafiaQuestPropertyValue(state, "started"); - } - else - QuestStateParseMafiaQuestPropertyValue(state, "unstarted"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_EXPLOSIONS) state.finished = true; - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Hidden Temple Unlock"; - state.image_name = "spooky forest"; - - __quest_state["Hidden Temple Unlock"] = state; -} - -void QLevel11HiddenTempleGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Hidden Temple Unlock"].in_progress) - return; - if (my_path().id == PATH_G_LOVER) return; - if (my_path().id == PATH_SEA) return; - - QuestState base_quest_state = __quest_state["Hidden Temple Unlock"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - - if (delayRemainingInLocation($location[the spooky forest]) > 0) - { - string hipster_text = ""; - if (__misc_state["have hipster"]) - { - hipster_text = " (use " + __misc_state_string["hipster name"] + ")"; - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - } - string line = "Delay for " + pluralise(delayRemainingInLocation($location[the spooky forest]), "turn", "turns") + hipster_text + "."; - subentry.entries.listAppend(line); - subentry.entries.listAppend("Run -combat after that."); - } - else - { - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("Run -combat in the spooky forest."); - } - if (__misc_state["free runs available"]) - { - subentry.modifiers.listAppend("free runs"); - subentry.entries.listAppend("Free run from low-stat monsters."); - } - - int ncs_remaining = 0; - - if ($item[spooky sapling].available_amount() == 0) - { - if (my_meat() < 100) - subentry.entries.listAppend("Obtain 100 meat for spooky sapling."); - else - subentry.entries.listAppend("Acquire spooky sapling.|*Follow the old road" + __html_right_arrow_character + "Talk to the hunter" + __html_right_arrow_character + "Buy a tree"); - ncs_remaining += 1; - } - - if ($item[tree-holed coin].available_amount() == 0) - { - if ($item[spooky temple map].available_amount() == 0) - { - //no coin, no map - subentry.entries.listAppend("Acquire tree-holed coin, then map.|*Explore the stream" + __html_right_arrow_character + "Squeeze into the cave"); - ncs_remaining += 2; - } - else - { - //no coin, have map, nothing to do here - } - } - else - { - if ($item[spooky temple map].available_amount() == 0) - { - //coin, no map - subentry.entries.listAppend("Acquire spooky temple map.|*Brave the dark thicket" + __html_right_arrow_character + "Follow the coin" + __html_right_arrow_character + "Insert coin to continue"); - - ncs_remaining += 1; - } - else - { - //wait, what? - subentry.entries.listAppend("how did we get here?"); - } - } - if ($item[spooky-gro fertilizer].item_amount() == 0) - { - subentry.entries.listAppend("Acquire spooky-gro fertilizer.|*Brave the dark thicket" + __html_right_arrow_character + "Investigate the dense foliage" + (in_hardcore() ? "" : "|*Or pull.")); - ncs_remaining += 1; - } - if ($item[spooky temple map].available_amount() > 0 && $item[spooky-gro fertilizer].item_amount() > 0 && $item[spooky sapling].available_amount() > 0) - { - subentry.modifiers.listClear(); - subentry.entries.listClear(); - subentry.entries.listAppend("Use the spooky temple map."); - } - - if (ncs_remaining > 0) - { - float spooky_forest_nc_rate = clampNormalf(1.0 - (85.0 + combat_rate_modifier()) / 100.0); - - float turns_remaining = -1.0; - float turns_per_nc = 7.0; - if (spooky_forest_nc_rate > 0.0) - turns_per_nc = MIN(7.0, 1.0 / spooky_forest_nc_rate); - - turns_remaining = ncs_remaining.to_float() * turns_per_nc; - turns_remaining += delayRemainingInLocation($location[the spooky forest]); - - subentry.entries.listAppend("~" + turns_remaining.roundForOutput(1) + " turns remain at " + combat_rate_modifier().floor() + "% combat."); - } - - if (my_level() < 6) - subentry.entries.listAppend("There's also another unlock quest at level six, but it's slower."); - else - subentry.entries.listAppend("There's also another unlock quest, but it's slower."); - - ChecklistEntry entry = ChecklistEntryMake(base_quest_state.image_name, "place.php?whichplace=woods", subentry, $locations[the spooky forest]); - entry.tags.id = "Council spooky forest hidden temple"; //ich... - - if (!__quest_state["Manor Unlock"].state_boolean["ballroom song effectively set"]) - { - entry.subentries[0].entries.listAppend(HTMLGenerateSpanOfClass("Wait until -combat ballroom song set.", "r_bold")); - future_task_entries.listAppend(entry); - } - else - { - task_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Quests/Level 11 - Manor.ash b/Source/relay/TourGuide/Quests/Level 11 - Manor.ash deleted file mode 100644 index fddd9043..00000000 --- a/Source/relay/TourGuide/Quests/Level 11 - Manor.ash +++ /dev/null @@ -1,309 +0,0 @@ -void QLevel11ManorInit() -{ - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL11Manor"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Lord Spookyraven Quest"; - state.image_name = "Spookyraven manor"; - - if (($items[2286,Headpiece of the Staff of Ed].available_amount() > 0 || to_item("2325").available_amount() > 0) && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) //eye of ed - QuestStateParseMafiaQuestPropertyValue(state, "finished"); - - - boolean use_fast_route = true; - if (!__misc_state["can equip just about any weapon"]) - use_fast_route = false; - if (my_path().id == PATH_NUCLEAR_AUTUMN && in_hardcore()) - use_fast_route = false; - if (in_bad_moon()) //This is possible, but certainly not plausible. - use_fast_route = false; - - state.state_boolean["Can use fast route"] = use_fast_route; - - __quest_state["Level 11 Manor"] = state; -} - -void QLevel11ManorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 11 Manor"].in_progress) - return; - if (__quest_state["Level 11"].mafia_internal_step <3 ) //strange bug where questL11MacGuffin = started, questL11Manor = step1 - return; - - QuestState base_quest_state = __quest_state["Level 11 Manor"]; - ChecklistSubentry subentry; - string url = ""; - subentry.header = base_quest_state.quest_name; - string image_name = base_quest_state.image_name; - if (true) - { - boolean use_fast_route = base_quest_state.state_boolean["Can use fast route"]; - boolean recipe_will_be_autoread = (($item[lord spookyraven's spectacles].available_amount() > 0) && use_fast_route) && get_property_boolean("autoCraft"); - boolean recipe_was_autoread_with_glasses = (get_property("spookyravenRecipeUsed") == "with_glasses"); - boolean recipe_was_autoread = recipe_was_autoread_with_glasses || (get_property("spookyravenRecipeUsed") == "no_glasses"); - //FIXME spectacles first? - if (!$location[the haunted ballroom].locationAvailable()) - return; - if (!$location[the haunted ballroom].noncombat_queue.contains_text("We'll All Be Flat") && base_quest_state.mafia_internal_step < 2) - { - url = "place.php?whichplace=manor2"; - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("Run -combat in the haunted ballroom."); - image_name = "Haunted Ballroom"; - if (delayRemainingInLocation($location[the haunted ballroom]) > 0) - { - string line = "Delay for " + pluralise(delayRemainingInLocation($location[the haunted ballroom]), "turn", "turns") + "."; - if (__misc_state["have hipster"]) - { - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - } - subentry.entries.listAppend(line); - } - } - else - { - url = "manor3.php"; - - if (use_fast_route && $item[lord spookyraven's spectacles].available_amount() == 0 && !recipe_was_autoread) - { - url = $location[the haunted bedroom].getClickableURLForLocation(); - subentry.entries.listAppend("Acquire Lord Spookyraven's spectacles from the haunted bedroom.|Unless you're using the slow route, in which case ignore this."); - image_name = "__item Lord Spookyraven's spectacles"; - } - else if ($item[recipe: mortar-dissolving solution].available_amount() == 0 && !__setting_debug_mode && !recipe_was_autoread) - { - if (recipe_will_be_autoread) - { - subentry.entries.listAppend("Click on the suspicious masonry in the basement."); - image_name = "__item recipe: mortar-dissolving solution"; - } - else if (use_fast_route && $item[lord spookyraven's spectacles].equipped_amount() == 0) - { - url = "inventory.php?ftext=lord+spookyraven's+spectacles"; - subentry.entries.listAppend("Equip Lord Spookyraven's Spectacles, click on the suspicious masonry in the basement, then read the recipe."); - image_name = "__item Lord Spookyraven's spectacles"; - } - else - { - subentry.entries.listAppend("Click on the suspicious masonry in the basement, then read the recipe."); - image_name = "__item recipe: mortar-dissolving solution"; - } - - } - else - { - //FIXME also make sure that is relevant when in the haunted bedroom/missing items - //FIXME detect the chamber being opened - boolean output_final_fight_info = base_quest_state.mafia_internal_step >= 4; - if (use_fast_route && !output_final_fight_info) - { - if ($item[wine bomb].available_amount() > 0) - { - output_final_fight_info = true; - } - else if ($item[unstable fulminate].available_amount() > 0) - { - string [int] tasks; - if ($item[unstable fulminate].equipped_amount() == 0) - { - url = "inventory.php?ftext=unstable+fulminate"; - tasks.listAppend(HTMLGenerateSpanFont("Equip unstable fulminate", "red")); - } - image_name = "monstrous boiler"; - - int ml_needed = 82; - int inherent_ml_modifier = 0; - //if (my_path().id == PATH_HEAVY_RAINS) //need to test this - //inherent_ml_modifier = 82 - 40; //maybe? - ml_needed -= inherent_ml_modifier; - tasks.listAppend("adventure in the haunted boiler room with +" + ml_needed + " ML"); - subentry.modifiers.listAppend("+" + ml_needed + " ML"); - - subentry.entries.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - - int current_ml = $location[The Haunted Boiler Room].monster_level_adjustment_for_location(); - - if (current_ml < ml_needed) - { - subentry.modifiers.listAppend("olfact boiler"); - } - else - { - string [int] banish_targets; - if (!$monster[coaltergeist].is_banished()) - banish_targets.listAppend("coaltergeist"); - if (!$monster[steam elemental].is_banished()) - banish_targets.listAppend("steam elemental"); - if (banish_targets.count() > 0) - subentry.modifiers.listAppend("banish " + banish_targets.listJoinComponents(", ")); - } - - float degrees_per_fight = 10 + floor(MAX((current_ml + inherent_ml_modifier).to_float(), 0.0) / 2.0); - - int boilers_needed = clampi(ceil(50.1 / degrees_per_fight.to_float()), 1, 6); - - monster boiler_monster = $monster[monstrous boiler]; - float [monster] appearance_rates = $location[The Haunted Boiler Room].appearance_rates_adjusted(); - - - float boiler_per_adventure = appearance_rates[boiler_monster] / 100.0; - - if (boiler_per_adventure > 0.0) - { - float turns_needed = boilers_needed.to_float() / boiler_per_adventure; - subentry.entries.listAppend("~" + turns_needed.roundForOutput(1) + " total turns to charge fulminate."); - } - else if ((appearance_rates contains boiler_monster) && boiler_monster != $monster[none]) - { - subentry.entries.listAppend("Seemingly unable to find boilers. They miss you. They look up to you."); - } - } - else if (!recipe_was_autoread_with_glasses) - { - subentry.entries.listAppend("Need to " + ($item[lord spookyraven's spectacles].available_amount() == 0 ? "acquire and " : "") + "equip Lord Spookyraven's spectacles and read the recipe before you can use the quick route."); - } - else - { - //FIXME implement this differently? - boolean need_item_modifier = false; - if ($item[bottle of Chateau de Vinegar].available_amount() == 0) - { - //+booze? +food seemingly doesn't work on this one - subentry.entries.listAppend("Find bottle of Chateau de Vinegar from possessed wine rack in the haunted wine cellar."); - subentry.modifiers.listAppend("olfact wine rack"); - need_item_modifier = true; - image_name = "possessed wine rack"; - } - if ($item[blasting soda].available_amount() == 0) - { - subentry.entries.listAppend("Find blasting soda from the cabinet in the haunted laundry room."); - subentry.modifiers.listAppend("olfact cabinet"); - need_item_modifier = true; - - if (image_name == base_quest_state.image_name) - image_name = "cabinet of Dr. Limpieza"; - } - if (need_item_modifier) - { - subentry.modifiers.listPrepend("+1900% item"); //+item, increasing drop - subentry.entries.listAppend("Base drop rate is 5%, then 10%, 15%, etc, for each wine rack/cabinet defeated, individually."); - } - - if ($item[bottle of Chateau de Vinegar].available_amount() > 0 && $item[blasting soda].available_amount() > 0) - { - url = "craft.php?mode=cook"; - string line = "Cook unstable fulminate."; - if (!__misc_state["can cook for free"]) - line += " (1 adventure)"; - subentry.entries.listAppend(line); - image_name = "__item unstable fulminate"; - } - } - } - if (!output_final_fight_info) - { - item [location] searchables; - searchables[$location[the haunted kitchen]] = $item[loosening powder]; - searchables[$location[the haunted conservatory]] = $item[powdered castoreum]; - searchables[$location[the haunted bathroom]] = $item[drain dissolver]; - searchables[$location[the haunted gallery]] = $item[triple-distilled turpentine]; - searchables[$location[the haunted laboratory]] = $item[detartrated anhydrous sublicalc]; - searchables[$location[the haunted storage room]] = $item[triatomaceous dust]; - - - item [location] missing_searchables; - foreach l in searchables - { - item it = searchables[l]; - if (it.available_amount() == 0) - missing_searchables[l] = it; - } - - if (missing_searchables.count() > 0) - { - string [int] places; - foreach l in missing_searchables - { - item it = searchables[l]; - //places.listAppend(it.capitaliseFirstLetter() + " in " + l + "."); - places.listAppend(l.to_string().replace_string("The Haunted ", "")); - } - string line = "Scavenger hunt! "; - if (use_fast_route) - line = "Alternatively, scavenger hunt! (likely much slower)|*"; - //line += "Go search for:|*" + places.listJoinComponents("
|*"); - line += "Go search in the Haunted " + places.listJoinComponents(", ", "and") + "."; - subentry.entries.listAppend(line); - /*if (!recipe_was_autoread) - subentry.entries.listAppend("Read the recipe.");*/ - - //are these scheduled, or regular NCs? - //assuming scheduled for now - if (__misc_state["free runs available"]) - { - subentry.modifiers.listAppend("free runs"); - } - if (__misc_state["have hipster"]) - { - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - } - } - else - { - subentry.entries.listClear(); - subentry.modifiers.listClear(); - output_final_fight_info = true; - } - - } - if (output_final_fight_info) - { - image_name = "Demon Summon"; - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - { - subentry.entries.listAppend("Talk to Lord Spookyraven."); - } - else if (my_path().id == PATH_VAMPIRE) - { - subentry.entries.listAppend("Fight the path-specific boss."); - } - else - { - subentry.modifiers.listAppend("elemental resistance"); - subentry.entries.listAppend("Fight Lord Spookyraven."); - - if ($effect[Red Door Syndrome].have_effect() == 0 && my_meat() > 1000 && black_market_available() && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING && my_path().id != PATH_POCKET_FAMILIARS && $item[can of black paint].item_is_usable()) - { - subentry.entries.listAppend("A can of black paint can help with fighting him." + (my_meat() < 20000 ? " Bit pricy. (1k meat)" : "")); - } - } - } - //This is covered elsewhere, in that mess of if statements up there. - /*if (use_fast_route && !recipe_was_autoread_with_glasses) - { - if ($item[unstable fulminate].available_amount() == 0 && !output_final_fight_info && $item[bottle of Chateau de Vinegar].available_amount() == 0 && $item[bottle of Chateau de Vinegar].available_amount() == 0 && !recipe_will_be_autoread) - subentry.entries.listAppend("Remember to wear Spookyraven's spectacles/read the recipe if you haven't."); - } - else if (!recipe_was_autoread) - subentry.entries.listAppend("Remember to read the recipe if you haven't.");*/ - } - } - } - - boolean [location] relevant_locations; - relevant_locations[$location[the haunted ballroom]] = true; - relevant_locations[$location[summoning chamber]] = true; - relevant_locations[$location[the haunted wine cellar]] = true; - relevant_locations[$location[The Haunted Boiler Room]] = true; - relevant_locations[$location[The Haunted Laundry Room]] = true; - foreach l in $locations[the haunted kitchen,the haunted conservatory,the haunted bathroom,the haunted gallery,the haunted laboratory,the haunted storage room] - relevant_locations[l] = true; - - - task_entries.listAppend(ChecklistEntryMake(image_name, url, subentry, relevant_locations).ChecklistEntrySetIDTag("Council L11 quest spookyraven manor")); -} diff --git a/Source/relay/TourGuide/Quests/Level 11 - Palindome.ash b/Source/relay/TourGuide/Quests/Level 11 - Palindome.ash deleted file mode 100644 index cf94dc0d..00000000 --- a/Source/relay/TourGuide/Quests/Level 11 - Palindome.ash +++ /dev/null @@ -1,336 +0,0 @@ -void QLevel11PalindomeInit() -{ - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL11Palindome"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Palindome Quest"; - state.image_name = "Palindome"; - - state.state_boolean["Need instant camera"] = false; - if ($item[photograph of a dog].available_amount() + $item[disposable instant camera].available_amount() == 0 && state.mafia_internal_step < 3) - state.state_boolean["Need instant camera"] = true; - if (7270.to_item().available_amount() > 0 || my_path().id == PATH_POCKET_FAMILIARS || my_path().id == PATH_G_LOVER) - state.state_boolean["Need instant camera"] = false; - - state.state_boolean["dr. awkward's office unlocked"] = false; - if (state.mafia_internal_step > 2) - state.state_boolean["dr. awkward's office unlocked"] = true; - if (get_property_int("palindomeDudesDefeated") >= 5 && 7262.to_item().available_amount() == 0) //inference - state.state_boolean["dr. awkward's office unlocked"] = true; - __quest_state["Level 11 Palindome"] = state; -} - -void QLevel11PalindomeGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //FIXME add whitey's grove fallthrough - - if (!__quest_state["Level 11 Palindome"].in_progress && __quest_state["Level 11"].mafia_internal_step <3) //questL11Palindome unstarted until uncertain time - return; - if (__quest_state["Level 11 Palindome"].finished) - return; - if (__quest_state["Level 11"].finished) - return; - if (__quest_state["Level 11"].mafia_internal_step <3 ) - return; - if (($item[Staff of Ed\, almost].available_amount() > 0 || $item[2325].available_amount() > 0 || $item[2268].available_amount() > 0) && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) - return; - - QuestState base_quest_state = __quest_state["Level 11 Palindome"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - string url; - - if (base_quest_state.mafia_internal_step < 2 && $item[talisman o' namsilat].available_amount() == 0 && $items[Copperhead Charm,Copperhead Charm (rampant)].items_missing().count() == 0) { - url = "craft.php?mode=combine"; - subentry.entries.listAppend("Paste the two copperhead charms together to acquire the talisman o' nam."); - } else if (base_quest_state.mafia_internal_step < 2 && $item[talisman o' namsilat].available_amount() == 0) { - //1 -> find palindome - string [int] quests; - if (!__quest_state["Level 11 Shen"].finished) - quests.listAppend("copperhead"); - if (!__quest_state["Level 11 Ron"].finished) - quests.listAppend("zeppelin"); - subentry.entries.listAppend("Find the palindome by completing the " + quests.listJoinComponents("/") + " quest."); - } else { - url = "place.php?whichplace=palindome"; - if ($item[talisman o' namsilat].equipped_amount() == 0) - url = "inventory.php?ftext=talisman+o'+namsilat"; - - - /* - Quest steps: - Adventure in palindome, acquire: - photograph of a dog (7263) by taking a picture of one of the racecar twins(?) with a disposable instant camera - photograph of an ostrich egg (7265) - photograph of a red nugget (7264) - photograph of god - stunt nuts for wet stunt nut stew - "I Love Me, Vol. I" (7262) (dropped from monster, possibly drab bard?, possibly after rest are available?) - Use I love me, volume 1. This removes it from your inventory, and unlocks the office. - Arrange the photographs on the shelf: - god, red nugget, dog, ostrich egg - This gives 2 Love Me, Vol. 2 (7270) - Read it to unlock mr. alarm in left office. It will disappear. - He'll tell you to go acquire wet stunt nut stew. Adventure in whitey's grove as per usual. - Cook wet stunt nut stew. - Go talk to mr. alarm. He'll give a mega gem. - Go fight Dr. Awkward with both equipped. - - */ - - if ($item[mega gem].available_amount() > 0 || base_quest_state.mafia_internal_step == 5) - { - //5 -> fight dr. awkward - string [int] tasks; - if ($item[talisman o' namsilat].equipped_amount() == 0) - tasks.listAppend("equip the Talisman o' Nam"); - if ($item[mega gem].equipped_amount() == 0) - tasks.listAppend("equip the Mega Gem"); - - tasks.listAppend("fight Dr. Awkward in his office"); - subentry.entries.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - } - else if (base_quest_state.mafia_internal_step == 3 && 7270.to_item().available_amount() > 0 && false) - { - //doesn't seem to work? - subentry.entries.listAppend("Use 2 Love Me, Vol. 2, then talk to Mr. Alarm in his office."); - } - else if (base_quest_state.mafia_internal_step == 4 || base_quest_state.mafia_internal_step == 3) - { - //4 -> acquire wet stunt nut stew, give to mr. alarm - //FIXME handle alternate route - //step3 not supported yet, so we have this instead: - if (base_quest_state.mafia_internal_step == 3) - { - if (!(7270.to_item().available_amount() > 0 && false)) - subentry.entries.listAppend("Use 2 Love Me, Vol. 2, then talk to Mr. Alarm in his office. Then:"); - } - - if ($item[wet stunt nut stew].available_amount() == 0) - { - if (($item[bird rib].available_amount() > 0 && $item[lion oil].available_amount() > 0 || $item[wet stew].available_amount() > 0) && $item[stunt nuts].available_amount() > 0) - { - url = "craft.php?mode=cook"; - subentry.entries.listAppend("Cook wet stunt nut stew."); - } - else - { - url = "place.php?whichplace=woods"; - subentry.entries.listAppend("Acquire and make wet stunt nut stew."); - if ($item[wet stunt nut stew].available_amount() == 0 && $item[stunt nuts].available_amount() == 0) - subentry.entries.listAppend("Acquire stunt nuts from Bob Racecar or Racecar Bob in Palindome. (30% drop)"); - if ($item[wet stew].available_amount() == 0 && ($item[bird rib].available_amount() == 0 || $item[lion oil].available_amount() == 0)) - { - string [int] components; - monster [int] monsters_need_to_meet; - if ($item[bird rib].available_amount() == 0) - { - components.listAppend($item[bird rib]); - monsters_need_to_meet.listAppend($monster[whitesnake]); - } - if ($item[lion oil].available_amount() == 0) - { - components.listAppend($item[lion oil]); - monsters_need_to_meet.listAppend($monster[white lion]); - } - string line = "Adventure in Whitey's Grove to acquire " + components.listJoinComponents("", "and") + "."; - - line += "|"; - int food_drop_have = $location[whitey's grove].item_drop_modifier_for_location() + numeric_modifier("food drop"); - if (food_drop_have >= 300.0) - { - line += "Have +300% item"; - } - else - { - line += HTMLGenerateSpanFont("Need +300% item", "red") + " (missing " + (300 - food_drop_have) + "%)"; - } - line += " and +combat."; - if (familiar_is_usable($familiar[jumpsuited hound dog])) - line += " (hound dog is useful for this)"; - subentry.entries.listAppend(line); - - if ($item[white page].available_amount() > 0) - subentry.entries.listAppend("Can use your white pages to dial up a " + monsters_need_to_meet.listJoinComponents(", ", "or a") + "."); - - subentry.modifiers.listAppend("+combat"); - subentry.modifiers.listAppend("+300% item/food drop"); - if (__quest_state["Level 6"].finished && !get_property_boolean("friarsBlessingReceived")) - { - subentry.entries.listAppend("Can use friars blessing for +30% food drop."); - } - if ($item[Gene Tonic: Goblin].available_amount() > 0 && $effect[Human-Goblin Hybrid].have_effect() == 0) - { - subentry.entries.listAppend("Use goblin gene tonic for +50% food drop."); - } - if (!in_hardcore()) - subentry.entries.listAppend("Or pull wet stew."); - } - subentry.entries.listAppend("Or try the alternate route in the Palindome."); - } - } - else - { - subentry.entries.listAppend("Talk to Mr. Alarm."); - if ($item[talisman o' namsilat].equipped_amount() == 0) - subentry.entries.listAppend("Equip the Talisman o' Nam."); - } - //if (7270.to_item() != $item[none] && 7270.to_item().available_amount() > 0) - //url = "place.php?whichplace=palindome"; - } - else if (base_quest_state.mafia_internal_step == 3 || 7270.to_item().available_amount() > 0) - { - string [int] tasks; - //talk to mr. alarm to unlock whitey's grove - if (7270.to_item().available_amount() > 0) - { - url = "inventory.php?ftext=2+love+me"; - tasks.listAppend("use 2 Love Me, Vol. 2"); - } - if ($item[wet stunt nut stew].available_amount() > 0) - tasks.listAppend("talk to Mr. Alarm"); - else - tasks.listAppend("talk to Mr. Alarm to unlock Whitey's Grove"); - - subentry.entries.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - if ($item[talisman o' namsilat].equipped_amount() == 0) - subentry.entries.listAppend("Equip the Talisman o' Nam."); - } - else - { - boolean dr_awkwards_office_unlocked = base_quest_state.state_boolean["dr. awkward's office unlocked"]; //no way to track this at the moment - string single_entry_mode = ""; - boolean need_to_adventure_in_palindome = false; - boolean need_palindome_location = true; - - //Need: - //√Wet stunt nut stew / stunt nuts - //√"I Love Me, Vol. I" (7262) - //√instant camera -> 7263 photograph of a dog - //√7264 photograph of a red nugget - //√7265 photograph of an ostrich egg - //√photograph of god - subentry.entries.listAppend("Adventure in the palindome."); - - if ($item[photograph of a dog].available_amount() == 0) - { - if (my_path().id == PATH_POCKET_FAMILIARS || my_path().id == PATH_G_LOVER) - { - need_to_adventure_in_palindome = true; - subentry.entries.listAppend("Defeat Bob Racecar or Racecar Bobs until you acquire the photograph of a dog."); - } - else if ($item[disposable instant camera].available_amount() == 0) - { - subentry.modifiers.listClear(); - url = $location[the haunted bedroom].getClickableURLForLocation(); - single_entry_mode = "Adventure in the haunted bedroom for a disposable instant camera."; - int monsters_in_zone = 0; - foreach m in $monsters[animated mahogany nightstand,animated ornate nightstand,animated rustic nightstand,elegant animated nightstand,Wardröb nightstand] - { - //monster m = s.to_monster(); - if (!m.is_banished() || m == $monster[none]) - monsters_in_zone += 1; - } - if (monsters_in_zone == 0) - monsters_in_zone = 5; - - if (!in_hardcore() && (get_property("questM21Dance") == "finished" || $location[the haunted ballroom].turnsAttemptedInLocation() > 0 || $item[Lady Spookyraven's finest gown].available_amount() > 0)) - single_entry_mode += "|Or pull for it. (saves " + pluraliseWordy(monsters_in_zone, "turn", "turns") + ")"; - need_palindome_location = false; - } - else - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Photograph Bob Racecar or Racecar Bob", "red") + " with disposable instant camera."); - need_to_adventure_in_palindome = true; - } - } - - if ($item[stunt nuts].available_amount() + $item[wet stunt nut stew].available_amount() == 0 && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) - { - subentry.modifiers.listAppend("+234% item"); - subentry.entries.listAppend("Possibly acquire stunt nuts from Bob Racecar or Racecar Bob. (30% drop)"); - need_to_adventure_in_palindome = true; - } - - - string [int] missing_ncs; - if ($item[photograph of a red nugget].available_amount() == 0) - { - missing_ncs.listAppend("photograph of a red nugget"); - } - if ($item[photograph of an ostrich egg].available_amount() == 0) - { - missing_ncs.listAppend("photograph of an ostrich egg"); - } - if ($item[photograph of god].available_amount() == 0) - { - missing_ncs.listAppend("photograph of god"); - } - if (missing_ncs.count() > 0) - { - subentry.modifiers.listAppend("-combat"); //initial spading suggests at least two of these are affected by -combat, need more data - subentry.entries.listAppend("Find " + missing_ncs.listJoinComponents(", ", "and") + " from non-combats, run -combat"); - need_to_adventure_in_palindome = true; - } - - - - - //This must be after all other need_to_adventure_in_palindome checks: - if (7262.to_item().available_amount() == 0 && !dr_awkwards_office_unlocked) //I love me, Vol. I - { - int dudes_left = clampi(5 - get_property_int("palindomeDudesDefeated"), 0, 5); - - if (__misc_state["have olfaction equivalent"] && __misc_state_string["olfaction equivalent monster"] != "Racecar Bob" && __misc_state_string["olfaction equivalent monster"] != "Bob Racecar" && __misc_state_string["olfaction equivalent monster"] != "Drab Bard" && dudes_left > 1) - { - subentry.modifiers.listAppend("olfact racecar"); - subentry.entries.listAppend("Olfact Bob Racecar or Racecar Bob."); - } - subentry.entries.listAppend("Defeat " + pluraliseWordy(dudes_left, "more dude", "more dudes") + " in the palindome."); - need_to_adventure_in_palindome = true; - } - else if (7262.to_item().available_amount() > 0) - { - if (!need_to_adventure_in_palindome) - { - url = "inventory.php?ftext=I+love+me"; - subentry.entries.listAppend("Use I Love Me, Vol. I. Then place the photographs in Dr. Awkward's Office."); - } - else - { - subentry.entries.listAppend("Have I Love Me, Vol. I. Collect photographs and such in the Palindome first."); - } - } - - if (!need_to_adventure_in_palindome) - { - if (subentry.entries contains 0) - remove subentry.entries[0]; //remove "Adventure in the palindome" by index - this is hacky - } - - if (!need_to_adventure_in_palindome && dr_awkwards_office_unlocked) - { - subentry.modifiers.listClear(); - single_entry_mode = "Place items on shelves in Dr. Awkward's office.|Order is god, red nugget, dog, and ostrich egg."; - } - - if (single_entry_mode != "") - { - subentry.entries.listClear(); - subentry.entries.listAppend(single_entry_mode); - } - if (need_palindome_location && $item[talisman o' namsilat].equipped_amount() == 0) - subentry.entries.listAppend("Equip the Talisman o' Nam."); - } - } - - boolean [location] relevant_locations = makeConstantLocationArrayMutable($locations[the poop deck, belowdecks,cobb's knob laboratory,whitey's grove]); - relevant_locations[$location[Inside the Palindome]] = true; - - task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, relevant_locations).ChecklistEntrySetIDTag("Council L11 quest palindome")); -} diff --git a/Source/relay/TourGuide/Quests/Level 11 - Pyramid.ash b/Source/relay/TourGuide/Quests/Level 11 - Pyramid.ash deleted file mode 100644 index b7038427..00000000 --- a/Source/relay/TourGuide/Quests/Level 11 - Pyramid.ash +++ /dev/null @@ -1,231 +0,0 @@ - -void QLevel11PyramidInit() -{ - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL11Pyramid"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Pyramid Quest"; - state.image_name = "Pyramid"; - __quest_state["Level 11 Pyramid"] = state; -} - -void QLevel11PyramidGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 11"].in_progress) - return; - if (__quest_state["Level 11 Pyramid"].finished) - return; - - QuestState base_quest_state = __quest_state["Level 11 Pyramid"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - string url = ""; - if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"]) - return; - //Desert explored. - - boolean definitely_have_staff_of_ed = false; - if (2286.to_item().available_amount() > 0 && 2268.to_item().available_amount() > 0 && 2180.to_item().available_amount() > 0) - definitely_have_staff_of_ed = true; - - if ($item[2325].available_amount() + $item[2325].creatable_amount() + $item[7961].available_amount() + $item[7961].creatable_amount() == 0 && !definitely_have_staff_of_ed) - { - //Staff of ed. - //subentry.entries.listAppend("Find the Staff of Ed."); - future_task_entries.listAppend(ChecklistEntryMake("Pyramid", "", ChecklistSubentryMake("Head down the pyramid", "", "Find the Staff of Ed."))); - return; - } - else if (!base_quest_state.in_progress && $location[the upper chamber].turnsAttemptedInLocation() == 0) - { - url = "place.php?whichplace=desertbeach"; - subentry.entries.listAppend("Visit the pyramid, click on it."); - } - else - { - /* - How the new pyramid seemingly works: - Adventure six times in the upper chamber with -combat. (delay, free runs relevant) This unlocks the middle chamber with the adventure "Down Dooby-Doo Down Down" - Adventure six times in the middle chamber with +400% item and banishes. (delay, free runs relevant). This unlocks the lower chamber. - Adventure five times in the middle chamber with +400% item and banishes. (delay, free runs relevant) This unlocks the control chamber. - After that, you handle the control chamber and solve the puzzle. One tomb ratchet/crumbling wooden wheel advances the puzzle by one step. So, you can farm tomb ratchets (+item) or wooden wheels (-combat). There's so much delay in the middle chamber though... - "Under Control" is the control room unlock. - - */ - //middleChamberUnlock, lowerChamberUnlock, controlRoomUnlock implemented - url = "place.php?whichplace=pyramid"; - boolean done_with_wheel_turning = false; //FIXME set this - boolean should_generate_control_room_information = false; - boolean ed_chamber_open = get_property_boolean("pyramidBombUsed"); - if (get_property_boolean("middleChamberUnlock") || $location[the middle chamber].turnsAttemptedInLocation() > 0 || $location[the upper chamber].noncombat_queue.contains_text("Down Dooby-Doo Down Down")) - { - //middle chamber unlocked: - if (get_property_boolean("controlRoomUnlock") || $location[the middle chamber].noncombat_queue.contains_text("Under Control")) - { - //control room unlocked: - should_generate_control_room_information = true; - //FIXME implement this - //FIXME suggest the better route - subentry.modifiers.listAppend("+400% item OR -combat"); - subentry.modifiers.listAppend("olfact tomb rats"); - subentry.entries.listAppend("Can find crumbling wooden wheels in the upper chamber (-combat), or tomb ratchets in the middle chamber (+400% item, olfact rats)"); - } - /*else if (get_property_boolean("lowerChamberUnlock") || $location[the middle chamber].noncombat_queue.contains_text("Further Down Dooby-Doo Down Down")) - { - //lower chamber unlocked: - subentry.entries.listAppend("Adventure in the middle chamber for five total turns to unlock the control room."); - subentry.modifiers.listAppend("+400% item"); - subentry.modifiers.listAppend("olfact tomb rats"); - if (__misc_state["have hipster"]) - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - if (__misc_state["free runs available"]) - subentry.modifiers.listAppend("free runs"); - }*/ - else - { - //unlock lower chamber: - int turns_spent = $location[the middle chamber].turns_spent; - - int turns_remaining = MAX(0, 11 - turns_spent); - subentry.entries.listAppend("Adventure in the middle chamber for " + pluraliseWordy(turns_remaining, "more turn", "more turns") + " to unlock the control room."); - - subentry.modifiers.listAppend("+400% item"); - subentry.modifiers.listAppend("olfact tomb rats"); - if (__misc_state["have hipster"]) - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - if (__misc_state["free runs available"]) - subentry.modifiers.listAppend("free runs"); - - } - if ($item[tangle of rat tails].available_amount() > 0) - subentry.entries.listAppend("Use tangle of rat tails against tomb rats for more tomb ratchets."); - if (my_path().id == PATH_HEAVY_RAINS && $item[catfish whiskers].available_amount() > 0 && $effect[Fishy Whiskers].have_effect() == 0 && $item[tangle of rat tails].available_amount() > 0) - subentry.entries.listAppend("Possibly use catfish whiskers to find more tomb ratchets."); - } - else - { - //unlock middle chamber: - int turns_spent = $location[the upper chamber].turns_spent; - int turns_remaining = MAX(0, 6 - turns_spent); - subentry.entries.listAppend("Adventure in the upper chamber for " + pluraliseWordy(turns_remaining, "more turn", "more turns") + " to unlock the middle chamber."); - subentry.modifiers.listAppend("-combat"); - if (__misc_state["have hipster"]) - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - if (__misc_state["free runs available"]) - subentry.modifiers.listAppend("free runs"); - } - - - //Generate spin cycle: - - //this is not very good code: - boolean have_pyramid_position = false; - int pyramid_position = get_property_int("pyramidPosition"); - - //Uncertain: - //if (get_property_ascension("lastPyramidReset")) - if (pyramid_position > 0) //does this work? - have_pyramid_position = true; - - //I think there are... five positions? - //1=Ed, 2=bad, 3=vending machine, 4=token, 5=bad - int next_position_needed = -1; - int additional_turns_after_that = 0; - string task; - done_with_wheel_turning = false; - if (2318.to_item().available_amount() > 0 || ed_chamber_open) - { - //need 1 - next_position_needed = 1; - additional_turns_after_that = 0; - - int ed_ml = 180 + monster_level_adjustment_for_location($location[the lower chambers]); - task = "fight Ed in the lower chambers"; - if (ed_ml > my_buffedstat($stat[moxie])) - task += " (" + ed_ml + " attack)"; - - if (ed_chamber_open) - done_with_wheel_turning = true; - } - else if ($item[ancient bronze token].available_amount() > 0) - { - //need 3 - next_position_needed = 3; - additional_turns_after_that = 3; - task = "acquire " + 2318.to_item().to_string() + " in lower chamber"; - } - else - { - //need 4 - next_position_needed = 4; - additional_turns_after_that = 3 + 4; - task = "acquire token in lower chamber"; - } - - int spins_needed = (next_position_needed - pyramid_position + 10) % 5; - int total_spins_needed = spins_needed + additional_turns_after_that; - int spins_available = $item[tomb ratchet].available_amount() + $item[crumbling wooden wheel].available_amount(); - - int extra_spin_sources_needed = clampi(total_spins_needed - spins_available, 0, 11); - - //Pyramid unlocked: - if (should_generate_control_room_information) - { - - string [int] tasks; - if (spins_needed > 0) - { - if (spins_needed == 1) - tasks.listAppend("spin the pyramid One More Time"); - else - tasks.listAppend("spin the pyramid " + spins_needed.int_to_wordy() + " times"); - if ($item[tomb ratchet].available_amount() + $item[crumbling wooden wheel].available_amount() > 0) - url = "place.php?whichplace=pyramid&action=pyramid_control"; - } - tasks.listAppend(task); - - - if (!have_pyramid_position) - { - tasks.listClear(); - //tasks.listAppend("look at the pyramid"); //I dunno - } - - if (ed_chamber_open && done_with_wheel_turning) - { - subentry.modifiers.listClear(); - subentry.entries.listClear(); - } - - if (tasks.count() > 0) - subentry.entries.listPrepend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - else - subentry.entries.listAppend("Spin the control room, search the lower chambers! Then fight Ed."); - - if (ed_chamber_open && my_path().id == PATH_EXPLOSIONS && lookupItem("low-pressure oxygen tank").equipped_amount() == 0) - { - subentry.modifiers.listAppend("+hp regen"); - subentry.entries.listAppend("Keep +hp regen up, so you survive the multi-round fight without the oxygen tank?"); - } - } - - if (!done_with_wheel_turning) - { - if (extra_spin_sources_needed > 0) - subentry.entries.listAppend("Need " + HTMLGenerateSpanFont(int_to_wordy(extra_spin_sources_needed), "red") + " more ratchet/wheel" + ((extra_spin_sources_needed > 1) ? "s" : "") + "."); - else - subentry.entries.listAppend("Have enough wheels."); - /*if (amount > 0) - subentry.entries.listAppend(pluralise(amount, "wheel turn", "wheel turns") + " available.");*/ - if ($item[tangle of rat tails].available_amount() > 0 && extra_spin_sources_needed > 0) - subentry.entries.listAppend(pluralise($item[tangle of rat tails]) + " available."); - } - - } - - task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the upper chamber,the lower chambers, the middle chamber]).ChecklistEntrySetIDTag("Council L11 quest pyramid")); -} diff --git a/Source/relay/TourGuide/Quests/Level 11.ash b/Source/relay/TourGuide/Quests/Level 11.ash deleted file mode 100644 index 14573ba6..00000000 --- a/Source/relay/TourGuide/Quests/Level 11.ash +++ /dev/null @@ -1,229 +0,0 @@ -import "relay/TourGuide/Quests/Level 11 - Copperhead.ash"; -import "relay/TourGuide/Quests/Level 11 - Pyramid.ash"; -import "relay/TourGuide/Quests/Level 11 - Desert.ash"; -import "relay/TourGuide/Quests/Level 11 - Palindome.ash"; -import "relay/TourGuide/Quests/Level 11 - Manor.ash"; -import "relay/TourGuide/Quests/Level 11 - Hidden City.ash"; -import "relay/TourGuide/Quests/Level 11 - Hidden Temple.ash"; - -void QLevel11Init() -{ - //questL11MacGuffin, questL11Manor, questL11Palindome, questL11Pyramid, questL11Worship - //hiddenApartmentProgress, hiddenBowlingAlleyProgress, hiddenHospitalProgress, hiddenOfficeProgress, hiddenTavernUnlock - //relocatePygmyJanitor, relocatePygmyLawyer - - - /* - gnasirProgress is a bitmap of things you've done with Gnasir to advance desert exploration: - - stone rose = 1 - black paint = 2 - killing jar = 4 - worm-riding manual pages (15) = 8 - successful wormride = 16 - */ - if (true) - { - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL11MacGuffin"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "MacGuffin Quest"; - state.image_name = "MacGuffin"; - state.council_quest = true; - - if (my_level() >= 11 || my_path().id == PATH_EXPLOSIONS) - state.startable = true; - - state.state_boolean["have diary"] = state.mafia_internal_step >= 3; - - __quest_state["Level 11"] = state; - __quest_state["MacGuffin"] = state; - } - - QLevel11CopperheadInit(); - QLevel11PyramidInit(); - QLevel11DesertInit(); - QLevel11PalindomeInit(); - QLevel11ManorInit(); - QLevel11HiddenCityInit(); - QLevel11HiddenTempleInit(); -} - -void QLevel11BaseGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 11"].in_progress) - return; - - QuestState base_quest_state = __quest_state["Level 11"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - string url = ""; - string image_name = base_quest_state.image_name; - boolean make_entry_future = false; - - if (base_quest_state.mafia_internal_step < 2) - { - subentry.header = "Unlock the Black Market"; - image_name = "Black Forest"; - //This needs better spading. - //Side info: in the livestream, the flag [blackforestexplore] => 55 was visible, as well as [blackforestprogress] => 5 - - //Unlock black market: - url = "place.php?whichplace=woods"; - - string combat_rate_string = "+5% combat"; - - subentry.modifiers.listAppend(combat_rate_string); - subentry.entries.listAppend("Adventure in the Black Forest with " + combat_rate_string + "."); - - if ($item[blackberry galoshes].available_amount() > 0) - { - if ($item[blackberry galoshes].equipped_amount() == 0) - { - string line = HTMLGenerateSpanFont("Equip blackberry galoshes", "red") + " to speed up exploration"; - - if (!$item[blackberry galoshes].can_equip()) - { - make_entry_future = true; - line += ", once you can equip them"; - } - line += "."; - subentry.entries.listAppend(line); - } - } - else - { - if (!in_hardcore()) - subentry.entries.listAppend("Possibly pull and wear the blackberry galoshes?"); - //it seems unlikely finding the galoshes in HC would be worth it? maaaybe in no-familiar paths, but probably not? sneaky pete, perhaps - //subentry.entries.listAppend("Possibly make the blackberry galoshes via NC, if you get three blackberries."); - } - - boolean [familiar] relevant_familiars = $familiars[reassembled blackbird,reconstituted crow]; - familiar bird_needed_familiar; - item bird_needed; - if (my_path().id == PATH_BEES_HATE_YOU) - { - bird_needed_familiar = $familiar[reconstituted crow]; - bird_needed = $item[reconstituted crow]; - } - else - { - bird_needed_familiar = $familiar[reassembled blackbird]; - bird_needed = $item[reassembled blackbird]; - } - item [int] missing_components = missingComponentsToMakeItem(bird_needed); - - //FIXME clean this up: - //FIXME test if having a reassembled blackbird in your inventory is more than enough in any path? - //FIXME handle both reassembled blackbird and reconstituted crow as familiar - - if (missing_components.count() > 0 && bird_needed.available_amount() == 0) - { - subentry.modifiers.listAppend("+100% item"); //FIXME what is the drop rate for bees hate you items? we don't know... - } - - if (bird_needed_familiar.familiar_is_usable()) - { - if (bird_needed.available_amount() == 0 && missing_components.count() == 0) - { - subentry.entries.listAppend("Make a " + bird_needed + "."); - } - else if (!(relevant_familiars contains my_familiar()) && bird_needed.available_amount() == 0) - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Bring along " + bird_needed_familiar + " to speed up quest.", "red")); - } - else if ((relevant_familiars contains my_familiar()) && bird_needed.available_amount() > 0) - { - subentry.entries.listAppend("Bring along another familiar, you don't need to use the bird anymore."); - } - } - if (bird_needed.available_amount() == 0) - { - string line = ""; - line = "Acquire " + bird_needed + "."; - - if (missing_components.count() == 0) - line += " You have all the parts, make it."; - else - line += " Parts needed: " + missing_components.listJoinComponents(", ", "and"); - subentry.entries.listAppend(line); - } - int black_forest_progress = get_property_int("blackForestProgress"); - if (black_forest_progress >= 1 && __quest_state["Level 13"].state_boolean["wall of skin will need to be defeated"] && $item[beehive].available_amount() == 0) - { - subentry.entries.listAppend("Find a beehive for the tower, from the non-combat.|*" + listMake("Head toward the blackberry patch", "Head toward the buzzing sound", "Keep going", "Almost... there...").listJoinComponents(__html_right_arrow_character) + "|*Costs two extra turns. Skip if you're towerkilling."); - } - //if (black_forest_progress > 0) - subentry.entries.listAppend("~" + (black_forest_progress * 20) + "% finished."); - } - else if (base_quest_state.mafia_internal_step < 3) - { - //Vacation: - if ($item[forged identification documents].available_amount() == 0) - { - subentry.header = "Buy forged identification documents"; - image_name = "__item forged identification documents"; - url = "shop.php?whichshop=blackmarket"; - subentry.entries.listAppend("From the black market."); - if ($item[can of black paint].available_amount() == 0) - subentry.entries.listAppend("Also buy a can of black paint while you're there, for the desert quest."); - } - else - { - url = "place.php?whichplace=desertbeach"; - subentry.header = "Vacation at the shore"; - image_name = "__item your father's MacGuffin diary"; - string diary_owner = "your father's"; - if (my_path().id == PATH_GELATINOUS_NOOB) - diary_owner = "an archeologist's"; - subentry.entries.listAppend("To acquire " + diary_owner + " diary."); - } - } - else if (base_quest_state.mafia_internal_step < 4) - { - //Have diary: - if (to_item("2334").available_amount() == 0) //$item[holy macguffin] has shadow aliasing problem - { - //nothing to say - //subentry.entries.listAppend("Retrieve the MacGuffin."); - return; - } - else - { - url = "place.php?whichplace=town"; - subentry.entries.listAppend("Speak to the council."); - } - } - - ChecklistEntry entry = ChecklistEntryMake(image_name, url, subentry, $locations[the black forest]); - entry.tags.id = "Council L11 quest diary"; - - if (make_entry_future) - future_task_entries.listAppend(entry); - else - task_entries.listAppend(entry); -} - -void QLevel11GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id == PATH_COMMUNITY_SERVICE) - return; - QLevel11RonGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel11ShenGenerateTasks(task_entries, optional_task_entries, future_task_entries); - if (!__misc_state["in run"]) - return; - //Such a complicated quest. - QLevel11BaseGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel11ManorGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel11PalindomeGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel11DesertGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel11PyramidGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel11HiddenCityGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QLevel11HiddenTempleGenerateTasks(task_entries, optional_task_entries, future_task_entries); -} diff --git a/Source/relay/TourGuide/Quests/Level 12.ash b/Source/relay/TourGuide/Quests/Level 12.ash deleted file mode 100644 index 8c97e781..00000000 --- a/Source/relay/TourGuide/Quests/Level 12.ash +++ /dev/null @@ -1,906 +0,0 @@ -import "relay/TourGuide/Support/Item Filter.ash" - -void QLevel12Init() -{ - //questL12War - //fratboysDefeated, hippiesDefeated - //sidequestArenaCompleted, sidequestFarmCompleted, sidequestJunkyardCompleted, sidequestLighthouseCompleted, sidequestNunsCompleted, sidequestOrchardCompleted - //warProgress - - //Sidequests: - //state_boolean["Lighthouse Finished"] - //state_boolean["Orchard Finished"] - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL12War"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can complete in gg - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Island War Quest"; - state.image_name = "island war"; - state.council_quest = true; - - state.state_boolean["Arena Finished"] = (get_property("sidequestArenaCompleted") != "none"); - state.state_boolean["Farm Finished"] = (get_property("sidequestFarmCompleted") != "none"); - state.state_boolean["Junkyard Finished"] = (get_property("sidequestJunkyardCompleted") != "none"); - state.state_boolean["Lighthouse Finished"] = (get_property("sidequestLighthouseCompleted") != "none"); - state.state_boolean["Nuns Finished"] = (get_property("sidequestNunsCompleted") != "none"); - state.state_boolean["Orchard Finished"] = (get_property("sidequestOrchardCompleted") != "none"); - state.state_boolean["War started"] = (state.mafia_internal_step >= 2); - state.state_boolean["War in progress"] = state.state_boolean["War started"] && !state.finished; - - state.state_int["hippies left on battlefield"] = 1000 - get_property_int("hippiesDefeated"); - state.state_int["frat boys left on battlefield"] = 1000 - get_property_int("fratboysDefeated"); - - if (state.finished) - { - state.state_boolean["Arena Finished"] = true; - state.state_boolean["Farm Finished"] = true; - state.state_boolean["Junkyard Finished"] = true; - state.state_boolean["Lighthouse Finished"] = true; - state.state_boolean["Nuns Finished"] = true; - state.state_boolean["Orchard Finished"] = true; - } - if (my_path().id == PATH_EXPLOSIONS) - state.state_boolean["Lighthouse Finished"] = true; - int quests_completed_hippy = 0; - int quests_completed_frat = 0; - - foreach s in $strings[sidequestArenaCompleted,sidequestFarmCompleted,sidequestJunkyardCompleted,sidequestLighthouseCompleted,sidequestNunsCompleted,sidequestOrchardCompleted] - { - string property_value = get_property(s); - if (property_value == "hippy") - quests_completed_hippy += 1; - else if (property_value == "fratboy") - quests_completed_frat += 1; - } - - state.state_int["Quests completed for hippies"] = quests_completed_hippy; - state.state_int["Quests completed for frat boys"] = quests_completed_frat; - - if (!state.finished) - { - //define state.state_string["Side seemingly fighting for"] - //"hippy", "frat boys", "both", "" - - if (state.state_int["Quests completed for hippies"] > 0) - state.state_string["Side seemingly fighting for"] = "hippy"; - if (state.state_int["Quests completed for frat boys"] > 0) - state.state_string["Side seemingly fighting for"] = "frat boys"; - - if (state.state_int["hippies left on battlefield"] == 1000 && state.state_int["frat boys left on battlefield"] != 1000) - state.state_string["Side seemingly fighting for"] = "hippy"; - if (state.state_int["hippies left on battlefield"] != 1000 && state.state_int["frat boys left on battlefield"] == 1000) - state.state_string["Side seemingly fighting for"] = "frat boys"; - if (state.state_int["hippies left on battlefield"] != 1000 && state.state_int["frat boys left on battlefield"] != 1000) - state.state_string["Side seemingly fighting for"] = "both"; - if (state.state_int["Quests completed for hippies"] > 0 && state.state_int["Quests completed for frat boys"] > 0) - state.state_string["Side seemingly fighting for"] = "both"; - } - - if (false) - { - //Internal debugging: - state.state_boolean["Arena Finished"] = false; - state.state_boolean["Farm Finished"] = false; - state.state_boolean["Junkyard Finished"] = false; - state.state_boolean["Lighthouse Finished"] = false; - state.state_boolean["Nuns Finished"] = false; - state.state_boolean["Orchard Finished"] = false; - } - - if (my_level() >= 12 && my_path().id != PATH_EXPLOSIONS) - state.startable = true; - - __quest_state["Level 12"] = state; - __quest_state["Island War"] = state; -} - -void QLevel12GenerateTasksSidequests(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Level 12"]; - if (!base_quest_state.state_boolean["Orchard Finished"] && my_path().id != PATH_2CRS) - { - string [int] details; - string [int] modifiers; - - string url = "bigisland.php?place=orchard"; - modifiers.listAppend("+1000% item"); - if (__misc_state["yellow ray potentially available"]) - modifiers.listAppend("potential YR"); - - location next_location; - monster pickpocket_monster = $monster[none]; - boolean need_gland = false; - if ($item[heart of the filthworm queen].available_amount() > 0) - { - modifiers.listClear(); - details.listAppend("Go talk to the hippies to complete quest."); - } - else if ($effect[Filthworm Guard Stench].have_effect() > 0 || $item[Filthworm royal guard scent gland].available_amount() > 0) - { - if ($effect[Filthworm Guard Stench].have_effect() == 0) - { - url = "inventory.php?ftext=filthworm+royal+guard+scent+gland"; - details.listAppend("Use filthworm royal guard scent gland."); - } - modifiers.listClear(); - modifiers.listAppend("+meat"); - details.listAppend("Defeat the filthworm queen in the queen's chamber."); - next_location = $location[the filthworm queen's chamber]; - } - else if ($effect[Filthworm Drone Stench].have_effect() > 0 || $item[Filthworm drone scent gland].available_amount() > 0) - { - if ($effect[Filthworm Drone Stench].have_effect() == 0) - { - url = "inventory.php?ftext=filthworm+drone+scent+gland"; - details.listAppend("Use filthworm drone scent gland"); - } - details.listAppend("Adventure with +item in the guards' chamber."); - need_gland = true; - pickpocket_monster = $monster[filthworm royal guard]; - next_location = $location[the royal guard chamber]; - } - else if ($effect[Filthworm Larva Stench].have_effect() > 0 || $item[filthworm hatchling scent gland].available_amount() > 0) - { - if ($effect[Filthworm Larva Stench].have_effect() == 0) - { - url = "inventory.php?ftext=filthworm+hatchling+scent+gland"; - details.listAppend("Use filthworm hatchling scent gland"); - } - details.listAppend("Adventure with +item in the feeding chamber."); - need_gland = true; - pickpocket_monster = $monster[filthworm drone]; - next_location = $location[the feeding chamber]; - } - else - { - details.listAppend("Adventure with +item in the hatching chamber."); - need_gland = true; - pickpocket_monster = $monster[larval filthworm]; - next_location = $location[the hatching chamber]; - } - - if (__misc_state["can pickpocket"] && pickpocket_monster != $monster[none]) - { - int total_initiative_needed = pickpocket_monster.base_initiative; - int initiative_needed = total_initiative_needed - initiative_modifier(); - if (initiative_needed > 0) - details.listAppend("Need " + initiative_needed + "% more initiative to pickpocket every turn."); - } - - if (need_gland) - { - float effective_item_drop = next_location.item_drop_modifier_for_location() / 100.0; - //FIXME take into account pickpocketing, init, etc. - float average_glands_found_per_combat = MIN(1.0, (effective_item_drop + 1.0) * 0.1); - float turns_per_gland = -1.0; - if (average_glands_found_per_combat != 0.0) - turns_per_gland = 1.0 / average_glands_found_per_combat; - details.listAppend("~" + roundForOutput(turns_per_gland, 1) + " turns per gland."); - } - - optional_task_entries.listAppend(ChecklistEntryMake("Island War Orchard", url, ChecklistSubentryMake("Island War Orchard Quest", modifiers, details), $locations[the hatching chamber, the feeding chamber, the royal guard chamber, the filthworm queen's chamber]).ChecklistEntrySetIDTag("Council L12 quest side orchard filthworms")); - } - if (!base_quest_state.state_boolean["Farm Finished"]) - { - string [int] details; - details.listAppend("Great flappin' beasts, with webbed feet and bills! dooks!"); - string [int] modifiers; - modifiers.listAppend("+meat"); - - string [int] tasks; - - boolean [string] area_known_ncs = $strings[Cornered!,Cornered Again!,How Many Corners Does this Stupid Barn Have!?]; - int ncs_seen = 0; - string [int] location_ncs = $location[McMillicancuddy's Barn].locationSeenNoncombats(); - foreach key, s in location_ncs - { - if (area_known_ncs contains s) - { - ncs_seen += 1; - } - } - - if (ncs_seen < 3 || my_location() == $location[McMillicancuddy's Barn]) - { - tasks.listAppend("make a fence out of the barbed wire"); - tasks.listAppend("knock over the lantern"); - tasks.listAppend("dump out the drum"); - details.listAppend((!get_property_boolean("chaosButterflyThrown") ? "Remember to use a chaos butterfly in combat before clearing the barn.|Then " : "Remember: ") + tasks.listJoinComponents(", ", "and") + "."); - - - if (__misc_state["free runs available"]) - modifiers.listAppend("free runs in barn"); - } - optional_task_entries.listAppend(ChecklistEntryMake("Island War Farm", "bigisland.php?place=farm", ChecklistSubentryMake("Island War Farm Quest", modifiers, details), $locations[mcmillicancuddy's farm,mcmillicancuddy's barn,mcmillicancuddy's pond,mcmillicancuddy's back 40,mcmillicancuddy's other back 40,mcmillicancuddy's granary,mcmillicancuddy's bog,mcmillicancuddy's family plot,mcmillicancuddy's shady thicket]).ChecklistEntrySetIDTag("Council L12 quest side farm")); - } - if (!base_quest_state.state_boolean["Nuns Finished"] && my_path().id != PATH_2CRS) - { - string [int] details; - int meat_gotten = get_property_int("currentNunneryMeat"); - int meat_remaining = 100000 - meat_gotten; - details.listAppend(meat_remaining + " meat remaining."); - - float meat_drop_multiplier = meat_drop_modifier() / 100.0 + 1.0; - vec2i brigand_meat_drop_range = vec2iMake(800 * meat_drop_multiplier, 1200 * meat_drop_multiplier); - vec2i turn_range; - if (brigand_meat_drop_range.x != 0 && brigand_meat_drop_range.y != 0) - turn_range = vec2iMake(ceil(to_float(meat_remaining) / to_float(brigand_meat_drop_range.y)), - ceil(to_float(meat_remaining) / to_float(brigand_meat_drop_range.x))); - if (my_path().id == PATH_2CRS) - turn_range = Vec2iMake(MAX(100, turn_range.x), MAX(100, turn_range.y)); - - - - string turns_extra = "."; - string [int] extra_details; - if (get_property("boomBoxSong") == "Total Eclipse of Your Meat") - { - vec2i brigand_meat_drop_range_sing = vec2iMake(820 * meat_drop_multiplier, 1230 * meat_drop_multiplier); - vec2i turn_range_sing; - if (brigand_meat_drop_range_sing.x != 0 && brigand_meat_drop_range_sing.y != 0) - turn_range_sing = vec2iMake(ceil(to_float(meat_remaining) / to_float(brigand_meat_drop_range_sing.y)), - ceil(to_float(meat_remaining) / to_float(brigand_meat_drop_range_sing.x))); - turns_extra = ", if you don't sing."; - if (turn_range_sing.x == turn_range.x && turn_range_sing.y == turn_range.y) - { - turns_extra = "."; - } - else if (turn_range_sing.x == turn_range_sing.y) - details.listAppend(pluralise(turn_range_sing.x, "turn", "turns") + " remaining, if you sing."); - else - details.listAppend("[" + turn_range_sing.x + " to " + turn_range_sing.y + "] turns remaining, if you sing."); - extra_details.listAppend("Be sure to Sing Along with your boombox every turn."); - /*float without = meat_remaining / (1000.0 * meat_drop_multiplier); - float with = meat_remaining / (1025.0 * meat_drop_multiplier); - details.listAppend("Singing saves " + (without - with) + " turns.");*/ - } - - - //FIXME consider looking into tracking how long until the semi-rare item runs out, for turn calculation - if (turn_range.x == turn_range.y) - details.listAppend(pluralise(turn_range.x, "turn", "turns") + " remaining" + turns_extra); - else - details.listAppend("[" + turn_range.x + " to " + turn_range.y + "] turns remaining" + turns_extra); - - - if (turn_range.x == 1 && turn_range.y == 2) - { - float chance = 1.0 - TriangularDistributionCalculateCDF(meat_remaining + 1, brigand_meat_drop_range.x, brigand_meat_drop_range.y); - details.listAppend((chance * 100.0).floor() + "% chance of completing in one turn."); - } - - if ($item[ice nine].available_amount() == 0 && __misc_state["can equip just about any weapon"] && $item[ice harvest].available_amount() >= 9 && $item[ice nine].is_unrestricted() && $item[miracle whip].available_amount() == 0) //is this safe? unfinished ice sculpture is really nice, and ice bucket in sneaky pete... - details.listAppend("Possibly make and equip an ice nine. (+30% meat 1h weapon)"); - - if ($effect[Sinuses For Miles].have_effect() > 0 && !get_property_ascension("lastTempleAdventures") && $item[stone wool].available_amount() > 0 && get_property_ascension("lastTempleUnlock")) - details.listAppend("Potentially use stone wool and visit the hidden temple to extend Sinuses for Miles for 3 turns."); - - - if (my_path().id == PATH_HEAVY_RAINS && $skill[Make it Rain].skill_is_usable() && turn_range.y > 1) - details.listAppend("Cast Make it Rain each fight. (+300%? meat)"); - if ($item[Sneaky Pete's leather jacket (collar popped)].equipped_amount() > 0 && turn_range.y > 1) - details.listAppend("Could unpop your collar. (+20% meat)"); - - if (__misc_state_int["pulls available"] > 0 && meat_drop_modifier() < 1000.0) - { - int limit = 100; - if (meat_drop_modifier() < 800.0) - limit = 50; - if (my_path().id == PATH_G_LOVER) - limit = 25; - limit = 0; //show them all - we'll go based off of turns saved - boolean [item] blacklist = $items[uncle greenspan's bathroom finance guide,black snowcone]; - item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Meat Drop", limit, blacklist); - string [int] relevant_potions_output; - float average_turns_currently = meat_remaining / ((meat_drop_modifier() / 100.0 + 1.0) * 1000.0); - foreach key, it in relevant_potions - { - effect e = it.to_effect(); - if (!e.effect_is_usable()) - continue; - if (!it.item_is_usable()) - continue; - //average_turns_currently - - float meat_dropped_per_turn_with_item = ((meat_drop_modifier() + e.numeric_modifier("meat drop")) / 100.0 + 1.0) * 1000.0; - float turns_saved = average_turns_currently - meat_remaining / meat_dropped_per_turn_with_item; - if (turns_saved < 1.0) continue; - relevant_potions_output.listAppend(it + " (" + e.numeric_modifier("meat drop").roundForOutput(0) + "%, " + turns_saved.roundForOutput(1) + " turns saved)"); - } - - if (relevant_potions_output.count() > 0) - details.listAppend("Could try pulling " + relevant_potions_output.listJoinComponents(", ", "or") + "."); - } - details.listAppendList(extra_details); - optional_task_entries.listAppend(ChecklistEntryMake("Island War Nuns", "bigisland.php?place=nunnery", ChecklistSubentryMake("Island War Nuns Quest", "+meat", details), $locations[the themthar hills]).ChecklistEntrySetIDTag("Council L12 quest side nuns")); - } - if (!base_quest_state.state_boolean["Junkyard Finished"]) - { - string [int] details; - if ($item[molybdenum magnet].available_amount() == 0) - { - details.listAppend("Talk to Yossarian first."); - } - else - { - location [item] items_and_locations; - items_and_locations[$item[molybdenum hammer]] = $location[Next to that Barrel with Something Burning in it]; - items_and_locations[$item[molybdenum pliers]] = $location[Near an Abandoned Refrigerator]; - items_and_locations[$item[molybdenum crescent wrench]] = $location[Over Where the Old Tires Are]; - items_and_locations[$item[molybdenum screwdriver]] = $location[Out By that Rusted-Out Car]; - boolean have_all = true; - - string [location][int] location_monsters; - location_monsters[$location[Next to that Barrel with Something Burning in it]] = listMake("tool batwinged", "vegetable"); - location_monsters[$location[Out By that Rusted-Out Car]] = listMake("tool vegetable", "erudite"); - location_monsters[$location[Near an Abandoned Refrigerator]] = listMake("tool spider", "batwinged"); - location_monsters[$location[Over Where the Old Tires Are]] = listMake("tool erudite", "spider"); - - location [int][monster] banishment_locations; //it's time we had a talk... about your hair! it's gone too far! - banishment_locations[1][$monster[batwinged gremlin]] = $location[Near an Abandoned Refrigerator]; - banishment_locations[1][$monster[erudite gremlin]] = $location[Out By that Rusted-Out Car]; - banishment_locations[1][$monster[spider gremlin]] = $location[Over Where the Old Tires Are]; - banishment_locations[1][$monster[vegetable gremlin]] = $location[Next to that Barrel with Something Burning in it]; - - - banishment_locations[0][$monster[batwinged gremlin]] = $location[Next to that Barrel with Something Burning in it]; - banishment_locations[0][$monster[erudite gremlin]] = $location[Over Where the Old Tires Are]; - banishment_locations[0][$monster[spider gremlin]] = $location[Near an Abandoned Refrigerator]; - banishment_locations[0][$monster[vegetable gremlin]] = $location[Out By that Rusted-Out Car]; - - foreach key in banishment_locations - { - foreach m in banishment_locations[key] - { - if (!m.is_banished()) - continue; - location l = banishment_locations[key][m]; - - if (key == 0 && location_monsters[l][key].contains_text("tool ")) - location_monsters[l][key] = "tool " + HTMLGenerateSpanFont(location_monsters[l][key].replace_string("tool ", ""), "grey", ""); - else - location_monsters[l][key] = HTMLGenerateSpanFont(location_monsters[l][key], "grey"); - } - } - - - - item [int] item_display_order = listMake($item[molybdenum hammer],$item[molybdenum pliers],$item[molybdenum crescent wrench],$item[molybdenum screwdriver]); //make a path - string [int] areas_left_strings; - //foreach it in items_and_locations - - string [location] location_shorthand_name; - location_shorthand_name[$location[Next to that Barrel with Something Burning in it]] = "Barrel"; - location_shorthand_name[$location[Out By that Rusted-Out Car]] = "Car"; - location_shorthand_name[$location[Near an Abandoned Refrigerator]] = "Refrigerator"; - location_shorthand_name[$location[Over Where the Old Tires Are]] = "Tires"; - - foreach key in item_display_order - { - item it = item_display_order[key]; - location loc = items_and_locations[it]; - if (it.available_amount() > 0) - { - continue; - } - else - have_all = false; - - string location_display_name; - if (location_shorthand_name contains loc) - location_display_name = location_shorthand_name[loc]; - else - location_display_name = loc.to_string().to_lower_case(); - - areas_left_strings.listAppend("" + location_display_name + " - " + location_monsters[loc].listJoinComponents(", ")); - } - if (areas_left_strings.count() > 0) - details.listAppend("Areas left:|*" + areas_left_strings.listJoinComponents("
|*")); - if (have_all) - details.listAppend("Talk to Yossarian to complete quest."); - else - { - if ($item[dictionary].available_amount() > 0 && $item[dictionary].item_is_usable()) - { - details.listAppend("Read from the dictionary to stasis gremlins."); - } - else if ($item[facsimile dictionary].available_amount() > 0 && $item[facsimile dictionary].item_is_usable()) - { - details.listAppend("Read from the facsimile dictionary to stasis gremlins."); - } - else if ($item[seal tooth].available_amount() > 0 && $item[seal tooth].item_is_usable()) - { - details.listAppend("Use your seal tooth to stasis gremlins."); - } - else if ($skill[suckerpunch].skill_is_usable()) - { - details.listAppend("Cast suckerpunch to stasis gremlins."); - } - else if ($item[seal tooth].item_is_usable() && my_path().id != PATH_ZOMBIE_SLAYER) - details.listAppend(HTMLGenerateSpanFont("Acquire a seal tooth", "red") + " to stasis gremlins. (from hermit)"); - else if ($item[beehive].available_amount() > 0) - details.listAppend("Use your beehive to stasis gremlins."); - - if (!$monster[A.M.C. gremlin].is_banished()) - details.listAppend("Potentially banish A.M.C. Gremlin."); - } - } - optional_task_entries.listAppend(ChecklistEntryMake("Island War Junkyard", "bigisland.php?place=junkyard", ChecklistSubentryMake("Island War Junkyard Quest", listMake("+DR", "+DA", "+HP", "+moxie"), details), $locations[next to that barrel with something burning in it,near an abandoned refrigerator,over where the old tires are,out by that rusted-out car]).ChecklistEntrySetIDTag("Council 12 quest side junkyard Yossarian")); - } - if (!base_quest_state.state_boolean["Lighthouse Finished"]) - { - string [int] details; - - int gunpowder_needed = MAX(0, 5 - $item[barrel of gunpowder].available_amount()); - - - string [int] modifiers; - if (gunpowder_needed > 0) - { - modifiers = listMake("+combat", "copies"); - details.listAppend("Need " + gunpowder_needed.pluralise("more barrel", "more barrels") + " of gunpowder."); - - - - //this is an approximation: - //off by a little over half a turn on average - float effective_combat_rate = (11.0 / 12.0) * clampNormalf(0.1 + combat_rate_modifier() / 100.0) + (1.0 / 12.0) * 1.0; - float turns_per_lobster = -1.0; - if (effective_combat_rate != 0.0) - turns_per_lobster = 1.0 / effective_combat_rate; - - - float turns_to_complete = gunpowder_needed.to_float() * turns_per_lobster; - - //I had the data lying around, so why not? - //misses <-10 and >30, but the estimate above will catch that - float [int][int] lfm_simulation_data; - lfm_simulation_data[5][-10] = 60.00; lfm_simulation_data[5][-5] = 40.02; lfm_simulation_data[5][0] = 29.92; lfm_simulation_data[5][5] = 23.84; lfm_simulation_data[5][10] = 19.76; lfm_simulation_data[5][15] = 16.84; lfm_simulation_data[5][20] = 14.66; lfm_simulation_data[5][25] = 13.00; lfm_simulation_data[4][-10] = 48.00; lfm_simulation_data[4][-5] = 32.27; lfm_simulation_data[4][0] = 24.20; lfm_simulation_data[4][5] = 19.29; lfm_simulation_data[4][10] = 16.00; lfm_simulation_data[4][15] = 13.68; lfm_simulation_data[4][20] = 11.96; lfm_simulation_data[4][25] = 10.63; lfm_simulation_data[3][-10] = 36.00; lfm_simulation_data[3][-5] = 24.53; lfm_simulation_data[3][0] = 18.47; lfm_simulation_data[3][5] = 14.78; lfm_simulation_data[3][10] = 12.34; lfm_simulation_data[3][15] = 10.59; lfm_simulation_data[3][20] = 9.26; lfm_simulation_data[3][25] = 8.20; lfm_simulation_data[2][-10] = 24.00; lfm_simulation_data[2][-5] = 16.79; lfm_simulation_data[2][0] = 12.84; lfm_simulation_data[2][5] = 10.38; lfm_simulation_data[2][10] = 8.68; lfm_simulation_data[2][15] = 7.40; lfm_simulation_data[2][20] = 6.40; lfm_simulation_data[2][25] = 5.60; lfm_simulation_data[1][-10] = 12.00; lfm_simulation_data[1][-5] = 9.19; lfm_simulation_data[1][0] = 7.17; lfm_simulation_data[1][5] = 5.72; lfm_simulation_data[1][10] = 4.66; lfm_simulation_data[1][15] = 3.87; lfm_simulation_data[1][20] = 3.29; lfm_simulation_data[1][25] = 2.84; lfm_simulation_data[5][26] = 12.71; lfm_simulation_data[5][27] = 12.44; lfm_simulation_data[5][28] = 12.18; lfm_simulation_data[5][29] = 11.93; lfm_simulation_data[5][30] = 11.69; lfm_simulation_data[4][26] = 10.40; lfm_simulation_data[4][27] = 10.17; lfm_simulation_data[4][28] = 9.96; lfm_simulation_data[4][29] = 9.75; lfm_simulation_data[4][30] = 9.56; lfm_simulation_data[3][26] = 8.01; lfm_simulation_data[3][27] = 7.83; lfm_simulation_data[3][28] = 7.65; lfm_simulation_data[3][29] = 7.48; lfm_simulation_data[3][30] = 7.32; lfm_simulation_data[2][26] = 5.46; lfm_simulation_data[2][27] = 5.33; lfm_simulation_data[2][28] = 5.20; lfm_simulation_data[2][29] = 5.07; lfm_simulation_data[2][30] = 4.96; lfm_simulation_data[1][26] = 2.76; lfm_simulation_data[1][27] = 2.69; lfm_simulation_data[1][28] = 2.62; lfm_simulation_data[1][29] = 2.56; lfm_simulation_data[1][30] = 2.50; - - if (lfm_simulation_data[gunpowder_needed] contains combat_rate_modifier().to_int()) - { - turns_to_complete = lfm_simulation_data[gunpowder_needed][combat_rate_modifier().to_int()]; - if (gunpowder_needed != 0.0) - turns_per_lobster = turns_to_complete / gunpowder_needed.to_float(); - } - - details.listAppend("~" + roundForOutput(turns_to_complete, 1) + " turns to complete quest at " + combat_rate_modifier().floor() + "% combat.|~" + roundForOutput(turns_per_lobster, 1) + " turns per lobster."); - - string macrometeorite_source; - - if ($skill[meteor lore].have_skill() && get_property_int("_macrometeoriteUses") < 10) - macrometeorite_source = "macrometeorite"; - else if (lookupItem("Powerful Glove").have() && 100 - get_property_int("_powerfulGloveBatteryPowerUsed") >= 10) - macrometeorite_source = "Replace Enemy"; - - if (macrometeorite_source != "") - { - details.listAppend("Could use " + macrometeorite_source + " on a wandering monster (portscan, voting, holiday monster...) to guarantee an LFM."); - if (macrometeorite_source == "Replace Enemy" && !lookupItem("Powerful Glove").equipped()) - details.listAppend("Equip the Powerful Glove, first."); - - if (lookupItem(""I Voted!" sticker").available_amount() > 0 && get_property_int("_voteFreeFights") >= 3) - { - if (total_turns_played() % 11 == 1 && get_property_int("lastVoteMonsterTurn") < total_turns_played()) - { - details.listAppend("Voting monster now!"); - } - else - { - int turns_to_next_voting_monster = 11 - (((total_turns_played() % 11) - 1 + 11) % 11); - details.listAppend("Voting monster will appear in " + pluralise(turns_to_next_voting_monster, "more turn", "more turns") + "."); - } - - } - } - - int sabersOwned = lookupItem("Fourth of May Cosplay Saber").available_amount() + lookupItem("replica Fourth of May Cosplay Saber").available_amount(); - - if (sabersOwned > 0 && get_property_int("_saberForceUses") < 5 && gunpowder_needed > 1) - { - int saber_fights_left = MIN(get_property_int("_saberForceMonsterCount"), 3); - boolean already_sabering_lfm = get_property_monster("_saberForceMonster") == $monster[lobsterfrogman] && saber_fights_left > 0; - - if (!already_sabering_lfm || already_sabering_lfm && saber_fights_left < gunpowder_needed) { - details.listAppend("Could Use the Force (friends) on a LFM to guarantee two more."); - - if (already_sabering_lfm && saber_fights_left > 1) //sabering now would waste some copies - details.listAppend("Finish fighting " + (saber_fights_left - 1).pluralise("more copy", "more copies") + ", first."); - else if (!lookupItem("Fourth of May Cosplay Saber").equipped()) - details.listAppend("Equip the Fourth of May saber, first."); - } - } - } - else - details.listAppend("Talk to the lighthouse keeper to finish quest."); - - - optional_task_entries.listAppend(ChecklistEntryMake("Island War Lighthouse", "bigisland.php?place=lighthouse", ChecklistSubentryMake("Island War Lighthouse Quest", modifiers, details), $locations[sonofa beach]).ChecklistEntrySetIDTag("Council L12 quest side lighthouse gunpowder LFM")); - } - if (!base_quest_state.state_boolean["Arena Finished"] && my_path().id != PATH_G_LOVER && my_path().id != PATH_POCKET_FAMILIARS) - { - string [int] modifiers; - modifiers.listAppend("+ML"); - float percent_done = clampf(get_property_int("flyeredML") / 10000.0 * 100.0, 0.0, 100.0); - int ml_remaining = 10000 - get_property_int("flyeredML"); - string [int] details; - if (percent_done >= 100.0) - { - modifiers.listClear(); - details.listAppend("Turn in quest."); - } - else - { - if ($item[jam band flyers].available_amount() == 0 && $item[rock band flyers].available_amount() == 0) - details.listAppend("Acquire fliers."); - details.listAppend(round(percent_done, 1) + "% ML completed, " + ml_remaining + " ML remains."); - } - - //Normally, this would be bigisland.php?place=concert - //But that could theoretically complete the quest for the wrong side, if they're wearing the wrong uniform and misclick. - optional_task_entries.listAppend(ChecklistEntryMake("Island War Arena", "bigisland.php", ChecklistSubentryMake("Island War Arena Quest", modifiers, details)).ChecklistEntrySetIDTag("Council L12 quest side arena")); - - if (ml_remaining > 0 && ($item[jam band flyers].available_amount() > 0 || $item[rock band flyers].available_amount() > 0)) - { - item it = $item[jam band flyers]; - if ($item[rock band flyers].available_amount() > 0 && $item[jam band flyers].available_amount() == 0) - it = $item[rock band flyers]; - task_entries.listAppend(ChecklistEntryMake(it, "", ChecklistSubentryMake("Flyer with " + it + " every combat", "+ML", details), -11).ChecklistEntrySetIDTag("Council L12 quest side advertise reminder")); - } - } -} - - -void QLevel12GenerateBattlefieldDescription(ChecklistSubentry subentry, string side, int enemies_remaining, int enemies_defeated_per_combat, string enemy_name, string enemy_name_plural, string boss_name, string [int] sidequest_list, string [int] base_sidequest_list) -{ - if (enemies_defeated_per_combat == 0) - return; - - int enemies_defeated = 1000 - enemies_remaining; - string line; - if (enemies_remaining > 0) - { - line = pluralise(enemies_remaining, enemy_name, enemy_name_plural) + " left."; - } - else - { - line += "Fight " + boss_name + "!"; - if (my_path().id == PATH_DEMIGUISE && $effect[Flared Nostrils].have_effect() > 0) - line += "|" + HTMLGenerateSpanFont("Remove Flared Nostrils", "red") + " or you will die."; - if (my_path().id == PATH_DEMIGUISE) - { - int damage_taken = 0; - damage_taken += ceil(my_maxhp() * 2.0 * (1.0 - elemental_resistance($element[stench]) / 100.0)); - if ($effect[flared nostrils].have_effect() > 0) - damage_taken += ceil(my_maxhp() * 2.0 * 2.0); - else - damage_taken += ceil(my_maxhp() * 2.0 * (1.0 - elemental_resistance($element[sleaze]) / 100.0)); - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+stench res", "r_element_stench_desaturated")); - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+sleaze res", "r_element_sleaze_desaturated")); - - line += "|Will take " + damage_taken + " damage at the start of combat"; - if (damage_taken >= my_maxhp()) - line += ", " + HTMLGenerateSpanFont("which you cannot survive", "red"); - line += "."; - line += "|Run " + HTMLGenerateSpanOfClass("stench", "r_element_stench") + " and " + HTMLGenerateSpanOfClass("sleaze", "r_element_sleaze") + " resistance."; - if (my_hp() != my_maxhp()) - line += "|" + HTMLGenerateSpanFont("Also restore your HP.", "red"); - } - } - - string outfit_name; - if (side == "hippy") - outfit_name = "War Hippy Fatigues"; - if (side == "frat boy") - outfit_name = "Frat Warrior Fatigues"; - - if (outfit_name != "") - { - item [int] missing_outfit_components = missing_outfit_components(outfit_name); - if (missing_outfit_components.count() > 0) - line += "|*Missing outfit piece" + (missing_outfit_components.count() > 1 ? "s" : "") + " " + missing_outfit_components.listJoinComponents(", ", "and") + "."; - } - int turns_remaining = ceiling(enemies_remaining.to_float() / enemies_defeated_per_combat.to_float()); - if (turns_remaining > 0) - { - line += "|*" + pluralise(turns_remaining, "turn", "turns") + " remaining."; - line += " " + pluralise(enemies_defeated_per_combat, enemy_name, enemy_name_plural) + " defeated per combat."; - } - int enemies_to_defeat_for_unlock = -1; - string area_to_unlock = ""; - string [int] areas_unlocked_but_not_completed; - - boolean [string] areas_blocked; - if (my_path().id == PATH_G_LOVER || my_path().id == PATH_POCKET_FAMILIARS) - areas_blocked["Arena"] = true; - - foreach key, sidequest in base_sidequest_list - { - if (areas_blocked[sidequest]) - continue; - if (!__quest_state["Level 12"].state_boolean[sidequest + " Finished"]) - { - areas_unlocked_but_not_completed.listAppend(sidequest); - } - } - - if (my_path().id != PATH_BUGBEAR_INVASION) //FIXME test against trendy bugbear chef being needed - { - if (side == "frat boy" && __misc_state["free runs usable"]) - subentry.modifiers.listAppend("possibly olfact Green Ops Soldier"); - else if (side == "hippy") - subentry.modifiers.listAppend("possibly olfact Sorority Operator"); - } - - int [int] unlock_threshold; - unlock_threshold[0] = 64; - unlock_threshold[1] = 192; - unlock_threshold[2] = 458; - - for i from 2 to 0 by -1 - { - int threshold = unlock_threshold[i]; - if (areas_blocked[sidequest_list[i]]) continue; - if (!__quest_state["Level 12"].state_boolean[sidequest_list[i] + " Finished"]) - { - if (enemies_defeated < threshold) - { - area_to_unlock = sidequest_list[i]; - enemies_to_defeat_for_unlock = threshold - enemies_defeated; - } - else - { - areas_unlocked_but_not_completed.listAppend(sidequest_list[i]); - } - } - } - - if (enemies_to_defeat_for_unlock != -1) - { - int turns_to_reach = ceiling(enemies_to_defeat_for_unlock.to_float() / enemies_defeated_per_combat.to_float()); - line += "|*" + pluralise(turns_to_reach, "turn", "turns") + " (" + pluralise(enemies_to_defeat_for_unlock, enemy_name, enemy_name_plural) + ") to unlock " + area_to_unlock + "."; - } - - if (areas_unlocked_but_not_completed.count() > 0 && enemies_remaining > 0) - line += "|*Quests accessible: " + areas_unlocked_but_not_completed.listJoinComponents(", ", "and") + "."; - - subentry.entries.listAppend(line); - - if (enemies_remaining == 0) - { - string [int] items_to_turn_in_for; - if (__quest_state["Level 13"].state_boolean["shadow will need to be defeated"]) - { - if (side == "hippy") - items_to_turn_in_for.listAppend("filthy poultices for shadow"); - else - items_to_turn_in_for.listAppend("gauze garters for shadow"); - } - - string line2 = "Also, turn in gear to your home camp."; - if (items_to_turn_in_for.count() > 0) - line2 += " Acquire " + items_to_turn_in_for.listJoinComponents(", ", "and") + ", etc."; - subentry.entries.listAppend(line2); - } -} - -void QLevel12ExplosionsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id != PATH_EXPLOSIONS) return; - if (QuestState("questL12HippyFrat").finished) return; - - string [int] description; - string url = "place.php?whichplace=exploathing"; - - int fratboys_defeated = get_property_int("fratboysDefeated"); - int hippies_defeated = get_property_int("hippiesDefeated"); - int fratboys_left = clampi(333 - fratboys_defeated, 0, 333); - int hippies_left = clampi(333 - hippies_defeated, 0, 333); - - if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues")) - description.listAppend("Find a uniform. Either calculate the universe 151st + YR, wish + YR?, pull, or yellow-ray a battlefield enemy with the outfit?"); - else if (!is_wearing_outfit("War Hippy Fatigues") && !is_wearing_outfit("Frat Warrior Fatigues")) - { - description.listAppend("Equip a war outfit first."); - url = "inventory.php?which=2"; - } - if ($items[jacob's rung,haunted paddle-ball].available_amount() == 0) - { - description.listAppend((!in_hardcore() ? "Pull/" : "") + "YR a jacob's rung or haunted paddle-ball, from the top floor of spookyraven manor.|Jacob's adder in the Haunted Laboratory or possessed toy chest in the The Haunted Nursery have them."); - } - else if ($items[jacob's rung,haunted paddle-ball].equipped_amount() == 0) - { - if ($item[haunted paddle-ball].have()) - { - description.listAppend("Equip haunted paddle-ball first."); - url = "inventory.php?ftext=haunted+paddle-ball"; - } - else if ($item[jacob's rung].have()) - { - description.listAppend("Equip jacob's rung first."); - url = "inventory.php?ftext=jacob's+rung"; - } - } - boolean likely_fighting_frats = false; - if (fratboys_defeated > 0 && fratboys_defeated > hippies_defeated) - { - likely_fighting_frats = true; - if (fratboys_left <= 0) - description.listAppend("Fight the Man!"); - else - description.listAppend("Defeat " + pluralise(fratboys_left, "more fratboy", "more fratboys") + "."); - } - else - { - if (hippies_left <= 0) - description.listAppend("Fight the Big Wisniewski!"); - else - description.listAppend("Defeat " + pluralise(hippies_left, "more hippy", "more hippies") + "."); - } - - - int battlefield_turns = lookupLocation("The Exploaded Battlefield").turns_spent; - int turns_until_next_war_nc = -1; - if (battlefield_turns < 7) - turns_until_next_war_nc = 7 - battlefield_turns; - else - { - turns_until_next_war_nc = (battlefield_turns + 7) % 7; - if (turns_until_next_war_nc != 0) - turns_until_next_war_nc = 7 - turns_until_next_war_nc; - } - - if (turns_until_next_war_nc == 0) - { - description.listAppend("Non-combat now. Throw high-adventure consumable to speed up war."); - } - else - description.listAppend(pluraliseWordy(turns_until_next_war_nc, "More Turn", "more turns").capitaliseFirstLetter() + " until war NC."); - - - if (likely_fighting_frats) - { - if (lookupItems("space wine").available_amount() == 0) - description.listAppend("Buy some space wine for the non-combat."); - } - else - { - if (lookupItems("pie man was not meant to eat,space chowder").available_amount() == 0) - description.listAppend("Buy some space chowder for the non-combat."); - } - - task_entries.listAppend(ChecklistEntryMake("island war", url, ChecklistSubentryMake("War!", "", description), 0).ChecklistEntrySetIDTag("Council L12 quest exploathing path")); -} - -void QLevel12GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id == PATH_EXPLOSIONS) - QLevel12ExplosionsGenerateTasks(task_entries, optional_task_entries, future_task_entries); - if (!__quest_state["Level 12"].in_progress) - return; - - QuestState base_quest_state = __quest_state["Level 12"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - - task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, "island.php", subentry, $locations[the battlefield (frat uniform), the battlefield (hippy uniform), The Orcish Frat House, The Hippy camp, wartime frat house, wartime frat house (hippy disguise), wartime hippy camp, wartime hippy camp (frat disguise)]).ChecklistEntrySetIDTag("Council L12 quest battlefield")); - if (base_quest_state.mafia_internal_step < 2) - { - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("Start the war!"); - - float noncombat_rate = 1.0 - (.85 + combat_rate_modifier() / 100.0); - float turns_remaining = -1.0; - if (noncombat_rate != 0.0) - turns_remaining = 3.0 / noncombat_rate; - - - if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues")) - { - //FIXME suggest routes to doing both. - subentry.entries.listAppend("Need either the war hippy fatigues or frat warrior fatigues outfit."); - if ($familiar[slimeling].familiar_is_usable()) - subentry.modifiers.listAppend("slimeling?"); - } - else - { - string [int] stats_needed; - if (my_basestat($stat[moxie]) < 70) - stats_needed.listAppend((70 - my_basestat($stat[moxie])) + " more moxie"); - if (my_basestat($stat[mysticality]) < 70) - stats_needed.listAppend((70 - my_basestat($stat[mysticality])) + " more mysticality"); - if (stats_needed.count() == 0) - subentry.entries.listAppend("Wear war outfit, run -combat, adventure in other side's camp."); - else - { - string line = "Acquire " + stats_needed.listJoinComponents(", ", "and") + " to wear war outfit."; - if (my_class() == $class[pastamancer] && (is_wearing_outfit("War Hippy Fatigues") || is_wearing_outfit("Frat Warrior Fatigues"))) - line += "|Or... wear it anyways, because you're a pastamancer."; - subentry.entries.listAppend(line); - } - - - //need 70 moxie, 70 myst - - } - if (false && $item[talisman o' namsilat].available_amount() == 0 && !__quest_state["Level 11 Palindome"].finished && my_path().id != PATH_G_LOVER) - { - subentry.entries.listAppend("May want to " + HTMLGenerateSpanFont("acquire the Talisman o' Nam", "red") + " first."); - } - - subentry.entries.listAppend(generateTurnsToSeeNoncombat(85, 3, "start war")); - } - else - { - int sides_completed_hippy = base_quest_state.state_int["Quests completed for hippies"]; - int sides_completed_frat = base_quest_state.state_int["Quests completed for frat boys"]; - - int frat_boys_left = base_quest_state.state_int["frat boys left on battlefield"]; - int hippies_left = base_quest_state.state_int["hippies left on battlefield"]; - - int frat_boys_defeated_per_combat = powi(2, sides_completed_hippy); - int hippies_defeated_per_combat = powi(2, sides_completed_frat); - - if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && get_property("peteMotorbikeCowling") == "Rocket Launcher") - { - frat_boys_defeated_per_combat += 3; - hippies_defeated_per_combat += 3; - } - if (my_path().id == PATH_LICENSE_TO_ADVENTURE && get_property_boolean("bondWar")) - { - frat_boys_defeated_per_combat += 3; - hippies_defeated_per_combat += 3; - } - - - subentry.modifiers.listAppend("+item"); - if (hippies_left < 1000 || (frat_boys_left == 1000 && hippies_left == 1000) || sides_completed_frat > 0) - QLevel12GenerateBattlefieldDescription(subentry, "frat boy", hippies_left, hippies_defeated_per_combat, "hippy", "hippies", "The Big Wisniewski", listMake("Orchard", "Nuns", "Farm"), listMake("Lighthouse", "Junkyard", "Arena")); - //specific exception to deal with 151st cheating: - if ((frat_boys_left < 1000 && !(frat_boys_left >= 998 && hippies_left < 1000)) || (frat_boys_left == 1000 && hippies_left == 1000) || sides_completed_hippy > 0) - QLevel12GenerateBattlefieldDescription(subentry, "hippy", frat_boys_left, frat_boys_defeated_per_combat, "frat boy", "frat boys", "The Man", listMake("Lighthouse", "Junkyard", "Arena"), listMake("Orchard", "Nuns", "Farm")); - - - if (frat_boys_left == 1 && hippies_left == 1) - { - if ($item[flaregun].available_amount() > 0) - subentry.entries.listAppend("Wossname time! Adventure on battlefield, use a flaregun."); - else if (!in_hardcore()) - subentry.entries.listAppend("Pull a flaregun for wossname."); - else if (__misc_state["fax equivalent accessible"]) - subentry.entries.listAppend("Fax smarmy pirate, run +234% item (or YR) for flaregun for wossname."); - else - subentry.entries.listAppend("That almost was a wossname, but you needed more flare."); - } - - item [int] items_to_closet_for_desert_hippy; - foreach it in $items[reinforced beaded headband,round purple sunglasses,bullet-proof corduroys,beer helmet,distressed denim pants,bejeweled pledge pin] - { - if (it.available_amount() == 0) - continue; - items_to_closet_for_desert_hippy.listAppend(it); - } - - if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues")) - { - string line = "Visit the Arid, Extra-Dry Desert to find a hippy uniform."; - if (items_to_closet_for_desert_hippy.count() > 0) - line += "|But first closet " + items_to_closet_for_desert_hippy.listJoinComponents(", ", "and"); - subentry.entries.listAppend(line); - } - //FIXME Add when spaded: - /*else if (!have_outfit_components("War Hippy Fatigues")) - { - string line = "If you want a hippy uniform without visiting the battlefield, adventure in the Arid, Extra-Dry Desert."; - if (items_to_closet_for_desert_hippy.count() > 0) - line += "|But first closet " + items_to_closet_for_desert_hippy.listJoinComponents(", ", "and"); - subentry.entries.listAppend(line); - }*/ - - QLevel12GenerateTasksSidequests(task_entries, optional_task_entries, future_task_entries); - } - -} diff --git a/Source/relay/TourGuide/Quests/Level 13.ash b/Source/relay/TourGuide/Quests/Level 13.ash deleted file mode 100644 index 7e13d8e3..00000000 --- a/Source/relay/TourGuide/Quests/Level 13.ash +++ /dev/null @@ -1,1577 +0,0 @@ -import "relay/TourGuide/Support/Spell Damage.ash" -import "relay/TourGuide/Support/Passive Damage.ash" -import "relay/TourGuide/Support/Item Filter.ash" - - -Record TFWMInternalModifier -{ - string description; - boolean have; - boolean obtainable_now; - boolean obtainable_theoretically; - float bonus; - - boolean from_familiar_equipment; -}; - -boolean TFWMInternalModifierEquals(TFWMInternalModifier a, TFWMInternalModifier b) -{ - if (a.description != b.description) - return false; - if (a.have != b.have) - return false; - if (a.obtainable_now != b.obtainable_now) - return false; - if (a.obtainable_theoretically != b.obtainable_theoretically) - return false; - if (a.bonus != b.bonus) - return false; - if (a.from_familiar_equipment != b.from_familiar_equipment) - return false; - return true; -} - -TFWMInternalModifier TFWMInternalModifierMake(string description, boolean have, boolean obtainable_now, boolean obtainable_theoretically, float bonus, boolean from_familiar_equipment) -{ - TFWMInternalModifier result; - result.description = description; - result.have = have; - result.obtainable_now = obtainable_now; - result.obtainable_theoretically = obtainable_theoretically; - result.bonus = bonus; - result.from_familiar_equipment = from_familiar_equipment; - - return result; -} - -TFWMInternalModifier TFWMInternalModifierMake(string description, boolean have, boolean obtainable_now, boolean obtainable_theoretically, float bonus) -{ - return TFWMInternalModifierMake(description, have, obtainable_now, obtainable_theoretically, bonus, false); -} - -TFWMInternalModifier TFWMInternalModifierMake() -{ - return TFWMInternalModifierMake("", false, false, false, 0); -} - -TFWMInternalModifier TFWMInternalModifierMake(skill s) -{ - effect e = s.to_effect(); - string description = s; - if (e != $effect[none] && e.have_effect() == 0) - description += " (cast)"; - - float weight_modifier = 0.0; - if (e != $effect[none]) - weight_modifier = e.numeric_modifier("familiar weight"); - else - weight_modifier = s.numeric_modifier("familiar weight"); - - return TFWMInternalModifierMake(description, s.skill_is_usable(), s.skill_is_usable(), s.skill_is_usable(), weight_modifier); -} - -TFWMInternalModifier TFWMInternalModifierMake(item equippable_item) -{ - if (equippable_item.available_amount() == 0) - return TFWMInternalModifierMake(); - float weight_modifier = equippable_item.numeric_modifier("familiar weight"); - - if (equippable_item == $item[crown of thrones]) - weight_modifier = 5.0; - - - string description = equippable_item; - if (equippable_item.equipped_amount() == 0) - description += " (equip)"; - - TFWMInternalModifier result = TFWMInternalModifierMake(description, true, true, true, weight_modifier); - - if (equippable_item.to_slot() == $slot[familiar]) - result.from_familiar_equipment = true; - return result; -} - -void listAppend(TFWMInternalModifier [int] list, TFWMInternalModifier entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - - -//Returns TRUE if they currently have, or can easily have, enough to pass. -//Example use: -/* - string [int] how; - string [int] immediately_obtainable; - string [int] missing_potentials; - FloatHandle missing_weight; - return !generateTowerFamiliarWeightMethod(how, immediately_obtainable, missing_potentials, missing_weight); -*/ -boolean generateTowerFamiliarWeightMethod(string [int] how, string [int] immediately_obtainable, string [int] missing_potentials, FloatHandle missing_weight) -{ - missing_weight.f = 0.0; - if (__quest_state["Level 13"].finished) //no need - return true; - if (!__misc_state["in run"]) - return true; - if (__misc_state["familiars temporarily blocked"]) - return true; - - - //Not the best of solutions, but... - - TFWMInternalModifier [int] weight_modifiers; - - //amphibian sympathy - weight_modifiers.listAppend(TFWMInternalModifierMake($skill[amphibian sympathy])); - //leash of linguini - weight_modifiers.listAppend(TFWMInternalModifierMake($skill[leash of linguini])); - //empathy of the newt - weight_modifiers.listAppend(TFWMInternalModifierMake($skill[empathy of the newt])); - //knob goblin pet-buffing spray - if ($item[knob goblin pet-buffing spray].available_amount() > 0 || dispensary_available() || $effect[heavy petting].have_effect() > 0 && false) - { - weight_modifiers.listAppend(TFWMInternalModifierMake("knob goblin pet-buffing spray", true, true, true, 5.0)); - } - else if (__misc_state["can equip just about any weapon"]) - { - weight_modifiers.listAppend(TFWMInternalModifierMake("knob goblin pet-buffing spray (unlock cobb's knob dispensary)", false, false, true, 5.0)); - } - //hippy concert - if (get_property("sidequestArenaCompleted") == "hippy" && !get_property_boolean("concertVisited") || $effect[Optimist Primal].have_effect() > 0) - { - boolean have_effect = $effect[Optimist Primal].have_effect() > 0; - weight_modifiers.listAppend(TFWMInternalModifierMake("Optimist Primal (hippy concert)", have_effect, have_effect || !get_property_boolean("concertVisited"), true, 5.0)); - } - //irradiated pet snacks - if ($item[irradiated pet snacks].available_amount() > 0 || $effect[healthy green glow].have_effect() > 0) - { - boolean have_effect = $effect[healthy green glow].have_effect() > 0; - weight_modifiers.listAppend(TFWMInternalModifierMake("irradiated pet snacks", have_effect, true, true, 10.0)); - } - else if (__misc_state["can eat just about anything"] || (__misc_state["can drink just about anything"] && __misc_state["VIP available"])) - { - weight_modifiers.listAppend(TFWMInternalModifierMake("irradiated pet snacks (lucky adventure, menagerie level 2)", false, false, true, 10.0)); - } - if (__misc_state["VIP available"] && __misc_state["can drink just about anything"]) - { - if (get_property_int("_speakeasyDrinksDrunk") <3 && availableDrunkenness() >= 3 && $item[clan speakeasy].is_unrestricted()) - { - boolean have_effect = $effect[1701].have_effect() > 0; //hip to the jive - weight_modifiers.listAppend(TFWMInternalModifierMake("Speakeasy hot socks", have_effect, true, true, 10.0)); - } - - } - //billiards - if (__misc_state["VIP available"] && get_property_int("_poolGames") <3 && $item[Clan pool table].is_unrestricted() || $effect[Billiards Belligerence].have_effect() > 0) - { - boolean have_effect = $effect[Billiards Belligerence].have_effect() > 0; - weight_modifiers.listAppend(TFWMInternalModifierMake("VIP Pool (play aggressively)", have_effect, have_effect || (get_property_int("_poolGames") <3), true, 5.0)); - } - //tea party - if (($item["DRINK ME" potion].available_amount() > 0 || $effect[Down the Rabbit Hole].have_effect() > 0) && (!get_property_boolean("_madTeaParty") || $effect[You Can Really Taste the Dormouse].have_effect() > 0)) - { - boolean have_effect = $effect[You Can Really Taste the Dormouse].have_effect() > 0; - weight_modifiers.listAppend(TFWMInternalModifierMake("Mad hatter (reinforced beaded headband)", have_effect, have_effect, true, 5.0)); - } - //beastly paste - if ($item[beastly paste].available_amount() > 0 || $effect[Beastly Flavor].have_effect() > 0) - { - boolean have_effect = $effect[Beastly Flavor].have_effect() > 0; - weight_modifiers.listAppend(TFWMInternalModifierMake("beastly paste (4 spleen)", have_effect, true, true, 3.0)); - } - else if ($familiar[pair of stomping boots].familiar_is_usable()) - { - weight_modifiers.listAppend(TFWMInternalModifierMake("beastly paste (4 spleen, stomp beasts)", false, false, true, 3.0)); - } - //resolution - if ($item[resolution: be kinder].available_amount() > 0 || $effect[Kindly Resolve].have_effect() > 0) - { - boolean have_effect = $effect[Kindly Resolve].have_effect() > 0; - weight_modifiers.listAppend(TFWMInternalModifierMake("resolution: be kinder", have_effect, true, true, 5.0)); - } - else if ($skill[summon resolutions].skill_is_usable() && __misc_state["bookshelf accessible"]) - { - weight_modifiers.listAppend(TFWMInternalModifierMake("resolution: be kinder (summon)", false, false, true, 5.0)); - } - //green candy heart - skill candy_hearts = $skill[Summon Candy Heart]; - if ($item[green candy heart].available_amount() > 0 || $effect[Heart of Green].have_effect() > 0) - { - boolean have_effect = $effect[Heart of Green].have_effect() > 0; - weight_modifiers.listAppend(TFWMInternalModifierMake("green candy heart", have_effect, true, true, 3.0)); - } - else if (candy_hearts.skill_is_usable() && __misc_state["bookshelf accessible"] && candy_hearts != $skill[none]) - { - weight_modifiers.listAppend(TFWMInternalModifierMake("green candy heart (summon)", false, false, true, 3.0)); - } - - //sugar sheet, sugar shield - if ($item[astral pet sweater].available_amount() == 0 && ($item[snow suit].available_amount() == 0 || $item[snow suit].numeric_modifier("familiar weight") < 10.0)) - { - if ($item[sugar shield].available_amount() > 0) - weight_modifiers.listAppend(TFWMInternalModifierMake($item[sugar shield])); - else if ($item[sugar sheet].available_amount() > 0) - { - weight_modifiers.listAppend(TFWMInternalModifierMake("sugar shield (use sugar sheet)", false, true, true, 10.0, true)); - } - else if ($skill[Summon Sugar Sheets].skill_is_usable() && __misc_state["bookshelf accessible"]) - { - //TFWMInternalModifier TFWMInternalModifierMake(string description, boolean have, boolean obtainable_now, boolean obtainable_theoretically, float bonus) - weight_modifiers.listAppend(TFWMInternalModifierMake("sugar shield (summon sugar sheet)", false, false, true, 10.0, true)); - } - } - //ittah bittah hookah - weight_modifiers.listAppend(TFWMInternalModifierMake($item[ittah bittah hookah])); - //lead necklace - weight_modifiers.listAppend(TFWMInternalModifierMake($item[lead necklace])); - //snow suit - numeric_modifier($item[snow suit], "familiar weight") - weight_modifiers.listAppend(TFWMInternalModifierMake($item[snow suit])); - //astral pet sweater - weight_modifiers.listAppend(TFWMInternalModifierMake($item[astral pet sweater])); - - //greaves of the whatever - weight_modifiers.listAppend(TFWMInternalModifierMake($item[greaves of the murk lord])); - //furry halo - weight_modifiers.listAppend(TFWMInternalModifierMake($item[furry halo])); - //CoT, if they have the right familiars - if ($familiars[Animated Macaroni Duck, Autonomous Disco Ball, Barrrnacle, Gelatinous Cubeling, Ghost Pickle on a Stick, Misshapen Animal Skeleton, Pair of Ragged Claws, Penguin Goodfella, Spooky Pirate Skeleton].have_familiar_replacement()) - { - weight_modifiers.listAppend(TFWMInternalModifierMake($item[crown of thrones])); - } - - - //Find best familiar equipment: - TFWMInternalModifier best_familiar_equipment; - foreach key in weight_modifiers - { - TFWMInternalModifier weight_modifier = weight_modifiers[key]; - if (weight_modifier.have && weight_modifier.from_familiar_equipment) - { - if (weight_modifier.bonus > best_familiar_equipment.bonus) - best_familiar_equipment = weight_modifier; - } - } - - float total = 0.0; - foreach key in weight_modifiers - { - TFWMInternalModifier weight_modifier = weight_modifiers[key]; - string description = weight_modifier.description; - description += " (+" + weight_modifier.bonus.floor() + ")"; - if (weight_modifier.have) - { - if (best_familiar_equipment.have && weight_modifier.from_familiar_equipment && !TFWMInternalModifierEquals(best_familiar_equipment, weight_modifier)) //not our chosen familiar equipment - continue; - how.listAppend(description); - total += weight_modifier.bonus; - } - else if (weight_modifier.obtainable_now) - { - immediately_obtainable.listAppend(description); - } - else if (weight_modifier.obtainable_theoretically) - { - missing_potentials.listAppend(description); - } - - } - missing_weight.f = MAX(0, 19 - total); - - if (numeric_modifier("familiar weight") >= 19.0) - return true; - if (total >= 19.0) - return true; - else - return false; -} - - - -string generatePotatoSuggestion() -{ - if (familiar_is_usable($familiar[fancypants scarecrow]) && $item[swashbuckling pants].available_amount() > 0) - return "Run swashbuckling pants on scarecrow. (2x potato)"; - else if (familiar_is_usable($familiar[fancypants scarecrow]) && $item[spangly mariachi pants].available_amount() > 0) - return "Run spangly mariachi pants on scarecrow. (2x potato)"; - else if (familiar_is_usable($familiar[mad hatrack]) && $item[spangly sombrero].available_amount() > 0) - return "Run spangly sombrero on mad hatrack. (2x potato)"; - else - return "Run a potato familiar if you can."; -} - - -void QLevel13Init() -{ - //questL13Final - - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL13Final"); - if (__misc_state["in aftercore"] || my_path().id == PATH_BUGBEAR_INVASION || my_path().id == PATH_SEA || my_path().id == PATH_GREY_GOO || (!state.in_progress && my_path().id == PATH_ACTUALLY_ED_THE_UNDYING)) //FIXME mafia may track the ed L13 quest under this variable - QuestStateParseMafiaQuestPropertyValue(state, "finished"); //never will start - if (__misc_state["Example mode"]) - QuestStateParseMafiaQuestPropertyValue(state, "step6"); - state.quest_name = "Naughty Sorceress Quest"; - state.image_name = "naughty sorceress lair"; - state.council_quest = true; - - state.state_string["Stat race type"] = ""; //telescope1 - state.state_string["Elemental damage race type"] = ""; //telescope2 - - //FIXME these all need checking: - string [string] telescope1_messages_to_type; - telescope1_messages_to_type["all wearing sunglasses and dancing"] = "moxie"; - telescope1_messages_to_type["standing around flexing their muscles and using grip exercisers"] = "muscle"; - telescope1_messages_to_type["sitting around playing chess and solving complicated-looking logic puzzles"] = "mysticality"; - - string [string] telescope2_messages_to_type; - telescope2_messages_to_type["greasy-looking people furtively skulking around"] = "sleaze"; - telescope2_messages_to_type["people, all of whom appear to be on fire"] = "hot"; //??? - telescope2_messages_to_type["people, clustered around a group of igloos"] = "cold"; - telescope2_messages_to_type["people, surrounded by a cloud of eldritch mist"] = "spooky"; //??? - telescope2_messages_to_type["people, surrounded by garbage and clouds of flies"] = "stench"; - - string [string] telescope3_messages_to_type; - string [string] telescope4_messages_to_type; - string [string] telescope5_messages_to_type; - - telescope3_messages_to_type["creepy-looking black bushes on the outskirts of a hedge maze"] = "spooky"; - telescope3_messages_to_type["nasty-looking, dripping green bushes on the outskirts of a hedge maze"] = "stench"; //stench? sleaze? - telescope3_messages_to_type["purplish, greasy-looking hedges"] = "sleaze"; //??? - telescope3_messages_to_type["smoldering bushes on the outskirts of a hedge maze"] = "hot"; //??? - telescope3_messages_to_type["frost-rimed bushes on the outskirts of a hedge maze"] = "cold"; - - telescope4_messages_to_type["a greasy purple cloud hanging over the center of the maze"] = "sleaze"; - telescope4_messages_to_type["smoke rising from deeper within the maze"] = "hot"; //???? - telescope4_messages_to_type["a miasma of eldritch vapors rising from deeper within the maze"] = "spooky"; //???? - telescope4_messages_to_type["a cloud of green gas hovering over the maze"] = "stench"; //???? - telescope4_messages_to_type["wintry mists rising from deeper within the maze"] = "cold"; - - telescope5_messages_to_type["occasionally disgorging a bunch of ice cubes"] = "cold"; - telescope5_messages_to_type["that occasionally vomits out a greasy ball of hair"] = "sleaze"; //??? - telescope5_messages_to_type["surrounded by creepy black mist"] = "spooky"; //??? - telescope5_messages_to_type["disgorging a really surprising amount of sewage"] = "stench"; //??? - telescope5_messages_to_type["with lava slowly oozing out of it"] = "hot"; //??? - - state.state_string["Stat race type"] = get_property("nsChallenge1"); //telescope1_messages_to_type[get_property("telescope1")]; - if (state.state_string["Stat race type"] == "none") - state.state_string["Stat race type"] = ""; - state.state_string["Elemental damage race type"] = get_property("nsChallenge2"); //telescope2_messages_to_type[get_property("telescope2")]; - if (state.state_string["Elemental damage race type"] == "none") - state.state_string["Elemental damage race type"] = ""; - - string [int] elements_needed = listMake(telescope3_messages_to_type[get_property("telescope3")], telescope4_messages_to_type[get_property("telescope4")], telescope5_messages_to_type[get_property("telescope5")]); - - boolean have_all_elements = true; - foreach key, e in elements_needed - { - if (e.length() == 0) - { - have_all_elements = false; - break; - } - } - state.state_string["Hedge maze elements needed"] = ""; - if (have_all_elements) - state.state_string["Hedge maze elements needed"] = elements_needed.listJoinComponents("|"); - - state.state_boolean["past races"] = state.mafia_internal_step >= 4; - - state.state_boolean["Init race completed"] = get_property_int("nsContestants1") != -1; - state.state_boolean["Stat race completed"] = get_property_int("nsContestants2") != -1; - state.state_boolean["Elemental damage race completed"] = get_property_int("nsContestants3") != -1; - if (state.finished || state.state_boolean["past races"]) - { - state.state_boolean["Init race completed"] = true; - state.state_boolean["Stat race completed"] = true; - state.state_boolean["Elemental damage race completed"] = true; - } - - state.state_boolean["past hedge maze"] = state.mafia_internal_step >= 6; - state.state_boolean["past keys"] = state.mafia_internal_step >= 7; - - state.state_boolean["past tower level 1"] = state.mafia_internal_step >= 8; - state.state_boolean["past tower level 2"] = state.mafia_internal_step >= 9; - state.state_boolean["past tower level 3"] = state.mafia_internal_step >= 10; - state.state_boolean["past tower level 4"] = state.mafia_internal_step >= 11; - state.state_boolean["past tower level 5"] = state.mafia_internal_step >= 12; - - state.state_boolean["past tower monsters"] = state.state_boolean["past tower level 3"]; //5 - state.state_boolean["wall of skin will need to be defeated"] = !state.state_boolean["past tower level 1"]; - state.state_boolean["wall of meat will need to be defeated"] = !state.state_boolean["past tower level 2"]; - state.state_boolean["wall of bones will need to be defeated"] = !state.state_boolean["past tower level 3"]; - state.state_boolean["shadow will need to be defeated"] = !state.state_boolean["past tower level 5"]; - //FIXME what paths don't fight the shadow? - state.state_boolean["king waiting to be freed"] = (state.mafia_internal_step >= 14 && !state.finished); - - //",," => {1:"",2:"",3:""} => {1:,2:,3:} => {:true,:true,:true} - boolean [item] keys_used = get_property("nsTowerDoorKeysUsed").split_string_alternate(",").listConvertToItem().listInvert(); - - foreach base_key in __ns_tower_door_base_keys { - state.state_boolean[base_key.name + " used"] = (keys_used contains base_key) || state.state_boolean["past keys"]; - } - - if (my_path().id == PATH_LOW_KEY_SUMMER) { - foreach index, LKS_key in LKS_keys { - if (LKS_key.it != $item[none]) { - LKS_key.was_used = (keys_used contains LKS_key.it) || state.state_boolean["past keys"]; - state.state_boolean[LKS_key.it.name + " used"] = LKS_key.was_used; - } - } - } - - //Silent, Shell Up, Sauceshell - - boolean other_quests_completed = true; - for i from 2 to 12 - { - if (!__quest_state["Level " + i].finished) - { - other_quests_completed = false; - } - } - if (other_quests_completed && (my_level() >= 13 || my_path().id == PATH_EXPLOSIONS)) - state.startable = true; - - - __quest_state["Level 13"] = state; - __quest_state["Lair"] = state; -} - - -void QLevel13GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 13"].in_progress) - return; - QuestState base_quest_state = __quest_state["Level 13"]; - ChecklistSubentry subentry; - ChecklistSubentry [int] subentries; - subentries.listAppend(subentry); - subentry.header = base_quest_state.quest_name; - string url = "place.php?whichplace=nstower"; - - string image_name = base_quest_state.image_name; - - boolean should_output_main_entry = true; - if (!base_quest_state.state_boolean["past races"] && (base_quest_state.state_string["Stat race type"].length() == 0 || base_quest_state.state_string["Elemental damage race type"].length() == 0)) - { - subentry.header = "Visit the registration desk"; - subentry.entries.listAppend("Find out what the races are, first."); - image_name = "lair registration desk"; - } - else if (base_quest_state.mafia_internal_step == 3) - { - image_name = "lair registration desk"; - subentry.header = "Visit the registration desk"; - subentry.entries.listAppend("Claim your prize!"); - url = "place.php?whichplace=nstower&action=ns_01_contestbooth"; - } - else if (!base_quest_state.state_boolean["past races"]) - { - image_name = "lair registration desk"; - remove subentries[0]; - - if (!base_quest_state.state_boolean["Init race completed"]) - { - string [int] description; - float current_value = numeric_modifier("initiative"); - - description.listAppend("Currently " + current_value.floor() + "%."); - - if (current_value < 400.0) - { - description.listAppend("Need " + (400.0 - current_value).roundForOutput(1) + "% more initiative for #2."); - - if (!($familiars[oily woim,Xiblaxian Holo-Companion] contains my_familiar()) && !__misc_state["familiars temporarily blocked"]) - { - familiar [int] init_familiar_evaluation_order; - init_familiar_evaluation_order.listAppend($familiar[Xiblaxian Holo-Companion]); - init_familiar_evaluation_order.listAppend($familiar[oily woim]); - foreach key, f in init_familiar_evaluation_order - { - if (f.familiar_is_usable()) - { - description.listAppend("Try switching to your " + f + "."); - break; - } - } - } - if (__misc_state_int["pulls available"] > 0) - { - boolean [item] blacklist;// = $items[hare brush,freddie's blessing of mercury,ruby on canes]; - item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Initiative", 30, blacklist); - string [int] relevant_potions_output; - foreach key, it in relevant_potions - { - float initiative_modifier = it.to_effect().numeric_modifier("Initiative"); - if ($effect[Bow-Legged Swagger].have_effect() > 0) - initiative_modifier *= 2.0; - relevant_potions_output.listAppend(it + " (" + initiative_modifier.roundForOutput(0) + "%)"); - } - - if (relevant_potions_output.count() > 0) - description.listAppend("Could try pulling " + relevant_potions_output.listJoinComponents(", ", "or") + "."); - } - } - else - description.listAppend("Take the test now, you should(?) make second place."); - - subentries.listAppend(ChecklistSubentryMake("Compete in the init race", "+init", description)); - } - if (!base_quest_state.state_boolean["Stat race completed"]) - { - stat stat_type = base_quest_state.state_string["Stat race type"].to_stat(); - string [int] description; - float current_value = my_buffedstat(stat_type); - - - //FIXME find this value; current is a guess - //highest seen #3 is 577 moxie - if (current_value < 600.0) - { - description.listAppend("Need " + (600.0 - current_value).roundForOutput(1) + " more " + stat_type.to_lower_case() + " for #2."); - } - else - description.listAppend("Take the test now, you should(?) make second place."); - - if (stat_type != $stat[none] && current_value < 600.0) - { - if (__misc_state_int["pulls available"] > 0) - { - float base_stat = MAX(1.0, my_basestat(stat_type)); - - //Rümpelstiltz,gummi snake,handful of laughing willow bark,dennis's blessing of minerva,smart watch,mer-kin smartjuice,lump of saccharine maple sap,burt's blessing of bacchus,augmented-reality shades,mer-kin cooljuice,lobos mints,mariachi toothpaste,disco horoscope (virgo),pressurized potion of pulchritude,pressurized potion of perspicacity,pressurized potion of puissance,handful of crotchety pine needles,bruno's blessing of mars,fitness wristband,gummi salamander,bottle of fire,banana smoothie,banana supersucker,ennui-flavored potato chips,moonds,ultrasoldier serum,kumquat supersucker,mer-kin strongjuice, - boolean [item] blacklist = $items[snake,M-242,sparkler]; //limited/expensive/unusable content - item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier(stat_type, MIN(600 - current_value, 25), blacklist); - item [int] relevant_potions_source_2 = ItemFilterGetPotionsCouldPullToAddToNumericModifier(stat_type + " percent", 25.0 / base_stat * 100.0, blacklist); - - relevant_potions.listAppendList(relevant_potions_source_2); - - sort relevant_potions by -(value.to_effect().numeric_modifier(stat_type) + (value.to_effect().numeric_modifier(stat_type + " percent") / 100.0 * my_basestat(stat_type))); - - - string [int] relevant_potions_output; - foreach key, it in relevant_potions - { - float total = (it.to_effect().numeric_modifier(stat_type) + (it.to_effect().numeric_modifier(stat_type + " percent") / 100.0 * my_basestat(stat_type))); - string line = it + " (" + total.roundForOutput(1) + ")"; - //if (it.mall_price() >= 15000) //for internal use, to fill out the blacklist - //line = HTMLGenerateSpanFont(line, "red", ""); - relevant_potions_output.listAppend(line); - } - - if (relevant_potions_output.count() > 0) - description.listAppend("Could try pulling " + relevant_potions_output.listJoinComponents(", ", "or") + "."); - } - } - - subentries.listAppend(ChecklistSubentryMake("Compete in the " + stat_type + " race", "+" + stat_type.to_string().to_lower_case(), description)); - } - if (!base_quest_state.state_boolean["Elemental damage race completed"]) - { - element element_type = base_quest_state.state_string["Elemental damage race type"].to_element(); - - string [int] description; - - string element_class = "r_element_" + element_type; - string element_class_desaturated = element_class + "_desaturated"; - - float current_value = numeric_modifier(element_type + " damage") + numeric_modifier(element_type + " spell damage"); - if (current_value < 100.0) - { - description.listAppend("Need " + (100.0 - current_value).roundForOutput(1) + " more " + HTMLGenerateSpanOfClass(element_type + " damage ", element_class) + " + " + HTMLGenerateSpanOfClass(element_type + " spell damage", element_class) + " for #2."); - - - if (__misc_state_int["pulls available"] > 0) - { - boolean [item] blacklist = $items[witch's brew,boiling seal blood]; - item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier(listMake(element_type + " damage", element_type + " spell damage"), 30, blacklist); - string [int] relevant_potions_output; - foreach key, it in relevant_potions - { - relevant_potions_output.listAppend(it + " (" + (it.to_effect().numeric_modifier(element_type + " damage") + it.to_effect().numeric_modifier(element_type + " spell damage")).roundForOutput(0) + ")"); - } - - if (relevant_potions_output.count() > 0) - description.listAppend("Could try pulling " + relevant_potions_output.listJoinComponents(", ", "or") + "."); - } - } - else - description.listAppend("Take the test now, you should(?) make second place."); - description.listAppend("Currently " + current_value.roundForOutput(1) + "."); - - subentries.listAppend(ChecklistSubentryMake("Compete in the " + HTMLGenerateSpanOfClass(element_type + " damage", element_class) + " race", listMake("+" + HTMLGenerateSpanOfClass(element_type + " damage", element_class_desaturated), "+" + HTMLGenerateSpanOfClass(element_type + " spell damage", element_class_desaturated)), description)); - } - - int total_contestants_to_fight = 0; - foreach s in $strings[nsContestants1,nsContestants2,nsContestants3] - { - if (get_property_int(s) > 0) - total_contestants_to_fight += get_property_int(s); - } - if (total_contestants_to_fight > 0) - { - subentries.listAppend(ChecklistSubentryMake("Fight " + pluraliseWordy(total_contestants_to_fight, "more contestant", "more contestants"), "", "")); - } - else if (subentries.count() == 0) - { - //hmm... - subentries.listAppend(ChecklistSubentryMake("Visit the registration desk", "", "Claim your prize!")); - url = "place.php?whichplace=nstower&action=ns_01_contestbooth"; - } - else if (total_contestants_to_fight == 0) - url = "place.php?whichplace=nstower&action=ns_01_contestbooth"; - //nsContestants1 - default -1 - //nsContestants2 - default -1 - //nsContestants3 - default -1 - } - else if (base_quest_state.mafia_internal_step == 4) - { - subentry.header = "Attend your coronation"; - image_name = "__item Snow Queen Crown"; - } - else if (!base_quest_state.state_boolean["past hedge maze"]) - { - //FIXME individualised room support - //need X more hot resistance, Y more Z resistance to pass elemental tests - subentry.header = "Find your way through the Hedge Maze"; - image_name = "__item hedge maze puzzle"; - int current_room = get_property_int("currentHedgeMazeRoom"); - if (current_room >= 9) - { - subentry.entries.listAppend("Almost there..."); - } - else - { - int [element] elements_needed_to_pass; - string [int] resists_needed_for_hedge_maze = base_quest_state.state_string["Hedge maze elements needed"].split_string_alternate("\\|"); - float total_damage_taken_from_resists = 0.0; - if (resists_needed_for_hedge_maze.count() > 0) - { - foreach key, element_name in resists_needed_for_hedge_maze - { - element e = element_name.to_element(); - if (e == $element[none]) //wha? - continue; - elements_needed_to_pass[e] = 7; - float percentage = 0.0; - if (key == 0) percentage = 0.9; - if (key == 1) percentage = 0.8; - if (key == 2) percentage = 0.7; - float resist = e.elemental_resistance() / 100.0; - float damage_taken = my_maxhp() * percentage * (1.0 - resist); - total_damage_taken_from_resists += damage_taken; - } - } - else - { - total_damage_taken_from_resists = 10000; - elements_needed_to_pass[$element[hot]] = 7; - elements_needed_to_pass[$element[stench]] = 7; - elements_needed_to_pass[$element[spooky]] = 7; - elements_needed_to_pass[$element[cold]] = 7; - elements_needed_to_pass[$element[sleaze]] = 7; - } - - int [element] amount_missing; - foreach e, amount_needed in elements_needed_to_pass - { - subentry.modifiers.listAppend("+" + HTMLGenerateSpanOfClass(amount_needed + " " + e + " resistance", "r_element_" + e + "_desaturated")); - float amount_have = numeric_modifier(e + " resistance"); - if (amount_have < amount_needed) - { - amount_missing[e] = amount_needed - amount_have; - } - } - if (amount_missing.count() > 0 && total_damage_taken_from_resists >= my_maxhp()) - { - if ($familiar[exotic parrot].familiar_is_usable() && !__misc_state["familiars temporarily blocked"]) - subentry.entries.listAppend("Potentially switch to the exotic parrot."); - - string [int] amount_missing_string; - foreach e, amount in amount_missing - { - amount_missing_string.listAppend(HTMLGenerateSpanOfClass(amount + " more " + e + " resistance", "r_element_" + e)); - } - subentry.entries.listAppend("Need " + amount_missing_string.listJoinComponents(", ", "and") + " to safely make it through the maze quickly."); - } - else - { - subentry.modifiers.listClear(); - subentry.entries.listAppend("Choose the second option each time to save the most turns."); - } - if (my_hp() < my_maxhp() && current_room <= 1) - { - //FIXME only output this if we won't make it. - subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); - } - } - - //elemental tests are 1, 4, 7 - //9 is escape - //subentry.entries.listAppend("currentHedgeMazeRoom = " + get_property_int("currentHedgeMazeRoom")); - } - else if (!base_quest_state.state_boolean["past keys"]) - { - url = "place.php?whichplace=nstower_door"; - subentry.header = "Open the tower door"; - - item [int] missing_keys; - foreach base_key in __ns_tower_door_base_keys { - if (!base_quest_state.state_boolean[base_key.name + " used"] && base_key.available_amount() == 0) { - /*string key_name_output = base_key.name.replace_string(" key", ""); - key_name_output = HTMLGenerateSpanFont(key_name_output, "grey");*/ //unused - missing_keys.listAppend(base_key); - } - } - if (my_path().id == PATH_LOW_KEY_SUMMER) { - foreach index, LKS_key in LKS_keys { - if (!LKS_key.was_used) - missing_keys.listAppend(LKS_key.it); - } - } - - if (missing_keys.count() == 0) { - subentry.entries.listAppend("Open the doorknob."); - } else { - subentry.entries.listAppend("Find " + pluraliseWordy(missing_keys.count(), "more key", "more keys") + " for the door"); - } - - if (my_path().id != PATH_LOW_KEY_SUMMER) { //has its own file, Low Key.ash, when in Low Key Summer - foreach keyIndex, key in missing_keys { - subentry.entries.listAppend(key); - } - } - - } - else if (!base_quest_state.state_boolean["past tower level 1"]) - { - //wall of skin - subentry.header = "Defeat the Wall of Skin"; - if ($item[beehive].available_amount() > 0) - { - subentry.entries.listAppend("Use the beehive against it."); - } - else - { - subentry.entries.listAppend("Either find the beehive in the black forest (-combat), or towerkill."); - subentry.entries.listAppend("Lots of passive damage sources."); - if (my_path().id == PATH_BIG) - subentry.entries.listAppend("Towerkilling is likely impractical in BIG?"); - //Originally I wanted this to properly calculate the exact amount of damage you can do against the wall of skin. - //But, I feel like that would be super complicated and prone to error. - //So, we'll just give suggestions and hope it works out. - boolean have_prismatic_damage = true; - string [int] prismatic_damage_needed; - foreach e in $elements[hot,cold,sleaze,stench,spooky] - { - if (numeric_modifier(e + " damage") > 0) continue; - have_prismatic_damage = false; - prismatic_damage_needed.listAppend(e); - } - string [int] methods; - string [int] skills_to_cast; - foreach s in $skills[spiky shell,Jalapeño Saucesphere,The Psalm of Pointiness,Scarysauce] - { - if (s.to_effect().have_effect() > 0) - continue; - if (!s.have_skill()) - continue; - if (!s.is_unrestricted()) - continue; - skills_to_cast.listAppend(s); - } - if (skills_to_cast.count() > 0) - { - methods.listAppend("Cast " + skills_to_cast.listJoinComponents(", ", "and") + "."); - } - if ($item[colorful toad].have() && $item[colorful toad].item_is_usable() && $item[colorful toad].to_effect().have_effect() == 0 && !have_prismatic_damage && my_path().id != PATH_2CRS) - methods.listAppend("Use colorful toad for +prismatic damage."); - familiar desired_familiar = $familiar[none]; - if ($familiar[mu].familiar_is_usable()) - { - methods.listAppend("Run extra +familiar weight for your mu; it will attack more often."); - desired_familiar = $familiar[mu]; - } - else if ($familiar[Imitation Crab].familiar_is_usable()) - desired_familiar = $familiar[Imitation Crab]; - else if ($familiar[Sludgepuppy].familiar_is_usable()) - desired_familiar = $familiar[Sludgepuppy]; - else if ($familiar[mini-crimbot].familiar_is_usable()) - { - desired_familiar = $familiar[mini-crimbot]; - //(crimbotArm - "STAL-1 UltraFist" or "Frostronic Hypercoil"/crimbotChassis - "Music Box Box"/crimbotPropulsion - "X-1 Hover Rocket") - string [int] configure_options; - if (get_property("crimbotChassis") == "") - configure_options.listAppend("Music Box Box"); - if (get_property("crimbotArm") == "") - configure_options.listAppend("STAL-1 UltraFist"); - if (get_property("crimbotPropulsion") == "") - configure_options.listAppend("X-1 Hover Rocket"); - if (configure_options.count() > 0) - methods.listAppend("Configure mini-crimbot for " + configure_options.listJoinComponents(" / ") + "."); - } - - if (!__misc_state["familiars temporarily blocked"] && desired_familiar != $familiar[none] && my_familiar() != desired_familiar) - { - methods.listAppend("Switch to familiar " + desired_familiar + "."); - } - item [int] items_to_equip; - foreach it in $items[hand in glove,bottle opener belt buckle,buddy bjorn,smirking shrunken head,kremlin's greatest briefcase] - { - if (!it.have()) continue; - if (it.equipped()) continue; - items_to_equip.listAppend(it); - } - if (items_to_equip.count() > 0) - { - methods.listAppend("Equip " + items_to_equip.listJoinComponents(", ", "and") + "?"); - } - if ($item[buddy bjorn].equipped() && $familiar[misshapen animal skeleton].familiar_is_usable() && my_bjorned_familiar() != $familiar[misshapen animal skeleton]) - methods.listAppend("Put misshapen animal skeleton in the buddy bjorn."); - - if (!have_prismatic_damage) - { - methods.listAppend("Gain prismatic damage. Need " + prismatic_damage_needed.listJoinComponents(", ", "and") + "."); - } - - if (monster_level_adjustment() > 0) - methods.listAppend("Reduce monster level."); - - - string [int] attack_methods; - if ($skill[shieldbutt].skill_is_usable()) - attack_methods.listAppend("shieldbutt if you can hit" + ($slot[off-hand].equipped_item().item_type() != "shield" ? " but equip a shield first" : "")); - if ($skill[headbutt].skill_is_usable()) - attack_methods.listAppend("headbutt if you can hit" + ($slot[hat].equipped_item() == $item[none] ? " but equip a hat first" : "")); - if ($skill[belch the rainbow].skill_is_usable()) - attack_methods.listAppend("belch the rainbow"); - if ($skill[clobber].skill_is_usable()) - attack_methods.listAppend("clobber"); - attack_methods.listAppend("regular attack(?)"); - if (attack_methods.count() > 0) - { - methods.listAppend("Attack using " + attack_methods.listJoinComponents(", ", "or") + "."); - } - - /* - - item best_shield = $item[none]; - foreach it in __items_shields - { - if (it.to_slot() != $slot[off-hand]) continue; - if (it.item_type() != "shield") continue; - if (!it.can_equip()) continue; - if (it.available_amount() == 0) continue; - if (it.get_power() > best_shield.get_power() || best_shield == $item[none]) - best_shield = it; - } - */ - if (methods.count() > 0) - subentry.entries.listAppend("Towerkilling ideas:|*" + methods.listJoinComponents("
")); - if (my_hp() < my_maxhp()) - { - //FIXME only output this if we won't make it. - subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); - } - } - } - else if (!base_quest_state.state_boolean["past tower level 2"]) - { - //wall of meat - //current assumption is it's a [160, 240] drop, and you need to clear one thousand (thousand slimy) meats - subentry.header = "Defeat the Wall of Meat"; - subentry.modifiers.listAppend("+526% meat"); - - float current_value = numeric_modifier("meat drop"); - if (current_value < 526.0) - { - subentry.entries.listAppend("Need " + (526.0 - current_value).roundForOutput(0) + "% more meat drop to always complete in a single turn."); - - float meat_multiplier = 1.0 + current_value / 100.0; - float chance = 1.0 - TriangularDistributionCalculateCDF(1001.0, 160.0 * meat_multiplier, 240.0 * meat_multiplier); - if (chance > 0.0) - subentry.entries.listAppend((chance * 100.0).floor() + "% chance of completing in one turn."); - } - else - subentry.entries.listAppend("Should take one turn."); - - if (__misc_state_int["pulls available"] > 0 && current_value < 526.0) - { - float delta = 526.0 - current_value; - boolean [item] blacklist = $items[uncle greenspan's bathroom finance guide,black snowcone,sorority brain,blue grass,salt wages,perl necklace]; - item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Meat Drop", MIN(25, delta), blacklist); - string [int] relevant_potions_output; - foreach key, it in relevant_potions - { - relevant_potions_output.listAppend(it + " (" + it.to_effect().numeric_modifier("meat drop").roundForOutput(0) + "%)"); - } - - if (relevant_potions_output.count() > 0) - subentry.entries.listAppend("Could try pulling " + relevant_potions_output.listJoinComponents(", ", "or") + "."); - } - //FIXME does mafia have a tracking variable for meat dropped? - //FIXME REST - //estimated turns? - if (my_hp() < my_maxhp()) - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); - } - } - else if (!base_quest_state.state_boolean["past tower level 3"]) - { - subentry.header = "Defeat the Wall of Bones"; - //wall of bones - if ($item[electric boning knife].available_amount() > 0) - { - subentry.entries.listAppend("Use the electric boning knife against it."); - } - else - { - //suggest towerkilling methods - //removing passive damage sources - //support saucegeyser, intimidating mien, grease up, and future airport skills (or lack thereof) - //strategy: saucegeyser three times, then either saucegeyser One More Time or unleash grease up/intimidating mien/future airport skills - //FIXME REST - subentry.entries.listAppend("Either find the electric boning knife on the ground floor of the castle in the clouds in the sky (-combat), or towerkill:"); - subentry.entries.listAppend("Make sure to remove all sources of passive damage."); - - string [int] passives_to_remove = PDSGenerateDescriptionToUneffectPassives(); - if (passives_to_remove.count() > 0) - subentry.entries.listAppend(HTMLGenerateSpanFont(passives_to_remove.listJoinComponents("|"), "red")); - //FIXME HACK USE A LIBRARY - /*string [int] things_to_do; - foreach it in $items[hand in glove,MagiMechTech NanoMechaMech,bottle opener belt buckle,old school calculator watch,ant hoe,ant pick,ant pitchfork,ant rake,ant sickle,fishy wand,moveable feast,oversized fish scaler,plastic pumpkin bucket,tiny bowler,cup of infinite pencils,double-ice box,smirking shrunken head,mr. haggis,stapler bear,dubious loincloth,muddy skirt,bottle of Goldschnöckered,acid-squirting flower,ironic oversized sunglasses,hippy protest button,cannonball charrrm bracelet,groovy prism necklace,spiky turtle shoulderpads,double-ice cap,parasitic headgnawer,eelskin hat,balloon shield,hot plate,Ol' Scratch's stove door,Oscus's garbage can lid,eelskin shield,eelskin pants,buddy bjorn] - { - if (it.equipped_amount() > 0) - things_to_do.listAppend("unequip " + it); - } - foreach e in $effects[Skeletal Warrior,Skeletal Cleric,Skeletal Wizard,Bone Homie,Burning\, Man,Biologically Shocked,EVISCERATE!,Fangs and Pangs,Permanent Halloween,Curse of the Black Pearl Onion,Long Live GORF,Apoplectic with Rage,Dizzy with Rage,Quivering with Rage,Jabañero Saucesphere,Psalm of Pointiness,Drenched With Filth,Stuck-Up Hair,It's Electric!,Smokin',Jalapeño Saucesphere,Scarysauce,spiky shell] - { - if (e.have_effect() > 0) - things_to_do.listAppend("uneffect " + e); - } - if (things_to_do.count() > 0) - subentry.entries.listAppend(HTMLGenerateSpanFont(things_to_do.listJoinComponents(", ", "and").capitaliseFirstLetter() + ".", "red"));*/ - - //FIXME Firegate - spade, etc - - //Firegate is 100% myst, +30-40 damage, but unaffected by spell damage % (and possibly spell damage?) - //Garbage nova is 40% myst, etc, but affected by spell damage %/spell damage. - //So, we have to calculate which one is better and suggest that. (garbage nova may be better, in fact) - if ($skill[Garbage Nova].skill_is_usable()) - { - //Special note on calculations: - //Spell damage percent is multiplied before the group size multiplier, then floored. - //I believe this means against a size 100 monster, garbage nova will always deal damage in multiples of 50 - //It also means estimation can be wildly off without taking that into account. - //Also, stench spell damage counts double, maybe? - float buffed_myst = my_buffedstat($stat[mysticality]); - float spell_damage = numeric_modifier("spell damage"); - float stench_spell_damage = numeric_modifier("stench spell damage"); - float spell_damage_percent = numeric_modifier("spell damage percent"); - float monster_level = monster_level_adjustment_ignoring_plants(); - float spell_damage_multiplier = 1.0 + spell_damage_percent / 100.0; - float monster_damage_multiplier = 1.0 - min(50.0, monster_level * 0.4) / 100.0; - - //Estimate: 62894 - //Actual: 63263 - - //Current damage formulas: - //min = floor((45.0 + floor(0.4 * buffed_myst) + spell_damage + stench_spell_damage * 2.0) * (1.0 + spell_damage_percent / 100.0)) * ceil(group_size * 0.5) - //max = floor((50.0 + floor(0.4 * buffed_myst) + spell_damage + stench_spell_damage * 2.0) * (1.0 + spell_damage_percent / 100.0)) * ceil(group_size * 0.5) - //group_size = 100 - //then apply damage resistance: damage_out = floor(damage_in * (1.0 - min(50.0, ml * 0.4)) / 100.0)); - //damage must be >= 5k - - string [int] tasks; - - int min_myst_needed = 1000; - //5000 = floor(floor((45.0 + floor(0.4 * buffed_myst) + spell_damage + stench_spell_damage * 2.0) * spell_damage_multiplier) * 50.0 * monster_damage_multiplier) - //approximation: - //buffed_myst = 2.5 * (5000 / monster_damage_multiplier / 50.0 / spell_damage_multiplier - spell_damage - stench_spell_damage * 2.0 - 45.0) - //hmm... 138 to 388 myst without anything else? yes - //though -100 myst with 50 stench spell damage is also enough - - float divisor = monster_damage_multiplier * 50.0 * spell_damage_multiplier; - if (divisor == 0.0) - divisor = 0.001; - min_myst_needed = ceil(2.5 * (5000 / divisor - spell_damage - stench_spell_damage * 2.0 - 45.0)); - - int per_round_damage = floor(floor((45.0 + floor(0.4 * buffed_myst) + spell_damage + stench_spell_damage * 2.0) * spell_damage_multiplier) * 50.0 * monster_damage_multiplier); - - - int casts_needed = 4; - if (per_round_damage != 0) - casts_needed = clampi(ceil(20000.0 / to_float(per_round_damage)), 1, 4); - - if (my_buffedstat($stat[mysticality]) < min_myst_needed) - { - tasks.listAppend(HTMLGenerateSpanFont("buff up to " + min_myst_needed + " mysticality", "red")); - if (monster_level > 0) - tasks.listAppend("possibly reduce ML"); - } - tasks.listAppend("cast garbage nova " + pluraliseWordy(casts_needed, "time", "times")); - - if (tasks.count() > 0) - subentry.entries.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - - subentry.entries.listAppend(per_round_damage + " damage/round."); - } - else if ($skill[saucegeyser].skill_is_usable()) - { - boolean need_modifier_output = true; - if (my_familiar() != $familiar[magic dragonfish] && $familiar[magic dragonfish].familiar_is_usable() && !__misc_state["familiars temporarily blocked"]) - subentry.entries.listAppend("Potentially switch to the magic dragonfish."); - if ($item[meteorb].have() && !$item[meteorb].equipped()) - subentry.entries.listAppend("Potentially equip meteorb."); - //Calculate saucegeyser damage: - float expected_saucegeyser_damage = skillExpectedDamageRangeAlternate($monster[wall of bones], $skill[saucegeyser]).x; - if ($item[meteorb].equipped()) - expected_saucegeyser_damage *= 2.0; - - subentry.entries.listAppend("Expected saucegeyser minimum damage: " + expected_saucegeyser_damage.roundForOutput(0)); - if (expected_saucegeyser_damage >= 5000.0) - { - subentry.entries.listAppend("Cast saucegeyser four times."); - need_modifier_output = false; - } - else - { - float hp_remaining = 20000.0 - expected_saucegeyser_damage * 3.0; - - float [skill] airport_skill_per_turn_damage_multiplier; - float [skill] airport_skill_base_damage; - - airport_skill_per_turn_damage_multiplier[$skill[grease up]] = 5.0; - airport_skill_base_damage[$skill[grease up]] = 30.0; - - airport_skill_per_turn_damage_multiplier[$skill[Intimidating Mien]] = 2.0; - airport_skill_base_damage[$skill[Intimidating Mien]] = 15.0; - - string [skill] airport_skill_name_of_combat_skill; - - airport_skill_name_of_combat_skill[$skill[grease up]] = "Unleash the Greash"; - airport_skill_name_of_combat_skill[$skill[Intimidating Mien]] = "Thousand-Yard Stare"; - - - float ml_damage_multiplier = MLDamageMultiplier(); - if (ml_damage_multiplier != 1.0) - { - //FIXME this is correct... right? hmm... - foreach s in airport_skill_base_damage - { - airport_skill_base_damage[s] *= ml_damage_multiplier; - airport_skill_per_turn_damage_multiplier[s] *= ml_damage_multiplier; - } - } - - skill chosen_skill = $skill[none]; - int chosen_skill_total_mp_cost = 0; - int chosen_skill_turns_left_to_cast = 0; - foreach s in airport_skill_base_damage - { - if (!s.skill_is_usable()) - continue; - float base_damage = airport_skill_base_damage[s]; - float variable_damage = airport_skill_per_turn_damage_multiplier[s]; - effect skill_effect = s.to_effect(); - - if (variable_damage == 0.0) - continue; - int total_turns_needed_of_effect = ceil((hp_remaining - base_damage) / variable_damage); - int turns_to_cast = MAX(0, total_turns_needed_of_effect - skill_effect.have_effect()); - - int mp_cost = MAX(0, s.mp_cost() * turns_to_cast / MAX(1.0, s.turns_per_cast().to_float())); - - if (chosen_skill == $skill[none] || chosen_skill_total_mp_cost > mp_cost) - { - chosen_skill = s; - chosen_skill_total_mp_cost = mp_cost; - chosen_skill_turns_left_to_cast = turns_to_cast; - } - } - if (chosen_skill != $skill[none]) - { - if (chosen_skill_turns_left_to_cast > 0) - { - string expected_meat_cost = ceil(chosen_skill_total_mp_cost * __misc_state_float["meat per MP"]); - - //string line = "Acquire " + chosen_skill_turns_left_to_cast + " more turns of " + chosen_skill + ".|Expected meat cost: "; - string line = "Cast " + chosen_skill + " "; - int cast_amount = ceil(chosen_skill_turns_left_to_cast.to_float() / MAX(1.0, chosen_skill.turns_per_cast().to_float())); - - if (cast_amount == 1) - line += "One More Time."; - else - line += cast_amount + " more times."; - - line += "|Expected meat cost: "; - - if (expected_meat_cost > my_meat()) - line += HTMLGenerateSpanFont(expected_meat_cost, "red"); - else - line += expected_meat_cost; - subentry.modifiers.listAppend("-mana cost"); - subentry.entries.listAppend(line); - } - else - { - subentry.entries.listAppend("Cast saucegeyser three times, then cast " + airport_skill_name_of_combat_skill[chosen_skill] + "."); - need_modifier_output = false; - } - } - else if ($item[hand turkey outline].is_unrestricted()) //FIXME test if we have an airport skill - { - subentry.entries.listAppend("Cast saucegeyser three times, then an airport skill?"); - } - } - if (my_hp() < my_maxhp()) - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); - } - if (my_mp() < $skill[saucegeyser].mp_cost() * 4.0) - subentry.entries.listAppend(HTMLGenerateSpanFont("Restore some MP first.", "red")); - if (__iotms_usable[lookupItem("candy cane sword cane")]) - subentry.entries.listAppend("Also, consider using your Candy Cane Sword Cane's surprisingly sweet slash to cut the wall's HP by 75%!"); - if (need_modifier_output) - { - subentry.modifiers.listAppend("mysticality"); - subentry.modifiers.listAppend("spell damage"); - subentry.modifiers.listAppend("spell damage percent"); - if (monster_level_adjustment() > 0) - subentry.modifiers.listAppend("-ML"); - } - } - if ($skill[splattersmash].skill_is_usable() && my_id() == 1557284) - { - //(30-40 damage + (muscle - monster defence)) * 100 / 4 - //Two jam band bootlegs make that 1000 defence 250. If you have funksling, that's 487 buffed muscle needed. - // - subentry.entries.listAppend(HTMLGenerateSpanFont("Write splattersmash + jam band bootleg code.", "red")); - } - } - } - else if (!base_quest_state.state_boolean["past tower level 4"]) - { - //stare into the looking glass, or break it - subentry.header = "Face the looking glass"; - if (my_path().id == PATH_VAMPIRE) - { - subentry.entries.listAppend("Gaze upon... nothing."); - } - else - { - subentry.entries.listAppend("Two options here."); - subentry.entries.listAppend("Gazing upon the looking glass will cost a turn, but makes the naughty sorceress much easier."); - subentry.entries.listAppend("Breaking the mirror will save a turn, but makes the NS fight much more difficult."); - } - } - else if (!base_quest_state.state_boolean["past tower level 5"] && my_path().id == PATH_VAMPIRE) - { - subentry.header = "Fight the mirror"; - subentry.entries.listAppend("It has, like, 3000 HP. You can handle it, right?"); - } - else if (!base_quest_state.state_boolean["past tower level 5"]) - { - //at top of tower (fight shadow??) - //8 -> fight shadow - int total_initiative_needed = $monster[Your Shadow].monster_initiative(); - subentry.modifiers.listAppend("+HP"); - subentry.modifiers.listAppend("+" + total_initiative_needed + "% init"); - subentry.header = "Fight your shadow"; - foreach it in $items[attorney's badge, navel ring of navel gazing, replica navel ring of navel gazing] - { - if (it.available_amount() > 0 && it.equipped_amount() == 0) - subentry.entries.listAppend("Possibly equip your " + it + ". (blocks shadow)"); - } - - string [int] healing_items_available; - foreach it in $items[filthy poultice,gauze garter,red pixel potion,Dreadsylvanian seed pod,soggy used band-aid,Mer-kin healscroll,scented massage oil,extra-strength red potion,red potion] - { - if (it.item_amount() == 0) - continue; - if (!it.item_is_usable()) continue; - if (it.item_amount() == 1) - healing_items_available.listAppend(it.to_string()); - else - healing_items_available.listAppend(it.pluralise()); - } - if (healing_items_available.count() > 0) - subentry.entries.listAppend("Healing items available: " + healing_items_available.listJoinComponents(", ", "and") + "."); - else - subentry.entries.listAppend("May want to go find some healing items."); - - - int initiative_needed = total_initiative_needed - initiative_modifier(); - if (initiative_needed > 0 && !$skill[Ambidextrous Funkslinging].skill_is_usable()) - subentry.entries.listAppend("Need " + initiative_needed + "% more initiative."); - if (my_hp() < my_maxhp()) - { - //FIXME only output this if we won't make it. - subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); - } - } - else if (!base_quest_state.state_boolean["king waiting to be freed"]) - { - //At NS. Good luck, we're all counting on you. - if (my_path().id != PATH_HEAVY_RAINS) - { - subentry.modifiers.listAppend("+moxie, DA equipment"); - subentry.modifiers.listAppend("no buffs"); - if (!__misc_state["familiars temporarily blocked"]) - subentry.modifiers.listAppend("attack familiar"); - } - image_name = "naughty sorceress"; - subentry.header = "She awaits"; - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - { - subentry.header = "You await"; - image_name = "Disco Bandit"; - } - if (my_path().id == PATH_LICENSE_TO_ADVENTURE) - { - subentry.header = "\"Blofeld\" awaits"; - image_name = "__monster \"Blofeld\""; - } - //don't think blocking works anymore? not sure - /*if (!__misc_state["familiars temporarily blocked"] && my_path().id != PATH_HEAVY_RAINS) - { - string potato_suggestion = generatePotatoSuggestion(); - - subentry.entries.listAppend(potato_suggestion); - }*/ - - if ($item[The Lot's engagement ring].equipped_amount() > 0) - { - subentry.entries.listAppend("You and her? Good luck!"); - } - - /*if ($item[The Lot's engagement ring].available_amount() > 0 && $item[The Lot's engagement ring].equipped_amount() == 0) - { - subentry.entries.listAppend("Potentially equip the lot's engagement ring for an alternate ending.|(sigh... if only)"); - }*/ - - if (my_path().id == PATH_HEAVY_RAINS) - { - subentry.modifiers.listAppend("many buffs"); - if ($familiar[warbear drone].have_familiar()) - subentry.entries.listAppend("Run a warbear drone if you can."); - - subentry.entries.listAppend("Try to run as many buffs as you can. (one removed per round, have " + my_effects().count() + ")"); - subentry.entries.listAppend("Try to have as many damage sources as possible. (40? damage cap per source)"); - subentry.entries.listAppend("Only your weapon, offhand, and familiar equipment(?) are relevant this fight."); - if ($item[crayon shavings].available_amount() > 0) - subentry.entries.listAppend("Try repeatedly using crayon shavings?"); - if ($skill[frigidalmatian].skill_is_usable() && my_maxmp() >= 300 && $effect[Frigidalmatian].have_effect() == 0) - subentry.entries.listAppend("Try casting Frigidalmatian."); - } - if (my_hp() < my_maxhp() && !get_property("lastEncounter").contains_text("The Naughty Sorceress") && __last_adventure_location != $location[The Naughty Sorceress' Chamber] && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); - } - - } - else if (base_quest_state.state_boolean["king waiting to be freed"]) - { - //King is waiting in his prism. - - boolean trophies_are_possible = false; - - //ehh, disable displaying this, mostly because it's in the way - //if (in_hardcore()) - //trophies_are_possible = true; //Gourdcore, Golden Meat Stack - - if (trophies_are_possible) - task_entries.listAppend(ChecklistEntryMake("__item puzzling trophy", "trophy.php", ChecklistSubentryMake("Check for trophies", "10k meat, trophy requirements", "Certain trophies are missable after freeing the king")).ChecklistEntrySetIDTag("Path end trophies")); - should_output_main_entry = false; - - - if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) - { - if (availableDrunkenness() > 0) - { - task_entries.listAppend(ChecklistEntryMake("__item gibson", "inventory.php?which=1", ChecklistSubentryMake("Drink " + availableDrunkenness() + " drunkenness", "", "Freeing the king reduces your liver capacity.")).ChecklistEntrySetIDTag("Path end max liver usage")); - } - } - - if (my_path().id == PATH_HEAVY_RAINS) - { - if ($skill[rain dance].skill_is_usable() && my_rain() >= 10) - { - int times = floor(my_rain().to_float() / 10.0); - task_entries.listAppend(ChecklistEntryMake("__effect Rain Dancin'", "skills.php", ChecklistSubentryMake("Cast Rain Dance " + pluraliseWordy(times, "time", "times"), "", "+20% item buff for aftercore.")).ChecklistEntrySetIDTag("Path end rain dance")); - } - } - - if ($item[Yearbook Club Camera].available_amount() > 0 && $item[Yearbook Club Camera].equipped_amount() == 0) - { - task_entries.listAppend(ChecklistEntryMake("__item yearbook club camera", "inventory.php?ftext=yearbook+club+camera", ChecklistSubentryMake("Equip the yearbook club camera", "", "Before prism break. Otherwise, it'll disappear.")).ChecklistEntrySetIDTag("Path end yearbook camera")); - } - - } - //I need to delete this code, but I love it so much. Look at all that towerkilling suggestions! sob - /*else if (base_quest_state.mafia_internal_step > 4 && base_quest_state.mafia_internal_step < 11) - { - //step4 through step9 - 5 - 10 - //at tower, time to kill monsters! - - - int level = -1; - - if (base_quest_state.mafia_internal_step == 5) - level = 1; - else if (base_quest_state.mafia_internal_step == 6) - level = 2; - else if (base_quest_state.mafia_internal_step == 7) - level = 3; - else if (base_quest_state.mafia_internal_step == 8) - level = 4; - else if (base_quest_state.mafia_internal_step == 9) - level = 5; - else if (base_quest_state.mafia_internal_step == 10) - level = 6; - - boolean output_tower_killing_ideas = false; - item monster_item = __misc_state_string["Tower monster item " + level].to_item(); - - subentry.entries.listAppend("Tower monster on floor " + level + "."); - if (monster_item != $item[none]) - { - if (monster_item.available_amount() > 0) - subentry.entries.listAppend("Use " + HTMLGenerateSpanOfClass(monster_item, "r_bold") + "."); - else - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Need " + HTMLGenerateSpanOfClass(monster_item, "r_bold") + ".", "red")); - output_tower_killing_ideas = true; - } - } - else - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Need unknown item.", "red")); - output_tower_killing_ideas = true; - } - - if (output_tower_killing_ideas) - { - string [int] tower_killing_ideas; - - if (my_path().id == PATH_HEAVY_RAINS && $skill[thunder bird].skill_is_usable() && my_thunder() >= 5 && $skill[curse of weaksauce].skill_is_usable()) - { - string [int] line; - if ($skill[itchy curse finger].skill_is_usable()) - { - line.listAppend("cast curse of weaksauce"); - line.listAppend("cast a stun"); - } - else - { - line.listAppend("cast a stun"); - line.listAppend("cast curse of weaksauce"); - } - line.listAppend("cast thunder bird/stun/staggers repeatedly under defense is below zero"); - line.listAppend("attack"); - tower_killing_ideas.listAppend(line.listJoinComponents(", ", "then").capitaliseFirstLetter()); - } - else if ($skill[curse of weaksauce].skill_is_usable() && $item[crayon shavings].available_amount() >= 2) //currently disabled because while it'll work in theory, I haven't tested it - { - string [int] line; - if ($skill[itchy curse finger].skill_is_usable()) - { - line.listAppend("cast curse of weaksauce"); - line.listAppend("cast a stun"); - } - else - { - line.listAppend("cast a stun"); - line.listAppend("cast curse of weaksauce"); - } - line.listAppend("throw two crayon shavings"); - line.listAppend("stagger/stun until defense is below zero"); - - line.listAppend("attack"); - tower_killing_ideas.listAppend(line.listJoinComponents(", ", "then").capitaliseFirstLetter()); - } - - //Familiar sources: - if (!__misc_state["familiars temporarily blocked"]) - { - string potato_suggestion = generatePotatoSuggestion(); - tower_killing_ideas.listAppend(potato_suggestion); - - - //Bjorn: - if ($familiar[mariachi chihuahua].have_familiar()) - { - if ($item[buddy bjorn].available_amount() > 0) - { - if (my_bjorned_familiar() != $familiar[mariachi chihuahua]) - tower_killing_ideas.listAppend("Put your mariachi chihuahua in your buddy bjorn. (50% stagger)"); - } - else if ($item[crown of thrones].available_amount() > 0) - { - if (my_enthroned_familiar() != $familiar[mariachi chihuahua]) - tower_killing_ideas.listAppend("Put your mariachi chihuahua in your crown of thrones. (50% stagger)"); - } - } - } - - if ($item[attorney's badge].available_amount() > 0 && $item[attorney's badge].equipped_amount() == 0) - tower_killing_ideas.listAppend("Could equip attorney's badge for more blocking."); - if ($item[navel ring of navel gazing].available_amount() > 0 && $item[navel ring of navel gazing].equipped_amount() == 0) - tower_killing_ideas.listAppend("Could equip navel ring of navel gazing for more blocking."); - - - - string [int] stun_sources; - string [int] stagger_sources; - - - //Stun/stagger sources: - //(this is not a comprehensive list) - //√shadow noodles, √thunderstrike, √soul bubble - //√potato, √bjorned chihuahua, √attorney's badge, √navel ring - - //√ply reality, √entangling noodles as not-pastamancer, √pantsgiving 2x, √deft hands, DNA...?, √3x disco dances... - //√airblaster gun - //√club foot IF seal clubber - //√Break It On Down - //√gob of wet hair, √gyroscope, √macrame net, √ornate picture frame, √palm-frond net(?), √Rain-Doh indigo cup, √superamplified boom box, √Throw Shield (OPS), √tongue depressor - - //√gas balloon, √brick of sand(?), √chloroform rag, naughty paper shuriken, √sausage bomb, √floorboard cruft - //√dumb mud will insta if available - //√finger cuffs (support acquiring) - //√Rain-Doh blue balls - //√CSA obedience grenade, √The Lost Comb - //Accordion Bash if AT wearing an accordion FIXME do that - //Shell Up(?) - //sooooooul finger? does it work? 40 saucery... - - if ($item[Game Grid ticket].item_amount() > 0 && $item[Game Grid ticket].is_unrestricted()) - tower_killing_ideas.listAppend("Could acquire " + $item[Game Grid ticket].item_amount() + " finger cuffs. (stun)"); - if ($skill[shadow noodles].skill_is_usable()) - stun_sources.listAppend("shadow noodles"); - if ($skill[thunderstrike].skill_is_usable()) - stun_sources.listAppend("thunderstrike"); - if ($skill[soul saucery].skill_is_usable() && my_class() == $class[sauceror]) - stun_sources.listAppend("soul bubble"); - - foreach it in $items[gas balloon,brick of sand,chloroform rag,sausage bomb,floorboard cruft,finger cuffs,CSA obedience grenade,The Lost Comb] - { - if (it.item_amount() == 0 || !it.is_unrestricted()) - continue; - stun_sources.listAppend(it.pluraliseWordy()); - } - if ($item[naughty paper shuriken].available_amount() > 0) - stun_sources.listAppend("naughty paper shuriken"); - if ($item[Rain-Doh blue balls].available_amount() > 0) - stun_sources.listAppend("Rain-Doh blue balls"); - - if ($skill[shell up].skill_is_usable() && ($effect[Blessing of the Storm Tortoise].have_effect() > 0 || $effect[Grand Blessing of the Storm Tortoise].have_effect() > 0 || $effect[Glorious Blessing of the Storm Tortoise].have_effect() > 0)) - stun_sources.listAppend("Shell Up"); - if ($skill[Accordion Bash].skill_is_usable()) - { - string line = "Accordion Bash"; - if ($slot[weapon].equipped_item().item_type() != "accordion") - line = HTMLGenerateSpanFont(line + " (equip accordion)", "gray"); - stun_sources.listAppend(line); - } - - if ($item[thor's pliers].equipped_amount() > 0) - stagger_sources.listAppend("ply reality"); - if (my_class() != $class[pastamancer] && $skill[entangling noodles].skill_is_usable()) - stagger_sources.listAppend("entangling noodles"); - if ($item[pantsgiving].equipped_amount() > 0) - { - stagger_sources.listAppend("pocket crumbs"); - stagger_sources.listAppend("air dirty laundry"); - } - if (my_class() == $class[disco bandit] && $skill[deft hands].skill_is_usable()) - stagger_sources.listAppend("first combat item thrown"); - if (my_class() == $class[disco bandit] && $skill[Disco State of Mind].skill_is_usable() && $skill[Flashy Dancer].skill_is_usable()) - { - if ($skill[disco dance of doom].skill_is_usable()) - stagger_sources.listAppend("disco dance"); - if ($skill[Disco Dance II: Electric Boogaloo].skill_is_usable()) - stagger_sources.listAppend("disco dance II"); - if ($skill[Disco Dance 3: Back in the Habit].skill_is_usable()) - stagger_sources.listAppend("disco dance 3"); - } - if ($item[airblaster gun].equipped_amount() > 0) - stagger_sources.listAppend("air blast"); - if (my_class() == $class[seal clubber] && $skill[club foot].skill_is_usable()) - { - int stun_rounds = 0; - - stun_rounds = MIN(3, my_fury()); - if ($slot[weapon].equipped_item().item_type() == "club") - stun_rounds += 1; - - if (stun_rounds == 1) - stagger_sources.listAppend("club foot"); - else if (stun_rounds > 1) - stun_sources.listAppend("club foot"); - } - if ($skill[Break It On Down].skill_is_usable()) - stagger_sources.listAppend("break it on down"); - - foreach it in $items[gob of wet hair,gyroscope,macrame net,ornate picture frame,palm-frond net,superamplified boom box] - { - if (it.item_amount() == 0 || !it.is_unrestricted()) - continue; - stagger_sources.listAppend(it.pluraliseWordy()); - } - if ($item[operation patriot shield].equipped_amount() > 0) - stagger_sources.listAppend("throw shield"); - if ($item[Rain-Doh indigo cup].available_amount() > 0) - stagger_sources.listAppend("Rain-Doh indigo cup"); - if ($item[tongue depressor].available_amount() > 0) - stagger_sources.listAppend("tongue depressor"); - - if (stun_sources.count() > 0) - tower_killing_ideas.listAppend("Stuns: " + stun_sources.listJoinComponents(", ", "and")); - if (stagger_sources.count() > 0) - tower_killing_ideas.listAppend("Stagger sources: " + stagger_sources.listJoinComponents(", ", "and")); - - - - - if ($item[small golem].available_amount() > 0) - { - if ($skill[Ambidextrous Funkslinging].skill_is_usable() && $item[slime stack].available_amount() > 0) - tower_killing_ideas.listAppend("Small golem available. Funksling early in combat with a slime stack for 3k damage/round."); - else - tower_killing_ideas.listAppend("Small golem available. Use early in combat for 3k damage/round."); - } - if ($item[slime stack].available_amount() > 0) - tower_killing_ideas.listAppend($item[slime stack].pluralise() + " available. (15% damage)"); - - if ($skill[frigidalmatian].skill_is_usable() && my_maxmp() >= 300 && $effect[Frigidalmatian].have_effect() == 0) - tower_killing_ideas.listAppend("Possibly cast Frigidalmatian."); - - if (monster_level_adjustment() > 0) - tower_killing_ideas.listAppend(HTMLGenerateSpanFont("Try to reduce your ML", "red") + ", as it reduces damage done to them."); - - if ((my_path().id == PATH_HEAVY_RAINS || $item[water wings for babies].available_amount() >= 3) && $item[water wings for babies].equipped_amount() <3) - tower_killing_ideas.listAppend("Equip three water wings for babies to reduce ML. (increased damage)"); - - if (tower_killing_ideas.count() > 0) - subentry.entries.listAppend("Or towerkill (very difficult):" + HTMLGenerateIndentedText(tower_killing_ideas.listJoinComponents("
"))); - else - subentry.entries.listAppend("Or towerkill."); - - if ($item[dumb mud].available_amount() > 0) - subentry.entries.listAppend("Or just use dumb mud, which will insta-kill a tower monster."); - } - - if (level <= 3) - url = "lair4.php"; - else - url = "lair5.php"; - }*/ - - if (should_output_main_entry) - task_entries.listAppend(ChecklistEntryMake(image_name, url, subentries).ChecklistEntrySetIDTag("Council L13 quest")); -} diff --git a/Source/relay/TourGuide/Quests/Level 2.ash b/Source/relay/TourGuide/Quests/Level 2.ash deleted file mode 100644 index 316ff8c1..00000000 --- a/Source/relay/TourGuide/Quests/Level 2.ash +++ /dev/null @@ -1,93 +0,0 @@ - -void QLevel2Init() -{ - //questL02Larva - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questL02Larva"); - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - - // Finish this quest if you are in 11,037 Leagues Under the Sea, so the tiles never generate. - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Spooky Forest Quest"; - state.image_name = "Spooky Forest"; - state.council_quest = true; - - if (my_level() >= 2 || my_path().id == PATH_EXPLOSIONS) - state.startable = true; - - if (state.in_progress) - { - if ($item[mosquito larva].available_amount() > 0) - { - state.state_boolean["have mosquito"] = true; - } - } - else if (state.finished) - { - state.state_boolean["have mosquito"] = true; - } - - __quest_state["Level 2"] = state; - __quest_state["Spooky Forest"] = state; -} - - -void QLevel2GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Level 2"]; - if (!base_quest_state.in_progress) - return; - - if (my_path().id == PATH_COMMUNITY_SERVICE || __misc_state["in aftercore"]) - return; - - ChecklistSubentry subentry; - string url = "place.php?whichplace=woods"; - - subentry.header = base_quest_state.quest_name; - - - if (base_quest_state.state_boolean["have mosquito"]) - { - subentry.entries.listAppend("Finished, go chat with the council."); - url = "place.php?whichplace=town"; - } - else - { - string [int] modifiers; - modifiers.listAppend("-combat"); - - if (delayRemainingInLocation($location[the spooky forest]) > 0) - { - string hipster_text = ""; - if (__misc_state["have hipster"]) - { - hipster_text = " (use " + __misc_state_string["hipster name"] + ")"; - modifiers.listAppend(__misc_state_string["hipster name"]); - } - string line = "Delay for " + pluralise(delayRemainingInLocation($location[the spooky forest]), "turn", "turns") + hipster_text + "."; - subentry.entries.listAppend(line); - subentry.entries.listAppend("Run -combat after that."); - } - else - subentry.entries.listAppend("Run -combat"); - subentry.entries.listAppend("Explore the stream" + __html_right_arrow_character + "March to the marsh"); - - - if (!__quest_state["Manor Unlock"].state_boolean["ballroom song effectively set"]) - subentry.entries.listAppend("Possibly wait until -combat ballroom song set. (marginal)"); - - if (__misc_state["free runs available"]) - { - subentry.entries.listAppend("Free run from monsters (low stats)"); - modifiers.listAppend("free runs"); - } - - - subentry.modifiers = modifiers; - } - - task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the spooky forest]).ChecklistEntrySetIDTag("Council L2 mosquito quest")); -} diff --git a/Source/relay/TourGuide/Quests/Level 3.ash b/Source/relay/TourGuide/Quests/Level 3.ash deleted file mode 100644 index c9443174..00000000 --- a/Source/relay/TourGuide/Quests/Level 3.ash +++ /dev/null @@ -1,146 +0,0 @@ - -void QLevel3Init() -{ - //questL03Rat - //lastTavernSquare - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL03Rat"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Typical Tavern Quest"; - state.image_name = "Typical Tavern"; - state.council_quest = true; - - if ((my_path().id == PATH_EXPLOSIONS || my_level() >= 3) && __quest_state["Level 2"].finished) - state.startable = true; - - __quest_state["Level 3"] = state; - __quest_state["Typical Tavern"] = state; -} - - -void QLevel3GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 3"].in_progress) - return; - QuestState base_quest_state = __quest_state["Level 3"]; - boolean wait_until_level_eleven = false; - if ($skill[ur-kel's aria of annoyance].skill_is_usable() && my_level() < 11) - wait_until_level_eleven = true; - - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - - if (base_quest_state.mafia_internal_step == 1) - subentry.entries.listAppend("Speak to the bartender."); - - boolean can_skip_cold = numeric_modifier("Cold Damage") >= 20.0; - boolean can_skip_hot = numeric_modifier("Hot Damage") >= 20.0; - boolean can_skip_spooky = numeric_modifier("Spooky Damage") >= 20.0; - boolean can_skip_stench = numeric_modifier("Stench Damage") >= 20.0; - - - - float combat_rate = clampNormalf((0.85 + combat_rate_modifier() / 100.0)); //15%? I can't remember... - - boolean need_to_complete_pyramid = true; - - //FIXME test properly - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - need_to_complete_pyramid = false; - if (__quest_state["Level 11"].finished) - need_to_complete_pyramid = false; - if (need_to_complete_pyramid && $item[tangle of rat tails].available_amount() < 6) - { - float rat_king_chance = clampNormalf(monster_level_adjustment_for_location($location[the typical tavern cellar]) / 300.0); - float average_tangles_found = (clampNormalf(rat_king_chance * combat_rate) * 8.5); - - if (wait_until_level_eleven) - subentry.entries.listAppend("May want to wait until level 11 for most +ML from aria."); - string line = "Run +ML for tangles (" + roundForOutput(rat_king_chance * 100.0, 0) + "% rat king chance, " + average_tangles_found.roundForOutput(1) + " tangles on average"; - line += ")"; - - subentry.entries.listAppend(line); - } - - string [int] elemental_sources_available; - if ($item[piddles].available_amount() > 0 && $effect[Belch the Rainbow™].have_effect() == 0) - elemental_sources_available.listAppend("+" + MIN(11, my_level()) + " piddles"); - - - if ($skill[Benetton's Medley of Diversity].skill_is_usable() && my_level() >= 15 && get_property_int("_benettonsCasts") < 10) - elemental_sources_available.listAppend("+15 Benetton's Medley of Diversity"); - - string elemental_sources_available_string; - if (elemental_sources_available.count() > 0) - elemental_sources_available_string = " (" + listJoinComponents(elemental_sources_available, ", ") + " available)"; - - if (true) - { - int ncs_skippable = 0; - string [int] additionals; - if (!can_skip_cold) - additionals.listAppend(HTMLGenerateSpanOfClass("cold", "r_element_cold")); - else - ncs_skippable += 1; - if (!can_skip_hot) - additionals.listAppend(HTMLGenerateSpanOfClass("hot", "r_element_hot")); - else - ncs_skippable += 1; - if (!can_skip_spooky) - additionals.listAppend(HTMLGenerateSpanOfClass("spooky", "r_element_spooky")); - else - ncs_skippable += 1; - if (!can_skip_stench) - additionals.listAppend(HTMLGenerateSpanOfClass("stench", "r_element_stench")); - else - ncs_skippable += 1; - - //drunken rat kings seem to happen after the combat/non-combat check, so recommend +combat if they need tangles: - - string combat_type_to_run = "-combat/maybe +combat"; - if (ncs_skippable > 0)// && ($item[tangle of rat tails].available_amount() * 3 + $item[tomb ratchet].available_amount() >= 11 || !need_to_complete_pyramid)) //technically should check if we're done with the pyramid moving, not level 11 finished, but that's harder to test. on second thought, just -combat if we can skip at least one? - combat_type_to_run = "-combat"; - string line; - if (additionals.count() > 0) - line += "Run " + combat_type_to_run + " with +20 " + additionals.listJoinComponents("/") + " damage."; - else - line += "Run " + combat_type_to_run + "."; - if (ncs_skippable < 4) - line += elemental_sources_available_string; - if (ncs_skippable > 0) - { - float rate = ncs_skippable.to_float() / 4.0; - if (ncs_skippable == 4) - line += "|Can skip every non-combat."; - else - line += "|Can skip " + (rate * 100.0).round() + "% of non-combats."; - } - subentry.modifiers.listAppend(combat_type_to_run); - subentry.entries.listAppend(line); - - if ($item[tangle of rat tails].available_amount() > 0 && need_to_complete_pyramid) - { - subentry.entries.listAppend(pluralise($item[tangle of rat tails]) + " found."); - } - } - if (need_to_complete_pyramid) - subentry.modifiers.listAppend("+300 ML"); - - string url = "tavern.php"; - - if (get_property_ascension("lastCellarReset") && base_quest_state.mafia_internal_step > 1) - url = "cellar.php"; - - ChecklistEntry entry = ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the typical tavern cellar]); - entry.tags.id = "Council L3 quest cellar"; - - if (wait_until_level_eleven && false) //Ehhh... no? It's like, a 5% difference? - optional_task_entries.listAppend(entry); - else - task_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Quests/Level 4.ash b/Source/relay/TourGuide/Quests/Level 4.ash deleted file mode 100644 index fb724e2b..00000000 --- a/Source/relay/TourGuide/Quests/Level 4.ash +++ /dev/null @@ -1,173 +0,0 @@ - -void QLevel4Init() -{ - //questL04Bat - //be sure to set state_int["areas unlocked"] - - //started -> no areas unlocked - //step1 -> 1 area unlocked - //step2 -> 2 areas unlocked - //step3 -> 3 areas unlocked - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL04Bat"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Boss Bat Quest"; - state.image_name = "Boss Bat"; - state.council_quest = true; - - if (state.in_progress) - { - //Zones opened? - if ($location[the batrat and ratbat burrow].locationAvailable()) - state.state_int["areas unlocked"] = 1; - if ($location[the beanbat chamber].locationAvailable()) - state.state_int["areas unlocked"] = 2; - if ($location[the boss bat\'s lair].locationAvailable()) - state.state_int["areas unlocked"] = 3; - - } - else if (state.finished) - { - state.state_int["areas unlocked"] = 3; - } - - if (my_level() >= 4 || my_path().id == PATH_EXPLOSIONS) - state.startable = true; - - __quest_state["Level 4"] = state; - __quest_state["Boss Bat"] = state; -} - - -void QLevel4GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 4"].in_progress) - return; - - QuestState base_quest_state = __quest_state["Level 4"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - string url = "place.php?whichplace=bathole"; - - if (base_quest_state.mafia_internal_step >= 5) - { - subentry.entries.listAppend("Quest finished, speak to the council of loathing."); - url = "place.php?whichplace=town"; - } - else if ($location[the boss bat\'s lair].locationAvailable()) - { - subentry.entries.listAppend("Possibly run +meat in the boss bat's lair. (250 meat drop)"); - subentry.modifiers.listAppend("+meat"); - if (delayRemainingInLocation($location[the boss bat\'s lair]) > 0) - { - string line = "Delay for " + pluralise(delayRemainingInLocation($location[the boss bat\'s lair]), "turn", "turns") + " before boss bat shows up."; - subentry.entries.listAppend(line); - } - } - else - { - int areas_unlocked = base_quest_state.state_int["areas unlocked"]; - int areas_locked = 3 - areas_unlocked; - int sonars_needed = MAX(areas_locked - $item[sonar-in-a-biscuit].available_amount(), 0); - - - if (true) - { - string line = pluraliseWordy(areas_locked, "area", "areas").capitaliseFirstLetter() + " to unlock"; - /*if ($item[sonar-in-a-biscuit].available_amount() > 0) - line += ", " + pluralise($item[sonar-in-a-biscuit]);*/ - line += "."; - subentry.entries.listAppend(line); - } - - if ($item[sonar-in-a-biscuit].available_amount() > 0 && areas_locked > 0 && $item[sonar-in-a-biscuit].item_is_usable()) - { - int amount = MIN(areas_locked, $item[sonar-in-a-biscuit].available_amount()); - subentry.entries.listAppend("Use " + pluralise(amount, $item[sonar-in-a-biscuit])); - url = "inventory.php?ftext=sonar-in-a-biscuit"; - } - - boolean have_stench_resistance = (numeric_modifier("stench resistance") > 0.0); - if (!have_stench_resistance) - { - string line = "Need " + HTMLGenerateSpanOfClass("stench resistance", "r_element_stench") + " to adventure in Guano Junction."; - string [int] possibilities; - //This could be more... unified: - if ($item[ghost of a necklace].available_amount() > 0) - { - if ($item[ghost of a necklace].equipped_amount() == 0) - line += "|*Equip your ghost of a necklace."; - } - else if ($item[bum cheek].available_amount() > 0) - { - if ($item[bum cheek].equipped_amount() == 0) - line += "|*Equip your bum cheek."; - } - else if ($item[knob goblin harem veil].available_amount() == 0) - { - possibilities.listAppend("acquire a knob goblin harem veil"); - possibilities.listAppend("finish the first floor of spookyraven manor"); - } - else - { - if ($item[knob goblin harem veil].equipped_amount() == 0) - { - possibilities.listAppend("equip your knob goblin harem veil"); - } - } - if ($skill[elemental saucesphere].have_skill()) - { - possibilities.listAppend("cast elemental saucesphere"); - } - else if (my_class() == $class[sauceror]) - possibilities.listAppend("learn elemental saucesphere at guild trainer"); - if (possibilities.count() > 0) - line += "|*Possibly " + possibilities.listJoinComponents(", ", "or") + "."; - - subentry.entries.listAppend(line); - } - - - if ($item[enchanted bean].available_amount() == 0 && !__quest_state["Level 10"].state_boolean["beanstalk grown"]) - { - if ($location[the beanbat chamber].locationAvailable()) - subentry.entries.listAppend("Run +100% item in the beanbat chamber for a single turn for enchanted bean. (50% drop)"); - else - subentry.entries.listAppend("When beanbat chamber is unlocked, run +100% item for a single turn there for enchanted bean (50% drop)"); - } - - int total_turns = $location[Guano Junction].turns_spent + $location[The Batrat and Ratbat Burrow].turns_spent + $location[The Beanbat Chamber].turns_spent; - int turns_until_next_screambat = 8 - (total_turns % 8); - if (turns_until_next_screambat == 8 && total_turns != 0) turns_until_next_screambat = 0; - boolean screambat_up_now = false; - - if (turns_until_next_screambat == 0) - { - screambat_up_now = true; - subentry.entries.listAppend("Screambat next turn."); - } - else - subentry.entries.listAppend("Screambat after " + pluraliseWordy(turns_until_next_screambat, "turn", "turns") + "."); - - if (!screambat_up_now && $item[sonar-in-a-biscuit].item_is_usable()) - { - if (__misc_state["yellow ray available"] && sonars_needed > 0) - subentry.entries.listAppend("Potentially yellow ray for sonar-in-a-biscuit."); - if (sonars_needed > 0) - subentry.entries.listAppend("Run +item in the batrat and ratbat burrow for biscuits. (15% drop)"); - subentry.modifiers.listAppend("+566% item"); - - //Low chance that they started copperhead without having done this, but who knows; just in case - if (__quest_state["Level 11 Shen"].state_int.getFutureShenAssignments().listInvert() contains $location[The Batrat and Ratbat Burrow]) - subentry.entries.listAppend("Could wait before going there? Shen will send you to the Burrow later."); - } - //subentry.entries.listAppend("Run +meat in the boss bat's lair, if you wish. (250 meat drop)"); - } - - task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the bat hole entrance, guano junction, the batrat and ratbat burrow, the beanbat chamber,the boss bat's lair]).ChecklistEntrySetIDTag("Council L4 bat quest")); -} diff --git a/Source/relay/TourGuide/Quests/Level 5.ash b/Source/relay/TourGuide/Quests/Level 5.ash deleted file mode 100644 index c637c29d..00000000 --- a/Source/relay/TourGuide/Quests/Level 5.ash +++ /dev/null @@ -1,245 +0,0 @@ - -void QLevel5Init() -{ - //questL05Goblin - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL05Goblin"); - - state.quest_name = "Knob Goblin Quest"; - state.image_name = "cobb's knob"; - state.council_quest = true; - - - if (my_level() >= 5 || my_path().id == PATH_EXPLOSIONS) - state.startable = true; - - if (get_property("questL05Goblin") == "unstarted" && $item[knob goblin encryption key].available_amount() == 0 && my_path().id != PATH_COMMUNITY_SERVICE) - { - //start the quest anyways, because they need to acquire the encryption key: - //there's also an edge case here in BIG!, where you want to avoid visiting the council for a while to yellow ray an outfit - QuestStateParseMafiaQuestPropertyValue(state, "started"); - } - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - __quest_state["Level 5"] = state; - __quest_state["Knob Goblin King"] = state; -} - - -void QLevel5GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 5"].in_progress) - return; - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO || my_path().id == PATH_SEA || __misc_state["in aftercore"]) - return; - string url = "place.php?whichplace=plains"; - //if the quest isn't started and we have unlocked the barracks, wait until it's started: - if (get_property("questL05Goblin") == "unstarted" && $item[knob goblin encryption key].available_amount() > 0) //have key already, waiting for quest to start, nothing more to do here - return; - - QuestState base_quest_state = __quest_state["Level 5"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - - boolean should_output = true; - - if (!$location[cobb's knob barracks].locationAvailable()) - { - if ($item[knob goblin encryption key].available_amount() == 0) - { - //Need key: - //Unlocking: - if (__misc_state["have hipster"]) - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - if (__misc_state["free runs available"]) - subentry.modifiers.listAppend("free runs"); - - int turns_spent = $location[the outskirts of cobb's knob].turns_spent; - if (turns_spent != -1) - { - int delay_turns_remaining = 10 - turns_spent; - if (delay_turns_remaining == 0) - subentry.entries.listAppend("Map appears next turn in cobb's knob."); - else - subentry.entries.listAppend("Delay for " + pluraliseWordy(delay_turns_remaining, "more turn", "more turns") + " in cobb's knob to unlock area."); - } - else - subentry.entries.listAppend("Delay for ten turns in cobb's knob to unlock area."); - if ($classes[seal clubber, turtle tamer] contains my_class() && !__misc_state["guild open"] && !QuestState("questG09Muscle").started && my_path().id != PATH_NUCLEAR_AUTUMN) - { - url = "guild.php"; - subentry.entries.listAppend("Start your guild quest first."); - } - } - else if ($item[cobb's knob map].available_amount() > 0 && $item[knob goblin encryption key].available_amount() > 0) - { - url = "inventory.php?ftext=cobb's+knob+map"; - subentry.entries.listAppend("Use cobb's knob map to unlock area."); - } - else if ($item[cobb's knob map].available_amount() == 0 && $item[knob goblin encryption key].available_amount() > 0) - should_output = false; - } - else - { - url = "cobbsknob.php"; - //Cobb's knob unlocked. Now to set up for king: - - boolean can_use_harem_route = true; - boolean can_use_kge_route = true; - - boolean have_knob_cake_or_ingredients = false; - have_knob_cake_or_ingredients = ($item[knob cake].available_amount() > 0 || creatable_amount($item[knob cake]) > 0); - - if (can_use_kge_route && have_outfit_components("Knob Goblin Elite Guard Uniform") && have_knob_cake_or_ingredients) - can_use_harem_route = false; - else if (can_use_harem_route && have_outfit_components("Knob Goblin Harem Girl Disguise") && have_outfit_components("Knob Goblin Elite Guard Uniform")) //only stop guarding after KGE is acquired, for dispensary - can_use_kge_route = false; - - if (!__misc_state["can equip just about any weapon"]) - can_use_kge_route = false; - string fight_king_string = "fight king"; - if (53 + monster_level_adjustment() > my_buffedstat($stat[moxie])) - fight_king_string += " (" + (53 + monster_level_adjustment()) + " attack)"; - if (can_use_harem_route) - { - string [int] harem_modifiers; - string [int] harem_lines; - if (!have_outfit_components("Knob Goblin Harem Girl Disguise")) - { - harem_lines.listAppend("Need disguise.|*20% drop from harem girls (olfact)|*Or adventure in zone for eleven (or more) turns."); - harem_modifiers.listAppend("+400% item"); - harem_modifiers.listAppend("olfact harem girls"); - if ($familiar[slimeling].familiar_is_usable()) - harem_modifiers.listAppend("slimeling?"); - } - else - { - string [int] things_to_do_before_fighting_king; - if (!is_wearing_outfit("Knob Goblin Harem Girl Disguise")) - things_to_do_before_fighting_king.listAppend("wear harem girl disguise"); - if ($effect[Knob Goblin Perfume].have_effect() > 0) - { - } - else - { - if ($item[knob goblin perfume].available_amount() > 0) - { - things_to_do_before_fighting_king.listAppend("use knob goblin perfume"); - } - else - { - things_to_do_before_fighting_king.listAppend("adventure in harem for perfume"); - } - } - things_to_do_before_fighting_king.listAppend(fight_king_string); - harem_lines.listAppend(things_to_do_before_fighting_king.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - } - subentry.entries.listAppend("Harem route:|*" + ChecklistGenerateModifierSpan(harem_modifiers) + harem_lines.listJoinComponents("|*")); - } - if (can_use_kge_route) - { - string [int] kge_modifiers; - string [int] kge_lines; - - if (!have_outfit_components("Knob Goblin Elite Guard Uniform")) - { - int outfit_pieces_needed = 0; - if ($item[Knob Goblin elite polearm].available_amount() == 0) - outfit_pieces_needed += 1; - if ($item[Knob Goblin elite pants].available_amount() == 0) - outfit_pieces_needed += 1; - if ($item[Knob Goblin elite helm].available_amount() == 0) - outfit_pieces_needed += 1; - //take into account combats? - //with banishes and slimeling and +item and? - //too complicated. Possibly remove? - kge_modifiers.listAppend("-combat"); - if ($familiar[slimeling].familiar_is_usable()) - kge_modifiers.listAppend("slimeling?"); - string line = "Need knob goblin elite guard uniform.|*Lucky adventure in barracks.|*Or run -combat in barracks"; - if (familiar_is_usable($familiar[slimeling])) - line += " with slimeling"; - - line += "."; - - line += "|*" + generateTurnsToSeeNoncombat(85, outfit_pieces_needed, "acquire outfit via only non-combats"); - kge_lines.listAppend(line); - } - else - { - string cook_cake_line = "cook a knob cake"; - - if (!__misc_state["can cook for free"]) - { - cook_cake_line += " (1 adventure"; - if (skill_is_usable($skill[inigo's incantation of inspiration])) - cook_cake_line += ", can use inigo's"; - cook_cake_line += ")"; - } - string [int] things_to_do_before_fighting_king; - if (!is_wearing_outfit("Knob Goblin Elite Guard Uniform")) - things_to_do_before_fighting_king.listAppend("wear knob goblin elite guard uniform"); - - - boolean have_first_step = ($item[knob cake pan].available_amount() > 0 || $item[unfrosted Knob cake].available_amount() > 0); - boolean have_second_step = ($item[knob batter].available_amount() > 0 || $item[unfrosted Knob cake].available_amount() > 0); - boolean have_third_step = ($item[knob frosting].available_amount() > 0); - have_third_step = have_third_step && have_second_step && have_first_step; - have_second_step = have_second_step && have_first_step; - - if ($item[knob cake].available_amount() > 0) - { - } - else if (have_first_step && have_second_step && have_third_step) - { - things_to_do_before_fighting_king.listAppend(cook_cake_line); - } - else - { - - string times_remaining = "three times"; - if (have_first_step) - times_remaining = "two times"; - if (have_second_step) - times_remaining = "One More Time"; - if (have_third_step) - times_remaining = "zero times?"; - string line = "adventure in kitchens " + times_remaining + " for knob cake components"; - things_to_do_before_fighting_king.listAppend(line); - things_to_do_before_fighting_king.listAppend(cook_cake_line); - } - things_to_do_before_fighting_king.listAppend(fight_king_string); - kge_lines.listAppend(things_to_do_before_fighting_king.listJoinComponents(", then ", "").capitaliseFirstLetter() + "."); - } - subentry.entries.listAppend("Guard route:|*" + ChecklistGenerateModifierSpan(kge_modifiers) + kge_lines.listJoinComponents("|*")); - } - if (!__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "") - { - stat stat_race_type = __quest_state["Level 13"].state_string["Stat race type"].to_stat(); - - int change_mcd_to = -1; - if (stat_race_type == $stat[muscle] && (current_mcd() == 3 || current_mcd() == 7) && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) - change_mcd_to = -2; - else if (stat_race_type == $stat[mysticality]) - change_mcd_to = 3; - else if (stat_race_type == $stat[moxie]) - change_mcd_to = 7; - - if (change_mcd_to != -1 && change_mcd_to != current_mcd()) - { - string mcd_change_text = change_mcd_to; - if (change_mcd_to == -2) - mcd_change_text = "anything besides 3 or 7"; - subentry.entries.listAppend("For the king fight, change MCD to " + mcd_change_text + " for the tower stat test. (+" + stat_race_type.to_lower_case() + ")"); - } - } - } - - - if (should_output) - task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[cobb's knob barracks, cobb's knob kitchens, cobb's knob harem, the outskirts of cobb's knob]).ChecklistEntrySetIDTag("Council L5 knob quest")); -} diff --git a/Source/relay/TourGuide/Quests/Level 6.ash b/Source/relay/TourGuide/Quests/Level 6.ash deleted file mode 100644 index a9c58ea4..00000000 --- a/Source/relay/TourGuide/Quests/Level 6.ash +++ /dev/null @@ -1,194 +0,0 @@ - -void QLevel6Init() -{ - //questL06Friar - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL06Friar"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Deep Fat Friars' Quest"; - state.image_name = "forest friars"; - state.council_quest = true; - - if (my_level() >= 6 || my_path().id == PATH_EXPLOSIONS) - state.startable = true; - - state.state_int["dark neck turns on last nc"] = 0; - state.state_int["dark heart turns on last nc"] = 0; - state.state_int["dark elbow turns on last nc"] = 0; - - __quest_state["Level 6"] = state; - __quest_state["Friars"] = state; -} - -float QLevel6TurnsToCompleteArea(location place) -{ - QuestState base_quest_state = __quest_state["Level 6"]; - //FIXME not sure how accurate these calculations are. - int ncs_found = noncombatTurnsAttemptedInLocation(place); - - - // get_property("lastFriarsXNC").to_int() will return 0 until the first NC is hit, then it will return the turns spent in the zone prior to hitting the NC, - // so we need to add 1 to account for the last NC itself - // For example, if you spend 3 turns in the neck, hit an NC, then hit another NC after 2 turns the pref will manifest as: - // TURN 1: lastFriarsNeckNC = 0 - // TURN 2: lastFriarsNeckNC = 0 - // TURN 3: lastFriarsNeckNC = 0 - // TURN 4: lastFriarsNeckNC = 3 <= hits NC - // TURN 5: lastFriarsNeckNC = 3 - // TURN 6: lastFriarsNeckNC = 3 - // TURN 7: lastFriarsNeckNC = 6 <= hits NC - base_quest_state.state_int["dark neck turns on last nc"] = get_property("lastFriarsNeckNC").to_int() > 0 ? get_property("lastFriarsNeckNC").to_int() + 1 : 0; - base_quest_state.state_int["dark heart turns on last nc"] = get_property("lastFriarsHeartNC").to_int() > 0 ? get_property("lastFriarsHeartNC").to_int() + 1 : 0; - base_quest_state.state_int["dark elbow turns on last nc"] = get_property("lastFriarsElbowNC").to_int() > 0 ? get_property("lastFriarsElbowNC").to_int() + 1 : 0; - - boolean [string] area_known_ncs; - if (place == $location[The Dark Neck of the Woods]) - area_known_ncs = $strings[How Do We Do It? Quaint and Curious Volume!,Strike One!,Olive My Love To You\, Oh.,Dodecahedrariffic!]; - if (place == $location[The Dark Heart of the Woods]) - area_known_ncs = $strings[Moon Over the Dark Heart,Running the Lode,I\, Martin,Imp Be Nimble\, Imp Be Quick]; - if (place == $location[The Dark Elbow of the Woods]) - area_known_ncs = $strings[Deep Imp Act,Imp Art\, Some Wisdom,A Secret\, But Not the Secret You're Looking For,Butter Knife? I'll Take the Knife]; - - if (area_known_ncs.count() > 0) - { - ncs_found = 0; - string [int] location_ncs = place.locationSeenNoncombats(); - foreach key, s in location_ncs - { - if (area_known_ncs contains s) - { - ncs_found += 1; - } - } - } - - if (ncs_found == 4) - { - return 0.0; - } - - float turns_remaining = 0.0; - int ncs_remaining = MAX(0, 4 - ncs_found); - - float combat_rate = 0.95 + combat_rate_modifier() / 100.0; - float noncombat_rate = 1.0 - combat_rate; - - if (noncombat_rate != 0.0) - turns_remaining = ncs_remaining / noncombat_rate; - else - turns_remaining = 10000.0; //how do you refer to infinity in this language? - - int max_turns_remaining = ncs_remaining * 5; - if (place == $location[The Dark Neck of the Woods]) - max_turns_remaining -= $location[The Dark Neck of the Woods].turns_spent - base_quest_state.state_int["dark neck turns on last nc"]; - if (place == $location[The Dark Heart of the Woods]) - max_turns_remaining -= $location[The Dark Heart of the Woods].turns_spent - base_quest_state.state_int["dark heart turns on last nc"]; - if (place == $location[The Dark Elbow of the Woods]) - max_turns_remaining -= $location[The Dark Elbow of the Woods].turns_spent - base_quest_state.state_int["dark elbow turns on last nc"]; - return MIN(turns_remaining, max_turns_remaining); -} - - -void QLevel6GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 6"].in_progress) - return; - boolean want_hell_ramen = false; - if ($skill[pastamastery].skill_is_usable() && $skill[Advanced Saucecrafting].skill_is_usable()) - want_hell_ramen = true; - if (my_path().id == PATH_SLOW_AND_STEADY) - want_hell_ramen = false; - want_hell_ramen = false; //this needs rethinking - - boolean hot_wings_relevant = __quest_state["Pirate Quest"].state_boolean["hot wings relevant"] && __quest_state["Pirate Quest"].state_boolean["valid"]; - boolean need_more_hot_wings = __quest_state["Pirate Quest"].state_boolean["need more hot wings"] && __quest_state["Pirate Quest"].state_boolean["valid"]; - - QuestState base_quest_state = __quest_state["Level 6"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - if (want_hell_ramen && __misc_state["have olfaction equivalent"]) - subentry.modifiers.listAppend("olfact hellions"); - - string [int] sources_need_234; - if (want_hell_ramen) - sources_need_234.listAppend("hell ramen"); - if (need_more_hot_wings) - sources_need_234.listAppend("hot wings"); - if (sources_need_234.count() > 0) - subentry.modifiers.listAppend("+234% item"); - - boolean hipster_fights_needed = false; - boolean need_minus_combat = false; - if ($item[dodecagram].available_amount() == 0) { - hipster_fights_needed = true; - subentry.entries.listAppend("Adventure in " + HTMLGenerateSpanOfClass("Dark Neck of the Woods", "r_bold") + ", acquire dodecagram.|~" + roundForOutput(QLevel6TurnsToCompleteArea($location[The Dark Neck of the Woods]), 1) + " turns remain at " + combat_rate_modifier().floor() + "% combat."); - if ($location[The Dark Neck of the Woods].turns_spent - base_quest_state.state_int["dark neck turns on last nc"] >= 5) - subentry.entries.listAppend(HTMLGenerateSpanOfClass("Your next adventure in the Neck will be an NC", "r_bold")); - need_minus_combat = true; - } - if ($item[box of birthday candles].available_amount() == 0) { - hipster_fights_needed = true; - subentry.entries.listAppend("Adventure in " + HTMLGenerateSpanOfClass("Dark Heart of the Woods", "r_bold") + ", acquire box of birthday candles.|~" + roundForOutput(QLevel6TurnsToCompleteArea($location[The Dark Heart of the Woods]), 1) + " turns remain at " + combat_rate_modifier().floor() + "% combat."); - if ($location[The Dark Heart of the Woods].turns_spent - base_quest_state.state_int["dark heart turns on last nc"] >= 5) - subentry.entries.listAppend(HTMLGenerateSpanOfClass("Your next adventure in the Heart will be an NC", "r_bold")); - need_minus_combat = true; - } - if ($item[Eldritch butterknife].available_amount() == 0) { - hipster_fights_needed = true; - subentry.entries.listAppend("Adventure in " + HTMLGenerateSpanOfClass("Dark Elbow of the Woods", "r_bold") + ", acquire Eldritch butterknife.|~" + roundForOutput(QLevel6TurnsToCompleteArea($location[The Dark Elbow of the Woods]), 1) + " turns remain at " + combat_rate_modifier().floor() + "% combat."); - if ($location[The Dark Elbow of the Woods].turns_spent - base_quest_state.state_int["dark elbow turns on last nc"] >= 5) - subentry.entries.listAppend(HTMLGenerateSpanOfClass("Your next adventure in the Elbow will be an NC", "r_bold")); - need_minus_combat = true; - } - - //hipster fights advance the superlikelies. in slow paths, is this relevant? - //FIXME suggest in HCO/S&S? - //if (hipster_fights_needed && __misc_state["have hipster"]) - //subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - - string [int] needed_modifiers; - if (need_minus_combat) { - subentry.modifiers.listAppend("-combat"); - needed_modifiers.listAppend("-combat"); - } - if (sources_need_234.count() > 0) - needed_modifiers.listAppend("+234% item for " + listJoinComponents(sources_need_234, "/")); - if (needed_modifiers.count() > 0) - subentry.entries.listAppend("Run " + needed_modifiers.listJoinComponents(", ", "and") + "."); - - if ($item[dodecagram].available_amount() + $item[box of birthday candles].available_amount() + $item[Eldritch butterknife].available_amount() == 3) { - if (!(hot_wings_relevant && $item[hot wing].available_amount() <3)) { - subentry.entries.listAppend("Go to the cairn stones!"); - } else { - subentry.entries.listAppend("Visit The Dark Heart of the Woods for hot wings."); - } - } - if (!get_property_ascension("lastTempleUnlock") && QuestState("questM16Temple").in_progress && $item[heavy-duty bendy straw].available_amount() == 0) - subentry.entries.listAppend("Potentially find a heavy-duty bendy straw, first.|From fallen archfiends in The Dark Heart of the Woods."); - if (__misc_state_int["ruby w needed"] > 0) - subentry.entries.listAppend("Potentially find ruby W, if not clovering (w imp, dark neck, 30% drop)"); - if (hot_wings_relevant) { - if ($item[hot wing].available_amount() <3 ) - subentry.entries.listAppend((MIN(3, $item[hot wing].available_amount())) + "/3 hot wings for pirate quest. (optional, 30% drop)"); - else - subentry.entries.listAppend((MIN(3, $item[hot wing].available_amount())) + "/3 hot wings for pirate quest."); - } - boolean should_delay = false; - if (!__quest_state["Manor Unlock"].state_boolean["ballroom song effectively set"] && need_minus_combat) { - subentry.entries.listAppend(HTMLGenerateSpanOfClass("Wait until -combat ballroom song set.", "r_bold")); - should_delay = true; - } - - ChecklistEntry entry = ChecklistEntryMake(base_quest_state.image_name, "friars.php", subentry, $locations[The Dark Neck of the Woods, The Dark Heart of the Woods, The Dark Elbow of the Woods]); - entry.tags.id = "Council L6 friars quest"; - - if (should_delay) - future_task_entries.listAppend(entry); - else - task_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Quests/Level 7.ash b/Source/relay/TourGuide/Quests/Level 7.ash deleted file mode 100644 index 4f5159ea..00000000 --- a/Source/relay/TourGuide/Quests/Level 7.ash +++ /dev/null @@ -1,327 +0,0 @@ -void QLevel7Init() -{ - int CYRPT_BOSS_EVILNESS = 13; - //questL07Cyrptic - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL07Cyrptic"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_GREY_GOO) state.finished = true; - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Cyrpt Quest"; - state.image_name = "cyrpt"; - state.council_quest = true; - - if (my_level() >= 7 || my_path().id == PATH_EXPLOSIONS) - state.startable = true; - - if (state.started) - { - state.state_int["alcove evilness"] = get_property_int("cyrptAlcoveEvilness"); - state.state_int["cranny evilness"] = get_property_int("cyrptCrannyEvilness"); - state.state_int["niche evilness"] = get_property_int("cyrptNicheEvilness"); - state.state_int["nook evilness"] = get_property_int("cyrptNookEvilness"); - } - else - { - //mafia won't track these properly until quest is started, I think? - state.state_int["alcove evilness"] = 50; - state.state_int["cranny evilness"] = 50; - state.state_int["niche evilness"] = 50; - state.state_int["nook evilness"] = 50; - } - - if (state.finished) - { - //just in case: - state.state_int["alcove evilness"] = 0; - state.state_int["cranny evilness"] = 0; - state.state_int["niche evilness"] = 0; - state.state_int["nook evilness"] = 0; - } - - foreach l in $strings[alcove,cranny,niche,nook] - { - boolean need_speeding_up = false; - int evilness = state.state_int[l + " evilness"]; - - if (l == "alcove" && get_property_monster("romanticTarget") == $monster[modern zmobie]) - evilness -= 5 * get_property_int("_romanticFightsLeft"); - - if (evilness <= CYRPT_BOSS_EVILNESS + 1) - need_speeding_up = false; - else - need_speeding_up = true; - state.state_boolean[l + " needs speed tricks"] = need_speeding_up; - - } - - if (state.state_int["alcove evilness"] <= 0) - state.state_boolean["alcove finished"] = true; - if (state.state_int["cranny evilness"] <= 0) - state.state_boolean["cranny finished"] = true; - if (state.state_int["niche evilness"] <= 0) - state.state_boolean["niche finished"] = true; - if (state.state_int["nook evilness"] <= 0) - state.state_boolean["nook finished"] = true; - - - __quest_state["Level 7"] = state; - __quest_state["Cyrpt"] = state; -} - - -void QLevel7GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - int CYRPT_BOSS_EVILNESS = 13; - if (!__quest_state["Level 7"].in_progress) - return; - QuestState base_quest_state = __quest_state["Level 7"]; - - ChecklistEntry entry; - entry.url = "crypt.php"; - entry.image_lookup_name = base_quest_state.image_name; - entry.tags.id = "Council L7 crypt cyrpt quest"; - entry.should_indent_after_first_subentry = true; - entry.subentries.listAppend(ChecklistSubentryMake(base_quest_state.quest_name)); - entry.should_highlight = $locations[the defiled nook, the defiled cranny, the defiled alcove, the defiled niche, haert of the cyrpt] contains __last_adventure_location; - - string [int] evilness_properties = split_string_alternate("cyrptAlcoveEvilness,cyrptCrannyEvilness,cyrptNicheEvilness,cyrptNookEvilness", ","); - string [string] evilness_text; - - foreach key in evilness_properties - { - string property = evilness_properties[key]; - int evilness = get_property_int(property); - string text; - if (evilness == 0) - text = "Finished"; - else if (evilness <= CYRPT_BOSS_EVILNESS) - text = HTMLGenerateSpanFont("At boss", "red"); - else - text = (evilness - CYRPT_BOSS_EVILNESS) + " evilness to boss."; - evilness_text[property] = text; - } - - // speed up cyrpt using Slay the Dead - if ($item[unwrapped knock-off retro superhero cape].available_amount() > 0 && __iotms_usable[lookupItem("unwrapped knock-off retro superhero cape")] && __misc_state["can equip just about any weapon"]) { - string cape_hero = get_property("retroCapeSuperhero"); - string cape_tag = get_property("retroCapeWashingInstructions"); - - string [int] problems; - if ($item[unwrapped knock-off retro superhero cape].equipped_amount() == 0) { - problems.listAppend("Equip the superhero cape"); - } - if (cape_hero != "vampire" || cape_tag != "kill") { - problems.listAppend("Set retro superhero cape to \"Vampire Slicer\"+\"Kill Me\""); - } - if ($slot[weapon].equipped_item().item_type() != "sword") { - problems.listAppend("Equip a sword in your main-hand"); - } - - if (problems.count() > 0) { - entry.subentries[0].entries.listAppend(problems.listJoinComponents(", ", "and") + " to Slay the Dead in combat."); - } - else { - entry.subentries[0].entries.listAppend("Cast Slay the Dead in combat for +1 evil reduction/fight."); - } - } - - if (!base_quest_state.state_boolean["nook finished"]) - { - int evilness = base_quest_state.state_int["nook evilness"]; - ChecklistSubentry subentry; - subentry.header = "Defiled Nook"; - - subentry.entries.listAppend(evilness_text["cyrptNookEvilness"]); - - if (evilness > CYRPT_BOSS_EVILNESS + 1 && my_path().id != PATH_G_LOVER) - { - subentry.modifiers.listAppend("+400% item"); - subentry.modifiers.listAppend("banish party skelteon"); - - float [monster] appearance_rates = $location[the defiled nook].appearance_rates_adjusted_cancel_nc(); - float chance_of_monster_with_eye = 0.0; - chance_of_monster_with_eye += 1.0 * appearance_rates[$monster[spiny skelelton]] / 100.0; - chance_of_monster_with_eye += 1.0 * appearance_rates[$monster[toothy sklelton]] / 100.0; - - float item_drop = (100.0 + chance_of_monster_with_eye * $location[the defiled nook].item_drop_modifier_for_location()) / 100.0; - - float eyes_per_adventure = MIN(1.0, (item_drop) * 0.2); - float eyes_value = 3.0; - if (evilness < CYRPT_BOSS_EVILNESS + 4) - eyes_value = clampi(evilness - CYRPT_BOSS_EVILNESS - 1, 0, 3); - float evilness_per_adventure = 1.0; - if ($item[gravy boat].equipped_amount() > 0) - evilness_per_adventure += 1.0; - evilness_per_adventure = MAX(evilness_per_adventure, evilness_per_adventure + eyes_per_adventure * eyes_value); - - if ($item[evil eye].available_amount() > 0) - { - if ($item[evil eye].available_amount() == 1) - subentry.entries.listAppend("Use your evil eye."); - else - subentry.entries.listAppend("Use your evil eyes."); - } - if (__iotms_usable[$item[haunted doghouse]] && !$location[the defiled nook].noncombat_queue.contains_text("Seeing-Eyes Dog") && $location[the defiled nook].turns_spent >= 5) - { - //haunted doghouse adventures are a percentage chance, and the NC is skippable. more NCs, more chances, less turns spent - subentry.modifiers.listAppend("-combat"); - } - if (my_path().id == PATH_EXPLOSIONS) - subentry.entries.listAppend("Ignore this area until the end of the run; wandering astronauts drop evil eyes. Lure them to delay-burning areas; keep signal jammer equipped otherwise."); - - float evilness_remaining = evilness - CYRPT_BOSS_EVILNESS; - evilness_remaining -= $item[evil eye].available_amount() * 3; - if (evilness_remaining > 0) - { - float average_turns_remaining = (evilness_remaining / evilness_per_adventure); - int theoretical_best_turns_remaining = ceil(evilness_remaining / 4.0); - if (average_turns_remaining < theoretical_best_turns_remaining) //not sure about this. +344.91% item, 38 evilness, 4 optimal, 3.something not-optimal, what does it mean? - average_turns_remaining = theoretical_best_turns_remaining; - - subentry.entries.listAppend(roundForOutput(eyes_per_adventure * 100.0, 0) + "% chance of evil eyes."); - subentry.entries.listAppend("~" + roundForOutput(average_turns_remaining, 1) + " turns remain to boss. (theoretical best: " + theoretical_best_turns_remaining + ")"); - } - } - - entry.subentries.listAppend(subentry); - } - if (!base_quest_state.state_boolean["niche finished"]) - { - int evilness = base_quest_state.state_int["niche evilness"]; - ChecklistSubentry subentry; - subentry.header = "Defiled Niche"; - - subentry.entries.listAppend(evilness_text["cyrptNicheEvilness"]); - - float [monster] appearance_rates = $location[the defiled niche].appearance_rates_adjusted_cancel_nc(); - float evilness_removed_per_adventure = 0.0; - evilness_removed_per_adventure += 1.0 * appearance_rates[$monster[basic lihc]] / 100.0; - evilness_removed_per_adventure += 1.0 * appearance_rates[$monster[slick lihc]] / 100.0; - evilness_removed_per_adventure += 1.0 * appearance_rates[$monster[senile lihc]] / 100.0; - evilness_removed_per_adventure += 3.0 * appearance_rates[$monster[dirty old lihc]] / 100.0; - - float evilness_remaining = MAX(0, evilness - CYRPT_BOSS_EVILNESS); - int turns_remaining = evilness_remaining; - - if (evilness_removed_per_adventure != 0.0) - turns_remaining = MAX(1, ceiling(evilness_remaining / evilness_removed_per_adventure)); - - // TODO: This doesn't work if the user is using a non-olfaction copy source, like nosy nose or monkey point. Need to add logic for that - boolean sniffedDOL = false; - if (get_property_monster("olfactedMonster") == $monster[dirty old lihc]) sniffedDOL = true; - - // evilness_removed_per_adventure will = 0 if all appearance rates are 0, i.e., everyone is banished. - // This allows the tile to note that if DOL is olfacted and everything else is banished via phylum - // silliness, you can assume the rest of the turns are DOL. Otherwise, everything is unbanished, so - // you get 1.5 per turn (average of all 4 monsters). - if (evilness_removed_per_adventure == 0.0) - { - if (sniffedDOL) turns_remaining = MAX(1, ceiling(evilness_remaining / 3.0)); - if (!sniffedDOL) turns_remaining = MAX(1, ceiling(evilness_remaining / 1.5)); - - } - - if (evilness > CYRPT_BOSS_EVILNESS + 1 && (appearance_rates[$monster[slick lihc]] > 0.0 || appearance_rates[$monster[senile lihc]] > 0.0)) - { - subentry.modifiers.listAppend("olfact dirty old lihc"); - subentry.modifiers.listAppend("banish"); - } - if (evilness > CYRPT_BOSS_EVILNESS) - subentry.entries.listAppend("~" + turns_remaining.roundForOutput(1) + " turns remaining to boss."); - - entry.subentries.listAppend(subentry); - } - if (!base_quest_state.state_boolean["cranny finished"]) - { - ChecklistSubentry subentry; - subentry.header = "Defiled Cranny"; - subentry.entries.listAppend(evilness_text["cyrptCrannyEvilness"]); - - if (base_quest_state.state_int["cranny evilness"] > CYRPT_BOSS_EVILNESS + 1) - { - subentry.modifiers.listAppend("-combat"); - subentry.modifiers.listAppend("+ML"); - float monster_level = monster_level_adjustment_for_location($location[the defiled cranny]); - - monster_level = MAX(monster_level, 0); - - float cranny_beep_beep_beep = MAX(3.0,sqrt(monster_level)); - int beep_boop_lookup = floor(cranny_beep_beep_beep) - 3; - - float area_combat_rate = clampNormalf(0.85 + combat_rate_modifier() / 100.0); - float area_nc_rate = 1.0 - area_combat_rate; - - float average_beeps_per_turn = cranny_beep_beep_beep * area_nc_rate + 1.0 * area_combat_rate; - float average_turns_remaining = ((base_quest_state.state_int["cranny evilness"] - CYRPT_BOSS_EVILNESS) / average_beeps_per_turn); - - average_turns_remaining = MAX(1, average_turns_remaining); - - subentry.entries.listAppend("~" + cranny_beep_beep_beep.roundForOutput(1) + " beeps per ghuol swarm. ~" + average_turns_remaining.roundForOutput(1) + " turns remain to boss."); - } - else if (base_quest_state.state_int["cranny evilness"] <= CYRPT_BOSS_EVILNESS) - subentry.modifiers.listAppend("+meat"); - - entry.subentries.listAppend(subentry); - } - if (!base_quest_state.state_boolean["alcove finished"]) - { - ChecklistSubentry subentry; - int evilness = base_quest_state.state_int["alcove evilness"]; - subentry.header = "Defiled Alcove"; - subentry.entries.listAppend(evilness_text["cyrptAlcoveEvilness"]); - - - int evilness_after_arrow = evilness; - if (get_property_monster("romanticTarget") == $monster[modern zmobie]) - evilness_after_arrow -= 5 * get_property_int("_romanticFightsLeft"); - - if (evilness_after_arrow <= CYRPT_BOSS_EVILNESS && evilness > CYRPT_BOSS_EVILNESS) - { - subentry.entries.listAppend("Wait for modern zmobie arrows."); - } - else if (evilness > CYRPT_BOSS_EVILNESS + 1) - { - subentry.modifiers.listAppend("+850% init"); - subentry.modifiers.listAppend("-combat"); - int zmobies_needed = ceil((evilness.to_float() - CYRPT_BOSS_EVILNESS.to_float()) / 5.0); // used to be a +1 there; hope this is OK? - float zmobie_chance = min(100.0, 15.0 + initiative_modifier_for_location($location[the defiled alcove]) / 10.0); - - subentry.entries.listAppend(pluralise(zmobies_needed, "modern zmobie", "modern zmobies") + " needed (" + roundForOutput(zmobie_chance, 0) + "% chance of appearing)"); - - //float combat_rate = clampNormalf(0.85 + combat_rate_modifier() / 100.0); - //float nc_rate = 1.0 - combat_rate; - - if ($familiar[oily woim].familiar_is_usable() && !(($familiars[oily woim,happy medium] contains my_familiar()))) - { - if (!(my_familiar() == $familiar[Xiblaxian Holo-Companion] && my_familiar() != $familiar[none])) - subentry.entries.listAppend("Run " + $familiar[oily woim] + ($familiar[happy medium].familiar_is_usable() ? "/medium" : "") + ($familiar[Xiblaxian Holo-Companion].familiar_is_usable() ? "/holo-companion" : "") + " for +init."); - } - - - } - else if (evilness <= CYRPT_BOSS_EVILNESS) - subentry.modifiers.listAppend("+meat"); - entry.subentries.listAppend(subentry); - } - if (base_quest_state.mafia_internal_step == 2) - { - entry.subentries[0].entries.listAppend("Go talk to the council to finish the quest."); - entry.url = "place.php?whichplace=town"; - } - else if (base_quest_state.state_boolean["alcove finished"] && base_quest_state.state_boolean["cranny finished"] && base_quest_state.state_boolean["niche finished"] && base_quest_state.state_boolean["nook finished"]) - { - float bonerdagon_attack = (90 + monster_level_adjustment()); - - string line = "Fight bonerdagon!"; - if (my_path().id == PATH_HEAVY_RAINS) - line = "Fight auqadargon!"; - if (my_basestat($stat[moxie]) < bonerdagon_attack) - line += " (attack: " + bonerdagon_attack.round() + ")"; - entry.subentries[0].entries.listAppend(line); - } - task_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Quests/Level 8.ash b/Source/relay/TourGuide/Quests/Level 8.ash deleted file mode 100644 index cbcb8285..00000000 --- a/Source/relay/TourGuide/Quests/Level 8.ash +++ /dev/null @@ -1,300 +0,0 @@ -import "relay/TourGuide/Sets/Copied Monsters.ash" //A quaint and curious import. - -void QLevel8Init() -{ - //questL08Trapper - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL08Trapper"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Trapper Quest"; - state.image_name = "trapper"; - state.council_quest = true; - - if (get_property("peteMotorbikeTires") == "Snow Tires" && state.started && !state.finished && state.mafia_internal_step < 4) //sort of hacky - they're not actually there, but... - { - state.mafia_internal_step = 4; - } - - - if (state.mafia_internal_step > 2) - state.state_boolean["Past mine"] = true; - if (state.mafia_internal_step > 3) - state.state_boolean["Mountain climbed"] = true; - if (state.mafia_internal_step > 5) - state.state_boolean["Groar defeated"] = true; - - state.state_string["ore needed"] = get_property("trapperOre").HTMLEscapeString(); - - if (my_level() >= 8 || my_path().id == PATH_EXPLOSIONS) - state.startable = true; - - __quest_state["Level 8"] = state; - __quest_state["Trapper"] = state; -} - - -void QLevel8GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 8"].in_progress) - return; - QuestState base_quest_state = __quest_state["Level 8"]; - string image_name = base_quest_state.image_name; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - string url = "place.php?whichplace=mclargehuge"; - string talk_to_trapper_string = "Go talk to the trapper."; - - float cold_resistance = numeric_modifier("cold resistance"); - string need_cold_res_string = "acquire " + (5.0 - cold_resistance).to_int() + " more " + HTMLGenerateSpanOfClass("cold resistance", "r_element_cold"); - - if (base_quest_state.mafia_internal_step == 1) - { - subentry.entries.listAppend(talk_to_trapper_string); - } - else if (!base_quest_state.state_boolean["Past mine"]) - { - string cheese_header; //string cheese - string [int] cheese_lines; - - cheese_header = MIN(3, $item[goat cheese].available_amount()) + "/3 goat cheese found"; - if ($item[goat cheese].available_amount() <3 ) - cheese_header += " (40% drop)"; - - boolean need_cheese = $item[goat cheese].available_amount() <3; - - if (need_cheese) - { - subentry.modifiers.listAppend("150% item"); - if (__misc_state["have olfaction equivalent"]) - subentry.modifiers.listAppend("olfact dairy goats"); - - - if ($skill[Advanced Saucecrafting].skill_is_usable() && fullness_limit() > 0 && __misc_state["can eat just about anything"] && my_path().id != PATH_SLOW_AND_STEADY) - cheese_lines.listAppend("Have " + pluralise($item[glass of goat\'s milk]) + " for magnesium (20% drop)"); - } - - subentry.entries.listAppend(cheese_header + HTMLGenerateIndentedText(cheese_lines)); - - - - string ore_header; - string [int] ore_lines; - item ore_needed = to_item(base_quest_state.state_string["ore needed"]); - - ore_header = MIN(3, ore_needed.available_amount()) + "/3 " + ore_needed + " found"; - - boolean need_ore = ore_needed.available_amount() <3; - if (need_ore) - { - string [int] potential_ore_sources; - potential_ore_sources.listAppend("Mining"); - if (!in_bad_moon()) - potential_ore_sources.listAppend("Clovering itznotyerzitzmine (one of each ore, consider if zap available?)"); - - - - boolean need_outfit = true; - if (have_outfit_components("Mining Gear")) - need_outfit = false; - if (my_path().id == PATH_AVATAR_OF_BORIS) - { - subentry.modifiers.listAppend("+150%/+1000% item"); - need_outfit = false; - potential_ore_sources.listClear(); - potential_ore_sources.listAppend("Fight mountain men in the mine (40%, 10% drop for each ore)"); - } - if (my_path().id == PATH_WAY_OF_THE_SURPRISING_FIST) - { - string have_skill_text = ""; - if (!skill_is_usable($skill[worldpunch])) - have_skill_text = " (you do not have this skill yet)"; - potential_ore_sources.listAppend("Earthen Fist will allow mining." + have_skill_text); - need_outfit = false; - } - // changed this to remove an is_unrestricted check; i think this still should work without it? - if (__iotms_usable[$item[Deck of Every Card]]) - potential_ore_sources.listAppend("Deck of Every Card - Mine card"); - ore_lines.listAppend("Potential sources of ore:" + HTMLGenerateIndentedText(potential_ore_sources)); - if (skill_is_usable($skill[unaccompanied miner])) - ore_lines.listAppend("You can free mine. Consider splitting mining over several days for zero-adventure cost."); - if (need_outfit) - { - subentry.modifiers.listAppend("-combat"); - if ($familiar[slimeling].familiar_is_usable()) - subentry.modifiers.listAppend("slimeling?"); - ore_lines.listAppend("Mining outfit not available. Consider acquiring one via -combat in mine"); - } - if (is_wearing_outfit("Mining Gear")) - { - url = "mining.php?mine=1"; - } - - } - subentry.entries.listAppend(ore_header + HTMLGenerateIndentedText(ore_lines)); - - if (!need_cheese && !need_ore) - { - subentry.entries.listClear(); - subentry.entries.listAppend(talk_to_trapper_string); - - } - } - else if (!base_quest_state.state_boolean["Mountain climbed"]) - { - //ninja: - string ninja_line; - boolean ninja_finishes_quest = false; - if (true) - { - string [int] ninja_path; - string [int] ninja_modifiers; - - item [int] items_needed; - if ($item[ninja rope].available_amount() == 0) items_needed.listAppend($item[ninja rope]); - if ($item[ninja crampons].available_amount() == 0) items_needed.listAppend($item[ninja crampons]); - if ($item[ninja carabiner].available_amount() == 0) items_needed.listAppend($item[ninja carabiner]); - - if (items_needed.count() == 0) - { - if (cold_resistance < 5.0) - ninja_path.listAppend(need_cold_res_string.capitaliseFirstLetter() + "."); - - ninja_path.listAppend("Climb the peak."); - ninja_finishes_quest = true; - } - else - { - ninja_path.listAppend("Need " + items_needed.listJoinComponents(", ", "and") + "."); - string [int] assassin_description; - - if (get_property_int("_romanticFightsLeft") > 0 && get_property_int("_romanticFightsLeft") >= items_needed.count() && get_property("romanticTarget") == "ninja snowman assassin") - { - ninja_path.listAppend("They will find you."); - } - else - { - ninja_modifiers.listAppend("+combat"); - ninja_path.listAppend("Run +combat in Lair of the Ninja Snowmen, fight assassins."); - CopiedMonstersGenerateDescriptionForMonster("ninja snowman assassin", assassin_description, true, false); - if (combat_rate_modifier() <= 0.0) - ninja_path.listAppend("Need more +combat, assassins won't appear at " + combat_rate_modifier().floor() + "% combat."); - else - { - int turns_spent = $location[lair of the ninja snowmen].turns_spent; - if (turns_spent != -1) - { - float chance = combat_rate_modifier() / 200.0 + turns_spent * 0.015; - if (turns_spent == 10 || turns_spent == 20 || turns_spent == 30 || chance >= 1.0) - ninja_path.listAppend("Assassin will appear next turn."); - else - ninja_path.listAppend((chance * 100.0).roundForOutput(0) + "% chance of assassins."); - } - } - - if (__quest_state["Level 11 Shen"].state_int.getFutureShenAssignments().listInvert() contains $location[Lair of the Ninja Snowmen]) - subentry.entries.listAppend("Could wait before going there? Shen will send you to the Ninja Lair later."); - } - ninja_path.listAppend(generateNinjaSafetyGuide(true)); - } - - ninja_line = "Ninja path:"; - - if (ninja_modifiers.count() > 0) - ninja_line += "|*" + ChecklistGenerateModifierSpan(ninja_modifiers) + "|"; - ninja_line += HTMLGenerateIndentedText(ninja_path.listJoinComponents("
")); - - if (ninja_finishes_quest) - ninja_line = ninja_path.listJoinComponents("
"); - } - //eXtreme outfit: - string extreme_line; - if (true) - { - string [int] extreme_path; - string [int] extreme_modifiers; - - - - item [int] items_needed = missing_outfit_components("eXtreme Cold-Weather Gear"); - - if (items_needed.count() == 0) - { - string [int] things_to_do; - if (!is_wearing_outfit("eXtreme Cold-Weather Gear")) - things_to_do.listAppend("wear eXtreme Cold-Weather Gear"); - - if (!$location[the extreme slope].noncombat_queue.contains_text("3 eXXXtreme 4ever 6pack")) - { - things_to_do.listAppend("run -combat"); - things_to_do.listAppend("become eXtreme"); - extreme_modifiers.listAppend("-combat"); - } - things_to_do.listAppend("jump onto the mountain top"); - extreme_path.listAppend(things_to_do.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - } - else - { - extreme_path.listAppend("Acquire outfit components: " + items_needed.listJoinComponents(", ", "and") + "."); - extreme_modifiers.listAppend("-combat"); - extreme_modifiers.listAppend("+item"); - if ($familiar[slimeling].familiar_is_usable()) - extreme_modifiers.listAppend("slimeling?"); - extreme_path.listAppend("Run -combat and maybe +item on the eXtreme slope."); - } - - extreme_line = "Extreme path:"; - - if (extreme_modifiers.count() > 0) - extreme_line += "|*" + ChecklistGenerateModifierSpan(extreme_modifiers) + "|"; - extreme_line += HTMLGenerateIndentedText(extreme_path.listJoinComponents("
")); - - } - if (!ninja_finishes_quest) - subentry.entries.listAppend("Find a way to climb the peak."); - subentry.entries.listAppend(ninja_line); - if (!ninja_finishes_quest) //ninja need not tricks - subentry.entries.listAppend(extreme_line); - } - else if (!base_quest_state.state_boolean["Groar defeated"]) - { - int turns_remaining = MAX(0, 4 - $location[mist-shrouded peak].turnsAttemptedInLocation()); - - if (get_property("peteMotorbikeTires") == "Snow Tires") - turns_remaining = 1; - - string [int] todo; - if (cold_resistance < 5.0) - todo.listAppend(need_cold_res_string); - - - float groar_attack = (120 + monster_level_adjustment()); - - string line = "fight Groar at the peak"; - if (my_basestat($stat[moxie]) < groar_attack) - line += " (attack: " + groar_attack.round() + ")"; - - todo.listAppend(line); - subentry.entries.listAppend(todo.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - - if (turns_remaining > 1) - { - subentry.modifiers.listAppend("+meat"); - subentry.entries.listAppend("Optionally run +meat for " + pluraliseWordy((turns_remaining - 1), "turn", "turns") + ". (200 base meat drop)"); - } - - image_name = "Yeti"; - } - else - { - subentry.entries.listAppend(talk_to_trapper_string); - } - - - - task_entries.listAppend(ChecklistEntryMake(image_name, url, subentry, $locations[itznotyerzitz mine,the goatlet, lair of the ninja snowmen, the extreme slope,mist-shrouded peak, itznotyerzitz mine (in disguise)]).ChecklistEntrySetIDTag("Council L8 trapper quest")); -} diff --git a/Source/relay/TourGuide/Quests/Level 9.ash b/Source/relay/TourGuide/Quests/Level 9.ash deleted file mode 100644 index 18ca065f..00000000 --- a/Source/relay/TourGuide/Quests/Level 9.ash +++ /dev/null @@ -1,693 +0,0 @@ - -void QLevel9Init() -{ - //questL09Topping - //oilPeakProgress - //twinPeakProgress - //booPeakProgress - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questL09Topping"); - - // Finish the quest state in paths that don't need the tile. - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG - if (my_path().id == PATH_SEA) state.finished = true; - - state.quest_name = "Highland Lord Quest"; - state.image_name = "orc chasm"; - state.council_quest = true; - - //Recorded in-run: - //twinPeakProgress(user, now '1', default 0) - +stench one done - //twinPeakProgress(user, now '3', default 0) - +stench, +item ones done - //twinPeakProgress(user, now '7', default 0) - +stench, +item, jar ones done - //twinPeakProgress(user, now '15', default 0) - finished - //twinPeakProgress(user, now '3', default 0) -> item done, stench done, jar not done, init not done, quest started - - if (state.mafia_internal_step > 1) - { - state.state_boolean["bridge complete"] = true; - } - else - { - int bridge_progress = get_property_int("chasmBridgeProgress"); - int fasteners_have = bridge_progress + $item[thick caulk].available_amount() + $item[long hard screw].available_amount() + $item[messy butt joint].available_amount() + 5 * $item[smut orc keepsake box].usable_amount() + 5 * $item[snow boards].usable_amount(); - int lumber_have = bridge_progress + $item[morningwood plank].available_amount() + $item[raging hardwood plank].available_amount() + $item[weirdwood plank].available_amount() + 5 * $item[smut orc keepsake box].usable_amount() + 5 * $item[snow boards].usable_amount(); - if (my_path().id == PATH_LICENSE_TO_ADVENTURE && get_property_boolean("bondBridge")) - { - fasteners_have += 15; - lumber_have += 15; - } - - int fasteners_needed = MAX(0, 30 - fasteners_have); - int lumber_needed = MAX(0, 30 - lumber_have); - - state.state_int["bridge fasteners needed"] = fasteners_needed; - state.state_int["bridge lumber needed"] = lumber_needed; - } - - if (my_level() >= 9 || my_path().id == PATH_EXPLOSIONS) - state.startable = true; - - - state.state_boolean["can complete twin peaks quest quickly"] = true; - - if (my_path().id == PATH_BEES_HATE_YOU) - state.state_boolean["can complete twin peaks quest quickly"] = false; - - state.state_float["oil peak pressure"] = get_property_float("oilPeakProgress"); - if ($location[oil peak].noncombat_queue.contains_text("Unimpressed with Pressure")) - state.state_float["oil peak pressure"] = 0.0; - state.state_int["twin peak progress"] = get_property_int("twinPeakProgress"); - state.state_int["a-boo peak hauntedness"] = get_property_int("booPeakProgress"); - if ($location[a-boo peak].noncombat_queue.contains_text("Come On Ghosty, Light My Pyre")) - state.state_int["a-boo peak hauntedness"] = 0; - - - if (!state.state_boolean["bridge complete"]) //haven't gotten over there yet. not sure what mafia says at this point, so set some defaults: - { - state.state_int["twin peak progress"] = 0; - state.state_float["oil peak pressure"] = 310.66; - state.state_int["a-boo peak hauntedness"] = 100; - } - if (state.finished) - { - state.state_boolean["bridge complete"] = true; - - state.state_int["twin peak progress"] = 15; - state.state_float["oil peak pressure"] = 0.0; - state.state_int["a-boo peak hauntedness"] = 0; - } - - if (state.state_float["oil peak pressure"] > 500.0) //not sure what causes this. detecting this situation - { - state.state_float["oil peak pressure"] = 310.66; - state.state_boolean["oil peak pressure bug in effect"] = true; - } - - - int twin_progress = state.state_int["twin peak progress"]; - - state.state_boolean["Peak Stench Completed"] = (twin_progress & 1) > 0; - state.state_boolean["Peak Item Completed"] = (twin_progress & 2) > 0; - state.state_boolean["Peak Jar Completed"] = (twin_progress & 4) > 0; - state.state_boolean["Peak Init Completed"] = (twin_progress & 8) > 0; - - state.state_int["peak tests remaining"] = 0; - foreach s in $strings[Peak Stench Completed,Peak Item Completed,Peak Jar Completed,Peak Init Completed] - { - if (!state.state_boolean[s]) - state.state_int["peak tests remaining"] += 1; - } - - __quest_state["Level 9"] = state; - __quest_state["Highland Lord"] = state; -} - -void QLevel9GenerateTasksSidequests(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Level 9"]; - - if (base_quest_state.state_int["a-boo peak hauntedness"] > 0) - { - boolean should_delay = false; - string [int] details; - string [int] modifiers; - int clues_needed = ceil(MIN(base_quest_state.state_int["a-boo peak hauntedness"], 90).to_float() / 30.0); - - if (true) - { - int clues_remaining = MAX(0, clues_needed - $item[a-boo clue].available_amount()); - string [int] tasks; - if (base_quest_state.state_int["a-boo peak hauntedness"] > 90) - tasks.listAppend("get down to 90% hauntedness"); - if (clues_remaining > 0) - tasks.listAppend("collect " + clues_remaining.int_to_wordy() + " a-boo clues"); - tasks.listAppend("use/survive each clue to finish quest.|May want to consider delaying until end of the run"); - details.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - } - - modifiers.listAppend("+567% item"); - details.listAppend(base_quest_state.state_int["a-boo peak hauntedness"] + "% hauntedness."); - - float item_drop_multiplier = (100.0 + $location[a-boo peak].item_drop_modifier_for_location())/100.0; - - if (true) - { - string line = "Have " + pluralise(lookupItems("a-boo clue,glued a-boo clue").available_amount(), $item[a-boo clue]) + "."; - - float clue_drop_rate = clampf(item_drop_multiplier * 0.15, 0.0, 1.0); - line += " " + clue_drop_rate.roundForOutput(2) + " clues/adventure at +" + ((item_drop_multiplier - 1) * 100.0).roundForOutput(1) + "% item."; - - details.listAppend(line); - } - - - if (base_quest_state.state_int["a-boo peak hauntedness"] <= 90 && __misc_state["can use clovers"] && $item[a-boo clue].available_amount() < clues_needed) - { - details.listAppend("Can clover for two A-Boo clues."); - } - - - - - int spooky_damage_taken_cumulative = 0; - int cold_damage_taken_cumulative = 0; - - int [int] spooky_damage_levels; - int [int] cold_damage_levels; - - int [int] damage_levels = listMake(13, 25, 50, 125, 250); - - foreach key in damage_levels - { - int damage = damage_levels[key]; - if ($item[glass pie plate].equipped_amount() > 0) - damage /= 2; - - int spooky_damage_at_level = damageTakenByElement(damage, $element[spooky]); - int cold_damage_at_level = damageTakenByElement(damage, $element[cold]); - - spooky_damage_taken_cumulative += spooky_damage_at_level; - cold_damage_taken_cumulative += cold_damage_at_level; - - spooky_damage_levels.listAppend(spooky_damage_taken_cumulative); - cold_damage_levels.listAppend(cold_damage_taken_cumulative); - } - - boolean can_survive_clues_now = false; - if (true) - { - string line; - - int hp_damage_taken = spooky_damage_levels[4] + cold_damage_levels[4] + 2; - string hp_string = hp_damage_taken + " HP"; - if (hp_damage_taken >= my_hp()) - hp_string = HTMLGenerateSpanFont(hp_string, "red"); - - if (hp_damage_taken <= my_maxhp()) - can_survive_clues_now = true; - line = "Need " + hp_string + " (" + HTMLGenerateSpanOfClass(spooky_damage_levels[4] + " spooky", "r_element_spooky") + ", " + HTMLGenerateSpanOfClass(cold_damage_levels[4] + " cold", "r_element_cold") + ") to survive 30% effective A-Boo clues."; - if (hp_damage_taken >= my_hp()) - { - hp_damage_taken = spooky_damage_levels[3] + cold_damage_levels[3] + 2; - string hp_string = hp_damage_taken + " HP"; - if (hp_damage_taken >= my_hp()) - hp_string = HTMLGenerateSpanFont(hp_string, "red"); - - line += "|Or "; - line += hp_string; - line += " to survive 22% effectiveness clues."; - } - if ($item[glass pie plate].available_amount() > 0 && $item[glass pie plate].can_equip() && $item[glass pie plate].equipped_amount() == 0) - line += "|Equip the glass pie plate for half damage."; - - details.listAppend(line); - } - - if (!black_market_available() && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST && my_path().id != PATH_NUCLEAR_AUTUMN) - { - details.listAppend("Possibly unlock the black market first, for cans of black paint. (+2 " + HTMLGenerateSpanOfClass("spooky", "r_element_spooky") + "/" + HTMLGenerateSpanOfClass("cold", "r_element_cold") + " res buff, 1k meat)"); - } - if ($item[a-boo clue].available_amount() * 30 >= base_quest_state.state_int["a-boo peak hauntedness"] && my_level() < 13) //wait for later - should_delay = true; - if (can_survive_clues_now) - should_delay = false; - - ChecklistEntry checklist_entry = ChecklistEntryMake("a-boo peak", "place.php?whichplace=highlands", ChecklistSubentryMake("A-Boo Peak", modifiers, details), $locations[a-boo peak]); - checklist_entry.tags.id = "Council L9 quest a-boo peak progress"; - if (should_delay) - { - checklist_entry.importance_level = 11; - future_task_entries.listAppend(checklist_entry); - } - else - task_entries.listAppend(checklist_entry); - } - else if (!$location[a-boo peak].noncombat_queue.contains_text("Come On Ghosty, Light My Pyre")) - { - string [int] details; - string [int] modifiers; - - details.listAppend("Light the fire!"); - - ChecklistEntry checklist_entry = ChecklistEntryMake("a-boo peak", "place.php?whichplace=highlands", ChecklistSubentryMake("A-Boo Peak", modifiers, details), $locations[a-boo peak]); - checklist_entry.tags.id = "Council L9 quest a-boo peak done"; - task_entries.listAppend(checklist_entry); - } - if (base_quest_state.state_int["twin peak progress"] < 15) - { - string [int] details; - string [int] modifiers; - string url = "place.php?whichplace=highlands"; - - if (base_quest_state.state_boolean["can complete twin peaks quest quickly"]) - { - int progress = base_quest_state.state_int["twin peak progress"]; - - boolean stench_completed = base_quest_state.state_boolean["Peak Stench Completed"]; - boolean item_completed = base_quest_state.state_boolean["Peak Item Completed"]; - boolean jar_completed = base_quest_state.state_boolean["Peak Jar Completed"]; - boolean init_completed = base_quest_state.state_boolean["Peak Init Completed"]; - - boolean can_complete_stench = false; - boolean can_complete_item = false; - boolean can_complete_jar = false; - boolean can_complete_init = false; - - boolean have_at_least_one_usable_option = false; - - - if (!stench_completed && numeric_modifier("stench resistance") >= 4.0) - can_complete_stench = true; - if (!item_completed) - { - int effective_familiar_weight = my_familiar().familiar_weight() + numeric_modifier("familiar weight"); - - int familiar_weight_from_familiar_equipment = $slot[familiar].equipped_item().numeric_modifier("familiar weight"); //need to cancel it out - - float familiar_item_drop = my_familiar().numeric_modifier("item drop", effective_familiar_weight - familiar_weight_from_familiar_equipment, $slot[familiar].equipped_item()); - //FIXME implement item_drop_modifier_for_location (friars does not count for this test, so maybe item_drop_modifier_ignoring_plants()) - float effective_non_familiar_item = $location[twin peak].item_drop_modifier_for_location() - familiar_item_drop + numeric_modifier("food drop"); - if (effective_non_familiar_item >= 50.0) - can_complete_item = true; - } - if (!jar_completed && $item[jar of oil].available_amount() > 0) - can_complete_jar = true; - if (!init_completed && (stench_completed && item_completed && jar_completed) && initiative_modifier() >= 40) - can_complete_init = true; - - if (can_complete_stench || can_complete_item || can_complete_jar || can_complete_init) - have_at_least_one_usable_option = true; - - if (!have_at_least_one_usable_option) - details.listAppend(HTMLGenerateSpanFont("Avoid adventuring in area until requirements met.", "red")); - - string [int] options_left; - - if (!stench_completed) - { - string line = "investigate room 37"; - if (options_left.count() == 0) - line = line.capitaliseFirstLetter(); //have to pre-capitalise because of possible HTML later - if (!can_complete_stench) - line = HTMLGenerateSpanFont(line, "gray"); - options_left.listAppend(line); - } - if (!item_completed) - { - string line = "search the pantry"; - if (options_left.count() == 0) - line = line.capitaliseFirstLetter(); - if (!can_complete_item) - line = HTMLGenerateSpanFont(line, "gray"); - options_left.listAppend(line); - } - if (!jar_completed) - { - string line = "follow the faint sound of music"; - if (options_left.count() == 0) - line = line.capitaliseFirstLetter(); - if (!can_complete_jar) - line = HTMLGenerateSpanFont(line, "gray"); - options_left.listAppend(line); - } - if (!init_completed) - { - string line = "you"; - if (options_left.count() == 0) - line = line.capitaliseFirstLetter(); - if (!can_complete_init) - line = HTMLGenerateSpanFont(line, "gray"); - options_left.listAppend(line); - } - - details.listAppend(options_left.listJoinComponents(", ", "and") + "."); - - boolean can_complete_using_trimmers = false; - if ($item[rusty hedge trimmers].available_amount() >= options_left.count()) //purely trimmers, now - { - can_complete_using_trimmers = true; - if (have_at_least_one_usable_option) - url = "inventory.php?ftext=rusty+hedge+trimmers"; - } - if (numeric_modifier("stench resistance") < 4.0 && !stench_completed) - { - details.listAppend("+" + (4.0 - numeric_modifier("stench resistance")).floor() + " more " + HTMLGenerateSpanOfClass("stench", "r_element_stench") + " resist required."); - } - if (!can_complete_using_trimmers) - { - modifiers.listAppend("-combat"); - modifiers.listAppend("+item"); - modifiers.listAppend("olfact a topiary animal"); - } - - if (!item_completed && !can_complete_item) - { - details.listAppend("+50% non-familiar item required. (+food works)"); - } - - if ($item[jar of oil].available_amount() == 0 && !jar_completed) - { - string line = HTMLGenerateSpanFont("Jar of oil required", "red") + "."; - if ($item[bubblin\' crude].available_amount() >= 12) - line += " Can make by multi-using 12 bubblin' crude."; - else - line += " Visit oil peak for bubblin' crude."; - details.listAppend(line); - } - if (initiative_modifier() < 40.0 && !init_completed) - { - string line = "+40% init required."; - if (options_left.count() > 1) - line = "+40% init will be required later."; - if ($familiar[oily woim].familiar_is_usable() && !($familiars[oily woim,happy medium] contains my_familiar())) - { - if (!(my_familiar() == $familiar[Xiblaxian Holo-Companion] && my_familiar() != $familiar[none])) - line += "|Run " + $familiar[oily woim] + " for +init."; - } - details.listAppend(line); - } - - if ($item[rusty hedge trimmers].available_amount() > 0) - { - if (!have_at_least_one_usable_option) - details.listAppend("Have " + pluraliseWordy(MIN(options_left.count(), $item[rusty hedge trimmers].available_amount()), $item[rusty hedge trimmers]) + "."); - else if ($item[rusty hedge trimmers].available_amount() > 1) - details.listAppend("Use " + pluraliseWordy(MIN(options_left.count(), $item[rusty hedge trimmers].available_amount()), $item[rusty hedge trimmers]) + "."); - else - details.listAppend("Use rusty hedge trimmers."); - } - - int ncs_need_to_visit_by_hand = MAX(0, options_left.count() - $item[rusty hedge trimmers].available_amount()); - int ncs_need_to_visit_with_hedge = options_left.count() - ncs_need_to_visit_by_hand; - if (have_at_least_one_usable_option && !can_complete_using_trimmers) - details.listAppend(generateTurnsToSeeNoncombat(80, ncs_need_to_visit_by_hand, "", 0, ncs_need_to_visit_with_hedge)); - - - } - else - { - details.listAppend("Spend 50 total turns in the twin peak."); - } - task_entries.listAppend(ChecklistEntryMake("twin peak", url, ChecklistSubentryMake("Twin Peak", modifiers, details), $locations[twin peak]).ChecklistEntrySetIDTag("Council L9 quest twin peak")); - } - boolean need_jar_of_oil = false; - if ($item[jar of oil].available_amount() == 0 && $item[bubblin\' crude].available_amount() < 12 && !base_quest_state.state_boolean["Peak Jar Completed"] && base_quest_state.state_boolean["can complete twin peaks quest quickly"]) - need_jar_of_oil = true; - - if (base_quest_state.state_float["oil peak pressure"] > 0.0 || need_jar_of_oil) - { - string [int] details; - string [int] modifiers; - - int oil_ml = monster_level_adjustment_for_location($location[oil peak]); - - if (my_path().id == PATH_HEAVY_RAINS) - { - //heavy rains ML doesn't affect which oil monster you get; cancel out the rain effect: - //int inherent_ml_reduction = monster_level_adjustment() - numeric_modifier("Monster Level"); - //oil_ml -= inherent_ml_reduction; - //FIXME this is complicated - } - - int turns_remaining_at_current_ml = 0; - if (base_quest_state.state_float["oil peak pressure"] > 0.0) - { - modifiers.listAppend("+100 ML"); - - - string line = "Run +" + HTMLGenerateSpanFont("20/50", "", "0.8em") + "/100 ML (at "; - string adjustment = (oil_ml > 0 ? "+" : "") + oil_ml + " ML"; - if (oil_ml < 100) - adjustment = HTMLGenerateSpanFont(adjustment, "red"); - adjustment += ")"; - details.listAppend(line + adjustment); - - - float pressure_reduced_per_turn = 0.0; - if ($item[dress pants].available_amount() > 0) - { - if ($item[dress pants].equipped_amount() > 0) - { - pressure_reduced_per_turn += 6.34; - } - else - { - if (oil_ml < 100) //only worth it <100 usually - details.listAppend("Wear dress pants."); - } - } - if (oil_ml >= 100) - pressure_reduced_per_turn += 63.4; - else if (oil_ml >= 50) - pressure_reduced_per_turn += 31.7; - else if (oil_ml >= 20) - pressure_reduced_per_turn += 19.02; - else - pressure_reduced_per_turn += 6.34; - - if (fabs(pressure_reduced_per_turn) > 0.01) - turns_remaining_at_current_ml = ceil(base_quest_state.state_float["oil peak pressure"] / pressure_reduced_per_turn); - - string line2 = pluralise(turns_remaining_at_current_ml, "turn", "turns") + " remaining at " + oil_ml + " ML."; - if (base_quest_state.state_boolean["oil peak pressure bug in effect"]) - line2 = "At most " + line2 + " (unable to track, sorry)"; - details.listAppend(line2); - - if (oil_ml < 50 && $item[dress pants].available_amount() == 0 && !in_hardcore()) - details.listAppend("If you can't reach +50 ML or more, possibly consider pulling and wearing dress pants. (lazy pull, doesn't add ML but saves 4 or 24 turns)"); - } - if (need_jar_of_oil) - { - modifiers.listAppend("+item"); - string item_drop_string = ""; - int [int] drop_rates; - if (oil_ml >= 100) - { - //last is possibly 10%, needs more spading - item_drop_string = "100%/30%/10% drops"; - drop_rates = listMake(100, 30, 10); - } - else if (oil_ml >= 50) - { - item_drop_string = "100%/30% drops"; - drop_rates = listMake(100, 30); - } - else if (oil_ml >= 20) - { - item_drop_string = "100%/10% drops"; - drop_rates = listMake(100, 10); - } - else - { - item_drop_string = "100% drop"; - drop_rates = listMake(100); - } - - float crudes_per_adventure = 0.0; - float item_drop_rate_multiplier = (100.0 + $location[oil peak].item_drop_modifier_for_location()) / 100.0; - foreach key in drop_rates - { - int rate = drop_rates[key]; - float effective_rate = MIN(1.0, rate.to_float() / 100.0 * item_drop_rate_multiplier); - crudes_per_adventure += effective_rate; - } - string crude_string = "~" + crudes_per_adventure.roundForOutput(1) + " crude/adventure."; - if (turns_remaining_at_current_ml > 0) - crude_string += " ~" + (crudes_per_adventure * turns_remaining_at_current_ml.to_float()).roundForOutput(1) + " crudes before fire lit."; - - - if ($item[bubblin' crude].available_amount() < 12) - { - details.listAppend("Run +item to acquire " + pluralise(MAX(0, 12 - $item[bubblin' crude].available_amount()), "more bubblin' crude", "more bubblin' crudes") + ". (" + item_drop_string + ")|" + crude_string); - if ($item[duskwalker syringe].available_amount() > 0) - details.listAppend("Use " + $item[duskwalker syringe].pluralise() + " in-combat for more crude."); - } - } - - task_entries.listAppend(ChecklistEntryMake("oil peak", "place.php?whichplace=highlands", ChecklistSubentryMake("Oil Peak", modifiers, details), $locations[oil peak]).ChecklistEntrySetIDTag("Council L9 quest oil peak progress")); - } - else if (!$location[oil peak].noncombat_queue.contains_text("Unimpressed with Pressure")) - { - string [int] details; - string [int] modifiers; - - details.listAppend("Light the fire!"); - - task_entries.listAppend(ChecklistEntryMake("oil peak", "place.php?whichplace=highlands", ChecklistSubentryMake("Oil Peak", modifiers, details), $locations[oil peak]).ChecklistEntrySetIDTag("Council L9 quest oil peak done")); - } -} - -void QLevel9GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Level 9"].in_progress) - return; - QuestState base_quest_state = __quest_state["Level 9"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - - string url = "place.php?whichplace=highlands"; - int tasks_before = task_entries.count() + optional_task_entries.count() + future_task_entries.count(); - - if (base_quest_state.mafia_internal_step == 1) - { - url = "place.php?whichplace=orc_chasm"; - //build bridge: - - //if (__misc_state["have olfaction equivalent"]) //don't remember what you'd olfact here - //subentry.modifiers.listAppend("olfaction"); - subentry.entries.listAppend("Build a bridge."); - - string smut_orc_noncombat_progress_string = get_property("smutOrcNoncombatProgress"); - boolean orc_tracking_supported = false; - if (smut_orc_noncombat_progress_string != "") - { - orc_tracking_supported = true; - } - float weapon_damage_actual = numeric_modifier("Weapon Damage"); - //correct numeric_modifier's response to actual: - foreach s in $slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3,familiar] - { - item it = s.equipped_item(); - if (it == $item[none]) continue; - if (it.to_slot() != $slot[weapon]) continue; - weapon_damage_actual -= it.get_power().to_float() * 0.15; - } - - int choice_1_pieces_gained = MAX(3, MIN(14, sqrt((my_buffedstat($stat[muscle]) + weapon_damage_actual) / 15.0 * (numeric_modifier("Weapon Damage Percent") / 100.0 + 1.0)))); - int choice_2_pieces_gained = MAX(3, MIN(14, sqrt((my_buffedstat($stat[mysticality]) + numeric_modifier("Spell Damage")) / 15.0 * (numeric_modifier("Spell Damage Percent") / 100.0 + 1.0)))); - int choice_3_pieces_gained = MAX(3, MIN(14, sqrt((my_buffedstat($stat[moxie]) / 30.0 * (numeric_modifier("Sleaze Resistance") * 0.69 + 1.0))))); - - if (orc_tracking_supported) - { - int smut_orc_noncombat_progress = smut_orc_noncombat_progress_string.to_int_silent(); - if (smut_orc_noncombat_progress < 15) - { - subentry.modifiers.listAppend("+item"); - subentry.modifiers.listAppend("-ML"); - int percent_to_nc = smut_orc_noncombat_progress.to_float() / 15.0 * 100; - subentry.entries.listAppend("Run as little monster level as possible.|Overkill the orcs with as much " + HTMLGenerateSpanOfClass("cold damage", "r_element_cold") + " as you can.|" + percent_to_nc + "% to NC."); - } - else - { - int best_choice_pieces = choice_1_pieces_gained; - string best_choice = "the first choice"; - if (choice_2_pieces_gained > best_choice_pieces) - { - best_choice = "the second choice"; - best_choice_pieces = choice_2_pieces_gained; - } - if (choice_3_pieces_gained > best_choice_pieces) - { - best_choice = "the third choice"; - best_choice_pieces = choice_3_pieces_gained; - } - - subentry.entries.listAppend("Next encounter will be the non-combat.|Choose " + best_choice + ". (" + best_choice_pieces + " pieces gained)"); - string line; - line += "Your buffing options are:"; - line += "|*Buff +muscle/weapon damage percent/weapon damage for the first NC option. (at " + choice_1_pieces_gained + " pieces)"; - line += "|*Or +myst/spell damage percent/spell damage for the second NC option. (at " + choice_2_pieces_gained + " pieces)"; - line += "|*Or +moxie/sleaze resistance and choose the third option at the NC. (at " + choice_3_pieces_gained + " pieces)"; - subentry.entries.listAppend(line); - } - } - else - { - subentry.modifiers.listAppend("+item"); - subentry.modifiers.listAppend("-ML"); - subentry.modifiers.listAppend("+moxie"); - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+sleaze resistance", "r_element_sleaze_desaturated")); - //FIXME show how effective you are at the moment. - subentry.entries.listAppend("Run as little monster level as possible.|Overkill the orcs with as much cold damage as you can."); - subentry.entries.listAppend("Then:"); - subentry.entries.listAppend("|*Buff +muscle/weapon damage/weapon damage percent for the first NC option."); - subentry.entries.listAppend("|*Or +myst/spell damage/spell damage percent for the second NC option."); - subentry.entries.listAppend("|*Or +moxie/sleaze resistance and choose the third option at the NC."); - } - - /*if (get_property("questM15Lol") != "finished" && ($item[bridge].available_amount() > 0 || $item[dictionary].available_amount() == 0) && false) //it's gone! - { - if ($item[bridge].available_amount() > 0) - subentry.entries.listAppend("Place the bridge."); - else if ($item[abridged dictionary].available_amount() > 0) - subentry.entries.listAppend("Untinker the abridged dictionary."); - else - subentry.entries.listAppend("Acquire an abridged dictionary from the pirates, untinker it."); - }*/ - - int fasteners_needed = base_quest_state.state_int["bridge fasteners needed"]; - int lumber_needed = base_quest_state.state_int["bridge lumber needed"]; - - if (__misc_state["can equip just about any weapon"]) - { - if (lumber_needed > 0) - { - if ($item[logging hatchet].available_amount() > 0 && $item[logging hatchet].equipped_amount() == 0) - subentry.entries.listAppend("Possibly equip that logging hatchet."); - else if ($item[logging hatchet].available_amount() == 0 && canadia_available()) - subentry.entries.listAppend("Possibly acquire a logging hatchet. (first adventure in Camp Logging Camp in Little Canadia)"); - } - - if (fasteners_needed > 0) - { - if ($item[loadstone].available_amount() > 0 && $item[loadstone].equipped_amount() == 0) - subentry.entries.listAppend("Possibly equip that loadstone."); - else if ($item[loadstone].available_amount() == 0 && !__quest_state["Level 8"].state_boolean["Past mine"]) - subentry.entries.listAppend("Possibly find a loadstone in the mine."); - } - } - - if (($item[snow berries].available_amount() > 0 || $item[ice harvest].available_amount() > 0) && $item[snow boards].available_amount() < 4) - subentry.entries.listAppend("Possibly make snow boards."); - if (__misc_state["can use clovers"]) - subentry.entries.listAppend("Possibly clover for 3 lumber and 3 fasteners."); - - - string [int] line; - if (fasteners_needed > 0) - line.listAppend(fasteners_needed + " fasteners"); - if (lumber_needed > 0) - line.listAppend(lumber_needed + " lumber"); - - if (lumber_needed + fasteners_needed == 0) - { - //finished - subentry.modifiers.listClear(); - subentry.entries.listClear(); - subentry.entries.listAppend("Build a bridge!"); - } - if ($item[smut orc keepsake box].available_amount() > 0) - subentry.entries.listAppend("Open " + pluralise($item[smut orc keepsake box]) + "."); - if (line.count() > 0) { - subentry.entries.listAppend("Need " + line.listJoinComponents(" ", "and") + "."); - - if (__quest_state["Level 11 Shen"].state_int.getFutureShenAssignments().listInvert() contains $location[The Smut Orc Logging Camp]) - subentry.entries.listAppend("Could wait before going there? Shen will send you here later."); - } - } - /*else if (base_quest_state.mafia_internal_step == 2) - { - //bridge built, talk to angus: - subentry.entries.listAppend("Talk to Angus in the Highland Lord's tower."); - }*/ - else if (base_quest_state.mafia_internal_step == 2 || base_quest_state.mafia_internal_step == 3) - { - //do three peaks: - //subentry.entries.listAppend("Light the fires!"); - if ($location[oil peak].noncombat_queue.contains_text("Unimpressed with Pressure") && $location[a-boo peak].noncombat_queue.contains_text("Come On Ghosty, Light My Pyre") && base_quest_state.state_int["twin peak progress"] == 15) - subentry.entries.listAppend("Talk to Lord Angus to finish the quest."); - else - subentry.entries.listAppend("Light the fires!"); - QLevel9GenerateTasksSidequests(task_entries, optional_task_entries, future_task_entries); - } - else if (base_quest_state.mafia_internal_step == 4) - { - //fires lit, talk to angus again: - subentry.entries.listAppend("Talk to Angus in the Highland Lord's tower."); - } - int tasks_after = task_entries.count() + optional_task_entries.count() + future_task_entries.count(); - if (tasks_before == tasks_after) //if our sidequests didn't add anything, show something: - task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the smut orc logging camp,a-boo peak,oil peak,twin peak]).ChecklistEntrySetIDTag("Council L9 quest highlands")); -} diff --git a/Source/relay/TourGuide/Quests/Madness Bakery.ash b/Source/relay/TourGuide/Quests/Madness Bakery.ash deleted file mode 100644 index 23b263fb..00000000 --- a/Source/relay/TourGuide/Quests/Madness Bakery.ash +++ /dev/null @@ -1,44 +0,0 @@ -//questM25Armorer -void QMadnessBakeryInit() -{ - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questM25Armorer"); - - state.quest_name = "Lending a Hand (and a Foot)"; - state.image_name = "__item unlit birthday cake"; - - - __quest_state["Madness Bakery"] = state; -} - - -void QMadnessBakeryGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Madness Bakery"]; - if (!base_quest_state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - string url = "place.php?whichplace=town_right"; - - if ($item[no-handed pie].available_amount() > 0 || base_quest_state.mafia_internal_step >= 5) - { - subentry.entries.listAppend("Talk to the leggerer."); - url = "place.php?whichplace=town_market"; - } - else - { - //step1 seems to exist, but no information on office visits left - //step2 - cake lord - //step3 - in the progress of talking to madeline - //step4 - acquire cake - //step5 - melon lord? - subentry.entries.listAppend("Adventure in the Madness Bakery|Choose the first option in the non-combat repeatedly."); - } - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[Madness Bakery]).ChecklistEntrySetIDTag("Armory madness bakery quest")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Manor.ash b/Source/relay/TourGuide/Quests/Manor.ash deleted file mode 100644 index 5a40b209..00000000 --- a/Source/relay/TourGuide/Quests/Manor.ash +++ /dev/null @@ -1,551 +0,0 @@ - -void QManorInit() -{ - QuestState state; - - - state.state_boolean["need ballroom song set"] = false; - - if (my_path().id == PATH_GELATINOUS_NOOB || in_bad_moon()) - state.state_boolean["need ballroom song set"] = true; - - //Trace every quest where it's worth setting the song: - //Let's see... - //L2: relevant - //L3: relevant...? (skipping NCs) - //L5: theoretically relevant (acquiring the KGE outfit without semi-rare) - //L6: relevant - //L7: relevant (two areas) - //L8: relevant (climbing the mountain, acquiring mining outfit) - //L9: relevant (twin peak) - //L10: relevant (everywhere) - //HitS: relevant (unlock) - //L11: relevant (black forest, ballroom, pirates, hidden park, temple unlock, city unlock without semi-rare) - //L12: relevant (starting the war) - //L13: relevant, but marginal (south of the border, zap wand) - //Pirates: relevant (acquiring outfit) - if (__misc_state["can reasonably reach -25% combat"]) - state.state_boolean["need ballroom song set"] = false; - if (my_turncount() >= 200) - state.state_boolean["need ballroom song set"] = false; - - - if (__misc_state_string["ballroom song"] == "-combat") - state.state_boolean["need ballroom song set"] = false; - - if ($location[the haunted ballroom].delayRemainingInLocation() == 0) //probably not worth it anymore - state.state_boolean["need ballroom song set"] = false; - - if ($location[the haunted ballroom].delayRemainingInLocation() > 0) - state.state_boolean["ballroom needs delay burned"] = true; - - state.state_boolean["ballroom song effectively set"] = !state.state_boolean["need ballroom song set"]; - if (combat_rate_modifier() <= -25.0) - state.state_boolean["ballroom song effectively set"] = true; - if (__quest_state["Level 13"].in_progress || (__quest_state["Level 13"].finished && my_path().id != PATH_BUGBEAR_INVASION) || questPropertyPastInternalStepNumber("questL13Final", 1)) - state.state_boolean["ballroom song effectively set"] = true; - - if (state.state_boolean["ballroom song effectively set"]) - state.state_boolean["need ballroom song set"] = false; - - - - if (locationAvailable($location[the haunted ballroom]) && !(state.state_boolean["need ballroom song set"] || state.state_boolean["ballroom needs delay burned"])) - QuestStateParseMafiaQuestPropertyValue(state, "finished"); - else - { - QuestStateParseMafiaQuestPropertyValue(state, "started"); - } - if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - if (my_path().id == PATH_SEA) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - state.quest_name = "Spookyraven Manor Unlock"; - state.image_name = "Spookyraven Manor"; - - - /*location zone_to_work_on = $location[none]; - if (!locationAvailable($location[the haunted billiards room])) - { - zone_to_work_on = $location[the haunted billiards room]; - } - else if (!locationAvailable($location[the haunted library])) - { - zone_to_work_on = $location[the haunted library]; - } - else if (!locationAvailable($location[the haunted bedroom])) - { - zone_to_work_on = $location[the haunted bedroom]; - } - else if (!locationAvailable($location[the haunted ballroom])) - { - zone_to_work_on = $location[the haunted ballroom]; - } - state.state_string["zone to work on"] = zone_to_work_on;*/ - - __quest_state["Manor Unlock"] = state; -} - - -void QManorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__quest_state["Manor Unlock"].in_progress && __misc_state["in run"]) - return; - if (my_level() < 5 && my_ascensions() == 0 && !QuestState("questM21Dance").in_progress) return; //not yet possible - - boolean should_output_optionally = false; - boolean should_output_futurally = false; - QuestState base_quest_state = __quest_state["Manor Unlock"]; - - boolean [location] relevant_locations = $locations[the haunted kitchen, the haunted library, the haunted billiards room, the haunted bedroom, the haunted ballroom, the haunted gallery, the haunted bathroom]; - //$locations[the haunted kitchen, the haunted library, the haunted billiards room, the haunted bedroom, the haunted ballroom]; - - - if (!__misc_state["in run"] && !(relevant_locations contains __last_adventure_location)) - return; - ChecklistSubentry subentry; - //subentry.header = "Unlock Spookyraven Manor"; - - //This is currently very incomplete, sorry. - - string url = ""; - - string image_name; - - boolean ballroom_probably_open = false; - if ($location[the haunted ballroom].turnsAttemptedInLocation() > 0) - ballroom_probably_open = true; - if (__misc_state_string["ballroom song"] != "") //FALSE if they haven't ascended since the revamp, I guess - ballroom_probably_open = true; - if (get_property("questM21Dance") == "finished") - ballroom_probably_open = true; - - boolean second_floor_probably_open = false; - - //if (to_item("7301").available_amount() == 0 || to_item("7302").available_amount() == 0) //first floor can be skipped via faxing - //second_floor_probably_open = false; - if (get_property_ascension("lastSecondFloorUnlock")) //updates properly now - second_floor_probably_open = true; - if (get_property("questM20Necklace") == "finished") //mafia will erroneously set questM20Necklace to finished in certain (unknown) cases. could be an error in QuestDatabase.java's reset(), but I am uncertain what caused the bug locally (it also set lastSecondFloorUnlock to current, though it is not unlocked) note - still in effect. additional information: south of the border? - second_floor_probably_open = true; - - if ($item[Lady Spookyraven's necklace].available_amount() > 0) //mostly - second_floor_probably_open = true; - if ($item[telegram from Lady Spookyraven].available_amount() > 0) - second_floor_probably_open = false; - - if (second_floor_probably_open && __misc_state["in run"]) - { - if ($item[Lady Spookyraven's necklace].available_amount() > 0 && get_property("questM20Necklace") != "finished") - { - subentry.header = "Speak to Lady Spookyraven"; - url = $location[the haunted kitchen].getClickableURLForLocation(); - image_name = "Lady Spookyraven"; - subentry.entries.listAppend("Give her her necklace."); - } - else - { - QuestState dance_quest_state; - QuestStateParseMafiaQuestProperty(dance_quest_state, "questM21Dance"); - if (!dance_quest_state.finished && !($location[the haunted ballroom].noncombat_queue.contains_text("Having a Ball in the Ballroom"))) - { - ChecklistSubentry [int] subentries; - //Haunted gallery, bathroom, bedroom - url = $location[the haunted gallery].getClickableURLForLocation(); - - - if (dance_quest_state.mafia_internal_step <= 1) - { - subentries.listAppend(ChecklistSubentryMake("Speak to Lady Spookyraven", "", "To open the haunted gallery, bathroom, and bedroom.")); - image_name = "Lady Spookyraven"; - } - else - { - if ($item[Lady Spookyraven's dancing shoes].available_amount() == 0 && dance_quest_state.mafia_internal_step < 4) - { - //NC (louvre or leave it) in gallery - string [int] modifiers; - string [int] description; - - description.listAppend("Find Lady Spookyraven's dancing shoes in the Louvre non-combat."); - - subentries.listAppend(ChecklistSubentryMake("Search in the Haunted Gallery", modifiers, description)); - if (image_name.length() == 0) - image_name = "__item antique painting of a landscape"; - - boolean garden_banished = CounterLookup("Garden Banished").CounterExists(); - - boolean need_minus_combat = false; - - if (delayRemainingInLocation($location[the haunted gallery]) > 0) - { - string line = "Delay for " + pluralise(delayRemainingInLocation($location[the haunted gallery]), "turn", "turns") + "."; - if (__misc_state["have hipster"]) - { - modifiers.listAppend(__misc_state_string["hipster name"]+"?"); - } - if (!garden_banished) - { - line += " Try to find the garden NC to banish it."; - need_minus_combat = true; - } - description.listAppend(line); - } - else - need_minus_combat = true; - - if (need_minus_combat) - modifiers.listAppend("-combat"); - - modifiers.listAppend("+meat"); - } - if ($item[Lady Spookyraven's powder puff].available_amount() == 0 && dance_quest_state.mafia_internal_step < 4) - { - string [int] modifiers; - string [int] description; - description.listAppend("Find Lady Spookyraven's powder puff. (NC leads to cosmetics wraith)"); - //combat rate extremely approximate, needs spading - - if (delayRemainingInLocation($location[the haunted bathroom]) == 0) - description.listAppend(generateTurnsToSeeNoncombat(85, 1, "find cosmetics wraith", 10 - delayRemainingInLocation($location[the haunted bathroom]), delayRemainingInLocation($location[the haunted bathroom]))); - subentries.listAppend(ChecklistSubentryMake("Search in the Haunted Bathroom", modifiers, description)); - - if (image_name.length() == 0) - image_name = "__item bottle of Monsieur Bubble"; - if (delayRemainingInLocation($location[the haunted bathroom]) > 0) - { - string line = "Delay for " + pluralise(delayRemainingInLocation($location[the haunted bathroom]), "turn", "turns") + "."; - if (__misc_state["have hipster"]) - { - modifiers.listAppend(__misc_state_string["hipster name"]+"?"); - } - description.listAppend(line); - } - else - modifiers.listAppend("-combat"); - } - if ($item[Lady Spookyraven's finest gown].available_amount() == 0 && dance_quest_state.mafia_internal_step < 4) - { - //elegant nightstand in bedroom (banish?) - //also acquire disposable instant camera. spectacles...? - //banishing may not help much? - string [int] modifiers; - string [int] description; - - description.listAppend("Find Lady Spookyraven's finest gown in the elegant nightstand."); - - string [int] items_needed_from_ornate_drawer; - - if ($item[lord spookyraven's spectacles].available_amount() == 0 && __quest_state["Level 11 Manor"].state_boolean["Can use fast route"]) - items_needed_from_ornate_drawer.listAppend("lord spookyraven's spectacles"); - - if (__quest_state["Level 11 Palindome"].state_boolean["Need instant camera"] && 7266.to_item().available_amount() == 0) - items_needed_from_ornate_drawer.listAppend("disposable instant camera"); - - - if (items_needed_from_ornate_drawer.count() > 0) - { - description.listAppend("Banish non-ornate drawers."); - modifiers.listAppend("banish non-ornate"); - } - else - { - description.listAppend("Banish non-elegant drawers."); - modifiers.listAppend("banish non-elegant"); - } - - if (items_needed_from_ornate_drawer.count() > 0) - description.listAppend("Also acquire " + items_needed_from_ornate_drawer.listJoinComponents(", ", "and") + " from the ornate drawer."); - - - if (delayRemainingInLocation($location[the haunted bedroom]) > 0) - { - string line = "Delay for " + pluralise(delayRemainingInLocation($location[the haunted bedroom]), "turn", "turns") + "."; - if (__misc_state["have hipster"]) - { - line += " (use " + __misc_state_string["hipster name"] + ")"; - modifiers.listAppend(__misc_state_string["hipster name"]); - } - description.listAppend(line); - } - - - subentries.listAppend(ChecklistSubentryMake("Search in the Haunted Bedroom", modifiers, description)); - if (image_name.length() == 0) - image_name = "Haunted Bedroom"; - - } - if ($item[Lady Spookyraven's dancing shoes].available_amount() > 0 && $item[Lady Spookyraven's powder puff].available_amount() > 0 && $item[Lady Spookyraven's finest gown].available_amount() > 0 || dance_quest_state.mafia_internal_step == 4) - { - if (dance_quest_state.mafia_internal_step < 4) - { - subentry.header = "Speak with Lady Spookyraven"; - subentry.entries.listAppend("Dancing."); - } - else - { - subentry.header = "Dance with Lady Spookyraven"; - subentry.entries.listAppend("Adventure in the Haunted Ballroom."); - subentry.entries.listAppend("Gives stats."); - } - image_name = "Lady Spookyraven"; - } - } - //FIXME suggest acquiring instant camera and spectacles - if (subentries.count() > 0) - { - task_entries.listAppend(ChecklistEntryMake(image_name, url, subentries, relevant_locations)); - } - } - else - { - if (base_quest_state.state_boolean["ballroom needs delay burned"] && __quest_state["Level 11"].mafia_internal_step < 3) - { - ChecklistSubentry [int] subentries2; - string [int] modifiers2; - if (__misc_state["have hipster"]) - modifiers2.listAppend(__misc_state_string["hipster name"]); - if (__misc_state["free runs available"]) - modifiers2.listAppend("free runs"); - - subentries2.listAppend(ChecklistSubentryMake("Burn " + pluralise($location[the haunted ballroom].delayRemainingInLocation(), "turn", "turns") + " delay in haunted ballroom", modifiers2, "")); - ChecklistEntry entry2 = ChecklistEntryMake("__half Haunted Ballroom", $location[the haunted ballroom].getClickableURLForLocation(), subentries2, $locations[the haunted ballroom]); - entry2.tags.id = "Manor spookyraven ballroom delay"; - entry2.importance_level = 5; - optional_task_entries.listAppend(entry2); - //subentry.header = ; - } - if (base_quest_state.state_boolean["need ballroom song set"]) - { - subentry.header = "Possibly set -combat ballroom song"; - url = $location[the haunted ballroom].getClickableURLForLocation(); - image_name = "__item the Legendary Beat"; - subentry.modifiers.listAppend("-combat"); - - subentry.entries.listAppend("Adventure in the Haunted Ballroom. May not be relevant."); - if (!$location[the haunted ballroom].noncombat_queue.contains_text("Curtains")) //initiate NC rejection - subentry.entries.listAppend(HTMLGenerateSpanFont("Do not skip the curtains NC the first time", "red") + ", this will make the ballroom song more likely to appear."); - - if (my_turncount() > 200 || base_quest_state.state_boolean["ballroom song effectively set"]) - { - should_output_optionally = true; - } - subentry.entries.listAppend(generateTurnsToSeeNoncombat(90, 2, "")); //may be 90% now? is this worth setting anymore? - } - } - } - } - else if ($item[telegram from Lady Spookyraven].available_amount() > 0) - { - //telegram is removed on using it, even on old copies of mafia - subentry.header = "Read telegram from Lady Spookyraven"; - url = "inventory.php?ftext=telegram+from+Lady+Spookyraven"; - image_name = "__item telegram from Lady Spookyraven"; - } - else if (to_item("7301").available_amount() == 0) //Spookyraven billiards room key - { - if (my_path().id == PATH_COMMUNITY_SERVICE && __last_adventure_location != $location[the haunted kitchen]) - return; - if (!__misc_state["in run"] && __last_adventure_location != $location[the haunted kitchen]) return; - subentry.header = "Adventure in the Haunted Kitchen"; - url = $location[the haunted kitchen].getClickableURLForLocation(); - image_name = "__item tiny knife and fork"; - subentry.entries.listAppend("To unlock the Haunted Billiards Room."); - - /*if (get_property_monster("romanticTarget") == $monster[writing desk] && get_property_int("_romanticFightsLeft") > 0 || get_property_int("writingDesksDefeated") > 0 && __misc_state["in run"]) - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Avoid adventuring here,", "red") + " as you seem to be using the writing desk trick?|Need to fight " + pluraliseWordy(clampi(5 - get_property_int("writingDesksDefeated"), 0, 5), "more writing desk.", "more writing desks.")); - should_output_futurally = true; - }*/ - - float hot_resistance = MIN(numeric_modifier("hot resistance"), 9.0); - float stench_resistance = MIN(numeric_modifier("stench resistance"), 9.0); - - int more_hot_needed = 9 - hot_resistance.to_int(); - int more_stench_needed = 9 - stench_resistance.to_int(); - - - string [int] needed_resists; - if (more_hot_needed > 0) - needed_resists.listAppend(more_hot_needed + " more " + HTMLGenerateSpanOfClass("hot", "r_element_hot") + " resistance"); - if (more_stench_needed > 0) - needed_resists.listAppend(more_stench_needed + " more " + HTMLGenerateSpanOfClass("stench", "r_element_stench") + " resistance"); - - //subentry.entries.listAppend("Run 9 " + HTMLGenerateSpanOfClass("hot", "r_element_hot") + " resistance and " + HTMLGenerateSpanOfClass("stench", "r_element_stench") + " resistance to search faster."); - - float drawers_per_turn = 1.0 + MAX(hot_resistance / 6.0, 0.0) + MAX(stench_resistance / 6.0, 0.0); - - int drawers_needed = MAX(0, 21 - get_property_int("manorDrawerCount")); - - int total_turns = ceil(drawers_needed / drawers_per_turn) + 1; - - if (drawers_needed == 0.0) - subentry.entries.listAppend("Find the key next turn."); - else { - string line; - if (hot_resistance <= 0 && stench_resistance <= 0) - line = "1 drawer"; //roundForOutput returns a string, incompatible with pluralise() - else - line = drawers_per_turn.roundForOutput(1) + " drawers"; - line += " searched per turn.|"; - - if (drawers_needed > drawers_per_turn.floor()) { - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("hot res", "r_element_hot_desaturated")); - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("stench res", "r_element_stench_desaturated")); - - line += "~"; - if (needed_resists.count() > 0) { - subentry.entries.listAppend("Run " + needed_resists.listJoinComponents(", ", "and") + " to search faster."); - if (!__misc_state["familiars temporarily blocked"] && $familiar[exotic parrot].familiar_is_usable() && my_familiar() != $familiar[exotic parrot]) - subentry.entries.listAppend("Possibly bring along your exotic parrot."); - } - } - - line += total_turns + " turns remaining, " + drawers_needed + " drawers remaining."; - subentry.entries.listAppend(line); - } - - if (__misc_state["have hipster"]) - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - - if (inebriety_limit() > 10 && my_inebriety() < 10) - subentry.entries.listAppend("Try not to drink past ten, the billiards room is next."); - } - else if (to_item("7302").available_amount() == 0) //Spookyraven library key - { - //Find key: - subentry.header = "Adventure in the Haunted Billiards Room"; - url = $location[the Haunted Billiards Room].getClickableURLForLocation(); - image_name = "__item pool cue"; - subentry.entries.listAppend("To unlock the Haunted Library."); - - int estimated_pool_skill = get_property_int("poolSkill"); - - /*if ($effect[chalky hand].have_effect() > 0) - estimated_pool_skill += 3; - - if ($item[2268].equipped_amount() > 0) //staff of fats - estimated_pool_skill += 5; - if (to_item("7961").equipped_amount() > 0) - estimated_pool_skill += 5; - if ($item[pool cue].equipped_amount() > 0) - estimated_pool_skill += 3; - if ($effect[chalked weapon].have_effect() > 0) - estimated_pool_skill += 5; - if ($effect[video... games?].have_effect() > 0) - estimated_pool_skill += 5; - if ($effect[swimming with sharks].have_effect() > 0) - estimated_pool_skill += 3;*/ - estimated_pool_skill += numeric_modifier("pool skill"); - - int theoretical_hidden_pool_skill = 0; - if (my_inebriety() <= 10) - theoretical_hidden_pool_skill = my_inebriety(); - else - theoretical_hidden_pool_skill = 10 - (my_inebriety() - 10) * 2; - - estimated_pool_skill += theoretical_hidden_pool_skill; - estimated_pool_skill += clampi(floor(2.0 * sqrt(get_property("poolSharkCount").to_float())), 0, 10); - - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("Train pool skill via -combat. Need 14 up to 18(?) total pool skill.|Have ~" + estimated_pool_skill + " pool skill."); - - int missing_pool_skill = MAX(18 - estimated_pool_skill, 0); - - if (missing_pool_skill > 0) - { - if ($item[Staff of Ed, almost].available_amount() > 0) - { - subentry.entries.listAppend("Untinker the Staff of Ed, almost."); - } - else if ($item[2268].available_amount() > 0) //staff of fats - { - if ($item[2268].equipped_amount() == 0) //staff of fats - { - subentry.entries.listAppend("Equip the Staff of Fats for +pool skill."); - } - } - else - { - if ($item[pool cue].available_amount() == 0) - { - subentry.entries.listAppend("Find pool cue."); - } - else if (my_path().id == PATH_GELATINOUS_NOOB) - { - subentry.entries.listAppend("Absorb pool cue for +pool skill?"); - } - else if ($item[pool cue].equipped_amount() == 0) - { - subentry.entries.listAppend("Equip pool cue for +pool skill."); - } - } - if ($effect[chalky hand].have_effect() == 0& $item[handful of hand chalk].available_amount() > 0) - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Use handful of hand chalk", "red") + " for +pool skill and faster pool skill training."); - url = "inventory.php?ftext=handful+of+hand+chalk"; - } - } - - if (inebriety_limit() > 0) - { - int desired_drunkenness = MIN(inebriety_limit(), 10); - if (my_inebriety() < desired_drunkenness) - { - int more_drunkenness = MIN(availableDrunkenness(), MIN(missing_pool_skill, desired_drunkenness - my_inebriety())); - if (more_drunkenness > 0) - subentry.entries.listAppend("Consider drinking " + more_drunkenness + " more drunkenness."); - } - - if (missing_pool_skill > 0 && my_inebriety() > 10) - subentry.entries.listAppend(HTMLGenerateSpanFont("Consider waiting for rollover for better pool skill.", "red") + " (you're over 10 drunkenness.)"); - } - if (my_inebriety() > 0 && false) - { - //shortly after rollover during the revamp, drunkenness affected listed pool skill in the quest log - //exact values were 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 8, 6, 4, 2, 0, -2, -4, -6, -8 - - string pool_skill_string; - if (theoretical_hidden_pool_skill >= 0) - pool_skill_string = "+"; - pool_skill_string += theoretical_hidden_pool_skill; - subentry.entries.listAppend("Drunkenness effect: " + pool_skill_string + " pool skill."); - } - } - else if (!second_floor_probably_open) - { - //Library: - subentry.header = "Adventure in the Haunted Library"; - url = $location[the Haunted Billiards Room].getClickableURLForLocation(); - image_name = "__item very overdue library book"; - subentry.modifiers.listAppend("olfact writing desk"); - - int desks_remaining = clampi(5 - get_property_int("writingDesksDefeated"), 0, 5); - subentry.entries.listAppend("To unlock the second floor."); - subentry.entries.listAppend("Defeat " + pluraliseWordy(desks_remaining, "more writing desk", "more writing desks") + " to acquire a necklace."); - - boolean need_killing_jar = false; - if ($item[killing jar].available_amount() == 0 && !__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && !__quest_state["Level 11 Desert"].state_boolean["Killing Jar Given"]) - { - need_killing_jar = true; - subentry.modifiers.listAppend("+900% item"); - subentry.entries.listAppend("Try to acquire a killing jar to speed up the desert later.|10% drop from banshee librarian."); - } - if (!need_killing_jar && (!$monster[banshee librarian].is_banished() || !$monster[bookbat].is_banished())) - { - subentry.modifiers.listAppend("banish rest"); - } - - } - if (subentry.header != "") - { - if (image_name.length() == 0) - image_name = base_quest_state.image_name; - ChecklistEntry entry = ChecklistEntryMake(image_name, url, subentry, relevant_locations); - entry.tags.id = "Manor spookyraven quest"; - if (should_output_futurally) - future_task_entries.listAppend(entry); - else if (should_output_optionally) - optional_task_entries.listAppend(entry); - else - task_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Quests/Marty.ash b/Source/relay/TourGuide/Quests/Marty.ash deleted file mode 100644 index b1daeb6f..00000000 --- a/Source/relay/TourGuide/Quests/Marty.ash +++ /dev/null @@ -1,103 +0,0 @@ -void QMartyInit() -{ - //questM03Bugbear - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questM18Swamp"); - - state.quest_name = "Marty's Quest"; - state.image_name = "__item maple leaf"; - - state.startable = canadia_available(); - - __quest_state["Marty"] = state; -} - -void QMartyGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Marty"]; - if (!base_quest_state.in_progress) - return; - if (!canadia_available()) - return; - if (__misc_state["in run"] && $location[The Edge of the Swamp].turnsAttemptedInLocation() == 0) - return; - - string url = "place.php?whichplace=marais"; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - boolean minus_combat_relevant = false; - string [int] missing_fork_ncs; - if (!$location[The Dark and Spooky Swamp].locationAvailable()) - missing_fork_ncs.listAppend("left"); - else { - string [int] missing_sophie_ncs; - if (!$location[The Corpse Bog].locationAvailable()) - missing_sophie_ncs.listAppend("the bog"); - else if ($item[Phil Bunion's axe].available_amount() == 0) - subentry.entries.listAppend("Adventure in the Corpse Bog to defeat the ghost of Phil Bunion."); - - if (!$location[The Ruined Wizard Tower].locationAvailable()) - missing_sophie_ncs.listAppend("the stone tower"); - else if ($item[shrunken navigator head].available_amount() == 0 && $item[branch from the Great Tree].available_amount() == 0) { - subentry.entries.listAppend("Adventure in the Ruined Wizard Tower to find a shrunken navigator head."); - minus_combat_relevant = true; - } - - if (missing_sophie_ncs.count() > 0) { - minus_combat_relevant = true; - subentry.entries.listAppend("Adventure in the Dark and Spooky Swamp, go towards " + missing_sophie_ncs.listJoinComponents(" and ") + " in Sophie's Choice."); - } - } - - if (!$location[The Wildlife Sanctuarrrrrgh].locationAvailable()) - missing_fork_ncs.listAppend("right"); - else { - string [int] missing_bad_to_worst_ncs; - if (!$location[Swamp Beaver Territory].locationAvailable()) - missing_bad_to_worst_ncs.listAppend("the swamp beaver territory"); - else if ($item[shrunken navigator head].available_amount() > 0 && $item[branch from the Great Tree].available_amount() == 0) { - minus_combat_relevant = true; - subentry.entries.listAppend("Adventure in the Swamp Beaver Territory, follow the shrunken navigator head's directions, and defeat a conservationist hippy."); - } - - if (!$location[The Weird Swamp Village].locationAvailable()) - missing_bad_to_worst_ncs.listAppend("the village"); - else if ($item[bouquet of swamp roses].available_amount() == 0) { - subentry.entries.listAppend("Adventure in the Weird Swamp Village to defeat a swamp skunk."); - subentry.modifiers.listAppend("+item?"); - } - - if (missing_bad_to_worst_ncs.count() > 0) { - minus_combat_relevant = true; - subentry.entries.listAppend("Adventure in the Wildlife Sanctuarrrrrgh, go towards " + missing_bad_to_worst_ncs.listJoinComponents(" and ") + " in From Bad to Worst."); - } - } - - if (missing_fork_ncs.count() > 0) { - minus_combat_relevant = true; - subentry.entries.listAppend("Adventure in the edge of the swamp, go " + missing_fork_ncs.listJoinComponents(" and ") + " in Stick a Fork In It."); - } - if (minus_combat_relevant) //....? - subentry.modifiers.listAppend("-combat?"); - - if ($items[Phil Bunion's axe,bouquet of swamp roses,branch from the Great Tree].items_missing().count() == 0) - { - subentry.entries.listAppend("Go talk to Marty to finish the quest."); - url = "place.php?whichplace=canadia"; - } - - boolean [location] relevant_locations; - relevant_locations[$location[the edge of the swamp]] = true; - relevant_locations[$location[The Dark and Spooky Swamp]] = true; - relevant_locations[$location[The Corpse Bog]] = true; - relevant_locations[$location[The Ruined Wizard Tower]] = true; - relevant_locations[$location[The Wildlife Sanctuarrrrrgh]] = true; - relevant_locations[$location[Swamp Beaver Territory]] = true; - relevant_locations[$location[The Weird Swamp Village]] = true; - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, relevant_locations).ChecklistEntrySetIDTag("Marty Canadia quest")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Meatsmith.ash b/Source/relay/TourGuide/Quests/Meatsmith.ash deleted file mode 100644 index cdf6341e..00000000 --- a/Source/relay/TourGuide/Quests/Meatsmith.ash +++ /dev/null @@ -1,82 +0,0 @@ - -void QMeatsmithInit() -{ - //questM23Meatsmith - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questM23Meatsmith"); - - state.quest_name = "Helping Make Ends Meat"; - state.image_name = "__item gnawed-up dog bone"; - - state.startable = true; - - __quest_state["Meatsmith"] = state; -} - - -void QMeatsmithGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Meatsmith"]; - if (base_quest_state.finished) - return; - - if (__last_adventure_location != $location[the skeleton store] || __last_adventure_location == $location[none]) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - string active_url = "place.php?whichplace=town_market"; - - boolean done = false; - boolean have_reason_to_add = false; - - if (!base_quest_state.started) - { - have_reason_to_add = true; - subentry.entries.listAppend("Go talk to the meatsmith to start the quest."); - } - else if (base_quest_state.mafia_internal_step == 1) - { - have_reason_to_add = true; - if ($item[skeleton store office key].available_amount() == 0) - { - subentry.entries.listAppend("Check out the cash register at the NC."); - } - else - { - subentry.entries.listAppend("Head into the manager's office at the NC."); - } - } - else if (base_quest_state.mafia_internal_step == 2) - { - have_reason_to_add = true; - done = true; - subentry.entries.listAppend("Return to the meatsmith."); - active_url = "shop.php?whichshop=meatsmith"; - } - - if ($item[ring of telling skeletons what to do].item_amount() == 0) - { - if (!have_reason_to_add) - subentry.header = "The Skeleton Store"; - string line = "Could acquire a ring of telling skeletons what to do, by opening the chest at the NC"; - if ($item[skeleton key].item_amount() == 0) - line += HTMLGenerateSpanFont(" after acquiring a skeleton key", "red"); - - line += "."; - subentry.entries.listAppend(line); - have_reason_to_add = true; - } - - if (!done) - subentry.entries.listAppend("Non-combat appears every fourth adventure."); //except the first time for some reason? needs spading - - boolean [location] relevant_locations; - relevant_locations[$location[the skeleton store]] = true; - - if (have_reason_to_add) - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, relevant_locations).ChecklistEntrySetIDTag("Meatsmith skeleton store quest")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Memories.ash b/Source/relay/TourGuide/Quests/Memories.ash deleted file mode 100644 index 810d399f..00000000 --- a/Source/relay/TourGuide/Quests/Memories.ash +++ /dev/null @@ -1,106 +0,0 @@ -//Currently disabled. Complicated. - -void QMemoriesInit() -{ - if (true) - return; - if (true) - { - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questF01Primordial"); - - state.quest_name = "Primordial Fear Quest"; - state.image_name = "__item empty agua de vida bottle"; - - - __quest_state["Primordial Fear"] = state; - } - if (true) - { - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questF02Hyboria"); - - state.quest_name = "Hyboria Quest"; - state.image_name = "__item empty agua de vida bottle"; - - - __quest_state["Hyboria"] = state; - } - if (true) - { - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questF03Future"); - - state.quest_name = "Future Quest"; - state.image_name = "__item empty agua de vida bottle"; - - - __quest_state["Future"] = state; - } -} - - -void QMemoriesPrimordialFearGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Primordial Fear"]; - if (!base_quest_state.in_progress) - return; - string active_url = ""; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - //FIXME implement this - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[the primordial soup]).ChecklistEntrySetIDTag("Memories quest primordial fear")); -} - -void QMemoriesHyboriaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Hyboria"]; - if (!base_quest_state.in_progress) - return; - string active_url = ""; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - //FIXME implement this - - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[the jungles of ancient loathing]).ChecklistEntrySetIDTag("Memories quest hyboria")); -} - -void QMemoriesFutureGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Future"]; - if (!base_quest_state.in_progress) - return; - string active_url = ""; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - //FIXME implement this - - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[seaside megalopolis]).ChecklistEntrySetIDTag("Memories quest future")); -} - -void QMemoriesGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (true) - return; - if (__quest_state["Primordial Fear"].in_progress) - { - QMemoriesPrimordialFearGenerateTasks(task_entries, optional_task_entries, future_task_entries); - } - else if (__quest_state["Hyboria"].in_progress) - { - QMemoriesHyboriaGenerateTasks(task_entries, optional_task_entries, future_task_entries); - } - else if (__quest_state["Future"].in_progress) - { - QMemoriesFutureGenerateTasks(task_entries, optional_task_entries, future_task_entries); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Nemesis.ash b/Source/relay/TourGuide/Quests/Nemesis.ash deleted file mode 100644 index a8c3f153..00000000 --- a/Source/relay/TourGuide/Quests/Nemesis.ash +++ /dev/null @@ -1,868 +0,0 @@ - -//"started", "finished" observed for questG04Nemesis - -void QNemesisInit() -{ - if (!($classes[seal clubber, turtle tamer, pastamancer, sauceror, disco bandit, accordion thief] contains my_class())) - return; - //questG04Nemesis - QuestState state; - - - QuestStateParseMafiaQuestProperty(state, "questG04Nemesis"); - if (my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - - state.quest_name = "Nemesis Quest"; - state.image_name = "__half Nemesis"; - - if (my_basestat(my_primestat()) >= 12) - state.startable = true; - if (!mafiaIsPastRevision(15935) && state.mafia_internal_step > 1) - state.mafia_internal_step += 4; //hack to support old versions, probably won't work - - __quest_state["Nemesis"] = state; -} - -void QNemesisGenerateIslandTasks(ChecklistSubentry subentry) -{ - if (my_class() == $class[disco bandit]) - { - skill [int] rave_skills_needed; - if (!$skill[Break It On Down].skill_is_usable()) - rave_skills_needed.listAppend($skill[Break It On Down]); - if (!$skill[Pop and Lock It].skill_is_usable()) - rave_skills_needed.listAppend($skill[Pop and Lock It]); - if (!$skill[Run Like the Wind].skill_is_usable()) - rave_skills_needed.listAppend($skill[Run Like the Wind]); - - monster [skill] rave_skills_to_monster; - rave_skills_to_monster[$skill[Break It On Down]] = $monster[breakdancing raver]; - rave_skills_to_monster[$skill[Pop and Lock It]] = $monster[pop-and-lock raver]; - rave_skills_to_monster[$skill[run like the wind]] = $monster[running man]; - - boolean have_all_rave_skills = (rave_skills_needed.count() == 0); - if (!$skill[gothy handwave].skill_is_usable()) - { - subentry.entries.listAppend("Talk to the girl in a black dress."); - } - else if (!have_all_rave_skills) - { - //Learn dance moves. - string [int] monsters_to_fight; - foreach key in rave_skills_needed - { - skill rave_skill = rave_skills_needed[key]; - monsters_to_fight.listAppend(rave_skills_to_monster[rave_skill].to_string()); - } - subentry.entries.listAppend("Learn dance moves from the " + monsters_to_fight.listJoinComponents(", ", "and") + "."); - } - else - { - //Acquire ravosity. - if (numeric_modifier("raveosity") >= 7) - { - subentry.entries.listAppend("Talk to the guard."); - } - else - { - int extra_raveosity_from_equip = 0; - item [int] items_have_but_unequipped; - foreach it in $items[rave visor,baggy rave pants,pacifier necklace,teddybear backpack,glowstick on a string,candy necklace,rave whistle,blue glowstick,green glowstick,purple glowstick,pink glowstick,orange glowstick,yellow glowstick] - { - if (it.available_amount() > 0 && it.equipped_amount() == 0) - { - items_have_but_unequipped.listAppend(it); - extra_raveosity_from_equip += numeric_modifier(it, "raveosity").to_int(); - } - } - - int raveosity_needed = (7 - (extra_raveosity_from_equip + numeric_modifier("raveosity").to_int())); - - if (raveosity_needed > 0) - { - string line = "Rave steal to find "; - - if (raveosity_needed == 1) - line += "One More Raveosity."; - else - line += raveosity_needed.int_to_wordy() + " more raveosity."; - subentry.entries.listAppend(line); - } - - if (items_have_but_unequipped.count() > 0) - subentry.entries.listAppend("Wear " + items_have_but_unequipped.listJoinComponents(", ", "and") + "."); - } - } - } - else if (my_class() == $class[accordion thief]) - { - if ($item[hacienda key].available_amount() >= 5) - subentry.entries.listAppend("All keys found. Fight in the Hacienda."); - else - { - subentry.modifiers.listAppend("-combat"); - int keys_needed = MAX(0, 5 - $item[hacienda key].available_amount()); - subentry.entries.listAppend(pluraliseWordy(keys_needed, "key", "keys").capitaliseFirstLetter() + " to go."); - subentry.entries.listAppend("Four are from the non-combat; one is from pick-pocketing a mariachi."); - } - } - else if (my_class() == $class[pastamancer]) - { - if ($item[spaghetti cult robe].available_amount() > 0) - { - if ($item[spaghetti cult robe].equipped_amount() == 0) - subentry.entries.listAppend("Equip spaghetti cult robe, then enter the lair."); - else - subentry.entries.listAppend("Enter the lair."); - } - else if (my_thrall() == $thrall[spaghetti elemental]) - { - string [int] tasks; - if ($thrall[spaghetti elemental].level <3) - { - string line = "level your cute and adorable spaghetti elemental to 3"; - if ($item[experimental carbon fiber pasta additive].available_amount() > 0) - { - line += " (use the experimental carbon fiber pasta additive)"; - } - tasks.listAppend(line); - } - tasks.listAppend("defeat an evil spaghetti cult middle-manager"); - - subentry.entries.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - } - else if ($skill[Bind Spaghetti Elemental].skill_is_usable()) - { - subentry.entries.listAppend("Cast Bind Spaghetti Elemental."); - } - else - { - if ($item[decoded cult documents].available_amount() > 0) - { - subentry.entries.listAppend("Use decoded cult documents."); - } - else - { - if ($item[encoded cult documents].available_amount() == 0) - subentry.entries.listAppend("Acquire encoded cult documents from a protestor."); - - int missing_cult_memos = MAX(0, 5 - $item[cult memo].available_amount()); - if (missing_cult_memos > 0) - { - subentry.entries.listAppend("Acquire another " + pluralise(missing_cult_memos, $item[cult memo]) + " from middle-managers."); - } - else if ($item[encoded cult documents].available_amount() > 0) - { - subentry.entries.listAppend("Use cult memos."); - } - } - } - } - else if (my_class() == $class[turtle tamer]) - { - if ($item[Fouet de tortue-dressage].available_amount() == 0) - subentry.entries.listAppend("Talk to a guy in the bushes."); - else - { - if ($item[Fouet de tortue-dressage].equipped_amount() == 0) - subentry.entries.listAppend("Equip Fouet de tortue-dressage."); - subentry.entries.listAppend("Use Apprivoisez la tortue on french turtles a bunch, save them!|Then talk to the guy in the bushes."); - } - } - else if (my_class() == $class[sauceror]) - { - if ($item[bottle of Gü-Gone].available_amount() == 0) - subentry.entries.listAppend("Visit the boat."); - else - { - /* - lastSlimeVial3891(user, now 'intensity', default ) - lastSlimeVial3892(user, now 'moxiousness', default ) - lastSlimeVial3893(user, now 'eyesight', default ) - lastSlimeVial3894(user, now 'mentalism', default ) - lastSlimeVial3895(user, now 'muscle', default ) - lastSlimeVial3896(user, now 'slimeform', default ) - */ - if ($effect[slimeform].have_effect() > 0) - subentry.entries.listAppend("Wiggle into the lair.|Also, go visit your mom in the slimetube."); - else - { - - boolean [item] tertiary_potions = $items[vial of vermilion slime,vial of amber slime,vial of chartreuse slime,vial of teal slime,vial of purple slime,vial of indigo slime]; - - item slimeform_potion = $item[none]; - item [int] creatable_unknown_potions; - foreach potion in tertiary_potions - { - string property_value = get_property("lastSlimeVial" + potion.to_int()); - if (property_value.length() == 0) - { - if (potion.available_amount() + potion.creatable_amount() > 0) - creatable_unknown_potions.listAppend(potion); - } - else if (property_value == "slimeform") - slimeform_potion = potion; - } - if (slimeform_potion != $item[none] && slimeform_potion.creatable_amount() + slimeform_potion.available_amount() > 0) - { - subentry.entries.listAppend("Use a " + slimeform_potion + " to gain slimeform."); - //FIXME URL - } - else - { - subentry.entries.listAppend("Use the " + $item[bottle of Gü-Gone] + " on slime, make potions to get slimeform."); - if (creatable_unknown_potions.count() > 0 && slimeform_potion == $item[none]) - { - boolean need_to_make = false; - foreach key, it in creatable_unknown_potions - { - if (it.available_amount() == 0 && it.creatable_amount() > 0) - need_to_make = true; - } - - string line = "Try"; - if (need_to_make) - line += " making and"; - line += " using " + creatable_unknown_potions.listJoinComponents(", ", "or") + "."; - subentry.entries.listAppend(line); - } - } - } - } - } - else if (my_class() == $class[seal clubber]) - { - if ($item[hellseal disguise].available_amount() > 0) - { - subentry.entries.listAppend("Approach the dark cave."); - } - else if ($item[hellseal hide].available_amount() >= 6 && $item[hellseal sinew].available_amount() >= 6 && $item[hellseal brain].available_amount() >= 6) - { - subentry.entries.listAppend("Speak with Phineas."); - } - else - { - int seal_screeches = get_property_int("_sealScreeches"); - string screech_name = "screech"; - if (my_path().id == PATH_KOLHS) //KOLHS support - screech_name = "samuel powers"; - if ($item[seal tooth].available_amount() == 0) - { - subentry.entries.listAppend("Acquire a seal tooth from the hermit."); - } - else - subentry.entries.listAppend("Use a seal tooth to damage the hellseal pups until they screech, once each."); - if ($skill[lunging thrust-smack].have_skill()) - { - subentry.entries.listAppend("Use lunging thrust-smack against the mother hell seals."); - } - else - { - subentry.entries.listAppend("Buy lunging thrust-smack from your guild."); - } - subentry.entries.listAppend(pluraliseWordy(seal_screeches, "seal " + screech_name, "seal " + screech_name + "es").capitaliseFirstLetter() + "."); - - - int sinew_need = clampi(6 - $item[hellseal sinew].available_amount(), 0, 6); - int brains_have = clampi(6 - $item[hellseal brain].available_amount(), 0, 6); - int hides_have = clampi(6 - $item[hellseal hide].available_amount(), 0, 6); - - string [int] items_needed_list; - foreach it in $items[hellseal sinew,hellseal brain,hellseal hide] - { - int remaining = clampi(6 - it.available_amount(), 0, 6); - if (remaining == 0) continue; - string name_short = it.to_string().replace_string("hellseal ", ""); - string name_short_plural = it.plural.to_string().replace_string("hellseal ", ""); - items_needed_list.listAppend(pluraliseWordy(remaining, "more " + name_short, "more " + name_short_plural)); - } - if (items_needed_list.count() == 0) - { - } - else - { - subentry.entries.listAppend("Need " + items_needed_list.listJoinComponents(", ", "and") + "."); - } - - - string [int] passive_uneffect_description = PDSGenerateDescriptionToUneffectPassives(); - if (passive_uneffect_description.count() > 0) - subentry.entries.listAppend(HTMLGenerateSpanFont(passive_uneffect_description.listJoinComponents("|"), "red")); - - if (!$slot[weapon].equipped_item().weapon_is_club()) - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Equip a club" + ($effect[Iron Palms].have_effect() > 0 ? " or sword" : "") + " first.", "red")); - } - } - } -} - - -void QNemesisGenerateClownTasks(ChecklistSubentry subentry) -{ - item [class] legendary_epic_weapon_craftable_source; - legendary_epic_weapon_craftable_source[$class[seal clubber]] = $item[distilled seal blood]; - legendary_epic_weapon_craftable_source[$class[turtle tamer]] = $item[turtle chain]; - legendary_epic_weapon_craftable_source[$class[pastamancer]] = $item[high-octane olive oil]; - legendary_epic_weapon_craftable_source[$class[sauceror]] = $item[peppercorns of power]; - legendary_epic_weapon_craftable_source[$class[disco bandit]] = $item[vial of mojo]; - legendary_epic_weapon_craftable_source[$class[accordion thief]] = $item[golden reeds]; - - subentry.entries.listAppend("Search in the Fun House."); - int clownosity = numeric_modifier("Clowniness").floor(); - int clownosity_needed = MAX(100 - clownosity, 0); - - if (clownosity_needed > 0) - { - string [int] available_clown_sources; - string [int] missing_sources; - - item [slot] possible_outfit; - foreach it in $items[clown wig,clown whip,clownskin buckler,clownskin belt,clownskin harness,polka-dot bow tie,balloon sword,balloon helmet,foolscap fool's cap,bloody clown pants,clown shoes,big red clown nose] - { - int clownosity = numeric_modifier(it, "Clowniness").floor(); - string description = it + " (" + clownosity + ")"; - if (it.available_amount() + it.creatable_amount() > 0 && it.equipped_amount() == 0 && it.can_equip()) - { - available_clown_sources.listAppend(description); - if (possible_outfit[it.to_slot()].numeric_modifier("Clowniness").floor() < clownosity) - possible_outfit[it.to_slot()] = it; - } - if (it.available_amount() == 0) - missing_sources.listAppend(description); - } - - item [int] suggested_outfit; - int clownosity_possible = 0; - foreach key in possible_outfit - { - clownosity_possible += possible_outfit[key].numeric_modifier("Clowniness").floor(); - suggested_outfit.listAppend(possible_outfit[key]); - if (clownosity_possible >= clownosity_needed) - break; - } - //Remove extraneous pieces: - foreach key in suggested_outfit - { - int clownosity = suggested_outfit[key].numeric_modifier("Clowniness").floor(); - if (clownosity_possible - clownosity >= clownosity_needed) - { - clownosity_possible -= clownosity; - remove suggested_outfit[key]; - } - - } - string line = "Need " + clownosity_needed + " more clowniness."; - - if (available_clown_sources.count() > 0) - { - if (clownosity_possible >= clownosity_needed) - { - string line2 = "Equip " + suggested_outfit.listJoinComponents(", ", "and") + "."; - if (__last_adventure_location == $location[The "Fun" House]) - line2 = HTMLGenerateSpanFont(line2, "red"); - line += "|" + line2; - } - else - line += "|Equip " + available_clown_sources.listJoinComponents(", ", "or") + "."; - } - if (missing_sources.count() > 0 && clownosity_possible < clownosity_needed) - { - if (!in_ronin()) - line += "|Could buy " + missing_sources.listJoinComponents(", ", "or") + "."; - else - line += "|Find sources in the Fun House."; - } - int delay_turns_remaining = delayRemainingInLocation($location[the "fun" house]); - if (delay_turns_remaining > 0) - { - subentry.entries.listAppend(pluraliseWordy(delay_turns_remaining, "more turn", "more turns").capitaliseFirstLetter() + " before non-combat can show up."); - } - - subentry.entries.listAppend(line); - - } -} - -void QNemesisGenerateCaveTasks(ChecklistSubentry subentry, item legendary_epic_weapon) -{ - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questG05Dark", true); - - //place.php?whichplace=mountains&action=mts_caveblocked leads to an non-leaving NC (skippable) - //place.php?whichplace=nemesiscave - - subentry.entries.listAppend("Visit the sinister cave, solve the new quest."); - subentry.modifiers.listAppend("+item"); -} - -void QNemesisGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - - - /* - mafia ordering: - 1 -> acquire disco banjo - 2 -> defeat the clown prince - 3 -> make shagadelic disco banjo, talk to your guild - 4 -> wait for guild to find out where your nemesis is hiding - 5 -> time to visit the dark and dank and sinister cave - 6 -> defeated nemesis in cave, let's go talk to the guild - 7 -> they aren't impressed, wait for assassins - 8 -> first assassin appeared - 9 -> first assassin defeated - 10 -> second assassin appeared - 11 -> second assassin defeated - 12 -> third assassin appeared - 13 -> third assassin defeated - 14 -> final assassin appeared - 15 -> final assassin defeated, go find the lair - 16 -> we're at the island, do island stuff - 17 -> "got away. Again." - 18 -> lava maze solved - 19 -> final form [cue music] - - (same ordering we use) - */ - - - QuestState base_quest_state = __quest_state["Nemesis"]; - if (base_quest_state.finished) - return; - if (!($classes[seal clubber,turtle tamer,pastamancer,sauceror,disco bandit,accordion thief] contains my_class())) - return; - if (!__misc_state["guild open"]) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - string url = ""; - - //volcanoMaze1 through volcanoMaze5 is relevant, blank when not available - - boolean have_legendary_epic_weapon = false; - boolean have_epic_weapon = false; - - item [class] class_epic_weapons; - item [class] class_legendary_epic_weapons; - item [class] class_legendary_epic_weapon_craftable_sources; - item [class] class_ultimate_legendary_epic_weapons; - - class_epic_weapons[$class[seal clubber]] = $item[bjorn's hammer]; - class_epic_weapons[$class[turtle tamer]] = $item[mace of the tortoise]; - class_epic_weapons[$class[pastamancer]] = $item[pasta spoon of peril]; - class_epic_weapons[$class[sauceror]] = $item[5-alarm saucepan]; - class_epic_weapons[$class[disco bandit]] = $item[disco banjo]; - class_epic_weapons[$class[accordion thief]] = $item[rock and roll legend]; - item epic_weapon = class_epic_weapons[my_class()]; - - - class_legendary_epic_weapons[$class[seal clubber]] = $item[hammer of smiting]; - class_legendary_epic_weapons[$class[turtle tamer]] = $item[chelonian morningstar]; - class_legendary_epic_weapons[$class[pastamancer]] = $item[greek pasta spoon of peril]; - class_legendary_epic_weapons[$class[sauceror]] = $item[17-alarm saucepan]; - class_legendary_epic_weapons[$class[disco bandit]] = $item[shagadelic disco banjo]; - class_legendary_epic_weapons[$class[accordion thief]] = $item[squeezebox of the ages]; - item legendary_epic_weapon = class_legendary_epic_weapons[my_class()]; - - - class_legendary_epic_weapon_craftable_sources[$class[seal clubber]] = $item[distilled seal blood]; - class_legendary_epic_weapon_craftable_sources[$class[turtle tamer]] = $item[turtle chain]; - class_legendary_epic_weapon_craftable_sources[$class[pastamancer]] = $item[high-octane olive oil]; - class_legendary_epic_weapon_craftable_sources[$class[sauceror]] = $item[peppercorns of power]; - class_legendary_epic_weapon_craftable_sources[$class[disco bandit]] = $item[vial of mojo]; - class_legendary_epic_weapon_craftable_sources[$class[accordion thief]] = $item[golden reeds]; - item legendary_epic_weapon_craftable_source = class_legendary_epic_weapon_craftable_sources[my_class()]; - - - class_ultimate_legendary_epic_weapons[$class[seal clubber]] = $item[Sledgehammer of the Vælkyr]; - class_ultimate_legendary_epic_weapons[$class[turtle tamer]] = $item[Flail of the Seven Aspects]; - class_ultimate_legendary_epic_weapons[$class[pastamancer]] = $item[Wrath of the Capsaician Pastalords]; - class_ultimate_legendary_epic_weapons[$class[sauceror]] = $item[Windsor Pan of the Source]; - class_ultimate_legendary_epic_weapons[$class[disco bandit]] = $item[Seeger's Unstoppable Banjo]; - class_ultimate_legendary_epic_weapons[$class[accordion thief]] = $item[The Trickster's Trikitixa]; - item ultimate_legendary_epic_weapon = class_ultimate_legendary_epic_weapons[my_class()]; - - if (epic_weapon.available_amount_ignoring_storage() > 0) - have_epic_weapon = true; - if (legendary_epic_weapon.available_amount_ignoring_storage() > 0) - have_legendary_epic_weapon = true; - - if (!__misc_state["in aftercore"] && !have_legendary_epic_weapon && $location[the unquiet garves].turns_spent == 0) - return; - - - string [class] first_boss_name; - first_boss_name[$class[Seal Clubber]] = "Gorgolok, the Infernal Seal"; - first_boss_name[$class[Turtle Tamer]] = "Stella, the Turtle Poacher"; - first_boss_name[$class[Pastamancer]] = "Spaghetti Elemental"; - first_boss_name[$class[Sauceror]] = "Lumpy, the Sinister Sauceblob"; - first_boss_name[$class[Disco Bandit]] = "The Spirit of New Wave"; - first_boss_name[$class[Accordion Thief]] = "Somerset Lopez, Dread Mariachi"; - - if (!base_quest_state.started) - { - subentry.entries.listAppend("Speak to your guild to start the quest.|Then adventure in the Unquiet Garves until you unlock the tomb of the unknown, and solve the puzzle."); - url = "guild.php"; - return; - } - else if (base_quest_state.mafia_internal_step <= 4) - { - //1 One of your guild leaders has tasked you to recover a mysterious and unnamed artifact stolen by your Nemesis. Your first step is to smith an Epic Weapon - - //1 can be when Tomb of the Unknown Your Class Here is unlocked (think there's a missing quest step here?) - //2 can be fighting ghost - //4 can be nearing end - //5 -> return it - //6 -> returning (? - if (have_epic_weapon && false) //not true anymore - { - subentry.entries.listAppend("Speak to your guild."); - url = "guild.php"; - } - else - { - item starter_item_needed; - if (my_class() == $class[seal clubber]) - starter_item_needed = $item[seal-clubbing club]; - else if (my_class() == $class[turtle tamer]) - starter_item_needed = $item[helmet turtle]; - else if (my_class() == $class[pastamancer]) - starter_item_needed = $item[pasta spoon]; - else if (my_class() == $class[sauceror]) - starter_item_needed = $item[saucepan]; - else if (my_class() == $class[disco bandit]) - starter_item_needed = $item[disco mask]; - else if (my_class() == $class[accordion thief]) - starter_item_needed = $item[stolen accordion]; - - //subentry.entries.listAppend("Acquire " + epic_weapon + "."); - if (starter_item_needed.item_amount() == 0) - subentry.entries.listAppend("Acquire a " + starter_item_needed + "."); - else if ($location[The Unquiet Garves].noncombat_queue.contains_text("Tomb of the Unknown Your Class Here")) - { - subentry.entries.listAppend("Solve the puzzle at the unknown tomb."); - - string puzzle_answer; - if (my_class() == $class[seal clubber]) - puzzle_answer = "The answer is \"Boredom\"."; - else if (my_class() == $class[turtle tamer]) - puzzle_answer = "The answer is \"Friendship\"."; - else if (my_class() == $class[pastamancer]) - puzzle_answer = "The answer is \"Binding pasta thralls\"."; - else if (my_class() == $class[sauceror]) - puzzle_answer = "The answer is \"Power\"."; - else if (my_class() == $class[disco bandit]) - puzzle_answer = "The answer is \"Me. Duh\"."; - else if (my_class() == $class[accordion thief]) - puzzle_answer = "The answer is \"Music\"."; - string puzzle_answer_html = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(puzzle_answer, "r_tooltip_inner_class") + "Hover over to see the answer.", "r_tooltip_outer_class"); - subentry.entries.listAppend(puzzle_answer_html); - } - else { - subentry.entries.listAppend("Adventure in the Unquiet Garves until you unlock the tomb of the unknown, then solve the puzzle."); - if (__quest_state["Level 11 Shen"].state_int.getFutureShenAssignments().listInvert() contains $location[The VERY Unquiet Garves]) - subentry.entries.listAppend("Could wait before going there? Shen will send you to the garves later."); - } - url = "place.php?whichplace=cemetery"; - } - } - else if (base_quest_state.mafia_internal_step == 5) - { - subentry.entries.listAppend("Speak to your guild."); - url = "guild.php"; - } - else if (base_quest_state.mafia_internal_step <= 6) - { - //6 To unlock the full power of the Legendary Epic Weapon, you must defeat Beelzebozo, the Clown Prince of Darkness, - QNemesisGenerateClownTasks(subentry); - url = "place.php?whichplace=plains"; - } - else if (base_quest_state.mafia_internal_step >= 7 && base_quest_state.mafia_internal_step <= 9) - { - if (have_legendary_epic_weapon) - { - subentry.entries.listAppend("Speak to your guild."); - url = "guild.php"; - } - else - { - subentry.entries.listAppend("Make " + legendary_epic_weapon + "."); - subentry.entries.listAppend("Recipe is " + epic_weapon + " + " + legendary_epic_weapon_craftable_source + "."); - url = "craft.php?mode=smith"; - } - } - else if (base_quest_state.mafia_internal_step == 10) - { - //??? - subentry.entries.listAppend("Speak to your guild?"); - } - else if (base_quest_state.mafia_internal_step >= 11 && base_quest_state.mafia_internal_step <= 16) - { - //QNemesisGenerateCaveTasks(subentry, legendary_epic_weapon); - if (base_quest_state.mafia_internal_step == 11 || base_quest_state.mafia_internal_step == 12) - { - url = "place.php?whichplace=mountains"; - //The hunt for your Nemesis is on! Better check out that cave they sent you to. - //Figure out how to get into your Nemesis' cave. If you're stumped, maybe your guild can help? - - skill skill_needed; - string skill_choice_name; - - if (my_class() == $class[seal clubber]) - { - skill_needed = $skill[wrath of the wolverine]; - skill_choice_name = "wolverine"; - } - else if (my_class() == $class[disco bandit]) - { - //Focus on your disco state of mind - skill_needed = $skill[disco state of mind]; - skill_choice_name = "disco state of mind"; - } - else if (my_class() == $class[sauceror]) - { - skill_needed = $skill[stream of sauce]; - skill_choice_name = "stream of sauce"; - } - else if (my_class() == $class[turtle tamer]) - { - skill_needed = $skill[amphibian sympathy]; - skill_choice_name = "sympathize with an amphibian"; - } - else if (my_class() == $class[pastamancer]) - { - skill_needed = $skill[entangling noodles]; - skill_choice_name = "entangle the wall with noodles"; - } - else if (my_class() == $class[accordion thief]) - { - skill_needed = $skill[accordion bash]; - skill_choice_name = "bash the wall with your accordion"; - } - //Stream of sauce? - //entangling noodles? - if (skill_needed != $skill[none] && !skill_needed.have_skill()) - { - subentry.entries.listAppend("Learn " + skill_needed + " from guild trainer."); - url = "guild.php?place=trainer"; - } - else if (skill_needed != $skill[none]) - { - subentry.entries.listAppend("Click on the nemesis cave, choose " + skill_choice_name + "."); - } - else - subentry.entries.listAppend("Solve the cave entrance puzzle."); - } - else if (base_quest_state.mafia_internal_step >= 13 && base_quest_state.mafia_internal_step <= 15) - { - url = "place.php?whichplace=nemesiscave"; - //The cavern is full of weird mushrooms, but where's your Nemesis? - //more fizzing spore pods to blow up the blockade in your Nemesis' cave. - //Take those fizzing spore pods to the rubble! - - item needed_item = $item[fizzing spore pod]; - - if (needed_item.available_amount() < 6) - { - subentry.modifiers.listAppend("+item"); - subentry.modifiers.listAppend("olfact angry mushroom guy"); - subentry.entries.listAppend("Adventure in the fungal nethers, collect " + pluraliseWordy(clampi(6 - needed_item.item_amount(), 0, 6), needed_item) + ", make rubble go boom!"); - } - else - { - if (needed_item.item_amount() < 6) - { - int delta = 6 - needed_item.item_amount(); - subentry.entries.listAppend("Pull " + pluralise(delta, $item[fizzing spore pod]) + " from hangk's, make rubble go boom!"); - } - else - subentry.entries.listAppend("Make rubble go boom!"); - } - } - else if (base_quest_state.mafia_internal_step == 16) - { - url = "place.php?whichplace=nemesiscave"; - //Boom! Time to bring the fight to your stinking Nemesis in that stinking cave! - subentry.entries.listAppend("Fight your nemesis in the nemesis cave."); - subentry.entries.listAppend("Do nemesis caves just get rented out on a time-share nemesis basis?|For the month of june, you'll be rueing the day! What? I paid how much?"); - } - } - else if (base_quest_state.mafia_internal_step >= 17 && base_quest_state.mafia_internal_step < 26) - { - // You have successfully shown your Nemesis what for, and claimed an ancient hat of power. It's pretty sweet - // You showed the Epic Hat to the class leader back at your guild, but they didn't seem much impressed. I guess all this Nemesis nonsense isn't quite finished yet, but at least with your Nemesis in hiding again you won't have to worry about it for a while. - // It appears as though some nefarious ne'er-do-well has put a contract on your head - // You handily dispatched some thugs who were trying to collect on your bounty, but something tells you they won't be the last ones to try - - // Whoever put this hit out on you (like you haven't guessed already) has sent Mob Penguins to do their dirty work. Do you know any polar bears you could hire as bodyguards - // So much for those mob penguins that were after your head! If whoever put this hit out on you wants you killed (which, presumably, they do) they'll have to find some much more competent thugs - // have been confirmed: your Nemesis has put the order out for you to be hunted down and killed, and now they're sending their own guys instead of contracting out - // Bam! So much for your Nemesis' assassins! If that's the best they've got, you have nothing at all to worry about - // You had a run-in with some crazy mercenary or assassin or... thing that your Nemesis sent to do you in once and for all. A run-in followed by a run-out, evidently, - string assassin_up_next = ""; - int assassins_left = -1; - - if (mafiaIsPastRevision(14330)) - { - if (base_quest_state.mafia_internal_step < 20) - { - assassin_up_next = "menacing thug"; - assassins_left = 4; - } - else if (base_quest_state.mafia_internal_step < 22) - { - assassin_up_next = "Mob Penguin hitman"; - assassins_left = 3; - } - else if (base_quest_state.mafia_internal_step < 24) - { - if (my_class() == $class[seal clubber]) - assassin_up_next = "hunting seal"; - else if (my_class() == $class[turtle tamer]) - assassin_up_next = "turtle trapper"; - else if (my_class() == $class[pastamancer]) - assassin_up_next = "evil spaghetti cult assassin"; - else if (my_class() == $class[sauceror]) - assassin_up_next = "béarnaise zombie"; - else if (my_class() == $class[disco bandit]) - assassin_up_next = "flock of seagulls"; - else if (my_class() == $class[accordion thief]) - assassin_up_next = "mariachi bandolero"; - - assassins_left = 2; - } - else - { - if (my_class() == $class[seal clubber]) - assassin_up_next = "Argarggagarg the Dire Hellseal"; - else if (my_class() == $class[turtle tamer]) - assassin_up_next = "Safari Jack, Small-Game Hunter"; - else if (my_class() == $class[pastamancer]) - assassin_up_next = "Yakisoba the Executioner"; - else if (my_class() == $class[sauceror]) - assassin_up_next = "Heimandatz, Nacho Golem"; - else if (my_class() == $class[disco bandit]) - assassin_up_next = "Jocko Homo"; - else if (my_class() == $class[accordion thief]) - assassin_up_next = "The Mariachi With No Name"; - assassins_left = 1; - } - } - - if (assassins_left != -1) - { - string line = "Wait for " + pluraliseWordy(assassins_left, "more assassin", "more assassins"); - - //int min_turns_left = 0; - //int max_turns_left = 0; - float average_turns_left = 0; - - int effective_assassins_left = assassins_left; - //35 to 50 - Counter nemesis_assassin_window = CounterLookup("Nemesis Assassin"); - if (nemesis_assassin_window.CounterExists() && nemesis_assassin_window.CounterIsRange()) - { - //min_turns_left += nemesis_assassin_window.range_start_turn; - //max_turns_left += nemesis_assassin_window.range_end_turn; - average_turns_left += (nemesis_assassin_window.range_start_turn + nemesis_assassin_window.range_end_turn).to_float() / 2.0; - effective_assassins_left -= 1; - } - - - effective_assassins_left = clampi(effective_assassins_left, 0, 4); - //min_turns_left += 35 * effective_assassins_left; - //max_turns_left += 50 * effective_assassins_left; - average_turns_left += 42.5 * effective_assassins_left.to_float(); - - //I wonder if showing max_turns_left would be less confusing here... - line += " over ~" + average_turns_left.roundForOutput(0) + " turns."; - subentry.entries.listAppend(line); - } - else - subentry.entries.listAppend("Wait for assassins."); - - //if (base_quest_state.mafia_internal_step < 20) - //subentry.entries.listAppend("Umm... you may need to talk to your guild(?)|Something about this step is weird."); - - if (assassin_up_next != "") - subentry.entries.listAppend(assassin_up_next.capitaliseFirstLetter() + " up next."); - - if (my_basestat(my_primestat()) < 90) - subentry.entries.listAppend("Level to 90 " + my_primestat().to_lower_case() + "."); - - if (my_class() == $class[pastamancer] && my_thrall() != $thrall[spaghetti elemental] && $skill[bind spaghetti elemental].have_skill() && $thrall[spaghetti elemental].level < 3) - { - subentry.entries.listAppend("Cast Bind Spaghetti Elemental to level up your spaghetti elemental to three in advance."); - } - if (base_quest_state.mafia_internal_step == 17) - { - subentry.entries.listAppend("Possibly speak to your guild?"); - url = "guild.php"; - } - } - else if (base_quest_state.mafia_internal_step == 15 && false) - { - // Now that you've dealt with your Nemesis' assassins and found a map to the secret tropical island volcano lair, it's time to take the fight to your foe. Booyah - //find island - url = "inventory.php?ftext=secret+tropical+island+volcano+lair+map"; - subentry.entries.listAppend("Use the secret tropical island volcano lair map."); - } - else if (base_quest_state.mafia_internal_step == 27 || base_quest_state.mafia_internal_step == 26) //mafia bug(?) - doesn't advance properly - { - // You've arrived at the secret tropical island volcano lair, and it's time to finally put a stop to this Nemesis nonsense once and for all. As soon as you can find where they're hiding. Maybe you can find someone to ask - if ($location[The Nemesis' Lair].turnsAttemptedInLocation() > 0) - { - if (my_class() == $class[disco bandit]) - subentry.entries.listAppend("Fight daft punk, then your nemesis face to face.|Then solve the volcano maze."); - else - subentry.entries.listAppend("Fight goons, then your nemesis.|Then solve the volcano maze."); - } - else - QNemesisGenerateIslandTasks(subentry); - url = "volcanoisland.php"; - } - else if (base_quest_state.mafia_internal_step >= 28 && base_quest_state.mafia_internal_step <= 30) - { - // Congratulations on solving the lava maze, which is probably the biggest pain-in-the-ass puzzle in the entire game! Hooray! (Unless you cheated, in which case - if (base_quest_state.mafia_internal_step == 21) - subentry.entries.listAppend("Solve the volcano maze, then fight your nemesis."); - else - subentry.entries.listAppend("Fight your nemesis."); - url = "volcanomaze.php"; - if (legendary_epic_weapon.equipped_amount() == 0 && ultimate_legendary_epic_weapon.equipped_amount() == 0) - subentry.entries.listAppend("Equip " + legendary_epic_weapon + "."); - if (my_class() == $class[sauceror]) - { - string [int] missing_saucespheres; - foreach s in $skills[elemental saucesphere,Jalapeño Saucesphere,antibiotic saucesphere,scarysauce] - { - effect e = s.to_effect(); - if (e.have_effect() > 0) - continue; - string line = s.to_string(); - - if (!s.skill_is_usable()) - line = HTMLGenerateSpanFont(line, "grey"); - - missing_saucespheres.listAppend(line); - } - if (missing_saucespheres.count() > 0) - { - subentry.entries.listAppend("Acquire saucespheres: " + missing_saucespheres.listJoinComponents(", ", "and") + "."); - } - } - if (my_class() == $class[pastamancer]) - { - subentry.entries.listAppend("Run a potato familiar, and alternate casting entangling noodles twice/some sort of attack to keep the demon blocked."); - } - } - - boolean [location] relevant_locations; - foreach l in $locations[the unquiet garves,the "fun" house, the nemesis' lair, the broodling grounds, the outer compound, the temple portico, convention hall lobby, outside the club, the island barracks, the poop deck] - relevant_locations[l] = true; - relevant_locations[$location[the fungal nethers]] = true; - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, relevant_locations).ChecklistEntrySetIDTag("Guild nemesis quest")); -} diff --git a/Source/relay/TourGuide/Quests/Old Landfill.ash b/Source/relay/TourGuide/Quests/Old Landfill.ash deleted file mode 100644 index faf316b3..00000000 --- a/Source/relay/TourGuide/Quests/Old Landfill.ash +++ /dev/null @@ -1,74 +0,0 @@ - -void QOldLandfillInit() -{ - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questM19Hippy"); - - state.quest_name = "Give a Hippy a Boat"; - state.image_name = "__item junk junk"; - - state.startable = true; - - __quest_state["Old Landfill"] = state; -} - - -void QOldLandfillGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Old Landfill"]; - //if (!base_quest_state.in_progress) //this isn't actively tracked, so the best we can do is checking the last adventure location - //return; - if ($item[junk junk].available_amount() > 0) //FIXME returning to the hippy - return; - if (__last_adventure_location != $location[the old landfill] && !base_quest_state.in_progress) - return; - if (__misc_state["mysterious island available"]) - return; - - ChecklistSubentry subentry; - subentry.entries.listAppend("Unlocks the Mysterious Island."); - - item [int] missing_boat_items = $items[old claw-foot bathtub,old clothesline pole,antique cigar sign].items_missing(); - - subentry.header = base_quest_state.quest_name; - - string active_url = "place.php?whichplace=woods"; - - if ($item[worse homes and gardens].available_amount() > 0 && missing_boat_items.count() == 0) - { - active_url = "shop.php?whichshop=junkmagazine"; - subentry.entries.listAppend("Use worse homes and gardens, craft a junk junk."); - } - else - { - string [int] nc_instructions = listMake("Go left", "Flush a bunch of toilets"); - - if ($item[old claw-foot bathtub].available_amount() == 0) - { - nc_instructions = listMake("Go left", "Take the tub"); - } - else if ($item[old clothesline pole].available_amount() == 0) - { - nc_instructions = listMake("Go center", "Take the antenna"); - } - else if ($item[antique cigar sign].available_amount() == 0) - { - nc_instructions = listMake("Go right", "Take the sign"); - } - - - if (missing_boat_items.count() > $item[funky junk key].available_amount() || $item[worse homes and gardens].available_amount() == 0) - { - subentry.modifiers.listAppend("+item"); - subentry.entries.listAppend("Adventure in the Old Landfill with +item."); - } - else - subentry.entries.listAppend("Adventure in the Old Landfill."); - - subentry.entries.listAppend("At the choice adventure, choose:|*" + nc_instructions.listJoinComponents(__html_right_arrow_character) + "."); - } - - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[the old landfill]).ChecklistEntrySetIDTag("Old landfill hippy quest")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Pirate.ash b/Source/relay/TourGuide/Quests/Pirate.ash deleted file mode 100644 index 5fd42bee..00000000 --- a/Source/relay/TourGuide/Quests/Pirate.ash +++ /dev/null @@ -1,387 +0,0 @@ -import "relay/TourGuide/Quests/Level 11.ash"; - -void QPirateInit() -{ - //questM12Pirate ? - //lastPirateInsult1 through lastPirateInsult8 - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questM12Pirate"); - state.quest_name = "Pirate Quest"; - state.image_name = "pirate quest"; - - state.state_boolean["valid"] = false; // now invalid by default since the 2020 change - - if (my_path().id == PATH_LOW_KEY_SUMMER) - state.state_boolean["valid"] = true; - - if (__misc_state["mysterious island available"] && state.state_boolean["valid"]) { - state.startable = true; - if (!state.in_progress && !state.finished) { - QuestStateParseMafiaQuestPropertyValue(state, "started"); - } - } - - - boolean hot_wings_relevant = knoll_available() || $item[frilly skirt].available_amount() > 0 || !in_hardcore(); - if (state.mafia_internal_step >= 4) //done that already - hot_wings_relevant = false; - boolean need_more_hot_wings = $item[hot wing].available_amount() <3 && hot_wings_relevant; - - state.state_boolean["hot wings relevant"] = hot_wings_relevant; - state.state_boolean["need more hot wings"] = need_more_hot_wings; - - - int insult_count = 0; - for i from 1 to 8 { - if (get_property_boolean("lastPirateInsult" + i)) - insult_count += 1; - } - state.state_int["insult count"] = insult_count; - - if ($item[Orcish Frat House blueprints].available_amount() > 0 && state.mafia_internal_step <3 ) - QuestStateParseMafiaQuestPropertyValue(state, "step2"); - - //Certain characters are in weird states, I think? (now obsolete; these two quests are no longer linked) - /*if ($item[pirate fledges].available_amount() > 0 || $item[talisman o\' namsilat].available_amount() > 0) - QuestStateParseMafiaQuestPropertyValue(state, "finished");*/ - __quest_state["Pirate Quest"] = state; -} - - -void QPirateCoveGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (__quest_state["Island War"].state_boolean["War in progress"]) return; - - QuestState base_quest_state = __quest_state["Pirate Quest"]; - ChecklistSubentry subentry; - subentry.header = base_quest_state.quest_name; - string url = ""; - - - boolean have_outfit = have_outfit_components("Swashbuckling Getup"); - if ($item[pirate fledges].available_amount() > 0) - have_outfit = true; - boolean is_a_pirate = is_wearing_outfit("Swashbuckling Getup") || $item[pirate fledges].equipped_amount() > 0; - - int insult_count = base_quest_state.state_int["insult count"]; - - float [int] insult_success_likelyhood; - //haven't verified these numbers, need to double-check - insult_success_likelyhood[0] = 0.0; - insult_success_likelyhood[1] = 0.0; - insult_success_likelyhood[2] = 0.0; - insult_success_likelyhood[3] = 0.0179; - insult_success_likelyhood[4] = 0.071; - insult_success_likelyhood[5] = 0.1786; - insult_success_likelyhood[6] = 0.357; - insult_success_likelyhood[7] = 0.625; - insult_success_likelyhood[8] = 1.0; - - boolean delay_for_future = false; - boolean can_acquire_cocktail_napkins = false; - - if (in_ronin() && $item[Talisman o\' Namsilat].available_amount() == 0 && my_path().id != PATH_LOW_KEY_SUMMER) - subentry.entries.listAppend(HTMLGenerateSpanFont("Pirates won't help you in-run anymore.", "red")); - - if (!have_outfit) { - url = "island.php"; - string line = "Acquire outfit."; - - item [int] outfit_pieces = outfit_pieces("Swashbuckling Getup"); - item [int] outfit_pieces_needed; - foreach key in outfit_pieces { - item piece = outfit_pieces[key]; - if (piece.available_amount() == 0) - outfit_pieces_needed.listAppend(piece); - } - line += " Need " + outfit_pieces_needed.listJoinComponents(", ", "and") + "."; - subentry.entries.listAppend(line); - - subentry.modifiers.listAppend("+item"); - subentry.modifiers.listAppend("-combat"); - - if ($familiar[slimeling].familiar_is_usable()) - subentry.modifiers.listAppend("slimeling?"); - - int ncs_relevant = 0; //out of six - if ($item[stuffed shoulder parrot].available_amount() == 0 || $item[eyepatch].available_amount() == 0) - ncs_relevant += 1; - if ($item[eyepatch].available_amount() == 0 || $item[swashbuckling pants].available_amount() == 0) - ncs_relevant += 1; - if ($item[swashbuckling pants].available_amount() == 0 || $item[stuffed shoulder parrot].available_amount() == 0) - ncs_relevant += 1; - - float average_combat_rate = clampNormalf(.6 + combat_rate_modifier() / 100.0); - float average_nc_rate = 1.0 - average_combat_rate; - - float average_useful_nc_rate = average_nc_rate * (ncs_relevant.to_float() / 6.0); - //FIXME make this more accurate - float turns_remaining = -1.0; - if (average_useful_nc_rate != 0.0) - turns_remaining = outfit_pieces_needed.count().to_float() / average_useful_nc_rate; - subentry.entries.listAppend("Run -combat in the obligatory pirate's cove." + "|~" + turns_remaining.roundForOutput(1) + " turns remain at " + combat_rate_modifier().floor() + "% combat."); - - if (!__quest_state["Manor Unlock"].state_boolean["ballroom song effectively set"]) { - subentry.entries.listAppend(HTMLGenerateSpanOfClass("Wait until -combat ballroom song set.", "r_bold")); - delay_for_future = true; - } - } else { - url = "place.php?whichplace=cove"; - - if (!is_a_pirate) - url = "inventory.php?which=2"; - - boolean have_all_fcle_items = false; - - if (base_quest_state.mafia_internal_step == 1) { - can_acquire_cocktail_napkins = true; - //caronch gave you a map - if ($item[Cap'm Caronch's nasty booty].available_amount() == 0 && $item[Cap'm Caronch's Map].available_amount() > 0) { - url = "inventory.php?ftext=cap'm+caronch's+map"; - subentry.entries.listAppend("Use Cap'm Caronch's Map, fight a booty crab."); - subentry.entries.listAppend("Possibly run +meat. (300 base drop)"); - subentry.modifiers.listAppend("+meat"); - } else if (have_outfit) { - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("Find Cap'm Caronch in Barrrney's Barrr."); - } - } else if (base_quest_state.mafia_internal_step == 2) { - can_acquire_cocktail_napkins = true; - //give booty back to caronch - subentry.entries.listAppend("Find Cap'm Caronch in Barrrney's Barrr."); - } else if (base_quest_state.mafia_internal_step == 3) { - can_acquire_cocktail_napkins = true; - //have blueprints, catburgle - string line = "Use the Orcish Frat House blueprints"; - if (insult_count < 6) { - subentry.modifiers.listAppend("+20% combat"); - line += ", once you have at least six insults"; //in certain situations five might be slightly faster? but that skips a lot of combats, so probably not - } - line += "."; - - string method; - if (have_outfit_components("Frat Boy Ensemble") && __misc_state["can equip just about any weapon"]) { - string [int] todo; - if (!is_wearing_outfit("Frat Boy Ensemble")) - todo.listAppend("wear frat boy ensemble"); - todo.listAppend("attempt a frontal assault"); - method = todo.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."; - } else if ($item[mullet wig].available_amount() > 0 && $item[briefcase].available_amount() > 0) { - string [int] todo; - if ($item[mullet wig].equipped_amount() == 0) - todo.listAppend("wear mullet wig"); - todo.listAppend("go in through the side door"); - method = todo.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."; - } else if (knoll_available() || ($item[frilly skirt].available_amount() > 0 && $item[hot wing].available_amount() >= 3)) { - string [int] todo; - if (insult_count < 6) - todo.listAppend("acquire at least six insults"); - if ($item[hot wing].available_amount() <3 ) - todo.listAppend("acquire " + pluralise((3 - $item[hot wing].available_amount()), "more hot wing", "more hot wings")); - if ($item[frilly skirt].equipped_amount() == 0) - todo.listAppend("wear frilly skirt"); - todo.listAppend("catburgle"); - string line2 = todo.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."; - method = line2; - } else { - //Non-knoll sign. - //I think the fastest method is frilly skirt? - if ($item[hot wing].available_amount() >= 3 && my_familiar() != $familiar[black cat]) - method = "Farm a frilly skirt in the knoll gym. (+300% item)"; - else { - method = "Acquire a frat boy outfit in the frat house? (-combat" + (my_level() < 9 ? " after level 9" : "") + ")"; - if (!__quest_state["Level 6"].finished) - method += "|Or collect hot wings from the friar demons" + ($item[frilly skirt].available_amount() == 0 ? ", and frilly skirt from the knoll gym" : "") + "."; - } - } - line += "|" + method; - subentry.entries.listAppend(line); - } else if (base_quest_state.mafia_internal_step == 4) { - //acquired teeth, give them back - subentry.entries.listAppend("Find Cap'm Caronch in Barrrney's Barrr. (next adventure)"); - } else if (base_quest_state.mafia_internal_step == 5) { - //ricketing - subentry.entries.listAppend("Play beer pong."); - subentry.entries.listAppend("If you want more insults now, adventure in the Obligatory Pirate's Cove, not in the Barrr."); - } else if (base_quest_state.mafia_internal_step == 6) { - //f'c'le - //We can't tell them which ones they need, precisely, since they may have already used them. - //We can tell them which ones they have... but it's still unreliable. I guess a single message if they have all three? - string line = "F'c'le."; - string additional_line = ""; - - item [int] missing_washing_items = $items[rigging shampoo,mizzenmast mop,ball polish].items_missing(); - - if (missing_washing_items.count() == 0) { - have_all_fcle_items = true; - url = "inventory.php?which=3"; - line += " " + HTMLGenerateSpanFont("Use rigging shampoo, mizzenmast mop, and ball polish", "red") + ", then adventure to complete quest."; - } else { - subentry.modifiers.listAppend("+234% item"); - subentry.modifiers.listAppend("+20% combat"); - string [int] missing_washing_items_wordy; - foreach key in missing_washing_items { - if (missing_washing_items [key] == $item[rigging shampoo]) - missing_washing_items_wordy.listAppend("rigging shampoo (cleanly pirate)"); - else if (missing_washing_items [key] == $item[mizzenmast mop]) - missing_washing_items_wordy.listAppend("mizzenmast mop (curmudgeonly pirate)"); - else if (missing_washing_items [key] == $item[ball polish]) - missing_washing_items_wordy.listAppend("ball polish (creamy pirate)"); - } - line += " Run +234% item, +combat, and collect " + missing_washing_items_wordy.listJoinComponents(", ", "and") + "."; - if ($location[the f'c'le].item_drop_modifier_for_location() < 234.0) - additional_line = "This location can be a nightmare without +234% item."; - - subentry.modifiers.listAppend("banish chatty/crusty pirate"); - } - - subentry.entries.listAppend(line); - if (!have_all_fcle_items) - subentry.entries.listAppend("Don't use the items right away: we can't tell if you did!"); - if (additional_line != "") - subentry.entries.listAppend(additional_line); - if (!($monster[clingy pirate (female)].is_banished() || $monster[clingy pirate (male)].is_banished()) && $item[cocktail napkin].available_amount() > 0 && !have_all_fcle_items) { - subentry.entries.listAppend("Use cocktail napkin on clingy pirate to " + (__misc_state["free runs usable"] ? "free run/" : "") + "banish."); - } - } else if (base_quest_state.mafia_internal_step == 7) { - //The Poop Deck - if (__quest_state["Level 11"].mafia_internal_step < 3) { - if (my_path().id == PATH_COMMUNITY_SERVICE || __quest_state["Level 11"].mafia_internal_step == 0 && get_property_int("lastCouncilVisit") >= 11) { //They CANNOT get the password, and are only here for the zone itself - QuestStateParseMafiaQuestPropertyValue(base_quest_state, "finished"); - subentry.entries.listAppend("Watch out for that recurring non-combat..."); - } else - subentry.entries.listAppend("Come back when you've read from your father's MacGuffin diary, or you'll keep getting beaten up by the recurring non-combat."); - } else { - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("Run -combat on the Poop Deck to unlock belowdecks."); - subentry.entries.listAppend(generateTurnsToSeeNoncombat(80, 1, "unlock belowdecks")); - } - } - - if (base_quest_state.mafia_internal_step <= 3 && my_inebriety() > 0) { - subentry.entries.listAppend("Could wait until rollover; one of the non-combats can become a combat at zero drunkenness."); - } - - - if (__misc_state["free runs available"] && !can_acquire_cocktail_napkins && !have_all_fcle_items) - subentry.modifiers.listAppend("free runs"); - } - boolean should_output_insult_data = false; - if ($item[the big book of pirate insults].available_amount() > 0 || have_outfit) - should_output_insult_data = true; - if (base_quest_state.mafia_internal_step >= 6) - should_output_insult_data = false; - - if (should_output_insult_data) { - string line = "At " + pluralise(insult_count, "insult", "insults") + ". " + roundForOutput(insult_success_likelyhood[insult_count] * 100, 1) + "% chance of beer pong success."; - if (insult_count < 8) - line += "|Insult every pirate with the big book of pirate insults."; - subentry.entries.listAppend(line); - } - if ($item[the big book of pirate insults].available_amount() == 0 && base_quest_state.mafia_internal_step < 6 && have_outfit) - subentry.entries.listAppend(HTMLGenerateSpanFont("Buy the big book of pirate insults.", "red")); - - if (can_acquire_cocktail_napkins && $item[cocktail napkin].available_amount() == 0) { - subentry.modifiers.listAppend("+item"); - subentry.entries.listAppend("Try to acquire a cocktail napkin to speed up F'c'le. (10% drop, marginal)"); - } - - if (have_outfit && !is_a_pirate) { - string line; - if ($item[pirate fledges].available_amount() > 0 && my_basestat($stat[mysticality]) >= 60) { - line = "Wear pirate fledges."; - } else if (!is_wearing_outfit("Swashbuckling Getup")) { - string [int] stats_needed; - if (my_basestat($stat[moxie]) < 25) - stats_needed.listAppend("moxie"); - if (my_basestat($stat[mysticality]) < 25) - stats_needed.listAppend("mysticality"); - line = "Wear swashbuckling getup."; - - if (stats_needed.count() > 0) { - delay_for_future = true; - line += HTMLGenerateSpanOfClass(" Need 25 " + stats_needed.listJoinComponents(", ", "and"), "r_bold") + "."; - } - } - subentry.entries.listAppend(line); - } - - ChecklistEntry entry = ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the obligatory pirate's cove, barrrney's barrr, the f'c'le,The Poop Deck]); - entry.tags.id = "Island pirates quest"; - entry.tags.combination = "pirates"; - - if (__misc_state["in run"] && base_quest_state.state_boolean["valid"]) { - if (delay_for_future) - future_task_entries.listAppend(entry); - else - task_entries.listAppend(entry); - } else - optional_task_entries.listAppend(entry); -} - -void QPoopDeckGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //O Cap'm, My Cap'm helper; the main feature of this section, now! - ChecklistSubentry subentry; - subentry.header = "Sail the sea"; - string url = "place.php?whichplace=cove"; - - if ($item[pirate fledges].equipped_amount() == 0) { - subentry.entries.listAppend("Wear pirate fledges."); - url = "inventory.php?ftext=pirate+fledges"; - } - - if (true) { //for when the last o'cap'm, my cap'm property will be implemented (if) - if (my_meat() < 977) { - subentry.entries.listAppend(HTMLGenerateSpanOfClass("Start by acquiring 977 meat.", "r_bold") + (__misc_state["need to level"] ? ", to gain extra stats from the other NC" : "") + "."); - } else { - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("Adventure on the Poop Deck until you get O Cap'm, My Cap'm."); - } - } else { - //how many turns they'll need to burn in the zone to get the adventure again - } - - subentry.entries.listAppend("*Sail to (48,47) to get an El Vibrato power sphere (or buy from mall)."); - if (item_amount_almost_everywhere(lookupItem("El Vibrato trapezoid")) == 0 && $location[El Vibrato Island].turns_spent == 0 && __campground[lookupItem("El Vibrato trapezoid")] == 0) { //mafia only registers the trapezoid in the campground from revisiton 20267 and onward - string line = "*Sail to (63,29) to get an El Vibrato trapezoid."; - if (!mafiaIsPastRevision(20267)) //Means that we can't trust "__campground[lookupItem("El Vibrato trapezoid")] == 0" to be accurate - line += HTMLGenerateSpanFont(" Don't do this if you've already set up a portal at your campground.", "red"); - - if (lookupItem("El Vibrato power sphere").item_amount() == 0) - line += "|*Need an El Vibrato power sphere in inventory. Buy from mall?"; - line += "|*Gives an item that creates a portal to El Vibrato Island at your campground (will need to keep it charged with more power spheres)."; - subentry.entries.listAppend(line); - } - subentry.entries.listAppend("*Or sail to (1,1) to get a random ancient cursed key/chest."); - if (__misc_state["need to level"]) { - string coordinates; - if (my_primestat() == $stat[muscle]) - coordinates = "(56, 14)"; - else if (my_primestat() == $stat[mysticality]) - coordinates = "(3, 35)"; - else if (my_primestat() == $stat[moxie]) - coordinates = "(5, 39)"; - if (coordinates != "") - subentry.entries.listAppend("Could sail to " + coordinates + " for stats?"); - } - - ChecklistEntry entry = ChecklistEntryMake("ship wheel", url, subentry, $locations[The Poop Deck]); - entry.tags.id = "Island pirates poop deck sailing"; - entry.tags.combination = "pirates"; - - if (__misc_state["in run"] && __quest_state["Pirate Quest"].state_boolean["valid"] && __quest_state["Pirate Quest"].in_progress) //To match if QPirateCoveGenerateTasks is being displayed in task or optional_task - task_entries.listAppend(entry); - else - optional_task_entries.listAppend(entry); -} - -void QPirateGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //Show the tile IF: they started the quest, and the quest is valid in this path, OR, they started the quest, and are adventuring in the relevant locations, OR, they started the quest, and are out of run. - if (__quest_state["Pirate Quest"].in_progress && (__quest_state["Pirate Quest"].state_boolean["valid"] || $locations[the obligatory pirate's cove, barrrney's barrr, the f'c'le, the poop deck] contains __last_adventure_location || !__misc_state["in run"])) - QPirateCoveGenerateTasks(task_entries, optional_task_entries, future_task_entries); - - if ($location[The Poop Deck] == __last_adventure_location || __quest_state["Pirate Quest"].mafia_internal_step == 7) - QPoopDeckGenerateTasks(task_entries, optional_task_entries, future_task_entries); -} diff --git a/Source/relay/TourGuide/Quests/Quest import.ash b/Source/relay/TourGuide/Quests/Quest import.ash deleted file mode 100644 index 6f5c2bea..00000000 --- a/Source/relay/TourGuide/Quests/Quest import.ash +++ /dev/null @@ -1,36 +0,0 @@ -import "relay/TourGuide/Quests/Level 2.ash"; -import "relay/TourGuide/Quests/Level 3.ash"; -import "relay/TourGuide/Quests/Level 4.ash"; -import "relay/TourGuide/Quests/Level 5.ash"; -import "relay/TourGuide/Quests/Level 6.ash"; -import "relay/TourGuide/Quests/Level 7.ash"; -import "relay/TourGuide/Quests/Level 8.ash"; -import "relay/TourGuide/Quests/Level 9.ash"; -import "relay/TourGuide/Quests/Level 10.ash"; -import "relay/TourGuide/Quests/Level 11.ash"; -import "relay/TourGuide/Quests/Level 12.ash"; -import "relay/TourGuide/Quests/Level 13.ash"; -import "relay/TourGuide/Quests/Manor.ash"; -import "relay/TourGuide/Quests/Pirate.ash"; -import "relay/TourGuide/Quests/Nemesis.ash"; -import "relay/TourGuide/Quests/Sea.ash"; -import "relay/TourGuide/Quests/Space Elves.ash"; -import "relay/TourGuide/Quests/Azazel.ash"; -import "relay/TourGuide/Quests/Untinker.ash"; -import "relay/TourGuide/Quests/Artist.ash"; -import "relay/TourGuide/Quests/Legendary Beat.ash"; -import "relay/TourGuide/Quests/Memories.ash"; -import "relay/TourGuide/Quests/White Citadel.ash"; -import "relay/TourGuide/Quests/Wizard of Ego.ash"; -import "relay/TourGuide/Quests/Spookyraven Lights Out.ash"; -import "relay/TourGuide/Quests/Felonia.ash"; -import "relay/TourGuide/Quests/Guild.ash"; -import "relay/TourGuide/Quests/Airport.ash"; -import "relay/TourGuide/Quests/Subject 37.ash"; -import "relay/TourGuide/Quests/Marty.ash"; -import "relay/TourGuide/Quests/Meatsmith.ash"; -import "relay/TourGuide/Quests/Intergalaktik.ash"; -import "relay/TourGuide/Quests/Old Landfill.ash"; -import "relay/TourGuide/Quests/Madness Bakery.ash"; -import "relay/TourGuide/Quests/8-bit Realm.ash"; - diff --git a/Source/relay/TourGuide/Quests/Sea.ash b/Source/relay/TourGuide/Quests/Sea.ash deleted file mode 100644 index 491262a2..00000000 --- a/Source/relay/TourGuide/Quests/Sea.ash +++ /dev/null @@ -1,731 +0,0 @@ -//merkinQuestPath - -void QSeaInit() -{ - // While in 11,037 leagues under the sea, you want this showing no matter what. - - if (my_path().id != 55){ - //Have they adventured anywhere underwater? - boolean have_adventured_in_relevant_area = false; - foreach l in $locations[the briny deeps, the brinier deepers, the briniest deepests, an octopus's garden,the wreck of the edgar fitzsimmons, the mer-kin outpost, madness reef,the marinara trench, the dive bar,anemone mine, the coral corral, mer-kin elementary school,mer-kin library,mer-kin gymnasium,mer-kin colosseum,the caliginous abyss] { - if (l.turnsAttemptedInLocation() > 0 || my_location() == l) { - have_adventured_in_relevant_area = true; - break; - } - } - //don't list the quest unless they've started on the path under the sea: - if (!have_adventured_in_relevant_area && $items[Mer-kin trailmap,Mer-kin lockkey,Mer-kin stashbox,wriggling flytrap pellet,damp old boot,Grandma's Map,Grandma's Chartreuse Yarn,Grandma's Fuchsia Yarn,Grandma's Note,black glass].available_amount() == 0) - return; - } - - - if (true) { - QuestState state; - - state.state_string["path"] = get_property("merkinQuestPath"); - if (state.state_string["path"] == "done") - QuestStateParseMafiaQuestPropertyValue(state, "finished"); - else - QuestStateParseMafiaQuestPropertyValue(state, "started"); - - state.quest_name = "Sea Quest"; - state.image_name = "Sea"; - - boolean have_crappy_disguise = have_outfit_components("Crappy Mer-kin Disguise"); - state.state_boolean["have scholar disguise"] = have_outfit_components("Mer-kin Scholar's Vestments"); - state.state_boolean["have gladiator disguise"] = have_outfit_components("Mer-kin Gladiatorial Gear"); - state.state_boolean["can fight dad sea monkee"] = $items[Goggles of Loathing,Stick-Knife of Loathing,Scepter of Loathing,Jeans of Loathing,Treads of Loathing,Belt of Loathing,Pocket Square of Loathing].items_missing().count() <= 1; - state.state_boolean["have one outfit"] = have_crappy_disguise || state.state_boolean["have scholar disguise"] || state.state_boolean["have gladiator disguise"]; - - __quest_state["Sea Temple"] = state; - } - if (true) { - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questS02Monkees"); - state.quest_name = "Hey, Hey, They're Sea Monkees"; - state.image_name = "Sea Monkey Castle"; - - if (get_property_boolean("mapToTheSkateParkPurchased")) - state.state_string["skate park status"] = get_property("skateParkStatus"); //"", "war", "ice", "roller", "peace" - - - __quest_state["Sea Monkees"] = state; - } -} - -void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name, QuestState temple_quest_state) -{ - string temple_path = temple_quest_state.state_string["path"]; - boolean can_fight_dad_sea_monkee = temple_quest_state.state_boolean["can fight dad sea monkee"]; - boolean have_any_outfit = temple_quest_state.state_boolean["have one outfit"] || temple_quest_state.state_boolean["can fight dad sea monkee"]; - - if (!have_any_outfit) { - subentry.entries.listAppend("Acquire crappy mer-kin disguise from grandma sea monkee."); - return; - } - - boolean at_boss = false; - boolean at_gladiator_boss = false; - boolean at_scholar_boss = false; - if (temple_path == "gladiator") { - image_name.s = "Shub-Jigguwatt"; - at_gladiator_boss = true; - } else if (temple_path == "scholar") { - image_name.s = "Yog-Urt"; - at_scholar_boss = true; - } - at_boss = at_gladiator_boss || at_scholar_boss; - - if (!at_boss || at_gladiator_boss) { - string [int] description; - string [int] modifiers; - //gladiator: - if (at_gladiator_boss) { - description.listAppend("Buff muscle, equip a powerful weapon."); - description.listAppend("Delevel him for a bit, then attack with your weapon."); - if ($item[crayon shavings].available_amount() > 0) description.listAppend("|*Your crayon shavings are great for this!"); - description.listAppend("Make sure not to have anything along that will attack him. (familiars, etc)"); - //umm... this probably won't be updated: - string [int] things_to_do; - foreach it in $items[hand in glove,MagiMechTech NanoMechaMech,bottle opener belt buckle,old school calculator watch,ant hoe,ant pick,ant pitchfork,ant rake,ant sickle,fishy wand,moveable feast,oversized fish scaler,replica plastic pumpkin bucket,plastic pumpkin bucket,tiny bowler,cup of infinite pencils,double-ice box,smirking shrunken head,mr. haggis,stapler bear,dubious loincloth,muddy skirt,bottle of Goldschnöckered,acid-squirting flower,ironic oversized sunglasses,hippy protest button,cannonball charrrm bracelet,groovy prism necklace,spiky turtle shoulderpads,double-ice cap,parasitic headgnawer,eelskin hat,balloon shield,hot plate,Ol' Scratch's stove door,Oscus's garbage can lid,eelskin shield,eelskin pants] { - if (it.equipped_amount() > 0) - things_to_do.listAppend("unequip " + it); - } - foreach e in $effects[Skeletal Warrior,Skeletal Cleric,Skeletal Wizard,Bone Homie,Burning\, Man,Biologically Shocked,EVISCERATE!,Fangs and Pangs,Permanent Halloween,Curse of the Black Pearl Onion,Long Live GORF,Apoplectic with Rage,Dizzy with Rage,Quivering with Rage,Jabañero Saucesphere,Psalm of Pointiness,Drenched With Filth,Stuck-Up Hair,It's Electric!,Smokin',Jalapeño Saucesphere,Scarysauce,spiky shell] { - if (e.have_effect() > 0) - things_to_do.listAppend("uneffect " + e); - } - if (things_to_do.count() > 0) - description.listAppend(HTMLGenerateSpanFont(things_to_do.listJoinComponents(", ", "and").capitaliseFirstLetter() + ".", "red")); - - if ($item[dark porquoise ring].equipped_amount() == 0) { - string line = "Possibly "; - if ($item[dark porquoise ring].available_amount() == 0) - line += "acquire and "; - line += "equip a dark porquoise ring to use fewer delevelers."; - description.listAppend(line); - } - if ($effect[Ruthlessly Efficient].have_effect() == 0) { - if ($skill[Ruthless Efficiency].have_skill()) { - description.listAppend("Possibly cast Ruthless Efficiency to delevel faster."); - } else if ($item[Crimbot ROM: Ruthless Efficiency (dirty)].available_amount() > 0) { - description.listAppend("Possibly use Crimbot ROM: Ruthless Efficiency (dirty) and cast it to delevel faster."); - } else if ($item[Crimbot ROM: Ruthless Efficiency].available_amount() > 0) { - description.listAppend("Possibly use Crimbot ROM: Ruthless Efficiency and cast it to delevel faster."); - } - } - if (my_mp() > 0) - description.listAppend(HTMLGenerateSpanFont("Try to reduce your MP to 0", "red") + " before fighting him."); - } else { - if (!temple_quest_state.state_boolean["have gladiator disguise"]) { - description.listAppend("Acquire gladiatorial outfit.|Components can be found by running +combat in the gymnasium.|Make the outfit with grandma."); - modifiers.listAppend("+combat"); - } else { - string shrap_suggestion = "Shrap is nice for this."; - if (!$skill[shrap].skill_is_usable()) { - if ($item[warbear metalworking primer (used)].available_amount() > 0) { - shrap_suggestion += " (use your used copy of warbear metalworking primer)"; - } else - shrap_suggestion += " (from warbear metalworking primer)"; - } - modifiers.listAppend("spell damage percent"); - modifiers.listAppend("mysticality"); - description.listAppend("Fight in the colosseum!"); - description.listAppend("Easy way is to buff mysticality and spell damage percent, then cast powerful spells.
" + shrap_suggestion); - description.listAppend("There's another way, but it's a bit complicated. Check the wiki?"); - - if (get_property("lastColosseumRoundWon") != "") { //backwards compatibility - int colosseum_round = get_property_int("lastColosseumRoundWon"); - int enemy_level = colosseum_round / 3; - string enemy_type, counter_weapon, counter_weapon_property; - - switch (colosseum_round % 3) { - case 0: - //missing the net GAIN cue: 1 turn of Gutballed (-300% muscle) - //missing the net LOSS cue: increase... monster level..? - //missing the net NEUTRALITY cue: reduces every future incoming damage to 1, for a few rounds - enemy_type = (enemy_level > 3 ? "Georgepaul, the B" : "a mer-kin b") + "alldodger"; - counter_weapon = "Mer-kin dragnet"; - counter_weapon_property = "gladiatorNetMovesKnown"; - break; - case 1: - //missing the blade SLING cue: heals - //missing the blade ROLLER ("rolls") cue: 1 turn of Nettled (-300% moxie) - //missing the blade RUNNER cue: hits for 1/2 of you max HP - enemy_type = (enemy_level > 3 ? "Johnringo, the N" : "a mer-kin n") + "etdragger"; - counter_weapon = "Mer-kin switchblade"; - counter_weapon_property = "gladiatorBladeMovesKnown"; - break; - case 2: - //missing the ball BUST cue: reflects all damage for a few rounds - //missing the ball SWEAT cue: increase attack? shrug off delevels? - //missing the ball SACK cue: unequips your weapon - enemy_type = (enemy_level > 3 ? "Ringogeorge, the B" : "a mer-kin b") + "ladeswitcher"; - counter_weapon = "Mer-kin dodgeball"; - counter_weapon_property = "gladiatorBallMovesKnown"; - break; - } - int colosseum_skills_known = get_property_int(counter_weapon_property); - - description.listAppend("Next fight is against " + enemy_type + "."); - if (counter_weapon.to_item().equipped_amount() == 0 && colosseum_skills_known > 0 && enemy_level > 0) - description.listAppend("Equip your " + counter_weapon + (colosseum_skills_known == 3 ? "." : "..?")); - //could be developped more? - } - - //if ($item[Mer-kin gladiator mask].equipped_amount() == 0 || $item[Mer-kin gladiator tailpiece].equipped_amount() == 0) - //description.listAppend("Equip the Mer-kin Gladiatorial Gear."); - } - } - string modifier_string = ""; - if (modifiers.count() > 0) - modifier_string = ChecklistGenerateModifierSpan(modifiers); - if (description.count() > 0) - subentry.entries.listAppend("Gladiator path" + HTMLGenerateIndentedText(modifier_string + description.listJoinComponents("
"))); - } - if (!at_boss || at_scholar_boss) { - string [int] description; - string [int] modifiers; - //scholar: - if (at_scholar_boss) { - description.listAppend("Wear several mer-kin prayerbeads and possibly a mer-kin gutgirdle."); - description.listAppend("Avoid wearing any +hp gear or buffs. Ideally, you want low HP."); - description.listAppend("Each round, use a different healing item, until you lose the Suckrament effect.
After that, your stats are restored. Fully heal, then " + HTMLGenerateSpanOfClass("attack with elemental damage", "r_bold") + "."); - string [item] potential_healers; - potential_healers[$item[mer-kin healscroll]] = "mer-kin healscroll (full HP)"; - potential_healers[$item[scented massage oil]] = "scented massage oil (full HP)"; - potential_healers[$item[soggy used band-aid]] = "soggy used band-aid (full HP)"; - potential_healers[$item[sea gel]] = "sea gel (+500 HP)"; - potential_healers[$item[waterlogged scroll of healing]] = "waterlogged scroll of healing (+250 HP)"; - potential_healers[$item[extra-strength red potion]] = "extra-strength red potion (+200 HP)"; - potential_healers[$item[red pixel potion]] = "red pixel potion (+100-120 HP)"; - potential_healers[$item[red potion]] = "red potion (+100 HP)"; - potential_healers[$item[filthy poultice]] = "filthy poultice (+80-120 HP)"; - potential_healers[$item[gauze garter]] = "gauze garter (+80-120 HP)"; - potential_healers[$item[green pixel potion]] = "green pixel potion (+40-60 HP)"; - potential_healers[$item[cartoon heart]] = "cartoon heart (40-60 HP)"; - potential_healers[$item[red plastic oyster egg]] = "red plastic oyster egg (+35-40 HP)"; - string [int] description_healers; - - foreach it in potential_healers { - if (it.item_amount() > 0) - description_healers.listAppend(potential_healers[it]); - else - description_healers.listAppend(HTMLGenerateSpanFont(potential_healers[it], "red")); - } - description.listAppend("Potential healing items:|*" + description_healers.listJoinComponents("|*")); - } else { - if (!temple_quest_state.state_boolean["have scholar disguise"]) { - description.listAppend("Acquire scholar outfit.|Components can be found by running -combat in the elementary school.|Make the outfit with grandma."); - modifiers.listAppend("-combat"); - } else { - if ($item[Mer-kin dreadscroll].available_amount() == 0) { - description.listAppend("Adventure in the library. Find the dreadscroll."); - modifiers.listAppend("-combat"); - } else { - if ($effect[deep-tainted mind].have_effect() > 0) - description.listAppend("Solve the dreadscroll.
Wait for Deep-Tainted Mind to wear off."); - else - description.listAppend("Solve the dreadscroll."); - - string [int] unknown_clues; - - /* - Mer-kin Library 1 -> dreadScroll1 - Mer-kin healscroll -> dreadScroll2 - Deep Dark Visions -> dreadScroll3 - Mer-kin knucklebone -> dreadScroll4 - Mer-kin killscroll -> dreadScroll5 - Mer-kin Library 2 -> dreadScroll6 - Mer-kin worktea -> dreadScroll7 - Mer-kin Library 3 -> dreadScroll8 - */ - - int known_clue_count = 0; - boolean [int] known_clues; - int library_clues_known = 0; - for i from 1 to 8 { - string property_name = "dreadScroll" + i; - int property_value = get_property_int(property_name); - - if (property_value >= 1 && property_value <= 4) { - known_clue_count += 1; - known_clues[i] = true; - - if (i == 1 || i == 6 || i == 8) - library_clues_known += 1; - } - } - - boolean need_to_learn_vocabulary = false; - - if (library_clues_known < 3) { - unknown_clues.listAppend((3 - library_clues_known).int_to_wordy().capitaliseFirstLetter() + " non-combats in the library. (vocabulary)"); - need_to_learn_vocabulary = true; - } - if (!known_clues[5]) { - unknown_clues.listAppend("Use a mer-kin killscroll in combat. (vocabulary)"); - need_to_learn_vocabulary = true; - } - if (!known_clues[2]) { - unknown_clues.listAppend("Use a mer-kin healscroll in combat. (vocabulary)"); - need_to_learn_vocabulary = true; - } - if (!known_clues[4]) - unknown_clues.listAppend("Use a mer-kin knucklebone."); - if (!known_clues[3]) - unknown_clues.listAppend("Cast deep dark visions."); - if (!known_clues[7]) - unknown_clues.listAppend("Eat sushi with mer-kin worktea."); - - if (unknown_clues.count() > 0) - description.listAppend("Clues are from:|*-" + unknown_clues.listJoinComponents("|*-")); - - if (need_to_learn_vocabulary) { - int vocabulary = get_property_int("merkinVocabularyMastery"); - if (vocabulary < 100) { - int word_quizzes_needed = clampi(10 - vocabulary / 10, 1, 10); - description.listAppend("At " + (vocabulary) + "% Mer-Kin vocabulary. (use " + pluralise(word_quizzes_needed, $item[mer-kin wordquiz]) + " with a mer-kin cheatsheet)"); - } else - description.listAppend("Mer-Kin vocabulary mastered."); - } - if (known_clue_count > 0) { - if (known_clue_count == 8) - description.listAppend("Have all clues."); - else - description.listAppend("Have " + known_clue_count + " out of 8 clues."); - } - } - } - } - string modifier_string = ""; - if (modifiers.count() > 0) - modifier_string = ChecklistGenerateModifierSpan(modifiers); - if (description.count() > 0) - subentry.entries.listAppend("Scholar path" + HTMLGenerateIndentedText(modifier_string + description.listJoinComponents("
"))); - } - if (!at_boss && can_fight_dad_sea_monkee) { - string [int] description; - - description.listAppend("Equip Clothing of Loathing, go to the temple."); - description.listAppend("Cast 120MP hobopolis spells at him."); - description.listAppend("Use Mafia's \"dad\" GCLI command to see which element to use which round."); - if (my_mp() < 1200) - description.listAppend("Will need 1200MP, or less if using shrap/volcanometeor showeruption."); - - string [int] modifiers_needed_150; - foreach s in $stats[] { - if (s.my_basestat() < 150) - modifiers_needed_150.listAppend((150 - s.my_basestat()) + " more " + s.to_lower_case()); - } - - if (modifiers_needed_150.count() > 0) - description.listAppend("Need " + modifiers_needed_150.listJoinComponents(", ", "and") + " to wear Clothing of Loathing."); - - if (description.count() > 0) - subentry.entries.listAppend("Dad sea monkee path" + HTMLGenerateIndentedText(description.listJoinComponents("
"))); - } - - item [class] class_to_scholar_item; - item [class] class_to_gladiator_item; - - class_to_scholar_item[$class[seal clubber]] = $item[Cold Stone of Hatred]; - class_to_scholar_item[$class[turtle tamer]] = $item[Girdle of Hatred]; - class_to_scholar_item[$class[pastamancer]] = $item[Staff of Simmering Hatred]; - class_to_scholar_item[$class[sauceror]] = $item[Pantaloons of Hatred]; - class_to_scholar_item[$class[disco bandit]] = $item[Fuzzy Slippers of Hatred]; - class_to_scholar_item[$class[accordion thief]] = $item[Lens of Hatred]; - - class_to_gladiator_item[$class[seal clubber]] = $item[Ass-Stompers of Violence]; - class_to_gladiator_item[$class[turtle tamer]] = $item[Brand of Violence]; - class_to_gladiator_item[$class[pastamancer]] = $item[Novelty Belt Buckle of Violence]; - class_to_gladiator_item[$class[sauceror]] = $item[Lens of Violence]; - class_to_gladiator_item[$class[disco bandit]] = $item[Pigsticker of Violence]; - class_to_gladiator_item[$class[accordion thief]] = $item[Jodhpurs of Violence]; - - item scholar_item = class_to_scholar_item[my_class()]; - item gladiator_item = class_to_gladiator_item[my_class()]; - - if (!at_boss) { - string line = "Can acquire " + scholar_item + " (scholar) or " + gladiator_item + " (gladiator)"; - if (can_fight_dad_sea_monkee) - line += " or " + $item[pocket square of loathing] + " (dad)"; - subentry.entries.listAppend(line); - } else if (at_gladiator_boss) - subentry.entries.listAppend("Will acquire " + gladiator_item + "."); - else if (at_scholar_boss) - subentry.entries.listAppend("Will acquire " + scholar_item + "."); -} - -//Hmm. Possibly show taffy in resources, if they're under the sea? - -void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState temple_quest_state = __quest_state["Sea Temple"]; - QuestState monkees_quest_state = __quest_state["Sea Monkees"]; - - if (!__misc_state["in aftercore"] && !monkees_quest_state.started || temple_quest_state.quest_name == "") - return; - - //Will have 4 possible tiles. 1 is the main questline, and always appear, and the 3 others only appear once they diverge from the main questline (if unfinished, of course) - //Tile 1 is the old man's boot (first since needs no adventuring once diverged). Diverges from the main questline when freeing big brother. - //Tile 2 is the main questline, which goes up to the Mer-Kin temple boss(es). (in other words, main questline = mer-kin questline, with all of its prerequisites) - //Tile 3 is the sea monkey questline (ends with finding Mom sea monkey). Diverges from the main questline when asking grandpa about grandma. - //Tile 4 is the skate park. Diverges from the main questline when freeing big brother. Only shows once you buy the map to the skate park. - - //Tile 1 - if (get_property("questS01OldGuy") != "finished" && monkees_quest_state.mafia_internal_step >= 3) { - string url, title, modifiers; - string [int] description; - if (get_property_boolean("dampOldBootPurchased")) { - url = "place.php?whichplace=sea_oldman"; - title = "Return damp old boot to the old man"; - if ($item[fishy pipe].available_amount() == 0) - description.listAppend("Choose the fishy pipe."); - else if ($item[das boot].available_amount() == 0) - description.listAppend("Choose the das boot."); - else - description.listAppend("Choose the damp old wallet."); - } else { - url = "monkeycastle.php?who=2"; - title = "Buy the old man's boot from Big Brother"; - modifiers = "50 sand dollars"; - int sand_dollars = $item[sand dollar].item_amount(); - if (sand_dollars < 50) - description.listAppend("Have " + sand_dollars.pluralise("sand dollar", "sand dollars") + " on hand."); - } - optional_task_entries.listAppend(ChecklistEntryMake("__item damp old boot", url, ChecklistSubentryMake(title, modifiers, description)).ChecklistEntrySetIDTag("Sea old man boot quest")); - } - - - //Tiles 2, 3 and 4 all want fishy, but we don't want to put the full notification in each of them. So instead, we initialize the 3 ChecklistSubentries here, add the general reminder to all of them, and add the how_to to the first that will be displayed. - ChecklistSubentry temple_subentry, sea_monkey_subentry, skate_park_subentry; - - boolean should_output_temple_questline = !temple_quest_state.finished; - boolean should_output_sea_monkey_questline = !monkees_quest_state.finished && monkees_quest_state.mafia_internal_step >= 7; - - string get_fishy, how_to_get_fishy; - if ($effect[fishy].have_effect() == 0) { - get_fishy = "Acquire fishy."; - how_to_get_fishy = "|*Easy way: Lucky adventure in the brinier deeps, 20 turns."; - if ($item[fishy pipe].available_amount() > 0 && !get_property_boolean("_fishyPipeUsed")) - how_to_get_fishy += "|*Use fishy pipe."; - if (monkees_quest_state.state_string["skate park status"] == "ice" && !get_property_boolean("_skateBuff1")) - how_to_get_fishy += "|*Visit Lutz at the Skate Park."; - - if (should_output_temple_questline) { - temple_subentry.entries.listAppend(get_fishy + how_to_get_fishy); - sea_monkey_subentry.entries.listAppend(get_fishy); - skate_park_subentry.entries.listAppend(get_fishy); - } else if (should_output_sea_monkey_questline) { - sea_monkey_subentry.entries.listAppend(get_fishy + how_to_get_fishy); - skate_park_subentry.entries.listAppend(get_fishy); - } else - skate_park_subentry.entries.listAppend(get_fishy + how_to_get_fishy); - } - - - //Tile 2 - string image_name = temple_quest_state.image_name; - string url = "seafloor.php"; - - temple_subentry.header = temple_quest_state.quest_name; - boolean need_minus_combat_modifier = false; - - - if (should_output_temple_questline) { - if (get_property("seahorseName").length() == 0) { - boolean professional_roper = false; - //merkinLockkeyMonster questS01OldGuy questS02Monkees - //Need to reach the temple: - if (get_property("lassoTraining") != "expertly") { - string line; - if ($item[sea lasso].item_amount() == 0) - line += HTMLGenerateSpanFont((in_ronin() ? "Acquire" : "Buy") + " and use a sea lasso in each combat.", "red"); - else - line += "Use a sea lasso in each combat."; - if ($item[sea cowboy hat].equipped_amount() == 0) - line += "|*Wear a sea cowboy hat to improve roping."; - if ($item[sea chaps].equipped_amount() == 0) - line += "|*Wear sea chaps to improve roping."; - temple_subentry.entries.listAppend(line); - } else { - professional_roper = true; - string line; - if ($item[sea lasso].item_amount() == 0) - line += "Buy a sea lasso."; - if ($item[sea cowbell].item_amount() < 3) { - int needed_amount = MAX(3 - $item[sea cowbell].item_amount(), 0); - if (line != "") line += " "; - line += "Buy " + pluraliseWordy(needed_amount, "sea cowbell", "sea cowbells") + "."; - } - if (line != "") - temple_subentry.entries.listAppend(line); - } - location class_grandpa_location; - if (my_primestat() == $stat[muscle]) - class_grandpa_location = $location[Anemone Mine]; - if (my_primestat() == $stat[mysticality]) - class_grandpa_location = $location[The Marinara Trench]; - if (my_primestat() == $stat[moxie]) - class_grandpa_location = $location[the dive bar]; - - int grandpa_ncs_remaining = 3; - - //Match NC names to prevent other NCs interfering with tracking: - int [string] noncombat_names; - noncombat_names["Lost and Found and Lost Again"] = 2; - noncombat_names["Respect Your Elders"] = 1; - noncombat_names["You've Hit Bottom"] = 0; - noncombat_names["Kids Today"] = 1; - noncombat_names["Not a Micro Fish"] = 0; - noncombat_names["No Country Music for Old Men"] = 2; - noncombat_names["Salty Old Men"] = 1; - noncombat_names["Boxing the Juke"] = 0; - noncombat_names["Bar Hunting"] = 2; - noncombat_names["The Salt of the Sea"] = 1; - noncombat_names["Ode to the Sea"] = 0; - foreach nc in noncombat_names { - if (class_grandpa_location.noncombat_queue.contains_text(nc)) - grandpa_ncs_remaining = MIN(grandpa_ncs_remaining, noncombat_names[nc]); - } - - //Detect where we are: - //This won't work beyond talking to little brother, my apologies (fixed since) - if (get_property_boolean("corralUnlocked") || $location[the coral corral].turnsAttemptedInLocation() > 0) { - //Coral corral. Banish strategy. - string sea_horse_details; - if (!professional_roper) - sea_horse_details = HTMLGenerateSpanFont("|But first, train up your roping skills.", "red"); - else - sea_horse_details = "|Once found, use three sea cowbells on him, then a sea lasso."; - temple_subentry.entries.listAppend("Look for your sea horse in the Coral Corral." + sea_horse_details); - string [int] banish_monsters; - monster [int] monster_list = $location[the coral corral].get_monsters(); - foreach key in monster_list { - monster m = monster_list[key]; - if (!m.is_banished() && m != $monster[wild seahorse]) - banish_monsters.listAppend(m.to_string()); - } - if (banish_monsters.count() > 1) - temple_subentry.entries.listAppend("Banish " + banish_monsters.listJoinComponents(", ", "and") + " with separate banish sources to speed up area."); - } else if (monkees_quest_state.mafia_internal_step >= 7 || $location[the mer-kin outpost].turnsAttemptedInLocation() > 0) { - //Find lockkey as well. - //Then stash box. Mention monster source. - //Use trailmap. - //Ask grandpa about currents. - if ($item[Mer-kin trailmap].available_amount() > 0) { - temple_subentry.entries.listAppend("Use Mer-kin trailmap."); - } else if ($item[Mer-kin stashbox].available_amount() > 0) { - temple_subentry.entries.listAppend("Open stashbox."); - } else if ($item[Mer-kin lockkey].available_amount() > 0) { - string nc_details = ""; - monster lockkey_monster = get_property_monster("merkinLockkeyMonster"); - if (lockkey_monster == $monster[Mer-kin burglar]) { - nc_details = "Stashbox is in the camouflaged tent."; - } else if (lockkey_monster == $monster[Mer-kin raider]) { - nc_details = "Stashbox is in the skull-bedecked tent."; - } else if (lockkey_monster == $monster[Mer-kin healer]) { - nc_details = "Stashbox is in the glyphed tent."; - } - - need_minus_combat_modifier = true; - temple_subentry.entries.listAppend("Adventure in the Mer-Kin outpost, find non-combat.|" + nc_details); - } else { - temple_subentry.entries.listAppend("Adventure in the Mer-Kin outpost to acquire a lockkey."); - temple_subentry.entries.listAppend("Unless you discovered the currents already (can't tell), in which case go ask grandpa about currents."); - } - } else if (monkees_quest_state.mafia_internal_step == 6 || grandpa_ncs_remaining == 0) { - url = "monkeycastle.php?who=3"; - temple_subentry.entries.listAppend("Ask grandpa about his wife to unlock the Mer-Kin outpost."); - } else if (monkees_quest_state.mafia_internal_step == 5 || class_grandpa_location.turnsAttemptedInLocation() > 0) { - //Find grandpa in one of the three zones. - need_minus_combat_modifier = true; - temple_subentry.entries.listAppend("Find grandpa sea monkee in " + class_grandpa_location + ".|" + pluraliseWordy(grandpa_ncs_remaining, "non-combat remains", "non-combats remain").capitaliseFirstLetter() + "."); - if(grandpa_ncs_remaining == 3) temple_subentry.entries.listAppend("|*Make sure you talk to little brother, too; the quest only starts when you talk to him!"); - } else if (monkees_quest_state.mafia_internal_step == 4) { - //Talk to little brother. - temple_subentry.entries.listAppend("Talk to little brother."); - url = "monkeycastle.php"; - } else if (monkees_quest_state.mafia_internal_step == 3) { - //Talk to big brother. - temple_subentry.entries.listAppend("Talk to big brother."); - url = "monkeycastle.php"; - } else if (monkees_quest_state.mafia_internal_step == 2 || $location[The Wreck of the Edgar Fitzsimmons].turnsAttemptedInLocation() > 0) { - //Adventure in wreck, free big brother. - need_minus_combat_modifier = true; - temple_subentry.entries.listAppend("Free big brother. Adventure in the wreck.|Then talk to him and little brother, find grandpa."); - } else if (monkees_quest_state.mafia_internal_step == 1) { - if ($item[wriggling flytrap pellet].available_amount() > 0) { - url = "inventory.php?ftext=wriggling+flytrap+pellet"; - temple_subentry.entries.listAppend("Open a wriggling flytrap pellet, talk to little brother."); - } else { - //Talk to little brother - temple_subentry.entries.listAppend("Talk to little brother."); - url = "monkeycastle.php"; - } - } else { - //Octopus's garden, obtain wriggling flytrap pellet - if ($item[wriggling flytrap pellet].available_amount() == 0) { - temple_subentry.entries.listAppend("Adventure in octopus's garden, find a wriggling flytrap pellet from a Neptune flytrap."); - temple_subentry.modifiers.listAppend("olfact Neptune flytrap"); - } else { - url = "inventory.php?ftext=wriggling+flytrap+pellet"; - temple_subentry.entries.listAppend("Open a wriggling flytrap pellet, talk to little brother."); - } - } - - //Find grandma IF they don't have a disguise/cloathing. - } else { - url = "seafloor.php?action=currents"; - StringHandle image_name_handle; - image_name_handle.s = image_name; - QSeaGenerateTempleEntry(temple_subentry, image_name_handle, temple_quest_state); - image_name = image_name_handle.s; - } - } - - if (need_minus_combat_modifier) - temple_subentry.modifiers.listAppend("-combat"); - - if (should_output_temple_questline) - optional_task_entries.listAppend(ChecklistEntryMake(image_name, url, temple_subentry, $locations[the brinier deepers, an octopus's garden,the wreck of the edgar fitzsimmons, the mer-kin outpost, madness reef,the marinara trench, the dive bar,anemone mine, the coral corral, mer-kin elementary school,mer-kin library,mer-kin gymnasium,mer-kin colosseum,the caliginous abyss]).ChecklistEntrySetIDTag("Sea mer-kin main quest")); - - - //Tile 3 - url = "seafloor.php"; - boolean [location] relevant_locations = {$location[the caliginous abyss]:true}; - - sea_monkey_subentry.header = monkees_quest_state.quest_name; - need_minus_combat_modifier = false; - - - if (should_output_sea_monkey_questline) { - if (monkees_quest_state.mafia_internal_step == 13) { - //Have black glass; only need to find mom. No progress tracking yet (the progress mechanic for this zone is not yet fully understood...) - string line; - line += "Adventure in the Caliginous Abyss. Find Mom Sea Monkey."; - if ($item[shark jumper].equipped_amount() == 0) - line += "|*Wear a shark jumper to speed up area."; - if ($item[scale-mail underwear].equipped_amount() == 0) - line += "|*Wear a scale-mail underwear to speed up area."; - if ($effect[Jelly Combed].have_effect() == 0) - line += "|*Use a Comb jelly to speed up area."; - - sea_monkey_subentry.entries.listAppend(line); - - if ($item[black glass].equipped_amount() == 0) { - url = "inventory.php?ftext=black+glass"; - sea_monkey_subentry.entries.listAppend("Equip the black glass."); - } - } else if (monkees_quest_state.mafia_internal_step == 12) { - url = "monkeycastle.php?who=2"; - sea_monkey_subentry.modifiers.listAppend("13 sand dollars"); - sea_monkey_subentry.entries.listAppend('"Buy" the black glass from big brother. Will get a full refund.'); - - int sand_dollars = $item[sand dollar].item_amount(); - if (sand_dollars < 13) - sea_monkey_subentry.entries.listAppend("Have " + sand_dollars.pluralise("sand dollar", "sand dollars") + " on hand."); - } else if (monkees_quest_state.mafia_internal_step == 11) { - //Discover the existence of the black glass - url = "monkeycastle.php"; - sea_monkey_subentry.entries.listAppend("Talk to big brother."); - } else if (monkees_quest_state.mafia_internal_step == 10) { - //Lil' bro caught big bro acting weird, and it's not linked to puberty... - url = "monkeycastle.php"; - sea_monkey_subentry.entries.listAppend("Talk to little brother."); - } else if (monkees_quest_state.mafia_internal_step == 9) { - //assembled grandma's map, now to find her - need_minus_combat_modifier = true; - relevant_locations[$location[the mer-kin outpost]] = true; - sea_monkey_subentry.entries.listAppend("Adventure at the mer-kin outpost, find grandma."); - } else if (monkees_quest_state.mafia_internal_step == 8 || !temple_quest_state.state_boolean["have one outfit"] && monkees_quest_state.mafia_internal_step == 7) { - //7=unlocked outpost, but didn't find grandma's note. 8=found grandma's note - string line = "Optionally, rescue grandma.|"; - item [int] missing_items = $items[Grandma's Chartreuse Yarn,Grandma's Fuchsia Yarn,Grandma's Note].items_missing(); - - if (missing_items.count() == 0) { - url = "monkeycastle.php?who=3"; - line += "Ask grandpa about the note."; - } else { - need_minus_combat_modifier = true; - relevant_locations[$location[the mer-kin outpost]] = true; - line += "Adventure at the mer-kin outpost, find " + missing_items.listJoinComponents(", ", "and") + "."; - } - sea_monkey_subentry.entries.listAppend(line); - } else - should_output_sea_monkey_questline = false; - } - - if (need_minus_combat_modifier) - sea_monkey_subentry.modifiers.listAppend("-combat"); - - if (should_output_sea_monkey_questline) - optional_task_entries.listAppend(ChecklistEntryMake(monkees_quest_state.image_name, url, sea_monkey_subentry, relevant_locations).ChecklistEntrySetIDTag("Sea monkey branch quest")); - - - //Tile 4 - if (monkees_quest_state.state_string["skate park status"] == "war") { //map purchased, and conflict still ongoing - skate_park_subentry.header = "Sea Side Story"; - skate_park_subentry.modifiers.listAppend("-combat"); - - int [item] skate_park_ncs_progress = { $item[skate blade]:0, $item[brand new key]:0, $item[skate board]:0 }; - - //Match NC names to prevent other NCs interfering with tracking: - int [item] [string] noncombat_names; - noncombat_names[$item[skate blade]]["Prayer of the Roller Skates"] = 1; - noncombat_names[$item[skate blade]]["Rollerbawl"] = 2; - noncombat_names[$item[skate blade]]["Holey Rollers"] = 3; //park now ice - noncombat_names[$item[brand new key]]["The Onbringing"] = 1; - noncombat_names[$item[brand new key]]["Choreography Amongst the Coral"] = 2; - noncombat_names[$item[brand new key]]["The Last of the Ice Skates"] = 3; //park now roller - noncombat_names[$item[skate board]]["A Boarding Party"] = 1; - noncombat_names[$item[skate board]]["A Board of Education"] = 2; - noncombat_names[$item[skate board]]["A Boarding Pass"] = 3; //park now peace - foreach faction_weapon, nc in noncombat_names { - if ($location[The Skate Park].noncombat_queue.contains_text(nc)) - skate_park_ncs_progress[faction_weapon] = MAX(skate_park_ncs_progress[faction_weapon], noncombat_names[faction_weapon][nc]); - } - - int highest_progress_seen; - item [int] factions_at_highest_progress; - - foreach faction_weapon, faction_progress in skate_park_ncs_progress { - if (faction_progress >= highest_progress_seen && faction_progress > 0) { - if (faction_progress > highest_progress_seen) { - factions_at_highest_progress.listClear(); - highest_progress_seen = faction_progress; - } - factions_at_highest_progress.listAppend(faction_weapon); - } - } - - string [int] factions; - - foreach faction_weapon, faction_progress in skate_park_ncs_progress { - string line; - - line += "• Use a " + faction_weapon.name + " for "; - - if (faction_weapon == $item[skate blade]) - line += "Fishy"; - else if (faction_weapon == $item[brand new key]) - line += "-30% pressure penalty (not recommended)"; - else if (faction_weapon == $item[skate board]) - line += "1 sand dollar/combat, +25% item drop and +10 fam weight (all 3 apply in underwater zones only)"; - - if (faction_weapon.equipped_amount() > 0 && $slot[weapon].equipped_item() != faction_weapon) - line += "
" + HTMLGenerateSpanFont("Weapon needs to be in your " + (faction_weapon.weapon_hands() > 1 ? "HANDS" : "MAIN-hand"), "red"); - - factions.listAppend(line.HTMLGenerateSpanFont(highest_progress_seen > 0 && highest_progress_seen > faction_progress && faction_weapon.equipped_amount() == 0 ? "gray" : "dark")); - } - - skate_park_subentry.entries.listAppend("Adventure in A Rumble Near the Fountain with a faction's weapon to unlock (a) daily 30 turns buff(s)." + factions.listJoinComponents("
").HTMLGenerateIndentedText()); - - if (factions_at_highest_progress.count() > 0) - skate_park_subentry.entries.listAppend("At " + highest_progress_seen + "/3 NCs with " + factions_at_highest_progress.listJoinComponents(", ", "and") + (factions_at_highest_progress.count() > 1 ? " (will have to make a decision)" : "") + "."); - - optional_task_entries.listAppend(ChecklistEntryMake("Skate Park", "sea_skatepark.php", skate_park_subentry, $locations[The Skate Park]).ChecklistEntrySetIDTag("Sea skate park war quest")); - } -} diff --git a/Source/relay/TourGuide/Quests/Space Elves.ash b/Source/relay/TourGuide/Quests/Space Elves.ash deleted file mode 100644 index 62a1c9fc..00000000 --- a/Source/relay/TourGuide/Quests/Space Elves.ash +++ /dev/null @@ -1,122 +0,0 @@ -void QSpaceElvesInit() -{ - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questF04Elves"); - - state.quest_name = "Repair the Elves' Shield Generator Quest"; - state.image_name = "spooky little girl"; - - if (my_basestat(my_primestat()) >= 12) - state.startable = true; - - - __quest_state["Space Elves"] = state; -} - - -void QSpaceElvesGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Space Elves"]; - if (base_quest_state.finished) - return; - - string url = "place.php?whichplace=spaaace"; - - boolean turns_spent_in_locations_already = false; - if ($locations[Domed City of Ronaldus,Domed City of Grimacia,Hamburglaris Shield Generator].turnsAttemptedInLocation() > 0) - turns_spent_in_locations_already = true; - - if (!turns_spent_in_locations_already && $effect[transpondent].have_effect() == 0) //suggest it when they go to spaaace, otherwise, don't bug them? - return; - if (in_ronin() && $effect[transpondent].have_effect() == 0 && $item[transporter transponder].available_amount() == 0) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - subentry.entries.listAppend("Gives 200 lunar isotopes and Elvish Paradise access."); - - if (base_quest_state.mafia_internal_step < 3) - { - string [int] ronald_map_entries; - string [int] grimace_map_entries; - if ($item[e.m.u. rocket thrusters].available_amount() == 0) - ronald_map_entries.listAppend("Ronald map" + __html_right_arrow_character + "Try the Swimming Pool" + __html_right_arrow_character + "To the Left, to the Left" + __html_right_arrow_character + "Take the Red Door"); - if ($item[E.M.U. joystick].available_amount() == 0) - ronald_map_entries.listAppend("Ronald map" + __html_right_arrow_character + "Check out the Armory" + __html_right_arrow_character + "My Left Door" + __html_right_arrow_character + "Crawl through the Ventilation Duct"); - if ($item[E.M.U. harness].available_amount() == 0) - grimace_map_entries.listAppend("Grimace map" + __html_right_arrow_character + "Check out the Coat Check" + __html_right_arrow_character + "Exit, Stage Left" + __html_right_arrow_character + "Be the Duke of the Hazard"); - if ($item[E.M.U. helmet].available_amount() == 0) - grimace_map_entries.listAppend("Grimace map" + __html_right_arrow_character + "Check out the Coat Check" + __html_right_arrow_character + "Stage Right, Even" + __html_right_arrow_character + "Try the Starboard Door"); - if (ronald_map_entries.count() > 0) - { - string header = "Ronald prime:"; - string [int] line; - int maps_needed = ronald_map_entries.count() - $item[map to safety shelter ronald prime].available_amount(); - if (maps_needed > 0) - { - if (subentry.modifiers.count() == 0) - subentry.modifiers.listAppend("+item"); - line.listAppend("Acquire " + pluralise(maps_needed, $item[map to safety shelter ronald prime])); - } - - line.listAppendList(ronald_map_entries); - - - subentry.entries.listAppend(header + HTMLGenerateIndentedText(line.listJoinComponents("
"))); - } - if (grimace_map_entries.count() > 0) - { - string header = "Grimace prime:"; - string [int] line; - int maps_needed = grimace_map_entries.count() - $item[map to safety shelter grimace prime].available_amount(); - if (maps_needed > 0) - { - if (subentry.modifiers.count() == 0) - subentry.modifiers.listAppend("+item"); - line.listAppend("Acquire " + pluralise(maps_needed, $item[map to safety shelter grimace prime])); - } - - line.listAppendList(grimace_map_entries); - subentry.entries.listAppend(header + HTMLGenerateIndentedText(line.listJoinComponents("
"))); - } - if (ronald_map_entries.count() == 0 && grimace_map_entries.count() == 0) - subentry.entries.listAppend("Look for the spooky little girl on Grimacia or Ronaldus."); - //else if ($items[map to safety shelter ronald prime, map to safety shelter grimace prime].available_amount() > 0) - else if ((ronald_map_entries.count() > 0 && $item[map to safety shelter ronald prime].available_amount() > 0) || (grimace_map_entries.count() > 0 && $item[map to safety shelter grimace prime].available_amount() > 0)) - url = "inventory.php?ftext=map+to+safety+shelter"; - } - else if (base_quest_state.mafia_internal_step == 3) - { - if ($item[spooky little girl].equipped_amount() == 0) - subentry.entries.listAppend("Equip spooky little girl."); - else if ($item[spooky little girl].available_amount() == 0) - subentry.entries.listAppend("spooky"); - else - { - subentry.entries.listAppend("Adventure in Grimacia with spooky little girl for eleven turns."); - } - - } - else if (base_quest_state.mafia_internal_step == 4) - { - if ($item[E.M.U. Unit].equipped_amount() == 0) - subentry.entries.listAppend("Equip E.M.U. Unit."); - else - subentry.entries.listAppend("Adventure at the Hamburglaris Shield Generator, solve puzzle."); - } - if ($effect[Transpondent].have_effect() == 0) - { - subentry.entries.listClear(); - subentry.entries.listAppend("Gives 200 lunar isotopes and Elvish Paradise access."); - subentry.entries.listAppend("Use transporter transponder to reach spaaace."); - if ($item[transporter transponder].available_amount() > 0) - url = "inventory.php?ftext=transporter+transponder"; - else - url = "mall.php"; - } - - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[domed city of ronaldus, domed city of grimacia,hamburglaris shield generator]).ChecklistEntrySetIDTag("Space elves generator quest")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Spookyraven Lights Out.ash b/Source/relay/TourGuide/Quests/Spookyraven Lights Out.ash deleted file mode 100644 index 7f712c44..00000000 --- a/Source/relay/TourGuide/Quests/Spookyraven Lights Out.ash +++ /dev/null @@ -1,212 +0,0 @@ -void QSpookyravenLightsOutGenerateEntry(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, boolean from_task) //if from_task is false, assumed to be from resources -{ - //nextSpookyravenElizabethRoom - //nextSpookyravenStephenRoom - - if (get_property_int("lastLightsOutTurn") >= total_turns_played()) - return; - - string next_elizabeth_room = get_property("nextSpookyravenElizabethRoom"); - string next_stephen_room = get_property("nextSpookyravenStephenRoom"); - location next_elizabeth_location = next_elizabeth_room.to_location(); - location next_stephen_location = next_stephen_room.to_location(); - - int turns_until_next_lights_out = -1; - - //Thought about enabling this, but it's better to only show it when they ask for spookyraven tracking, I think... - //then again, spookyraven tracking doesn't work well with automation (auto-aborts, even if adventuring in relevant locations) - //turns_until_next_lights_out = 37 - total_turns_played() % 37; - - Counter lights_out_counter = CounterLookup("Spookyraven Lights Out"); - if (lights_out_counter.CounterExists() && !lights_out_counter.CounterIsRange()) - { - //turns_until_next_lights_out = lights_out_counter.CounterGetNextExactTurn(); //LYING. - turns_until_next_lights_out = 37 - total_turns_played() % 37; - } - - - if (turns_until_next_lights_out == 37) - turns_until_next_lights_out = 0; - - if (turns_until_next_lights_out == -1) - return; - - string url = ""; - - ChecklistSubentry [int] important_subentries; - if (turns_until_next_lights_out == 0 && from_task) - { - //now - if (next_stephen_location != $location[none]) - { - string [location][int] stephen_area_descriptions; - stephen_area_descriptions[$location[The Haunted Bedroom]] = listMake("Search for a light", "Search a nearby nightstand", "Check a nightstand on your left"); - stephen_area_descriptions[$location[The Haunted Nursery]] = listMake("Search for a lamp", "Search over by the (gaaah) stuffed animals", "Examine the Dresser", "Open the bear and put your hand inside", "Unlock the box"); - stephen_area_descriptions[$location[The Haunted Conservatory]] = listMake("Make a torch", "Examine the graves", "Examine the grave marked \"Crumbles\""); - stephen_area_descriptions[$location[The Haunted Billiards Room]] = listMake("Search for a light", "What the heck, let's explore a bit", "Examine the taxidermy heads"); - stephen_area_descriptions[$location[The Haunted Wine Cellar]] = listMake("Try to find a light", "Keep your cool", "Investigate the wine racks", "Examine the Pinot Noir rack"); - stephen_area_descriptions[$location[The Haunted Boiler Room]] = listMake("Look for a light", "Search the barrel", "No, but I will anyway"); - stephen_area_descriptions[$location[The Haunted Laboratory]] = listMake("Search for a light", "Check it out", "Examine the weird machines", "Enter 23-47-99 and turn on the machine", "Oh god"); - - string [int] description; - - string first_line = ""; - if (__misc_state["in run"]) - { - if (__misc_state["familiars temporarily blocked"]) - first_line += "Not useful this run. "; - else - first_line += "Situationally useful (+familiar weight) in-run. "; - } - if (next_stephen_location == $location[The Haunted Laboratory]) - first_line += HTMLGenerateSpanFont("Will take a turn.", "red"); - else - first_line += "Will not take a turn."; - - if (first_line != "") - description.listAppend(first_line); - - string line = "Adventure in " + next_stephen_room; - if (next_stephen_location == $location[The Haunted Laboratory]) - line += " to fight Stephen Spookyraven"; - line += "."; - if (stephen_area_descriptions contains next_stephen_location) - line += "|*" + stephen_area_descriptions[next_stephen_location].listJoinComponents(__html_right_arrow_character) + "."; - description.listAppend(line); - - url = next_stephen_location.getClickableURLForLocation(); - - important_subentries.listAppend(ChecklistSubentryMake("Stephen Spookyraven Quest", "", description)); - } - - - if (next_elizabeth_location != $location[none]) - { - string [location][int] elizabeth_area_descriptions; - elizabeth_area_descriptions[$location[The Haunted Storage Room]] = listMake("Look out the Window"); - elizabeth_area_descriptions[$location[The Haunted Laundry Room]] = listMake("Check a Pile of Stained Sheets"); - elizabeth_area_descriptions[$location[The Haunted Bathroom]] = listMake("Inspect the Bathtub"); - elizabeth_area_descriptions[$location[The Haunted Kitchen]] = listMake("Make a Snack"); - elizabeth_area_descriptions[$location[The Haunted Library]] = listMake("Go to the Childrens' Section"); - elizabeth_area_descriptions[$location[The Haunted Ballroom]] = listMake("Dance with Yourself"); - elizabeth_area_descriptions[$location[The Haunted Gallery]] = listMake("Check out the Tormented Damned Souls Painting"); - - string [int] description; - string first_line = ""; - if (__misc_state["in run"]) - first_line += "Not useful in-run. "; - if (next_elizabeth_location == $location[The Haunted Gallery]) - first_line += HTMLGenerateSpanFont("Will take a turn.", "red"); - else - first_line += "Will not take a turn."; - - if (first_line != "") - description.listAppend(first_line); - - string line = "Adventure in " + next_elizabeth_room; - if (next_elizabeth_location == $location[The Haunted Gallery]) - line += " to fight Elizabeth Spookyraven"; - line += "."; - if (elizabeth_area_descriptions contains next_elizabeth_location) - line += "|*" + elizabeth_area_descriptions[next_elizabeth_location].listJoinComponents(__html_right_arrow_character) + "."; - description.listAppend(line); - - - if (url.length() == 0) - url = next_elizabeth_location.getClickableURLForLocation(); - - important_subentries.listAppend(ChecklistSubentryMake("Elizabeth Spookyraven Quest", "", description)); - } - } - else if ((turns_until_next_lights_out < 6 && from_task) || (turns_until_next_lights_out >= 6 && !from_task)) - { - //Soon... - //FIXME should we show this? - string [int] available_questlines; - if (next_stephen_location != $location[none]) - available_questlines.listAppend("Stephen"); - if (next_elizabeth_location != $location[none]) - available_questlines.listAppend("Elizabeth"); - if (available_questlines.count() > 0) - { - optional_task_entries.listAppend(ChecklistEntryMake("__half Lights Out", "", ChecklistSubentryMake("Lights Out in " + pluralise(turns_until_next_lights_out, "adventure", "adventures"), "", available_questlines.listJoinComponents(", ", "and") + " quest " + (available_questlines.count() > 1 ? "lines" : "line") + "."), (from_task ? 5 : 8)).ChecklistEntrySetIDTag("Manor lights out prediction")); //difference if they come from task or not? - } - } - - if (important_subentries.count() > 0) - { - if (url == "place.php?whichplace=manor2" && !get_property_ascension("lastSecondFloorUnlock")) - url = ""; - task_entries.listAppend(ChecklistEntryMake("__half Lights Out", url, important_subentries, -11).ChecklistEntrySetIDTag("Manor lights out now")); - } -} - -void QSpookyravenLightsOutGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QSpookyravenLightsOutGenerateEntry(task_entries, optional_task_entries, true); - - if (get_property_int("lastLightsOutTurn") < total_turns_played() && total_turns_played() % 37 == 0 && __misc_state["in run"]) - { - string [int] exploit_description; - string url = ""; - if (__iotms_usable[$item[haunted doghouse]]) - { - location [int] possible_locations; - boolean [location] all_lights_out_locations; - all_lights_out_locations[$location[the haunted storage room]] = true; - all_lights_out_locations[$location[the haunted Laundry Room]] = true; - //all_lights_out_locations[$location[the haunted Bathroom]] = true; //Very small chance of a demon name, which costs a turn. It happened to me! - all_lights_out_locations[$location[the haunted Kitchen]] = true; - all_lights_out_locations[$location[the haunted Library]] = true; - all_lights_out_locations[$location[the haunted Ballroom]] = true; - all_lights_out_locations[$location[the haunted Gallery]] = true; - if ($location[the haunted Bedroom].turns_spent < 10) - all_lights_out_locations[$location[the haunted Bedroom]] = true; - all_lights_out_locations[$location[the haunted Nursery]] = true; - all_lights_out_locations[$location[the haunted Conservatory]] = true; - all_lights_out_locations[$location[the haunted Billiards Room]] = true; - all_lights_out_locations[$location[the haunted Wine Cellar]] = true; - all_lights_out_locations[$location[the haunted Boiler Room]] = true; - all_lights_out_locations[$location[the haunted Laboratory]] = true; - - foreach l in all_lights_out_locations - { - if (l.combatTurnsAttemptedInLocation() < 5) - continue; - if (l.noncombat_queue.contains_text("Wooooooof!")) - continue; - possible_locations.listAppend(l); - } - if (possible_locations.count() > 0) - { - exploit_description.listAppend("Adventure in " + possible_locations.listJoinComponents(", ", "or") + " to potentially trigger a halloweiner adventure.|It won't cost a turn."); - url = possible_locations[0].getClickableURLForLocation(); - } - } - if ($item[turkey blaster].available_amount() + $item[turkey blaster].creatable_amount() > 0 && availableSpleen() >= 2 && get_property_int("_turkeyBlastersUsed") < 3) - { - location [int] possible_locations; - foreach l in $locations[the haunted gallery,the haunted bathroom] - { - if (l.delayRemainingInLocation() >= 4 && l.locationAvailable()) - { - possible_locations.listAppend(l); - - } - } - if (possible_locations.count() > 0) - { - exploit_description.listAppend("Adventure in " + possible_locations.listJoinComponents(", ", "or") + ", then chew a turkey blaster to burn delay."); - if (url == "") - url = possible_locations[0].getClickableURLForLocation(); - } - } - if (exploit_description.count() > 0) - task_entries.listAppend(ChecklistEntryMake("__half Lights Out", url, ChecklistSubentryMake("Lights Out Exploit", "", exploit_description), -11).ChecklistEntrySetIDTag("Manor lights out suggest exploit")); - } -} - -void QSpookyravenLightsOutGenerateResource(ChecklistEntry [int] resource_entries) -{ - QSpookyravenLightsOutGenerateEntry(resource_entries, resource_entries, false); -} diff --git a/Source/relay/TourGuide/Quests/Subject 37.ash b/Source/relay/TourGuide/Quests/Subject 37.ash deleted file mode 100644 index e59a30a8..00000000 --- a/Source/relay/TourGuide/Quests/Subject 37.ash +++ /dev/null @@ -1,113 +0,0 @@ - -void QSubject37Init() -{ - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questM13Escape"); - - - state.quest_name = "The Pretty Good Escape"; - state.image_name = "__item mysterious silver lapel pin"; - - state.startable = true; - - __quest_state["Subject 37"] = state; -} - - -void QSubject37GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Subject 37"]; - if (!base_quest_state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - string active_url = $location[Cobb's Knob Menagerie, Level 1].getClickableURLForLocation(); - - /* -started Subject 37 wants you to investigate the Cobb's Knob Laboratories and find out what they're planning. -step1 Take the file you found back to Subject 37. -step2 Subject 37 wants something from the BASIC Elementals on level 1 of the Cobb's Knob Menagerie. -step3 Take the GOTO back to Subject 37. -step4 Subject 37 wants some weremoose spit from level 2 of the Cobb's Knob Menagerie. -step5 Take the spit back to Subject 37. -step6 Subject 37 wants some abominable blubber from level 3 of the Cobb's Knob Menagerie. -step7 Take the blubber back to Subject 37. -step8 You've done a good turn, and helped Subject 37 make his escape from the Cobb's Knob Menagerie. - */ - - boolean need_to_return_goto = base_quest_state.mafia_internal_step <= 3; - boolean need_to_return_weremoose = base_quest_state.mafia_internal_step <= 5; - boolean need_to_return_blubber = base_quest_state.mafia_internal_step <= 7; - - if (base_quest_state.mafia_internal_step == 1) - { - subentry.entries.listAppend("Acquire a subject 37 file from Knob Goblin Very Mad Scientist."); - if (!$monster[Knob Goblin Mad Scientist].is_banished()) - subentry.modifiers.listAppend("banish Knob Goblin Mad Scientist"); - active_url = $location[Cobb's Knob Laboratory].getClickableURLForLocation(); - } - else if (base_quest_state.mafia_internal_step == 2) - { - subentry.entries.listAppend("Return the file to Subject 37."); - } - else - { - item [int] items_to_buy_in_mall; - if (need_to_return_goto && $item[goto].available_amount() == 0) - { - //234% item from BASIC elemental - if (!in_ronin()) - { - items_to_buy_in_mall.listAppend($item[goto]); - } - else - { - subentry.modifiers.listAppend("+234% item"); - subentry.entries.listAppend("10 ADVENTURE \"MENAGERIE LEVEL 1\"|20 PRINT \"COLLECT GOTO FROM BASIC ELEMENTAL\"|30 GOTO 10"); - } - } - if (need_to_return_weremoose && $item[weremoose spit].available_amount() == 0) - { - //+item? from weremoose - if (!in_ronin()) - { - items_to_buy_in_mall.listAppend($item[weremoose spit]); - } - else - { - if (subentry.modifiers.count() == 0) - subentry.modifiers.listAppend("+item?"); - subentry.entries.listAppend("Collect weremoose spit from a weremoose in Menagerie Level 2."); - } - } - if (need_to_return_blubber && $item[abominable blubber].available_amount() == 0) - { - //234% item from Portly Abomination - if (!in_ronin()) - { - items_to_buy_in_mall.listAppend($item[abominable blubber]); - } - else - { - if (subentry.modifiers.count() == 0) - subentry.modifiers.listAppend("+234% item"); - subentry.entries.listAppend("Collect abominable blubber from a Portly Abomination in Menagerie Level 3."); - } - } - if (items_to_buy_in_mall.count() > 0) - { - subentry.entries.listAppend("Buy " + items_to_buy_in_mall.listJoinComponents(", ", "and") + " from the mall."); - active_url = "mall.php"; - } - if (subentry.entries.count() == 0) - { - subentry.entries.listAppend("Speak to Subject 37."); - } - } - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[]).ChecklistEntrySetIDTag("Subject 37 quest")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Quests/Untinker.ash b/Source/relay/TourGuide/Quests/Untinker.ash deleted file mode 100644 index 4eb8db72..00000000 --- a/Source/relay/TourGuide/Quests/Untinker.ash +++ /dev/null @@ -1,59 +0,0 @@ - -void QUntinkerInit() -{ - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questM01Untinker"); - - state.quest_name = "Untinker's Quest"; - state.image_name = "rusty screwdriver"; - - state.startable = $location[the spooky forest].locationAvailable(); - - __quest_state["Untinker"] = state; -} - - -void QUntinkerGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Untinker"]; - if (base_quest_state.finished || !base_quest_state.startable) - return; - - if (my_path().id == PATH_EXPLOSION || my_path().id == PATH_GREY_GOO) return; - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - string url = ""; - - if ($item[rusty screwdriver].available_amount() > 0 || base_quest_state.mafia_internal_step == 0) - { - subentry.entries.listAppend("Speak to the Untinker."); - url = "place.php?whichplace=forestvillage&action=fv_untinker_quest"; - } - else - { - //Acquire rusty screwdriver: - if (knoll_available()) - { - subentry.entries.listAppend("Speak to Innabox in Degrassi Knoll."); - url = "place.php?whichplace=knoll_friendly"; - } - else - { - url = "place.php?whichplace=knoll_hostile"; - subentry.entries.listAppend("Retrieve screwdriver from the Degrassi Knoll Garage.|(25% superlikely)"); - if (__misc_state["free runs available"]) - { - subentry.modifiers.listAppend("free runs"); - } - if (__misc_state["have hipster"]) - { - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - } - } - } - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the degrassi knoll garage]).ChecklistEntrySetIDTag("Untinker quest")); -} diff --git a/Source/relay/TourGuide/Quests/White Citadel.ash b/Source/relay/TourGuide/Quests/White Citadel.ash deleted file mode 100644 index 8f34f531..00000000 --- a/Source/relay/TourGuide/Quests/White Citadel.ash +++ /dev/null @@ -1,247 +0,0 @@ - -void QWhiteCitadelInit() -{ - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questG02Whitecastle"); - - //sorry, no way to query for familiar name - state.quest_name = my_name().HTMLEscapeString() + " and Kumar Go To White Citadel"; - if (my_familiar() == $familiar[black cat]) - state.quest_name = my_name().HTMLEscapeString() + " and Luna Go To White Citadel"; - state.image_name = "__item White Citadel burger"; - - if ($item[White Citadel Satisfaction Satchel].available_amount() > 0 && state.mafia_internal_step < 11) - QuestStateParseMafiaQuestPropertyValue(state, "step10"); - if ($effect[SOME PIGS].have_effect() == 2147483647 && state.mafia_internal_step < 7) - QuestStateParseMafiaQuestPropertyValue(state, "step6"); - - __quest_state["White Citadel"] = state; -} - -void QWhiteCitadelGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__misc_state["in aftercore"] && !in_bad_moon() && my_location() != $location[the road to the white citadel] && __last_adventure_location != $location[the road to the white citadel]) //not yet - return; - if (!__misc_state["guild open"]) //bugged - return; - QuestState base_quest_state = __quest_state["White Citadel"]; - if (!base_quest_state.in_progress && !(in_bad_moon() && !base_quest_state.started)) - return; - - boolean using_black_cat_equivalent = ($familiars[O.A.F.,black cat] contains my_familiar()); - - if (__misc_state["in run"] && $location[The Road to the White Citadel].turnsAttemptedInLocation() == 0 && !in_bad_moon()) //not until they're sure - return; - - boolean add_as_future_task = false; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - string active_url = "place.php?whichplace=woods"; - - if (in_bad_moon()) - { - string [int] reasons; - if (base_quest_state.mafia_internal_step < 6) - reasons.listAppend("duonoculars"); - if (base_quest_state.mafia_internal_step < 8) - reasons.listAppend("food from the wand of pigification"); - if (base_quest_state.mafia_internal_step < 11) - reasons.listAppend("an epic drink"); - - if (reasons.count() > 0) - subentry.entries.listAppend("Relevant in Bad Moon for " + reasons.listJoinComponents(", ", "and") + "."); - } - if (!base_quest_state.started) - { - if (QuestState("questG01Meatcar").finished || $item[bitchin' meatcar].available_amount() > 0) - { - subentry.entries.listAppend("Visit your friend at the guild to start the quest."); - active_url = "guild.php"; - } - else - { - subentry.entries.listAppend("Build a meatcar first."); - active_url = ""; - } - } - else if (base_quest_state.mafia_internal_step == 1) - { - //1 Find the road to the White Citadel, somewhere in Whitey's Grove. - //Unlock the road to white citadel: - subentry.modifiers.listAppend("+15% combat"); - subentry.modifiers.listAppend("free runs"); - subentry.entries.listAppend("Adventure in Whitey's Grove, unlock the road to the White Citadel."); - } - else if (base_quest_state.mafia_internal_step >= 2 && base_quest_state.mafia_internal_step <= 4) - { - //2 You've found the Road to the White Citadel! Now you can begin your quest there. - //3 Make your way through the dark forest near the Road to the White Citadel - //4 pairs of burnouts near the Road to the White Citadel. - int burnouts_defeated = get_property_int("burnoutsDefeated"); - int burnouts_remaining = 30 - burnouts_defeated; - - subentry.modifiers.listAppend("+item"); - - subentry.entries.listAppend("Adventure on the Road to White Citadel, defeat " + pluraliseWordy(burnouts_remaining, "more set of burn-outs", "more burn-outs") + "."); - - item opium_grenade = $item[opium grenade]; - - if (burnouts_remaining > 1) - { - if (opium_grenade.storage_amount() > 1 && pulls_remaining() == -1 && ceil(burnouts_remaining / 3.0) > $item[opium grenade].item_amount()) - subentry.entries.listAppend("Pull some opium grenades from hagnk's."); - else if (opium_grenade.storage_amount() > 0 && pulls_remaining() == -1 && ceil(burnouts_remaining / 3.0) > $item[opium grenade].item_amount()) - subentry.entries.listAppend("Pull an opium grenade from hagnk's."); - else if (opium_grenade.available_amount() == 1) - subentry.entries.listAppend("Throw an opium grenade at burnouts."); - else if (opium_grenade.available_amount() > 1) - subentry.entries.listAppend("Throw opium grenades at burnouts."); - } - - if ($item[poppy].available_amount() >= 2) - { - string line = "Make opium grenade. (meatpaste poppy + poppy)"; - if (opium_grenade.available_amount() == 0) - line = HTMLGenerateSpanFont(line, "red"); - subentry.entries.listAppend(line); - } - - //turn estimation why not? - float grenades_have_now = opium_grenade.available_amount().to_float() + $item[poppy].available_amount().to_float() * 0.5; - - float poppy_one_drop_rate = clampNormalf(0.3 * (1.0 + $location[the road to the white citadel].item_drop_modifier_for_location() / 100.0)); - float poppy_two_drop_rate = clampNormalf(0.1 * (1.0 + $location[the road to the white citadel].item_drop_modifier_for_location() / 100.0)); - if (using_black_cat_equivalent) - { - //strangely, there's no public listing of the batting away rates of these familiars - //umm... let's go with the assumption of 25%. - //data we have: 35 items batted, 120 items not batted, 22.5% rate. so 20-25%? - poppy_one_drop_rate *= 0.75; - poppy_two_drop_rate *= 0.75; - } - - if (my_path().id == PATH_HEAVY_RAINS) - { - float washaway_rate = $location[The Road to the White Citadel].washaway_rate_of_location(); - - poppy_one_drop_rate *= (1.0 - washaway_rate); - poppy_two_drop_rate *= (1.0 - washaway_rate); - } - - float grenades_per_combat = clampf((poppy_one_drop_rate + poppy_two_drop_rate) * 0.5, 0.0, 1.0); - - float turns_remaining = burnouts_remaining; - float burnouts_defeated_per_turn = 1.0 + grenades_per_combat * 2.0; - - //How many can we cover with the grenades we have? - int maximum_grenades_needed = ceil(burnouts_remaining / 3.0); - grenades_have_now = MIN(maximum_grenades_needed, grenades_have_now); - - turns_remaining = grenades_have_now; - int burnouts_remaining_after_turns = MAX(0, burnouts_remaining - turns_remaining * 3.0); - - if (burnouts_defeated_per_turn > 0.0) - turns_remaining += burnouts_remaining_after_turns / burnouts_defeated_per_turn; - - //turns_remaining = burnouts_remaining - MIN(maximum_grenades_needed, grenades_have_now) * 3; - - /*if (burnouts_defeated_per_turn > 0.0) - { - //very approximate: - float operating_burnouts_remaining = burnouts_remaining; - - operating_burnouts_remaining -= 3.0 * grenades_have_now; - //turns_remaining = grenades_have_now * 1.0; - - turns_remaining = operating_burnouts_remaining / burnouts_defeated_per_turn; - }*/ - - turns_remaining = clampf(turns_remaining, 1.0, 30.0); - if (turns_remaining < 1.05) - subentry.entries.listAppend("One More Turn remaining."); - else - subentry.entries.listAppend("~" + turns_remaining.roundForOutput(1) + " turns remaining."); - - } - else if (base_quest_state.mafia_internal_step == 5) - { - //5 Defeat the terrible biclops guarding the Road to the White Citadel. - subentry.entries.listAppend("Defeat the terrible biclops on the Road to the White Citadel."); - } - else if (base_quest_state.mafia_internal_step == 6) - { - //6 (Make your way through the dark forest near the Road to the White Citadel) - subentry.entries.listAppend("Adventure on the Road to the White Citadel."); - - string line; - - line = "Careful: this will turn your familiars into pigs"; - if (!using_black_cat_equivalent) - line = HTMLGenerateSpanFont(line, "red"); //ruby red spanners - line += ", who are unable to do anything, until you defeat Circe."; - - if (using_black_cat_equivalent) - line += "|Um... not that you'll mind."; - subentry.entries.listAppend(line); - } - else if (base_quest_state.mafia_internal_step == 7) - { - //7 Get into the witch's hut near the Road to the White Citadel. You could break the door down, but that seems risky. Maybe you can find a key somewhere? - subentry.entries.listAppend("Kick in the front door of the witch, on the Road to the White Citadel."); - subentry.entries.listAppend("This will bring back your familiars."); - if (my_familiar() == $familiar[black cat]) - { - add_as_future_task = true; - subentry.entries.listAppend("Or possibly don't. Poor kitty..."); - } - else if (my_familiar() == $familiar[O.A.F.]) - { - add_as_future_task = true; - subentry.entries.listAppend("Or possibly don't. Poor robot..."); - } - } - else if (base_quest_state.mafia_internal_step == 8 || base_quest_state.mafia_internal_step == 9) - { - //8 (Make your way through the dark forest near the Road to the White Citadel) - //9 Get through the cave full of shiny, delicious, enticing treasure chests near the Road to the White Citadel. - subentry.entries.listAppend("Adventure on the Road to the White Citadel, ignoring the treasure chests."); - } - else if (base_quest_state.mafia_internal_step == 10) - { - //10 Defeat the final obstacle on your way down the Road to the White Citadel. - subentry.entries.listAppend("Defeat Elpízo & Crosybdis, on the Road to the White Citadel, then collect the White Citadel Satisfaction Satchel."); - } - else if (base_quest_state.mafia_internal_step == 11 && $item[White Citadel Satisfaction Satchel].available_amount() == 0) - { - //11 lunch at the White Citadel. - subentry.entries.listAppend("Visit the white citadel for the White Citadel Satisfaction Satchel."); - } - else if (base_quest_state.mafia_internal_step == 11 || $item[White Citadel Satisfaction Satchel].available_amount() > 0) - { - //11 lunch at the White Citadel. - //Visit guild: - subentry.entries.listAppend("Visit your friend at the guild."); - active_url = "guild.php"; - } -//final You've delivered a satchel of incredibly greasy food to someone you barely know. Plus, you can now shop at White Citadel whenever you want. Awesome! - - - boolean [location] relevant_locations; - relevant_locations[$location[whitey's grove]] = true; - relevant_locations[$location[the road to the white citadel]] = true; - - string image_name = base_quest_state.image_name; - if (my_familiar() == $familiar[black cat]) - image_name = "__familiar black cat"; - - - ChecklistEntry entry = ChecklistEntryMake(image_name, active_url, subentry, relevant_locations); - entry.tags.id = "White citadel guild quest"; - if (add_as_future_task) - future_task_entries.listAppend(entry); - else - optional_task_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Quests/Wizard of Ego.ash b/Source/relay/TourGuide/Quests/Wizard of Ego.ash deleted file mode 100644 index f850fe88..00000000 --- a/Source/relay/TourGuide/Quests/Wizard of Ego.ash +++ /dev/null @@ -1,139 +0,0 @@ - -void QWizardOfEgoInit() -{ - //if (!__misc_state["in aftercore"]) //not yet - //return; - if ($items[Manual of Dexterity,Manual of Labor,Manual of Transmission].available_amount() > 0) //finished already - return; - - //questM02Artist - QuestState state; - - QuestStateParseMafiaQuestProperty(state, "questG03Ego"); - if (my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - - if (!state.finished) - { - //FIXME temporary code - //Update internal step locally: - //(this is buggy) - if (state.mafia_internal_step < 7 && $item[dusty old book].available_amount() > 0) - { - state.mafia_internal_step = 7; - } - if (state.mafia_internal_step < 1 && $location[The Unquiet Garves].noncombat_queue.contains_text("A Grave Mistake") || $location[The VERY Unquiet Garves].noncombat_queue.contains_text("A Grave Mistake")) - state.mafia_internal_step = 1; - if (state.mafia_internal_step < 2 && $location[The Unquiet Garves].noncombat_queue.contains_text("A Grave Situation") || $location[The VERY Unquiet Garves].noncombat_queue.contains_text("A Grave Situation")) - state.mafia_internal_step = 2; - - if (state.mafia_internal_step < 2 && $item[Fernswarthy's key].available_amount() > 0) - state.mafia_internal_step = 2; - - if (state.mafia_internal_step < 4 && $location[tower ruins].turnsAttemptedInLocation() > 0 && $item[Fernswarthy's key].available_amount() > 0) - state.mafia_internal_step = 4; - - if (state.mafia_internal_step < 5 && $location[tower ruins].noncombat_queue.contains_text("Staring into Nothing")) - state.mafia_internal_step = 5; - if (state.mafia_internal_step < 6 && $location[tower ruins].noncombat_queue.contains_text("Into the Maw of Deepness")) - state.mafia_internal_step = 6; - if (state.mafia_internal_step < 7 && $location[tower ruins].noncombat_queue.contains_text("Take a Dusty Look!")) - state.mafia_internal_step = 7; - - if (!state.in_progress && state.mafia_internal_step > 0 && $item[Fernswarthy's key].available_amount() > 0) - { - QuestStateParseMafiaQuestPropertyValue(state, "step" + (state.mafia_internal_step - 1)); - } - } - - state.quest_name = "The Wizard of Ego"; - state.image_name = "__item dilapidated wizard hat"; - - state.startable = true; - - __quest_state["Wizard of Ego"] = state; -} - - -void QWizardOfEgoGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - QuestState base_quest_state = __quest_state["Wizard of Ego"]; - if (!base_quest_state.in_progress) - return; - - ChecklistSubentry subentry; - - subentry.header = base_quest_state.quest_name; - - string url = ""; - if (base_quest_state.mafia_internal_step == 7 || $item[dusty old book].available_amount() > 0) - { - //7 You found some kind of dusty old book in Fernswarthy's tower. Hopefully that's enough to keep that guy in your guild off your case. - url = "guild.php"; - subentry.entries.listAppend("Speak to the guild."); - } - else if (base_quest_state.mafia_internal_step == 1) - { - url = "place.php?whichplace=plains"; - //1 You've been tasked with digging up the grave of an ancient and powerful wizard and bringing back a key that was buried with him. What could possibly go wrong? - if ($item[Fernswarthy's key].available_amount() > 0) - { - url = "guild.php"; - subentry.entries.listAppend("Return to your guild."); - } - else if ($items[grave robbing shovel, rusty grave robbing shovel].item_amount() == 0 && $item[grave robbing shovel].equipped_amount() == 0 && $item[rusty grave robbing shovel].equipped_amount() == 0) - { - string line = "Acquire a grave robbing shovel."; - if ($items[grave robbing shovel, rusty grave robbing shovel].available_amount() == 0) - line += " (from mall)"; - else if ($item[grave robbing shovel].storage_amount() + $item[rusty grave robbing shovel].storage_amount() > 0) - { - line += " (from hagnk's)"; - url = "storage.php?which=2"; - } - subentry.entries.listAppend(line); - } - else - { - url = "place.php?whichplace=cemetery"; - subentry.entries.listAppend("Adventure at the unquiet garves."); - } - } - else if (base_quest_state.mafia_internal_step == 2) - { - //2 Well, you got the key and turned it in -- mission accomplished. How much do you wanna bet, though, that they won't be able to find anyone else to search the tower, and you'll be stuck with the dirty work again? - url = "guild.php"; - subentry.entries.listAppend("Speak to the guild."); - } - else if (base_quest_state.mafia_internal_step == 3) - { - //3 Much as you expected, you've been given back the key to Fernswarthy's tower and ordered to investigate. - url = "fernruin.php"; - subentry.entries.listAppend("Adventure in the tower ruins."); - } - else if (base_quest_state.mafia_internal_step == 4) - { - //4 You've unlocked Fernswarthy's tower. Now you just have to find something to show your guild leaders, to prove you haven't just been slacking off this whole time. - //Unlocking just means visiting the area. - url = "fernruin.php"; - subentry.entries.listAppend("Adventure in the tower ruins. Three more non-combats remain."); - } - else if (base_quest_state.mafia_internal_step == 5) - { - //5 You've found some stairs in Fernswarthy's tower, but they don't lead to much. Better keep looking. - url = "fernruin.php"; - subentry.entries.listAppend("Adventure in the tower ruins. Two more non-combats remain."); - } - else if (base_quest_state.mafia_internal_step == 6) - { - //6 You've found a trapdoor to Fernswarthy's basement, which is potentially interesting and/or dangerous. It's probably not what your Guild is interested in, though, so you should probably keep looking. - url = "fernruin.php"; - subentry.entries.listAppend("Adventure in the tower ruins. One more non-combat remain."); - } - - boolean [location] relevant_locations; - relevant_locations[$location[The Unquiet Garves]] = true; - relevant_locations[$location[The VERY Unquiet Garves]] = true; - relevant_locations[$location[Tower Ruins]] = true; - - optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, relevant_locations).ChecklistEntrySetIDTag("Fernswarthy wizard guild quest")); -} diff --git a/Source/relay/TourGuide/Sections/API.ash b/Source/relay/TourGuide/Sections/API.ash deleted file mode 100644 index 99f72efa..00000000 --- a/Source/relay/TourGuide/Sections/API.ash +++ /dev/null @@ -1,199 +0,0 @@ -//Support auto-refreshing guide while editing code: -static -{ - string __last_compile_time = ""; - __last_compile_time = now_to_string("kmsS"); -} - -string [string] generateAPIResponse() -{ - //35ms response time measured in-run - string [string] result; - - boolean should_force_reload = false; - - if (should_force_reload) - { - result["need to reload"] = should_force_reload; - return result; - } - - //Unique identifiers to determine whether a reload is necessary: - //All of these will be checked by the javascript. - result["turns played"] = my_turncount(); - result["hp"] = my_hp(); - result["mp"] = my_mp(); - result["+ml"] = monster_level_adjustment(); - result["+init"] = initiative_modifier(); - result["combat rate"] = combat_rate_modifier(); - result["+item"] = item_drop_modifier(); - result["familiar"] = my_familiar().to_int(); - result["adventures remaining"] = my_adventures(); - result["meat available"] = my_meat(); - result["stills available"] = stills_available(); - result["enthroned familiar"] = my_enthroned_familiar(); - result["bjorned familiar"] = my_bjorned_familiar(); - result["pulls remaining"] = pulls_remaining(); - result["location"] = my_location(); - - if (true) - { - int [effect] my_effects = my_effects(); - int total_effect_length = 0; - foreach e in my_effects - total_effect_length += my_effects[e]; - - result["effect count"] = my_effects.count(); - result["total effect length"] = total_effect_length; - } - result["fullness available"] = availableFullness(); - result["drunkenness available"] = availableDrunkenness(); - result["spleen available"] = availableSpleen(); - result["auto attack id"] = get_auto_attack(); //for copied monsters warning, don't want that to be stale - - if (true) - { - result["equipped items"] = equipped_items().to_json(); - } - - if (false) - { - //if we need a clockwork maid? maybe? - result["campground items"] = get_campground().to_json(); - } - if (__iotms_usable[$item[Order of the Green Thumb Order Form]]) - { - int plant_count = 0; - string [location, 3] florist_plants = get_florist_plants(); - foreach l in florist_plants - { - foreach key in florist_plants[l] - { - if (florist_plants[l][key] != "") - plant_count+= 1; - } - } - result["plant count"] = plant_count; - } - - if (true) - { - //Before discovering get_inventory() existed, this was very intensive - 40ms API load versus 25ms, or 28ms versus 16ms; - //With get_inventory(), maybe it won't be a problem? In-run, it's about 0.2ms. - int item_count = 0; - foreach it, amount in get_inventory() - item_count += amount; - result["item count"] = item_count; - } - if (true) - { - //When foldables change, item count does not, so we need to manually watch them: - //FIXME probably spooky putty/etc? - int [int] output; - boolean [item] relevant_items_strings = lookupItemsArray($strings[deceased crimbo tree,broken champagne bottle,tinsel tights,wad of used tape,makeshift garbage shirt]); - foreach it in relevant_items_strings - { - if (it.available_amount() > 0) - output[it.to_int()] = it.available_amount(); - } - - result["relevant items"] = output.to_json(); - } - /*else if (true) - { - //Checking every item is slow. But certain items won't trigger a reload, but need to. So: - boolean [item] relevant_items = $items[photocopied monster,4-d camera,pagoda plans,Elf Farm Raffle ticket,skeleton key,heavy metal thunderrr guitarrr,heavy metal sonata,Hey Deze nuts,rave whistle,damp old boot,map to Professor Jacking's laboratory,world's most unappetizing beverage,squirmy violent party snack,White Citadel Satisfaction Satchel,rusty screwdriver,giant pinky ring,The Lost Pill Bottle,GameInformPowerDailyPro magazine,dungeoneering kit,Knob Goblin encryption key,dinghy plans,Sneaky Pete's key,Jarlsberg's key,Boris's key,fat loot token,bridge,chrome ore,asbestos ore,linoleum ore,csa fire-starting kit,tropical orchid,stick of dynamite,barbed-wire fence,psychoanalytic jar,digital key,Richard's star key,star hat,star crossbow,star staff,star sword,Wand of Nagamar,Azazel's tutu,Azazel's unicorn,Azazel's lollipop,smut orc keepsake box,blessed large box,massive sitar,hammer of smiting,chelonian morningstar,17-alarm saucepan,shagadelic disco banjo,squeezebox of the ages,E.M.U. helmet,E.M.U. harness,E.M.U. joystick,E.M.U. rocket thrusters,E.M.U. unit,wriggling flytrap pellet,Mer-kin trailmap,Mer-kin stashbox,Makeshift yakuza mask,Novelty tattoo sleeves,strange goggles,zaibatsu level 2 card,zaibatsu level 3 card,flickering pixel,jar of oil,bowl of scorpions,molybdenum magnet,steel lasagna,steel margarita,steel-scented air freshener,Grandma's Map,mer-kin healscroll,scented massage oil,soggy used band-aid,extra-strength red potion,red pixel potion,red potion,filthy poultice,gauze garter,green pixel potion,cartoon heart,red plastic oyster egg,Manual of Dexterity,Manual of Labor,Manual of Transmission,wet stunt nut stew,lost key,resolution: be more adventurous,sugar sheet,sack lunch,glob of Blank-Out,gaudy key,plus sign,Newbiesport™ tent,Frobozz Real-Estate Company Instant House (TM),dry cleaning receipt,book of matches,rock band flyers,jam band flyers,disassembled clover,continuum transfunctioner,UV-resistant compass,eyepatch,carton of astral energy drinks,astral hot dog dinner,astral six-pack,gym membership card,tattered scrap of paper,bowling ball, snow boards,reassembled blackbird,reconstituted crow,louder than bomb,odd silver coin,grimstone mask,empty rain-doh can,Lord Spookyraven's spectacles,lump of Brituminous coal,bone rattle,mer-kin knucklebone,spooky glove,steam-powered model rocketship,crappy camera,shaking crappy camera,hedge maze puzzle,ghost of a necklace,telegram from Lady Spookyraven,Lady Spookyraven's finest gown,recipe: mortar-dissolving solution,disposable instant camera,unstable fulminate,thunder thigh,aquaconda brain,lightning milk,White Citadel Satisfaction Satchel,handful of smithereens,Loathing Legion jackhammer,lynyrd skin,red zeppelin ticket,lynyrd snare,glark cable,Fernswarthy's key,bottle of Gü-Gone,BURT,handful of juicy garbage,Jeff Goldblum larva,imbued seal-blubber candle,claw of the infernal seal,junk junk,sea lasso,seal tooth,worthless trinket,worthless gewgaw,worthless knick-knack,gnollish toolbox,poppy,opium grenade,talisman o' namsilat,toxic globule,yellow pixel,greek pasta spoon of peril,hellseal disguise,8042,uncapped red lava bottle,uncapped green lava bottle,uncapped blue lava bottle,capped red lava bottle,capped green lava bottle,capped blue lava bottle,insulated gold wire,little firkin,normal barrel,big tun,weathered barrel,dusty barrel,disintegrating barrel,moist barrel,rotting barrel,mouldering barrel,barnacled barrel,incriminating evidence,dangerous chemicals,kidnapped orphan,bat-oomerang,bat-jute,bat-o-mite,rad,cashew,stuffing fluffer]; - - - int [int] output; - - foreach it in relevant_items - { - if (it.available_amount() > 0) - output[it.to_int()] = it.available_amount(); - } - - boolean [item] relevant_items_strings = lookupItemsArray($strings[cornucopia]); - foreach it in relevant_items_strings - { - if (it.available_amount() > 0) - output[it.to_int()] = it.available_amount(); - } - - result["relevant items"] = output.to_json(); - }*/ - - /*if (true) - { - //Possibly switch to this in 17.7? It's slower by 4ms, but drastically simplifies implementation. - //The other method is 9/10ms. - //16ms: - //result["mafia properties"] = get_all_properties("", false).to_json(); - //13ms: - buffer mafia_properties; - foreach property_name, property_value in get_all_properties("", false) - { - mafia_properties.append(property_value); - } - result["mafia properties"] = mafia_properties.to_string(); - } - else if (true)*/ - if (true) - { - boolean [string] relevant_mafia_properties = $strings[merkinQuestPath,questF01Primordial,questF02Hyboria,questF03Future,questF04Elves,questF05Clancy,questG01Meatcar,questG02Whitecastle,questG03Ego,questG04Nemesis,questG05Dark,questG06Delivery,questI01Scapegoat,questI02Beat,questL02Larva,questL03Rat,questL04Bat,questL05Goblin,questL06Friar,questL07Cyrptic,questL08Trapper,questL09Topping,questL10Garbage,questL11MacGuffin,questL11Manor,questL11Palindome,questL11Pyramid,questL11Worship,questL12War,questL13Final,questM01Untinker,questM02Artist,questM03Bugbear,questM04Galaktic,questM05Toot,questM06Gourd,questM07Hammer,questM08Baker,questM09Rocks,questM10Azazel,questM11Postal,questM12Pirate,questM13Escape,questM14Bounty,questM15Lol,questS01OldGuy,questS02Monkees,sidequestArenaCompleted,sidequestFarmCompleted,sidequestJunkyardCompleted,sidequestLighthouseCompleted,sidequestNunsCompleted,sidequestOrchardCompleted,cyrptAlcoveEvilness,cyrptCrannyEvilness,cyrptNicheEvilness,cyrptNookEvilness,desertExploration,gnasirProgress,relayCounters,timesRested,currentEasyBountyItem,currentHardBountyItem,currentSpecialBountyItem,volcanoMaze1,_lastDailyDungeonRoom,seahorseName,chasmBridgeProgress,_aprilShower,lastAdventure,lastEncounter,_floristPlantsUsed,_fireStartingKitUsed,_psychoJarUsed,hiddenHospitalProgress,hiddenBowlingAlleyProgress,hiddenApartmentProgress,hiddenOfficeProgress,pyramidPosition,parasolUsed,_discoKnife,lastPlusSignUnlock,olfactedMonster,photocopyMonster,lastTempleUnlock,volcanoMaze1,blankOutUsed,peteMotorbikeCowling,peteMotorbikeGasTank,peteMotorbikeHeadlight,peteMotorbikeMuffler,peteMotorbikeSeat,peteMotorbikeTires,_petePeeledOut,_navelRunaways,_peteRiotIncited,_petePartyThrown,hiddenTavernUnlock,_dnaPotionsMade,_psychokineticHugUsed,dnaSyringe,_warbearGyrocopterUsed,questM20Necklace,questM21Dance,grimstoneMaskPath,cinderellaMinutesToMidnight,merkinVocabularyMastery,_pirateBellowUsed,questM21Dance,_defectiveTokenChecked,questG07Myst,questG08Moxie,questESpClipper,questESpGore,questESpJunglePun,questESpFakeMedium,questESlMushStash,questESlAudit,questESlBacteria,questESlCheeseburger,questESlCocktail,questESlSprinkles,questESlSalt,questESlFish,questESlDebt,_pickyTweezersUsed,_bittycar,questESpSerum,questESpOutOfOrder,_shrubDecorated,questESpEVE,questESpSmokes,questG09Muscle,_rapidPrototypingUsed,nsTowerDoorKeysUsed,_chateauDeskHarvested,lastGoofballBuy,nsChallenge1,nsChallenge2,nsContestants1,nsContestants2,nsContestants3,lastDesertUnlock,questM18Swamp,edPiece,warehouseProgress,questEStFishTrash,questEStNastyBears,questEStSocialJusticeI,questEStSocialJusticeII,questEStSuperLuber,questEStZippityDooDah,_summonAnnoyanceUsed,questEStWorkWithFood,questM24Doc,questEStGiveMeFuel,_mayoTankSoaked,_feastUsed,spelunkyNextNoncombat,spelunkySacrifices,spelunkyStatus,spelunkyUpgrades,spelunkyWinCount,_deckCardsDrawn,_glarkCableUses,_banderRunaways,questM25Armorer,pyramidBombUsed,_powerPillUses,nextAdventure,_volcanoItem1,_volcanoItem2,_volcanoItem3,_barrelPrayer,questECoBucket,_machineTunnelsAdv,_snojoFreeFights,snojoSetting,_lastCombatStarted,batmanZone,batmanUpgrades,batmanTimeLeft,batmanStats,questLTTQuestByWire,questM26Oracle,sourceTerminalEducate1,sourceTerminalEducate2,sourceTerminalEnquiry,_sourceTerminalDigitizeUses,_sourceTerminalEnhanceUses,_sourceTerminalExtrudes,_detectiveCasesCompleted,_pottedTeaTreeUsed,lastIslandUnlock,falloutShelterChronoUsed,_timeSpinnerMinutesUsed,_lynyrdSnareUses,_noobSkillCount,_universeCalculated,_horsery,_expertCornerCutterUsed,boomBoxSong,_questPartyFair,_questPartyFairQuest,_neverendingPartyFreeTurns,_latteRefillsUsed,_latteBanishUsed,_latteCopyUsed,_latteDrinkUsed,_kgbTranquilizerDartUses,banishedMonsters,lastLightsOutTurn,lastVoteMonsterTurn,_lastCombatStarted,_sausageFights,_saberMod,_saberForceMonster,_daycareRecruits,_daycareGymScavenges,_campAwayCloudBuffs,_campAwaySmileBuffs,moonTuned,zeppelinProtestors,questL11Ron,questL11Shen,redSnapperPhylum,_canSeekBirds,questGuzzlr,retroCapeSuperhero,retroCapeWashingInstructions,noncombatForcerActive]; - - if (false) - { - //Give full description: - string [string] mafia_properties; - foreach property_name in relevant_mafia_properties - { - mafia_properties[property_name] = get_property(property_name); - } - result["mafia properties"] = mafia_properties.to_json(); - } - else - { - //Give partial description: (equivalent for equivalency testing) - //65% smaller - buffer mafia_properties; - boolean first = true; - foreach property_name in relevant_mafia_properties - { - //This could fail an update if two properties coincidentally update a certain way - i.e. "1" and "21" becoming "12" and "1" both would be "121" - but it's unlikely to happen, and the faster this is, the better. - /*if (first) - first = false; - else - mafia_properties.append(",");*/ - string value = get_property(property_name); - mafia_properties.append(value); - } - result["mafia properties"] = mafia_properties.to_string(); - } - result["logged in"] = playerIsLoggedIn(); - } - if (my_path().id == PATH_AVATAR_OF_WEST_OF_LOATHING || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_THE_SOURCE || my_path().id == PATH_GELATINOUS_NOOB) - { - int skill_count = 0; - foreach s in $skills[] - { - if (s.skill_is_usable()) - skill_count += 1; - } - result["skill_count"] = skill_count; - } - else if (true) - { - int relevant_skill_count = 0; - foreach s in $skills[Gothy Handwave] - { - if (s.skill_is_usable()) - relevant_skill_count += 1; - } - result["relevant_skill_count"] = relevant_skill_count; - } - result["last compile time"] = __last_compile_time; - - result["monster_phylum"] = monster_phylum().to_string(); - return result; -} diff --git a/Source/relay/TourGuide/Sections/CSS.ash b/Source/relay/TourGuide/Sections/CSS.ash deleted file mode 100644 index f6471bce..00000000 --- a/Source/relay/TourGuide/Sections/CSS.ash +++ /dev/null @@ -1,141 +0,0 @@ - -void setUpCSSStyles() -{ - if (true) //body - { - string body_style, body_medium, body_small, body_tiny; - if (!__setting_use_kol_css) - { - //Base page look: - body_style += "font-family:Arial,Helvetica,sans-serif;background-color:white;color:black;"; - PageAddCSSClass("a:link", "", "color:black;", -10); - PageAddCSSClass("a:visited", "", "color:black;", -10); - PageAddCSSClass("a:active", "", "color:black;", -10); - } - if (__setting_side_negative_space_is_dark) - body_style += "background-color:" + __setting_dark_colour + ";"; - else - body_style += "background-color:#FFFFFF;"; - body_style += "margin:0px;padding:0px;font-size:14px;"; - - if (__setting_ios_appearance) - body_style += "font-family:'Helvetica Neue',Arial, Helvetica, sans-serif;font-weight:lighter;"; - - - body_medium += "font-size:13px;"; - body_small += "font-size:12px;"; - body_tiny += "font-size:12px;"; - - body_style += "--cl_entry_container_padding: 5px;"; - body_medium += "--cl_entry_container_padding: 4px;"; - body_small += "--cl_entry_container_padding: 3px;"; - body_tiny += "--cl_entry_container_padding: 3px;"; - - body_style += "--cl_container_padding:" + __setting_indention_width + ";"; - body_medium += "--cl_container_padding:" + (__setting_indention_width_in_em / 2.0) + "em;"; - body_small += "--cl_container_padding: 0px;"; - body_tiny += "--cl_container_padding: 0px;"; - - body_style += "--image-width:" + __setting_image_width_large + "px;"; - body_medium += "--image-width:" + __setting_image_width_medium + "px;"; - body_small += "--image-width:" + __setting_image_width_small + "px;"; - body_tiny += "--image-width: 0px;"; - - PageAddCSSClass("body", "", body_style, -11); - PageAddCSSClass("body", "", body_medium, -11, __setting_media_query_medium_size); - PageAddCSSClass("body", "", body_small, -11, __setting_media_query_small_size); - PageAddCSSClass("body", "", body_tiny, -11, __setting_media_query_tiny_size); - } - - PageAddCSSClass("", "r_clickable", "cursor:pointer;cursor:hand;"); - PageAddCSSClass("", "r_future_option", "color:" + __setting_unavailable_colour + ";"); - - PageAddCSSClass("a", "r_cl_internal_anchor", "position:absolute;z-index:2;display:inline-block;"); - - PageAddCSSClass("", "r_button", "visibility:hidden;cursor:pointer;color:#7F7F7F;font-size:1.5em;z-index:3;position:absolute;"); //background:" + __setting_page_background_colour + "; - - PageAddCSSClass("div", "r_word_wrap_group", "display:inline-block;"); - - if (true) - { - string hr_definition; - hr_definition = "height: 1px; margin-top: 1px; margin-bottom: 1px; border: 0px; width: 100%;"; - - hr_definition += "background: " + __setting_line_colour + ";"; - PageAddCSSClass("hr", "", hr_definition); - } - - - if (__setting_fill_vertical) - PageAddCSSClass("div", "r_vertical_fill", "bottom:0;left:0;right:0;position:fixed;height:100%;margin-left:auto;margin-right:auto;"); - - if (__setting_show_navbar) - { - PageAddCSSClass("div", "r_navbar_line_separator", "position:absolute;float:left;min-width:1px;min-height:" + __setting_navbar_height + ";background:" + __setting_line_colour + ";"); - PageAddCSSClass("div", "r_navbar_text", "text-align:center;font-weight:bold;font-size:.9em;"); - PageAddCSSClass("div", "r_navbar_button_container", "overflow:hidden;vertical-align:top;display:inline-block;height:" + __setting_navbar_height + ";"); - - if (__setting_gray_navbar) - { - PageAddCSSClass("div", "r_navbar_line_separator", "display:none;"); - PageAddCSSClass("div", "r_navbar_text", "text-align:center;font-size:.9em;font-weight:normal;"); - PageAddCSSClass("div", "r_navbar_button_container", "overflow:hidden;vertical-align:top;display:inline-block;height:" + __setting_navbar_height + ";"); - __setting_navbar_background_colour = __setting_page_background_colour; - } - } - PageAddCSSClass("div", "r_bottom_outer_container", "height:" + __setting_navbar_height + ";position:fixed;z-index:7;width:100%;overflow:hidden;"); - if (true) - { - //Second holding container: - string style = ""; - int width = __setting_horizontal_width; - if (!__setting_fill_vertical) - width -= 2; - - style += "max-width:" + width + "px;margin-left:auto; margin-right:auto;font-size:1em;"; - style += "height:" + __setting_navbar_height + ";"; - if (!__setting_side_negative_space_is_dark && !__setting_fill_vertical) - style += "border-left:1px solid;border-right:1px solid;"; - style += "border-top:1px solid;border-color:" + __setting_line_colour + ";"; - PageAddCSSClass("div", "r_bottom_inner_container", style); - } - //PageAddCSSClass("", "r_location_bar_table_entry", "vertical-align:middle;padding-left:0.5em;display:table-cell;"); - PageAddCSSClass("", "r_location_bar_table_entry", "vertical-align:middle;padding-left:0.5em;padding-right:0.5em;display:table-cell;"); - PageAddCSSClass("", "r_location_bar_ellipsis_entry", "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;"); - - PageAddCSSClass("", "r_only_display_if_not_large", ""); - PageAddCSSClass("", "r_only_display_if_not_large", "display:none !important;", 0, __setting_media_query_large_size); - - PageAddCSSClass("", "r_only_display_if_not_medium", ""); - PageAddCSSClass("", "r_only_display_if_not_medium", "display:none !important;", 0, __setting_media_query_medium_size); - - PageAddCSSClass("", "r_only_display_if_not_tiny", ""); - PageAddCSSClass("", "r_only_display_if_not_tiny", "display:none !important;", 0, __setting_media_query_tiny_size); - - PageAddCSSClass("", "r_only_display_if_not_small", ""); - PageAddCSSClass("", "r_only_display_if_not_small", "display:none !important;", 0, __setting_media_query_small_size); - - PageAddCSSClass("", "r_only_display_if_small", "display:none !important;", 0, __setting_media_query_large_size); - PageAddCSSClass("", "r_only_display_if_small", "display:none !important;", 0,__setting_media_query_medium_size); - PageAddCSSClass("", "r_only_display_if_small", "", 0, __setting_media_query_small_size); - PageAddCSSClass("", "r_only_display_if_small", "display:none !important;", 0,__setting_media_query_tiny_size); - - PageAddCSSClass("", "r_only_display_if_tiny", "display:none !important;", 0, __setting_media_query_large_size); - PageAddCSSClass("", "r_only_display_if_tiny", "display:none !important;", 0,__setting_media_query_medium_size); - PageAddCSSClass("", "r_only_display_if_tiny", "display:none !important;", 0, __setting_media_query_small_size); - PageAddCSSClass("", "r_only_display_if_tiny", "", 0, __setting_media_query_tiny_size); - - - PageAddCSSClass("", "r_location_bar_background_blur", "background:rgba(255, 255, 255, 0.95);box-shadow:0px 0px 1px 2px rgba(255, 255, 255, 0.95);"); - PageAddCSSClass("", "r_location_bar_background_blur_small", "background:rgba(255, 255, 255, 0.95);box-shadow:0px 0px 0.5px 1px rgba(255, 255, 255, 0.95);"); - - PageAddCSSClass("", "r_tooltip_outer_class", "border-bottom:1px dotted;border-color:" + __setting_line_colour + ";");//"position:relative;"); - PageAddCSSClass("", "r_tooltip_inner_class", "background:white;border-style:solid;border-color:" + __setting_line_colour + ";border-width:1px;padding-left:1em;padding-right:1em;padding-bottom:0.25em;padding-top:0.25em;position:absolute;opacity:0;transition:visibility 0s linear 0.25s, opacity 0.25s linear;visibility:hidden;margin-top:1.5em;z-index:1000"); - PageAddCSSClass("", "r_tooltip_inner_class_margin", "margin-top:-200px;"); - PageAddCSSClass("", "r_tooltip_outer_class:hover .r_tooltip_inner_class", "opacity:1;visibility:visible;transition-delay:0s;"); - //PageAddCSSClass("", "r_tooltip_inner_class_weve_had_one_yes_but_what_about_second_inner_class", "background:white;border-style:solid;border-color:black;border-width:1px;padding:1em;top:1.5em;"); - - PageAddCSSClass("", "r_no_css_transition", "-webkit-transition:none !important;-moz-transition:none !important;-o-transition:none !important;-ms-transition:none !important;transition:none !important;"); - - PageAddCSSClass("img", "", "border:0px;"); -} diff --git a/Source/relay/TourGuide/Sections/Checklists.ash b/Source/relay/TourGuide/Sections/Checklists.ash deleted file mode 100644 index 62e0d8a3..00000000 --- a/Source/relay/TourGuide/Sections/Checklists.ash +++ /dev/null @@ -1,299 +0,0 @@ -import "relay/TourGuide/Sections/Tests.ash" -import "relay/TourGuide/Limit Mode/Batfellow.ash"; - -void generateMisc(Checklist [int] checklists) -{ - if (__quest_state["Level 13"].state_boolean["king waiting to be freed"]) - { - ChecklistEntry [int] unimportant_task_entries; - string [int] king_messages; - king_messages.listAppend("You know, whenever."); - king_messages.listAppend("Or become the new naughty sorceress?"); - unimportant_task_entries.listAppend(ChecklistEntryMake("king imprismed", "place.php?whichplace=nstower", ChecklistSubentryMake("Free the King", "", king_messages)).ChecklistEntrySetIDTag("He's still trapped, just saying")); - - checklists.listAppend(ChecklistMake("Unimportant Tasks", unimportant_task_entries)); - } - - if (availableDrunkenness() < 0 && ($item[drunkula\'s wineglass].equipped_amount() == 0 || my_adventures() == 0)) - { - //They are drunk, so tasks are not as relevant. Re-arrange everything: - string url; - - //Give them something to mindlessly click on: - //url = "bet.php"; - if ($coinmaster[Game Shoppe].is_accessible()) - url = "aagame.php"; - - - Checklist task_entries = lookupChecklist(checklists, "Tasks"); - - lookupChecklist(checklists, "Future Tasks").entries.listAppendList(lookupChecklist(checklists, "Tasks").entries); - lookupChecklist(checklists, "Future Tasks").entries.listAppendList(lookupChecklist(checklists, "Optional Tasks").entries); - lookupChecklist(checklists, "Future Unimportant Tasks").entries.listAppendList(lookupChecklist(checklists, "Unimportant Tasks").entries); - - lookupChecklist(checklists, "Tasks").entries.listClear(); - lookupChecklist(checklists, "Optional Tasks").entries.listClear(); - lookupChecklist(checklists, "Unimportant Tasks").entries.listClear(); - - //Remove extra-important popups, because they will not work anymore: - Checklist future_checklist = lookupChecklist(checklists, "Future Tasks"); - foreach key, c in future_checklist.entries - { - if (c.only_show_as_extra_important_pop_up) - remove future_checklist.entries[key]; - } - - string [int] description; - string line = "You're drunk."; - if (__last_adventure_location == $location[Drunken Stupor]) - url = "campground.php"; - - if (hippy_stone_broken() && pvp_attacks_left() > 0) - url = "peevpee.php"; - - description.listAppend(line); - if ($item[drunkula\'s wineglass].available_amount() > 0 && $item[drunkula\'s wineglass].can_equip() && my_adventures() > 0) - { - description.listAppend("Or equip your wineglass."); - } - - int pvp_fights_gained = numeric_modifier("pvp fights").to_int() + 10; - int pvp_fights_after_rollover_before_caps = pvp_attacks_left() + pvp_fights_gained; - int pvp_fights_after_rollover = MIN(pvp_fights_after_rollover_before_caps, 100); - if (today_is_pvp_season_end()) - pvp_fights_after_rollover = 0; - - int adventures_after_rollover = __misc_state_int["adventures after rollover"]; - - string [int] all_tomorrows_parties; - all_tomorrows_parties.listAppend(pluralise(adventures_after_rollover, "adventure", "adventures")); //it should be impossible to have under twenty adventures after rollover, but why should that stop us from checking the singular case? - if (hippy_stone_broken() && pvp_fights_after_rollover > 0) - all_tomorrows_parties.listAppend(pluralise(pvp_fights_after_rollover, "fight", "fights")); - - description.listAppend("Will start with " + all_tomorrows_parties.listJoinComponents(", ", "and") + " tomorrow."); - - int rollover_adventures_from_equipment = 0; - foreach s in $slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3,familiar] - rollover_adventures_from_equipment += s.equipped_item().numeric_modifier("adventures").to_int_silent(); - - //detect if they're going to lose some turns, be nice: - int adventures_lost = __misc_state_int["adventures lost to rollover"]; - if (rollover_adventures_from_equipment == 0.0 && adventures_lost == 0 && my_path().id != PATH_SLOW_AND_STEADY) - { - description.listAppend("Possibly wear +adventures gear."); - } - if (adventures_lost > 0) - { - string [int] leisure_activities; - leisure_activities.listAppend("work out in the gym"); - leisure_activities.listAppend("craft"); - if ($item[game grid ticket].is_unrestricted()) - leisure_activities.listAppend("play arcade games"); - description.listAppend("You'll miss out on " + pluraliseWordy(adventures_lost, "adventure", "adventures") + ". Alas.|Could " + leisure_activities.listJoinComponents(", ", "or") + "."); - } - - if (hippy_stone_broken()) - { - int pvp_fights_lost = pvp_fights_after_rollover_before_caps - pvp_fights_after_rollover;//MAX(0, pvp_fights_after_rollover_before_caps - 100); - if (pvp_fights_lost > 0 && pvp_attacks_left() > 0) - { - description.listAppend("Fight " + pluralise(MIN(pvp_attacks_left(), pvp_fights_lost), "time", "times") + " to avoid losing fights to rollover."); - } - } - - //this could be better (i.e. checking against current shirt and looking in inventory, etc.) - if (my_path().id != PATH_SLOW_AND_STEADY) - { - if ($item[Sneaky Pete's leather jacket (collar popped)].equipped_amount() > 0 && adventures_lost <= 0) - description.listAppend("Could unpop your collar. (+4 adventures)"); - if ($item[Sneaky Pete's leather jacket].equipped_amount() > 0 && hippy_stone_broken()) - description.listAppend("Could pop your collar. (+4 fights)"); - if (in_ronin() && $item[resolution: be more adventurous].available_amount() > 0 && get_property_int("_resolutionAdv") < 5) - { - description.listAppend("Use resolution: be more adventurous."); - } - } - if (in_ronin() && pulls_remaining() > 0) - { - description.listAppend("Don't forget your " + pluraliseWordy(pulls_remaining(), "pull", "pulls") + "."); - } - //FIXME resolution be more adventurous goes here - - task_entries.entries.listAppend(ChecklistEntryMake("__item counterclockwise watch", url, ChecklistSubentryMake("Wait for rollover", "", description), -11).ChecklistEntrySetIDTag("Game unplayable")); - if (stills_available() > 0 && __misc_state["in run"]) - { - string url = "shop.php?whichshop=still"; - if ($item[soda water].available_amount() == 0) - url = "shop.php?whichshop=generalstore"; - task_entries.entries.listAppend(ChecklistEntryMake("__item tonic water", url, ChecklistSubentryMake("Make " + pluralise(stills_available(), $item[tonic water]), "", listMake("Tonic water is a ~40MP restore, improved from soda water.", "Or improve drinks.")), -11).ChecklistEntrySetIDTag("End of day nash crosby still")); - } - } -} - - -void generateChecklists(Checklist [int] ordered_output_checklists) -{ - setUpState(); - setUpQuestState(); - - if (__misc_state["Example mode"]) - setUpExampleState(); - - finaliseSetUpState(); - - Checklist [int] checklists; - - ChecklistCollection checklist_collection; - - if (limit_mode() == "spelunky") - { - LimitModeSpelunkingGenerateChecklists(checklists); - } - else if (limit_mode() == "batman") - { - LimitModeBatfellowGenerateChecklists(checklists); - } - else if (!playerIsLoggedIn() && !__misc_state["Example mode"]) - { - Checklist task_entries = lookupChecklist(checklists, "Tasks"); - - string image_name; - image_name = "disco bandit"; - task_entries.entries.listAppend(ChecklistEntryMake(image_name, "", ChecklistSubentryMake("Log in", "+internet", "An Adventurer is You!"), -11).ChecklistEntrySetIDTag("Not logged in")); - } - else if (__misc_state["In valhalla"] && !__misc_state["Example mode"]) - { - //Valhalla: - Checklist task_entries = lookupChecklist(checklists, "Tasks"); - task_entries.entries.listAppend(ChecklistEntryMake("astral spirit", "", ChecklistSubentryMake("Start a new life", "", listMake("Perm skills.", "Buy consumables.", "Bring along a pet."))).ChecklistEntrySetIDTag("Astral spirit")); - } - else - { - generateDailyResources(checklists); - - generateTasks(checklists); - if (__misc_state["Example mode"] || !__misc_state["in aftercore"]) - { - generateMissingItems(checklists); - generatePullList(checklists); - } - if (__setting_debug_show_all_internal_states && __setting_debug_mode) - { - generateAllTests(checklists); - } - generateFloristFriar(checklists); - - - generateStrategy(checklists); - - foreach key, checklist_generation_function_name in __checklist_generation_function_names - { - call checklist_generation_function_name(checklist_collection); - } - - foreach checklist_name in __specific_checklist_1_generation_function_names - { - ChecklistEntry [int] checklist_entries = checklist_collection.lookup(checklist_name).entries; - foreach key, function_name in __specific_checklist_1_generation_function_names[checklist_name] - { - call function_name(checklist_entries); - } - } - foreach key, request in __specific_checklist_generation_requests - { - int argument_count = request.checklist_names.count(); - string function_name = request.function_name; - //"call request.function_name()" will not work - if (argument_count == 3) - { - call function_name(checklist_collection.lookup(request.checklist_names[0]).entries, checklist_collection.lookup(request.checklist_names[1]).entries, checklist_collection.lookup(request.checklist_names[2]).entries); - } - else if (argument_count == 2) - { - call function_name(checklist_collection.lookup(request.checklist_names[0]).entries, checklist_collection.lookup(request.checklist_names[1]).entries); - } - else if (argument_count == 1) - { - call function_name(checklist_collection.lookup(request.checklist_names[0]).entries); - } - } - } - - - //Convert checklist_collection to checklists: - checklists = ChecklistCollectionMergeWithLinearList(checklist_collection, checklists); - - generateMisc(checklists); //Last, due to drunkenness re-arranging - - //Remove checklists that have no entries: - int [int] keys_to_remove; - foreach key in checklists - { - Checklist cl = checklists[key]; - if (cl.entries.count() == 0) - keys_to_remove.listAppend(key); - } - listRemoveKeys(checklists, keys_to_remove); - listClear(keys_to_remove); - - //Go through desired output order: - string [int] setting_desired_output_order = split_string_alternate("Tasks,Keys,Optional Tasks,Unimportant Tasks,Future Tasks,Resources,Future Unimportant Tasks,Required Items,Suggested Pulls,Florist Friar,Strategy", ","); - foreach key in setting_desired_output_order { - string title = setting_desired_output_order[key]; - //Find title in checklists: - foreach key2 in checklists { - Checklist cl = checklists[key2]; - if (cl.title == title) { - ordered_output_checklists.listAppend(cl); - keys_to_remove.listAppend(key2); - break; - } - } - } - listRemoveKeys(checklists, keys_to_remove); - listClear(keys_to_remove); - - //Add remainder: - foreach key in checklists { - Checklist cl = checklists[key]; - ordered_output_checklists.listAppend(cl); - } -} - -/** -Adds the checklists to the DOM. -@param ordered_output_checklists Checklists to output. -*/ -void outputChecklists(Checklist [int] ordered_output_checklists) { - Checklist extra_important_tasks; - - // Checklists: - foreach i, cl in ordered_output_checklists { - // Check for Pin - if (__show_importance_bar && cl.title == "Tasks") { - foreach key, entry in cl.entries { - if (entry.importance_level <= -11) { - extra_important_tasks.entries.listAppend(entry); - if (entry.only_show_as_extra_important_pop_up) { - remove cl.entries[key]; - } - } - } - } - - // Output - PageWrite(ChecklistGenerate(cl)); - } - - if (__show_importance_bar && extra_important_tasks.entries.count() > 0) { - extra_important_tasks.title = "Tasks"; - extra_important_tasks.disable_generating_id = true; - PageWrite(HTMLGenerateTagPrefix("div", mapMake("id", "importance_bar", "style", "z-index:3;position:fixed; top:0;width:100%;max-width:" + __setting_horizontal_width + "px;visibility:hidden;"))); - PageWrite(ChecklistGenerate(extra_important_tasks, false)); - - string background = "background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAUCAYAAABMDlehAAAAb0lEQVR42gFkAJv/AFFRUf8AVlZW+ABcXFzvAGRjY+QAa2xr2AB1dHXLAH5+fr0AiIiIrgCTk5KfAJ2dnZAAqKiofwCzs7JwAL69vmAAyMjIUQDS0tJBANzb3DMA5eXlJwDt7e0bAPT09BAA+vr6B861MNMaArkVAAAAAElFTkSuQmCC);background-repeat:repeat-x;"; //use this gradient image, because alpha gradients are not consistent across browsers (compare black to white, 100% to zero opacity, on safari versus firefox) - - PageWrite(HTMLGenerateTagWrap("div", "", mapMake("id", "importance_bar_gradient", "style", "height:20px;transition:opacity 0.25s;opacity:0;" + background))); - PageWrite(HTMLGenerateTagSuffix("div")); - } -} diff --git a/Source/relay/TourGuide/Sections/Contextual Menu.ash b/Source/relay/TourGuide/Sections/Contextual Menu.ash deleted file mode 100644 index 9dbc61e7..00000000 --- a/Source/relay/TourGuide/Sections/Contextual Menu.ash +++ /dev/null @@ -1,79 +0,0 @@ - -void contextMenuInit() -{ - PageAddCSSClass("div", "menu", "position:absolute; border:5px double; padding:0px 10px 5px; z-index:4; background:ghostwhite; display:none; flex-direction:column;"); - PageAddCSSClass("div", "ct_menu_choice_group", "display:flex; flex-direction:column; margin-top:5px;"); - PageAddCSSClass("div", "ct_menu_choice", "display:inline-flex; flex-flow:row wrap; justify-content:center; align-items:center;"); - PageAddCSSClass("", "ct_menu_choice_subheader", "width:100%; margin-bottom:5px;"); //text-decoration:underline; ? - PageAddCSSClass("", "ct_menu_choice_label", ""); //width:50%; text-align:right; - PageAddCSSClass("", "ct_menu_choice_setting", "width:auto; overflow:hidden; font-size:1em;"); //width:50%; //for some reason, they don't inherit size, so set it - -} - -buffer generateContextualMenuChoice(string choice_label, string choice_id, string [string] option_values) -{ - buffer choice; - choice.append(HTMLGenerateTagWrap("label", choice_label, string [string] {"class":"ct_menu_choice_label", "for":choice_id})); - - buffer options; - options.append(HTMLGenerateTagWrap("option", "", string [string] {"value":"default", "id":"default_" + choice_id, "style":"display:none;"})); - foreach choice_value, choice_text in option_values - { - options.append(HTMLGenerateTagWrap("option", choice_text, string [string] {"value":choice_value})); - } - - choice.append(HTMLGenerateTagWrap("select", options, string [string] {"id":choice_id, "class":"ct_menu_choice_setting", "onchange":"registerSettingsChange(event)"})); - return HTMLGenerateTagWrap("div", choice, string [string] {"class":"ct_menu_choice"}); -} - -buffer generateContextualMenu() -{ - //Minimization-specific contextual menu - buffer guide_contextual_menu; - - buffer guide_contextual_menu_header; - guide_contextual_menu_header.append(HTMLGenerateTagWrap("div", "", string [string] {"id":"contextual_menu_header_text", "style":"flex-grow:1; font-size:1.07em; font-weight:bold; padding-bottom:5px; word-wrap:anywhere;"})); - guide_contextual_menu_header.append(HTMLGenerateTagWrap("div", "?", string [string] {"id":"settings_help_button", "title":entity_encode('"What is this?"'), "style":"margin-left:-8px; width:1.2em; border:1px solid; border-radius:1em; background-color:lightcyan; cursor:pointer; flex-shrink:0;", "onclick":"alterSettingsHelpDisplay()"})); - - guide_contextual_menu.append(HTMLGenerateTagWrap("div", guide_contextual_menu_header, string [string] {"id":"contextual_menu_header", "style":"display:flex; flex-direction:row-reverse; align-items:center; margin-bottom:5px; border-bottom:2px solid;"})); - //guide_contextual_menu.append(HTMLGenerateTagWrap("span", "", string [string] {"id":"contextual_menu_trace", "style":"margin-bottom:2px;"})); //cur. unused - //guide_contextual_menu.append(HTMLGenerateTagWrap("span", "", string [string] {"id":"contextual_menu_current_node", "style":"margin-bottom:2px;"})); - //guide_contextual_menu.append(HTMLGenerateTagWrap("div", "", string [string] {"id":"contextual_menu_next_nodes", "style":"margin-bottom:2px;"})); //cur. unused - - - if (true) - { - //auto-expansion choices - buffer choice_group; - choice_group.append(HTMLGenerateTagWrap("div", "Auto-expansion", string [string] {"class":"ct_menu_choice_subheader"})); - choice_group.append(generateContextualMenuChoice("At rollover", "rollover_AE", string [string] {"true":"yes","false":"no"})); - choice_group.append(generateContextualMenuChoice("On ascension", "ascension_AE", string [string] {"true":"yes", "false":"no"})); - - guide_contextual_menu.append(HTMLGenerateTagWrap("div", choice_group, string [string] {"class":"ct_menu_choice_group", "id":"auto_expansion_choice_group"})); - } - if (true) - { - //when minimized choices - buffer choice_group; - choice_group.append(HTMLGenerateTagWrap("div", "When minimized", string [string] {"class":"ct_menu_choice_subheader"})); - choice_group.append(generateContextualMenuChoice("Opacity", "opacity", string [string] {"half":"halve opacity","full":"keep full opacity"})); - choice_group.append(generateContextualMenuChoice("Tile image", "image", string [string] {"none":"don't display", "small":"display smallest", "auto":"don't change image size"})); - choice_group.append(generateContextualMenuChoice("Content to show", "collapsing", string [string] {"modifiers":"title", "entries":"title + subtitle", "replace":"replace all with tile ID"})); - guide_contextual_menu.append(HTMLGenerateTagWrap("div", choice_group, string [string] {"class":"ct_menu_choice_group", "id":"auto_expansion_choice_group"})); - } - - if (true) - { - //info - buffer help_text; - help_text.append("- Right-click on the minimize button of a tile to open the settings for that specific tile."); - help_text.append("

- Neither the Minimize nor the Settings feature will work if you don't set your browser to be able to store data."); - help_text.append("
- Everything is saved in LocalStorage. To access it, right-click anywhere => inspect element => Storage => Local Storage (Firefox), or right-click anywhere => inspect => Application => Storage => Local Storage (Edge/Chrome)."); - help_text.append("
- If you're actually relying on this feature, make sure you note its value every once in a while; if there's ever a release that changes their syntax, they'll get erased!."); - help_text.append("
- Deleting your browser's cache will also wipe out everything."); - guide_contextual_menu.append(HTMLGenerateTagWrap("div", help_text, string [string] {"id":"ct_menu_help", "style":"display:none;"})); - } - - //the rest of the computation happens in the .js - return guide_contextual_menu; -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sections/Data.ash b/Source/relay/TourGuide/Sections/Data.ash deleted file mode 100644 index 3ecdd917..00000000 --- a/Source/relay/TourGuide/Sections/Data.ash +++ /dev/null @@ -1,13 +0,0 @@ -string __close_image_data = "data:image/gif;base64,R0lGODlhgACAANUiAODg4IqKitra2o2NjYGBgdXV1YCAgOPj49vb24eHh4iIiIODg+fn5+Tk5NnZ2YmJidbW1ouLi9zc3M/Pz4WFhdTU1MDAwMfHx8HBwcrKysbGxtjY2Lu7u8XFxfj4+IKCgsTExH9/f/f39wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACIALAAAAACAAIAAAAb/QJFwmBEMj8ikcslsOp/QaBOgcSIMBKN0y+16v0fAIlRgCgKhUOAAbrvfXcYgnagoL4Z0OuCA+/+AAHN6IRZIV4RpBn2AjY5bYolpZUJnkmkPbI+bnEhylyF1Ihl5oCEPG52qj4KmaSASBK4hi6u2cJGuBmUIEbOZt8Fen64JlCINvq4PjMLOTq3FAEgCsrrNz9lhY7oQSpbLmtraxKYKx0kHaMvY48HR5tNN1bO17u/cpgbeT+CmwPdWlQN1Toq6X+0CNoJHUJ4UetcUssoHap8Xf6AASvQz8FLBLwfZbcQ1KJ4biPoSjoRE8ZLFNxgvaVy5paOkj3BC/lNJkwlD/48O/aCsqKUntJaSXjaKKWmm0SQ2E+F0pDMjT6M/bwZ9NNRl0adCcunjp4ppIqc9oxKaqqqqzKsKs0rduqpr0q8jxVYkK8wsIbQB1ephK8xtU7jP5K6l68xuIgN4x+l1yXecXz2AnQlOQ3ic4bOIVSkezNidY0KQtU1OWlniZUzigm0O0VniZ0J8hI3mXHojAmumstxa/bh1z9dqYm+aXbtng3WmcnPaTbu30d+zhE+sZxxsJeig1jhijs57kuezpPuhrsC6eRHYXWl/Qxx19/dHkIt3Qx4/FPSuqOcFe+75N0R8wUUWRX16KGVgP+Bdsl9NJRFU3oNOABhdaGFUCP8UhlwgCMp8R3EHYhf6KadEfyd2oWF4cBHY4hciXkLiNibO+EWKUHl404U6bvGihF/JGGQbNUqiHYOK3HfkQxFKsgZ7QD7pYpRSAdeQlX4kOUtxXP6BnDlVhvnFkF9WZ2YjXo61piNjclbmm200oMCXFBRI54AffJnanoH4GJ6CgA6IlHyEFirFbBKqqOiCgqYZQKKPLsHklzdWysRsFJQSnaOadjhLAgDoR2mll+4iRJt6ZBrqbMbkhyVuoCpKHannzarHpKGGdShqVbKahqt7wjonArruUauZtxaIZiK8FprqnEcIGwKxVhq7BbLpLatjs1emd+qJ09KopY3jPqj/LRjcBuitgeC68Sxu6ZpXLhzWYovful0mm1yL8QIy7671rnSvI/kWLBG/j7T7qX8BczLwHgpL9muD1P6RsHcMr+JweO9KFqkeuDozsRoVD3exIhlvsvFIHTvzcaMbRazNydHec/A9L48TszszSxnyJjYrhHPKuKxMS8vZ9HzLz775O+EqRdN0tC07g+X0I1BfJ/XQA45Mh54rXe1I1v5t/UbX7wUNLdhPVP2g2W6gfaLaXLCNodu0giH3jMmIa2g9TGMYS3YV661jL91K8beVgQeYrt1rHo6oE4pzybi7PokdCtlcRh6dgpQXanmCnngea68HKvNwWKqDTqfog4pQT3qlHohw+ogCXDBq4YpuboohBdx5ScmsM0E7IRRMMAQELgGv6e56OH8EBomsnvwTwqfBgRLFj729FJE3zwT0qo4vxeHWM9GB9OojgEESQQAAOw=="; -string __new_window_image_data = "data:image/gif;base64,R0lGODlhgACAANU7AImJiZiYmKCgoKenp/Dw8MjIyKGhoYyMjKioqLW1tZmZmYiIiISEhICAgIWFhfPz8+7u7ry8vIeHh6Ojo4aGhunp6dTU1JeXl+Tk5JycnLGxsaSkpI6Ojpubm4qKisXFxYKCgvb29u/v75+fn7S0tK6urqWlpb29vaKiotbW1q2trdPT08fHx9DQ0K+vr+3t7Y2NjZGRkaamptHR0bq6ure3t8bGxtfX16mpqbKysn9/f/f39wAAAAAAAAAAAAAAACH5BAEAADsALAAAAACAAIAAAAb/wJ1wSCwaj8ikcslsOp/QqHRKrVqv2Kx2y+16v+CweExGYjSZS2DNbrvf8Lh8Tq+/L5kcZrxq6P6AgYKDhIWGh4iJiQ0WYS8AipGSk5SUABBgNJWbnJ2TEWATnqOkpRtgI6Wqq5MCYAKssbKEBq+zt7O1X7C4vaq6XryDFALFxsfIycrLzM3OzQ6FwF3Cggpl2DsB0raE19lk27Tdg9/gYuKD01zVgebnYOmC61vtgO/wXvKB9Fr2f/jycdkHqF+WfzoCCtRC8I9BLAgVLsTSUMfDKxEn6uO2q5BEjVUqXrSSEeQWkeSsmTzJMZjHlQxbUnsJk6JMdjRrWkHZ0ZvO/ys8Xfr8GfJmvZxEpQSdOTSpUqP+kDp9shRn06lUoR6UipUJzwoRTEwYQLas2bNoz3ootCCt27dw45KVgQIHiwc2x1nw46tvJQ4VgEqrIMGvYUodBNNScbixpBs7pcFwTBlRjci0olXePKgEZnVrOYv+Q+LzvAOjRycwzQ91as6ri9JyPQgEgNu4c+verZsBgwW8gwsfTvw230GxqYikLQhBVyiQCCWfsryQ8+dOoiNnXZB5oOvYmWgXNP3pbOvhm4wPVD5KdULg0ydZD6g9lPeD4ss/Qv+P/aznwbefEv3p8J8T+DU34HyFHNhEgt8tiESBDnoljXeA6CehEBRy5/8Qhn9ouGGHsqkDog4iSkiicheit2ERK1LXooAvEhGjeSa6WCOHDXpo0YkpLnijezPmt+MQQ95XpIJH7pAkgDnSeOSTCC4ZYZNUPmhlhk062WOJp+m4Y5YWBmgkll+yaCaTU6Yp45pXtimdjwYA2SWZS0DIJZpzgtmamDXiqYSeId7pJo5hSjnmoUTCuaec2/nZHaAvCpoEoSga2qeaUZ4JqSAxyAVXYY4WyqdhdVI6YmOpKlrjAqza2aRmhgkg65EMNLbBrTvCetgJvAZ6GAUEBFvpYR/sYOyqhDBQ3LML/DZBCkIsqyKjWlgrJLZZaDugpVJ4ux+4UYgrH7lQmJvJHrpPqBseu064ix28Tcj7HL1M2NsVvkvoixW/Svg7FcBJCOwUwUgYnBTCRyhMFMNGOPwTxEVIrBPFRFhcE8ZDaAwTx9Wqeu2mXXi8EsjKirwtyVycGEABMMcs88w012zzzTjnjDOt5IFx4mt+VVjFz0D7IjQVRBeNy9FTkKp0YxqAQcHTjrkARgdUN5bsFy1kbdgCmIAxgNd92SDGAxFwQLYsDSgwAzYPiEDA3HTXbffdeOet99589303BCF0KfjghBdu+OGIgxMEADs="; -string __left_arrow_image_data = "data:image/gif;base64,R0lGODlhgACAAOZyAH5+fnt7e/b29vr6+nx8fPn5+fv7+/f394ODg3l5eXp6evj4+H19ffz8/Hh4eImJiYKCgvHx8bGxsbW1te7u7o6OjoyMjJOTk5ubm8TExM3NzeXl5dzc3N/f34eHh8nJyb6+vtnZ2fDw8Kqqquzs7Jqamubm5uLi4paWloCAgIuLi/Pz86WlpZKSkq6urrq6urOzs+Tk5N7e3szMzLCwsIiIiNbW1tPT0+Dg4Ly8vKKiotvb24SEhOrq6tfX19HR0ZeXl/T09M/Pz4+Pj52dnXd3d9LS0ujo6IGBgZ6enrS0tKurq+np6ZCQkO3t7a+vr+/v7/Ly8srKysbGxpGRkaSkpJycnKGhocDAwOHh4efn57m5uaOjo/39/Z+fn729vYaGhuvr66ioqIqKipSUlMLCwqenp8vLy9XV1bu7u5mZmdra2oWFhb+/v8PDw6CgoMjIyH9/f/X19QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAHIALAAAAACAAIAAAAf/gHKCg4SFhoeIiYqLhAU2PBAIkpOUlQgML4yam5ydnp9yAkQBAKWmp6gADk1MoK6vsLEDHwwAcbe4uboADFINscDBwoYLJC0Kusm6ARgCAsPQ0a4GIAq2ysoAEDsL0t7fiwUbDwTY2A4wA8/g7O1yCy4J5soKQ0cF7vneCzIQ1/O4eGX4pa+gMAEHdCADmCtAklAGI8ZqoIEXw4AAbOCTyPHTAhEl5F28lYDGgXUdU2oqkCHAyFsBLGwYoLLmogNMVJQbCSBAGYI2gxpqMMHlywBqIqAUytRAhxo7L5YKsZEpUwELlhR5GSfBiJNWrQ7wEecfwwAPYtAMK/QZBqNS/wOAMMCW6YAzUS8GQBHhQN2gByi0gCv1RtW/KhvksPYygZgFSxFzLGDCwkK9HnCslZxyAQ2RcXMA5TyZAw+zAAOQgeKXdMcFOkBfZPBjs+uIXTTEYdDYjLPbEhdQCPmSAJgOtoHrMzDFwUtVEwxEVt5OQBgVvEcSuOCkG/WCDWAQZkhgBt3v+gZk8ZAXoAIWENG7QzjCuXYEHM7Lb2cATQrU5gCQgBLq7FddFBhcdlYFPRxmoDcGfDAeQAR8kNyD0RxAwgXtzROAF/Fh6M0ALzB2EQH4XSiiMAPEMMaE5jggQQHTrQgMQhLIlloFJjhoYzAF4PDfURno9+MwB7wBI/82zIR4ZDAN3IBEdgwxAAFVTw6zQARW6DiPjDRmKYwBZ5AyUkwb+CgmKIE10aE5AWCh4pqfGJCGgu4BsUKNdHZCGTk8xeHDnH1uIsAA8TT2BFiFThPClGc+cAKhjS4iQBCxvaTAXJW6UsAPb2JDAAoi8NmpIgdEwCFPBNxg5KmbUGPmRQksgRCsnQygRQV4wikppbgWgpUSXpqjwBavBqsIPwgAKCoVSim7SQEsLJlMKUKoKa0hBhiRApUAOQBfa9smssAKRNh3Vg3IlbvIAHDMetYEo7lryAFQoGCtLgRUQAG59nL7xb65AECABskGLMgBPVgQajIJVLECwAoPUoD/BL2K6sEOCVcsQpfabdyxwt1+O1ICXExc8SEHVJFxNgEgvLIhQfqjnb8Ur4zVBFudSe/Mheg6xMvJBMAusO520Ya84Y4L9CACqPrwLgBk+7TFPxCcCwHQmmrvpVcUi82xIwdsQAgQgOvhr1eHgqi6DHl169UFnACoVAQYUba9dhKdzKiltq3hqiNture7BsxAgLPKoDWp4EFwIbYyCSzqtbsDrMGG2gEKinS5Azzhty4K6Hl5uQscgd1RcrYtxwBuJMB40TJpG3ABTgAxei5gnr6tAUKYPNuVtn8thxda49Kk79IWIENZRB6+LY6TF81j8Zi7mPwtvbdNoonkpSj4/4ZTL/MQ88pGuP0tFX4urQBRlLC78gxiX25/SMy+y4AFPk0f3BTCj/SkpR72aAo+6AtWeNYXh/IMUFnWWZ12uOOdpw2gOc9xQHQSCCvhEEc7x3Gfsiiym978xn8FyNRLaCPCYBXANPpbxmpyVjHPVG8XARBN2yhjmaNkpoW4Ugz44vYYDp4qMIPhCgAM4z3FcWUvfbmaM97ynAB8oV4rGwv0IqUWKWalZyf7ihE75RSoPAcAWLoaURiIlGg9jWE6qeJPdtiSJ8oEiKf6yAdPZpIxVooiFuFJRuz3PgFcYX7KO9/V+GEznjBgIG2Dxw1JZw9CKkscdxsJOvoHNGoMESwg2uDGIo2BSJg0w4+NmkUtntMLLFZMFKRIhSxLsYpW0O0RkbCELiWBCXcEAgA7"; -string __right_arrow_image_data = "data:image/gif;base64,R0lGODlhgACAAOZyAH5+fnt7e/b29vr6+nx8fPn5+fv7+/f394ODg3l5eXp6evj4+H19ffz8/Hh4eImJiYKCgvHx8bGxsbW1te7u7o6OjoyMjJOTk5ubm8TExM3NzeXl5dzc3N/f34eHh8nJyb6+vtnZ2fDw8Kqqquzs7Jqamubm5uLi4paWloCAgIuLi/Pz86WlpZKSkq6urrq6urOzs+Tk5N7e3szMzLCwsIiIiNbW1tPT0+Dg4Ly8vKKiotvb24SEhOrq6tfX19HR0ZeXl/T09M/Pz4+Pj52dnXd3d9LS0ujo6IGBgZ6enrS0tKurq+np6ZCQkO3t7a+vr+/v7/Ly8srKysbGxpGRkaSkpJycnKGhocDAwOHh4efn57m5uaOjo/39/Z+fn729vYaGhuvr66ioqIqKipSUlMLCwqenp8vLy9XV1bu7u5mZmdra2oWFhb+/v8PDw6CgoMjIyH9/f/X19QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAHIALAAAAACAAIAAAAf/gHKCg4SFhoeHLwwIjI2OjwgQPDYFiJaXmJmam5ybTE0OAKKjpKUAAUQCnausra6dDVIMAHG1tre4AAwfA6++v8CcAgIYAbjHuAotJAvBzs/PCzsQtMjIAAogBtDc3awCAzAO1tYEDxuV3urriAVHQwrkyAkuzez3+A0Zs/K5EDL28AnspiqJsX63FOg4oGqgw2cFbIhCaGuWhgYPMwITcIBGAoq2EpQQEVCjyVUDNlg4CDJAhnQnY3JqUCZANYoEVDA5ILNnJgER1LCkGGACRp9I24WYCJJAjQ7bkkodxHHER5BxiixZ0HCq1AExHgztR8tHL69TDYCwiTUABjld/9H6PBABxdh+BM6clYu0wI2bRFtQ4MnXp4AFYq5SxJbjaOGeA3B4uEtOgQUTMB/HbJCDLcgENEpqNnkAChnK1gDw4JB5tMYBPxhgjZNAh2jXD4eZUYxQtoYuuE8O6ACGAFaRFG4HxyfAwIRQWB1Mibr84QInF4yDZKAiTNzqAg3M0N4ShmPwAlWxiNfUQ5a96PEZ4ICAPEIHIxjGTz9ASQLA8gCQAhrU7cdOAT1UgBoyCmAQxXcGejPAB/YhFMAHBUbojSpeLHgMAReQQJiG6gxAX4XkYPMCfCRyI0ABEozT0hgxsNgiRCYoeJwE+t3YjQEZeJhLCji05mMwqhTT1v8bIx4JUQgQyEYRA0jccJ6TG8EoI0UJWBGBcli6UoBKQtpyyhkZhunLAFiUaQsBTQymJpIrAMEeRQqkkeacrQzgQxwAkmMOZnz+wtETvPVDzwAQFtrJACeItR0SIezpKCdq3YlQbUE0eqkmAoiAAoqC/mDkp5sYcAMBgZZzQQRNoroJQ0skmmIA2sjKCqSS4lmBFjbqiokBW2iqqBJcCStMBFSQeg0CACnLSQFCMGUhC6dKewhPLGzZDwMpGGGptoUMV4ObcThAxApgkktIAxOgewocwbpLyAEUVODsMQGgAEWs9hZigAastvTFuAEfsEIVtpZjQQ8ABzyIATt4sG//MhJkKzHFFn9mhQgSb7sCFw0jA664IRsysGcIKVBFxBLjqy9IAEBQZMqFwItuVhMki7Mg5qKrwBDA/iwIt94GGEAbwBktB7XW4vWqp/YC1WxbpjotB7HGypPAFZ06zSu6DEBQqdMMWRWdC4w6bYARBeP0wAkauxvqqFjlibC7mWIFoohiRyovATPsre2hJc/DRRAw2+snoNuxsUa9VdfZdWVPUO54m1hxd0S77o65Es0JuKE5uS/GmDcQTtRNbgFQStlbCkIYLm2SOwfgBVxuB4kVLTK4rm0BOe6cAI9Uo65lWzSerq2J9dGswIpOF7Tz3427O+HF/GLoNII6gqRA/wkPGg2Of61egwSBbp8YXX7JHy7Hen6757y04nGPSwDmOX1ddp3rTvxu5xzogEQ691PWcIpznBIkx3wC2E3n4nARscVmNrUpwACVVZrT/G41wpMWZ1i2qdCITTI7swyhfnaYxPxOAY353l9mEwDBZE9bdLHLbAiXQGE14Ask7IdbhmE0sPRqMXEwi/kOoDasaMVnOINd1PDyFNsJCyhCoaFRnEaTIMojJxArIplo+JIlegSDIwHd8CSSPpMBoIIslINBZqOAKxDxZ/rgB83+oUZpuQMeGKyH+cKRNLycI4TCkgY1XpgrFhJjZ3FQBjOMFgs9LmYXPdTVJ0Jhik6KAg8VG5SWIiBBykZIghIRCgQAOw=="; -string __refresh_image_data = "data:image/gif;base64,R0lGODlhgACAAPeIAG1tbW5ubvPz8/T09G9vb/Ly8vHx8XBwcPDw8HNzc+zs7HFxcbq6unR0dIKCgs3Nze7u7urq6nJycoCAgIGBgXV1dd3d3dfX1+/v74SEhJmZmXd3d+np6ePj44yMjJWVldXV1dDQ0ODg4Ovr635+fnl5edHR0aWlpdTU1OXl5ebm5t7e3qysrNjY2IqKisHBwXp6eri4uNvb276+vsnJye3t7eTk5LGxscTExOHh4ZCQkJycnJGRkaamppOTk6Kiont7e6ioqIODg4uLi6+vr3x8fN/f35+fn6CgoMXFxZ2dnc/Pz7W1tefn5+Li4n9/f87Ozq2trdzc3JKSkoWFhZubm9PT04eHh4mJiaenp4+Pj8fHx7S0tKurq5qamqOjo9ra2nh4eJ6ensLCwpaWlszMzLOzs9nZ2cPDw4iIiI6Ojqmpqb+/v42Njb29vcvLy9bW1nZ2dry8vH19fbKysujo6JeXl5iYmMDAwIaGhqqqqq6urre3t7m5udLS0sbGxrCwsJSUlMjIyMrKyru7u6GhoaSkpGxsbPX19QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAIgALAAAAACAAIAAAAj/ABEJHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXOlQBQ1CRzQ4mElz5o4eci6w3AkxApQbdzIsOES0qNGjRA+Q+KBnSxOeUAUisOCmDdKrWLG6wCNCQFSVTA4AyEq2bNEAG2Z8LblFx1CzcOFu+ABmrccRM4TE3cuXRwivdi8aePGWr+G4VGQMCEwxBIWxhyPDPaBjBGOIK3ZI3ry3ARMMlxcaoNGA8yEAFYpMyMC6tYMiFQJwTiMiNEIEHzhT0LNEAQIDBQQIHy7AAAIIKNaUkHwAje2CF/QaBqAmBgoOFFOY6LLhcBUEzwds/ykcNw0gFRxpaCi9l4qT0ANi8D3goUNIBEjIm5XBeMAPAnEF0IN9JKlABGRmJUCDXQb0gGBZO6yQkgg7AGhWBUksBtUAUcQ1gRU7PQAEXAE8EBUdD2a1RgFQQeADXASUMREg72GEg35XlQCFXTMccKFOD1mhlw4sWrSCBGapUQdjIBRh1gYpNGSAIUYhoeFEGCRglhLPUZAgeAt5aVQAf1R0hFksGPBcBLmVJQZDLiB1ABwTjVEWAXwU+dwIPJjFwEIc4ChEDREpsFxWAPzwXEEFXFFWBdgpdMJVWlzZ0Itk6QHYogNB4EBZG4CJEAfdHQVAFw+FUBYPCnBqkBTsZf/1p0J2XvVGQwJ4QFYRhLpqUAgWYnWAEQohUOpRCxCo0AxkAVCbrwdlUZYXC3XgI1JXMEQFWTdAi1CuZAUAwkIaYOWFmgihQBYWonpbkAVaZkUBugiNgCRSAIxh6UAFjIgVAPxFNMBTgTHQ7LgKMYEVASYcZESwSO2wL0MpaJBADoFlSRYMeh5kKFYkREpQEFnBAMFDAvjxQbyKBnbGtVjtqJAJsl2VxqaIYAAzUlk4hAANQyAF5FoDWJXVBwsJkEdWJxA0CFmgLTQAGykW5QNjMpSlLEJG3HsVDgP9oCKgJ8BAFgEgBmYHWS0rJC1WFbQgkJhX0YnQBT/sjBUVDQf/9gZZEzDEgddIzWtDVmEcZEALWMAlQRS2TUCWhAslQZYLdMha0AAvkFBzWUOkMPFaW5ClBUMQzIForEclEMFATdzwRFxh4NHxZXXEexUArS5kgd5wTVDAAEYEoXtZB2hwsqtB/3tGQ3ccVogKbVSdlQTPQ/sAWXw01MHxcCXwuVkLmNG7t/5e5YFDCpuWlQ5DuzsFWb0upADh7hNVgXPuEpR5Vn1jCAjG5z4liKx/AvEDWbjgkAI0z31PuBUCC4IAiB0FCQ8RAY4MU4EeTBAhjcPK6R7yNslQwAYfRMiksFIEiKigApGJwxhul8KByCErC4gIDqyHKA2gsIYIKQNZ/87XEGPtpQTxA6JB1JUVuUFEBATEyg2IqESDWIAsSZCIF8qihiRW0SArIMusIGID/BUlDDH4IkMiIMaJyAcprFLjGtsoEQXEYAr3ooCJ5DhHzVUEAUvgQv34qBA2+pGQJDEkVsaISJF0gI6NFEkYDxlJkICBLE6sJEisQBYLaDIkgiDLJ0PSIawAISMCKIBxMEDDRpZLKxTJwQtYoAQPUOEJMGgAAFgwSkTAECtkoMgKr4K0Tz4yK6iaCA6yUoJRvoAs/JMIE7EihU+eKSvPkogKyNI0TS7NlBZRHVaEV0kIRLEo3aQIF3D4ukjugSwhsEgTLGgUJkQSA2b71w8pgv8AcV6lAVEjpBToWZQStBIigSCLzAj5BbK8ACMgIIsGENmBcxJlAziriHSuEgAvKpEIZOGBRm5AFmrJ0QAkwKJGRHA2KgKRBYDjSBXWNboJIiAMZOkDR2RAUKIAYAlf7MHZorQRAWRgV/RKYQvKQgSP2KCnRNmDEh94lThYxiNry0oCEPZBM5QFch/53cYG6S4ngO8oJBAJSMlyNQQqgHVXeWhIImDGozDQXQWIHlnIcNCNwAF4RiEA2LwF03DVaCRZvR7GfOWGsgCAkSLBwKfIsgCuPgcHUCVKW01iBcAapQFAfQ4bzDIBgp1kBjwsSgOgUFOoNLYsAUCBSgZABrP/BECngRGAGFJLlBKxpADz21K7eMKBPpklChlFyQioKi+PomQAKJCcWY4QlRScdZFJRYkBusDbokz0K3VIKVyEEM+UOCYuHljeV5wQJxJpoC4lkUEVLIqUNzFGAVfobpUskFyNDCAH14wLBkNjAB3wJQBPKC9HcuCCzB4lADNo7VfeyJcJiEFGF5FBEDJA36ts4AESXosJ0seXOCjhBSBQQX8NogAp0IAF0jWMC4jlLR3otyxX6IEZHsDjHieBBVOAq2EC8IUVP6cAf9hg/tznAPhOMAJfcPCSO3MD9aZwBVfo8JTLsoAPXLWKAsjBUbdsmCmIjpACWMIOtEzmQwQhV5ORtMAXxNvms+SBCFYepQW0IJYtByABQchzLwcyghbEQFecaYAP2GCBgA5aITUwgRyCUAUPkOBQSIHBEzxQBSLgQQrZfbSoR03qUpv61KhOtapXfZKAAAA7"; - -string __bad_moon_small_image_data = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAACyUlEQVR4AZ2WzUsbXRSHVUQhgi0iSgmYtFS7aJG2WdQgiCGlqyKKC1+yaHFRhQpFsCAKIqgLRZOFLgItqYK4SCRI03FTtFCC1Fr84P0PJItQQjbNR5vU5NdzBicMYT4u88CDMPfMfSA4M7dGEAf5gvSTETJ2/TdAviSdAGrMNMNLfiRR7draGmZmZuD1elFfX8/XJPKZldhNMkxCy+npaahJJpNYWVlBW1sbr0fJVtHYA/KnXqixsRHFYhF6jI+P81yafGgWu08WSOg5Pz8PM0KhEM9ekY/0Yjbyl1GotrYWmUwG1ZTLZQwPD6OhoQHZbBbM5uYm3/ObvKEVk0gYOTAwgGqOjo7Q3t4ur3s8HuRyOSiMjY3x9cPqmJuEmTs7O1AzOztbWdva2oIWLS0tvO5Rx76KxPi/jrm4uIDT6ZSv9ff3w4hgMMhzJ0rMLhLq7OyEwsbGhnxtfX0dTCKRQD6fhxalUgk2m43n73DslUhsaGgIapR//8nJSXm9o6MDqVQKWgwODvLMG44FRWK8qRZ1dXWVmdPTU2jBDzytv+fYJ5HY4uIitIhGo+ju7sbExIT8k2kRDochv/aIQ5HY6uoqrCJJEu/xmWP7IrHl5WVYZXd3F/IvSLwTifEzZRW/3897hDj2WiQ2OjoKq4yMjPAeUxxzisR6e3thlebmZt7jHilzYhZramrC8fExzs/PcXZ2VvHy8hJGbG9v8/3/q19XT0lYNZ1OQw+73c4zz9UxJm62qdvtlh/QpaUl2YWFBX736X5M+dhA9/3Q+sS0kldGsZ6eHogSi8WU+25pxZgnJIw8ODiAGXt7e8p8n9kZpI/8oxdzuVwwYm5ujuf+kh7R09Vt8oteMB6PQ02hUJA/Ow6HA9ffxrtWzo3/kd+qY11dXYhEIggEAvD5fMqx4DvpMz83muMi35IfyH3ykJTIEDlFPhY5Ef8DCuHZP51PEtAAAAAASUVORK5CYII="; - -string __matrix_glyphs = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAACvCAIAAAD1+0KvAAA++ElEQVR4AcRbi3dO55r/Pa8JQgSRtkRL6hI+xCDSOi7pEXXXOFRLi6Ip6kJQF22IICEuVZc0otJjnHbWzFFdRw+nnc4cR3UZPZQxf9J0/9Z693523v3u70vHmvmtZ2V92fvd7+Xdz/15N34lBgLvCzYI1gv6IETwuxQYD0wVuOiG4JFvDJ5FF1ACHOJYNRwrRwwD1gp2Co4KcsFrgiOkN/zthwsmCioErwqWCbYLzgi+MuiGBOQjWGYx9yoDzBCsFDQLrhn8A54yBNgrOCg4LBiKJLwi2G2wUbBW0QZuUKNBg3GWCnxuAuowyEOEV0Vdd3ii3oB3cdzgOXjRHfjYBAy0QDBJsMT2eYZbmSP+kU+REthipmCToC8iLLXt3xH4sJZtXCpDAiaycSJlPEMkrm6KYLWl8D2sECwXVAnGCgYjWEiL7XwEO88jh0XYKPhv46W/qBfMn5hk2/9soDEK0VOliKFacF/1+YMJRCERLyB5Gn83uG5wxeD3/DEKEcqAcwZTRPGT6mQ0Ynhd8ITXfzT4iFK7SnDaNm6SgPkGw85fYbVnl3YKXJTBs58c1MV8wW2Ddx0ttc0O+lht9XX/y/qJG/WEEhJhmY/dSK2q67kSCOJ22/6iwUgJaJRgCif3mX1qrLOMoRTNsNtLJnjrLobwbX2ejQYqnjtkL2416A/MEvxOcNlefE0CpukH9ABGqRk2G6sekmirOO9MsFuwmertbcFCwTQJJKZnoopWSq6VY+0yASdVczIxUAQv2HH3G2gsUFsdojmH/akRWNBaNAn5mvTLj4MS7Ms8vrYRiLAhVdZLgK/t7yUCF88B/xx/pFnQCxqBQBynddgluMk2lDbcMPjW4J6lAUoiw95WC+75pse7N+zvuyYQ07X+5Zx15r9Z8MjgzyZgnVOCBsEewft0RGoFLsqBxYKFpNk0Ny9QebpotNP4L4OMR23cNzGTuk7wJd/UV2TlH+2071Dj3jR4y51SRtCipHYgEvBmqqwXIxLuRYIEcIXvxjs5ZGLveGfSEKcMtnFV7whW82+ZFd8TSubqUqf3kmC44DR/TxKATtA0CV7DQdvmtMEeUo1AY6xSCS6dM0Dc2axLbEnmaDHBPMfZ/gcopbLO2bR5dkWfmCSHgNeP0kHhv8Fy0tALgey2GQzy+7SzKGGhxu8gXTZoExQBDfbWvtSRlgj+rsSlTjX+A69kpXl8pEqJ4ASJGPkkJSxUSF9yqpV8pAiBwA0D1ggOCY7y7+/tg3sFiagU/M03GUqMRkf2+UeBxmY1T9cHfs/evWUiX+xDCWTd56lskdwcdaEqOJTk8f5GIn9Yox+w0t5aLUjHQiVtmwUaxaHtIZ2gBF8kJ4UXy/lIrZ6JEoWRgv6IGg+hrHPZyCP76640HTOYLNDQszpim/0y0FzBcKCC6neeKB9CjdtmsEOwVQID3MynQsPc2zGoe0zMhL/EPpfbBTbau2/YK1oFntJX6CQZpMIAZy1T/JthRKGwwLLVbRPpmSM0UVfsU/WSFgjtDk0+6U3pNDr7sdQiaGKQt4NR0/P0cnuRBe/YNrvZw2P7LzUw/mT/3aL63y/ZxIt6Lx8JKADalKey3t1HuzmkuBdJDhtBlzbcnBLlbL9tLxbRU7nGrk8J75K/wVU/jKIb/uCeNziLWivIgjLgkuWIZZIUZZITCxCgB2jblJC96ZeDA3F2WykwfuF26WMKKAcNhKND2dQ226ZCsz/NnoBvSEl5PQ3tSEaT251R6gTuCmqFjytaL539pklq8lMF6ahUjeldoxDcSdJzDHC1RiyFiiOU7/2pUgPWNtvAuhcpEZ9bdvjKQGOo4rvQL1geZ6L3BC6mCe6qNg+4xa5p2CP4STX7mS21xN8xUXAyjMqDTgO+iY8+Qc3zN8INVZMcRIfjKh3+j+z1rzkcfwcWSuN5T2h7ld5liCJEPdxldJ6CLXbcR8xwUcqjLbqmRnldOofXMwRL7eN6maFWy4ThXTvZuZYKcIFgPmOkLYIOFTJ2QosKZydaeWpVrD1doCHUXdoRPUGeTURPYJVgG81bsTJLmxS/Dxe42GobHKbPvFIJ3A4uYURcvEJ+b1TqJBylRlCIyN8ss9fbeatZO/kqsaM1BwkfGrwqGJokSEuSvJm3JMH37m9f/3kltQsEe3VLBv2tnVJsM3OwSfsFcSjeoWwd4Js4qi6+LLEkXLMehdmofvBiBKK48Fs2vmTwRShbpGFIwBpnLQ1xN7snkgPlz0w0onbUq/n43wz+iRFwKOUgF55WnT9UPN0duOjZyduOdR9KvmwRhBikDC0pdved1Pel1V4fm+3MkhPZRn3oemFbRLltBr10V45ftljd2sJMdQomZJ2SIBH9uLO6ZYn1JDqslqt2Oj/MW51tsIFhHOGOvl2iTVgrkUXvjhhP/07sZBQtFuSCKqrPULgL47pwmbpLDwNLQl3luk1DyPi76Km2Ci5RXNoYINYKMvAiD6gnN50WdLOJqjrBfpo0DZ1WbWHjdEwCzgq+s/Kk6XsTqNAe8OJlwR8N/pNO5seCXlQe5wWj445uKI5XaSmGK4f8Fh1aY7WlVhuU5tieGASj3KQKdTGAftkfAhPLxzlWjhgn2ChYIShAAsYKjlmHZrUAXMI+QQdV91KB4CmhTBTnZmfMrhXL8uh1v0hPqpQeZtfhHbE3jaIe6wW+Etfp68/tGykoZTM36ivOYSElfCtPHX3ZeddQAFxgonU5XYP/d7zCwLFFAlnJEQupgT6lQvL5caxIYqoEUd8Yvt2BpGHOlhWwMckyGf21hZbyPZmiVs6hnX5oV9EPWCSooRCP9z++hrNaLBiT+xDPq2CrU9eFVMKsHGM1OaCG21QtgYNeyZhyGHX1APxKdKNMaExTYXcP5ITZEvmf3Tz7kmLjC9F51W51Wdvy3irKr2RdISMokyiRMINVyCIKXAHZK4+UgmI16AJBiP7kRWP3KvSZFwpyxXzlpxU7pX5ez04PdBWZzHhOcIvW8Z7BTb6tep6gGIfYaxuMwPR+Z3CF1v0gjY325zcJ6sm2iThj8ImgTT2ywbKjzuE88c48uGXiRfgBatWhVl+khnC2LieqFqSg0Ek26CHuMbg4o4ar4Lu33KytD43caEGeUzI65T3LkZ3OmGik/emNGaU0Wz9laG5D7BAkosnT/ojpnG9qizui2xgWH2WmLEQD88lno5ZBm110pPcpCV7IdHSl6DgiO2U1yZeTpHOeZNtMCs8a9QgZgfWWTyV4u/9qmeKEJESo5wXXyeadoq4vKZcP7JU/2206LblKPLkP45FDe06VwDkGqR10/k/568F/cpg1A/y7klot4ulnJ3x0UTCD4colS+Eu/YUb8j3Luo9DmROkIyy4rVct1wt7yEZbRTl45GWHUnXIAEZj7arxcon8l0H0rkGfpSPkLG7iNLL5bB6KqDc6M2ydXjqcoygQr9DA10gUc3cwlJxFI6dzapouk+WbVJpplVAI6F5MZ89jBC+SX7XEr3MCMN7NlTYJ4ohW10LdsE34UrlFA/k3HZ84xzP0Fm1TNatGqsyLJhL6ueEjk4VRWhLdYbws8GI08FfV3s27LlPi+64kV6CrGYLvEccI8QVk6LL1UcmdmQKN7/Sc1fGlHbrklXquSlHQ2zFmBdYLBnOB5cB0pVSqBHPIdvskdsyqmccQNAySRa0uKf2+gt3GEdWLdkiCC3bflW+iN+/md+KIoTwTuVVsXULR+wKTmlbsUPbJ8dfU6UPpwpnIBgqrPjLR6klj/ZYO/BTBVO7R63w3nao6A50jTtlJZUPzoVbB6VVJrH9kO1h5wGC/0mSFegNtPtk95HTcPvK2c2ud6rzB4Lg99vWaZItfuvMQ70meGdBeXAquGlUSceJR5c3mGPV6XFyVLh4CL57lKa3pgmIldm9JNJ9LZJ0bKrvkI32s5aFzMnK2OomRiANq7UskVsgqh4VSge3O/tz0FNcnp27RwxxDplJ1uvGkQQp2uhGhRV9lh9pZtc2Kj/RZBcprnfDglaJa8ab3OqwP30MdltglcJFHKW+MJ4onMKZ/g7WsnnqNzpnFSokkEvCXthy6GN+l91Q//T0SrB1AfYrU+iV2k1WJ7xmVWPDvtWI640nWzAmztfTDJaUT0mXuY6l/3NANPiOdKxB/ZCr4EJ3VRAhwyz6+WOzQdPIL/aXJWz5PmxB70PokM9hfM7iYyNJqKDGJOCzJ6mepY2KikySCbor/7nuqeflAjVDwBBm7kwXxQtNKUTbgND3AxXRxx/OQczn9iAvu0WiiQrBGsF14zlnRRoGLHkC9J1w7awLJ6ISjqt45W1BCr6GAWzyFUVxZPBO+gU51Oc9mTBacVZVdXZWqkpjsPkvPw9CvblGikFjaamCMUMXNGUmil+DNFrhlulO0o3O5nE4w8XPO9ZzqFG5veHGO40Y10dyWCXor2zo9HpoT+mCin1rEX3ZV4jvEn9a/4BnF/RZofbb5ZJBT5mgzU8Q/q4NLIYYg+ZF7qk3uyalz/gPCN+O+fQfdWPfTrKnI4naMhPcLEqoQfs3gObWZPfnS6NiGyfYRzXelSIMAGdqbc3Fr1DNpX2pTp6QrzTPFm0ejM4k6dQyDO6tONjmWbJbARVXqZNoMhsOLQUCzo+TEI+6tniGWSJfr5Rt04PMSM1n/IvghzgV36dfVJBX4ygGyJL4xaBRUogsQYDTj4w/4GYgPk1hn/dFRElcol9qAtQlukosf8e8NE/RcpE6e3KCTotlioiOU1w2mIxmVPNr4heCvKgn1mMmpI6yspCOfZdpHNlvXP9X/3y+4raz1VbGWxZHgI3QInjhZ9GtU3Wm7n0/Ky3aotpB//w9QwBx6EUeUX1WbkiTHahgwBhgHvNj1MrOgyyhkTWxmbk/2AvqkvwJld58BhpBKgHxPizSemk+/ppbG/OmiiAWZVZLre6oU/zEu6uoa0oj4p1Bz+CHaOob/TxcV/Iyj0f8J8igEQ+8VVKiEUl90AT34CjLAy9lOVUziZM7/Qsb5FIX2CS0MOvcYfEDazfJLueiPA/63qBT8ltHFRh5J7LD+eZ4nDXSEnudkQZ4yhO30SI+RNM/tSfo4Rxe2M06kMZMuTxPTQIdpt6ZwrBxRoaaUiA91JtkyXAdTTmvj4ZAgux9ekuSsFKgTPDYPH19CJrV0Mw7RBzlzUuyl4AyrbytSk5rfekZxXRtdg3pAd+k/Eh6kNbGFz7AArPPyAtxN+HgiGPEHz2S+Z3E+cY21rCtX2DVWq0zWYL48bnfCV9df8ETHM9TSocnX5b+f6DpcsTWoz9jgA8FAJBePM8AhCSrrbfTJ240qmZN7FnGqvRm/B8LapFMhikbSFeJvzBdf3lg/61G5nrLPCX5R/z/tnfl7ldXV/tlPIMRAAkFClEEGRBCQQURQrHXAAeNLwVoVxLaiYFsHNBAGEdCUAYSCMhhIUmul1sG++FXq8NbWalWUIuRf+ub95Nqn92Y9e58nGK+XH1jXunrVkyeH55w8a69h3fdal7mc4LNN+LJXhSDCDslZx9M03Zb54ByWykJGLCwHXtLkeF2qlVeneIIYgeHoPeTObi1Pd5SZVAV3UQfP1n6lpRxdeSXXm5BYqleeNujJdmOhOYVA6NgHIaBr4PQbW+rJUEyvRQfgoTe4OC+dUOVrtQDB4Ft5WaM+U9DRCK5dLtviuqNl32nmYR9HfMQ5GT+BOFFW+wsO+D7dZ9IrUzbGeqEjn+J7SOPGoR2o8nAT7xAJW9XPnmxwSf35iP/pZv7zKXc2ynpb9BsgLbzS/P0Pk54e9gMf7nQly7DxrT7F+g7R5GGEEPQORnKGRXpL8l3M9HasPNorpP1l9TYKy4romG26WyXTv9XJJ5Ke1ZPia5/NFOrsleO02Vfa18pJU6r0/TaTyhRHTuk8rwWvOZv6623ozUQDo3i3Eluze1BEjW/e7wazcS3VulkEN9pfWu66TiyC6vlJC5jlSnWcsKSOKbwmV+7JfP8V/TQcsXBZ8DeWR75AGUuxV+tKbk/qKo5z6E/++g0c0XfzTY0S+/uE+28WDpJyeUvVuh/LTIwa7fb4nt0g3uRMpO+kNbKfULL2RQUNd2xxMDX5pXRgdMsykuNbzQcZWGp5aZ1yKGM37hc7WEcU3URfuutLnOxKjZ2gf7xKmQG0bjJ5eLEY8kt4rt3XNBI6TgtLrMNAQDaB16lVXoJthfIZDkvnJzdkhTmv3VYtp1MjE0iXztd5mYZKJjjFiVzTpgNsvEzSkhw+NZMP202BdDx82w39ydt3Ppq6nirQJs9wmSsESZWJ/vWtmelf8UcMRRoXi2g5DDVFn2PZf6LzfVrwErR+Ax5OurACa6J5MEV89hfwl/zF5K/ewr7iLm2lV33SK/q6UIF/S/thvk94bugjKE/p8LyR+Q/YJ0SkyFvdEnKO5wDH7PqwTsp5Jd0N3GeRMbif2aqZhAi2hHLU//RJJ5VwOFoqN7j/hP3LaBSN5PiRir2Y402G8d6Bn5vKc6oM86qwM3pE80tlFQMzyHjQdETGPvHTEylfeJOFq4kR78cKSwS9/SGw+RHDeK+md9aaB6PE4wYWvFjyxfoS90RAVRV4ZU2dWzV698Y0xSluGaV4UDK4Vzylv9UkDj9ycjgZmSQnSqPTf1QKUHnN5nbild1nxRAzZfCM1U1O+IDERMe08plLpeLr/s4/QVtkxARcWJSkq/vZ+rO0QhGcN6PnLPU9E/PqyHCZQoe1ulOQD3/n+ln6iXyrY5W49tfl0w3lwPw8Mgpjhpqmd/9T0pBQaJhLNTEBP1MfGbD1MFeWcofub+A30oC3eiTAXZOMB08BDOInhOXeJjjkTMNmMrOYjHXcjVjDvS5o7AwBfbGZoSe5naWakrvFDpbiOJ6Wu/2pywcJU/L1YCXaSuqrnMIhMLJbnaTyomszMW5/hz+XQUR364wRTK2BZraeGY8p8NR/llckyC+VB17iyHkhtHisWdyqdM/0I1wvU4Ie9V38DnAvHPFK4qNn+aHMqimVn1pcdwjHf5IYlJXxIcE+L2MT2INBEm10cVgWUTSlVmxU+jz/wruX/PQbinjyTteSFv9u3n8GF+8PadB7pduzXH40mR55lxxUxjCO+d8+sf7G/BMj+CfsCaRRwnfi4zmc+aRSUfiGBOwDyZ6fAvoyo1SS3UZHc2teQWeavL7YcT1GubgYOzGjztWEfVRx+FhDWeFtYjM2qlIVgTW1Q5jX0HEq6YS9rOtvuVpSQ+lnSwxM9DeEw6Ar4j1AxaMUis/m5l8097AnC0oIY6V6LOmvQKbB1uwu2bGUHm300AGIjO6IfytBRjzCVzqNBM/+4hRHRhOU3X10voEH4SRGcJiYqHtMx9c8gAtdqYLfY+FRxd/I8XCCiBckepyFTKb+quf2f4kNBXw4oWF1HeN/JNo8zmWzuWw7MK5vDSq9lm/qDUy/yaX6OfPoYq1z8DYoHm2lSiw+2E9e4vobGenYDL/5JPn3Go/fq+SnC/h17RmM5cm4HUzPvNAldz1bf8YBl7q8Q30n8Z5w4MkXGN55IXUQI4iNi0tvt5/l+608V9pxrVe+8f8DqQDQPkmJy8VlGI/tc7Q8083USh7ATRTxyzxDgLMOoYn2lHI33iNx/JUrgvPlndGhnsc2Jf5kaEV9OefeC/GW8yBOmke4RmfaFgUL4ERaUPxLSq5jfM6NFMKuIuG+PDa4m0ilWxuKzLXbTOzXQoRcJXOybG15AP51IUUopTbNKXf3hxTmmBYpXN8txee5nGM6ZceOmKuRaTf7BaOUK2PlF2MzHKc4M6TOD93cbcJDR8J9F/9oJfUfB4W8CJH3RgnpNcPWTvmd8CrGE9aUrhnCodJ1b3V8Fd2l7Pj8N9zwfwshxz71sR5LVJRKJE7dShXluhdlWlaLt601Lgfs358m4H3yESp5/V2hSeZCMtaAcdec+2mQYi95cpv+E6WbacaPXi5J/ENhE7pUPzhMDkMU7WuFnhv9AX1u4/LFrYoelPdfW4ytuUXvf7KLdkYTM0xbwhyxiUDmRho42iZ60P1vereKdsdDgh2c66LzTndG8IsLICAFo27wDi/nlbEeljLQ7EgPP9EVnh7ONXrCGJbqeDv6Ct3EiITUHAEi0EcpEqwm835IqgW/gO3e5CR6kguSGo4y3Od8gYaH8UlTK1E2sf5LHXzR1xGa9xMQsqLLFGyguiBCNsTEo/qm/z9/zjivyhGZSlm7dcbXxk1Bk/LpQraI6fRSiVju5z0Qvhi6IFZFG3xNW0mRc+Wu6iP0nIf5w28ChCUD9yBJ0/neJc+E9ESF4ztDYA/qAtOyKazRINEZzrNdfLYGN7pATFAraDoaTkdPP0sBdlOmxaMUo2kIjuCXPNDbSyVf/t1pktjsliyzQ2gTW8Ki1Qg/nTw2cHtpaaIWn93J8eDPS4JzCVMa84K+Gq5ninxAGVnBZ+Ew+N/XM3F4xqpMIckGsZMh4L5MyNrC0MDLxFjXu2CS22wyvEUwaL+L+3U9S54Hj62JZqOeK9hEl5RKr3/Kgqh+lqXBC6SmSuZsXMOdr/hP04zIkVvVkngnTYJ2GV/rbzW8Ad7zWwNOHif9um59SgaCK3X4dTMd7K/K0tbrk1qr8bA2fJRi3JHDMBc/YcooB6SIHZP2JF14dQjk0HEWQ7FXLT/1kdD0EF5zkJ9zo+HlYnbKHPEd1gaKR89TtjVkAqUgiMMDGqaDsl+S3KHdeOJ6X0Eqfcs/k5J7afJeg/8+8e5JFS9Zw+SQndxAR/z6AZqwn4nwgD80Fiw7EuJK+J0rg+Xp+z1YzGYXRFs7nXexHDInpaH0BnsU3lAekUAbVT/kj+cv85NylLbrO6mfRD8CYFimb2opu1Ib3ug/KafrCIPBnMa7SQFGm9B3retSf6LQF3k7+U1qpdqceQK75Ih+GNzPEFtE2i4UI5Vm9cHWp9LSn060soRQVn2SrfvcARsxzaWZ57R+y3uKlXRwZUhZlpGZ8otNCmWKgDvvwWlt525bw0nRi3319EHpzvbzfcyzDGtBCNy8WsIIZ9hE7QJgnRGOrOWnODvKxn7sNueWIW9W0MXPHSGyxe7bWB0mgn0lY5mEasbWIZPgXZi8Lmez12uuT4dMM3F8KVFbERvlTUi+cxX20SaLMGHu06sQmf5NX2gF1pM/m0BOhfvDQEGDW10jpJiNGjyaxvmPOIiT3jErSvJjnRQmyO3S+VENd94kF4ID4ePM8/f2lu94Njo4zXH9FB+sdbjAG+3E6V6JsVv239LQyKZSyBxCPWgeme6kgIkrOF7TuJ0k7dWmrBTchvAlGWF+Jb+yz6fdMZnYR/s8EQvmDOieDlYTNqMGhsXe7XoyYbK2c6VwsAXibuuDOMtfSV+5zndUjxAl7BWsywzM44AUADx2M5WV3EgYG01SbolMX9pmLGCUzG+yageqvihLgXbJA/sakeS/dE+RnOcLqWS1ixP6rvAs3l8Jsb8y/lOrOtte8wWbB3eYWPdNn5ncri1kjOk92kEn7Iw7LPtKw0LuxK9vcRbmLVtaOK5+J9e8RQs5NUZvmjw1KJFehJZzJGKXHWYOCzArBnIKxkM0WZrmruwY5LQ0C6Ijt330XJzTMDm/jSEtYZKFKr6EfYIrHSKuitQ5paPi4zN1vSNDBFAyzwr//nspsI8nUG+N7HGqivRMqE95H9Ya/zZHcVa8Kd7uFL3YA/orcjzMETry+2bGHXigqCzx2XOTuPZ4Hdv7e5LpXKmmOnhMqksngG9OT77t3Rwqn4K9Kp004/BNzvS/N9P5PmNiiLeSlI4n+KTHvV0NoF/yDNXyypBKOV7oy0cFp32SwvWV5Zuv3OWwH4wyO5xoczY+tarA9eMpiBaXodT8Jrry/Mw6EhvX251pJVLXoQX5zfDYeiyV/oP0ftd8i29z5j+Y8tCNKvilFMMCJK4ZBg7kKbC0Ews8mtupif43AVRxuQ7bWuuiY1GHYN+DIyiDsnI54UIT/0SuTIK6MoEHgtWbpWM4HDVbgz0NTWnqb9MqbLgIRZ/kleJRERb5z/nDHEzqKzps08iP7LAZQz5+gkHbC2gtr5ORcRMYXTPTtAujZXOgzlacjA/r8Iyvbm0r1gufJNG4lWpZr2T1JhdJ9Yrs5qvDPq7xeqoUBmf+RZ6s0d4c3wy7xelj3243Lb4dVM+rf0qJOLcP1vP3V5EyNXGyFRLZqNrmTQNFlUeZ0RdM3cVzW9lSrBUmhLu46lafAZqkxlVbyA3hs7aX7DMmNxWeJZmwYIagpihAja5n798XFu8KTuNH+BvUalztGQxac72C1FYpINtJ5RkIKzV/ZFiYv2wj49ch291H2qIQLaQY7A6aaVupYRzC0gILPkMz8mSwYIxXiI1Py/DnCYUnvjeGoxQ+UEgwJdkBkZk0n8uxMZzn4yr6d91DyBpwKKOoPUWFn3bGp9xewjG+kJLF48TG26WP2+YYRS9MC5AhqKCv/2Bs6A53diB5LJjbFfPBQsyUVLhVXtR1bur79stPZUJicinJwTxIQF8Jbdok2VodarM8U3PN3aw2o6xulrJo7kTzlVSaXpQubHF5VjyrykzYtIP9v0UMgWuUvnImrpSea1Kxub1CbNROXXM4/iCLhB1yGOTntew7NQEpvkBwLAUi8K8E1JMrpe7H23k3ay1Y7+Z9Syng0R4ZPnDqtt8VpsI6Vy4Cp2/zL+pfxyPFtT95EznK/ybX8gu+gut/gcXbT1Gbl6fdSwy8Xqd9USSpiccEH2ZYggtvzAcu/c0OjGN8P1/qsL74NJW4BZu7ibu35OLNuP/uYKLyiNK3I277JTR9S/XkCYl4otHpVCFRYSKtt78iAKs9Mr0mA5ojXjO0LXLCwylz55Pmlak7fNN6dlgrvCvsIz1d7kTRsVc9tuB5LmAWqVRTOkcFtSPyjnDlsCTpv3J8qds+RkNmJJmYtyFjslByvyRs0cE2qnrYjKaW257J/GepjT8te8k/Zrvic7l0ZGXoem329z+tAEzsW1muBrSW+5EtqRAn8/cBL3NBaexNaJIfmtPocyjX52LByjHULaNF5HndmQJ+rMmPO26IVGd0mWeHqeJuDFFgC2WZ5xKFlZn37y+9XkWJLADmsdNjWu+VN3R5ZidKEMTdar98gl8UvlRb5rSGMt+dq5QPIq4tf+/hM8LtH+wJYD8lvF8r/OB13Tc8l58tLGnpEeYifV3rGLeGrY8mF9lAHLfgQ+FO9DQW/JqQJtuQh+E6wjv82ikXksZRfJ/xw8LG/3spJgB7dalUMxRF1VeqRXNMQrHWBRlqp6n4V3eze4kq6j3m/jTWv9kJi9AENDom5VWhI1f7Vel6Vm2hoD1BVtUWVZVl7uyQeCHFyKwnFlxc1EHux+dd5M9JdVTrJPzuPgNeloZPCVwxn1udS17bxC9eK+8zIcxndus/zftsx9aVXfg4qOmLTRbQzJCv7kJ0A6b2M+anTHNnY9AOSjRQEp2C8nveCgrMfxrkv5aBAgdkV87I4jB50bMP6ufzfneHK27BRQXfKbEo+gfAVlWy+0h1swsH86Bjw37wGaiCx4Etai98qpk2ezLPYV8dLhMv9aoHGdyW6hkFFMjtKUXfWvA1gDidH3N3Om9wwO9zzypWSDOiMq5ruGBTll94OqRQEILAhLxQ2IKtjJHQeq9kJlfmhawzXalkr71khVkZldEi9p/eYEBkU+R9Lo7fqqpAyey8IlQ4A1Vy52PCo3FevB9/mOpQb0o9xwCzc8oHXO8rZrHnMhjaz2nDipgMWLzbzv4WjqWsoDT2OkCtCZ7l9y6lqE6zGPhZl5oGO5Lgo5ETfrgiN/Li1YH4+KNC7P+OWHdDXnngXoBdB0OC7zCxYEsSGEPL+Z9h8euPjDbrZVH6V1mp8YRaPaZ6KsPinj7LvzcjMty3Dh1wTsTiWq99y5VfzuFrz7grNNUbHUSUOgKL74FcTmSLym/2ttSSxSpWQZfNrEBLh+2d/hWy/l6WieC9N4LTTks1kelmrFM7telhzk+RiUxLPwrIWDglWyAij0kiTFY4NLlduFBXp3+ExroGyO7DlOx/Th61FID0UjiAaRkOxrbVJ2PRNrMU3la6/M1no4gkFsSUB+Ke9GMq04Zi86u10btVQt8i+eFCIQz2K8BG13g+bt+2+xu/4wF596TBs+0HnCk3DSohm8Naz7/zwK0nzTzLFqedWrtcLak+DhpIHfRio3fKm9CVCw6zDyn5vuMZfJ/m94jkcWGuyDrGuc2BvqWDc6xoZDpcXO880+9xtuwfsZBMiUbdg2SeJZ9jUWcwulRFByUmdKmhXilj+CcuYP3+QrYJPeZD93ap3K5GfyfVaTpXnBMFtsYoGXdesea3ds/SEMlWaAQFd57t9CvTLhMg2FQykVavh8Musn+RpiffJL1hrYTzilF6aFL6Segpwr/3woVFb4WL/H5FnWw9bqxFyan8Ab4Kk7OLSF6/palez2kxQhPlAqrG3Rg2fDqM/p4pH3XmZEqojuR5Kf0rWHZ1ZOdgQk97zLa2zhLa4uyAzPRd+QICX0EhbYisE9DlVvYwb5dlggo4Go7v3Ke7BQvDRbT+rHei3S0rasFpbZfmrr7/3RjfWCxJQcvNYVVyKuWqB2E17o2fE3H+tFGx4AIX6yxPHc5GBfxhNuO+nvfYVoegxmNxJ6rBsL65lpdDthKEWmK3Oxj1XCoG7aD21qXtArO6g0Ek44wPHl5gi9FQv6Tnr1J9I9sJauzf+MbOAKH26vq0MVpcw0mP8oMDtBuoQ+VXwTp8h0Nxvzt7AsIuR0Ag5eVX/SvcMzE8/y6cMfn2/Dja0RREL+WC0YpfOSwr9kaYJ72Wq0swIrXCDnleKiNL7faLWVzldIyzV3zq5PD9d5iJ78udRUv12IJV1gin0na7mylAWjqWpvvjwubbRTIu4RW84ErnWRTEEGoetYbQQLwW/HOH4lF3bZ4pPxnQSiJP2QlGIamvikhIuddpovE3/0agPC+7bq+Zn8YdFXRj8Sh6eI/+wFKUbpDyxX7fy1Mb+LcQdkeES+A+Fw5jQ9xHdmJkh0i17wM2JOVorUILzjVO1VGev5amD4LMihNjCPNcaMFWlCar2qzppqRhzYo5otBYQf1lcZyxslJQwRf5+GgVuriXLHim0xUnZSD194UbF2q0KqmnWjG6vhal/0u3Sng/clhShppI1VZr7IdD73uxreRlbJ8oTZZYHLfg/mYz7lchu/5WM6p0sIkVP6ZeMT2O8dcj5HcJSpJaMAXn+4wuoQ4zPg9Q8Em4HKJvsoD1Tujw5sYqoFSt51AaY0CAVYWI+PFezAR1eUuX37RoCD0qiEhuCGeAfMWBX19ihu3Fsd1H3ec2wpz14jjPXrUY4oG7l6m/aHoy12Cm+m3+2uXnkRvhrteZr2lngGOKriUrmAdfHR+VpW3XGfFDpc58zKY4AcLe2yTqBzdS/Vgt5ZSpLhgnMo/5/LWmD31DeGN1YsGzHAmRaWGRRuraaFFBPUbJtaeEgjGsj5BTZZ66scv8nUJf50UHM73nU1Z8XdyC06p82TQmeWvkSoU6q/4pXrB8RpjKfePdgqAs6N3iZDVKygbTItM5bpFBtIf9i9udtISjD74ZB5T5mRgdpofVj7ZXm896a+K8kltkyJSWl62MF6PpIDfNJYHpGuPmPH1BonQrdwt6a4ukA7Eqv643PpJ85ybdWROX38gb6rSyy31M3mY+e0Of/MPJkWpuI3BByH9Wk5+1uj5vuT7vUbR6BwiBDv5WH3wUeHCuTKHIlSh9aJOgi/61g6Hyy1yq47SF0veLkWvu6II6dyWXaP33WCX6gc6sSwuQx//h+ieS/YDPdF57coXuC7zhl3h3jZzHUhezY6mmmOlmvTl6+aLkW2Ro786CHsxR9oNKBU3DIqJDlPune8aUHaZTMzhnqeJ97IvjvRYaaSw+CWBzElVTQes+OSy7d2Q0bhvtmXUOABaIUl0xFpO4w/7lmueVBZ7IORCUJ51Tq38azOPDLFj/3t9kvBPydBwXvdIBZkaF+erJu7icXhEFO5LnFJVB4qL0BCs4sFWJVYMorC6Rltf9IJx/QwE1IzYeYOLtfRIAN9Neu40+0kQStnH6DHkG9lB0SBh7X5N3/LKyLx+4vohAvc4OOnnMP+9/kWGp3a/8gv+NrhcsMDX6IAHwR7kKPOqqPuVZFLFryhZ6rIPf6IpSI2e7cNAc1n9CctkroDGeIZae4o83tjrGlY9cJbDwvyVnBgaFFwGzdipAE5nax/9Ix4UOE/BwTLdm6vaLtzIU/ZvSceK0MjtnXa9JI61sqdaSaHwLHFJvqLzYLhasgzwbfTtEU9vlsqGtv3yltzJYPNZL/rkzNUSjsf1UP9YbcDnlP1Qc04T8KeOoWLNKycq/pN3dgM7g3BjuWxkqR5JvrtZ5B2CP0141QTwjr8NdPncL7tuTASAfhmPXD8sutyqsWZHYiXrTBnbbd6/BuDp0Qzq/s8Xrx1JvmB7ZRvV4uLnzpBQMshDoFUy6W8VTX9LbHYsF7UMkON7rYNu9EklVr5V3s3onPqPwuIHI5Aqxnp+QCOZa8HisakdZlebPcqmKD5I9Fg/gU8+ymEpOnQleZ4Rf1ATRqb4wl0kFquRWpwEl6xB+sK7o3SMFPlMPkExaZabMrzsNjCZLhpH/EBbbFl33pcyAnos2UlKqFixH0V7D7FML1mWqRRAXiOCf6V1eCrL6bR76Uiv3O6xZTbYoTEyraXyoCb7P9inbn9RtTy6B2uT1Wf5FrXvPyYmNzertFsKKqp5AI14CJ/Z9Iug6GnBTuzM8/o8y9bpfnMjr08KaCaTQGPBDHoKCJ4QsxFaC025txlEPmE779lGnJeJiKuSMejkY9FNsFtZyk+AIJpT+FS4orQa7gmLis2cV7fvS98DTiEoHdwcHqc2m2w1dh25dr4o4uT2RtG1qntX+NWLBlR5VWYuqP1vtcR2DuUCmAcmaQtxQv5TvZ3ECAfYh9BsZztv9yiueeKIjtDa4HE7zdAyslVKuM0R7f2VyHs1V6q6S2h7OaL/ebCFZxdPd67Jeqr72AbJjNJrh/aWjaD23WsUUEi5JW1tPUa8uKM/IwmOXrMzsC2dWVyTLfONkdn5HvJUSuk/OgTfkCVJ0oA6hXBDBRX/iYy4F0B8jLU7ru8qqi8+0estOwxDP+j5A2iJRtEqb3L+dbqExynea6OMsi4ha/8pyK7E6hcj0UDln1xQa/ercfnaVfzZXeftYHe6lnwp1/CAoe13xLq6R/xR9lv5GRfGoWFNtFRmuqmDE8S4/JugXz4MLFsvaALTECJLXh26+jVEY4wpEFa06PUOdXWTCkK5dmposGK82bfgJufGz0vGO5M3o6Gd+5aTschhpJkl1cmgUj4pJtVOP9hl9c5AbaSluwZkJJk4ASokF+coV5tiIdkG0lBEO6CAoi09y7DTfzMzYwS6Efx1CnxK14KjAk18pnr8fFdo2k4eN5Y4fKqCLyx1f7QLBrCxei9ZKULxbt1lXPiTORiqL22QIfcG48v5wFvSgcs2GvWFw0zfZsHrUFbl5Y8E7XY9HCE+iNfsZ3eZel5tgIX8ahxIk1pGUlSpqvJ2km7UFLt7AoRINbSKwvZPU4yYXSxd3O0CcyfvRN/8WQFz5b/5KP1BUY+bi4shDfrjFw2MLN5hrvPYv/P4jqUMVlHP4mINBgRWXccUbyXw5I9IM7vlUDc9Bav3yz+I1rAZ+5S5m/PSmgBL5FUpv4LwSMmy0pjfeDYpDAakAZHTI1DaLicbJqb9Wg9/JspFaQWItxDjGaCxM6mL+NzXIh5ykVyQDRAz1OaL8dF5P1iEvz+t/PAqedQrFjb40bG4AgjnJmNMCQG1KrY6LLkZBZ2iDosBBVCsJYkfk32tNxs9PhDOz/tmTqHsIec5M0eOC8dfXr3Up3MgB3jB3A/imnuzr1YPELk541Vws1VYpL9NmLv3nkuBi+ZHpu6f8rl3ROQFobkuB+tQ66beYMp7s5DR6iL0Z+gF+2cO8eWLh63dlUdel+9g2ksGrNPV8X+8YUq920iFlDzfHM5Sr5F8ZTJVbz8XE5ubRBSOjt6X7OJW/2WnhzQ1Lb6eXZ5xWuYgMLz9DdWwzx86syNnQoEuKmF+3Fd3m+uwU3UVXVYfgxVS5CFaG5C1aawkLv49oKQ34aaCUl1sFQFMdvmcnk6V/SYDyWsyCBXB+wlc0E4jMJSHto5Bo57JDfSSPmwQFsulBmiH53H55gKb7cYeD+f+LADy0YMSXmB082ipRe6qmLKwyjlr6Viq9KGUjdL9/pYULmjPLRhF4tpkKKaG1TqMsFD+uchHWdXy/xVqpA55l7jste0hBOArMTstrltaQZ5HKav2jp2C8K+Xo3BD9LlAKH+XZ1iqDrT8a+jbnvdQHeEqbRy7inL+C331HDLG7g/azvAioShsyPGc/kglyneEE3/8nTehhhfGgqx0jMK3iCFRqJI4pTe5ZnVwF/rDTw6lArpwZ/7cxXnC5Qq58wJ1NNhxjqy25C7qEOFthjOBg+LyPkgJ4m3lmt0oF7XmJVNdHdn9XahUXK68yuxyOwGuVBSvC4i0sGd/VvbCE2+IWfIPlH2t6QmM+3eBqIvpJZUrbnN1gGXXgfxQWW60PK3RcupUDToqxvoO9EFDLMCmK6WfW7s134e5sF+KNtB2kFtwi+Ck9mdv0Y4qPyHQihwcO09hXW0wf1Kn619GIBb8hAdBAKad3Sq89r03CBdKoHhB7ylZEAsWX8tDIyoZTksVmgT1kedvtWsjbxvswNaOpPpmdxiMiU4TtEMp7XDRE7+DIUQtWBOQon/htDMP4ywxpY5s363626SRO+hyAK83WgjV+5tlVeVaBp/qjcF6RZhZj0mM0OiGrKxziFPisigiWYC2DG6dzhD6WjKX7+iLGvcxweyvT6QDRuve18hRLfCuHv0Sbf+YrVwtukF9fTz/xg/CjXefyK0T/yGv3hqxoEBARXs+syPi+t4wFV5YcPHqTs8MRUtM9M4Vioaf5pPVnVSp2htDfSwxSejPzNvlRoaRwO6HTZT6EntC99TwJkcwdDfCkk3vgL5SAhhEWqQWz0F3+iVpNapOjU2sjfZuNocV00MkYblKv7kBhG26oq72zEm2S0PpBpyYYPfmqNXYROqdKpuREr4f5JzLNBD6kjuOkXnjMoDXqmblYFDXoXbhTIr3RE+TZB7WOnUeh+Edk/sZ2WaZLfCsW7KM/RRHPdRxUekj2RGo1mJChBmoxhCNJlXbqGqk3LMq7pVXCY9jsIiEUafSp8HC6wRZ0KkxuUyLC7vWNz1/6x/AA31Ez60g6IqjECqnb6cO1Flc6nRlBCRnlw+OORKpHmLrZcwWsBWe80iQ+bL0GpT0XB2vhFUEsDzUnfPp428RxpVDtfWT8LtIE2kEwVHaX4kjx2fPNxalFjx+AddLhzPupLml8OBY+3d2MJ10DYHhPFkxK+Brm/M1xQEysx7WJolX55qDJWfc5n2Wa9v73l0s4PM4oQV588FTwPY1wulbQ2vq1g/1FSbwiD0QwOlFI5o9XRBx9iL09DQBzr+7Xw3fo//2Yuz3aTHwZyon9w8pQPtoFiZX06PMALqiLdE+7oQc3UbLvS/xyKUdIP7NUeZJXfQSnAKOfZlYuVzO24Y6I3kVS8H8uixn/eT9xw/d6jKrxrEsSytjFBglcFxTQhuIjqS0W0EzDu9YFiMOayO6/A1n+HBrlVumPiozkmUeokdZNgNTtWVJvlzHzOFYbTxQd3GFq0dXMLdma1F2laTX9JTlL6zQFEhfQstiUxnLc36vCUVA/letrI3xfbRldHJuojEEXH8mjm8ZU06tH73E5y9V0i4oy7k8ySnorg0J/7LcTHY90k2oL0Z/EwDQ9Tei4wmRfNcqCM6TGRfCLmgLq9QMijH1t+io0ep4p7q9iCfhyo08wekFvXgrRRuNJ6prkb010Ogw+R1slN1nJX6uvQGWL3E+dbSKdpHWjut8amcAu3zPX75TrZ7rCRMLIxZMCC5brzbSstQUtWArdM41eLWvN5zLZI7RgYJT8iGtEMbtLTf6qlJGTXk/xPtdIoaNgUaHTg5AqiNInYQDD0a9l/PxofjRFw5RSsttmOhITXNyCtVagvk0tWNzGgCSYSy/W0EmHZkyX64eYBrhOdE1b8F09RGjcJt9PTFwywhhhcooKyak0pe5KqF6wK4Rlol1GmFkX6kGpkPsXCUttwfNqM+kvYcEb8xbRW6PMoO3a1b/zQwvWp2G62V7Q6AJq7xQzOMZzIZMWLOMJimOs1Ad/ZZUxfXuTu0nnujTgKaxFY3w7hTF83E86GFvEAYsOU0NRo9Qi0a4MFUZQjyy4gtY05ESpRpk5kROF+PSMn6g/VC2Ykm9s9kyjNJT65pEbNGjSaHwbPUGrTSRLxX2wJXBeas6PmNRK5Z8RCcFW1Q0ZsTDos4qiDti44eNSw0yxqXpuwVoK/jIk/9/owqiSj/qav40RITuhEcRPZwQEcq+81ZXytO3w8y5udEF14pQMck2nmKlZnqIv5SFGOpP8XZVbpbP7JSuTv4nsr6kBdfoRHe7jXs/ItIXj/OgjFrnV5z7UO8TDGemxBWfhEvtWUtJMV7eULJjD+ZAQ2i82RvCiTB9QuaKHsKmHwnEW6d9YID6YPWSB1nq1srsnIJDbHRg05jo0mLMnLQejPEpx9crw/yxOr1MLPkrzWPXJPLc62Li9d+ic6Grem514Uxm6epYT3So/vTbk7X8Rdqkry5UYdd3Cbi2lxdFPp7Pyw/3GENMsREuLGv/G/QdKiepSg4nob5YWS/YVla+L8CjH+nBOEY1zdEbH98iDa8SppCpHOJvt9gJvwRpItyjH0MTGuznVx8Tr2DNCsu9BGlwNMQuWy6weokV2t5PAophOdNEipWb8tn7wOM9HIxXDRfJBsOC4zHI816E+5qIWnFKT2laSGn5XoAw0Lm//7j3+wH9PXnwmnMO/3y7rTUaw/6X3E/HuasExVQ7jLYUulsjDiuDCPs2SIw+M3uUKtEeaQ6asiwOLWnDDqo+US20bqHsHRwX4xSvMrKtNeo2HmqgRP2omFlTIwOo0V0rThB0hcKVf0oLjigXDEdlQZB8z4fHYyO3tlkBEJXU/1OFri/cU34MpWxdZVvIS+jNn+z8MkkGvTOILb2b5yB9JIiOr95jTjec7oqcx+wxejjdYxjJGivS00FCYSrhun1AqmhSJyLrz3S+IgHK1njirV6SOU+q0CaE1vVzF+tNd/g+xHRbBedABQyZIx7sgZ7dfAVxAZl7RpzMaFv3wUn9OE4X7Up8Y3psMWAHIzQcrOSF5Z9Wct6wQQ3mQBxW478lEibez9bZ/geunEU0spF04vngPVG6sfyRxiJljQ5K/O5qjZRm3NCGelYzA39X5e1DF4gs/5ZEjsKbAN2BtH4ckuiPS9YvQ+lJItox608uGXfgAf+aC1+P4kyR8JUYkAUoLXeHWkAQoa+zOf4sGLDZPr67gAUbqODQcvLKOml1bXNshnQayNB6bgfFUidD6JCgwktog9GpeOek5l5gimSL71pi0m/Cn8MhoiepVLolPdf5Mpk4Wn4jZkIZAERw87TGXbwtOb0/6zZXjpNgDDT7bUP3P4UUsOE44nxJe3G4aJmflVOO5XrNPAksdBBc90lfHx7er/LqHFqwI7Z0gcPV0ecB9Lwuup+Op73GxMEW0Qlc8ql/iIoMSW6HHDFTkhowP1zu4nVXu+ru/0styOQFAFwbx/sfi2fbNBId/gcX0kafrbA5H3llxlmGl49sjsx6PhrHxMPqsg0znoFPKcFV+bnMHvYr5pkLSQMLWGOoBuaU2aYpM9WeD9CRkzix6UHqOM6VE/xOXF0OgAblBi0ej7TL55OyO21x5C74DaP8a3meuL1lssWlufP155tfso/mTke7RklM5C94mTvQhRl60UDS+Ni8BU47TnUAD7qGWNB/mXEGsZ6tU2QZKxn9E7iQTeoTfmHR22bif1ByfCSd73wJR9lanH5lfOCMkvizv9TNxduKyAhZso5VX1Mi0v6tCWeMzqANfy8Vf5FHitKH0B8arpy3Y1uzUXCojiBFazmGxDCN25VDDf5JfCRGASoYGZSAd5RORViMDpVN6yIX9SKUTqmjJqfZcLdgCOV6O0+nT4Wg7xTUbf06VAtaL3OoSl7LgLLn33H6Q5a7ALvIkeUAr/Laa1hHZoxaLtOfE7kdZivouukNQRXGBdd/bgjNFL6An4s9EIhx9NyQuj5DuaSftv5kQ3XSKz83hMJQ6uqqdfg/qjYwq2uGUbpTiFR6kDPd2SDJOpPIfxfmDNqT/Nj70Vg/dT8OA+WEQgyvQx5zZOtwqdLkqoXhEFyT03IKdjlREnyNVSMtAqruXA3PUJu4LWdTKi28freiGL0la0ibfg8p9xv3b/aiD4i0cmWUQo4lAKxJ9vFzp8Qb9NsqOd3xVOxIK+NPd9YUsuCguYnuyZTueatEqas53ulIoawFHUStPQ52HAYpbRgpwh2zQOS2eNQbhftLlus/oYrZWp4tXUkPw/py31/QRDqSaPIM5JO/8cRqIPt8FTYk7+VoPpItBxS0YQzxkms3NXjfAMVfRrtQeyhrjzRiCup5bsPowDTuuYwfK0/Lib7Pw/mUl9wHa5CO1FsbYWRcZ99tm7iEm/c0hp7rY5bz5NkNWviSSigir3+gHnNtpC06Djx4sHvUhUySAz9Xj8oX2RRNerRHYQmVYy43Nv4lBI5qSHyGCExLcGXpJITonFGejc+Sf0AT9fQOfDqtAcumuvAdnZzlP2eh0SFZ6H2JUn3b2YDCBrtjQ5eWRcv76yJyGrnfQI0r1cfWU8hg9Hrl+Zbx3uTBMzQuKI/JYwaD96AhBsWP9ejcnJgoP5GzsOvc/R1/n5NSmROx4b/FqOeqlStkef43qVipWh3C3uetUXoCdfNrn6H8BxVGktnCf/CvXu2hPYg3IqTM+waXkEv1rOdCJ7eQap0nHD8B8TMhP5TZw3oVFmmnLCIzL0kQ+poWPNfaSjLIl8gtynstAfMBCuPpXFaCl1oIBuwudQ7B3Qc5TuQhsymHjgGe46J92pVmd1IZDqj3fPtsF6a9JmInKbC23nx3SKvoefv6CnEeikXAbSeoLIe6iNladQZ8ll+0wMOYLcr6Imu8sGSFQevEhF819n3MGgwHj4YKcR7JLhlg5O1KW+pzKNPnRFshSIxTJjOe+IOeN6N4yoB6OmGtPuN9LpcI0dFUBLV+Q80nuNRioI+UWHjQoaEh0G3NdL8j5JTWmpGnX8arMknXhVk8xGe+CnF9SA2vokBQ/FXe4Lotu/VjqcV/LQurfBTkfZRzMg0vpvfzY5QOeq8O+7FDBlWn2fEHOI5ne3V33ndorYDkoFHlMWAHXAtYjNEdHar+WA+CCnEcyRXC/qnYzj6J2E7rjfPPBF2RB2H/VKlV1znZeKXUZ3Qzu94KcdzIbDNTnNDu/BfL/gIs2BPsB2uoy7uNc/C2R9h46UedND/GC/H/Z+dV1BMjijgAAAABJRU5ErkJggg=="; - -string __red_pill_image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAIsUlEQVR4Ae3d/29ddR3H8Xv6ZVvazs4C2Ro1G0EX2RzGkQgJigP9QTSUqb8sWVKjCQqaKCGpASWZzi1CMAG3KBolJfEHg4jBCNHhUMMUMTPYL260a0tpu663a9fvu12/3B6fP5xPcnPb7dPz5d7POZ/z/uHxB8Dr+WnOOffu3IzruikmbP8PFBKAkACEBCAkACEBCAlASABCAhASgJAAhAQgAVQ45VSBD+AefAOP4/v4Lr6Mu1EPB5mgVjx5LHuWCixiwXMF856c5zLmMIsZzzSmMIkJzyWMYwwXMYosRjwXMIzzGMIgBvAu+vGOp89xMr3owTlPl+dtnPWc8fzP01Gg3dPmU6kHb8AX8TT+gjEsw72GRfThFTyG21CVnAAkgG14EG9iCW4ERvAM7oATzwAkgL1oxRW4JdSFh7EpHgFIALvwEpbhltEUWrDBTAASwPX4hTrxBp3DveUNQAK4D8NwY+QEdkkApQ2gEkeQhxtDSzjG+A3RByABbMbLcONsBRhHCwHUSADRBFCJV5MxPpAHehn/znABSADV+DXcuCscX2H8PFoZvtF/ABKAg6eSND4KxwfA8DN4BBslgPUH8DW4CT79avxCvQSwXwLQB3AX5iw5/QAWPYx/Eh+RANYefyuGLTv9BeMDjL+EVsbfDgmgwCtw7T39KgCA8XM4zPi1SH0An0vX+EAOGMJBAnDSGkAF2lIbAC4DJwlgexoDaErz+CqAOWCWAL7H+JvSEoCDf1hz4acJYF5Za3zMehj/HTQTQKXtAdwmf/oLAsCMZxpoJ4C7bA7gWctOv358/elneGAKk8CLjH+jbQHUYgLuanL6pzyTmADmcZQA6mwJYL9c+BWMf/XTz/jAJWCYAJoJwEl6AM/Yf+GnP/2zutNfFMC4hwDeJIDbkxzAWT9DyOkvGB8XgTwBtBLADUkLYBvyabnty/k6/QXjawIY9RDAOON/E1VJCeA+ufALe/oLAsAI0EkAn0lCAIfltg/rHB9qfFxlfFzAMPASAdwU4wD0X/SU2z796c961PgqgPPAFQJ4nAA2xzGA/9g6vvnTz/gY8hDACAF8hQAq4hTAgPW3fdrxw5/+kauefjU+MAACOEMATXEJIBt6LLnw059+NT76PYz/KnabDmAs3Rd+KMmffhSPXxwA+vhaGgEcJ4AGUwF0asaQ0x/gwk9/+oE+MD6cUQL4kokA/iqnvzQXfvrTD4fxPT1g/D/iQ+UM4HiaTv9sOW771PjrPf3oUQEAC4z/UzSWI4AHNaPI8/7oTr9+fHSjC5ghgEcZf2MpA/hgup/3h7/tG9affv2f/uLx8baH8fvwhVIF4OCinP4At30BLvx0p79rzQAAxn8Ne0rxcfBvrDr95m/7wPiRnH41PsDwy/gZrosygK+m7nm/ods+/ekvHr84AKDTcSYY/luojiKAm4yNb+DTPpO3fb3hTj+ATnQA57AvXADAafN/+hP7aR/jQ3vhF9HpR0cBhp/Do6gKE8DD8iXPwvFLf9sX9PR3rA5A+TOjvjdoAPWYScOnfZPBT3+5bvv0f/qLx0cb0I2b/QcAHINbQJ73a05/1Ld9Z32c/vbVAShZ3BokgPcjF+fn/Yjn837zp7/YOD7mLwDgCbjhyfP+0Ld9wcdXRnGj3wDqMShf84rXhV+gAIDTqFl/AMA9ibvtM/A1r6AXftCMj2jGV1r9BBDgn4vJp339Jm770LZ++/0GsAGvJ+WlDuZPv/kLP40stq0/AKARg2n9kueFuN/2+dfqLwBgD0bhBpem5/3mT7/GLf4CAHYjm/J/3aMCMH/bF84L/gMAdqJbnvfH/rZPJ48d/gMAbsAJS17qkNzn/eE9GSwAwMEPkLP9a16RXfgZuO3TyIYJQNmHQSte6oCR9Jx+5dPhAgA24RHMJPNrXijLhR+CXPiVNoAjUQSgNOI55OW2L/anX/lXlAEoH8cbBk6/uU/7HMO3fcEtY0uU4ysOwx/EkHzaZ/7CT+OT0QeAFaCW8X+IXPjbPnneXyIPlS4A5IEdjP8clix5qUP8nvcH95PSB4BlYA/Dn7TjpQ4WnH7ghfIFgCWgmfEnjX3JM2W3fRp/L38AYPytDP8s8qU9/XLbp/FfMwFgAbiV8U/JlzwNjA+0mQ0AjO8w/AEMWPJSh2ScfuAt8wFgHqhh+BaMx/6lDjaMD7wWnwCQAxoY/xjjL1nyUgcUjR+fAH4fxwDUL3fuZvwT5l/qYOnpB56IcwDqlzub0GPBSx3iNT7w9fgHAGwggBbGnzbxvD+q098RvwA+lZQA1C93vo/xf2vJSx1Mj7+ILUkLQP1y5z60W/JSB1MB/BuZZAYAVDL+A4w/Jl/yDORI0gNQv9y5hfGfYvjFRL7UwYwV7LUlAPXLnR9m/D9BnvfrtSNjVwAYBT5PAN3yvP+aHrI3ABBANQE8wPjD8rx/lUu4zvYA1C931jH+Ucafj9VLHcw6ikxaAlC/3LmT8d+IzUsdzJlHY/oCAONXMP79GE3lbR/wI2TSGoD65c56xv8xwy+U+7avzaxBbJYA8C4YfydeTsnpn8VHkVEkAA8B3EkA/7T8tu/byKxFAgABOIx/kOGHLDz9z8O5dgASgPrlzlocZvycJeOfRt263xQqAQAEsJ3hn8dKgm/7erA1yLuCJQB0AZ9l+KEEnv4R7EBGAggTABj/PTjE+NMG/nVPEOdxCzKRBCABAIy/leF/hXyMT//r2IZM1AFIADgD7GX4UzEbfxlPYiMypQxAAgDjOzjA6AMxCKAdn1CDSgBlCQBg9BocwmUD4/ejGVXISABmAlCuZ/jHkC1DAB24H5vUiBKA6QDQDlTyP/VevIjZCEefxC9xNyrVeHELQAJAGzw1aMJxvIWcjy9sDuJvOIQ7UI2MkowAJIBidbgd38HP8Qec8ob+HZ7GAewKcsqDB+C66SUkAMtJAEICEBKAkACEBCAkACEBCAlASABCAhASgPg/csK8SMv+MG0AAAAASUVORK5CYII="; - -string __blue_pill_image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAJMElEQVR4AezStw3CABRF0Q+9gwdgGTqmoGcEKiowOWOgJuecmc0861uip6CAV5wBrnTF9/0/Rr8dSByAOABxAOIAxAGIAxAHIA5AHIA4AHEAEqf//KYoxCABKXAhA2lIQhwsiIB8rPd4695DN3E8ZXtXsTuBi2qfVesUOordPKjGXqxAfadqW1XdiFVZw0qVl2KWFqo4V4UZTMXMT5Q7FjM3EiOQHcJAjFd79/9b1V3Hcfxc2kLT3q7ItkCjCSxToiAzssQtmU6m/uCXjKH+QkJCosl0i4kuSzBbnMNBiSNz2dZGUaGU0iWsTth0NI4vc2bonMHM4aKRfdFQJBTBfSmzbLR3x+e56Ttt8jHXcz89537O55z3D49/gNfz05zPvZd7t0QGg47u3cDmAWDTrqAcuacfO4Py9yJ9wMbIjqB89/Zp3/2plbQHX4Av4UEcwllMIqzhIl7FMO7CNWj2JwANYBFuxXOYQJiA09iG61DSALIZwEr0422EKfobbkerBpCNAJbhcfnT3kBvYAPmagBuArgMP5ET79BLuLGxAWgAN+EUwgw5gGXpBqABNKEbFYQZNIEehl+gASQfQAf2I8wyRo+cwwa0aQDJBNCEg56MP9MrjH+9BjC7AFowiNC/AA6FjF9BPwF0aQD1B1DCA16OD4aHODjG+HdgXvwANICvIfT49Mv4wLaqVwhgjQbw/wO4AW/5Pz5kfDB+FQEcZvwPQwP4HxbiVG5Ovzk+noxMoJ/xF0MDgBj2e/x4AQjGH8cmxm9H4QP4vLfjw2J8AIx/EusIoFTUAObghYKdfhkfYvgw4y8uYgCrizi+EUDvMPafx3cIoLUoAZTw25xd+4wAYowvAYTzeyJP/J0A1jN+U94DuEZPvzF+2Bl5KPLLY7ghzwH0+RtAon/6ZwYg41cxfGQvrshbAO14raAPfrVPv4wvAYDxL2ALAZTzEsCaAlz74p9+Gd88/RIAHgsJ4BTjr0fJ9wC2FeDBL6nTX8X4U/aFnffve44ArvU5gL/WOYaefhkfjB9ecv/eCuP343LfAliESjGufRann9Frn34QAMOLc4z/DTT7EsBNCPXBr/bpZ/gap386AIYXLxLAZ3wIYBNC6LWvzj/9xumHBMD4GIo8zvhXZjkA84Oeeu2zP/0yvgSwNfLI27iXADqyGMAfcze+xenvtDj95vjG6Y/GB+6N7DlNAF8hgDlZCuBE4a59vbO99tV1+mX8KgIICeAvBLA6KwGM6uv99g9+sU+/jA/Gn/LwQQJY7jqAs4V/8EPtP/0i9oOfnH5zfEgAjB+ZIIBexl/gKoAXode+hB/8Ypx+xp/SPYjdZ/BlFwH82tnQevoxKAGEHZsjA0/gA40MoFevfTEe/KxO/564p39mAJF3COCHBNDViABu1df7U7r2Gac/xvhg/CoCGCOAOwlgXpoBvL/wr/dbnP4Yf/qBGH/6YY4Pxp+y81UC+GJaAZTwL6vB9PV+iwe/GKffDCAkAPQ9hRVJBxDZ48ODnxlAhh/80JHM6Zfxqxh/Ej8igEuTDOCrFqPp6/3Jn35zfDMA7AjLd+94jeG/iZYkArjS/fjZfLdPxhd2D36YOT5i/+k3x5cAsD3yElbNJgBxNO2x9fQP1nH6ZXwzABlfMORbuBPNswngdr321RgfyV/7bE//diEBiCfxHtsAOjFWgHf7YnzMy/W1zxy/xukX4jg+ZBNApCfRgfXdPovTvzP+6TfHF6O42iaA92HcblR9vR9xX+9P/vSbzuGj9QQgtuqDXwqv9yf/4BfHGVxRbwCdGPH/wQ8evN5vce2LG4A4ira4AYjP6bt98T/mFf/aNyBqjZ/A6Tf01xOA2OZgfH/f7WN4B9e+eqypN4C5eMaLd/vcf8jTDCDla5+FUSyKG4DowkhRr30M78u1L67+egIQK3CmwP+7x/5jXg4e/GK4qp4AxHKMItRrHxxe+xLwqE0AkaU4HmNwfb0/m6dfVLDEJoDI5Tjg8Zc62L/eD/ev9yfmPpsARAn3YDwT174e+9Pv/7XP2qhFAIZVGPH8Sx18fLcvKZ+2CMDQijswpv+7x/ba52B8oDuJAEQXdqFSgGuf76df/D7JAMTH8GzO3u1z9TGvtE1ifpLjixKjr8NJ/7/Uwf3HvFL2ieQDAMNH2rGZAMbtr336en/KbksxAHFoCePvwkQir/ejoB/zSsNDjQhAfr51BcMfdvkxL33wMzzauADA+JH1jP+6Xvucji9+0/gAwPgLGb+P0Sv+f6mDl6df/MlVAPLLnVfjiP9f6uD+2mfpBdcBREoMvxYnYr3bpx/yTNLz7gMAw0faGH0Dzjn6UocCXPsMT2UnADB8ZAF6GH8iJ1/qAGP8rASwL3MBCAJYTgAHPPhSBx9Pv9ia5QDklztXM/7L+jGvVHzdhwACApjL8BvwZuO+1OFh8/R79np/DJ/0IwAwfuS9DP+znHypg2sXMd+vAMD4kVWMf8zphzz9P/1/QOBnACCAJgK4hQDO+v+lDk50+x4AHgsIYD4BPMD4F/Xdvtjexcq8BCC/3PlBhv+VvtsXyzEEeQtAfrnzCwx/XF/vr+m2/AYAxm/BLYx/Sl/vN/wbl+Y9gCoCKDP+Fk7/BQ+/1CEtWxAUJQAMBQSwlACedf+/e5y7gK4iBoBH5jD+zThTnHf7DN9HUNQA5Jc7Oxn/Bwz/TkGufWIEHRrA9C93LsV+F1/q4MB5fATBNA2givGvx+9qnn7/r33fMsfXACSASIkA1jH+yRye/iGUNIBaAYAAsLudADYx/nhOHvyOohz/m0I1gIAAMLCY8YfwrsfXvpexEEH9AWgA8sudn2X4kx6e/tNYgmA2AWgAYPxLsJEA3vTkwe+fuApBMgFoAFWMv5Dhd6CS4dP/DBYhSD4ADQB9kZWMfyRj40/iPsxDoAGkGQAIoEQAaxn9RAYCOIaPy6AaQGMCkF/ubMNG/MfB8P/AejQj0ADcBCAu4x/zLowiTNmfcTNaZUQNwH0A8g/ahBuxF+cTHP11bMen0CTjZS8ADWCmNqxGL57HeB0f2BzB09iI69CCQHgRgAZgKONafBs/xi9wBE/j53gQa7FMTnkjBGEYFpfKeQBKA1AagNIAlAagNAClASgNQGkASgNQGoDSANR/AWJ2EQGXgXEIAAAAAElFTkSuQmCC"; \ No newline at end of file diff --git a/Source/relay/TourGuide/Sections/Globals.ash b/Source/relay/TourGuide/Sections/Globals.ash deleted file mode 100644 index 2362ac03..00000000 --- a/Source/relay/TourGuide/Sections/Globals.ash +++ /dev/null @@ -1,69 +0,0 @@ -//Runtime variables: -location __last_adventure_location; - - -//Runtime call functions: - -//Init functions happen after state and quest initialisation, so they can be referred to safely. -string [int] __init_functions; - -void RegisterInitFunction(string function_name) -{ - __init_functions.listAppend(function_name); -} - -string [int] __checklist_generation_function_names; - -//Call function registration: -void RegisterChecklistGenerationFunction(string function_name) -{ - __checklist_generation_function_names.listAppend(function_name); -} - -string [string][int] __specific_checklist_1_generation_function_names; -void RegisterSpecificChecklistGenerationFunction1(string function_name, string checklist_name_1) -{ - if (!(__specific_checklist_1_generation_function_names contains checklist_name_1)) { - __specific_checklist_1_generation_function_names[checklist_name_1] = listMakeBlankString(); - } - __specific_checklist_1_generation_function_names[checklist_name_1].listAppend(function_name); -} - -Record ChecklistGenerationFunctionRequest -{ - string function_name; - string [int] checklist_names; -}; - -void listAppend(ChecklistGenerationFunctionRequest [int] list, ChecklistGenerationFunctionRequest entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -ChecklistGenerationFunctionRequest [int] __specific_checklist_generation_requests; - -void RegisterSpecificChecklistGenerationFunction3(string function_name, string checklist_name_1, string checklist_name_2, string checklist_name_3) -{ - ChecklistGenerationFunctionRequest request; - request.function_name = function_name; - //Hardcoded to match call structure: - request.checklist_names[0] = checklist_name_1; - request.checklist_names[1] = checklist_name_2; - request.checklist_names[2] = checklist_name_3; - __specific_checklist_generation_requests.listAppend(request); -} - -void RegisterTaskGenerationFunction(string function_name) { - RegisterSpecificChecklistGenerationFunction3(function_name, "Tasks", "Optional Tasks", "Future Tasks"); -} - -void RegisterResourceGenerationFunction(string function_name) { - RegisterSpecificChecklistGenerationFunction1(function_name, "Resources"); -} - -void RegisterLowKeyGenerationFunction(string function_name) { - RegisterSpecificChecklistGenerationFunction1(function_name, "Keys"); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sections/Location Bar Popup.ash b/Source/relay/TourGuide/Sections/Location Bar Popup.ash deleted file mode 100644 index 33ce6898..00000000 --- a/Source/relay/TourGuide/Sections/Location Bar Popup.ash +++ /dev/null @@ -1,1415 +0,0 @@ -import "relay/TourGuide/Support/Banishers.ash"; -import "relay/TourGuide/Paths/Bad Moon.ash"; - -Record LBPItemInformation -{ - string image_url; - boolean should_display_drop_current; - string item_drop_current_information; - string item_name; - boolean should_display_drop_base; - string item_drop_base_information; - string [int] tags; - boolean greyed_out; -}; - -void listAppend(LBPItemInformation [int] list, LBPItemInformation entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -buffer createItemInformationTableMethod2(int columns, LBPItemInformation [int] items_presenting, boolean want_item_minimal_display, string table_class, string table_style) -{ - buffer output_buffer; - - string [string] table_map; - table_map = mapMake("style", "display:table;"); - if (table_style != "") - table_map["style"] += table_style; - if (table_class != "") - table_map["class"] = table_class; - output_buffer.append(HTMLGenerateTagPrefix("div", table_map)); - - - foreach key, info in items_presenting - { - if (key % columns == 0) - { - if (key != 0) - { - output_buffer.append(""); - } - output_buffer.append(HTMLGenerateTagPrefix("div", mapMake("style", "display:table-row;"))); - } - int image_size = 30; - if (want_item_minimal_display) - image_size = 15; - - //hack? - float percentage = 33; - if (columns == 2) - percentage = 50; - if (columns == 1) - percentage = 100; - - - int [int] image_sizes; - string [int] image_classes; - - image_classes.listAppend("r_only_display_if_not_tiny"); // r_only_display_if_not_small"); - image_sizes.listAppend(image_size); - - //image_classes.listAppend("r_only_display_if_small"); - //image_sizes.listAppend(MIN(image_size, 20)); - - string image_url = info.image_url; - if (image_url.length() == 0) - { - image_url = "images/itemimages/confused.gif"; - } - - foreach key in image_sizes - { - int using_size = image_sizes[key]; - string image_class = image_classes[key]; - output_buffer.append(HTMLGenerateTagPrefix("div", mapMake("style", "display:table-cell;max-width:" + using_size + ";max-height:" + using_size + ";min-width:" + using_size + ";min-height:" + using_size + ";padding-left:3px;padding-right:3px;vertical-align:middle;", "class", image_class))); - - //Generate image: - string [string] image_map = mapMake("src", image_url, "width", using_size, "height", using_size); - - image_map["style"] += "display:block;"; //removes implicit pixels around image - if (info.greyed_out) - image_map["style"] += "opacity:0.5;"; - image_map["alt"] = info.item_name; - output_buffer.append(HTMLGenerateTagPrefix("img", image_map)); - output_buffer.append(""); - } - - - string main_tag_style = "display:table-cell;width:" + percentage + "%;vertical-align:middle;"; - if (info.greyed_out) - main_tag_style += "color:gray;"; - if (want_item_minimal_display) - main_tag_style += "font-size:0.9em;"; - output_buffer.append(HTMLGenerateTagPrefix("div", mapMake("style", main_tag_style))); - if (want_item_minimal_display) - output_buffer.append(HTMLGenerateTagPrefix("span", mapMake("class", "r_location_bar_background_blur_small"))); - else - output_buffer.append(HTMLGenerateTagPrefix("span", mapMake("class", "r_location_bar_background_blur"))); - - if (info.should_display_drop_current) - { - output_buffer.append(info.item_drop_current_information); - output_buffer.append(" "); - } - output_buffer.append(info.item_name); - output_buffer.append(""); - - string [int] secondary_line; - if (info.should_display_drop_base) - secondary_line.listAppend(info.item_drop_base_information); - if (info.tags.count() > 0) - secondary_line.listAppendList(info.tags); - - if (secondary_line.count() > 0) - { - string [string] tag_map = mapMake("class", "r_cl_modifier_inline"); - if (info.greyed_out) - tag_map["style"] += "color:gray;"; - string wrap_type = "span"; //"div"; - if (want_item_minimal_display) - wrap_type = "span"; - else - tag_map["style"] += "display:block;"; - - output_buffer.append(HTMLGenerateTagPrefix(wrap_type, tag_map)); - if (!want_item_minimal_display) - output_buffer.append(HTMLGenerateTagPrefix("span", mapMake("class", "r_location_bar_background_blur"))); - if (want_item_minimal_display) - output_buffer.append(" ("); - output_buffer.append(secondary_line.listJoinComponents(", ")); - if (want_item_minimal_display) - output_buffer.append(")"); - if (!want_item_minimal_display) - output_buffer.append(""); - output_buffer.append(HTMLGenerateTagSuffix(wrap_type)); - } - - output_buffer.append(""); - } - output_buffer.append(""); //row - output_buffer.append(""); //table - return output_buffer; -} - - -buffer generateItemInformationMethod2(location l, monster m, boolean try_for_minimal_display, boolean [monster] monsters_to_display_items_minimally) -{ - int number_of_slimeling_eligible_items = 0; - foreach key, r in m.item_drops_array() - { - if ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3] contains r.drop.to_slot()) - number_of_slimeling_eligible_items += 1; - } - - - LBPItemInformation [int] items_presenting; - - foreach key, r in m.item_drops_array() - { - item it = r.drop; - int base_drop_rate = r.rate; - - - - int adjusted_base_drop_rate = base_drop_rate; - boolean drop_rate_is_actually_zero = false; - boolean drop_rate_is_guess = false; - - //r-type? - boolean item_is_conditional = r.type.contains_text("c"); - boolean item_is_stealable_accordion = r.type.contains_text("a"); - boolean item_is_pickpockable_only = r.type.contains_text("p"); - boolean item_cannot_be_pickpocketed = r.type.contains_text("n"); //FIXME use this for anything? - boolean item_rate_is_fixed = r.type.contains_text("f"); - boolean item_is_avatar_potion = r.drop.item_type() == "avatar potion"; //r.drop.to_effect().string_modifier("Avatar") != ""; - boolean grey_out_item = false; - if (item_is_stealable_accordion && my_class() != $class[accordion thief]) - { - grey_out_item = true; - adjusted_base_drop_rate = 0; - drop_rate_is_actually_zero = true; - } - if (item_is_pickpockable_only && !__misc_state["can pickpocket"]) - { - grey_out_item = true; - adjusted_base_drop_rate = 0; - drop_rate_is_actually_zero = true; - } - if (it == $item[reflection of a map] && get_property_int("pendingMapReflections") == 0) - { - grey_out_item = true; - adjusted_base_drop_rate = 0; - drop_rate_is_actually_zero = true; - } - if (($items[folder (red),folder (blue),folder (green),folder (magenta),folder (cyan),folder (yellow),folder (smiley face),folder (wizard),folder (space skeleton),folder (D-Team),folder (Ex-Files),folder (skull and crossbones),folder (Knight Writer),folder (Jackass Plumber),folder (holographic fractal),folder (barbarian),folder (rainbow unicorn),folder (Seawolf),folder (dancing dolphins),folder (catfish),folder (tranquil landscape),folder (owl),folder (Stinky Trash Kid),folder (sports car),folder (sportsballs),folder (heavy metal),folder (Yedi),folder (KOLHS)] contains it)) - { - if (base_drop_rate <= 0) - { - base_drop_rate = 5; //assumed - adjusted_base_drop_rate = base_drop_rate; //assumed - drop_rate_is_guess = true; - } - if ($item[over-the-shoulder folder holder].equipped_amount() == 0) - { - grey_out_item = true; - adjusted_base_drop_rate = 0; - drop_rate_is_actually_zero = true; - drop_rate_is_guess = false; - } - } - - string [int] item_drop_modifiers_to_display; - boolean yes_it_is_actually_zero = false; - if (adjusted_base_drop_rate > 0 && adjusted_base_drop_rate < 100) - { - - float effective_drop_rate = adjusted_base_drop_rate; - float item_modifier = l.item_drop_modifier_for_location(); - Error error; - // if (it.fullness > 0 || (__items_that_craft_food contains it)) // Switching to use mixable/cookable - if (it.fullness > 0 || it.cookable) - { - // need exception for chateau de vinegar; booze drop only impacts it - if (it != $item[bottle of chateau de vinegar]) { - item_modifier += numeric_modifier("Food Drop"); - item_drop_modifiers_to_display.listAppend("+food"); - } - } - if (it.inebriety > 0 || it.mixable || it == $item[bottle of chateau de vinegar]) - { - item_modifier += numeric_modifier("Booze Drop"); - item_drop_modifiers_to_display.listAppend("+booze"); - } - if (it.to_slot() == $slot[hat]) - { - item_modifier += numeric_modifier("Hat Drop"); - item_drop_modifiers_to_display.listAppend("+hat"); - } - if (it.to_slot() == $slot[weapon]) - { - item_modifier += numeric_modifier("Weapon Drop"); - item_drop_modifiers_to_display.listAppend("+weapon"); - } - if (it.to_slot() == $slot[off-hand]) - { - item_modifier += numeric_modifier("Offhand Drop"); - item_drop_modifiers_to_display.listAppend("+offhand"); - } - if (it.to_slot() == $slot[shirt]) - { - item_modifier += numeric_modifier("Shirt Drop"); - item_drop_modifiers_to_display.listAppend("+shirt"); - } - if (it.to_slot() == $slot[pants]) - { - item_modifier += numeric_modifier("Pants Drop"); - item_drop_modifiers_to_display.listAppend("+pants"); - } - if ($slots[acc1,acc2,acc3] contains it.to_slot()) - { - item_modifier += numeric_modifier("Accessory Drop"); - item_drop_modifiers_to_display.listAppend("+accessory"); - } - if (it.candy) - { - item_modifier += numeric_modifier("Candy Drop"); - item_drop_modifiers_to_display.listAppend("+candy"); - } - if ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3] contains it.to_slot()) //assuming familiar equipment isn't "gear" - { - item_modifier += numeric_modifier("Gear Drop"); - item_drop_modifiers_to_display.listAppend("+gear"); - } - if (it == $item[black picnic basket] && $skill[Bear Essence].have_skill()) - { - item_modifier += 20.0 * MAX(1, get_property_int("skillLevel134")); - } - if (l.environment == "underwater") //FIXME underwater drops are complicated and I'd have to look deeply into this to verify - { - //item_modifier -= l.pressurePenaltyForLocation(error); //pressure is actually already included in item_drop_modifier_for_location() - } - if (item_is_pickpockable_only) - { - if (__misc_state["can pickpocket"]) - item_modifier = numeric_modifier("pickpocket chance"); - else - item_modifier = 0.0; - } - if (item_rate_is_fixed) - item_modifier = 0.0; - if ($locations[sweet-ade lake,Eager Rice Burrows,Gumdrop Forest] contains l) - { - item_modifier = 0.0; - if (it.candy) - item_modifier += numeric_modifier("Candy Drop"); - } - //FIXME pickpocketting...? - //FIXME black cat - - if (my_path().id == PATH_LIVE_ASCEND_REPEAT && !item_rate_is_fixed && !item_is_pickpockable_only && !item_is_avatar_potion && effective_drop_rate > 0.0) - { - //It's either 0.0 or not. - float needed_rate = 1.0 / (2.0 * effective_drop_rate / 100.0); - //print_html("needed_rate = " + needed_rate + " effective_drop_rate = " + effective_drop_rate); - if (1.0 + item_modifier / 100.0 >= needed_rate) - effective_drop_rate = 100.0; - else - { - effective_drop_rate = 0.0; - } - yes_it_is_actually_zero = true; - } - else - effective_drop_rate *= 1.0 + item_modifier / 100.0; - if (my_path().id == PATH_HEAVY_RAINS) - { - effective_drop_rate = clampf(floor(effective_drop_rate), 0.0, 100.0); - float washaway_rate = l.washaway_rate_of_location(); - effective_drop_rate *= (1.0 - washaway_rate); - } - if (my_familiar() == $familiar[slimeling] && ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3] contains it.to_slot()) && effective_drop_rate < 100.0) - { - effective_drop_rate = clampf(floor(effective_drop_rate), 0.0, 100.0); - //number_of_slimeling_eligible_items - float slimeling_chance = 0.0; - if (number_of_slimeling_eligible_items > 0) - slimeling_chance = 1.0 / number_of_slimeling_eligible_items.to_float(); - - int effective_familiar_weight = my_familiar().familiar_weight() + numeric_modifier("familiar weight"); - int familiar_weight_from_familiar_equipment = $slot[familiar].equipped_item().numeric_modifier("familiar weight"); //need to cancel it out - - float slimeling_base_drop_rate = my_familiar().numeric_modifier("item drop", effective_familiar_weight - familiar_weight_from_familiar_equipment, $slot[familiar].equipped_item()); - if ($slot[familiar].equipped_item() == $item[undissolvable contact lenses]) - slimeling_base_drop_rate += 25.0; - - slimeling_chance *= adjusted_base_drop_rate.to_float() * (1.0 + slimeling_base_drop_rate / 100.0); - effective_drop_rate += (100.0 - effective_drop_rate) * (slimeling_chance / 100.0); - } - //not a quest item, ??? - //if (my_familiar() == $familiar[black cat]) - - effective_drop_rate = clampf(floor(effective_drop_rate), 0.0, 100.0); - adjusted_base_drop_rate = effective_drop_rate; - - if (error.was_error) - adjusted_base_drop_rate = -1; - } - - - - //FIXME implement this - LBPItemInformation info; - - info.image_url = "images/itemimages/" + it.smallimage; - if (it.smallimage.contains_text("/")) - info.image_url = "images/" + it.smallimage; - - if (!grey_out_item) - { - if (adjusted_base_drop_rate <= 0 && !yes_it_is_actually_zero) - { - info.should_display_drop_current = true; - info.item_drop_current_information = "?%"; - } - else if (adjusted_base_drop_rate < 100 || base_drop_rate < 100) - { - info.should_display_drop_current = true; - if (drop_rate_is_guess || l.environment == "underwater") - info.item_drop_current_information = adjusted_base_drop_rate + "?%"; - else - info.item_drop_current_information = adjusted_base_drop_rate + "%"; - } - } - info.item_name = it; - if (it.available_amount() == 0) - info.item_name = "" + info.item_name + ""; - - if (base_drop_rate != adjusted_base_drop_rate && base_drop_rate > 0 && base_drop_rate < 100 && !grey_out_item) - { - info.should_display_drop_base = true; - if (drop_rate_is_guess) - info.item_drop_base_information = base_drop_rate + "?%"; - else - info.item_drop_base_information = base_drop_rate + "%"; - } - if (item_drop_modifiers_to_display.count() > 0) - { - if (info.item_drop_base_information != "") - info.item_drop_base_information += ", "; - info.item_drop_base_information += item_drop_modifiers_to_display.listJoinComponents(", ") + " drop"; - } - if (item_is_conditional) - info.tags.listAppend("conditional"); - if (item_is_pickpockable_only) - info.tags.listAppend("pickpocket"); - if (item_rate_is_fixed) - info.tags.listAppend("unaffected by +item"); - if (item_is_avatar_potion) - info.tags.listAppend("avatar"); - info.greyed_out = grey_out_item; - - items_presenting.listAppend(info); - } - - - int columns = 3; - if (items_presenting.count() % 2 == 0 && items_presenting.count() % 3 != 0 && items_presenting.count() < 8) - columns = 2; - if (items_presenting.count() < columns) - columns = 1; - - boolean want_item_minimal_display = false; - if (try_for_minimal_display || monsters_to_display_items_minimally[m] || monsters_to_display_items_minimally.count() > 2) - want_item_minimal_display = true; - - boolean display_alternate_for_smaller_sizes = (columns == 3); - - buffer output_buffer; - output_buffer.append(HTMLGenerateTagPrefix("div", mapMake("style", "padding-left:" + (__setting_indention_width_in_em * 0.5) + "em;"))); - string table_class = ""; - if (display_alternate_for_smaller_sizes) - table_class = "r_only_display_if_not_tiny r_only_display_if_not_small"; - - output_buffer.append(createItemInformationTableMethod2(columns, items_presenting, want_item_minimal_display, table_class, "")); - - if (display_alternate_for_smaller_sizes) - { - int maximum_columns = 2; - if (items_presenting.count() >= 7 || monsters_to_display_items_minimally.count() >= 5) //hippy camp - maximum_columns = 3; - output_buffer.append(createItemInformationTableMethod2(MIN(columns, maximum_columns), items_presenting, want_item_minimal_display, "r_only_display_if_not_large r_only_display_if_not_medium", "")); //font-size:0.95em; - } - output_buffer.append(""); //container - - return output_buffer; -} - -string generateLocationBarModifierEntries(string [int] entries_in) -{ - if (entries_in.count() == 1) - return entries_in.listJoinComponents(", "); - - //Returns entries using a minimum-width algorithm designed to use two lines. - - string [int] entries = entries_in; - if (!entries.listKeysMeetStrictRequirements()) //insure we can test [key + 1] and such - entries = entries.listCopyStrictRequirements(); - - int [int] entries_length; - foreach key in entries - { - entries_length[key] = entries[key].HTMLStripTags().length(); - } - - int calculating_sum = 0; - - int smallest_length = 0; - int smallest_length_index = -1; - foreach key in entries - { - if (key == entries.count() - 1) - continue; - - calculating_sum += entries_length[key]; - //If we split at the end of this entry, what will be our length? - int line_1_length = calculating_sum; - int line_2_length = 0; - foreach key2 in entries - { - if (key2 <= key) - continue; - line_2_length += entries_length[key2]; - } - int line_length = MAX(line_1_length, line_2_length); - - if (smallest_length_index == -1) - { - smallest_length = line_length; - smallest_length_index = key; - } - else - { - if (smallest_length >= line_length) - { - smallest_length_index = key; - smallest_length = line_length; - } - } - } - //Split after smallest_length: - buffer result; - foreach key in entries - { - result.append(entries[key]); - boolean should_br = false; - if (key == smallest_length_index) - should_br = true; - if (key != entries.count() - 1) - { - if (should_br) - result.append(","); - else - result.append(", "); - } - if (should_br) - result.append("
"); - - } - return result; -} - - -buffer generateLocationBarTable(string [int] table_entries, string [int] table_entry_urls, string [int] table_entry_styles, string [int] table_entry_classes, float [int] table_entry_width_weight, float [int] table_entry_fixed_width_percentage, string base_url) -{ - buffer bar; - - - int [int] table_entry_widths; - if (__setting_location_bar_fixed_layout) - { - float reserved_percentage = 0.0; - foreach key, v in table_entry_fixed_width_percentage - reserved_percentage += v; - reserved_percentage = clampf(reserved_percentage, 0.0, 1.0); - - - int [int] table_entry_character_length; - foreach key in table_entries - { - if (table_entry_fixed_width_percentage contains key) - continue; - //Complicated: - string entry = table_entries[key]; - string [int] lines = entry.split_string("
"); - int max_length = 0; - foreach key2 in lines - { - //Remove HTML: - string l = HTMLStripTags(lines[key2]); - max_length = MAX(max_length, l.length()); - } - if (table_entry_width_weight contains key) - max_length = round(max_length.to_float() * table_entry_width_weight[key]); - table_entry_character_length[key] = max_length; - } - int total_character_count = listSum(table_entry_character_length); - int [int] proportional_character_lengths; - foreach key in table_entry_character_length - { - if (table_entry_fixed_width_percentage contains key) - continue; - int v = table_entry_character_length[key]; - if (total_character_count != 0 && __setting_location_bar_limit_max_width) - { - if (v.to_float() / total_character_count.to_float() >= __setting_location_bar_max_width_per_entry) - { - v = floor(total_character_count.to_float() * __setting_location_bar_max_width_per_entry); - } - } - proportional_character_lengths[key] = v; - } - - float remaining_percentage = 100.0 * (1.0 - reserved_percentage); - - int proportional_total = listSum(proportional_character_lengths); - foreach key in table_entry_fixed_width_percentage - { - table_entry_widths[key] = clampf(table_entry_fixed_width_percentage[key], 0.0, 1.0) * 100.0; - } - foreach key in proportional_character_lengths - { - if (table_entry_fixed_width_percentage contains key) - continue; - int v = proportional_character_lengths[key]; - int width = 25; - if (proportional_character_lengths.count() > 0) - width = floor(remaining_percentage / proportional_character_lengths.count().to_float()); //backup - if (proportional_total != 0) - { - width = v.to_float() / proportional_total.to_float() * remaining_percentage; - } - table_entry_widths[key] = width; - } - } - - if (table_entry_widths.listSum() > 100) - { - //Safety backup. Renormalize: - int current_sum = table_entry_widths.listSum(); - foreach key in table_entry_widths - { - if (current_sum != 0) //not strictly necessary, will always be true (as the code currently is) - table_entry_widths[key] = floor(table_entry_widths[key].to_float() / current_sum.to_float() * 100.0); - } - } - - - if (true) - { - buffer table_style; - table_style.append("display:table;width:100%;height:100%;text-align:center;"); - if (__setting_location_bar_fixed_layout) - table_style.append("table-layout:fixed;"); - bar.append(HTMLGenerateTagPrefix("div", mapMake("style", table_style))); // - } - - foreach key in table_entries - { - string s = table_entries[key]; - string entry_url = base_url; - if (table_entry_urls contains key) - entry_url = table_entry_urls[key]; - - string [string] map; - - if (entry_url != "") - map = generateMainLinkMap(entry_url); - map["class"] += " r_location_bar_table_entry"; - if (table_entry_classes contains key) - map["class"] += " " + table_entry_classes[key]; - if (table_entry_styles contains key) - map["style"] += table_entry_styles[key]; - - if (table_entry_widths contains key) - map["style"] += "width:" + table_entry_widths[key] + "%;"; - - if (entry_url.length() != 0) - bar.append(HTMLGenerateTagPrefix("a", map)); - else - bar.append(HTMLGenerateTagPrefix("div", map)); - - if (table_entry_classes contains key) - bar.append(s); - else - bar.append(HTMLGenerateTagWrap("div", s, mapMake("class", "r_cl_modifier_inline", "style", "color:black;"))); //r_cl_modifier_inline needs its own div due to CSS class order precedence - if (entry_url.length() != 0) - { - bar.append(""); - } - else - bar.append(""); - } - - - bar.append(HTMLGenerateTagSuffix("div")); - - - - return bar; -} - - -static -{ - boolean __manuel_available = false; - boolean __did_check_manuel_available = false; -} - -buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_location_name_is_centre_aligned) -{ - buffer buf; - if (!__setting_enable_location_popup_box) - return buf; - location l = __last_adventure_location; - if (!__setting_location_bar_uses_last_location && !get_property_boolean("_relay_guide_setting_ignore_next_adventure_for_location_bar") && get_property_location("nextAdventure") != $location[none]) - l = get_property_location("nextAdventure"); - - string transition_time = "0.5s"; - buf.append(HTMLGenerateTagWrap("div", "", mapMake("id", "r_location_popup_blackout", "style", "position:fixed;z-index:6;width:100%;height:100%;background:rgba(0,0,0,0.5);opacity:0;pointer-events:none;visibility:hidden;"))); - - - buf.append(HTMLGenerateTagPrefix("div", mapMake("id", "r_location_popup_box", "style", "height:auto;transition:bottom " + transition_time + ";z-index:6;opacity:0;pointer-events:none;bottom:-10000px", "class", "r_bottom_outer_container"))); - buf.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_bottom_inner_container", "style", "background:white;height:auto;"))); - - float [monster] appearance_rates_adjusted = l.appearance_rates_adjusted(false).appearance_rates_cancel_nc(); - float [monster] appearance_rates_next_turn = l.appearance_rates_adjusted(true).appearance_rates_cancel_nc(); - - string [monster] monsters_that_we_cannot_encounter; - if ($effect[Ancient Annoying Serpent Poison].have_effect() == 0) - { - foreach m in $monsters[The Frattlesnake,Batsnake,Frozen Solid Snake,Burning Snake of Fire,The Snake With Like Ten Heads,Snakeleton] - { - monsters_that_we_cannot_encounter[m] = "not on copperhead quest"; - } - } - if (l == $location[the boss bat's lair]) - { - if (l.delayRemainingInLocation() > 0) - { - monsters_that_we_cannot_encounter[$monster[Boss Bat]] = "on delay"; - } - } - else if (l == $location[the defiled niche]) - { - int evilness = __quest_state["Level 7"].state_int["niche evilness"]; - if (evilness > 13) - { - monsters_that_we_cannot_encounter[$monster[gargantulihc]] = "evilness too high"; - } - else if (evilness > 0) - { - monsters_that_we_cannot_encounter[$monster[senile lihc]] = "boss up"; - monsters_that_we_cannot_encounter[$monster[slick lihc]] = "boss up"; - monsters_that_we_cannot_encounter[$monster[dirty old lihc]] = "boss up"; - } - } - else if (l == $location[the defiled cranny]) - { - int evilness = __quest_state["Level 7"].state_int["cranny evilness"]; - if (evilness > 13) - { - monsters_that_we_cannot_encounter[$monster[huge ghuol]] = "evilness too high"; - } - else if (evilness > 0) - { - foreach m in $monsters[gluttonous ghuol,gaunt ghuol,swarm of ghuol whelps,big swarm of ghuol whelps,giant swarm of ghuol whelps] - monsters_that_we_cannot_encounter[m] = "boss up"; - } - } - else if (l == $location[the defiled nook]) - { - int evilness = __quest_state["Level 7"].state_int["nook evilness"]; - if (evilness > 13) - { - monsters_that_we_cannot_encounter[$monster[giant skeelton]] = "evilness too high"; - } - else if (evilness > 0) - { - foreach m in $monsters[spiny skelelton,toothy sklelton,party skelteon] - monsters_that_we_cannot_encounter[m] = "boss up"; - } - } - else if (l == $location[the defiled alcove]) - { - int evilness = __quest_state["Level 7"].state_int["alcove evilness"]; - if (evilness > 13) - { - monsters_that_we_cannot_encounter[$monster[conjoined zmombie]] = "evilness too high"; - } - else if (evilness > 0) - { - foreach m in $monsters[grave rober zmobie,corpulent zobmie,modern zmobie] - monsters_that_we_cannot_encounter[m] = "boss up"; - } - } - else if (l == $location[oil peak]) - { - int oil_ml = $location[oil peak].monster_level_adjustment_for_location(); - monster correct_monster = $monster[oil slick]; - if (oil_ml < 20) - correct_monster = $monster[oil slick]; - else if (oil_ml < 50) - correct_monster = $monster[oil tycoon]; - else if (oil_ml < 100) - correct_monster = $monster[oil baron]; - else if (oil_ml >= 100) - correct_monster = $monster[oil cartel]; - foreach m in $monsters[oil slick,oil tycoon,oil baron,oil cartel] - { - if (m != correct_monster) - monsters_that_we_cannot_encounter[m] = "ML based"; - } - } - - boolean banishes_are_possible = true; - if ($locations[the secret government laboratory,sloppy seconds diner] contains l) - banishes_are_possible = false; - if (my_path().id == PATH_LIVE_ASCEND_REPEAT) - banishes_are_possible = false; - - foreach m in appearance_rates_next_turn - { - if (monsters_that_we_cannot_encounter contains m) - remove appearance_rates_next_turn[m]; - } - - monster [int] monster_display_order; - boolean rates_are_equal = true; - boolean next_rates_are_equal = true; - float last_rate = -1.0; - float last_next_rate = -1.0; - foreach m in appearance_rates_adjusted - { - if (m == $monster[none]) - continue; - float rate = appearance_rates_adjusted[m]; - float next_rate = appearance_rates_next_turn[m]; - if (rate <= 0.0 && l == $location[Investigating a Plaintive Telegram]) - continue; - monster_display_order.listAppend(m); - if (rate > 0.0) - { - if (last_rate == -1.0) - last_rate = rate; - else if (fabs(last_rate - rate) > 0.01) - { - rates_are_equal = false; - } - } - - if (next_rate > 0.0) - { - if (last_next_rate == -1.0) - last_next_rate = next_rate; - else if (fabs(last_next_rate - next_rate) > 0.01) - { - next_rates_are_equal = false; - } - } - } - - boolean [monster] possible_alien_monsters; - if (!(appearance_rates_adjusted contains last_monster())) //wandering monsters, etc - { - possible_alien_monsters[last_monster()] = true; - monster_display_order.listAppend(last_monster()); - } - - int minimal_cutoff_monster_count = 10; - boolean try_for_minimal_display = false; - if (monster_display_order.count() > minimal_cutoff_monster_count) - try_for_minimal_display = true; - - if (next_rates_are_equal) - { - //equality - sort monster_display_order by -appearance_rates_next_turn[value]; - sort monster_display_order by -appearance_rates_adjusted[value] - (possible_alien_monsters[value] ? -100.0 : 0); - } - else - { - sort monster_display_order by -appearance_rates_adjusted[value] - (possible_alien_monsters[value] ? -100.0 : 0); - sort monster_display_order by -appearance_rates_next_turn[value] - (possible_alien_monsters[value] ? -100.0 : 0); - } - int entries_displayed = 0; - int monsters_displayed = 0; - - boolean can_display_as_2x = true; - boolean spelunking = limit_mode() == "spelunky"; - - /*if (false) //trying with it off - it feels better to use layout more effectively, rather than try to line up everything. example area: domed city of grimacia - { - foreach key, m in monster_display_order - { - int item_count_displaying = m.item_drops_array().count(); - if (item_count_displaying <= 1) - { - } - else if (item_count_displaying == 2 || (item_count_displaying % 2 == 0 && item_count_displaying % 3 != 0)) - { - } - else - can_display_as_2x = false; - } - }*/ - - boolean [monster] monsters_to_display_items_minimally; - int item_minimal_display_limit = 6; - foreach key, m in monster_display_order - { - //pooltergeist has lots of items, but they're very short named - int total_string_length = 0; - foreach key, r in m.item_drops_array() - { - total_string_length += r.drop.to_string().length(); - } - if (m.item_drops_array().count() > item_minimal_display_limit && total_string_length >= 100) - monsters_to_display_items_minimally[m] = true; - } - foreach key, m in monster_display_order - { - string [int] fl_entries; - string [int] fl_entry_urls; - string [int] fl_entry_styles; - string [int] fl_entry_classes; - float [int] fl_entry_width_weight; - float [int] fl_entry_fixed_width_percentage; - - string monster_image_url = "images/adventureimages/" + m.image; - if (m.image.contains_text("/")) - monster_image_url = "images/" + m.image; - if (m.image == "toxbeast1.gif") - monster_image_url = "images/adventureimages/toxbeast3.gif"; - if (m.image.length() == 0) - monster_image_url = ""; - ServerImageStats monster_image_stats = ServerImageStatsOfImageURL(monster_image_url); - float rate = appearance_rates_adjusted[m]; - float next_rate = appearance_rates_next_turn[m]; - if (entries_displayed > 0) - buf.append(HTMLGenerateTagPrefix("hr", mapMake("style", "margin:0px;"))); - entries_displayed += 1; - monsters_displayed += 1; - - boolean avoid_outputting_conditional = false; - boolean monster_cannot_be_encountered = false; - string reason_monster_cannot_be_encountered = ""; - if (rate == -3.0 && banishes_are_possible) //-3.0 => is (properly) banished - { - monster_cannot_be_encountered = true; - reason_monster_cannot_be_encountered = "banished"; - } - else if (monsters_that_we_cannot_encounter contains m) - { - monster_cannot_be_encountered = true; - reason_monster_cannot_be_encountered = monsters_that_we_cannot_encounter[m]; - } - else if (appearance_rates_adjusted[$monster[none]] >= 100.0 && !(possible_alien_monsters contains m)) - { - monster_cannot_be_encountered = true; - reason_monster_cannot_be_encountered = "no combats"; - avoid_outputting_conditional = true; - } - if (true) - { - //string style = "width:100%;display:table;padding:0.25em;z-index:8;position:relative;overflow:hidden;"; - string style = "width:100%;padding-bottom:0.1em;z-index:8;position:relative;overflow:hidden;"; - if (try_for_minimal_display) - style += "padding-top:0.1em;"; - if (monster_cannot_be_encountered) - style += "color:grey;"; - if (monster_image_stats.height > 100 && false) //those tall monsters like to impress - style += "min-height:100px;"; - buf.append(HTMLGenerateTagPrefix("div", mapMake("style", style))); - } - if (!monster_image_url.contains_text("nopic.gif") && monster_image_url != "") - { - //FIXME centre image if it's small? maybe a table? more tables! - boolean from_bottom_instead = false; - //if ($strings[images/adventureimages/lower_b.gif,images/adventureimages/lower_k.gif,images/adventureimages/lower_h.gif,images/adventureimages/upper_q.gif,images/adventureimages/aswarm.gif,images/adventureimages/lowerm.gif,images/adventureimages/dad_machine.gif] contains monster_image_url && monster_image_stats.maximum_y_coordinate != -1 && monster_image_stats.height != -1) //dungeons of doom, dad sea monkee - //from_bottom_instead = true; - - - float max_height = 100; - //monster_image_stats.height - //make max_height adjust: - float effective_height = monster_image_stats.maximum_y_coordinate - monster_image_stats.minimum_y_coordinate + 1; - float height_fraction = 1.0; - if (monster_image_stats.height > 0) - height_fraction = effective_height / monster_image_stats.height.to_float(); - - if (height_fraction > 0) - max_height = 100.0 / height_fraction; - - string image_style = "position:absolute;right:0px;top:0px;max-height:" + max_height.ceil() + "px;z-index:-3;"; - if (monster_cannot_be_encountered) - image_style += "opacity:0.1;"; - else if (last_monster() == m) - image_style += "opacity:0.5;"; //1.0 - else if (m.attributes.contains_text("ULTRARARE")) - image_style += "opacity:0.1;"; - else - image_style += "opacity:0.2;"; //0.5 - if (from_bottom_instead && false) //disabled, no longer works - { - float location_of_first_bottom_pixel = monster_image_stats.maximum_y_coordinate; - float margin_bottom = monster_image_stats.height - location_of_first_bottom_pixel; - if (monster_image_stats.height != 100) - { - //correct margin, as we scale images down to 100 - float ratio = monster_image_stats.height.to_float() / 100.0; - if (ratio != 0.0) - margin_bottom /= ratio; - } - image_style += "bottom:0px;"; - image_style += "margin-bottom:-" + ceil(margin_bottom) + "px;"; - - } - else - { - float location_of_first_top_pixel = MAX(0, monster_image_stats.minimum_y_coordinate); - if (monster_image_stats.height != 100 && false) //FIXME ??? - { - //correct margin, as we scale images down to 100 - float ratio = monster_image_stats.height.to_float() / 100.0; - if (ratio != 0.0) - location_of_first_top_pixel /= ratio; - } - if (location_of_first_top_pixel > 0) - image_style += "margin-top:-" + location_of_first_top_pixel + "px;"; - } - buf.append(HTMLGenerateTagPrefix("img", mapMake("src", monster_image_url, "style", image_style, "alt", m))); - } - - if (true) - { - string style; - float width_weight = 1.4; - if (monster_cannot_be_encountered) - { - style += "text-decoration:line-through;"; - //width_weight = 1.0; - } - else - style = "font-size:1.2em;"; - style += "text-align:left;padding-top:2px;"; - - fl_entries.listAppend(m.capitaliseFirstLetter()); - fl_entry_classes[fl_entries.count() - 1] = "r_bold r_location_bar_ellipsis_entry"; - fl_entry_styles[fl_entries.count() - 1] = style; - fl_entry_width_weight[fl_entries.count() - 1] = width_weight; - } - - // ----------- NEW BIT FROM SCOTCH ABOUT BOFA ------------- - if (true) - { - if ($skill[just the facts].have_skill()) { - string bofaText; - string bofaEffect = m.fact_type(); - string factAppend; - - // TODO: Bunch of stuff, this is a first implementation. Goals: - // - Try to figure out a nicer way to format this. - // - Filter out the "junk" BOFA results. - if (bofaEffect == "item") factAppend = HTMLGenerateSpanFont(m.item_fact().name,"red"); - if (bofaEffect == "effect") factAppend = HTMLGenerateSpanFont(`{m.effect_fact().name} ({m.numeric_fact()})`,"blue"); - bofaText = `{factAppend}`; - - // I tried to put this a few places. First I tried in the stats - // sidebar, then I tried under the name, then I tried as an - // appended item. I ended up preferring having it generate in - // visibly in large zones with cutoff entries. I am pretty sure - // the "best" solution is a more elegant way to add it to the - // item list, but this initial implementation is good enough for - // now, I think. - - fl_entries.listAppend(bofaText); - fl_entry_styles[fl_entries.count() - 1] = "text-align:left;font-size:0.8em"; - } - } - - //FIXME handle canceling NC - buffer rate_buffer; - if (m.attributes.contains_text("ULTRARARE")) - rate_buffer.append("ultra rare "); - else if (m.boss) - rate_buffer.append("boss "); - else if (rate > 0 && !monster_cannot_be_encountered) - { - if (!rates_are_equal) - { - rate_buffer.append(rate.roundForOutput(0)); - rate_buffer.append("%"); - } - if (next_rate != rate && next_rate > 0 && !next_rates_are_equal) - { - if (rates_are_equal) - rate_buffer.append("equal %"); - rate_buffer.append("
next "); - - rate_buffer.append(next_rate.roundForOutput(0)); - rate_buffer.append("%"); - } - } - else if (rate <= 0 && !(m.is_banished() && banishes_are_possible)) - { - if (possible_alien_monsters contains m) - rate_buffer.append("elsewhere"); - else if (!avoid_outputting_conditional) - rate_buffer.append("conditional"); - } - //seen values for rate: - //0.0 for bosses - //-1.0 for ultra-rares - //-3.0 for (properly) banished - if (m.is_banished() && banishes_are_possible) - { - Banish banish_information = m.BanishForMonster(); - if (rate == -3.0) - { - rate_buffer.append("banished"); - if (banish_information.banish_source != "") - { - rate_buffer.append(" by "); - rate_buffer.append(banish_information.banish_source); - } - if (banish_information.custom_reset_conditions != "") - { - rate_buffer.append(" until "); - rate_buffer.append(banish_information.custom_reset_conditions); - } - else if (banish_information.banish_turn_length == -1) - rate_buffer.append(" forever"); - else if (banish_information.banish_turn_length > 0) - { - int turns_left = banish_information.BanishTurnsLeft(); - rate_buffer.append(" for "); - rate_buffer.append(pluralise(turns_left, "more turn", "more turns")); - } - } - else if (rate > 0.0) - { - //monster was banished, but they are olfacting it (only base copies of the monsters are removed by banishes) - if (!rates_are_equal || !next_rates_are_equal) - rate_buffer.append("
"); - rate_buffer.append("banished"); - if (banish_information.banish_source != "") - { - rate_buffer.append(" by "); - rate_buffer.append(banish_information.banish_source); - } - //want to avoid cluttering, so don't show until when - rate_buffer.append("
"); - rate_buffer.append("brought back by copies".HTMLGenerateSpanOfClass("r_element_important")); - - } - rate_buffer.append(" "); - } - - if (rate_buffer.length() > 0) - { - fl_entries.listAppend(rate_buffer); - } - if (monster_cannot_be_encountered && reason_monster_cannot_be_encountered != "banished") - { - fl_entries.listAppend(reason_monster_cannot_be_encountered); - } - - - - - - - int item_count_displaying = m.item_drops_array().count(); - if (item_count_displaying > 0 && try_for_minimal_display && !monster_cannot_be_encountered) - { - fl_entries.listAppend(pluralise(item_count_displaying, "item", "items")); - } - - - if (!monster_cannot_be_encountered) - { - string [int] stats_l1; - string [int] stats_l2; - //if (m.base_hp > 0) - //stats_l1.listAppend(m.base_hp + " HP"); - if (m.phylum != $phylum[none] && !spelunking) - { - string line; - if ($monsters[broodling seal] contains m) - line = "cute
"; - line += m.phylum; - if (true && m.attack_element != $element[none]) - line = HTMLGenerateSpanOfClass(line, "r_element_" + m.attack_element + "_desaturated"); - stats_l1.listAppend(line); - } - /*if (m.attack_element != $element[none] && false) - { - stats_l2.listAppend(HTMLGenerateSpanOfClass(m.attack_element, "r_element_" + m.attack_element + "_desaturated")); - }*/ - if (m.max_meat > 0) - { - float average_meat = (m.min_meat + m.max_meat) * 0.5; - Error error; - // float pressure_penalty = l.environment == "underwater" ? -l.pressurePenaltyForLocation(error) : 0.0; //already accounted for in meat_drop_modifier() - average_meat *= 1.0 + meat_drop_modifier() / 100.0; - if (average_meat >= 25) //ignore really low amounts - { - if (error.was_error) - stats_l1.listAppend("? meat"); - else - stats_l1.listAppend(average_meat.round() + " meat"); - } - } - if (m.base_attack > 0) - stats_l2.listAppend(m.base_attack + " ML"); - if (spelunking) - stats_l2.listAppend(m.base_hp + " HP"); - if ($skill[Extract Oil].have_skill()) - { - string oil_type = lookupAWOLOilForMonster(m); - if (oil_type != "") - stats_l2.listAppend(oil_type); - } - //if (m.raw_defense > 0) - //stats_l2.listAppend(m.raw_defense + " def"); - if (false) - { - //disabled - monster_factoids_available constantly reissues server requets if we don't have a factoid on a monster - if (!__did_check_manuel_available) - { - //so, if the manuel isn't available, we incur a quest log load every time. so don't do that. - __manuel_available = $monster[spooky vampire].monster_factoids_available(false) > 0; - __did_check_manuel_available = true; - } - if (__manuel_available) - { - int factoids_left = 3 - monster_factoids_available(m, false); - if (m.attributes.contains_text("ULTRARARE") || m.attributes.contains_text("NOMANUEL")) //ULTRARARE test may be superfluous - factoids_left = 0; - if (factoids_left > 0) - stats_l2.listAppend(factoids_left + " more fact" + (factoids_left > 1 ? "s" : "")); - } - } - - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - { - int ka_dropped = m.ka_dropped(); - if (ka_dropped > 0) - stats_l1.listAppend(ka_dropped + " ka"); - } - - if (m.expected_damage() > 1 && (m.expected_damage() >= my_hp().to_float() * 0.5 || ($monsters[spider gremlin,batwinged gremlin,erudite gremlin,vegetable gremlin] contains m)) || spelunking) - { - string damage_text = m.expected_damage() + " dmg"; - if (m.expected_damage() >= 0.75 * my_hp()) - damage_text = HTMLGenerateSpanOfClass(damage_text, "r_element_hot_desaturated"); //"#FC686F", ""); - stats_l2.listAppend(damage_text); - } - - if (stats_l2.count() == 0 && stats_l1.count() == 2) //rebalance hack - { - stats_l2.listPrepend(stats_l1[1]); - remove stats_l1[1]; - } - if (stats_l2.count() == 1 && stats_l1.count() == 3) //rebalance hack - { - stats_l2.listPrepend(stats_l1[2]); - remove stats_l1[2]; - } - - if (stats_l1.count() + stats_l2.count() > 0) - { - string line = stats_l1.listJoinComponents(" / "); - if (stats_l2.count() > 0) - { - if (stats_l1.count() > 0) - line += "
"; - line += stats_l2.listJoinComponents(" / "); - } - fl_entries.listAppend(line); - fl_entry_styles[fl_entries.count() - 1] = "text-align:right;"; - fl_entry_width_weight[fl_entries.count() - 1] = 1.4; - } - } - - //add background blur: - if (true) - { - foreach key, entry in fl_entries - { - entry = HTMLGenerateSpanOfClass(entry, "r_location_bar_background_blur"); - fl_entries[key] = entry; - } - } - if (!(m.is_banished() && banishes_are_possible)) - { - if (fl_entries.count() == 2) - fl_entry_fixed_width_percentage[0] = 0.60; - else if (fl_entries.count() == 3) - { - fl_entry_fixed_width_percentage[0] = 0.50; - fl_entry_fixed_width_percentage[1] = 0.2; - fl_entry_fixed_width_percentage[2] = 0.3; - } - else if (fl_entries.count() == 4) - { - fl_entry_fixed_width_percentage[0] = 0.40; - fl_entry_fixed_width_percentage[1] = 0.2; - fl_entry_fixed_width_percentage[2] = 0.15; - fl_entry_fixed_width_percentage[3] = 0.25; - } - } - //remove fl_entry_fixed_width_percentage[0]; - - buf.append(generateLocationBarTable(fl_entries, fl_entry_urls, fl_entry_styles, fl_entry_classes, fl_entry_width_weight, fl_entry_fixed_width_percentage, "")); - - - if (item_count_displaying > 0 && !try_for_minimal_display && !monster_cannot_be_encountered && true) - { - buf.append(generateItemInformationMethod2(l, m, try_for_minimal_display,monsters_to_display_items_minimally)); - } - - //buf.append(HTMLGenerateTagSuffix("div")); - buf.append(HTMLGenerateTagSuffix("div")); - //break; - } - - if (in_bad_moon()) - { - BadMoonAdventure [int] bad_moon_adventures = BadMoonAdventuresForLocation(l); - - if (bad_moon_adventures.count() > 0) - { - foreach key, adventure in bad_moon_adventures - { - if (haveSeenBadMoonEncounter(adventure.encounter_id)) - continue; - - string [int] fl_entries; - string [int] fl_entry_urls; - string [int] fl_entry_styles; - string [int] fl_entry_classes; - float [int] fl_entry_width_weight; - float [int] fl_entry_fixed_width_percentage; - - - string image_style = "margin-top:1px;"; - if (adventure.has_additional_requirements_not_yet_met) - image_style += "opacity:0.25;"; - fl_entries.listAppend(HTMLGenerateTagPrefix("img", mapMake("src", __bad_moon_small_image_data, "style", image_style))); - fl_entry_styles[fl_entries.count() - 1] = "text-align:right;"; - fl_entry_fixed_width_percentage[fl_entries.count() - 1] = 0.1; - fl_entries.listAppend(adventure.description); - fl_entry_styles[fl_entries.count() - 1] = "text-align:left;"; - if (adventure.has_additional_requirements_not_yet_met) - fl_entries.listAppend("Need to " + adventure.conditions_to_finish); - - - buf.append(HTMLGenerateTagPrefix("hr", mapMake("style", "margin:0px;"))); - buf.append(generateLocationBarTable(fl_entries, fl_entry_urls, fl_entry_styles, fl_entry_classes, fl_entry_width_weight, fl_entry_fixed_width_percentage, "")); - } - } - } - - - if (false) - { - string [int] lines; - string [int] lines_offscreen; - if (false && l.parentdesc != "" && l.parentdesc != "No Category" && l.parentdesc.to_lower_case() != l.to_lower_case()) - lines.listAppend(l.parentdesc); - if (!__misc_state["in run"] && l.turns_spent > 0) - { - lines.listAppend(pluralise(l.turns_spent, "turn spent", "turns spent")); //lines_offscreen - } - if (lines.count() + lines_offscreen.count() > 0) - { - if (entries_displayed >= 1) - buf.append(HTMLGenerateTagPrefix("hr", mapMake("style", "margin:0px;"))); - string div_class = "r_cl_modifier_inline"; - string div_style = "height:1.1em;padding-top:1px;padding-bottom:1px;"; - if (location_bar_location_name_is_centre_aligned) - div_class += " r_centre"; - else - div_style += "padding-left:" + __setting_indention_width + ";"; - buf.append(HTMLGenerateTagPrefix("div", mapMake("class", div_class, "style", div_style))); - buf.append(lines.listJoinComponents(" - ")); - buf.append(""); - if (lines_offscreen.count() > 0) - { - buf.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_cl_modifier_inline", "style", "position:absolute;right:0px;top:0px;"))); - buf.append(lines_offscreen.listJoinComponents(" - ")); - buf.append(""); - } - entries_displayed += 1; - } - } - if (false) - { - string [int] fl_entries; - string [int] fl_entry_urls; - string [int] fl_entry_styles; - string [int] fl_entry_classes; - float [int] fl_entry_width_weight; - float [int] fl_entry_fixed_width_percentage; - - if (false && l.parentdesc != "" && l.parentdesc != "No Category" && l.parentdesc.to_lower_case() != l.to_lower_case()) - fl_entries.listAppend(l.parentdesc); - - /*Error err; - if (!l.locationAvailable(err)) - { - if (!err.was_error) - fl_entries.listAppend("Inaccessible"); //doesn't make any sense unless we add that one feature - }*/ - - if (!__misc_state["in run"] && l.turns_spent > 0) - fl_entries.listAppend(pluralise(l.turns_spent, "turn spent", "turns spent")); - - boolean all_entries_blank = true; - foreach key, entry in fl_entries - { - if (entry != "") - all_entries_blank = false; - } - if (fl_entries.count() > 0 && !all_entries_blank) - { - if (entries_displayed >= 1) - buf.append(HTMLGenerateTagPrefix("hr", mapMake("style", "margin:0px;"))); - /*if (fl_entries.count() == 2) - { - fl_entry_styles[1] += "text-align:right;"; - }*/ - foreach key in fl_entries - fl_entry_styles[key] += "height:1.25em;"; - - fl_entry_styles[0] += "text-align:left;"; - fl_entry_styles[0] += "padding-left:" + __setting_indention_width + ";"; - if (fl_entries.count() > 1) - { - fl_entry_styles[fl_entries.count() - 1] += "text-align:right;"; - fl_entry_styles[fl_entries.count() - 1] += "padding-right:" + __setting_indention_width + ";"; - } - buf.append(generateLocationBarTable(fl_entries, fl_entry_urls, fl_entry_styles, fl_entry_classes, fl_entry_width_weight, fl_entry_fixed_width_percentage, "")); - entries_displayed += 1; - - //output_hr_override = true; - } - - } - - //boolean output_hr_override = false; - - if (entries_displayed == 0) - return "".to_buffer(); - buf.append(HTMLGenerateTagSuffix("div")); - //if (output_hr_override) - //buf.append("
"); - buf.append(HTMLGenerateTagSuffix("div")); - - return buf; -} diff --git a/Source/relay/TourGuide/Sections/Location Bar.ash b/Source/relay/TourGuide/Sections/Location Bar.ash deleted file mode 100644 index f3dfd389..00000000 --- a/Source/relay/TourGuide/Sections/Location Bar.ash +++ /dev/null @@ -1,625 +0,0 @@ -import "relay/TourGuide/Sections/Location Bar Popup.ash"; - -buffer generateLocationBar(boolean displaying_navbar) -{ - buffer bar; - if (!playerIsLoggedIn()) - return bar; - location l = __last_adventure_location; - if (!__setting_location_bar_uses_last_location && !get_property_boolean("_relay_guide_setting_ignore_next_adventure_for_location_bar") && get_property_location("nextAdventure") != $location[none]) //setting exists for ascension scripts that alter my_location() to a null value/noob cave whenever they're not adventuring somewhere specific, to avoid environment-based effects on modifiers. - l = get_property_location("nextAdventure"); - - if (l == $location[none] || __misc_state["In valhalla"]) - return "".to_buffer(); - - string url = l.getClickableURLForLocation(); - - float [monster] monster_appearance_rates = l.appearance_rates_adjusted(); - - int nc_rate = MAX(0.0, monster_appearance_rates[$monster[none]]); - - float location_base_ml = l.monster_level_adjustment_for_location(); - float location_base_init_penalty = monsterExtraInitForML(location_base_ml); - if (l.locationHasPlant("Impatiens") || l.locationHasPlant("Shuffle Truffle")) - location_base_init_penalty -= 25.0; - - - float average_ml = 0.0; - float max_init = 0.0; - float sample_count = 0.0; - - boolean [location] locations_where_monsters_always_matter = $locations[the haunted bedroom]; - - foreach m in monster_appearance_rates - { - if (monster_appearance_rates[m] <= 0.0 && !(locations_where_monsters_always_matter contains l)) //one-time hack, sure? - continue; - if (m == $monster[none]) - continue; - average_ml += m.raw_attack + location_base_ml; - - if (m.raw_attack == m.base_attack && location_base_ml > 0) //scaling monsters will have equivalent base_attack and raw_attack with ML already applied. - average_ml -= location_base_ml; //this will be slightly incorrect with plants, due to how location ML works, but fixing it is very complicated - - max_init = MAX(max_init, m.raw_initiative + location_base_init_penalty); - sample_count += 1.0; - } - if (sample_count > 0.0) - { - average_ml /= sample_count; - } - - float chance_of_jump = 0.0; - chance_of_jump = clampNormalf(((100.0 - max_init) + initiative_modifier_ignoring_plants()) / 100.0); - - string [int] plant_data; - - if (__iotms_usable[$item[Order of the Green Thumb Order Form]]) - { - string [location, 3] florist_plants = get_florist_plants(); - - if (florist_plants contains l) - { - string [3] area_plants = get_florist_plants()[l]; - - foreach key in area_plants - { - string plant_name = area_plants[key]; - if (plant_name.length() == 0) - continue; - string plant_description = plant_name.getPlantDescription(); - - string class_name = ""; - //Half-saturation of their original colour, to fit in with the modifier look: - if (plant_description == "spooky attack") - class_name = "r_element_spooky_desaturated"; - else if (plant_description == "hot attack") - class_name = "r_element_hot_desaturated"; - else if (plant_description == "sleaze attack") - class_name = "r_element_sleaze_desaturated"; - else if (plant_description == "stench attack") - class_name = "r_element_stench_desaturated"; - else if (plant_description == "cold attack") - class_name = "r_element_cold_desaturated"; - - if (class_name != "") - plant_description = HTMLGenerateSpanOfClass(plant_description, class_name); - - if (plant_description != "") - plant_data.listAppend(plant_description); - else - plant_data.listAppend("Unknown"); - } - } - string environment_display = l.environment.capitaliseFirstLetter(); - if (l.environment == "unknown" || l.environment == "none" || l.environment == "") - environment_display = "Unknown"; - if (plant_data.count() == 0)// && l.environment != "unknown" && l.environment != "none" && l.environment != "") - { - if (l == $location[The Valley of Rof L'm Fao]) - plant_data.listAppend(l.environment.replace_string("o", "0")); - else if (!($locations[The Prince's Restroom,The Prince's Dance Floor,The Prince's Kitchen,The Prince's Balcony,The Prince's Lounge,The Prince's Canapes table,the shore\, inc. travel agency] contains l)) - plant_data.listAppend(environment_display); - } - } - - - /*int [location] pressure_penalties; - pressure_penalties[$location[The Briny Deeps]] = 25; - pressure_penalties[$location[The Brinier Deepers]] = 50; - pressure_penalties[$location[The Briniest Deepests]] = 75; - foreach loc in $locations[An Octopus's Garden,The Wreck of the Edgar Fitzsimmons,Madness Reef,The Mer-Kin Outpost,The Skate Park,The Coral Corral] - pressure_penalties[loc] = 100; - foreach loc in $locations[Mer-kin Colosseum,Mer-kin Library,Mer-kin Gymnasium,Mer-kin Elementary School] - pressure_penalties[loc] = 150; - foreach loc in $locations[The Marinara Trench,Anemone Mine,The Dive Bar,The Caliginous Abyss] - pressure_penalties[loc] = 200;*/ - - - string custom_location_information; - string custom_location_url; - if (l == $location[domed city of ronaldus]) - { - int ronald_phase = moon_phase() % 8; - int ronald_darkness = abs(ronald_phase - 4); - int ronald_light = 4 - ronald_darkness; - if (ronald_light < 2) - custom_location_information = "No aliens"; - else - custom_location_information = (ronald_light * 8) + "% aliens"; - } - else if (l == $location[domed city of grimacia]) - { - int grimace_phase = moon_phase() / 2; - int grimace_darkness = abs(grimace_phase - 4); - int grimace_light = 4 - grimace_darkness; - if (grimace_light < 2) - custom_location_information = "No aliens"; - else - custom_location_information = (grimace_light * 8) + "% aliens"; - } - else if (l == $location[a-boo peak]) - { - if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0) - { - custom_location_information = __quest_state["Level 9"].state_int["a-boo peak hauntedness"] + "% haunted"; - } - } - else if (l == $location[oil peak]) - { - if (__quest_state["Level 9"].state_float["oil peak pressure"] > 0.0) - { - float pressure = __quest_state["Level 9"].state_float["oil peak pressure"]; - float pressure_remaining = pressure / 310.66; - custom_location_information = round(clampNormalf(pressure_remaining) * 100.0) + "% pressure"; - } - } - else if (l == $location[Inside the Palindome]) - { - if (!__quest_state["Level 11 Palindome"].state_boolean["dr. awkward's office unlocked"]) - { - float likelyhood_of_dudes = 0.0; - foreach m in monster_appearance_rates - { - if (monster_appearance_rates[m] <= 0.0) - continue; - if (m == $monster[none]) - continue; - if (m == $monster[Bob Racecar] || m == $monster[Racecar Bob] || m == $monster[Drab Bard]) - likelyhood_of_dudes += monster_appearance_rates[m]; - } - custom_location_information = likelyhood_of_dudes.round() + "% dudes"; - } - } - else if (l == $location[the hidden bowling alley]) - { - int pygmy_banishes_left = clampi(11 - get_property_int("_drunkPygmyBanishes"), 0, 11); - if ($item[bowl of scorpions].item_amount() > 0 && !$monster[drunk pygmy].is_banished() && pygmy_banishes_left > 0) - { - custom_location_information = pluralise(pygmy_banishes_left, "drunk pygmy", "drunk pygmies") + " left"; - } - } - /*else if (l == $location[twin peak]) //disabled, not very useful - { - string [int] entries; - - if (!__quest_state["Level 9"].state_boolean["Peak Stench Completed"]) - entries.listAppend(HTMLGenerateSpanOfClass("room 237", "r_element_stench_desaturated")); - if (!__quest_state["Level 9"].state_boolean["Peak Item Completed"]) - entries.listAppend("pantry"); - if (!__quest_state["Level 9"].state_boolean["Peak Jar Completed"]) - entries.listAppend("music"); - if (!__quest_state["Level 9"].state_boolean["Peak Init Completed"]) - entries.listAppend("you"); - custom_location_information = entries.generateLocationBarModifierEntries(); - }*/ - else if (l == $location[the arid\, extra-dry desert]) - { - if (__quest_state["Level 11 Desert"].state_int["Desert Exploration"] < 100) - { - custom_location_information = __quest_state["Level 11 Desert"].state_int["Desert Exploration"] + "% explored"; - } - } - else if (l == $location[barrrney's barrr]) - { - if (!__quest_state["Pirate Quest"].finished) - { - custom_location_information = pluralise(__quest_state["Pirate Quest"].state_int["insult count"], "insult", "insults"); - } - } - else if ($locations[Dreadsylvanian Woods,Dreadsylvanian Village,Dreadsylvanian Castle,The Slime Tube,A Maze of Sewer Tunnels,Hobopolis Town Square,Burnbarrel Blvd.,Exposure Esplanade,The Heap,The Ancient Hobo Burial Ground,The Purple Light District] contains l) - { - custom_location_information = "Clan logs"; - custom_location_url = "clan_raidlogs.php"; - } - else if (l == $location[the defiled alcove]) - custom_location_information = __quest_state["Level 7"].state_int["alcove evilness"] + " evilness"; - else if (l == $location[the defiled nook]) - custom_location_information = __quest_state["Level 7"].state_int["nook evilness"] + " evilness"; - else if (l == $location[the defiled cranny]) - custom_location_information = __quest_state["Level 7"].state_int["cranny evilness"] + " evilness"; - else if (l == $location[the defiled niche]) - custom_location_information = __quest_state["Level 7"].state_int["niche evilness"] + " evilness"; - else if (l == $location[the battlefield (hippy uniform)]) - custom_location_information = pluralise(__quest_state["Level 12"].state_int["frat boys left on battlefield"], "frat boy", "frat boys"); - else if (l == $location[the battlefield (frat uniform)]) - custom_location_information = pluralise(__quest_state["Level 12"].state_int["hippies left on battlefield"], "hippy", "hippies"); - else if (l.environment == "underwater") - { - Error error; - float pressure_penalty = l.pressurePenaltyForLocation(error); - custom_location_information = pressure_penalty.floor() + "% pressure"; - if (error.was_error) - custom_location_information = "Unknown pressure"; - /*int pressure_penalty = MAX(0, -numeric_modifier("item drop penalty")); - if (l == my_location()) - custom_location_information = pressure_penalty + "% pressure"; - else //numeric_modifier is location sensitive - custom_location_information = "Unknown pressure";*/ - } - else if ($locations[The Prince's Restroom,The Prince's Dance Floor,The Prince's Kitchen,The Prince's Balcony,The Prince's Lounge,The Prince's Canapes table] contains l) - { - int minutes_to_midnight = get_property_int("cinderellaMinutesToMidnight"); - if (minutes_to_midnight > 0) - custom_location_information = pluralise(minutes_to_midnight, "minute", "minutes") + " left"; - } - else if ($locations[Ye Olde Medievale Villagee,Portal to Terrible Parents,Rumpelstiltskin's Workshop] contains l) - { - int turns_left = clampi(30 - get_property_int("rumpelstiltskinTurnsUsed"), 0, 30); - custom_location_information = pluralise(turns_left, "turn", "turns") + " left"; - } - else if (l == $location[fernswarthy's basement]) - { - custom_location_information = "Floor " + __misc_state_int["Basement Floor"]; - } - else if ($locations[Your Bung Chakra,Your Guts Chakra,Your Liver Chakra,Your Nipple Chakra,Your Nose Chakra,Your Hat Chakra,Crimbo's Sack,Crimbo's Boots,Crimbo's Jelly,Crimbo's Reindeer,Crimbo's Beard,Crimbo's Hat] contains l) - { - string [location] property_name_for_location; - property_name_for_location[$location[Your Bung Chakra]] = "crimbo16BungChakraCleanliness"; - property_name_for_location[$location[Your Guts Chakra]] = "crimbo16GutsChakraCleanliness"; - property_name_for_location[$location[Your Liver Chakra]] = "crimbo16LiverChakraCleanliness"; - property_name_for_location[$location[Your Nipple Chakra]] = "crimbo16NippleChakraCleanliness"; - property_name_for_location[$location[Your Nose Chakra]] = "crimbo16NoseChakraCleanliness"; - property_name_for_location[$location[Your Hat Chakra]] = "crimbo16HatChakraCleanliness"; - property_name_for_location[$location[Crimbo's Sack]] = "crimbo16SackChakraCleanliness"; - property_name_for_location[$location[Crimbo's Boots]] = "crimbo16BootsChakraCleanliness"; - property_name_for_location[$location[Crimbo's Jelly]] = "crimbo16JellyChakraCleanliness"; - property_name_for_location[$location[Crimbo's Reindeer]] = "crimbo16ReindeerChakraCleanliness"; - property_name_for_location[$location[Crimbo's Beard]] = "crimbo16BeardChakraCleanliness"; - property_name_for_location[$location[Crimbo's Hat]] = "crimbo16CrimboHatChakraCleanliness"; - - string property_name = property_name_for_location[l]; - if (property_name != "") - { - custom_location_information = get_property_int(property_name) + "% clean"; - } - } - - //else if (pressure_penalties contains l) - //custom_location_information = pressure_penalties[l] + "% pressure"; - - string [int] monster_data; - if (false) - { - boolean even_appearance_rates = true; - float last_seen_rate = -10000.0; - foreach m in monster_appearance_rates - { - if (m == $monster[none]) - continue; - float rate = monster_appearance_rates[m]; - if (rate <= 0.0) - continue; - if (last_seen_rate == -10000.0) - last_seen_rate = rate; - else if (rate != last_seen_rate) - { - even_appearance_rates = false; - break; - } - - } - foreach m in monster_appearance_rates - { - if (m == $monster[none]) - continue; - float rate = monster_appearance_rates[m]; - if (rate <= 0.0) - continue; - if (even_appearance_rates) - monster_data.listAppend(m.to_string()); - else - monster_data.listAppend(m.to_string() + " (" + rate.round() + "%)"); - } - } - - float mpa = -1.0; - boolean should_output_meat_drop = false; - if (false) //disabled for the moment, still thinking about this. is it really that useful...? - { - float base_mpa = 0.0; - float total_appearance = 0.0; - foreach m in monster_appearance_rates - { - if (m == $monster[none]) - continue; - float rate = monster_appearance_rates[m]; - if (rate <= 0.0) - continue; - - float average_meat = (m.min_meat + m.max_meat) * 0.5; - - total_appearance += rate; - base_mpa += average_meat * rate; - } - if (total_appearance != 0.0) - { - base_mpa /= total_appearance; - mpa = base_mpa * (1.0 + meat_drop_modifier() / 100.0); - } - if (numeric_modifier(my_familiar(), "meat drop", familiar_weight(my_familiar()), $slot[familiar].equipped_item()) > 0.0) - should_output_meat_drop = true; - if (l == $location[the themthar hills]) - should_output_meat_drop = true; - } - - string [int] location_data; - string [int] location_urls; - float [int] location_fixed_widths; - - if (true) //__misc_state["in run"]) //useful even in aftercore - { - int area_delay = l.delayRemainingInLocation(); - - int turns_spent = l.turns_spent; - if (area_delay > 0) - location_data.listAppend(pluralise(area_delay, "turn", "turns") + "
delay"); - else if (turns_spent > 0) - location_data.listAppend(pluralise(turns_spent, "turn", "turns")); - } - - //easy list: $locations[Pump Up Muscle,Pump Up Mysticality,Pump Up Moxie,The Shore\, Inc. Travel Agency,Goat Party,Pirate Party,Lemon Party,The Roulette Tables,The Poker Room,Anemone Mine (Mining),The Knob Shaft (Mining),Friar Ceremony Location,Itznotyerzitz Mine (in Disguise),The Prince's Restroom,The Prince's Dance Floor,The Prince's Kitchen,The Prince's Balcony,The Prince's Lounge,The Prince's Canapes table,Portal to Terrible Parents,fernswarthy's basement] - //ashq foreach l in $locations[] if (l.appearance_rates().count() == 1 && l.appearance_rates()[$monster[none]] == 100.0) print(l); - boolean [location] nc_blacklist = {$location[fernswarthy's basement]:true}; - foreach l in $locations[] - if (l.appearance_rates().count() == 1 && l.appearance_rates()[$monster[none]] == 100.0) - nc_blacklist[l] = true; - - if ((my_buffedstat($stat[moxie]) < average_ml || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) && sample_count > 0 && __misc_state["in run"] && monster_level_adjustment() < 100) - { - //Init: - //We only show this if the monsters out-moxie the player in-run. It feels as though it can easily be information overload otherwise. - if (true) - { - if (chance_of_jump == 0 && false) - location_data.listAppend("No jump"); - else - location_data.listAppend((chance_of_jump * 100.0).round() + "% jump"); - } - else if (true) - { - if (chance_of_jump <= 0.0) - location_data.listAppend(max_init.round() + "% init
" + (chance_of_jump * 100.0).round() + "% jump"); - else - location_data.listAppend((chance_of_jump * 100.0).round() + "% jump"); - } - else if (false) - { - string line; - if (chance_of_jump >= 1.0) - line = "100% jump"; - else - line = max_init.round() + "% init
" + (chance_of_jump * 100.0).round() + "% jump"; - location_data.listAppend(line); - } - else if (chance_of_jump < 1.0) - { - if (false) - location_data.listAppend(max_init.round() + "% init
" + (chance_of_jump * 100.0).round() + "% jump"); - else - location_data.listAppend((chance_of_jump * 100.0).round() + "% jump"); - } - } - if (nc_rate > 0.0 && !(nc_blacklist contains l)) - location_data.listAppend(nc_rate + "% NCs"); - if (custom_location_information != "") - { - location_data.listAppend(custom_location_information); - if (custom_location_url != "") - location_urls[location_data.count() - 1] = custom_location_url; - } - - if (my_path().id == PATH_HEAVY_RAINS) - { - boolean has_items_that_will_wash_away = false; - - foreach key, m in l.get_monsters() - { - foreach it, drop_rate in m.item_drops() - { - if (drop_rate == 0) - continue; - if (drop_rate == 100) - continue; - if (it.quest) - continue; - has_items_that_will_wash_away = true; - break; - } - if (has_items_that_will_wash_away) - break; - } - - if (has_items_that_will_wash_away) - { - //Calculate washaway chance: - boolean unknown_washaway = false; - int current_water_level = l.water_level_of_location(); - - int washaway_chance = current_water_level * 5; - if ($item[fishbone catcher's mitt].equipped_amount() > 0) - washaway_chance -= 15; //GUESS - - if ($effect[Fishy Whiskers].have_effect() > 0) - { - //washaway_chance -= ?; //needs spading - unknown_washaway = true; - } - if (unknown_washaway) - location_data.listAppend("?% wash"); - else - location_data.listAppend(washaway_chance + "% wash"); - } - } - if (mpa != -1.0 && should_output_meat_drop) - { - location_data.listAppend(mpa.round() + " MPA"); - } - if (monster_data.count() > 0) - { - location_data.listAppend(pluralise(monster_data.count(), "monster", "monsters")); - } - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - { - float average_coins_gained = 0.0; - foreach m, rate in monster_appearance_rates - { - if (rate <= 0) continue; - float coin_from_monster = m.ka_dropped(); - //NC should already be included in appearance rates? - average_coins_gained += coin_from_monster * rate / 100.0; - } - if (average_coins_gained <= 0.0) - location_data.listAppend("No ka"); - else - location_data.listAppend(average_coins_gained.roundForOutput(1) + " ka"); - } - - boolean [location] powerleveling_locations = $locations[hamburglaris shield generator,[DungeonFAQ - Level 1],[DungeonFAQ - Level 2],[DungeonFAQ - Level 3]]; - - if (sample_count > 0 && (__misc_state["in run"] || powerleveling_locations contains l || average_ml > my_buffedstat($stat[moxie]))) - { - if (false) - location_data.listAppend(average_ml.round() + " ML
" + (average_ml * __misc_state_float["ML to mainstat multiplier"]).round() + " " + my_primestat().to_lower_case() + "/fight"); - else - location_data.listAppend(average_ml.round() + " ML"); - } - - if (in_bad_moon()) - { - boolean bad_moon_adventure_possible_now = false; - boolean bad_moon_adventure_possible = false; - - BadMoonAdventure [int] bad_moon_adventures = BadMoonAdventuresForLocation(l); - - if (bad_moon_adventures.count() > 0) - { - foreach key, adventure in bad_moon_adventures - { - boolean possible = !haveSeenBadMoonEncounter(adventure.encounter_id); - if (possible) - bad_moon_adventure_possible = possible; - if (!bad_moon_adventure_possible_now) - bad_moon_adventure_possible_now = !adventure.has_additional_requirements_not_yet_met; - } - } - - if (bad_moon_adventure_possible) - { - string style = "margin-top:1px;"; - if (!bad_moon_adventure_possible_now) - style += "opacity:0.25;"; - string image_html = HTMLGenerateTagPrefix("img", mapMake("src", __bad_moon_small_image_data, "style", style)); //"images/itemimages/badmoon.gif" - location_data.listAppend(image_html); - location_fixed_widths[location_data.count() - 1] = 0.15; //won't display otherwise - } - } - - if (plant_data.count() > 0) - { - string line; - - line = plant_data.generateLocationBarModifierEntries(); - - - if (__setting_location_bar_fixed_layout) - line = HTMLGenerateDivOfClass(line, "r_location_bar_ellipsis_entry"); - location_data.listAppend(line); - if (l == __last_adventure_location || true) - location_urls[location_data.count() - 1] = "place.php?whichplace=forestvillage&action=fv_friar"; - } - if (true) - { - //Holding containers: - string style; - if (displaying_navbar) - style += "bottom:" + __setting_navbar_height + ";"; - else - style += "bottom:0px;"; - - string onmouseenter_code; - string onmouseleave_code; - - if (__setting_enable_location_popup_box) - { - onmouseenter_code = "alterLocationPopupBarVisibility(event, true);"; - onmouseleave_code = "alterLocationPopupBarVisibility(event, false);"; - } - - string [string] outer_containiner_map = mapMake("class", "r_bottom_outer_container", "style", style); - bar.append(HTMLGenerateTagPrefix("div", outer_containiner_map)); - - string [string] inner_containiner_map = mapMake("id", "location_bar_inner_container", "class", "r_bottom_inner_container", "style", "background:white;"); - if (onmouseenter_code != "") - inner_containiner_map["onmouseenter"] = onmouseenter_code; - if (onmouseleave_code != "") - inner_containiner_map["onmouseleave"] = onmouseleave_code; - bar.append(HTMLGenerateTagPrefix("div", inner_containiner_map)); - } - - - - - - string [int] table_entries; - string [int] table_entry_urls; - string [int] table_entry_styles; - string [int] table_entry_classes; - float [int] table_entry_width_weight; - float [int] table_entry_fixed_width_percentage; - if (true) - { - buffer style; - if (location_data.count() > 0) - style.append("text-align:left;"); - style.append("padding-left:" + __setting_indention_width + ";"); - //style.append("text-wrap:none;"); - //style.append("overflow:hidden;"); - //style.append("white-space:nowrap;"); - //style.append("text-overflow:clip;"); - - string l_name = l.to_string(); - - if (__setting_location_bar_fixed_layout) - l_name = HTMLGenerateDivOfClass(l_name, "r_location_bar_ellipsis_entry"); - - //table_entries.listAppend(HTMLGenerateTagWrap("div", l_name, mapMake("class", "r_bold", "style", style))); - table_entries.listAppend(l_name); - table_entry_classes[table_entries.count() - 1] = "r_bold"; - table_entry_styles[table_entries.count() - 1] = style; - table_entry_width_weight[table_entries.count() - 1] = 1.05; - } - table_entries.listAppendList(location_data); - foreach key in location_urls - { - table_entry_urls[key + 1] = location_urls[key]; - } - foreach key in location_fixed_widths - { - table_entry_fixed_width_percentage[key + 1] = location_fixed_widths[key]; - } - foreach key in location_data - { - table_entry_width_weight[key + 1] = 0.8; - } - - - - bar.append(generateLocationBarTable(table_entries, table_entry_urls, table_entry_styles, table_entry_classes, table_entry_width_weight, table_entry_fixed_width_percentage, url)); - - - - //bar.append(""); - - - - - bar.append(""); - bar.append(""); - - float bottom_coordinates = __setting_navbar_height_in_em; - if (displaying_navbar) - bottom_coordinates = __setting_navbar_height_in_em * 2.0; - bar.append(generateLocationPopup(bottom_coordinates, (table_entries.count() == 1))); - return bar; -} diff --git a/Source/relay/TourGuide/Sections/Messages.ash b/Source/relay/TourGuide/Sections/Messages.ash deleted file mode 100644 index 462bdc66..00000000 --- a/Source/relay/TourGuide/Sections/Messages.ash +++ /dev/null @@ -1,977 +0,0 @@ -void generateRandomMessageLocation(string [int] random_messages) -{ - if (__last_adventure_location == $location[none]) - return; - string message = ""; - switch (__last_adventure_location) - { - case $location[the penultimate fantasy airship]: - message = "insert disc 2 to continue"; break; - case $location[a-boo peak]: - message = "allons-y!"; break; - case $location[twin peak]: - message = "fire walk with me"; break; - case $location[The Arrrboretum]: - message = "save the planet"; break; - case $location[the red queen's garden]: - message = "curiouser and curiouser"; break; - case $location[A Massive Ziggurat]: - message = "1.21 ziggurats"; break; - case $location[McMillicancuddy's Barn]: - message = "dooks"; break; - case $location[The Roman Forum]: - message = "they go the house"; break; - case $location[the battlefield (hippy uniform)]: - message = "love and war"; break; - case $location[the middle chamber]: - message = "pyramid laundry machine"; break; - case $location[the arid, extra-dry desert]: - message = "can't remember your name"; break; - case $location[outside the club]: - message = "around the world around the world around the world around the world"; break; - case $location[the hidden temple]: - message = "beware of temple guards"; break; - case $location[sonar]: - message = "one ping only"; break; - case $location[galley]: - message = "hungry?"; break; - case $location[science lab]: - message = "poetry in motion"; break; - case $location[fear man's level]: - case $location[doubt man's level]: - case $location[regret man's level]: - case $location[anger man's level]: - message = "this isn't me"; break; - case $location[domed city of ronaldus]: - case $location[domed city of grimacia]: - case $location[hamburglaris shield generator]: - message = "spaaaace!"; break; - case $location[The Mansion of Dr. Weirdeaux]: - case $location[The Deep Dark Jungle]: - case $location[The Secret Government Laboratory]: - message = "they know where you live, " + get_property("System.user.name").to_lower_case(); break; - case $location[The castle in the clouds in the sky (ground floor)]: - case $location[The castle in the clouds in the sky (basement)]: - case $location[The castle in the clouds in the sky (top floor)]: - if (my_class() == $class[disco bandit]) - message = "making castles of your disco"; - break; - case $location[The Prince's Restroom]: - case $location[The Prince's Dance Floor]: - case $location[The Prince's Kitchen]: - case $location[The Prince's Balcony]: - case $location[The Prince's Lounge]: - case $location[The Prince's Canapes table]: - message = "social sabotage"; break; - case $location[anemone mine (mining)]: - case $location[itznotyerzitz mine (in disguise)]: - case $location[the knob shaft (mining)]: - case $location[The Crimbonium Mine]: - case $location[The Velvet / Gold Mine (Mining)]: - message = "street sneaky pete don't you call me cause I can't go"; break; - case lookupLocation("Through the Spacegate"): - message = "oh look! rocks!"; - case $location[hell]: - message = "that's a clean burning hell, I'll tell you what"; break; - case $location[The Neverending Party]: - message = "duffo was lit"; break; - } - if (message != "") - random_messages.listAppend(message); -} - - -void generateRandomMessageFamiliar(string [int] random_messages) -{ - string lowercase_player_name = my_name().to_lower_case().HTMLEscapeString(); - if (my_familiar() == $familiar[none]) - return; - string message = ""; - switch (my_familiar()) - { - case $familiar[none]: - message = "even introverts need friends"; break; - case $familiar[crimbo shrub]: - if (format_today_to_string("MM") == "07") - message = "crimbo in july"; break; - case $familiar[black cat]: - message = "aww, cute kitty!"; break; - case $familiar[temporal riftlet]: - message = "master of time and space"; break; - case $familiar[Frumious Bandersnatch]: - message = "frabjous"; break; - case $familiar[Pair of Stomping Boots]: - if (__misc_state["free runs usable"]) - message = "running away again?"; - break; - case $familiar[baby sandworm]: - message = "the waters of life"; break; - case $familiar[baby bugged bugbear]: - message = "expected }, found }̋̑̀̆͊̑̔͏̱̩̠̰ ̣̻͊ͅf̝͎̰̥̙ͣͦͥ̎,̜̘̖ͭ͋ ̲͉̮̭̪̣͌͋ͤ̉͗ͪ̄̕;̹̼̋̈͛͊ ̧͔̥̤「͙̺̻͖̯͛̀̓̏͑̀l͍̍̍̍͑i̖̖͙͂ͪͮ̍ ̓͑̉̀̆҉̠̜͚̜̹1̶͔̩̬̦̦͍ͥ7͛҉̬̯͇̻͖͉1̆̑̂͒̓」̧̼̜̹̘͕͆̾́͆͐ͯͧ"; //causes severe rendering slowdown; working as intended - break; - case $familiar[mechanical songbird]: - message = "a little glowing friend"; break; - case $familiar[nanorhino]: - message = "write every day"; break; - case $familiar[rogue program]: - message = "ascends for the users"; break; - case $familiar[O.A.F.]: - message = "helping"; break; - case $familiar[Bank Piggy]: - case $familiar[Egg Benedict]: - case $familiar[Floating Eye]: - case $familiar[Money-Making Goblin]: - case $familiar[Oyster Bunny]: - case $familiar[Plastic Grocery Bag]: - case $familiar[Snowhitman]: - case $familiar[Vampire Bat]: - case $familiar[Worm Doctor]: - message = "hacker, or a QT, who could know"; break; - case $familiar[adorable space buddy]: - message = "far beyond the stars"; break; - case $familiar[happy medium]: - message = "karma slave"; //what mistakes could I have made? - break; - case $familiar[wild hare]: - message = "or you wouldn't have come here"; //you must be mad - break; - case $familiar[artistic goth kid]: - message = "life is pain, " + lowercase_player_name; break; - case $familiar[angry jung man]: - message = "personal trauma"; break; - case $familiar[unconscious collective]: - message = "zzz"; break; - case $familiar[dataspider]: - message = "spiders are your friends"; break; - case $familiar[stocking mimic]: - message = "delicious candy"; break; - case $familiar[cocoabo]: - message = "flightless bird"; break; - case $familiar[whirling maple leaf]: - message = "canadian pride"; break; - case $familiar[Hippo Ballerina]: - message = "spin spin spin"; break; - case $familiar[Mutant Cactus Bud]: - message = "always watching"; break; - case $familiar[ghuol whelp]: - message = "¯\\_(ツ)_/¯"; //¯\_(ツ)_/¯ - break; - case $familiar[bulky buddy box]: - message = "♥︎"; //♥︎ - break; - case $familiar[emo squid]: - message = "sob"; break; - case $familiar[fancypants scarecrow]: - message = "the best in terms of pants"; break; - case $familiar[jumpsuited hound dog]: - message = "a little less conversation"; break; - case $familiar[Gluttonous Green Ghost]: - message = "I think he can hear you, " + lowercase_player_name; break; - case $familiar[hand turkey]: - message = "a rare bird"; break; - case $familiar[reanimated reanimator]: - message = "weird science"; break; - case $familiar[Twitching Space Critter]: - message = "right right right right down right agh"; break; - case $familiar[slimeling]: - message = "lost mother"; break; - case $familiar[Puck Man]: - case $familiar[Ms. Puck Man]: - message = "ᗧ • • • • • • • • •"; break; - case $familiar[Lil' Barrel Mimic]: - message = ":D"; break; - case $familiar[pet rock]: - message = "what if the rock's eyebrow froze that way. would anyone notice?"; break; - case $familiar[space jellyfish]: - message = "deer force"; - if (__quest_state["Level 13"].state_boolean["king waiting to be freed"]) - { - int obtained = 0; - int obtainable = 0; - foreach it in $items[] - { - if (it.quest) continue; //these disappear - if (it.item_amount_almost_everywhere() > 0) - obtained += 1; - obtainable += 1; - } - float rate = to_float(obtained) / to_float(obtainable); - random_messages.listClear(); - message = "SEE YOU NEXT MISSION
your rate for collecting items is " + to_int(rate * 100) + "%"; - } - else if (my_level() == 1 || my_turncount() <= 2) - { - random_messages.listClear(); - message = "the last jellyfish is in captivity
the kingdom is at peace"; - } - - break; - case $familiar[bad vibe]: - message = "it's all your fault"; break; - case $familiar[pocket professor]: - message = "when your professor's in your pocket, you can profess anytime"; break; - case $familiar[god lobster]: - message = "god save the lobster"; break; - case $familiar[cat burglar]: - message = "cat got your tongue?"; break; - case $familiar[elf operative]: - message = "your mission, if you choose to accept it, is to use a better familiar"; break; - case $familiar[red-nosed snapper]: - message = "dude, where's my fish"; break; - case $familiar[melodramedary]: - message = "schlurrrrrk!"; break; - case $familiar[vampire vintner]: - message = "he doesn't drink... wine"; break; - case $familiar[grey goose]: - message = "gooso is lit"; break; - case $familiar[patriotic eagle]: - message = "proud to be a loather"; break; - } - if (message != "") - random_messages.listAppend(message); -} - -string generateRandomMessage() -{ - string [int] random_messages; - int current_hour = now_to_string("HH").to_int_silent(); - int current_minute = now_to_string("mm").to_int_silent(); - int minute_of_day = current_hour * 60 + current_minute; - - if (!playerIsLoggedIn()) - return "the kingdom awaits"; - - if (__misc_state["In valhalla"]) - return "rebirth"; - - if (__misc_state["in run"]) - { - if (my_turncount() > 1000 && !in_bad_moon()) - random_messages.listAppend("so many turns"); - - if (false) - random_messages.listAppend("you are ascending perfectly, excellent work!"); - else if (my_daycount() >= 365) - random_messages.listAppend("no king, forever"); - else if (my_daycount() >= 11) - random_messages.listAppend("does the king even exist...?"); - else if (my_turncount() > 400 && my_daycount() == 1) - random_messages.listAppend("you are ascending too... wait, what?"); - else if (gameday_to_int() == 7) - random_messages.listAppend("you are ascending at a reasonable pace, could do better"); - else - random_messages.listAppend("you are ascending too slowly, ascend faster!"); - - string what_does_the_spreadsheet_say = "saves a turn"; - if (my_path().id == PATH_ONE_CRAZY_RANDOM_SUMMER) - what_does_the_spreadsheet_say = "gives +fun"; - if ($item[optimal spreadsheet].equipped_amount() > 0) - random_messages.listAppend("every spreadsheet you wear " + what_does_the_spreadsheet_say); //sure, why not? - else - random_messages.listAppend("every spreadsheet you make " + what_does_the_spreadsheet_say); - } - - string [string] holiday_messages; - holiday_messages["Groundhog Day"] = "it's cold out there every day"; - holiday_messages["Crimbo"] = "merry crimbo"; - if ($item[tommy gun].equipped_amount() > 0) //I believe ya, but my tommy gun don't! - holiday_messages["Crimbo"] = "merry crimbo, ya filthy animal"; - holiday_messages["April Fool's Day"] = "you are ascending too quickly, ascend slower!"; - holiday_messages["Valentine's Day"] = HTMLGenerateSpanFont("♥︎", "pink", "3.0em"); - holiday_messages["Towel Day"] = "don't panic"; - - boolean [string] holidays_today = getHolidaysToday(); - foreach holiday in holidays_today - { - if (holiday_messages contains holiday) - { - random_messages.listAppend(holiday_messages[holiday]); - } - } - - if ($item[The One Mood Ring].equipped_amount() > 0 || $item[mood ring].equipped_amount() > 0) - { - string [int] moods = split_string("grateful,awake,accomplished,disappointed,enraged,tired,exhausted,amused,crushed,peaceful,energetic,listless,hyper,jubilant,hungry,sad,bewildered,alone,quixotic,recumbent,bored,excited,relaxed,lonely,curious,guilty,jealous,cheerful,depressed,stressed,infuriated,pleased,crappy,aggravated,okay,rejuvenated,apathetic,bittersweet,optimistic,exanimate,complacent,devious,rejected,blissful,discontent,sympathetic,mellow,refreshed,ecstatic,lazy,morose,dark,mischievous,bouncy,thankful,melancholy,content,drained,numb,uncomfortable,indifferent,groggy,calm,irate,determined,giggly,good,confused,anxious,relieved,mad,accepted,happy,angry,lethargic,shocked,indescribable,satisfied,gloomy,irritated,pessimistic,rushed,frustrated,surprised,annoyed,sleepy,touched,enthralled,cynical,envious,hopeful,ashamed,chipper,loved,giddy,restless", ","); - string mood_today = moods[gameday_to_int()]; - if (mood_today != "") - random_messages.listAppend(mood_today); - } - - if (__misc_state["in run"]) - { - random_messages.listAppend("optimal power, make up!"); - random_messages.listAppend("the faster your runs, the longer they take"); - } - - generateRandomMessageLocation(random_messages); - - //random_messages.listAppend(HTMLGenerateTagWrap("a", "if you're feeling stressed, play alice's army", generateMainLinkMap("aagame.php"))); - random_messages.listAppend(HTMLGenerateTagWrap("a", "if you're feeling stressed, play witchess", generateMainLinkMap("playwitchess.php?action=another"))); - random_messages.listAppend("consider your mistakes creative spading"); - random_messages.listAppend(HTMLGenerateTagWrap("a", "Found inaccurate/questionable information?
Have a question/suggestion? Click here!", string [string] {"href":"https://github.com/loathers/TourGuide/", "target":"_blank", "class":"r_a_undecorated"})); - - if (hippy_stone_broken()) - random_messages.listAppend(HTMLGenerateTagWrap("a", "it's not easy having yourself a good time", generateMainLinkMap("peevpee.php"))); - - string [item] equipment_messages; - equipment_messages[$item[whatsian ionic pliers]] = "ionic pliers untinker to a screwdriver and a sonar-in-a-biscuit"; - equipment_messages[$item[yearbook club camera]] = "rule of thirds"; - equipment_messages[$item[happiness]] = "bang bang"; - equipment_messages[$item[mysterious silver lapel pin]] = "be seeing you"; - equipment_messages[$item[Moonthril Circlet]] = "moon tiara"; //action! - equipment_messages[$item[numberwang]] = "simply everyone"; - equipment_messages[$item[Mark V Steam-Hat]] = "girl genius"; - equipment_messages[$item[mr. accessory]] = "you can equip mr. accessories?"; - equipment_messages[$item[replica haiku katana]] = "a haiku state of mind"; - equipment_messages[$item[white hat hacker T-shirt]] = "hack the planet"; - equipment_messages[$item[heart necklace]] = "♥︎"; //♥︎ - equipment_messages[$item[fleetwood chain]] = "running in the shadows"; - equipment_messages[$item[liar's pants]] = "never tell the same lie twice"; - equipment_messages[$item[detective skull]] = HTMLGenerateSpanFont("too slow ascend faster", "#ACA200"); //speakeasy password - equipment_messages[$item[gasmask]] = "are you my mummy?"; - equipment_messages[$item[spanish fly trap]] = "around the world around the world around the world around the world"; - equipment_messages[$item[wand of nagamar]] = "levi OH sa"; - if (in_bad_moon() && my_primestat() != $stat[moxie]) - equipment_messages[$item[sneaky pete's breath spray]] = "every class a moxie class"; - foreach it in $items[twisted-up wet towel,sommelier's towel,time bandit time towel] - equipment_messages[it] = "don't panic"; - equipment_messages[$item[pirate fledges]] = " oh, better far to live and die, under the brave black flag I fly! "; - - equipment_messages[$item[guzzlr tablet]] = "looking for booze, eh?"; - equipment_messages[$item[retrospecs]] = "cleesh is love, cleesh is life"; - equipment_messages[$item[tiny stillsuit]] = "it's called fashion sweaty"; - equipment_messages[$item[jurassic parka]] = "so preoccupied with whether you could, never stopped to think if you should"; - equipment_messages[$item[replica jurassic parka]] = "so preoccupied with whether you replica could, never stopped to think if you replica should"; - - foreach it in equipment_messages - { - if (it.equipped_amount() > 0) - { - random_messages.listAppend(equipment_messages[it]); - break; - } - } - - if (my_ascensions() == 0) - random_messages.listAppend("welcome to the kingdom!"); - else if (my_ascensions() == 1) - random_messages.listAppend("run, while you still have the chance!"); - - if (__misc_state["in run"]) - random_messages.listAppend("perfect runs are overrated"); - random_messages.listAppend("math is your helpful friend"); - - if (get_property_int("_pantsgivingCount") >= 5500) - { - random_messages.listAppend("Could not connect to secondary database server:2003 - Can't connect to MySQL server on '10.0.0.51' (99)"); - } - - if ((gameday_to_int() & 31) == 0) - random_messages.listAppend("seek the alchemist"); //a young lady's illustrated ascension guide - - string [effect] effect_messages; - - effect_messages[$effect[consumed by anger]] = "don't ascend angry"; - effect_messages[$effect[consumed by regret]] = "wasted potential"; - effect_messages[$effect[All Revved Up]] = "vroom"; - if (my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) - effect_messages[$effect[Expert Timing]] = "martial arts and crafts"; - effect_messages[$effect[apathy]] = ""; // - effect_messages[$effect[silent running]] = "an awful lot of running"; - effect_messages[$effect[Neuromancy]] = "the silver paths"; - effect_messages[$effect[Teleportitis]] = "everywhere and nowhere"; - effect_messages[$effect[Form of...Bird!]] = "fiddle fiddle fiddle"; - effect_messages[$effect[superstar]] = "★"; - effect_messages[$effect[hopped up on goofballs]] = "a massive drug deficiency"; - foreach s in $strings[Warlock\, Warstock\, and Warbarrel,Barrel of Laughs,Barrel Chested,Pork Barrel,Double-Barreled,Beer Barrel Polka] - effect_messages[s.to_effect()] = "just let me throw a barrel at it"; - effect_messages[$effect[Meteor Showered]] = "すきだ"; - foreach e in effect_messages - { - if (e.have_effect() > 0 && e != $effect[none]) - { - random_messages.listAppend(effect_messages[e]); - break; - } - } - - - if (__misc_state["single familiar run"]) - random_messages.listAppend("together forever"); - - random_messages.listAppend("click click click"); - - switch (my_path().id) - { - case PATH_OXYGENARIAN: - random_messages.listAppend("the slow path"); break; - case PATH_BEES_HATE_YOU: - random_messages.listAppend("bzzzzzz"); break; - case PATH_WAY_OF_THE_SURPRISING_FIST: - random_messages.listAppend("martial arts and crafts"); break; - case PATH_TRENDY: - random_messages.listAppend("played out"); break; - case PATH_AVATAR_OF_BORIS: - random_messages.listAppend("testosterone poisoning"); break; - case PATH_BUGBEAR_INVASION: - random_messages.listAppend("bugbears!"); break; - case PATH_ZOMBIE_SLAYER: - random_messages.listAppend("consumerism metaphor"); break; - case PATH_CLASS_ACT: - random_messages.listAppend("try the sequel"); break; - case PATH_AVATAR_OF_JARLSBERG: - random_messages.listAppend("nerd"); break; - case PATH_BIG: - random_messages.listAppend("everything's so tiny..."); break; - case PATH_KOLHS: - random_messages.listAppend("did you study?"); break; - case PATH_CLASS_ACT_2: - random_messages.listAppend("lonely guild trainer"); break; - case PATH_AVATAR_OF_SNEAKY_PETE: - random_messages.listAppend("sunglasses at night"); break; - case PATH_SLOW_AND_STEADY: - if (!in_hardcore()) - random_messages.listAppend("infinite pulls"); - else - random_messages.listAppend("skip a day if you like"); - break; - case PATH_HEAVY_RAINS: - random_messages.listAppend("survive"); break; - case PATH_PICKY: - if ($skill[cannelloni cannon].skill_is_usable() && !$skill[cannelloni cocoon].skill_is_usable()) //such an easy mistake... - random_messages.listAppend("cannelloni confusion"); - else - random_messages.listAppend("combinatorial ascension"); - break; - case PATH_STANDARD: - random_messages.listAppend("no past no path"); break; - case PATH_ACTUALLY_ED_THE_UNDYING: - random_messages.listAppend("UNDYING!"); break; - case PATH_ONE_CRAZY_RANDOM_SUMMER: - random_messages.listAppend("dance the mersenne twist"); break; - case PATH_COMMUNITY_SERVICE: - random_messages.listAppend("make the world a better place"); break; - case PATH_AVATAR_OF_WEST_OF_LOATHING: - random_messages.listAppend("draw"); break; - case PATH_THE_SOURCE: - if (my_daycount() % 2 == 0) - random_messages.listAppend("don't think you aren't. know you aren't."); - else - random_messages.listAppend("it is not the spoon that ascends, it is only yourself"); - break; - case PATH_NUCLEAR_AUTUMN: - random_messages.listAppend("I do want to set the world on " + HTMLGenerateSpanFont("fire", "red")); - break; - case PATH_GELATINOUS_NOOB: - random_messages.listAppend("you jelly?"); - break; - case PATH_LICENSE_TO_ADVENTURE: - random_messages.listAppend("FOR YOUR EYES ONLY"); - break; - case PATH_LIVE_ASCEND_REPEAT: - random_messages.listAppend("a single perfect day"); - break; - case PATH_POCKET_FAMILIARS: - random_messages.listAppend("adorable slaves"); - break; - case PATH_G_LOVER: - random_messages.listAppend("get going, guuuurl"); - break; - case PATH_DEMIGUISE: - random_messages.listAppend("who are you?"); break; - case PATH_VAMPIRE: - random_messages.listAppend("die monster! you don't belong in this world!"); break; - case PATH_2CRS: - random_messages.listAppend("what happened to my inventory?"); break; - case PATH_EXPLOSIONS: - random_messages.listAppend("kaboooooom"); break; - /*case PATH_CLASS_ACT_3: - random_messages.listAppend("buttons for the people"); break; - case PATH_AVATAR_OF_THE_NAUGHTY_SORCERESS: - random_messages.listAppend("go forth to your lair! have some tea"); break;*/ - } - - if (in_ronin() && my_adventures() <= 3) - random_messages.listAppend("always tomorrow"); - - random_messages.listAppend("I don't know either, sorry"); - - string lowercase_player_name = my_name().to_lower_case().HTMLEscapeString(); - - random_messages.listAppend(HTMLGenerateTagWrap("a", "check the wiki", mapMake("class", "r_a_undecorated", "href", "http://kol.coldfront.net/thekolwiki/index.php/Main_Page", "target", "_blank"))); - random_messages.listAppend("the RNG is only trying to " + ((random(100) == 0) ? "hurt" : "help")); - if (__misc_state["in run"]) - { - int choice = gameday_to_int() & 3; - - if (choice == 0) - random_messages.listAppend("speed ascension is all I have left, " + lowercase_player_name); - else if (choice == 1) - random_messages.listAppend("let the turns go"); - else if (choice == 2) - random_messages.listAppend("mostly made up"); - else if (choice == 3) - random_messages.listAppend("kingdom of self loathing"); - if (my_ascensions() >= 1000) - random_messages.listAppend("dedicated"); - } - - if (item_drop_modifier() <= -100.0) - random_messages.listAppend("let go of your material posessions"); - if ($item[puppet strings].item_amount() > 0 && my_id() != 1557284) - { - //full puppet string support: - string chosen_message; - switch (gameday_to_int() % 13) - { - case 0: chosen_message = "%playername% is easily the most great person ever! three cheers for %playername%!"; break; - case 1: chosen_message = "%playername% is my hero! don't you all agree?"; break; - case 2: chosen_message = "%playername% is such a sexy beast!"; break; - case 3: chosen_message = "%playername% is super-attractive and studly! don't you all agree?"; break; - case 4: chosen_message = "%playername% is super-attractive and studly! just saying that name makes me feel all tingly inside!"; break; - case 5: chosen_message = "who do I think is the best KoLer? obviously\, it's %playername%! how about a round of applause?"; break; - case 6: chosen_message = "I wish I was as good-looking as %playername%. hip hip hooray!"; break; - case 7: chosen_message = "I'm %playername%'s biggest fan! let's hear it for %playername%!"; break; - case 8: chosen_message = "I've never met anyone as attractive as %playername%! how about a round of applause?"; break; - case 9: chosen_message = "I've never met anyone as studly as %playername%! all the rest of us are totally lame in comparison!"; break; - case 10: chosen_message = "is anyone as fabulous as %playername%? I don't think so! just saying that name makes me feel all tingly inside!"; break; - case 11: chosen_message = "is anyone as intelligent as %playername%? I don't think so! hooray for %playername%!"; break; - default: chosen_message = "%playername% is totally awesome! hooray for %playername%!"; break; - } - chosen_message = chosen_message.replace_string("%playername%", lowercase_player_name); - random_messages.listAppend(chosen_message); - //random_messages.listAppend(lowercase_player_name + " is totally awesome! hooray for " + lowercase_player_name + "!"); - } - - if (__quest_state["Level 12"].in_progress && __quest_state["Level 12"].state_int["hippies left on battlefield"] < 1000 && __quest_state["Level 12"].state_int["frat boys left on battlefield"] < 1000) - random_messages.listAppend("playing sides"); - - if (__iotms_usable[$item[Order of the Green Thumb Order Form]]) - random_messages.listAppend(HTMLGenerateTagWrap("a", "the forgotten friar cries himself to sleep", generateMainLinkMap("place.php?whichplace=forestvillage&action=fv_friar"))); - - if (!__misc_state["skills temporarily missing"] && !$skill[Transcendent Olfaction].skill_is_usable()) - { - random_messages.listAppend(HTMLGenerateTagWrap("a", "visit the bounty hunter hunter sometime", generateMainLinkMap("bounty.php"))); - } - if (__misc_state["in aftercore"]) - random_messages.listAppend(HTMLGenerateTagWrap("a", "ascension is waiting for you", generateMainLinkMap("place.php?whichplace=nstower"))); - - if (my_adventures() == 0) - random_messages.listAppend("nowhere left to go"); - - if (__quest_state["Level 11"].in_progress) - random_messages.listAppend("try not to lose your sanity"); - if (__quest_state["Level 13"].in_progress) - { - if (my_daycount() == 1) - random_messages.listAppend("all the world's work in a day"); - else - random_messages.listAppend("it'll be all over soon"); - } - - if (hippy_stone_broken() && pvp_attacks_left() > 0) - random_messages.listAppend(HTMLGenerateTagWrap("a", "aggressive friendship", generateMainLinkMap("peevpee.php"))); - - - if (get_property_boolean("_warbearGyrocopterUsed")) - random_messages.listAppend("[gyroseaten] => 109"); - - //random_messages.listAppend(HTMLGenerateTagWrap("a", "♫", mapMake("class", "r_a_undecorated", "href", "http://www.kingdomofloathing.com/radio.php", "target", "_blank"))); - - if (__misc_state_int["free rests remaining"] > 0) - random_messages.listAppend(HTMLGenerateTagWrap("a", "dream your life away", generateMainLinkMap(__misc_state_string["resting url"]))); - - if (get_property_int("cinderellaScore") >= 32) - random_messages.listAppend("mother knows best"); - - if ($location[the shore\, inc. travel agency].turnsAttemptedInLocation() >= 11) - { - if (hippy_stone_broken()) - random_messages.listAppend("beware of shorebots"); - else - random_messages.listAppend("under a distant shore you will find your answers"); - } - - if (current_hour >= 2 && current_hour <= 3) - random_messages.listAppend("up late?"); - else if (current_hour >= 4 && current_hour <= 5) - random_messages.listAppend("zzz..."); - else if (current_hour == 6) - random_messages.listAppend("the dawn is your enemy"); - - random_messages.listAppend("take chances, be courageous, go exploring!"); - switch (my_class()) - { - case $class[disco bandit]: - random_messages.listAppend("making discos of your castles"); break; - case $class[seal clubber]: - random_messages.listAppend("I ♣︎ seals"); break; - case $class[turtle tamer]: - random_messages.listAppend("friends everywhere you go"); break; - case $class[sauceror]: - random_messages.listAppend("journey of the sauceror"); break; - case $class[Snake Oiler]: - random_messages.listAppend("ten points to slytherin"); break; - } - - if (numeric_modifier("hot damage") <= 0.0 && gameday_to_int() % 4 == 0) - random_messages.listAppend("have you tried " + HTMLGenerateSpanFont("fire", "red")); - - - if (__misc_state["Chateau Mantegna available"] && get_property_monster("chateauMonster").phylum == $phylum[fish] && !get_property_boolean("_chateauMonsterFought")) - { - random_messages.listAppend(HTMLGenerateTagWrap("a", "personal aquarium", generateMainLinkMap("place.php?whichplace=chateau"))); //WhiteWizard42: feeeeesh. feesh in the waaaall - } - generateRandomMessageFamiliar(random_messages); - - if (last_monster().phylum == $phylum[penguin]) - { - random_messages.listClear(); //sufficiently rare - random_messages.listAppend("dood"); - } - - string [monster] monster_messages; - string [monster] beaten_up_monster_messages; - //TODO add a message for the procrastination giant - foreach m in $monsters[The Temporal Bandit,crazy bastard,Knott Slanding,hockey elemental,Hypnotist of Hey Deze,infinite meat bug,QuickBASIC Elemental,The Master of Thieves,Baiowulf,Count Bakula,The Nuge] //Pooltergeist (Ultra-Rare)? - monster_messages[m] = "an ultra rare! congratulations!"; - monster_messages[$monster[The Master of Thieves]] = "don't @ me"; - monster_messages[$monster[Dad Sea Monkee]] = "is always was always" + HTMLGenerateSpanFont(" is always was always", "#444444") + HTMLGenerateSpanFont(" is always was always", "#888888") + HTMLGenerateSpanFont(" is always was always", "#BBBBBB"); - - foreach m in $monsters[Ed the Undying (1),Ed the Undying (2),Ed the Undying (3),Ed the Undying (4),Ed the Undying (5),Ed the Undying (6),Ed the Undying (7)] - monster_messages[m] = "UNDYING!"; - foreach m in $monsters[Naughty Sorceress, Naughty Sorceress (2), Naughty Sorceress (3)] - { - if (holidays_today["Valentine's Day"]) - monster_messages[m] = "please be mine, sorceress"; - else - monster_messages[m] = "she isn't all that bad"; - } - foreach m in $monsters[Shub-Jigguwatt\, Elder God of Violence,Yog-Urt\, Elder Goddess of Hatred] - monster_messages[m] = "strange aeons"; - monster_messages[$monster[daft punk]] = "can you feel it?"; - monster_messages[$monster[ghastly organist]] = "phantom of the opera"; - monster_messages[$monster[The Man]] = "let the workers unite"; - monster_messages[$monster[The Big Wisniewski]] = "far out"; - monster_messages[$monster[Quiet Healer]] = "..."; - monster_messages[$monster[menacing thug]] = "watch your back"; - monster_messages[$monster[sea cowboy]] = "pardon me"; - monster_messages[$monster[topiary golem]] = "almost ther... wait, golems?"; - monster_messages[$monster[The Server]] = "console cowboy"; - monster_messages[$monster[Fickle Finger of F8]] = "f/8 and be there"; - monster_messages[$monster[malevolent crop circle]] = "I want to believe"; - monster_messages[$monster[Enraged Cow]] = "moo"; - if ($item[bottle of blank-out].is_unrestricted()) - monster_messages[$monster[Claybender Sorcerer Ghost]] = "accio blank-out"; - else - monster_messages[$monster[Claybender Sorcerer Ghost]] = "leaderboardus totalus"; - monster_messages[$monster[Whatsian Commando Ghost]] = "captain jack hotness"; - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - monster_messages[$monster[Whatsian Commando Ghost]] = "are you my mummy?"; - monster_messages[$monster[Space Tourist Explorer Ghost]] = "oh my"; - monster_messages[$monster[Battlie Knight Ghost]] = "boring conversation anyway"; - monster_messages[$monster[oil slick]] = "run more ML!"; - monster_messages[$monster[Space Marine]] = "as if it were from an old dream"; - monster_messages[$monster[Regret Man]] = "wasted potential"; - monster_messages[$monster[Principal Mooney]] = "life moves pretty fast"; - if (my_turncount() < 11) - monster_messages[$monster[family of kobolds]] = "in a hurry?"; - monster_messages[$monster[Black Crayon Spiraling Shape]] = "be what you're like"; - monster_messages[$monster[best-selling novelist]] = "fiction to escape reality"; - monster_messages[$monster[7-Foot Dwarf Replicant]] = "it's too bad she won't live
but then again, who does?"; - monster_messages[$monster[The Avatar of Jarlsberg]] = "smoked cheese"; - monster_messages[$monster[giant sandworm]] = "walk without rhythm"; - monster_messages[$monster[bookbat]] = "tattered scrap of dignity"; - monster_messages[$monster[Urge to Stare at Your Hands]] = ".⃝.⃝"; //.⃝.⃝ - if (my_path().id == PATH_HEAVY_RAINS) - monster_messages[$monster[pygmy bowler]] = "right into the gutter"; //come back! - monster_messages[$monster[Ron "The Weasel" Copperhead]] = "RONALD WEASLEY! HOW DARE YOU STEAL THAT ZEPPELIN
" + ChecklistGenerateModifierSpan("your father's now facing an inquiry at work and it's entirely YOUR FAULT"); - monster_messages[$monster[Mr. Loathing]] = HTMLGenerateTagWrap("a", "ruuun! go! get to the towah!", generateMainLinkMap("place.php?whichplace=nstower")); - if (my_hp() < my_maxhp()) - monster_messages[$monster[Smooth Criminal]] = "you've been hit by
you've been struck by
a smooth criminal"; - monster_messages[$monster[demonic icebox]] = "zuul"; - monster_messages[$monster[angry mushroom guy]] = "touch fizzy, get dizzy"; - beaten_up_monster_messages[$monster[storm cow]] = "
^__^            
(oo)\\_______
(__)\\ )\\/\\
||----w |
|| ||
"; - monster_messages[$monster[The Barrelmech of Diogenes]] = "just let me throw a barrel at it"; - //beaten_up_monster_messages[$monster[Lavalos]] = HTMLGenerateTagWrap("span", "but... the future refused to change", mapMake("onclick", "var l = new Audio('" + __lavalos_sound_data + "'); l.play();", "class", "r_clickable")); //copyright, etc - beaten_up_monster_messages[$monster[Lavalos]] = "but... the future refused to change"; - if ($item[protonic accelerator pack].equipped_amount() > 0 && last_monster().monsterIsGhost()) - beaten_up_monster_messages[last_monster()] = "venkman makes it look easy"; - if ($effect[beaten up].have_effect() > 0 && $items[rainbow pearl earring,rainbow pearl necklace,rainbow pearl ring,vampire pearl earring,vampire pearl ring,vampire pearl necklace,freshwater pearl necklace,pearl diver's ring,pearl diver's necklace,pearl necklace].equipped_amount() > 0) - beaten_up_monster_messages[last_monster()] = "WHY WON'T YOU LET ME DO THIS FOR YOU, ROSE?"; - if (last_monster().phylum == $phylum[demon]) - beaten_up_monster_messages[last_monster()] = "he made the devil so much stronger than a man!"; - if (current_hour >= 5 && current_hour <= 11) - monster_messages[$monster[Lavalos]] = "good morning, " + lowercase_player_name + "!"; - else - monster_messages[$monster[Lavalos]] = "all life begins with nu and ends with nu"; - monster_messages[$monster[sk8 gnome]] = "he was a sk8r gnome she said see u l8r gnome"; - monster_messages[$monster[The Inquisitor]] = "nothing is up"; - monster_messages[$monster[Doc Clock]] = "your defeat will happen at " + (current_hour > 12 ? current_hour - 12 : current_hour) + ":" + current_minute + " precisely"; // + (current_hour >= 12 ? " PM" : " AM") - monster_messages[lookupMonster("God Lobster")] = "what a grand and intoxicating innocence"; //how can you kill a god? equip the heart of the volcano? - monster_messages[lookupMonster("cockroach")] = "are bug exterminators professional assassins?"; - monster_messages[lookupMonster("Mountain Man")] = "it's ok, TPTB don't like mining either"; - monster_messages[lookupMonster("Smut Orc Pervert")] = "remember, gooso is lit"; - monster_messages[lookupMonster("void slab")] = "return the slab, or suffer my curse"; - monster_messages[lookupMonster("Astrologer of Shub-Jigguwatt")] = "gettin' jiggu watt it"; - monster_messages[lookupMonster("party skelteon")] = "when it's time to party we will party hard"; - - string day_cycle; - if (current_hour >= 5 && current_hour <= 11) - day_cycle = "morning"; - else if (current_hour >= 12 && current_hour <= 16) - day_cycle = "afternoon"; - else if (current_hour >= 17 && current_hour <= 20) - day_cycle = "evening"; - else - day_cycle = "night"; - monster_messages[$monster[Travoltron]] = now_to_string("EEEE").to_lower_case() + " " + day_cycle + " fever"; - - if (my_daycount() == 2 && (my_adventures() == 0 || availableDrunkenness() < 0) && availableFullness() == 0 && availableDrunkenness() <= 0 && my_path().id != PATH_OXYGENARIAN && __quest_state["Level 12"].started && !__quest_state["Level 13"].state_boolean["king waiting to be freed"] && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_SLOW_AND_STEADY && !__quest_state["Level 13"].finished) - { - //detect failed two-day runs, and provide psychological support: - random_messages.listClear(); - if (__quest_state["Level 13"].started) - random_messages.listAppend("ever so close"); - else - random_messages.listAppend("three days is fine"); - } - - boolean already_output_relevant_beaten_up_effect = false; - if ((my_hp() == 0 || $effect[beaten up].have_effect() > 0) && beaten_up_monster_messages contains last_monster() && last_monster() != $monster[none]) - { - random_messages.listClear(); - random_messages.listAppend(beaten_up_monster_messages[last_monster()]); - already_output_relevant_beaten_up_effect = true; - } - else if (monster_messages contains last_monster() && last_monster() != $monster[none]) - { - random_messages.listClear(); - random_messages.listAppend(monster_messages[last_monster()]); - } - - - if (__quest_state["Level 13"].state_boolean["king waiting to be freed"]) - { - if (my_path().id == PATH_ONE_CRAZY_RANDOM_SUMMER) - { - random_messages.listClear(); - random_messages.listAppend(HTMLGenerateTagWrap("a", "roll the dice", generateMainLinkMap("place.php?whichplace=nstower"))); - } - } - - if (__misc_state_int["Basement Floor"] == 500) - { - random_messages.listClear(); - random_messages.listAppend(HTMLGenerateTagWrap("a", "open it!", generateMainLinkMap("basement.php"))); - } - - string [string] encounter_messages; - boolean encounter_override = false; - encounter_messages["It's Always Swordfish"] = "one two three four five"; - encounter_messages["Meet Frank"] = "don't trust the skull"; - encounter_messages["The Mirror in the Tower has the View that is True"] = "shatter the false reality"; - encounter_messages["A Tombstone"] = "peperony and chease"; - encounter_messages["Witchess Puzzles"] = "this etch a sketch is hard"; - encounter_messages["Rubbed it the Right Way"] = "desire incarnate"; - if (my_class() == $class[turtle tamer]) - { - //The Horror... needs disambiguation - foreach s in $strings[Nantucket Snapper,Blue Monday,Capital!,Training Day,Boxed In,Duel Nature,Slow Food,A Rolling Turtle Gathers No Moss,Slow Road to Hell,C'mere\, Little Fella,The Real Victims,Like That Time in Tortuga,Cleansing your Palette,Harem Scarum,Turtle in peril,No Man\, No Hole,Slow and Steady Wins the Brawl,Stormy Weather,Turtles of the Universe,O Turtle Were Art Thou,Allow 6-8 Weeks For Delivery,Kick the Can,Turtles All The Way Around,More eXtreme Than Usual,Jewel in the Rough,The worst kind of drowning] - encounter_messages[s] = "friend!"; - } - if (encounter_messages contains get_property("lastEncounter")) - { - random_messages.listClear(); - random_messages.listAppend(encounter_messages[get_property("lastEncounter")]); - encounter_override = true; - } - - if (__quest_state["Level 12"].in_progress && __quest_state["Level 12"].state_int["hippies left on battlefield"] == 1 && __quest_state["Level 12"].state_int["frat boys left on battlefield"] == 1) - { - random_messages.listClear(); - random_messages.listAppend("wossname is waiting"); - } - - if (my_familiar() == $familiar[Helix Fossil]) - { - buffer generated; - - - string [int] commands; - - string property_value = get_property("__voices"); - - if (property_value.length() > 1) //remove sentinel - { - if (property_value.char_at(property_value.length() - 1) == "|") - property_value = property_value.substring(0, property_value.length() - 1); - } - - commands = property_value.split_string_alternate(","); - - for i from 0 to 0 - { - string word; - int r = random(100); - if (r < 15) - word = "⬆"; //⬆︎ - else if (r < 30) - word = "⬇"; //⬇︎ - else if (r < 45) - word = "➡"; //➡ - else if (r < 60) - word = "⬅"; //⬅︎ - else if (r < 75) - word = "A";// Ⓐ = Ⓐ - else if (r < 95) - word = "B"; //Ⓑ = Ⓑ - else - word = "start"; - - - - commands.listAppend(word); - } - while (commands.count() > 6) - remove commands[commands.listKeyForIndex(0)]; - set_property("__voices", commands.listJoinComponents(", ") + "|"); //we add an ending sentinel because set_property() will remove ";" if it's at the end of the string. set_property() is not guaranteed to keep data integrity - - random_messages.listClear(); - - string message = commands.listJoinComponents(" "); - message = HTMLGenerateTagWrap("span", message, mapMake("onclick", "updatePageAndFireTimer()", "class", "r_clickable")); - - random_messages.listAppend(message); - } - - - - foreach s in $strings[rainDohMonster,spookyPuttyMonster,cameraMonster,photocopyMonster,envyfishMonster,iceSculptureMonster,crudeMonster,crappyCameraMonster,romanticTarget,chateauMonster] - { - if (get_property_monster(s) == $monster[Quiet Healer]) - { - random_messages.listClear(); - random_messages.listAppend("you can't bring her back"); - break; - } - } - if (false)//mmg_my_bets().count() > 0) - { - random_messages.listClear(); - random_messages.listAppend("win some, lose some"); - } - if ($effect[beaten up].have_effect() > 0 && limit_mode().length() == 0 && !already_output_relevant_beaten_up_effect) - { - random_messages.listClear(); - - - switch (my_path().id) - { - case PATH_BEES_HATE_YOU: - random_messages.listAppend("BZZZZZZ"); break; - case PATH_ONE_CRAZY_RANDOM_SUMMER: - random_messages.listAppend("tick, tock"); break; - case PATH_ACTUALLY_ED_THE_UNDYING: - random_messages.listAppend("DYING!"); break; - case PATH_COMMUNITY_SERVICE: - random_messages.listAppend("no good deed goes unpunished"); break; - case PATH_AVATAR_OF_WEST_OF_LOATHING: - random_messages.listAppend("shucks"); break; - case PATH_LIVE_ASCEND_REPEAT: - random_messages.listAppend("I got you babe"); break; - case PATH_LICENSE_TO_ADVENTURE: - random_messages.listAppend("you only live twice"); break; - case PATH_THE_SOURCE: - random_messages.listAppend("not like this"); break; - case PATH_POCKET_FAMILIARS: - random_messages.listAppend(lowercase_player_name + "! now is not the time to use that!"); break; - case PATH_G_LOVER: - random_messages.listAppend("the Gs will continue until morale improves"); break; - case 46: // Fall of the Dinosaurs - random_messages.listAppend("watch out for velociraptors"); break; - default: - random_messages.listAppend("ow"); break; - } - } - if (my_turncount() <= 0) - { - random_messages.listClear(); - if (my_path().id == PATH_LIVE_ASCEND_REPEAT) - random_messages.listAppend("I got you babe"); - else if (my_path().id == PATH_POCKET_FAMILIARS) - random_messages.listAppend("pika pika!"); - else - random_messages.listAppend("find yourself
starting back"); - } - if (limit_mode() == "Spelunky" && !encounter_override) - { - random_messages.listClear(); - - if (get_property("lastEncounter") == "Spelunkrifice" && get_property("spelunkyStatus").contains_text("Buddy: ")) - { - if (get_property("spelunkingStatus").contains_text("Resourceful Kid")) - random_messages.listAppend("he's only a child!"); - else - random_messages.listAppend("et tu, " + lowercase_player_name + "?"); - } - else - random_messages.listAppend("ascend? yes! play? no!"); - } - if (limit_mode() == "batman" && !encounter_override) - { - random_messages.listClear(); - random_messages.listAppend("a superstitious, cowardly lot"); - } - - // Adding a few Legacy of Loathing replica messages - - if (my_path() == $path[Legacy of Loathing]) - { - random_messages.listAppend("make sure you get your hand turkey"); - random_messages.listAppend("hot legacy summer"); - random_messages.listAppend("living like the richy-rich"); - random_messages.listAppend("it's one banana, " + lowercase_player_name + ". what could it cost, replica ten bucks?"); - random_messages.listAppend("replicas are like any other machine -- they're either a benefit or a hazard"); - random_messages.listAppend("claimin' respect, just to get a rep... lica"); - } - - // There's no way I could determine for mafia to tell that you -just- cast Feel Disappointed. - // Therefore, for this silly set of disappointment messages, they only show in the pool if - // you've cast it exactly two times. This is silly, but I think it's fine. - - if (get_property("_feelDisappointedUsed") == 2) - { - random_messages.listAppend("zapdos ran away! aww..."); - random_messages.listAppend("mentally simulate a 1-day HC Grey You ascension"); - random_messages.listAppend("manifesting a 40 turn friars"); - random_messages.listAppend("agriculture will become impossible in our lifetime"); - random_messages.listAppend("we will never get the cruelest moth"); - random_messages.listAppend("gaze upon this display case and despair"); - random_messages.listAppend(HTMLGenerateTagWrap("a", "gaze upon this display case and despair", generateMainLinkMap("displaycollection.php?who=252058"))); - random_messages.listAppend("home depot is out of 12-foot skeletons"); - random_messages.listAppend("imagine being a Sacramento Kings fan, tho"); - random_messages.listAppend("are you SURE you took the crystal ball off?"); - random_messages.listAppend("does king ralph really care about us?"); - } - - if (format_today_to_string("yyyyMMdd") == "20151021") //october 21st, 2015 - { - //kept active for any time travelers - random_messages.listClear(); - if (get_property("System.user.country.format") == "US") - random_messages.listAppend("88 MPH
hey, you did it!"); - else - random_messages.listAppend("142 km/h
hey, you did it!"); - } - - - //Choose: - if (random_messages.count() == 0) - return "lack of cleverness"; - string chosen_message = ""; - //Base message off of the minute, so it doesn't cycle when the page reloads often: - chosen_message = random_messages[minute_of_day % random_messages.count()]; - - return chosen_message; -} diff --git a/Source/relay/TourGuide/Sections/Navigation Bar.ash b/Source/relay/TourGuide/Sections/Navigation Bar.ash deleted file mode 100644 index b6f6f66c..00000000 --- a/Source/relay/TourGuide/Sections/Navigation Bar.ash +++ /dev/null @@ -1,84 +0,0 @@ -buffer generateNavbar(Checklist [int] ordered_output_checklists) -{ - buffer navbar; - navbar.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_bottom_outer_container", "style", "bottom:0px;"))); - navbar.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_bottom_inner_container", "style", "background:" + __setting_navbar_background_colour + ";"))); - - string [int] titles; - foreach key in ordered_output_checklists - titles.listAppend(ordered_output_checklists[key].title); - - if (titles.count() > 0) - { - int [int] each_width; - //Calculate width of each title: - if (__setting_navbar_has_proportional_widths) - { - int total_character_count = 0; - foreach i in titles - { - string title = titles[i]; - int title_length = title.length(); - total_character_count += title_length; - } - if (total_character_count > 0) - { - foreach i in titles - { - string title = titles[i]; - float title_length = title.length(); - - float calculating_value = (100.0 * title_length) / (to_float(total_character_count)); - each_width[i] = floor(calculating_value); - } - } - } - else - { - float remaining_width = 100.0; - int number_done = 0; - foreach i in titles - { - int shared_width = to_int(remaining_width / to_float(titles.count() - number_done)); - each_width[i] = shared_width; - remaining_width -= shared_width; - number_done += 1; - } - } - boolean first = true; - foreach i in titles - { - string title = titles[i]; - - string onclick_javascript = ""; - - //Cancel our usual link: - onclick_javascript += "navbarClick(event,'" + HTMLConvertStringToAnchorID(title + " checklist container") + "')"; - - navbar.append(HTMLGenerateTagPrefix("a", mapMake("class", "r_a_undecorated", "href", "#" + HTMLConvertStringToAnchorID(title), "onclick", onclick_javascript))); - navbar.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_navbar_button_container", "style", "width:" + each_width[i] + "%;"))); - - //Vertical separator: - if (first) - first = false; - else if (!__setting_gray_navbar) - navbar.append(HTMLGenerateDivOfClass("", "r_navbar_line_separator")); - - string text_div = HTMLGenerateDivOfClass(title, "r_navbar_text"); - if (true) - { - //Vertical centring with divs: - //Which is to... tell the browser to act like a table. - //Sorry. - navbar.append(HTMLGenerateTagPrefix("div", mapMake("style", "padding-left:1px;padding-right:1px;margin-left:auto;margin-right:auto;display:table;height:100%;"))); - navbar.append(HTMLGenerateTagWrap("div", text_div, mapMake("style", "display:table-cell;vertical-align:middle;"))); - navbar.append(""); - } - navbar.append(""); - navbar.append(""); - } - } - navbar.append(""); - navbar.append(""); - return navbar; -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sections/Tests.ash b/Source/relay/TourGuide/Sections/Tests.ash deleted file mode 100644 index 9c0ea15b..00000000 --- a/Source/relay/TourGuide/Sections/Tests.ash +++ /dev/null @@ -1,215 +0,0 @@ -import "relay/TourGuide/Support/Banishers.ash"; - -void generateImageTest(Checklist [int] checklists) -{ - ChecklistEntry [int] image_test_entries; - KOLImagesInit(); - foreach i in __kol_images - { - KOLImage image = __kol_images[i]; - image_test_entries.listAppend(ChecklistEntryMake(i, "", ChecklistSubentryMake(i))); - - } - checklists.listAppend(ChecklistMake("All images", image_test_entries)); -} - -void generateStateTest(Checklist [int] checklists) -{ - ChecklistEntry [int] misc_state_entries; - ChecklistEntry [int] quest_state_entries; - - - string [int] state_description; - string [int] string_description; - string [int] int_description; - foreach key in __misc_state - { - state_description.listAppend(key + " = " + __misc_state[key]); - } - foreach key in __misc_state_string - { - string_description.listAppend(key + " = \"" + __misc_state_string[key] + "\""); - } - foreach key in __misc_state_int - { - int_description.listAppend(key + " = " + __misc_state_int[key]); - } - - misc_state_entries.listAppend(ChecklistEntryMake("__item milky potion", "", ChecklistSubentryMake("Boolean", "", state_description.listJoinComponents("|")))); - misc_state_entries.listAppend(ChecklistEntryMake("__item ghost thread", "", ChecklistSubentryMake("String", "", string_description.listJoinComponents("|")))); - misc_state_entries.listAppend(ChecklistEntryMake("__item handful of numbers", "", ChecklistSubentryMake("Int", "", int_description.listJoinComponents("|")))); - - boolean [string] names_already_seen; - - foreach key in __quest_state - { - if (names_already_seen[key]) - continue; - names_already_seen[key] = true; - - QuestState quest_state = __quest_state[key]; - - string [int] full_name_list; - full_name_list.listAppend(key); - - //Look for others: - foreach key2 in __quest_state - { - if (key == key2) - continue; - QuestState quest_state_2 = __quest_state[key2]; - - if (QuestStateEquals(quest_state, quest_state_2)) - { - full_name_list.listAppend(key2); - names_already_seen[key2] = true; - } - } - - ChecklistSubentry subentry; - - subentry.header = listJoinComponents(full_name_list, " / " ); - if (quest_state.quest_name != "") - subentry.entries.listAppend("Internal name: " + quest_state.quest_name); - - subentry.entries.listAppend("Startable: " + quest_state.startable); - subentry.entries.listAppend("Started: " + quest_state.started); - subentry.entries.listAppend("In progress: " + quest_state.in_progress); - subentry.entries.listAppend("Finished: " + quest_state.finished); - subentry.entries.listAppend("Mafia's internal step: " + quest_state.mafia_internal_step); - - foreach key2 in quest_state.state_boolean - { - subentry.entries.listAppend(key2 + ": " + quest_state.state_boolean[key2]); - } - foreach key2 in quest_state.state_string - { - subentry.entries.listAppend(key2 + ": \"" + quest_state.state_string[key2] + "\""); - } - foreach key2 in quest_state.state_int - { - subentry.entries.listAppend(key2 + ": " + quest_state.state_int[key2]); - } - - quest_state_entries.listAppend(ChecklistEntryMake(quest_state.image_name, "", subentry)); - } - - - checklists.listAppend(ChecklistMake("Misc. States", misc_state_entries)); - checklists.listAppend(ChecklistMake("Quest States", quest_state_entries)); -} - -void generateCounterTest(Checklist [int] checklists) -{ - ChecklistEntry [int] checklist_entries; - - ChecklistEntry main_entry; - main_entry.image_lookup_name = "__item sinister ancient tablet"; - - string [int] counter_names = CounterGetAllNames(); - - if (counter_names.count() == 0) - return; - - foreach key in counter_names - { - string counter_name = counter_names[key]; - Counter c = CounterLookup(counter_name); - - string [int] description; - description.listAppend(c.CounterDescription()); - - main_entry.subentries.listAppend(ChecklistSubentryMake(c.name, "", description)); - } - - checklist_entries.listAppend(main_entry); - - - checklists.listAppend(ChecklistMake("Counters", checklist_entries)); -} - -buffer generateMajorMinorText(string [string][int] entries) -{ - buffer description; - foreach zone in entries - { - if (description.length() > 0) - description.append("|"); - description.append(zone); - description.append(":|*"); - description.append(entries[zone].listJoinComponents("|*")); - } - return description; -} - -void generateSelfDataTest(Checklist [int] checklists) -{ - ChecklistEntry [int] checklist_entries; - //Show missing locations in locationAvailable and missing locations from clickables. - - string [string][int] missing_available_locations; - string [string][int] missing_location_links_description; - - foreach l in $locations[] - { - Error unable_to_find_location; - l.locationAvailable(unable_to_find_location); - - if (unable_to_find_location.was_error) - { - if (!(missing_available_locations contains l.zone)) - missing_available_locations[l.zone] = listMakeBlankString(); - missing_available_locations[l.zone].listAppend(l.to_string()); - } - - Error unable_to_find_clickable; - l.getClickableURLForLocation(unable_to_find_clickable); - if (unable_to_find_clickable.was_error) - { - if (!(missing_location_links_description contains l.zone)) - missing_location_links_description[l.zone] = listMakeBlankString(); - missing_location_links_description[l.zone].listAppend("lookup_map[\"" + l.to_string() + "\"] = \"REPLACEME\";"); - } - } - if (missing_available_locations.count() > 0) - { - buffer description = generateMajorMinorText(missing_available_locations); - checklist_entries.listAppend(ChecklistEntryMake("__item cobb's knob map", "", ChecklistSubentryMake("Missing locationAvailable() locations", "", description))); - } - - - if (missing_location_links_description.count() > 0) - { - buffer description = generateMajorMinorText(missing_location_links_description); - checklist_entries.listAppend(ChecklistEntryMake("__item reflection of a map", "", ChecklistSubentryMake("Missing getClickableURLForLocation() locations", "", description))); - } - checklists.listAppend(ChecklistMake("Self data tests", checklist_entries)); -} - - -void generateBanishTest(Checklist [int] checklists) -{ - ChecklistEntry [int] checklist_entries; - - string [int][int] banish_table; - banish_table.listAppend(listMake("Monster", "Source", "On turn", "Turn length", "Reset conditions")); - foreach key, b in BanishesActive() - { - banish_table.listAppend(listMake(b.banished_monster, b.banish_source, b.turn_banished, b.banish_turn_length, b.custom_reset_conditions)); - } - if (banish_table.count() > 1) - { - checklist_entries.listAppend(ChecklistEntryMake("__item ice house", "", ChecklistSubentryMake("Banishes", "", HTMLGenerateSimpleTableLines(banish_table)))); - } - - checklists.listAppend(ChecklistMake("Banishes", checklist_entries)); -} - -void generateAllTests(Checklist [int] checklists) -{ - generateImageTest(checklists); - generateStateTest(checklists); - generateCounterTest(checklists); - generateBanishTest(checklists); - generateSelfDataTest(checklists); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sections/User Preferences.ash b/Source/relay/TourGuide/Sections/User Preferences.ash deleted file mode 100644 index e3c8bc71..00000000 --- a/Source/relay/TourGuide/Sections/User Preferences.ash +++ /dev/null @@ -1,87 +0,0 @@ -string [string] __user_preferences_private; -boolean __read_user_preferences_initially = false; - - - -//File implementation: -//Preferred, but not chosen in case this somehow triggers an HD read too often: -/*string __user_preferences_file_name = "data/relay_ezandora_guide_preferences_" + my_id() + ".txt"; -void readUserPreferences() -{ - __read_user_preferences_initially = true; - file_to_map(__user_preferences_file_name, __user_preferences_private); -} - -void writeUserPreferences() -{ - map_to_file(__user_preferences_private, __user_preferences_file_name); -}*/ - - -string __user_preferences_property_name = "ezandora_guide_preferences"; -void readUserPreferences() -{ - string [string] blank; - __user_preferences_private = blank; - string guide_value = get_property(__user_preferences_property_name); - foreach key, pair in guide_value.split_string_alternate(";") - { - string [int] split = pair.split_string_alternate("="); - if (split.count() != 2) - continue; - __user_preferences_private[split[0]] = split[1]; - } - __read_user_preferences_initially = true; -} - -void writeUserPreferences() -{ - if (!__read_user_preferences_initially) - readUserPreferences(); - buffer output_value; - boolean first = true; - foreach key, value in __user_preferences_private - { - if (!first) - output_value.append(";"); - else - first = false; - output_value.append(key); - output_value.append("="); - output_value.append(value); - } - set_property(__user_preferences_property_name, output_value); -} - - -string PreferenceGet(string name) -{ - if (!__read_user_preferences_initially) - readUserPreferences(); - - return __user_preferences_private[name]; -} - -boolean PreferenceGetBoolean(string name) -{ - return PreferenceGet(name).to_boolean(); -} - -void PreferenceSet(string name, string value) -{ - if (!__read_user_preferences_initially) - readUserPreferences(); - __user_preferences_private[name] = value; - writeUserPreferences(); -} - - -void processSetUserPreferences(string [string] form_fields) -{ - foreach key, value in form_fields - { - if (key == "set user preferences") - continue; - PreferenceSet(key, value); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets.ash b/Source/relay/TourGuide/Sets.ash deleted file mode 100644 index 7b31eca1..00000000 --- a/Source/relay/TourGuide/Sets.ash +++ /dev/null @@ -1,49 +0,0 @@ - -import "relay/TourGuide/Support/Checklist.ash"; -import "relay/TourGuide/Sets/Sets import.ash"; - -void SetsInit() -{ - SCountersInit(); - QHitsInit(); -} - - -void SetsGenerateResources(ChecklistEntry [int] resource_entries) -{ - SFamiliarsGenerateResource(resource_entries); - SSkillsGenerateResource(resource_entries); - SMiscItemsGenerateResource(resource_entries); - SCopiedMonstersGenerateResource(resource_entries); - SPulveriseGenerateResource(resource_entries); - SCountersGenerateResource(resource_entries); - SFaxGenerateResource(resource_entries); - SClassesGenerateResource(resource_entries); - SEquipmentGenerateResource(resource_entries); - SCalculateUniverseGenerateResource(resource_entries); - SEventsGenerateResource(resource_entries); -} - -void SetsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - SFamiliarsGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SDispensaryGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SCouncilGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SCopiedMonstersGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SAftercoreGenerateTasks(task_entries, optional_task_entries, future_task_entries); - QHitsGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SDailyDungeonGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SCountersGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SBountyHunterHunterGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SOldLevel9GenerateTasks(task_entries, optional_task_entries, future_task_entries); - SFaxGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SDungeonsOfDoomGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SOlfactionGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SHolidayGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SRemindersGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SEventsGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SClassesGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SEquipmentGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SMiscItemsGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SPVPGenerateTasks(task_entries, optional_task_entries, future_task_entries); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets/Active Banishes.ash b/Source/relay/TourGuide/Sets/Active Banishes.ash deleted file mode 100644 index 82dac9ac..00000000 --- a/Source/relay/TourGuide/Sets/Active Banishes.ash +++ /dev/null @@ -1,206 +0,0 @@ -// Setting a static converter of phyla to monsters for (mostly bad) reasons. - -static -{ - string [phylum] __phylum_to_monster; - // This is my best attempt to associate a funny monster with each phylum. Some are better than others. - __phylum_to_monster[$phylum[beast]] = "__monster "+$monster[fluffy bunny].to_string().to_lower_case(); - __phylum_to_monster[$phylum[bug]] = "__monster "+$monster[Spant soldier].to_string().to_lower_case(); - __phylum_to_monster[$phylum[constellation]] = "__monster "+$monster[Astrologer of Shub-Jigguwatt].to_string().to_lower_case(); - __phylum_to_monster[$phylum[construct]] = "__monster "+$monster[Luggage-Handling Trainbot].to_string().to_lower_case(); - __phylum_to_monster[$phylum[demon]] = "__monster "+$monster[W imp].to_string().to_lower_case(); - __phylum_to_monster[$phylum[dude]] = "__monster "+$monster[dirty thieving brigand].to_string().to_lower_case(); - __phylum_to_monster[$phylum[elemental]] = "__monster "+$monster[BASIC Elemental].to_string().to_lower_case(); - __phylum_to_monster[$phylum[elf]] = "__monster "+$monster[wire-crossin' elf].to_string().to_lower_case(); - __phylum_to_monster[$phylum[fish]] = "__monster "+$monster[sea cowboy].to_string().to_lower_case(); - __phylum_to_monster[$phylum[goblin]] = "__monster "+$monster[Knob Goblin Very Mad Scientist].to_string().to_lower_case(); - __phylum_to_monster[$phylum[hippy]] = "__monster "+$monster[Neil].to_string().to_lower_case(); - __phylum_to_monster[$phylum[humanoid]] = "__monster "+$monster[yeti].to_string().to_lower_case(); - __phylum_to_monster[$phylum[horror]] = "__monster "+$monster[Guy Made Of Bees].to_string().to_lower_case(); - __phylum_to_monster[$phylum[mer-kin]] = "__monster "+$monster[Ringogeorge, the Bladeswitcher].to_string().to_lower_case(); - __phylum_to_monster[$phylum[orc]] = "__monster "+$monster[Danglin' Chad].to_string().to_lower_case(); - __phylum_to_monster[$phylum[penguin]] = "__monster "+$monster[Mob Penguin Arsonist].to_string().to_lower_case(); - __phylum_to_monster[$phylum[pirate]] = "__monster "+$monster[grungy pirate].to_string().to_lower_case(); - __phylum_to_monster[$phylum[plant]] = "__monster "+$monster[man-eating plant].to_string().to_lower_case(); - __phylum_to_monster[$phylum[slime]] = "__monster "+$monster[fan slime].to_string().to_lower_case(); - __phylum_to_monster[$phylum[undead]] = "__monster "+$monster[the ghost of Phil Bunion].to_string().to_lower_case(); - __phylum_to_monster[$phylum[weird]] = "__monster "+$monster[loaf of Bread of Wonder].to_string().to_lower_case(); -} - -// In order to make the for loop a bit nicer, generate the string in a helper function. -string DescribeThisBanish(Banish b) { - - string banishedMon = b.banished_monster.to_string(); - string source = b.banish_source; - int banishTurn = b.turn_banished; - int banishLength = b.banish_turn_length; - string banishLengthString = ""; - - int turnsOfBanishLeft = BanishTurnsLeft(b); - - if (source == "Bowl a Curveball") { - turnsOfBanishLeft = get_property_int("cosmicBowlingBallReturnCombats"); - } - - if (source == "Roar like a Lion") { - turnsOfBanishLeft = have_effect($effect[Hear Me Roar]); - } - - if (turnsOfBanishLeft <= 0) { - return ""; - } - - if (turnsOfBanishLeft >= 300) banishLengthString = " until rollover."; - if (turnsOfBanishLeft <= 300) banishLengthString = ` for {pluralise(turnsOfBanishLeft,"more turn","more turns")}.`; - if (source == "ice house") banishLengthString = " forever."; - - string textReturn = ""+banishedMon+", via "+source+banishLengthString+"
|*"; - - return textReturn; - -} - -// Due to the world being the way it is, need to enumerate this twice to handle both record types. -string DescribeThisBanish(BanishedPhylum b) { - - string banishedPhy = b.banished_phylum.to_string().to_upper_case(); - string source = b.banish_source; - int banishTurn = b.turn_banished; - int banishLength = b.banish_turn_length; - string banishLengthString = ""; - - - if (b.custom_reset_conditions == "rollover") { - banishLength = 1234567; - } - - int turnsSinceBanish = my_turncount() - banishTurn; - int turnsOfBanishLeft = banishLength - turnsSinceBanish; - - if (turnsOfBanishLeft < 0) { - return ""; - } - - if (turnsOfBanishLeft >= 300) banishLengthString = " until rollover."; - if (turnsOfBanishLeft <= 300) banishLengthString = ` for {pluralise(turnsOfBanishLeft,"more turn","more turns")}!`; - - // If a new source is introduced, just add "by "+source" as in the above monster example. - - string textReturn = "The entire "+banishedPhy+" phylum is banished"+banishLengthString; - - return textReturn; - -} - -// I think there are better ways to do this. However, I am tired. So, I'm instead doing... whatever the fuck this is, I guess. -RegisterResourceGenerationFunction("ActiveBanishesList"); -void ActiveBanishesList(ChecklistEntry [int] resource_entries) -{ - // Read in the banisher preferences - string banishedMonstersUnparsed = get_property("banishedMonsters"); - string banishedPhylumUnparsed = get_property("banishedPhyla"); - - Banish [int] monsterResult = BanishesActive(); - BanishedPhylum [int] phylaResult; - - // Save the banished monsters to compare later for snapper/eagle checks, with snapper phylum. - monster [int] banishedMonsterList; - phylum snapperPhylum = get_property("redSnapperPhylum").to_phylum(); - - // Banishes are in the format "thing:source:###" where # is turncount of banished. This splits it. - string [int] banishedMonstersParsed = banishedMonstersUnparsed.split_string(":"); - string [int] banishedPhylumParsed = banishedPhylumUnparsed.split_string(":"); - - // ... then this reads it. - foreach key, banish in monsterResult { - // Add the banished monster to the banishedMonsterList - banishedMonsterList.listAppend(banish.banished_monster); - } - - // Now that you've addressed "normal" banishes, address the phylum banish. - - foreach key, parsedString in banishedPhylumParsed { - if (parsedString.length() == 0) - continue; // This bypasses if there is no result - if (key % 3 != 0) - continue; // This bypasses when you aren't at a divisible-by-three key. - - BanishedPhylum b; - b.banished_phylum = banishedPhylumParsed[key + 0].to_phylum(); - b.banish_source = banishedPhylumParsed[key + 1]; - b.turn_banished = banishedPhylumParsed[key + 2].to_int(); - b.banish_turn_length = 0; - if (__banish_source_length contains b.banish_source.to_lower_case()) - b.banish_turn_length = __banish_source_length[b.banish_source.to_lower_case()]; - - phylaResult.listAppend(b); - } - - // Now, make a resource entry for this whole thing - ChecklistSubentry [int] subentries; - string name; - string description; - string monsterIcon; - string phylaSubtitle; - string monsterSubtitle; - string monsterSymbol; // 🠞 for normal monster, 🞮 for un-banished monster - string banishDescribed; - phylum phylumBanished = $phylum[none]; - int monsterCount = 0; - - if (phylaResult.count() > 0) { - name = "Current Phyla Banished"; - - int screechCharge = get_property_int("screechCombats"); - if (screechCharge == 0) phylaSubtitle = "can clear with your patriotic eagle"; - if (screechCharge > 0) phylaSubtitle = `spend {pluralise(screechCharge,"turn/run","turns/runs")} with your eagle to cast screech again`; - - foreach key, banish in phylaResult { - banishDescribed = DescribeThisBanish(banish); - if (banishDescribed != "") { - description += "|*"+banishDescribed+"
|*"; - monsterIcon = __phylum_to_monster[banish.banished_phylum]; - phylumBanished = banish.banished_phylum; - } - } - subentries.listAppend(ChecklistSubentryMake(name,phylaSubtitle,description)); - } - - if (monsterResult.length() > 0) { - description = ""; - monsterSubtitle = ""; - - // If your snapper is active, show the snapper phylum. - phylum snapperTarget = my_familiar() == lookupFamiliar("Red Nosed Snapper") ? get_property("redSnapperPhylum").to_phylum() : $phylum[none]; - - if (snapperTarget != $phylum[none]) { - monsterSubtitle = `your snapper is un-banishing {snapperTarget.to_string()} targets, marked with 🞮`; - } - - foreach key, banish in monsterResult { - banishDescribed = DescribeThisBanish(banish); - monsterSymbol = "🠞 "; - if (banishDescribed != "") { - // add an icon for snapper unbanishing the monster - if (banish.banished_monster.phylum == snapperTarget) { - monsterSymbol = `🞮 `; - } - description += "|*"+monsterSymbol+banishDescribed; - monsterIcon = "__monster "+banish.banished_monster.to_string().to_lower_case(); - monsterCount += 1; - } - } - name = `{pluralise(monsterCount,"monster banished", "monsters banished")}`; - subentries.listAppend(ChecklistSubentryMake(name,monsterSubtitle,description)); - - } - - if (subentries.count() > 0) { - - // Want this atop resources for testing. Also, maybe just want it there period? - int priority = -69; - ChecklistEntry entry = ChecklistEntryMake(monsterIcon, "", subentries, priority); - entry.tags.id = "Active banishes"; - resource_entries.listAppend(entry); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets/Aftercore.ash b/Source/relay/TourGuide/Sets/Aftercore.ash deleted file mode 100644 index e2f5b2a4..00000000 --- a/Source/relay/TourGuide/Sets/Aftercore.ash +++ /dev/null @@ -1,310 +0,0 @@ -import "relay/TourGuide/Support/Campground.ash" - -void SAftercoreThingsToDoGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //To implement: - //The Sea - rescuing mom, √temple boss if they're missing anything, that one skater quest, whatever else is there - //The suburbs of dis? Is this detectable? - //Farming four shore inc. trip scrip for ascension. - //√Space elves. - //telescope upgrades - telescopeUpgrades (needs basement level check) - //dungeons? slime tube, hobopolis, dreadsylvania, library, items and skills and such - //hobo codes? (no support) - //demon names - //el vibrato island - familiar, mostly, plus items? (bad moon check) - //agua de vida memories quest? - //artist quest? - //going postal quest - //bounty hunting - //starting SBB quests / UMD in inventory to use - //examine http://kol.coldfront.net/thekolwiki/index.php/Quest_Spoilers - //jung jar items - //dwarven factory - - Record AftercoreOption - { - string header; - string url; - string [int] description; - }; - AftercoreOption AftercoreOptionMake(string header, string url, string [int] description) - { - AftercoreOption task; - task.header = header; - task.url = url; - task.description = description; - return task; - } - void listAppend(AftercoreOption [int] list, AftercoreOption entry) - { - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; - } - - - AftercoreOption [int] options; - - if (knoll_available() && !QuestState("questM03Bugbear").started) - { - options.listAppend(AftercoreOptionMake("Felonia quest", "place.php?whichplace=knoll_friendly", listMake("speak to Mayor Zapruder", "rewards once/ascension mushroom fermenting solution"))); - } - - if (!QuestState("questG04Nemesis").started) - { - string [int] things_gives; - things_gives.listAppend("instant karma"); - if (my_class() == $class[disco bandit]) - things_gives.listAppend("rave skills"); - options.listAppend(AftercoreOptionMake("Nemesis quest", "guild.php", listMake("Rewards " + things_gives.listJoinComponents(", ", "and")))); - } - - if (!QuestState("questF04Elves").started && $effect[transpondent].have_effect() == 0) - { - string url; - string first_task; - if ($item[transporter transponder].available_amount() > 0) - { - url = "inventory.php?ftext=transporter+transponder"; - first_task = "use transporter transponder"; - } - else - { - url = "mall.php"; - first_task = "buy and use transporter transponder"; - } - options.listAppend(AftercoreOptionMake("Repair the Elves' Shield Generator", url, listMake(first_task, "rewards 200 lunar isotopes, and space store access"))); - } - - - if (false) //FIXME disabled for now - we don't have suggestions for every path, and this may be too much information to list? need to decide - { - //Grimstone: - string [item] grimstone_paths; - grimstone_paths[$item[silver cow creamer]] = "stepmother"; - grimstone_paths[$item[wolf whistle]] = "wolf"; - grimstone_paths[$item[witch's bra]] = "witch"; - if (__campground[$item[spinning wheel]] == 0) - grimstone_paths[$item[spinning wheel]] = "gnome"; - grimstone_paths[$item[hare pin]] = "hare"; - - string [int] relevant_grimstone_paths; - item [int] relevant_rewards; - foreach it in grimstone_paths - { - if (haveAtLeastXOfItemEverywhere(it, 1)) - continue; - relevant_grimstone_paths.listAppend(grimstone_paths[it]); - relevant_rewards.listAppend(it); - } - if (relevant_grimstone_paths.count() > 0) - { - string path_string = "path available"; - if (relevant_grimstone_paths.count() > 1) - path_string = "paths available"; - - options.listAppend(AftercoreOptionMake("grimstone mask quests", "", listMake(relevant_grimstone_paths.listJoinComponents(", ", "and") + " " + path_string, "Rewards " + relevant_rewards.listJoinComponents(", ", "or")))); - } - } - - if (get_property("merkinQuestPath") == "none" || get_property("merkinQuestPath").length() == 0) - { - //Do they need to complete that quest? Let's find out. - item [class][int] class_temple_items; - boolean [item] loathing_craftable_items = $items[belt of loathing,goggles of loathing,jeans of loathing,scepter of loathing,stick-knife of loathing,treads of loathing]; - class_temple_items[$class[seal clubber]] = listMake($item[Cold Stone of Hatred], $item[Ass-Stompers of Violence]); - class_temple_items[$class[turtle tamer]] = listMake($item[Girdle of Hatred], $item[Brand of Violence]); - class_temple_items[$class[pastamancer]] = listMake($item[Staff of Simmering Hatred], $item[Novelty Belt Buckle of Violence]); - class_temple_items[$class[sauceror]] = listMake($item[Pantaloons of Hatred], $item[Lens of Violence]); - class_temple_items[$class[disco bandit]] = listMake($item[Fuzzy Slippers of Hatred], $item[Pigsticker of Violence]); - class_temple_items[$class[accordion thief]] = listMake($item[Lens of Hatred], $item[Jodhpurs of Violence]); - - //For our class, determine what items we're missing: - item [int] our_class_items = class_temple_items[my_class()]; - int [item] total_amount_of_item_wanted; - boolean [item] want_item_for_crafting_loathing; - foreach key, it in our_class_items - { - total_amount_of_item_wanted[it] = 1; - } - foreach loathing_piece in loathing_craftable_items - { - if (haveAtLeastXOfItemEverywhere(loathing_piece, 1)) - continue; - int [item] components = loathing_piece.get_ingredients_fast(); - foreach component in components - { - if (total_amount_of_item_wanted contains component) //if this component is part of our class components - { - total_amount_of_item_wanted[component] += 1; - want_item_for_crafting_loathing[component] = true; - } - } - } - string [int] description_items; - foreach it, amount in total_amount_of_item_wanted - { - int missing = amount - it.item_amount_almost_everywhere(); - if (missing <= 0) - continue; - string line = "a " + it; - if (it.to_string().contains_text("Violence")) - line += " (gladiator path)"; - else - line += " (scholar path)"; - if (want_item_for_crafting_loathing[it]) - { - line += " for loathing gear piece"; - if (missing >= 2) - line += "/to own"; - } - description_items.listAppend(line); - } - if (description_items.count() > 0) - options.listAppend(AftercoreOptionMake("mer-kin temple in the sea", "", listMake("can find " + description_items.listJoinComponents(", ", "or")))); - } - if (__misc_state["stench airport available"] && !get_property_ascension("lastWartDinseyDefeated")) - { - item dinsey_item; - if (my_class() == $class[seal clubber]) - dinsey_item = $item[Dinsey's oculus]; - else if (my_class() == $class[turtle tamer]) - dinsey_item = $item[Dinsey's radar dish]; - else if (my_class() == $class[pastamancer]) - dinsey_item = $item[Dinsey's pizza cutter]; - else if (my_class() == $class[sauceror]) - dinsey_item = $item[Dinsey's brain]; - else if (my_class() == $class[disco bandit]) - dinsey_item = $item[Dinsey's pants]; - else if (my_class() == $class[accordion thief]) - dinsey_item = $item[Dinsey's glove]; - - if (dinsey_item != $item[none] && !haveAtLeastXOfItemEverywhere(dinsey_item, 1)) - { - location [item] keycards; - - keycards[$item[keycard α]] = $location[Barf Mountain]; - keycards[$item[keycard β]] = $location[Pirates of the Garbage Barges]; - keycards[$item[keycard γ]] = $location[The Toxic Teacups]; - keycards[$item[keycard δ]] = $location[Uncle Gator's Country Fun-Time Liquid Waste Sluice]; - location [int] missing_locations; - item [int] missing_keycards; - foreach it, l in keycards - { - if (it.available_amount() == 0) - { - missing_keycards.listAppend(it); - missing_locations.listAppend(l); - } - - } - if (missing_keycards.count() > 0) - { - options.listAppend(AftercoreOptionMake("defeat Wart Dinsey", "", listMake("Find keycards in " + missing_locations.listJoinComponents(", ", "and")))); - } - } - } - - if (options.count() > 0) - { - string [int] description; - string url = ""; - foreach key, option in options - { - option.header = option.header.capitaliseFirstLetter(); - foreach key in option.description - { - option.description[key] = option.description[key].capitaliseFirstLetter() + "."; - } - if (url.length() == 0) - url = option.url; - description.listAppend(option.header + HTMLGenerateIndentedText(option.description.listJoinComponents("
"))); - } - optional_task_entries.listAppend(ChecklistEntryMake("__effect confused", url, ChecklistSubentryMake("Try an optional quest", "", description), 8).ChecklistEntrySetIDTag("Aftercore task suggestions")); - } -} - -void SAftercoreGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__misc_state["in aftercore"]) - return; - //Campground items: - if (__campground[$item[clockwork maid]] == 0) - { - string url = "mall.php?pudnuggler=%22clockwork+maid"; - optional_task_entries.listAppend(ChecklistEntryMake("__item sprocket", url, ChecklistSubentryMake("Install a clockwork maid", "", listMake("+8 adventures/day.", "Buy from mall."))).ChecklistEntrySetIDTag("Aftercore task clockwork maid")); - } - if (__campground[$item[pagoda plans]] == 0 && $location[Pandamonium Slums].locationAvailable()) - { - string url; - string [int] details; - details.listAppend("+3 adventures/day."); - - if ($item[hey deze nuts].item_amount() == 0) - { - if ($item[hey deze map].item_amount() == 0) - { - url = "pandamonium.php"; - details.listAppend("Adventure in Pandamonium Slums for Hey Deze Map. (25% superlikely)"); - } - else - { - string [int] things_to_do; - string [int] things_to_buy; - if ($item[heavy metal sonata].item_amount() == 0) - things_to_buy.listAppend("heavy metal sonata"); - if ($item[heavy metal thunderrr guitarrr].item_amount() == 0) - things_to_buy.listAppend("heavy metal thunderrr guitarrr"); - if ($item[guitar pick].item_amount() == 0) - things_to_buy.listAppend("guitar pick"); - if (things_to_buy.count() > 0) - things_to_do.listAppend("buy " + things_to_buy.listJoinComponents(", ", "and") + " in mall, "); - things_to_do.listAppend("use hey deze map"); - details.listAppend(things_to_do.listJoinComponents("", "then").capitaliseFirstLetter() + "."); - } - } - if ($item[pagoda plans].item_amount() == 0) - { - if ($item[Elf Farm Raffle ticket].item_amount() == 0) - { - details.listAppend("Buy a Elf Farm Raffle ticket from the mall."); - } - else - { - if (url.length() == 0) - url = "inventory.php?which=3"; - if (in_bad_moon()) //Does bad moon aftercore require a clover? - { - details.listAppend("Use Elf Farm Raffle ticket."); - } - else - { - details.listAppend("Acquire ten-leaf clover, then use Elf Farm Raffle ticket."); - } - } - } - if ($item[ketchup hound].item_amount() == 0) - { - if (url.length() == 0) - url = "mall.php"; - details.listAppend("Buy a ketchup hound from the mall."); - } - if ($item[ketchup hound].item_amount() > 0 && $item[hey deze nuts].item_amount() > 0 && $item[pagoda plans].item_amount() > 0) - { - if (url.length() == 0) - url = "inventory.php?ftext=ketchup+hound"; - details.listAppend("Use a ketchup hound to install pagoda."); - } - optional_task_entries.listAppend(ChecklistEntryMake("__item pagoda plans", url, ChecklistSubentryMake("Install a pagoda", "", details)).ChecklistEntrySetIDTag("Aftercore task pagoda")); - } - - if (knoll_available() && !have_mushroom_plot() && get_property("plantingScript") != "") - { - //They can plant a mushroom plot, and they have a planting script. But they haven't yet, so let's suggest it: - optional_task_entries.listAppend(ChecklistEntryMake("__item knob mushroom", "knoll_mushrooms.php", ChecklistSubentryMake("Plant a mushroom plot", "", "Degrassi Knoll")).ChecklistEntrySetIDTag("Aftercore task mushroom plot")); - } - - - SAftercoreThingsToDoGenerateTasks(task_entries, optional_task_entries, future_task_entries); -} diff --git a/Source/relay/TourGuide/Sets/Area Unlocks.ash b/Source/relay/TourGuide/Sets/Area Unlocks.ash deleted file mode 100644 index 0e730e58..00000000 --- a/Source/relay/TourGuide/Sets/Area Unlocks.ash +++ /dev/null @@ -1,187 +0,0 @@ -RegisterTaskGenerationFunction("SAreaUnlocksGenerateTasks"); -void SAreaUnlocksGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__misc_state["desert beach available"] && __misc_state["in run"] && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_SEA) - { - string url; - ChecklistSubentry subentry; - boolean optional = false; - subentry.header = "Unlock desert beach"; - boolean [location] relevant_locations; - if (my_path().id == PATH_COMMUNITY_SERVICE) - { - subentry.header = "Optionally unlock desert beach"; - subentry.entries.listAppend("Not needed to finish path."); - optional = true; - } - if (my_path().id == PATH_NUCLEAR_AUTUMN) - { - subentry.entries.listAppend("Wait until level eleven, which will unlock it autumn-atically."); - } - else if (!knoll_available()) - { - relevant_locations[$location[the degrassi knoll garage]] = true; - string meatcar_line = "Build a bitchin' meatcar."; - if ($item[bitchin' meatcar].creatable_amount() > 0) - meatcar_line += "|*You have all the parts, build it!"; - else - { - item [int] missing_parts_list = missingComponentsToMakeItem($item[bitchin' meatcar]); - boolean [item] missing_parts = missing_parts_list.listInvert(); - - //Tires - 100% drop - Gnollish Tirejuggler in The Degrassi Knoll Garage - //empty meat tank, cog, spring, sprocket - Gnollish toolbox - Gnollish Gearhead in The Degrassi Knoll Garage - // - string [int] meatcar_modifiers; - if (missing_parts[$item[empty meat tank]] || missing_parts[$item[cog]] || missing_parts[$item[spring]] || missing_parts[$item[sprocket]]) - { - meatcar_modifiers.listAppend("+34% item"); - meatcar_modifiers.listAppend("olfact gnollish gearhead"); - } - - - meatcar_modifiers.listAppend("banish guard bugbear"); - - if (meatcar_modifiers.count() > 0) - meatcar_line += "|*" + ChecklistGenerateModifierSpan(meatcar_modifiers); - - meatcar_line += "|*Parts needed: " + missing_parts_list.listJoinComponents(", ", "and") + "."; - if (missing_parts[$item[tires]] || missing_parts[$item[empty meat tank]] || missing_parts[$item[cog]] || missing_parts[$item[spring]] || missing_parts[$item[sprocket]]) - meatcar_line += " (found in the degrassi knoll garage?)"; - } - subentry.entries.listAppend(meatcar_line); - - if (my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) - subentry.entries.listAppend("Or buy a desert bus pass. (5000 meat)"); - if ($item[pumpkin].available_amount() > 0) - subentry.entries.listAppend("Or build a pumpkin carriage."); - if ($items[can of Brütalbräu,can of Drooling Monk,can of Impetuous Scofflaw,fancy tin beer can].available_amount() > 0) - subentry.entries.listAppend("Or build a tin lizzie."); - url = "place.php?whichplace=knoll_hostile"; - } - else - { - url = "shop.php?whichshop=gnoll"; - int meatcar_price = $item[spring].npc_price() + $item[sprocket].npc_price() + $item[cog].npc_price() + $item[empty meat tank].npc_price() + 100 + $item[tires].npc_price() + $item[sweet rims].npc_price() + $item[spring].npc_price(); - subentry.entries.listAppend("Build a bitchin' meatcar. (" + meatcar_price + " meat)"); - } - - ChecklistEntry entry = ChecklistEntryMake("__item bitchin' meatcar", url, subentry, relevant_locations); - entry.tags.id = "Area unlock desert beach"; - if (optional) - optional_task_entries.listAppend(entry); - else - task_entries.listAppend(entry); - } - else if (!__misc_state["mysterious island available"] && __misc_state["in run"]) - { - ChecklistSubentry subentry; - subentry.header = "Unlock mysterious island"; - if (my_path().id == PATH_SEA) return; - if (my_path().id == PATH_COMMUNITY_SERVICE) - { - subentry.header += "?"; - subentry.entries.listAppend("Or not...?"); - } - - string url; - boolean suggest_hippy_alternative = false; - if (my_path().id == PATH_NUCLEAR_AUTUMN) - { - suggest_hippy_alternative = true; - } - - - if (!(my_path().id == PATH_NUCLEAR_AUTUMN && in_hardcore())) - { - if (__misc_state["desert beach available"]) - url = "place.php?whichplace=desertbeach"; - int scrip_number = $item[Shore Inc. Ship Trip Scrip].available_amount(); - int trips_needed = MAX(0, 3 - scrip_number); - - if ($item[dinghy plans].available_amount() > 0) - { - if ($item[dingy planks].available_amount() > 0) - { - url = "inventory.php?ftext=dinghy+plans"; - subentry.entries.listAppend("Use dinghy plans."); - } - else - { - if (my_path().id == PATH_NUCLEAR_AUTUMN) - { - subentry.entries.listAppend("Pull dingy planks, then build dinghy dinghy."); - } - else - { - url = "shop.php?whichshop=generalstore"; - subentry.entries.listAppend("Buy dingy planks, then build dinghy dinghy."); - } - } - - } - else if (trips_needed > 0) - { - int trip_adventure_cost = 3; - int trip_meat_cost = 500; - if (my_path().id == PATH_WAY_OF_THE_SURPRISING_FIST) - { - trip_adventure_cost = 5; - trip_meat_cost = 5; - } - string line_string = "Shore, " + (trip_adventure_cost * trips_needed) + " adventures"; - if (!__misc_state["desert beach available"]) - line_string += ", once the desert beach is unlocked"; - line_string += "."; - int meat_needed = trip_meat_cost * trips_needed; - if (my_meat() < meat_needed) - line_string += "|Need " + meat_needed + " meat for vacations, have " + my_meat() + "."; - subentry.entries.listAppend(line_string); - if ($item[skeleton].available_amount() > 0) - subentry.entries.listAppend("Skeletal skiff?"); - } - else - { - url = "shop.php?whichshop=shore"; - subentry.entries.listAppend("Redeem scrip at shore for dinghy plans."); - } - } - if (suggest_hippy_alternative) - { - string line_string = "Or try"; - if (my_path().id == PATH_NUCLEAR_AUTUMN && in_hardcore()) - line_string = "Try"; - line_string += " the hippy quest in the woods"; - if (my_basestat(my_primestat()) < 25) - line_string += ", once your mainstat reaches 25"; - else if (url == "") - url = "place.php?whichplace=woods"; - line_string += "."; - if (my_path().id == PATH_LOW_KEY_SUMMER) - line_string += " (need to go there anyway)"; - else if (my_path().id != PATH_NUCLEAR_AUTUMN) - line_string += " (probably slower?)"; - subentry.entries.listAppend(line_string); - } - if (my_path().id == PATH_NUCLEAR_AUTUMN && ($familiar[ms. puck man].familiar_is_usable() || $familiar[puck man].familiar_is_usable())) - { - string line = "Or build a yellow submarine."; - string [int] missing_components = $item[yellow submarine].missingComponentsToMakeItemInHumanReadableFormat(); - if (missing_components.count() > 0) - line += " Need " + missing_components.listJoinComponents(", ", "and") + "."; - subentry.entries.listAppend(line); - } - - if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && get_property("peteMotorbikeGasTank").length() == 0) - subentry.entries.listAppend("Possibly upgrade your motorcycle's gas tank. (extra-buoyant)"); - - - ChecklistEntry entry = ChecklistEntryMake("__item dingy dinghy", url, subentry, $locations[the shore\, inc. travel agency]); - entry.tags.id = "Area unlock mysterious island"; - if (my_path().id == PATH_COMMUNITY_SERVICE) - optional_task_entries.listAppend(entry); - else - task_entries.listAppend(entry); - - } -} diff --git a/Source/relay/TourGuide/Sets/Bounty Hunter Hunter.ash b/Source/relay/TourGuide/Sets/Bounty Hunter Hunter.ash deleted file mode 100644 index da030d72..00000000 --- a/Source/relay/TourGuide/Sets/Bounty Hunter Hunter.ash +++ /dev/null @@ -1,260 +0,0 @@ -Record BountyFileEntry -{ - string plural; - string difficulty; - string image; - int amount_needed; - monster bounty_monster; -}; - - -location [int] locationsForMonster(monster m) -{ - //hacky, slow, sorry - location [int] result; - if (m == $monster[none]) - return result; - foreach l in $locations[] - { - monster [int] location_monsters = l.get_monsters(); - foreach key in location_monsters - { - if (location_monsters[key] == m) - result.listAppend(l); - } - } - - return result; -} - -ChecklistSubentry SBHHGenerateHunt(string bounty_item_name, int amount_found, int amount_needed, monster target_monster, location [int] relevant_locations, StringHandle url) -{ - //FIXME update to use new bounty API once 16.3 is out for a sufficient time - ChecklistSubentry subentry; - - subentry.header = "Bounty hunt for " + bounty_item_name.HTMLEscapeString(); - - - - - //Look up monster location: - location [int] monster_locations = locationsForMonster(target_monster); - - relevant_locations.listAppendList(monster_locations); - - - boolean [location] skippable_ncs_locations = $locations[the stately pleasure dome, the poop deck, the spooky forest,The Haunted Gallery,tower ruins,the castle in the clouds in the sky (top floor), the castle in the clouds in the sky (ground floor), the castle in the clouds in the sky (basement), mt. molehill, the jungles of ancient loathing]; - - boolean [location] want_nc_locations = $locations[the penultimate fantasy airship]; - - string turns_remaining_string = ""; - - boolean need_plus_combat = false; - int plus_combat_needed = 25; - boolean need_minus_combat = false; - - - location [int] target_locations; - if (amount_needed != 0 && target_monster != $monster[none] && monster_locations.count() > 0) - { - float min_turns_remaining = -1.0; // Infinity - foreach key in monster_locations - { - location l = monster_locations[key]; - boolean noncombats_skippable = (skippable_ncs_locations contains l); - boolean noncombats_wanted = (want_nc_locations contains l); - float [monster] appearance_rates = l.appearance_rates_adjusted(); - int number_remaining = amount_needed - amount_found; - - - if (number_remaining == 0) - { - if (url.s.length() == 0) - url.s = "place.php?whichplace=forestvillage"; - subentry.header = "Return to the bounty hunter hunter"; - return subentry; - } - string clickable_url = getClickableURLForLocation(l); - if (clickable_url != "" && (url.s.length() == 0 || url.s == "place.php?whichplace=forestvillage")) //if it's that URL, then it's back to the BHH - we'd rather override that with a bounty - url.s = clickable_url; - - float bounty_appearance_rate = appearance_rates[target_monster] / 100.0; - if (bounty_appearance_rate < 0.0) { // is banished, for instance - bounty_appearance_rate = 0.0; - } - - float base_combat_rate = 0.0; - foreach mon, appearance_rate in appearance_rates { - if (mon != $monster[none] && appearance_rate >= 0) { - base_combat_rate += appearance_rate; - } - } - if (noncombats_skippable) - { - //Recorrect for NC: - if (base_combat_rate != 0.0) - bounty_appearance_rate /= (base_combat_rate / 100.0); - } - else if (noncombats_wanted) - { - //Recorrect for NC: - float nc_rate = (100.0 - base_combat_rate) / 100.0; - bounty_appearance_rate += nc_rate; - } - - // always show at least one location if possible, even if there is no chance to encounter the monster (e.g. it is banished) - float turns_remaining = -1.0; - if (bounty_appearance_rate != 0.0) - { - turns_remaining = number_remaining.to_float() / bounty_appearance_rate; - } - - if (min_turns_remaining == -1.0 || (turns_remaining != -1.0 && turns_remaining <= min_turns_remaining)) - { - if (turns_remaining != min_turns_remaining) - target_locations.listClear(); - target_locations.listAppend(l); - - min_turns_remaining = turns_remaining; - if (turns_remaining != -1.0) turns_remaining_string = " ~" + pluralise(round(turns_remaining), "turn remains", "turns remain") + "."; - } - - // Using a fancy function to get the combat percentage, it already accounts for combat modifiers - int combat_rate = l.combat_percent; - - if (noncombats_wanted && combat_rate != 0.0) - need_minus_combat = true; - else if (!noncombats_skippable && combat_rate < 100.0) - { - need_plus_combat = true; - plus_combat_needed = 100.0 - combat_rate; - } - } - } - - - if (need_plus_combat) - subentry.modifiers.listAppend("+" + plus_combat_needed + "% combat"); - if (need_minus_combat) - subentry.modifiers.listAppend("-combat"); - - if (target_monster != $monster[none]) - { - string monster_text = target_monster; - if (last_monster() == target_monster) - monster_text = HTMLGenerateSpanOfClass(monster_text, "r_bold"); - subentry.entries.listAppend("From " + monster_text + " in " + target_locations.listJoinComponents(", ", "or") + "."); - subentry.modifiers.listAppend("olfact " + target_monster); - subentry.modifiers.listAppend("banish"); - } - - - if (amount_needed == 0) - { - subentry.entries.listAppend(amount_found + " found." + turns_remaining_string); - } - else - { - int amount_remaining = amount_needed - amount_found; - subentry.entries.listAppend(amount_remaining.int_to_wordy().capitaliseFirstLetter() + " left." + turns_remaining_string); - //subentry.entries.listAppend(amount_found + " out of " + amount_needed + " found." + turns_remaining_string); - } - - item [string] bounty_item_to_unlock; - - bounty_item_to_unlock["glittery skate key"] = $item[tiny bottle of absinthe]; - bounty_item_to_unlock["pile of country guano"] = $item[astral mushroom]; - if (!get_property_boolean("_psychoJarUsed")) - { - bounty_item_to_unlock["greasy string"] = $item[jar of psychoses (The Meatsmith)]; - bounty_item_to_unlock["pixellated ashes"] = $item[jar of psychoses (The Crackpot Mystic)]; - bounty_item_to_unlock["unlucky claw"] = $item[jar of psychoses (The Suspicious-Looking Guy)]; - } - bounty_item_to_unlock["pop art banana peel"] = $item[llama lama gong]; - bounty_item_to_unlock["wig powder"] = $item["DRINK ME" potion]; - bounty_item_to_unlock["grizzled stubble"] = $item[transporter transponder]; - bounty_item_to_unlock["hickory daiquiri"] = $item[devilish folio]; - - if (bounty_item_to_unlock contains bounty_item_name) - subentry.entries.listAppend("Accessed with " + bounty_item_to_unlock[bounty_item_name] + "."); - - - if ((bounty_item_name == "half-empty bottle of eyedrops" || bounty_item_name == "broken plunger handle") && knoll_available()) - { - url.s = "place.php?whichplace=forestvillage"; - subentry.entries.listClear(); - subentry.modifiers.listClear(); - subentry.entries.listAppend("Unable to complete this bounty under knoll sign."); - subentry.header = "Cancel bounty hunt for " + bounty_item_name.HTMLEscapeString(); - } - - if (bounty_item_name == "greasy string") - subentry.entries.listAppend("Run away from non-salaminders to complete this bounty in a day."); - - if (bounty_item_name == "burned-out arcanodiode") - { - if (monster_level_adjustment() < 20) - subentry.entries.listAppend(HTMLGenerateSpanFont("Run +20 ML to find more MechaMechs.", "red")); - } - - return subentry; -} - -void SBountyHunterHunterGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //Preliminary support, this may break. - //currentEasyBountyItem, currentHardBountyItem, currentSpecialBountyItem - - //FIXME add suggesting taking bounties if we can detect if they have a bounty available - ChecklistSubentry [int] subentries; - string [int] bounty_property_names = split_string_alternate("currentEasyBountyItem,currentHardBountyItem,currentSpecialBountyItem", ","); - string [string] bounty_properties; - boolean on_bounty = false; - - foreach key in bounty_property_names - { - string property_name = bounty_property_names[key]; - string property_value = get_property(property_name); - if (property_value.length() == 0) - continue; - bounty_properties[property_name] = property_value; - on_bounty = true; - } - - StringHandle url_handle; - - - if (!on_bounty) - return; - - location [int] relevant_locations; - foreach bounty_name in bounty_properties - { - string property_value = bounty_properties[bounty_name]; - - //Parse: - //Format is bounty_item:number_found - string [int] split = split_string_alternate(property_value, ":"); - if (split.count() != 2) - continue; - string bounty_item_name = split[0]; - int amount_found = split[1].to_int_silent(); - - if (bounty_item_name.length() == 0 || bounty_item_name == "null") //unknown - bounty_item_name = "unknown"; - - bounty bounty_data = to_bounty(bounty_item_name); - - int amount_needed = bounty_data.number; - monster target_monster = bounty_data.monster; - - subentries.listAppend(SBHHGenerateHunt(bounty_item_name, amount_found, amount_needed, target_monster, relevant_locations, url_handle)); - - } - - boolean [location] highlight_locations = listInvert(relevant_locations); - if (subentries.count() > 0) - { - optional_task_entries.listAppend(ChecklistEntryMake("__item bounty-hunting helmet", url_handle.s, subentries, highlight_locations).ChecklistEntrySetIDTag("Bounty hunter hunter")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets/Buff Upkeep.ash b/Source/relay/TourGuide/Sets/Buff Upkeep.ash deleted file mode 100644 index 402e2d14..00000000 --- a/Source/relay/TourGuide/Sets/Buff Upkeep.ash +++ /dev/null @@ -1,100 +0,0 @@ -RegisterTaskGenerationFunction("SBuffUpkeepGenerateTasks"); -void SBuffUpkeepGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //Least-effort (basically a copy-paste from my ascension script), needs examining: - if (!__misc_state["in run"]) - return; - if (my_meat() < 1000) return; //save - skill [int] skills_want_running; - int [skill] minimum_meat_for_skill; - - skills_want_running.listAppend($skill[iron palm technique]); - - if (in_bad_moon() && my_mp() >= 1) - { - if (my_class() == $class[disco bandit]) - skills_want_running.listAppend($skill[disco aerobics]); - } - if (!__misc_state["familiars temporarily blocked"] && my_familiar() != $familiar[none]) - { - skills_want_running.listAppend($skill[leash of linguini]); - skills_want_running.listAppend($skill[empathy of the newt]); - } - if (get_property("peteMotorbikeMuffler").length() == 0) - skills_want_running.listAppend($skill[rev engine]); - if (my_primestat() == $stat[mysticality] && my_hp() < 500) - { - if ($item[turtle totem].available_amount() > 0) - { - skills_want_running.listAppend($skill[reptilian fortitude]); - skills_want_running.listAppend($skill[astral shell]); - skills_want_running.listAppend($skill[ghostly shell]); - } - } - boolean have_facial_expression = false; - foreach s in $skills[Arched Eyebrow of the Archmage,Disco Leer,Disco Smirk,Icy Glare,Knowing Smile,Patient Smile,Scowl of the Auk,Snarl of the Timberwolf,Stiff Upper Lip,Suspicious Gaze,Wizard Squint,Wry Smile] - { - if (s == $skill[suspicious gaze] && get_property_int("cyrptAlcoveEvilness") <= 26 && QuestState("questL07Cyrptic").started) //only need suspicious gaze there - continue; - if (s.to_effect().have_effect() > 0) - have_facial_expression = true; - } - if (lookupSkill("Inscrutable Gaze").to_effect().have_effect() > 0) - have_facial_expression = true; - - if (__misc_state["need to level"] && !have_facial_expression) - { - if (my_primestat() == $stat[mysticality]) - skills_want_running.listAppend($skill[Wry Smile]); - else if (my_primestat() == $stat[moxie]) - skills_want_running.listAppend($skill[knowing smile]); - else if (my_primestat() == $stat[muscle]) - skills_want_running.listAppend($skill[Patient Smile]); - } - - //UNDYING! - if (my_level() >= 3) - skills_want_running.listAppend($skill[Purr of the Feline]); - skills_want_running.listAppend($skill[Prayer of Seshat]); - if (__misc_state["need to level"]) - skills_want_running.listAppend($skill[Blessing of Serqet]); - skills_want_running.listAppend($skill[Hide of Sobek]); - if (!in_hardcore()) - skills_want_running.listAppend($skill[Bounty of Renenutet]); - skills_want_running.listAppend($skill[Power of Heka]); - skills_want_running.listAppend($skill[Wisdom of Thoth]); - if (my_primestat() == $stat[mysticality] && my_level() < 13) - skills_want_running.listAppend(lookupSkill("Inscrutable Gaze")); - - - - minimum_meat_for_skill[$skill[The Magical Mojomuscular Melody]] = 100; - minimum_meat_for_skill[$skill[blessing of serqet]] = 500; - minimum_meat_for_skill[$skill[Prayer of Seshat]] = 500; - minimum_meat_for_skill[$skill[Power of Heka]] = 500; - minimum_meat_for_skill[$skill[Purr of the Feline]] = 500; - minimum_meat_for_skill[$skill[leash of linguini]] = 2000; - minimum_meat_for_skill[$skill[empathy of the newt]] = 3000; - foreach s in $skills[ur-kel's aria of annoyance,drescher's annoying noise,pride of the puffin] - minimum_meat_for_skill[s] = 2000; - - - skill [int] final_skills; - foreach key, s in skills_want_running - { - if (!s.skill_is_usable() || !s.is_unrestricted()) - continue; - effect e = s.to_effect(); - if (e == $effect[none]) - continue; - if (e.have_effect() > 1) - continue; - if (my_maxmp() < s.mp_cost()) - continue; - final_skills.listAppend(s); - } - if (final_skills.count() > 0) - { - optional_task_entries.listAppend(ChecklistEntryMake("__skill " + final_skills[0], "skillz.php", ChecklistSubentryMake("Upkeep buffs", "", "Cast " + final_skills.listJoinComponents(", ", "and") + ".")).ChecklistEntrySetIDTag("Buff upkeep suggestions")); - } -} diff --git a/Source/relay/TourGuide/Sets/Calculate Universe.ash b/Source/relay/TourGuide/Sets/Calculate Universe.ash deleted file mode 100644 index cd9c0adf..00000000 --- a/Source/relay/TourGuide/Sets/Calculate Universe.ash +++ /dev/null @@ -1,149 +0,0 @@ -import "relay/TourGuide/Support/Numberology.ash" -void SCalculateUniverseGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!$skill[Calculate the Universe].skill_is_usable()) - return; - int uses_remaining = 1; - if (get_property_boolean("_universeCalculated") && !mafiaIsPastRevision(17039)) - return; - if (mafiaIsPastRevision(17039)) - { - int universe_calculated = get_property_int("_universeCalculated"); - int limit = 1; - - // As of August 2022, within run, you only get access to 3 calculates per day. This cuts the tile off in-run while letting - // it remain active out-of-run. - int skill_number = __misc_state["in run"] ? min(get_property_int("skillLevel144"),3) : get_property_int("skillLevel144"); - limit = max(skill_number, limit); - if (universe_calculated >= limit) - return; - uses_remaining = limit - universe_calculated; - } - - string [int] description; - - string [int] useful_digits_and_their_reasons; - if (__setting_enable_outputting_all_numberology_options) - { - for digit from 0 to 99 - { - if (!($ints[24,25,26,28,29,31,32,39,41,42,46,52,53,54,55,56,59,60,61,62,64,65,67,72,73,74,76,79,80,81,82,84,85,86,91,92,94,95,96] contains digit)) //Try Again - useful_digits_and_their_reasons[digit] = ""; - } - } - //Set up useful digits: - if (my_path().id != PATH_SLOW_AND_STEADY) - useful_digits_and_their_reasons[69] = "+3 adventures"; - if (hippy_stone_broken()) - useful_digits_and_their_reasons[37] = "+3 fights"; - if (__misc_state["in run"]) - { - if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues") && !__quest_state["Level 12"].finished) - useful_digits_and_their_reasons[51] = "War frat orc to YR"; - useful_digits_and_their_reasons[14] = "1400 meat (autosell 14 moxie weeds)"; - - int ice_cubes_needing_creation = $item[perfect ice cube].available_amount(); - if ($skill[Perfect Freeze].skill_is_usable() && !get_property_boolean("_perfectFreezeUsed")) - ice_cubes_needing_creation += 1; - if (ice_cubes_needing_creation > 0 && $items[bottle of rum,bottle of vodka,boxed wine,bottle of gin,bottle of whiskey,bottle of tequila].available_amount() < ice_cubes_needing_creation && __misc_state["can drink just about anything"]) - { - //FIXME 18, 44, 75, and 99 are all valid for this - pick whichever we can summon now? - useful_digits_and_their_reasons[99] = "base booze for perfect ice cube"; - } - if (__quest_state["Level 5"].mafia_internal_step < 3 && $item[Knob Goblin Perfume].available_amount() == 0 && $effect[Knob Goblin Perfume].have_effect() == 0 && in_ronin()) //have_outfit_components("Knob Goblin Harem Girl Disguise") - { - useful_digits_and_their_reasons[9] = "knob goblin perfume for boss fight"; - } - if ($item[Vegetable of Jarlsberg].available_amount() > 0) - useful_digits_and_their_reasons[16] = "magicalness-in-a-can for Jarlsberg's vegetable soup"; - } - if (my_level() < 13) - { - //making a guess here - 89 is 89 mainstat with bonus experience percent (seems logical with the limited data we have) - float mainstat_gained = 89.0 * (1.0 + numeric_modifier(my_primestat() + " experience percent") / 100.0); - useful_digits_and_their_reasons[89] = roundForOutput(mainstat_gained, 0) + " mainstats"; - } - - //useful_digits_and_their_reasons[44] = "is very bad to steal jobu's rum"; - - //Run complicated calculation code: - boolean [int] desired_digits; - foreach digit in useful_digits_and_their_reasons - desired_digits[digit] = true; - int [int] digit_inputs_to_outputs; - int [int] digit_inputs_to_deltas; - calculateNumberologyInputValuesForOutputs(desired_digits, digit_inputs_to_outputs, digit_inputs_to_deltas); - - string [int][int] table; - table.listAppend(listMake(HTMLGenerateSpanOfClass("Enter", "r_bold"), HTMLGenerateSpanOfClass("For", "r_bold"))); - string [int][int] mappings; - - foreach digit, reason in useful_digits_and_their_reasons - { - string what_to_do; - if (digit_inputs_to_outputs contains digit) - { - if (__setting_enable_outputting_all_numberology_options) - mappings.listAppend(listMake(digit_inputs_to_outputs[digit].to_string(), digit.to_string())); - //mappings.listAppend(digit_inputs_to_outputs[digit] + " -> " + digit); - what_to_do = digit_inputs_to_outputs[digit].to_string();// + HTMLGenerateSpanFont(" (" + digit + ")", "gray", "0.9em"); - } - else if (digit_inputs_to_deltas contains digit) - { - what_to_do = "Wait " + digit_inputs_to_deltas[digit] + " adv"; - } - else - what_to_do = "Unknown result to end in " + digit; - if (reason != "") - { - //table.listAppend(listMake(what_to_do, reason)); - table.listAppend(listMake(what_to_do, reason + HTMLGenerateSpanFont(" (" + digit + ")", "gray", "0.9em"))); - } - } - - string table_description; - if (table.count() > 0) - table_description += "|*" + HTMLGenerateSimpleTableLines(table); - if (mappings.count() > 0) - { - //FIXME full description? - string [int][int] mappings_final; - //Compress mappings: - mappings_final[0] = listMakeBlankString(); - foreach key in mappings - { - string [int] mapping = mappings[key]; - string [int] line = listMake(" ", mapping[0], __html_right_arrow_character, mapping[1]); - - if (mappings_final[mappings_final.count() - 1].count() >= 12) - mappings_final.listAppend(listMakeBlankString()); - mappings_final[mappings_final.count() - 1].listAppendList(line); - } - - - buffer tooltip_text; - tooltip_text.append(HTMLGenerateTagWrap("div", "Values to input for " + __html_right_arrow_character + " output", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); - tooltip_text.append(HTMLGenerateSimpleTableLines(mappings_final)); - - string line = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class") + "Full table", "r_tooltip_outer_class"); - //we can't do full-width table entries because of colspan and display:table, so mimic it: - //description.listAppend(line); - //table.listAppend(listMake(line)); - if (table_description != "") - table_description += "
"; - table_description += line; - } - if (table_description != "") - description.listAppend("Cast skill, enter the right number: (this changes)" + table_description); - else - description.listAppend("Cast skill, enter the right number."); - - /*if (table.count() > 1) - description.listAppend("Cast skill, enter the right number: (this changes, and is still being spaded)|*" + HTMLGenerateSimpleTableLines(table)); - else - description.listAppend("Cast skill, enter the right number.");*/ - string title = "Calculate the Universe"; - if (uses_remaining > 1) - title = pluralise(uses_remaining, "Calculate the Universe", "Calculate the Universes"); - resource_entries.listAppend(ChecklistEntryMake("__skill Calculate the Universe", "skillz.php", ChecklistSubentryMake(title, "", description), 0).ChecklistEntrySetIDTag("Calculate universe resource")); -} diff --git a/Source/relay/TourGuide/Sets/Classes.ash b/Source/relay/TourGuide/Sets/Classes.ash deleted file mode 100644 index ec312441..00000000 --- a/Source/relay/TourGuide/Sets/Classes.ash +++ /dev/null @@ -1,233 +0,0 @@ -Record SealSummon -{ - monster summoned_monster; - item figurine; - boolean can_buy_in_store_or_hermit; - int seal_clubber_candles_required; - int imbued_seal_blubber_candles_required; //0 or 1 - int minimum_level; - item item_dropped; - item equipment_dropped; - string item_dropped_description; -}; - -SealSummon SealSummonMake(monster summoned_monster, item figurine, boolean can_buy_in_store_or_hermit, int seal_clubber_candles_required, int imbued_seal_blubber_candles_required, int minimum_level, item item_dropped, string item_dropped_description, item equipment_dropped) -{ - SealSummon summon; - summon.summoned_monster = summoned_monster; - summon.figurine = figurine; - summon.can_buy_in_store_or_hermit = can_buy_in_store_or_hermit; - summon.seal_clubber_candles_required = seal_clubber_candles_required; - summon.imbued_seal_blubber_candles_required = imbued_seal_blubber_candles_required; - summon.minimum_level = minimum_level; - summon.item_dropped = item_dropped; - summon.equipment_dropped = equipment_dropped; - summon.item_dropped_description = item_dropped_description; - - return summon; -} - -void listAppend(SealSummon [int] list, SealSummon entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void SSealClubberInfernalSealsGenerateResource(ChecklistEntry [int] resource_entries) -{ - string [int] description; - int seal_summon_limit = 5; - if ($item[Claw of the Infernal Seal].available_amount() > 0) - { - seal_summon_limit = 10; - if ($item[Claw of the Infernal Seal].item_amount() + $item[Claw of the Infernal Seal].equipped_amount() == 0 && $item[Claw of the Infernal Seal].storage_amount() > 0) - description.listAppend("Pull the Claw of the Infernal Seal from hangk's."); - } - int seals_summoned = get_property_int("_sealsSummoned"); - int summons_remaining = MAX(seal_summon_limit - seals_summoned, 0); - if (summons_remaining == 0) - return; - - //Seal summons: - //FIXME suggest they equip a club (support swords with iron palms) - - if (!$slot[weapon].equipped_item().weapon_is_club()) - { - description.listAppend("Equip a club" + ($effect[Iron Palms].have_effect() > 0 ? " or sword" : "") + " first."); - } - - - //initialise all the seals: - SealSummon [int] seal_summons; - //seal_summons.listAppend(SealSummonMake($monster[SUMMONED_MONSTER], $item[FIGURINE], CAN_BUY_IN_STORE_OR_HERMIT, SEAL_CLUBBER_CANDLES_REQUIRED, IMBUED_SEAL_BLUBBER_CANDLES_REQUIRED, MINIMUM_LEVEL, $item[ITEM_DROPPED], "ITEM_DROPPED_DESCRIPTION")); - seal_summons.listAppend(SealSummonMake($monster[broodling seal], $item[figurine of a cute baby seal], true, 5, 0, 5, $item[severed flipper], "low-level club", $item[none])); - - seal_summons.listAppend(SealSummonMake($monster[Centurion of Sparky], $item[figurine of an armored seal], true, 10, 0, 9, $item[ingot of seal-iron], ($items[ingot of seal-iron,bad-ass club,creepy-ass club,evil-ass club,frigid-ass club,hot-ass club,nasty-ass club].available_amount() == 0 ? "+10ML craftable club" : ""), $item[none])); - - seal_summons.listAppend(SealSummonMake($monster[hermetic seal], $item[figurine of an ancient seal], true, 3, 0, 6, $item[powdered sealbone], "imbued candle source", $item[none])); - - seal_summons.listAppend(SealSummonMake($monster[Spawn of Wally], $item[figurine of a wretched-looking seal], true, 1, 0, 1, $item[tainted seal's blood], "minor potion", $item[none])); - - seal_summons.listAppend(SealSummonMake($monster[heat seal], $item[figurine of a charred seal], false, 0, 1, 6, $item[sizzling seal fat], "+init, +hot damage potion", $item[Abyssal ember])); - - seal_summons.listAppend(SealSummonMake($monster[navy seal], $item[figurine of a cold seal], false, 0, 1, 6, $item[frost-rimed seal hide], "+cold damage, +HP potion", $item[frozen seal spine])); - - seal_summons.listAppend(SealSummonMake($monster[Servant of Grodstank], $item[figurine of a stinking seal], false, 0, 1, 6, $item[fustulent seal grulch], "+20 ML, +stench damage potion", $item[infernal toilet brush])); - - seal_summons.listAppend(SealSummonMake($monster[shadow of Black Bubbles], $item[figurine of a shadowy seal], false, 0, 1, 6, $item[scrap of shadow], "+spooky damage potion", $item[shadowy seal eye])); - - seal_summons.listAppend(SealSummonMake($monster[watertight seal], $item[figurine of a sleek seal], false, 0, 1, 12, $item[hyperinflated seal lung], "underwater breathing potion", $item[none])); - - seal_summons.listAppend(SealSummonMake($monster[wet seal], $item[figurine of a slippery seal], false, 0, 1, 6, $item[seal lube], "+sleaze damage, +moxie potion", $item[mannequin leg])); - - seal_summons.listAppend(SealSummonMake($monster[none], $item[depleted uranium seal figurine], false, 0, 1, 0, $item[none], "random", $item[none])); - - //description left blank, due to possible revamp? - string url = ""; - if (guild_store_available()) - url = "shop.php?whichshop=guildstore3"; - - boolean want_output_ml = __misc_state["need to level"]; - - - string [int][int] options; - - if (true) - { - string [int] option; - option.listAppend("figurine"); - option.listAppend("candles"); - if (want_output_ml) - option.listAppend("ML"); - option.listAppend("drops"); - foreach key, s in option - { - option[key] = HTMLGenerateSpanOfClass(s, "r_bold"); - } - options.listAppend(option); - } - - if ($item[powdered sealbone].available_amount() > 0 && $item[imbued seal-blubber candle].available_amount() == 0) - { - description.listAppend("Can make an imbued seal-blubber candle."); - } - - foreach key, summon in seal_summons - { - if (summon.minimum_level > my_level()) - continue; - if (!summon.can_buy_in_store_or_hermit && summon.figurine.available_amount() == 0) - continue; - string figurine_name_simple = summon.figurine.to_string().replace_string("figurine of an ", "").replace_string("figurine of a ", ""); - - string candles_required = summon.seal_clubber_candles_required; - if ($item[seal-blubber candle].available_amount() < summon.seal_clubber_candles_required) - candles_required = HTMLGenerateSpanFont(candles_required, "grey"); - if (summon.imbued_seal_blubber_candles_required > 0) - { - candles_required = "imbued"; - } - string ml_description; - if (summon.summoned_monster != $monster[none]) - { - ml_description = summon.summoned_monster.base_attack; - } - - string item_description = summon.item_dropped_description; - - string [int] option; - option.listAppend(figurine_name_simple); - option.listAppend(candles_required); - if (want_output_ml) - option.listAppend(ml_description); - option.listAppend(item_description); - if (summon.imbued_seal_blubber_candles_required > 0 && $items[imbued seal-blubber candle,powdered sealbone].available_amount() == 0) - { - foreach key, s in option - { - option[key] = HTMLGenerateSpanFont(s, "grey"); - } - } - options.listAppend(option); - } - description.listPrepend(HTMLGenerateSimpleTableLines(options)); - - resource_entries.listAppend(ChecklistEntryMake("__item figurine of an ancient seal", url, ChecklistSubentryMake(pluralise(summons_remaining, "seal summon", "seal summons"), "", description), 10).ChecklistEntrySetIDTag("Seal clubber summon resource")); - - resource_entries.listAppend(ChecklistEntryMake("__item figurine of an ancient seal", url, ChecklistSubentryMake(pluralise(summons_remaining, "seal summon", "seal summons"), "", "See dedicated tile."), 10).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Seal clubber summon free fight")); //add an anchor to the dedicated tile?? -} - -void SSealClubberGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_class() != $class[seal clubber]) - return; - - SSealClubberInfernalSealsGenerateResource(resource_entries); -} - -void STurtleTamerGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_class() != $class[turtle tamer]) - return; - - if (__misc_state["in run"] && guild_store_available() && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST && $effect[Eau de Tortue].have_effect() == 0 && my_meat() >= 200) - { - optional_task_entries.listAppend(ChecklistEntryMake("__item helmet turtle", "shop.php?whichshop=guildstore3", ChecklistSubentryMake("Buy and use turtle pheromones", "", "Lets you encounter more turtles.")).ChecklistEntrySetIDTag("Turtle tamer pheromones")); - } -} - -void SDiscoBanditGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (my_class() != $class[disco bandit]) - return; - if ($skill[Break It On Down].have_skill() && $skill[Run Like the Wind].have_skill() && $skill[Pop and Lock It].have_skill()) - { - int steals_done = get_property_int("_raveStealCount"); - int steals_remaining = clampi(30 - steals_done, 0, 30); - if (steals_done > 0 && steals_remaining > 0) - { - string [int] description; - description.listAppend("Knocks loose a pickpocketable item."); - //raveCombo5 is rave steal - //FIXME list combo order - string rave_combo_number_5 = get_property("raveCombo5"); - if (rave_combo_number_5 != "") - { - string [int] skill_order = rave_combo_number_5.split_string(","); - description.listAppend(skill_order.listJoinComponents(__html_right_arrow_character).capitaliseFirstLetter() + "."); - } - resource_entries.listAppend(ChecklistEntryMake("__skill Disco Dance 3: Back in the Habit", "", ChecklistSubentryMake(pluralise(steals_remaining, "Rave Steal", "Rave Steals"), "", description), 8).ChecklistEntrySetIDTag("Disco bandit rave steal")); - } - } -} - -void SPastamancerGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_class() != $class[pastamancer]) - return; - if (__quest_state["Nemesis"].finished && !$skill[Canticle of Carboloading].have_skill()) - { - if ($item[black hymnal].available_amount() == 0) - { - optional_task_entries.listAppend(ChecklistEntryMake("__skill Canticle of Carboloading", "volcanoisland.php", ChecklistSubentryMake("Collect the black hymnal from the Nemesis Temple", "", "Unlocks Carboloading.")).ChecklistEntrySetIDTag("Nemesis quest pastamancer black hymnal get")); - } - else - { - optional_task_entries.listAppend(ChecklistEntryMake("__skill Canticle of Carboloading", "inventory.php?ftext=black+hymnal", ChecklistSubentryMake("Use the black hymnal", "", "Unlocks Carboloading.")).ChecklistEntrySetIDTag("Nemesis quest pastamancer black hymnal use")); - } - } -} - -void SClassesGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - STurtleTamerGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SPastamancerGenerateTasks(task_entries, optional_task_entries, future_task_entries); -} - -void SClassesGenerateResource(ChecklistEntry [int] resource_entries) -{ - SSealClubberGenerateResource(resource_entries); - SDiscoBanditGenerateResource(resource_entries); -} diff --git a/Source/relay/TourGuide/Sets/Copied Monsters.ash b/Source/relay/TourGuide/Sets/Copied Monsters.ash deleted file mode 100644 index cc1d8a75..00000000 --- a/Source/relay/TourGuide/Sets/Copied Monsters.ash +++ /dev/null @@ -1,520 +0,0 @@ - - - -string generateNinjaSafetyGuide(boolean show_colour) -{ - boolean can_survive = false; - float init_needed = $monster[ninja snowman assassin].monster_initiative(); - init_needed = monster_initiative($monster[Ninja snowman assassin]); - - float damage_taken = calculateCurrentNinjaAssassinMaxDamage(); - float damage_taken_always = calculateCurrentNinjaAssassinMaxEnvironmentalDamage(); - - string result; - if (initiative_modifier() >= init_needed) - { - if (my_hp() >= ceil(damage_taken_always) + 2) - can_survive = true; - result += "Keep"; - } - else - result += "Need"; - result += " +" + ceil(init_needed) + "% init"; - - if (damage_taken_always > my_hp()) - result += "/" + ceil(damage_taken_always) + " HP"; - - result += " to survive ninja, or "; - - //FIXME warn about damage_taken_always WITH INIT - - int min_safe_damage = (ceil(damage_taken) + 2) + (ceil(damage_taken_always) + 2) ; - if (my_hp() >= min_safe_damage) - { - result += "keep"; - can_survive = true; - } - else - result += "need"; - result += " HP above " + min_safe_damage + "."; - - if (my_path().id == PATH_CLASS_ACT_2 && monster_level_adjustment() > 50) - { - result += " Reduce ML to +50 to prevent elemental damage."; - can_survive = false; - } - - if (!can_survive && show_colour) - result = HTMLGenerateSpanFont(result, "red"); - return result; -} - - -void CopiedMonstersGenerateDescriptionForMonster(string monster_name, string [int] description, boolean show_details, boolean from_copy) -{ - if (!__misc_state["in run"]) - return; - monster_name = monster_name.to_lower_case(); - if (monster_name == "ninja snowman assassin") - { - description.listAppend(generateNinjaSafetyGuide(show_details)); - int components_missing = $items[ninja rope,ninja carabiner,ninja crampons].items_missing().count(); - if (components_missing > 0) - description.listAppend("Need to fight " + components_missing.int_to_wordy() + " more."); - else - description.listAppend("Don't need to fight anymore."); - - if (from_copy && $familiar[obtuse angel].familiar_is_usable() && $familiar[reanimated reanimator].familiar_is_usable()) - { - string line = "Make sure to copy with angel, not the reanimator."; - if (my_familiar() == $familiar[reanimated reanimator]) - line = HTMLGenerateSpanFont(line, "red"); - description.listAppend(line); - } - } - else if (monster_name == "quantum mechanic") - { - string line; - boolean requirements_met = false; - if (item_drop_modifier_ignoring_plants() < 150.0) - line += "Need "; - else - { - line += "Keep "; - requirements_met = true; - } - line += "+150% item for large box"; - if (show_details && !requirements_met) - line = HTMLGenerateSpanFont(line, "red"); - description.listAppend(line); - } - else if ($strings[bricko bat,bricko cathedral,bricko elephant,bricko gargantuchicken,bricko octopus,bricko ooze,bricko oyster,bricko python,bricko turtle,bricko vacuum cleaner] contains monster_name) - { - description.listAppend("Zero adventure cost, use to burn delay."); - } - else if (monster_name == "lobsterfrogman" && show_details) - { - string line; - - if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) - { - int number_to_fight = clampi(5 - $item[barrel of gunpowder].available_amount(), 0, 5); - line += number_to_fight.int_to_wordy().capitaliseFirstLetter() + " more to defeat. "; - } - - int lfm_attack = $monster[lobsterfrogman].base_attack + 5.0; - string attack_text = lfm_attack + " attack."; - - if (my_buffedstat($stat[moxie]) < lfm_attack) - attack_text = HTMLGenerateSpanFont(attack_text, "red"); - - line += attack_text; - description.listAppend(line); - } - else if (monster_name == "big swarm of ghuol whelps" || monster_name == "swarm of ghuol whelps" || monster_name == "giant swarm of ghuol whelps") - { - float monster_level = monster_level_adjustment_ignoring_plants(); - - monster_level = MAX(monster_level, 0); - - float cranny_beep_beep_beep = MAX(3.0,sqrt(monster_level)); - description.listAppend("~" + cranny_beep_beep_beep.roundForOutput(1) + " cranny beeps."); - } - else if (monster_name == "writing desk") - { - /*if ($item[telegram from Lady Spookyraven].available_amount() > 0) - description.listAppend(HTMLGenerateSpanFont("Read the telegram from Lady Spookyraven first.", "red")); - int desks_remaining = clampi(5 - get_property_int("writingDesksDefeated"), 0, 5); - if (desks_remaining > 0 && !get_property_ascension("lastSecondFloorUnlock") && $item[Lady Spookyraven's necklace].available_amount() == 0 && get_property("questM20Necklace") != "finished" && mafiaIsPastRevision(15244)) - description.listAppend(pluraliseWordy(desks_remaining, "desk", "desks").capitaliseFirstLetter() + " remaining.");*/ - description.listAppend("This doesn't work anymore."); - - } - else if (monster_name == "skinflute" || monster_name == "camel's toe") - { - description.listAppend("Have " + pluralise($item[star]) + " and " + pluralise($item[line]) + "."); - if (item_drop_modifier_ignoring_plants() < 234.0) - description.listAppend(HTMLGenerateSpanFont("Need +234% item.", "red")); - } - else if (monster_name == "source agent") - { - if (monster_level_adjustment() > 0) - description.listAppend("Possibly remove +ML."); - string stat_description; - - if (get_property_int("sourceAgentsDefeated") > 0) - stat_description += pluralise(get_property_int("sourceAgentsDefeated"), "agent", "agents") + " defeated so far. "; - stat_description += $monster[Source Agent].base_attack + " attack."; - float our_init = initiative_modifier(); - if ($skill[Overclocked].have_skill()) - our_init += 200; - float agent_initiative = $monster[Source Agent].base_initiative; - float chance_to_get_jump = clampf(100 - agent_initiative + our_init, 0.0, 100.0); - boolean might_not_gain_init = false; - boolean avoid_displaying_init_otherwise = false; - if (my_thrall() == $thrall[spaghetti elemental] && my_thrall().level >= 5 && monster_level_adjustment() <= 150) - { - stat_description += "|Will effectively gain initiative on agent."; - if (!__iotms_usable[$item[source terminal]] || get_property_int("_sourceTerminalPortscanUses") >= 3) - avoid_displaying_init_otherwise = true; - } - if (avoid_displaying_init_otherwise) - { - } - else if (chance_to_get_jump >= 100.0) - stat_description += "|Will gain initiative on agent."; - else if (chance_to_get_jump <= 0.0) - { - stat_description += "|Will not gain initiative on agent. Need " + round(agent_initiative - our_init) + "% more init."; - might_not_gain_init = true; - } - else - { - stat_description += "|" + round(chance_to_get_jump) + "% chance to gain initiative on agent."; - might_not_gain_init = true; - } - if (might_not_gain_init) - { - if (my_class() == $class[pastamancer] && $skill[bind spaghetti elemental].have_skill() && my_thrall() != $thrall[spaghetti elemental]) - { - stat_description += " Or run "; - if ($thrall[spaghetti elemental].level < 5) - stat_description += "and level up "; - stat_description += "a spaghetti elemental to block the first attack."; - } - } - description.listAppend(stat_description); - if (__last_adventure_location == $location[the haunted bedroom]) - description.listAppend("Won't appear in the haunted bedroom, so may want to go somewhere else?"); - if ($skill[Humiliating Hack].have_skill()) - { - string [int] delevelers; - if ($skill[ruthless efficiency].have_skill() && $effect[ruthlessly efficient].have_effect() == 0) - { - delevelers.listAppend("cast ruthless efficiency"); - } - if ($item[dark porquoise ring].available_amount() > 0 && $item[dark porquoise ring].equipped_amount() == 0 && $item[dark porquoise ring].can_equip()) - { - delevelers.listAppend("equip dark porquoise ring"); - } - if (delevelers.count() > 0) - { - description.listAppend("Possibly " + delevelers.listJoinComponents(", ", "or") + " for better deleveling."); - } - } - } - - if (__misc_state["monsters can be nearly impossible to kill"] && monster_level_adjustment() > 0) - description.listAppend(HTMLGenerateSpanFont("Possibly remove +ML to survive. (at +" + monster_level_adjustment() + " ML)", "red")); -} - -void generateCopiedMonstersEntry(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, boolean from_task) //if from_task is false, assumed to be from resources -{ - string [int] description; - boolean very_important = false; - int show_up_in_tasks_turn_cutoff = 10; - string title = ""; - int min_turns_until = -1; - string url = ""; - if (get_property_boolean("dailyDungeonDone")) - url = $location[the daily dungeon].getClickableURLForLocation(); - Counter romantic_arrow_counter = CounterLookup("Romantic Monster", ErrorMake(), true); - if (false && (romantic_arrow_counter.CounterIsRange() || get_property_int("_romanticFightsLeft") > 0)) - { - Vec2i turn_range = romantic_arrow_counter.CounterGetWindowRange(); - - title = "Arrowed " + __misc_state_string["Romantic Monster Name"].to_lower_case() + " appears "; - - if (turn_range.y <= 0) - title += "now or soon"; - else if (turn_range.x <= 0) - title += "between now and " + turn_range.y + " turns."; - else - title += "in [" + turn_range.x + " to " + turn_range.y + "] turns."; - - min_turns_until = turn_range.x; - - int fights_left = get_property_int("_romanticFightsLeft"); - if (fights_left > 1) - { - string line = fights_left + " fights left"; - - Vec2i estimated_range = Vec2iMake(15 * (fights_left - 1), 25 * (fights_left - 1)); - estimated_range.x += turn_range.x; - estimated_range.y += turn_range.y; - - line += " over ~" + (estimated_range.x + estimated_range.y) / 2 + " turns."; - - description.listAppend(line); - } - else if (fights_left == 1) - description.listAppend("Last fight."); - - - - - if (turn_range.x <= 0) - very_important = true; - } - if (from_task && min_turns_until > show_up_in_tasks_turn_cutoff) - return; - if (!from_task && min_turns_until <= show_up_in_tasks_turn_cutoff) - return; - - if (title != "") - { - CopiedMonstersGenerateDescriptionForMonster(__misc_state_string["Romantic Monster Name"], description, very_important, false); - } - - if (title != "") - { - int importance = 4; - if (very_important) - importance = -11; - ChecklistEntry entry = ChecklistEntryMake(__misc_state_string["obtuse angel name"], url, ChecklistSubentryMake(title, "", description), importance); - entry.tags.id = "Angel copy monster old obsolete"; - if (very_important) - task_entries.listAppend(entry); - else - optional_task_entries.listAppend(entry); - - } -} - -void SCopiedMonstersGenerateResourceForCopyType(ChecklistEntry [int] resource_entries, item shaking_object, string shaking_shorthand_name, string monster_name_property_name) -{ - if (shaking_object.available_amount() == 0 && shaking_object != $item[none]) - return; - - string url = "inventory.php?ftext=" + shaking_object; - - string [int] monster_description; - string monster_name = get_property(monster_name_property_name).HTMLEscapeString(); - CopiedMonstersGenerateDescriptionForMonster(monster_name, monster_description, true, true); - - if (get_auto_attack() != 0) - { - url = "account.php?tab=combat"; - monster_description.listAppend("Auto attack is on, disable it?"); - } - - //string line = monster_name.capitaliseFirstLetter() + HTMLGenerateIndentedText(monster_description); - string line = HTMLGenerateSpanOfClass(monster_name.capitaliseFirstLetter(), "r_bold"); - - if (monster_description.count() > 0) - line += "
" + monster_description.listJoinComponents("|"); - - string image_name = "__item " + shaking_object; - if (shaking_shorthand_name == "chateau painting") - { - image_name = "__item fancy oil painting"; - url = "place.php?whichplace=chateau"; - } - - resource_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(shaking_shorthand_name.capitaliseFirstLetter() + " monster trapped!", "", line)).ChecklistEntrySetIDTag("Copy item " + shaking_shorthand_name)); -} - -void SCopiedMonstersGenerateResource(ChecklistEntry [int] resource_entries) -{ - //Sources: - - boolean have_spooky_putty = $items[Spooky Putty ball,Spooky Putty leotard,Spooky Putty mitre,Spooky Putty sheet,Spooky Putty snake,Spooky Putty monster].available_amount() > 0; - - int copies_used = get_property_int("spookyPuttyCopiesMade") + get_property_int("_raindohCopiesMade"); - int copies_available = MIN(6,5*MIN($items[Spooky Putty ball,Spooky Putty leotard,Spooky Putty mitre,Spooky Putty sheet,Spooky Putty snake,Spooky Putty monster].available_amount(), 1) + 5*MIN($item[Rain-Doh black box].available_amount() + $item[rain-doh box full of monster].available_amount(), 1)); - int copies_left = copies_available - copies_used; - - string [int] potential_copies; - if (!__misc_state["in CS aftercore"]) - { - //√ghuol whelps, √modern zmobies, √wine racks, √lobsterfrogmen, √ninja assassin - if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) - potential_copies.listAppend("Lobsterfrogman."); - if (__quest_state["Level 7"].state_boolean["cranny needs speed tricks"]) - potential_copies.listAppend("Swarm of ghuol whelps."); - if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"]) - potential_copies.listAppend("Modern zmobies."); - if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && $items[ninja rope,ninja carabiner,ninja crampons].available_amount() == 0 && !have_outfit_components("eXtreme Cold-Weather Gear")) - potential_copies.listAppend("Ninja assassin."); - //if (!__quest_state["Level 11"].finished && !__quest_state["Level 11 Palindome"].finished && $item[talisman o' namsilat].available_amount() == 0 && $items[gaudy key,snakehead charrrm].available_amount() < 2 && my_path().id != PATH_G_LOVER) - //potential_copies.listAppend("Gaudy pirate - copy once for extra key."); //now obsolete - //√baa'baa. astronomer? √nuns trick brigand - //FIXME astronomer when we can calculate that - //if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) - //potential_copies.listAppend("Brigand - nuns trick."); - //possibly less relevant: - //√ghosts/skulls/bloopers...? - //seems very marginal - //if (!__quest_state["Level 13"].state_boolean["past keys"] && ($item[digital key].available_amount() + creatable_amount($item[digital key])) == 0) - //potential_copies.listAppend("Ghosts/morbid skulls/bloopers, for digital key. (marginal?)"); - //bricko bats, if they have bricko...? - //if (__misc_state["bookshelf accessible"] && $skill[summon brickos].skill_is_usable()) - //potential_copies.listAppend("Bricko bats...?"); - } - ChecklistEntry copy_source_entry; - copy_source_entry.tags.id = "Copy options resource"; - - if ( __iotms_usable[$item[Chateau Mantegna room key]] && !get_property_boolean("_chateauMonsterFought") && mafiaIsPastRevision(15115)) - { - string url = "place.php?whichplace=chateau"; - string header = "Chateau painting copy"; - string [int] description; - monster current_monster = get_property_monster("chateauMonster"); - - if (current_monster == $monster[none]) - header += " available"; - else - header += " fightable"; - - if (__misc_state["in run"]) - { - if ($item[alpine watercolor set].available_amount() == 0) - description.listAppend("Acquire an alpine watercolor set to copy something else."); - else - description.listAppend("Copy something else with alpine watercolor set."); - /*string line; - if (current_monster == $monster[none]) - line += "Options:"; - else - line += "Other options:"; - - if ($item[alpine watercolor set].available_amount() == 0) - { - //url = "shop.php?whichshop=chateau"; - line += " (buy alpine watercolor set first)"; - } - else - line += " (copy with alpine watercolor set)"; - - line += "|*" + potential_copies.listJoinComponents("|*"); - description.listAppend(line);*/ - } - - if (current_monster != $monster[none]) - { - string [int] monster_description; - CopiedMonstersGenerateDescriptionForMonster(current_monster, monster_description, true, true); - string line = HTMLGenerateSpanOfClass("Currently have " + current_monster.to_string() + ".", "r_bold"); - if (monster_description.count() > 0) - line += "|*" + monster_description.listJoinComponents("|*"); - description.listPrepend(line); - } - //resource_entries.listAppend(ChecklistEntryMake("__item fancy oil painting", url, ChecklistSubentryMake(header, "", description))); - - - copy_source_entry.subentries.listAppend(ChecklistSubentryMake(header, "", description)); - if (copy_source_entry.image_lookup_name == "") - copy_source_entry.image_lookup_name = "__item fancy oil painting"; - if (copy_source_entry.url == "") - copy_source_entry.url = "place.php?whichplace=chateau"; - } - if (copies_left > 0) - { - string [int] copy_source_list; - if (have_spooky_putty) - copy_source_list.listAppend("spooky putty"); - if ($item[Rain-Doh black box].available_amount() + $item[rain-doh box full of monster].available_amount() > 0) - copy_source_list.listAppend("rain-doh black box"); - - string copy_sources = copy_source_list.listJoinComponents("/"); - string name = ""; - //FIXME make this possibly say which one in the case of 6 (does that matter? how does that mechanic work?) - name = pluralise(copies_left, copy_sources + " copy", copy_sources + " copies") + " left"; - string [int] description;// = potential_copies; - - //resource_entries.listAppend(ChecklistEntryMake(copy_source_list[0], "", ChecklistSubentryMake(name, "", description))); - - copy_source_entry.subentries.listAppend(ChecklistSubentryMake(name, "", description)); - if (copy_source_entry.image_lookup_name == "") - copy_source_entry.image_lookup_name = copy_source_list[0]; - } - - if (!get_property_boolean("_cameraUsed") && (get_property("cameraMonster") == "") && $item[4-d camera].available_amount() > 0) - { - //resource_entries.listAppend(ChecklistEntryMake("__item 4-d camera", "", ChecklistSubentryMake("4-d camera copy available", "", potential_copies))); - - copy_source_entry.subentries.listAppend(ChecklistSubentryMake("4-d camera copy available", "", "")); - if (copy_source_entry.image_lookup_name == "") - copy_source_entry.image_lookup_name = "__item 4-d camera"; - } - if (!get_property_boolean("_iceSculptureUsed") && $item[unfinished ice sculpture].available_amount() > 0) - { - //resource_entries.listAppend(ChecklistEntryMake("__item unfinished ice sculpture", "", ChecklistSubentryMake("Ice sculpture copy available", "", potential_copies))); - - copy_source_entry.subentries.listAppend(ChecklistSubentryMake("Ice sculpture copy available", "", "")); - if (copy_source_entry.image_lookup_name == "") - copy_source_entry.image_lookup_name = "__item unfinished ice sculpture"; - } - if ($item[sticky clay homunculus].available_amount() > 0) - { - //resource_entries.listAppend(ChecklistEntryMake("__item sticky clay homunculus", "", ChecklistSubentryMake(pluralise($item[sticky clay homunculus].available_amount(), "sticky clay copy", "sticky clay copies") + " available", "", "Unlimited/day."))); - - copy_source_entry.subentries.listAppend(ChecklistSubentryMake(pluralise($item[sticky clay homunculus].available_amount(), "sticky clay copy", "sticky clay copies") + " available", "", "Unlimited/day.")); - if (copy_source_entry.image_lookup_name == "") - copy_source_entry.image_lookup_name = "__item sticky clay homunculus"; - } - if ($item[print screen button].available_amount() > 0) - { - copy_source_entry.subentries.listAppend(ChecklistSubentryMake(pluralise($item[print screen button].available_amount(), "print screen copy", "print screen copies") + " available", "", "")); - if (copy_source_entry.image_lookup_name == "") - copy_source_entry.image_lookup_name = "__item print screen button"; - } - if ($item[LOV Enamorang].available_amount() > 0) - { - copy_source_entry.subentries.listAppend(ChecklistSubentryMake(pluralise($item[LOV Enamorang]), "", "")); - if (copy_source_entry.image_lookup_name == "") - copy_source_entry.image_lookup_name = "__item lov enamorang"; - } - if (!get_property_boolean("_crappyCameraUsed") && $item[crappy camera].available_amount() > 0) - { - string [int] description;// = listCopy(potential_copies); - description.listPrepend("50% success rate"); - //resource_entries.listAppend(ChecklistEntryMake("__item crappy camera", "", ChecklistSubentryMake("Crappy camera copy available", "", description))); - - - copy_source_entry.subentries.listAppend(ChecklistSubentryMake("Crappy camera copy available", "", description)); - if (copy_source_entry.image_lookup_name == "") - copy_source_entry.image_lookup_name = "__item crappy camera"; - } - if (copy_source_entry.subentries.count() > 0) - { - ChecklistSubentry last_subentry = copy_source_entry.subentries[copy_source_entry.subentries.count() - 1]; - if (last_subentry.entries.count() > 0 && potential_copies.count() > 0) - { - copy_source_entry.subentries.listAppend(ChecklistSubentryMake("Potential targets:", "", potential_copies)); - } - else - last_subentry.entries.listAppendList(potential_copies); - resource_entries.listAppend(copy_source_entry); - } - - //Copies made: - - - generateCopiedMonstersEntry(resource_entries, resource_entries, false); - SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[Rain-Doh box full of monster], "rain doh", "rainDohMonster"); - SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[spooky putty monster], "spooky putty", "spookyPuttyMonster"); - if (!get_property_boolean("_cameraUsed")) - SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[shaking 4-d camera], "shaking 4-d camera", "cameraMonster"); - if (!get_property_boolean("_crappyCameraUsed")) - SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[shaking crappy camera], "shaking crappy camera", "crappyCameraMonster"); - if (!get_property_boolean("_photocopyUsed")) - SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[photocopied monster], "photocopied", "photocopyMonster"); - if (!get_property_boolean("_envyfishEggUsed")) - SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[envyfish egg], "envyfish egg", "envyfishMonster"); - if (!get_property_boolean("_iceSculptureUsed")) - SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[ice sculpture], "ice sculpture", "iceSculptureMonster"); - SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[screencapped monster], "screencapped", "screencappedMonster"); - - //if (__misc_state["Chateau Mantegna available"] && !get_property_boolean("_chateauMonsterFought") && mafiaIsPastRevision(15115)) - //SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[none], "chateau painting", "chateauMonster"); - - SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[wax bugbear], "wax bugbear", "waxMonster"); - SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[crude monster sculpture], "crude sculpture", "crudeMonster"); -} - -void SCopiedMonstersGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - generateCopiedMonstersEntry(task_entries, optional_task_entries, true); - -} diff --git a/Source/relay/TourGuide/Sets/Council.ash b/Source/relay/TourGuide/Sets/Council.ash deleted file mode 100644 index 2b4b191b..00000000 --- a/Source/relay/TourGuide/Sets/Council.ash +++ /dev/null @@ -1,36 +0,0 @@ - -void SCouncilGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__misc_state["in run"]) - return; - if (my_path().id == PATH_COMMUNITY_SERVICE) - return; - boolean council_probably_wants_to_speak_to_you = false; - string [int] reasons; - boolean [string] seen_quest_name; - foreach quest_name in __quest_state - { - QuestState state = __quest_state[quest_name]; - if (state.quest_name == "Island War Quest" && my_path().id == PATH_EXPLOSION) continue; - if (state.startable && !state.in_progress && !state.finished && state.council_quest) - { - if (seen_quest_name[state.quest_name]) - continue; - seen_quest_name[state.quest_name] = true; - reasons.listAppend(state.quest_name); - council_probably_wants_to_speak_to_you = true; - } - } - if (!council_probably_wants_to_speak_to_you) - return; - - string [int] description; - - description.listAppend("Start the " + reasons.listJoinComponents(", ", "and") + "."); - - if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues") && !have_outfit_components("Filthy Hippy Disguise") && __quest_state["Level 12"].startable && !__quest_state["Level 12"].in_progress && !__quest_state["Level 12"].finished && my_path().id != PATH_EXPLOSIONS) - description.listAppend(HTMLGenerateSpanFont("May want to wait", "red") + " until you've acquired a filthy hippy disguise for acquiring a war outfit?"); - if (my_path().id == PATH_EXPLOSIONS) - description.listAppend("You might need to visit your quest log afterwards, to update mafia's tracking."); - task_entries.listAppend(ChecklistEntryMake("council", "place.php?whichplace=town", ChecklistSubentryMake("Visit the Council of Loathing", "", description)).ChecklistEntrySetIDTag("Council visit")); -} diff --git a/Source/relay/TourGuide/Sets/Counters.ash b/Source/relay/TourGuide/Sets/Counters.ash deleted file mode 100644 index c030e347..00000000 --- a/Source/relay/TourGuide/Sets/Counters.ash +++ /dev/null @@ -1,363 +0,0 @@ -import "relay/TourGuide/Support/Counter.ash" -import "relay/TourGuide/Support/Holiday.ash" - - - -location [int] generatePossibleLocationsToBurnDelay() -{ - location [int] possible_locations; - foreach l in __place_delays - { - if (l == $location[the hidden park] && __dense_liana_machete_items.available_amount() > 0) continue; - if (l == $location[the oasis] && $effect[ultrahydrated].have_effect() == 0) continue; - if (l == $location[the hidden apartment building] && get_property_int("hiddenApartmentProgress") >= 7) continue; - if (l == $location[the hidden office building] && get_property_int("hiddenOfficeProgress") >= 7) continue; - if ($locations[the spooky forest,the outskirts of cobb's knob] contains l && (my_path().id == PATH_COMMUNITY_SERVICE || __misc_state["in CS aftercore"] || my_path().id == PATH_GREY_GOO)) continue; - - if (l.delayRemainingInLocation() > 0 && l.locationAvailable()) - possible_locations.listAppend(l); - } - return possible_locations; -} -void SCountersInit() -{ - CountersInit(); -} - -string [int] SCountersGenerateDescriptionForRainMonster() -{ - string [int] description; - - string last_terrain = __last_adventure_location.environment; - - string [int] waterbending_skills_can_cast; - - if ($effect[Personal Thundercloud].have_effect() == 0 && $skill[Thundercloud].skill_is_usable()) - waterbending_skills_can_cast.listAppend("Thundercloud"); - - if ($effect[The Rain In Loathing].have_effect() == 0 && $skill[Rainy Day].skill_is_usable()) - waterbending_skills_can_cast.listAppend("Rainy Day"); - - int water_level_modifier = numeric_modifier("water level"); - - string [string][int] monster_for_terrain_depth; - int [string] base_depth_for_terrain; - - foreach terrain in $strings[underground,indoor,outdoor] - { - monster_for_terrain_depth[terrain][1] = "giant isopod"; - monster_for_terrain_depth[terrain][2] = "gourmet gourami"; - monster_for_terrain_depth[terrain][3] = "freshwater bonefish"; - monster_for_terrain_depth[terrain][4] = "alley catfish"; - monster_for_terrain_depth[terrain][5] = "piranhadon"; - } - base_depth_for_terrain["underground"] = 5; - base_depth_for_terrain["indoor"] = 3; - base_depth_for_terrain["outdoor"] = 1; - monster_for_terrain_depth["underground"][6] = "giant tardigrade"; - monster_for_terrain_depth["indoor"][6] = "aquaconda"; - monster_for_terrain_depth["outdoor"][6] = "storm cow"; - - string [string] monster_descriptions; - monster_descriptions["giant isopod"] = "fishbone"; - monster_descriptions["freshwater bonefish"] = "2x fishbone"; - monster_descriptions["piranhadon"] = "3x fishbone"; - monster_descriptions["gourmet gourami"] = "+init potion"; - monster_descriptions["alley catfish"] = "-washaway potion"; - - //init potion - //-washaway potion - // - - monster_descriptions["giant tardigrade"] = "thunder skill"; - monster_descriptions["aquaconda"] = "rain skill"; - monster_descriptions["storm cow"] = "lightning skill"; - - if (__iotms_usable[$item[Little Geneticist DNA-Splicing Lab]] && mafiaIsPastRevision(13918) && !get_property_boolean("_dnaHybrid") && $effect[Human-Fish Hybrid].have_effect() == 0 && !__misc_state["familiars temporarily blocked"]) - { - //FIXME all once spaded - //NOT giant isopod - //gourmet gourami? - //freshwater bonefish - //alley catfish - //piranhadon - foreach s in $strings[gourmet gourami,freshwater bonefish,alley catfish,piranhadon] - { - monster_descriptions[s] = monster_descriptions[s] + " (fish DNA)"; - } - } - - - if (my_mp() > 50) - { - monster_descriptions["storm cow"] += HTMLGenerateSpanFont(", burn MP to 50 to survive", "red"); - } - - boolean have_usable_last_terrain = (last_terrain == "outdoor" || last_terrain == "indoor" || last_terrain == "underground"); - foreach terrain in $strings[outdoor,indoor,underground] - { - int depth_min = base_depth_for_terrain[terrain] + water_level_modifier; - int depth_max = depth_min + 1; - - depth_min = clampi(depth_min, 1, 6); - depth_max = clampi(depth_max, 1, 6); - - string [int] terrain_monsters; - string line = monster_for_terrain_depth[terrain][depth_min]; - //if (monster_descriptions contains line) - //line += " (" + monster_descriptions[line] + ")"; - if (monster_descriptions contains line) - line = monster_descriptions[line]; - if (last_terrain == terrain && (__last_adventure_location.recommended_stat < 40 || depth_min == depth_max)) - line = HTMLGenerateSpanOfClass(line, "r_bold"); - terrain_monsters.listAppend(line); - - if (depth_min != depth_max) - { - line = monster_for_terrain_depth[terrain][depth_max]; - //if (monster_descriptions contains line) - //line += " (" + monster_descriptions[line] + ")"; - if (monster_descriptions contains line) - line = monster_descriptions[line]; - if (last_terrain == terrain && __last_adventure_location.recommended_stat >= 40) - line = HTMLGenerateSpanOfClass(line, "r_bold"); - terrain_monsters.listAppend(line); - } - - line = terrain.capitaliseFirstLetter() + ": "; - if (!have_usable_last_terrain || last_terrain == terrain) - line = HTMLGenerateSpanOfClass(line, "r_bold"); - line += terrain_monsters.listJoinComponents(", ", "or"); - //if (last_terrain == terrain) - //line = HTMLGenerateSpanOfClass(line, "r_bold"); - description.listAppend(line); - } - - if (waterbending_skills_can_cast.count() > 0) - description.listAppend("Can cast " + waterbending_skills_can_cast.listJoinComponents(", ", "and") + " for deeper water."); - - - return description; -} - -void SCountersGenerateEntry(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, boolean from_task) -{ - string [string] window_image_names; - window_image_names["Nemesis Assassin"] = "__familiar Penguin Goodfella"; //technically not always a penguin, but.. - window_image_names["Bee"] = "__effect Float Like a Butterfly, Smell Like a Bee"; //bzzz! - window_image_names["Holiday Monster"] = "__familiar hand turkey"; - if (getHolidaysToday()["El Dia De Los Muertos Borrachos"]) - window_image_names["Holiday Monster"] = "__item corpse island iced tea"; - window_image_names["Rain Monster"] = "__familiar personal raincloud"; - window_image_names["WoL Monster"] = "__effect Cowrruption"; - window_image_names["Digitize Monster"] = "__item source essence"; - window_image_names["Romantic Monster"] = "__familiar " + __misc_state_string["obtuse angel name"]; - window_image_names["Enamorang Monster"] = "__item lov enamorang"; - window_image_names["portscan.edu"] = "__item gyroscope"; - //window_image_names["Event Monster"] = ""; //no idea - - - - boolean [string] counter_blacklist = $strings[Semi-rare]; //Romantic Monster, - boolean [string] non_range_whitelist = $strings[Digitize Monster,Enamorang Monster,portscan.edu]; - - string [int] all_counter_names = CounterGetAllNames(true); - - foreach key in all_counter_names - { - string window_name = all_counter_names[key]; - if (window_name == "") - continue; - if (counter_blacklist contains window_name) - continue; - - Counter c = CounterLookup(window_name, ErrorMake(), true); - if (!c.CounterIsRange() && !(non_range_whitelist contains window_name)) - continue; - boolean counter_is_range = c.CounterIsRange(); - Vec2i turn_range = c.CounterGetWindowRange(); - int next_exact_turn = c.CounterGetNextExactTurn(); - - if (counter_is_range && !(turn_range.x <= 10 && from_task) && !(turn_range.x > 10 && !from_task) && window_name != "Romantic Monster") - continue; - - //print_html("c = " + c.to_json()); - boolean very_important = false; - if (turn_range.x <= 0 && counter_is_range) - very_important = true; - if (!counter_is_range && next_exact_turn <= 3) //warn three turns ahead - very_important = true; - - - ChecklistSubentry subentry; - string url; - string window_display_name = window_name; - - monster fighting_monster; - if (window_name == "Digitize Monster") - { - fighting_monster = get_property_monster("_sourceTerminalDigitizeMonster"); - string monster_name = fighting_monster.to_lower_case(); - if (monster_name == "") - window_display_name = "Digitised monster"; - else - window_display_name = "Digitised " + monster_name; - } - if (window_name == "Enamorang Monster") - { - fighting_monster = get_property_monster("enamorangMonster"); - string monster_name = fighting_monster.to_lower_case(); - if (monster_name == "") - window_display_name = "Boomerang'd monster"; - else - window_display_name = "Boomerang'd " + monster_name; - } - if (window_name == "Romantic Monster") - { - fighting_monster = get_property_monster("romanticTarget"); - window_display_name = "Arrowed " + __misc_state_string["Romantic Monster Name"].to_lower_case() + " (" + get_property_int("_romanticFightsLeft") + " left)"; - } - if (window_name == "Nemesis Assassin" && __quest_state["Nemesis"].mafia_internal_step >= 26) - { - //someone reported they saw this window after going past the relevant quest step; safety ignore - continue; - } - if (window_name == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) - continue; - subentry.header = window_display_name; - - - if (!counter_is_range) - { - if (next_exact_turn <= 0) - subentry.header += HTMLGenerateSpanFont(" now", "red"); - else - subentry.header += " after " + pluralise(next_exact_turn, "More Turn", "more turns"); - } - else if (turn_range.y <= 0) - subentry.header += " now or soon"; - else if (turn_range.x <= 0) - subentry.header += " between now and " + turn_range.y + " turns."; - else - subentry.header += " in [" + turn_range.x + " to " + turn_range.y + "] turns."; - - - if (window_name == "Digitize Monster") - { - //Display next window: - int next_window_count = get_property_int("_sourceTerminalDigitizeMonsterCount") + 1; - //Vec2i next_window_range = Vec2iMake(15 + 10 * next_window_count, 25 + 10 * next_window_count); - int next_turn_count = next_window_count * 10 + 10; - //subentry.entries.listAppend("Next window will be [" + next_window_range.x + " to " + next_window_range.y + "] turns."); - subentry.entries.listAppend("Next gap will be " + next_turn_count + " turns."); - - //calculate the limit: - boolean [string] chips = getInstalledSourceTerminalSingleChips(); - int digitisations = get_property_int("_sourceTerminalDigitizeUses"); - int digitisation_limit = 1; - if (chips["TRAM"]) - digitisation_limit += 1; - if (chips["TRIGRAM"]) - digitisation_limit += 1; - int digitisations_left = clampi(digitisation_limit - digitisations, 0, 3); - if (get_property_int("_sourceTerminalDigitizeMonsterCount") >= 2 && digitisations < digitisation_limit) - subentry.entries.listAppend("Could re-digitise to reset the window."); - } - if (window_name == "Rain Monster" && my_path() == $path[Heavy Rains]) - { - // Adding a note here -- there was a bug report that multiple people hit - // this counter outside of heavy rains. I have no idea what was going - // wrong here; feels like a mafia pref issue of something? Dunno. - - // Still adding a big note so that it's easier to find this file if - // this recurs for a user. - - subentry.entries = SCountersGenerateDescriptionForRainMonster(); - } - if (fighting_monster != $monster[none]) - { - CopiedMonstersGenerateDescriptionForMonster(fighting_monster, subentry.entries, (turn_range.x <= 0), false); - } - if (c.waiting_for_adventure_php) - subentry.entries.listAppend("Need to adventure in adventure.php to start counting."); - - if (turn_range.x <= 0) // && counter_is_range || (!counter_is_range && next_exact_turn <= 0)) - { - if (my_path().id != PATH_COMMUNITY_SERVICE && __misc_state["in run"]) - { - if (window_name == "portscan.edu" && $skill[macrometeorite].skill_is_usable() && get_property_int("_macrometeoriteUses") < 10 && !__quest_state["Level 12"].finished && !__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) - { - subentry.entries.listAppend("Adventure in sonofa beach, macrometeorite the government agent to gain a LFM."); - url = $location[sonofa beach].getClickableURLForLocation(); - } - location [int] possible_locations = generatePossibleLocationsToBurnDelay(); - if (possible_locations.count() > 0) - { - subentry.entries.listAppend("Adventure in " + possible_locations.listJoinComponents(", ", "or") + " to burn delay."); - if (url == "") - url = possible_locations[0].getClickableURLForLocation(); - } - } - /*if (get_property_boolean("dailyDungeonDone")) - { - url = "da.php"; - subentry.entries.listAppend("Could check for free in the daily dungeon."); - } - else if (get_property_int("hiddenApartmentProgress") >= 1 && get_property_int("hiddenBowlingAlleyProgress") >= 1 && get_property_int("hiddenHospitalProgress") >= 1 && get_property_int("hiddenOfficeProgress") >= 1) //we could support suggesting each shrine individually, but effort - { - url = $location[the hidden park].getClickableURLForLocation(); - subentry.entries.listAppend("Could check for free in one of the shrines."); - }*/ - } - - string image_name = "__item Pokëmann figurine: Frank"; //default - some person - if (window_image_names contains window_name) - image_name = window_image_names[window_name]; - - int importance = 10; - if (very_important) - importance = -11; - ChecklistEntry entry = ChecklistEntryMake(image_name, url, subentry, importance); - entry.tags.id = window_name + " counter"; - - if (very_important) - task_entries.listAppend(entry); - else - optional_task_entries.listAppend(entry); - - } -} - -void SCountersGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (true) - { - //dance card: - int turns_until_dance_card = CounterLookup("Dance Card").CounterGetNextExactTurn(); - - if (turns_until_dance_card >= 0) - { - string stats = "Gives ~" + __misc_state_float["dance card average stats"].round() + " "; - if (my_primestat() == $stat[moxie]) - stats += "mainstat"; - else - stats += "moxie"; - stats += "."; - if (turns_until_dance_card == 0) - { - task_entries.listAppend(ChecklistEntryMake("__item dance card", $location[the haunted ballroom].getClickableURLForLocation(), ChecklistSubentryMake("Dance card up now.", "", "Adventure in haunted ballroom. " + stats), -11).ChecklistEntrySetIDTag("Counter").ChecklistEntrySetIDTag("Dance card counter now")); - } - else - { - optional_task_entries.listAppend(ChecklistEntryMake("__item dance card", "", ChecklistSubentryMake("Dance card up after " + pluralise(turns_until_dance_card, "adventure", "adventures") + ".", "", "Haunted ballroom. " + stats)).ChecklistEntrySetIDTag("Dance card counter soon")); - } - } - } - - SCountersGenerateEntry(task_entries, optional_task_entries, true); -} - -void SCountersGenerateResource(ChecklistEntry [int] resource_entries) -{ - SCountersGenerateEntry(resource_entries, resource_entries, false); -} diff --git a/Source/relay/TourGuide/Sets/Crepe Parachute.ash b/Source/relay/TourGuide/Sets/Crepe Parachute.ash deleted file mode 100644 index f8398332..00000000 --- a/Source/relay/TourGuide/Sets/Crepe Parachute.ash +++ /dev/null @@ -1,15 +0,0 @@ -//Crepe Parachute -RegisterTaskGenerationFunction("CrepeParachuteGenerateTasks"); -void CrepeParachuteGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[crepe paper parachute cape].available_amount() == 0) return; - - string url = "inventory.php?action=parachute&pwd=" + my_hash(); - // Beige Map - if ($effect[Everything Looks Beige].have_effect() == 0) - { - string [int] description; - description.listAppend(HTMLGenerateSpanFont("It's mapparachute time!", "orange")); - task_entries.listAppend(ChecklistEntryMake("__item crepe paper parachute cape", url, ChecklistSubentryMake("Crepe Parachute ready", "", description), -11)); - } -} diff --git a/Source/relay/TourGuide/Sets/Daily Dungeon.ash b/Source/relay/TourGuide/Sets/Daily Dungeon.ash deleted file mode 100644 index 5005965f..00000000 --- a/Source/relay/TourGuide/Sets/Daily Dungeon.ash +++ /dev/null @@ -1,276 +0,0 @@ -//Lock Picking -RegisterTaskGenerationFunction("LockPickingGenerateTasks"); -void LockPickingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (get_property_boolean("lockPicked") == true || !lookupSkill("Lock Picking").have_skill()) - return; - { - string [int] description; - string main_title = "Pick a lock!"; - description.listAppend("Grab your mainstat key, probably."); - task_entries.listAppend(ChecklistEntryMake("__skill lock picking", "skillz.php", ChecklistSubentryMake(main_title, "", description), -11)); - } -} - -void SDailyDungeonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) { - return; - } - - if (__last_adventure_location == $location[The Daily Dungeon]) - { - if ($item[ring of detect boring doors].equipped_amount() == 0 && $item[ring of detect boring doors].available_amount() > 0 && !get_property_boolean("dailyDungeonDone") && get_property_int("_lastDailyDungeonRoom") < 10) - { - task_entries.listAppend(ChecklistEntryMake("__item ring of detect boring doors", "inventory.php?ftext=ring+of+detect+boring+doors", ChecklistSubentryMake("Wear ring of detect boring doors", "", "Speeds up daily dungeon"), -11).ChecklistEntrySetIDTag("Daily dungeon detect boring door reminder")); - } - if (familiar_is_usable($familiar[gelatinous cubeling]) && ($item[pick-o-matic lockpicks].available_amount() == 0 || $item[eleven-foot pole].available_amount() == 0 || $item[Ring of Detect Boring Doors].available_amount() == 0)) //have familiar, but not the drops - { - task_entries.listAppend(ChecklistEntryMake("__familiar gelatinous cubeling", "", ChecklistSubentryMake("Use a gelatinous cubeling first", "", "You're adventuring in the daily dungeon without cubeling drops."), -11).ChecklistEntrySetIDTag("Daily dungeon gelatinous cubeling drops reminder")); - } - } - - - boolean need_to_do_daily_dungeon = false; - - if (__misc_state_int["fat loot tokens needed"] > 0) - need_to_do_daily_dungeon = true; - - string [int] daily_dungeon_aftercore_items_wanted; - - if (__misc_state["in aftercore"]) - { - int tokens_needed = 0; - if (!__misc_state["familiars temporarily missing"]) - { - if (!have_familiar_replacement($familiar[gelatinous cubeling]) && $item[dried gelatinous cube].available_amount() == 0) - { - daily_dungeon_aftercore_items_wanted.listAppend("gelatinous cubeling"); - tokens_needed += 27; - } - } - if (!__misc_state["skills temporarily missing"]) - { - if (!$skill[singer's faithful ocelot].skill_is_usable() && $item[Spellbook: Singer's Faithful Ocelot].available_amount() == 0) - { - daily_dungeon_aftercore_items_wanted.listAppend("Singer's faithful ocelot"); - tokens_needed += 15; - } - if (!$skill[Drescher's Annoying Noise].skill_is_usable() && $item[Spellbook: Drescher's Annoying Noise].available_amount() == 0) - { - daily_dungeon_aftercore_items_wanted.listAppend("Drescher's Annoying Noise"); - tokens_needed += 15; - } - if (!$skill[Walberg's Dim Bulb].skill_is_usable() && $item[Spellbook: Walberg's Dim Bulb].available_amount() == 0) - { - daily_dungeon_aftercore_items_wanted.listAppend("Walberg's Dim Bulb"); - tokens_needed += 15; - } - } - if (tokens_needed > $item[fat loot token].available_amount()) - { - need_to_do_daily_dungeon = true; - __misc_state_int["fat loot tokens needed"] += tokens_needed - $item[fat loot token].available_amount(); - } - } - //When we're down to two potential skeleton keys, mention they shouldn't use them in the door. - int skeleton_key_amount = $item[skeleton key].available_amount() + $item[skeleton key].creatable_amount(); - boolean avoid_using_skeleton_key = ($item[Platinum Yendorian Express Card].available_amount() == 0 && $item[pick-o-matic lockpicks].available_amount() == 0 && (skeleton_key_amount) <= 2 && skeleton_key_amount > 0 && !__quest_state["Level 13"].state_boolean["Past keys"] && in_ronin()); - - boolean delay_daily_dungeon = false; - string delay_daily_dungeon_reason = ""; - if (need_to_do_daily_dungeon) - { - if (familiar_is_usable($familiar[gelatinous cubeling])) - { - item [int] missing_items; - string gelatinousCubelingProgress = get_property("cubelingProgress"); - int priority = CHECKLIST_DEFAULT_IMPORTANCE; - - missing_items = $items[eleven-foot pole,ring of detect boring doors,pick-o-matic lockpicks].items_missing(); - if (missing_items.count() > 0) - { - delay_daily_dungeon = true; - delay_daily_dungeon_reason = "Bring along the gelatinous cubeling first"; - ChecklistSubentry subentry; - - string url = ""; - if (my_familiar() != $familiar[gelatinous cubeling]) - url = "familiar.php"; - - // Cubeling progress added to the tile - int progress = get_property_int("cubelingProgress"); - subentry.header = (12 - progress).pluralise("Gelatinous Cubeling kill", "Gelatinous Cubeling kills") + " remaining"; - - subentry.entries.listAppend("Acquire " + missing_items.listJoinComponents(", ", "and") + " to speed up the daily dungeon."); - - if (missing_items.count() == 1 && missing_items[0] == $item[pick-o-matic lockpicks] && skeleton_key_amount > 1) - { - subentry.entries.listAppend("Or ignore this and use the skeleton keys. (slightly risky)"); - priority = 8; - } - - optional_task_entries.listAppend(ChecklistEntryMake("__familiar gelatinous cubeling", url, subentry, priority).ChecklistEntrySetIDTag("Daily dungeon gelatinous cubeling reminder")); - } - } - else - { - //No gelatinous cubeling. - //But! We can acquire a skeleton key in-run. - //So suggest doing that: - boolean can_make_skeleton_key = ($items[loose teeth,skeleton bone].items_missing().count() == 0); - - if (!avoid_using_skeleton_key && ($item[pick-o-matic lockpicks].available_amount() == 0 && $item[Platinum Yendorian Express Card].available_amount() == 0 && $item[skeleton key].available_amount() == 0 && (!__quest_state["Level 7"].state_boolean["nook finished"] || can_make_skeleton_key))) //they don't have lockpicks or a key, and they can reasonably acquire a key - { - delay_daily_dungeon = true; - if (can_make_skeleton_key) - delay_daily_dungeon_reason = "Make a skeleton key first. (you have the ingredients)"; - else - { - delay_daily_dungeon_reason = "Acquire a skeleton key first. (from defiled nook)"; - if (!in_bad_moon() && my_path().id != PATH_OXYGENARIAN) //FIXME state track this elsewhere - delay_daily_dungeon_reason += "|Unless you can't reach that by the end of today."; - } - - - if (can_make_skeleton_key) - { - ChecklistEntry cl = ChecklistEntryMake("__item skeleton key", "", ChecklistSubentryMake("Make a skeleton key", "", listMake("You have the ingredients.", "Speeds up the daily dungeon."))); - cl.tags.id = "Daily dungeon skeleton key reminder"; - if (__last_adventure_location == $location[The Daily Dungeon]) - { - cl.importance_level = -11; - task_entries.listAppend(cl); - } - else - optional_task_entries.listAppend(cl); - } - } - } - } - - - //Pop up a warning: - if (__last_adventure_location == $location[the daily dungeon] && avoid_using_skeleton_key && $item[skeleton key].available_amount() > 0) - { - task_entries.listAppend(ChecklistEntryMake("__item skeleton key", "", ChecklistSubentryMake("Avoid using the skeleton key in the daily dungeon", "", listMake("Running low, will need one for the tower.")), -11).ChecklistEntrySetIDTag("Daily dungeon skeleton key avoid")); - } - - if (get_property_int("_lastDailyDungeonRoom") > 0) - need_to_do_daily_dungeon = true; - if (need_to_do_daily_dungeon && !get_property_boolean("dailyDungeonDone")) - { - if (delay_daily_dungeon) - { - future_task_entries.listAppend(ChecklistEntryMake("daily dungeon", "da.php", ChecklistSubentryMake("Daily Dungeon", "", delay_daily_dungeon_reason), $locations[the daily dungeon]).ChecklistEntrySetIDTag("Daily dungeon later")); - } - else - { - string url = "da.php"; - string [int] description; - string l; - - if (__misc_state_int["fat loot tokens needed"] > 0) - l = pluralise(__misc_state_int["fat loot tokens needed"], "token", "tokens") + " needed."; - - if (daily_dungeon_aftercore_items_wanted.count() > 0) - { - if (l != "") - l += "|"; - l += "Missing " + daily_dungeon_aftercore_items_wanted.listJoinComponents(", ", "and") + ". Possibly buy "; - if (daily_dungeon_aftercore_items_wanted.count() > 1) - l += "them"; - else - l += "it"; - l += " in the mall?"; - } - if (l != "") - description.listAppend(l); - if (!__misc_state["in aftercore"]) - { - string submessage = ""; - if (familiar_is_usable($familiar[gelatinous cubeling])) - submessage = ""; - if (__misc_state["zap wand available"] && __misc_state_int["DD Tokens and keys available"] > 0) - submessage = "Or zap for it"; - if (submessage != "") - description.listAppend(submessage); - } - - if (!in_ronin() && !have_familiar_replacement($familiar[gelatinous cubeling])) - { - string [int] shopping_list; - foreach it in $items[eleven-foot pole,ring of detect boring doors,pick-o-matic lockpicks] - { - if (it.available_amount() > 0) - continue; - if (it == $item[pick-o-matic lockpicks] && $item[skeleton key].available_amount() > 0) - continue; - shopping_list.listAppend(it); - } - if (shopping_list.count() > 0) - description.listAppend("Buy " + shopping_list.listJoinComponents(", ", "and") + " from mall."); - } - - int rooms_left = MAX(0, 15 - get_property_int("_lastDailyDungeonRoom")); - boolean need_ring = true; - if (get_property_int("_lastDailyDungeonRoom") > 10) - { - need_ring = false; - } - if ($item[ring of detect boring doors].available_amount() > 0 && need_ring) - { - if ($item[ring of detect boring doors].equipped_amount() == 0) - { - url = "inventory.php?ftext=ring+of+detect+boring+doors"; - description.listAppend("Wear the ring of detect boring doors."); - } - else - description.listAppend("Keep the ring of detect boring doors equipped."); - } - - - if (rooms_left < 15) - description.listAppend(pluraliseWordy(rooms_left, "room", "rooms").capitaliseFirstLetter() + " left."); - - if (avoid_using_skeleton_key && $item[skeleton key].available_amount() > 0) - description.listAppend(HTMLGenerateSpanOfClass("Avoid using your skeleton key, you don't have many left.", "r_bold")); - - optional_task_entries.listAppend(ChecklistEntryMake("daily dungeon", url, ChecklistSubentryMake("Daily Dungeon", "", description), $locations[the daily dungeon]).ChecklistEntrySetIDTag("Daily dungeon today")); - } - } - -} - -void SDailyDungeonGenerateMissingItems(ChecklistEntry [int] items_needed_entries) -{ - string url = "da.php"; - if (my_path().id == PATH_KINGDOM_OF_EXPLOATHING) - url = "shop.php?whichshop=exploathing"; - - string from_daily_dungeon_string = "From daily dungeon"; - if ($item[fat loot token].available_amount() > 0) - from_daily_dungeon_string += "|" + pluralise($item[fat loot token]) + " available"; - - if ($item[sneaky pete\'s key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["Sneaky Pete\'s key used"]) { - string [int] options; - options.listAppend(from_daily_dungeon_string); - if (__misc_state_int["pulls available"] > 0 && __misc_state["can eat just about anything"] && $item[sneaky pete's key lime pie].item_is_usable()) - options.listAppend("From key lime pie"); - items_needed_entries.listAppend(ChecklistEntryMake("__item Sneaky Pete\'s key", url, ChecklistSubentryMake("Sneaky Pete\'s key", "", options)).ChecklistEntrySetIDTag("Daily dungeon key sneaky_pete")); - } - if ($item[jarlsberg\'s key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["Jarlsberg\'s key used"]) { - string [int] options; - options.listAppend(from_daily_dungeon_string); - if (__misc_state_int["pulls available"] > 0 && __misc_state["can eat just about anything"] && $item[jarlsberg's key lime pie].item_is_usable()) - options.listAppend("From key lime pie"); - items_needed_entries.listAppend(ChecklistEntryMake("__item jarlsberg's key", url, ChecklistSubentryMake("Jarlsberg's key", "", options)).ChecklistEntrySetIDTag("Daily dungeon key jarlsberg")); - } - if ($item[Boris\'s key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["Boris\'s key used"]) { - string [int] options; - options.listAppend(from_daily_dungeon_string); - if (__misc_state_int["pulls available"] > 0 && __misc_state["can eat just about anything"] && $item[boris's key lime pie].item_is_usable()) - options.listAppend("From key lime pie"); - items_needed_entries.listAppend(ChecklistEntryMake("__item Boris's key", url, ChecklistSubentryMake("Boris's key", "", options)).ChecklistEntrySetIDTag("Daily dungeon key boris")); - } -} diff --git a/Source/relay/TourGuide/Sets/Demon Summon.ash b/Source/relay/TourGuide/Sets/Demon Summon.ash deleted file mode 100644 index ce7abd9b..00000000 --- a/Source/relay/TourGuide/Sets/Demon Summon.ash +++ /dev/null @@ -1,79 +0,0 @@ -//demonSummoned -RegisterResourceGenerationFunction("SDemonSummonGenerateResource"); -void SDemonSummonGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!QuestState("questL11Manor").finished || my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) - return; - if (get_property_boolean("demonSummoned")) - return; - //thin black candle >= 3 - //scroll of ancient forbidden unspeakable evil - //FIXME suggest running intergnat? - - if ($item[thin black candle].available_amount() >= 3 && $item[scroll of ancient forbidden unspeakable evil].available_amount() + $item[scroll of ancient forbidden unspeakable evil].creatable_amount() > 0) - { - string [int] description; - string url = "place.php?whichplace=manor4&action=manor4_chamber"; - - if ($item[thin black candle].item_amount() < 3 && $item[thin black candle].available_amount() >= 3) - { - description.listAppend("Pull 3 thin black candles."); - url = ""; - } - if ($item[scroll of ancient forbidden unspeakable evil].available_amount() == 0 && $item[scroll of ancient forbidden unspeakable evil].creatable_amount() > 0) - { - description.listAppend("Create a scroll of ancient forbidden unspeakable evil."); - url = ""; - } - - string [int][int] john; - //Prenatural greed. - string [string] demons; - demons["demonName2"] = "+100% meat"; - if ($familiar[intergnat].familiar_is_usable() && in_ronin()) - { - if (!get_property("demonName12").contains_text("Neil")) //FIXME what if neil is on their friends list? - { - description.listAppend("Could run intergnat for demon name."); - } - else - { - if (my_level() == 11) - { - if (__dense_liana_machete_items.available_amount() == 0) - demons["demonName12"] += "Antique machete, tomb ratchet, and cigarette lighter."; - else - demons["demonName12"] += "Tomb ratchet, and cigarette lighter."; - } - else if (my_level() == 12) - { - if ($items[richard's star key,star chart].available_amount() == 0) - demons["demonName12"] += "Star chart."; - } - else if (my_level() == 13) - demons["demonName12"] += "+50% init buff."; - else - demons["demonName12"] += "1000 meat."; - if (demons["demonName12"] != "") - demons["demonName12"] += "|"; - demons["demonName12"] += "+10% item, +20% meat, +50% init, +spell/weapon damage buff."; - if (my_familiar() != $familiar[intergnat]) - demons["demonName12"] += "|Make sure to switch to your intergnat familiar before summoning."; - } - } - //Intergnat. - - foreach property, description in demons - { - string property_value = get_property(property); - if (property_value == "") - continue; - john.listAppend(listMake(property_value, description)); - } - - if (john.count() > 0) - description.listAppend(HTMLGenerateSimpleTableLines(john)); - - resource_entries.listAppend(ChecklistEntryMake("__item thin black candle", url, ChecklistSubentryMake("Demon summonable", "", description), 7).ChecklistEntrySetIDTag("Manor demon summoning")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets/Dispensary.ash b/Source/relay/TourGuide/Sets/Dispensary.ash deleted file mode 100644 index 9fc45356..00000000 --- a/Source/relay/TourGuide/Sets/Dispensary.ash +++ /dev/null @@ -1,49 +0,0 @@ -void SDispensaryGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //Not sure how I feel about this. The dispensary is very useful, but not necessary to complete an ascension. - if (dispensary_available()) - return; - //It's even less useful now that they've changed the buffs. Sorry, dispensary. - if (true) - return; - if (!__misc_state["can equip just about any weapon"]) //need to wear KGE to learn the password - return; - - if (!__quest_state["Level 5"].started || !$location[cobb's knob barracks].locationAvailable()) - return; - if (__quest_state["Level 5"].finished && !have_outfit_components("Knob Goblin Elite Guard Uniform")) //level 5 quest completed, but they don't have KGE - I think we'll close the suggestion here, as they probably don't want to go back? maybe? it'll still show up in semi-rare if they care to - return; - if (!have_outfit_components("Knob Goblin Elite Guard Uniform") && __misc_state["in run"]) //don't bother unless they have the uniform - return; - - ChecklistSubentry subentry; - subentry.header = "Unlock Cobb's Knob Dispensary"; - - string [int] dispensary_advantages; - if (!black_market_available() && !__misc_state["MMJs buyable"]) - dispensary_advantages.listAppend("MP Restorative"); - dispensary_advantages.listAppend("+30% meat"); - dispensary_advantages.listAppend("+15% items"); - if (my_path().id != PATH_BEES_HATE_YOU && !__misc_state["familiars temporarily blocked"]) - dispensary_advantages.listAppend("+5 familiar weight"); - dispensary_advantages.listAppend("+1 mainstat/fight"); - - if (dispensary_advantages.count() > 0) - subentry.entries.listAppend("Access to " + dispensary_advantages.listJoinComponents(", ", "and") + " buff items."); - - if ($item[Cobb's Knob lab key].available_amount() == 0) - subentry.entries.listAppend("Find the cobb's knob lab key either laying around, or defeat the goblin king."); - else - { - if (have_outfit_components("Knob Goblin Elite Guard Uniform")) - { - if (!is_wearing_outfit("Knob Goblin Elite Guard Uniform")) - subentry.entries.listAppend("Wear KGE outfit, adventure in Cobb's Knob Barracks."); - else - subentry.entries.listAppend("Adventure in Cobb's Knob Barracks."); - } - else - subentry.entries.listAppend("Acquire KGE outfit"); - } - optional_task_entries.listAppend(ChecklistEntryMake("Dispensary", "cobbsknob.php", subentry, 10).ChecklistEntrySetIDTag("Dispensary cobb knob")); -} diff --git a/Source/relay/TourGuide/Sets/Dungeons of Doom.ash b/Source/relay/TourGuide/Sets/Dungeons of Doom.ash deleted file mode 100644 index 9c39e210..00000000 --- a/Source/relay/TourGuide/Sets/Dungeons of Doom.ash +++ /dev/null @@ -1,67 +0,0 @@ - -void SDungeonsOfDoomGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //Let's see... - //Normally, we assume the best path is to fax a quantum mechanic (in HC) or pull a large box (in SC) - //However, that won't work for paths without a fax machine, or for people without a VIP key, or for people who desire to open the dungeons of doom regardless. - //So, we suggest it in those cases. - //We also want to work in aftercore - if they haven't unlocked the DOD yet and they've started, give suggestions. - - //lastPlusSignUnlock is set by the oracle, not reading the book. - string title = "Dungeons of Doom"; - string image_name = "Dungeons of Doom"; - string [int] description; - string [int] modifiers; - string url = "da.php"; - - boolean should_output = true; - - int turns_attempted = $location[The Enormous Greater-Than Sign].turnsAttemptedInLocation() + $location[the dungeons of doom].turnsAttemptedInLocation(); - - if (my_basestat(my_primestat()) < 45) //not yet - return; - if (turns_attempted == 0) //no, they haven't started yet - return; - - if (get_property_ascension("lastPlusSignUnlock")) - { - should_output = false; - //Dungeons of doom unlocked. - if ($item[plus sign].available_amount() > 0) - { - should_output = true; - //Read plus sign: - title = "Read plus sign"; - image_name = "__item plus sign"; - url = "inventory.php?ftext=plus+sign"; - } - } - else - { - boolean adventuring_in_sign = true; - string [int] tasks; - if (my_meat() < 1000) - tasks.listAppend("acquire 1000 meat"); - if ($item[plus sign].available_amount() == 0) - tasks.listAppend("acquire plus sign from non-combat"); - else if ($effect[Teleportitis].have_effect() == 0) - tasks.listAppend("acquire teleportitis from non-combat or uppercase Q hitting you"); - else - { - adventuring_in_sign = false; - tasks.listAppend("find the oracle, pay for major consultation"); - } - - title = "Unlock dungeons of doom"; - if (adventuring_in_sign) - { - modifiers.listAppend("-combat"); - description.listAppend("Run -combat in the enormous greater-than sign."); - - } - description.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); - } - - if (should_output) - optional_task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(title, modifiers, description), $locations[the enormous greater-than sign,the dungeons of doom]).ChecklistEntrySetIDTag("Dungeon of doom")); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets/Equipment.ash b/Source/relay/TourGuide/Sets/Equipment.ash deleted file mode 100644 index ad6e8c2b..00000000 --- a/Source/relay/TourGuide/Sets/Equipment.ash +++ /dev/null @@ -1,72 +0,0 @@ - -string [int] SEquipmentGenerateXiblaxianHoloWristPuterDescription() -{ - string [int] description; - string [int][int] table; - table.listAppend(listMake("Outdoor", "polymer")); - table.listAppend(listMake("Indoor", "circuitry")); - table.listAppend(listMake("Underground", "alloy")); - table.listAppend(listMake("Underwater", "polymer")); - //this is kind of a hack: - int index_to_bold = -1; - if (__last_adventure_location.environment == "outdoor") - index_to_bold = 0; - else if (__last_adventure_location.environment == "indoor") - index_to_bold = 1; - else if (__last_adventure_location.environment == "underground") - index_to_bold = 2; - if (__last_adventure_location.environment == "underwater") - index_to_bold = 3; - - if (index_to_bold != -1) - { - foreach key, v in table[index_to_bold] - table[index_to_bold][key] = HTMLGenerateSpanOfClass(v, "r_bold"); - } - description.listAppend(HTMLGenerateSimpleTableLines(table)); - - if (!get_property_boolean("_holoWristCrystal")) - description.listAppend("Can acquire a crystal by mining. (once/day)"); - - string [int] items_owned; - foreach it in $items[Xiblaxian alloy,Xiblaxian circuitry,Xiblaxian polymer,Xiblaxian crystal] - { - if (it.available_amount() > 0) - items_owned.listAppend(it.available_amount() + " " + it); - } - - description.listAppend("Own " + items_owned.listJoinComponents(", ", "and") + "."); - return description; -} - -void SEquipmentGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[Xiblaxian holo-wrist-puter].equipped_amount() > 0) - { - int turns_left = XiblaxianHoloWristPuterTurnsUntilNextItem(); - if (turns_left == 1 || turns_left == 0) - { - string [int] description = SEquipmentGenerateXiblaxianHoloWristPuterDescription(); - task_entries.listAppend(ChecklistEntryMake("__item Xiblaxian holo-wrist-puter", "", ChecklistSubentryMake("Xiblaxian item next combat", "", description), -11).ChecklistEntrySetIDTag("Xiblaxian wrist now")); - } - } -} - -void SEquipmentGenerateResource(ChecklistEntry [int] resource_entries) -{ - if ($item[Xiblaxian holo-wrist-puter].equipped_amount() > 0) - { - int turns_left = XiblaxianHoloWristPuterTurnsUntilNextItem(); - if (turns_left != -1 || true) - { - string [int] description = SEquipmentGenerateXiblaxianHoloWristPuterDescription(); - //description.listAppend("_holoWristDrops = " + get_property_int("_holoWristDrops")); - //description.listAppend("_holoWristProgress = " + get_property_int("_holoWristProgress")); - - string header = turns_left + " combats to Xiblaxian item"; - if (turns_left <= 1) - header = "Xiblaxian next turn"; - resource_entries.listAppend(ChecklistEntryMake("__item Xiblaxian holo-wrist-puter", "", ChecklistSubentryMake(header, "", description), 8).ChecklistEntrySetIDTag("Xiblaxian wrist reminder")); - } - } -} diff --git a/Source/relay/TourGuide/Sets/Events.ash b/Source/relay/TourGuide/Sets/Events.ash deleted file mode 100644 index c7fc3571..00000000 --- a/Source/relay/TourGuide/Sets/Events.ash +++ /dev/null @@ -1,45 +0,0 @@ -import "relay/TourGuide/Support/Banishers.ash"; - -void SEventsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - return; -} - -void SCrimbo2015GenerateResource(ChecklistEntry [int] resource_entries) -{ - string year_and_month = format_today_to_string("yyyyMM"); - if (year_and_month != "201512") - return; - if (mafiaIsPastRevision(16544) && !in_ronin()) - { - int herb_uses_left = clampi(10 - get_property_int("_fragrantHerbsUsed"), 0, 10); - if ($item[bundle of "fragrant" herbs].available_amount() > 0 && herb_uses_left > 0) - { - string [int] description; - description.listAppend("Free run/banish three monsters at once."); - monster [int] banished_monsters; - foreach key, b in BanishesActive() - { - if (b.banish_source == "bundle of "fragrant" herbs") - { - banished_monsters.listAppend(b.banished_monster); - } - } - if (banished_monsters.count() > 0) - description.listAppend("Have " + banished_monsters.listJoinComponents(", ", "and") + " banished."); - resource_entries.listAppend(ChecklistEntryMake("__item bundle of "fragrant" herbs", "", ChecklistSubentryMake(pluralise(herb_uses_left, "fragrant herb banish", "fragrant herb banishes"), "", description), 3).ChecklistEntrySetIDTag("Crimbo 2015 flagrant herbs")); - } - int stockpile_uses_left = clampi(10 - get_property_int("_nuclearStockpileUsed"), 0, 10); - if ($item[nuclear stockpile].available_amount() > 0 && stockpile_uses_left > 0) - { - string [int] description; - description.listAppend("Does not cost a turn."); - resource_entries.listAppend(ChecklistEntryMake("__item nuclear stockpile", "", ChecklistSubentryMake(pluralise(stockpile_uses_left, "nuclear stockpile instakill", "nuclear stockpile instakills"), "", description), 3).ChecklistEntrySetIDTag("Crimbo 2015 nuclear stockpile")); - } - } -} - -void SEventsGenerateResource(ChecklistEntry [int] resource_entries) -{ - SCrimbo2015GenerateResource(resource_entries); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets/Familiars.ash b/Source/relay/TourGuide/Sets/Familiars.ash deleted file mode 100644 index cbed9d17..00000000 --- a/Source/relay/TourGuide/Sets/Familiars.ash +++ /dev/null @@ -1,510 +0,0 @@ -void SFamiliarsGenerateEntry(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, boolean from_task) -{ - if (get_property_int("_badlyRomanticArrows") == 0 && (familiar_is_usable($familiar[obtuse angel]) || familiar_is_usable($familiar[reanimated reanimator])) && my_path().id != PATH_LIVE_ASCEND_REPEAT && my_path().id != PATH_G_LOVER) - { - if (!__misc_state["in aftercore"] && !from_task) - return; - if (__misc_state["in aftercore"] && from_task) - return; - string familiar_image = __misc_state_string["obtuse angel name"]; - string [int] description; - string title = "Arrow monster"; - if (familiar_image == "reanimated reanimator") - title = "Wink at monster"; - string url; - if (!($familiars[obtuse angel, reanimated reanimator] contains my_familiar())) - url = "familiar.php"; - - if ($familiar[reanimated reanimator].familiar_is_usable() || ($familiar[obtuse angel].familiar_is_usable() && $familiar[obtuse angel].familiar_equipment() == $item[quake of arrows])) - description.listAppend("Three wandering copies."); - else - description.listAppend("Two wandering copies."); - - string [int] potential_targets; - //a short list: - //FIXME writing desk - if (__quest_state["Level 7"].state_int["alcove evilness"] > 31) - potential_targets.listAppend("modern zmobie"); - - if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && $items[ninja rope,ninja carabiner,ninja crampons].available_amount() == 0 && !have_outfit_components("eXtreme Cold-Weather Gear")) - potential_targets.listAppend("ninja assassin"); - - if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) - potential_targets.listAppend("lobsterfrogman"); - - if (!__quest_state["Level 12"].state_boolean["Nuns Finished"] && have_outfit_components("Frat Warrior Fatigues") && have_outfit_components("War Hippy Fatigues")) //brigand trick - potential_targets.listAppend("brigand"); - - // Adding KoE check to the romantic arrow check for a ghost monster, since this is only useful in KoE now. - if (!familiar_is_usable($familiar[angry jung man]) && in_hardcore() && my_path().id == PATH_KINGDOM_OF_EXPLOATHING && !__quest_state["Level 13"].state_boolean["digital key used"] && ($item[digital key].available_amount() + creatable_amount($item[digital key])) == 0 && __misc_state["fax equivalent accessible"]) - potential_targets.listAppend("ghost"); - - if (__misc_state["in run"] && ($items[bricko eye brick,bricko airship,bricko bat,bricko cathedral,bricko elephant,bricko gargantuchicken,bricko octopus,bricko ooze,bricko oyster,bricko python,bricko turtle,bricko vacuum cleaner].available_amount() > 0 || $skill[summon brickos].skill_is_usable())) - potential_targets.listAppend("BRICKO monster"); - - if (potential_targets.count() > 0) - description.listAppend("Possibly a " + potential_targets.listJoinComponents(", ", "or") + "."); - - optional_task_entries.listAppend(ChecklistEntryMake(familiar_image, url, ChecklistSubentryMake(title, "", description), 6).ChecklistEntrySetIDTag("Romantic-like familiar copy make")); - } - - - if ($familiar[Crimbo Shrub].familiar_is_usable() && my_path().id != PATH_G_LOVER) - { - boolean should_output = false; - if (__misc_state["in run"]) - { - if (from_task) - should_output = true; - } - else - { - if (!from_task) - should_output = true; - } - if (get_property("shrubGifts") == "meat" && $effect[everything looks red].have_effect() == 0 && should_output) - { - string url = ""; - string title = "Open a Big Red Present in combat"; - if (!from_task) - title = "Big Red Present openable in combat"; - string description = "Gives 2.5k meat."; - if (my_familiar() != $familiar[Crimbo Shrub]) - { - url = "familiar.php"; - if (from_task) - title = "Switch to Crimbo Shrub to open a big red present"; - else - description = "Switch to Crimbo Shrub first.|" + description; - } - optional_task_entries.listAppend(ChecklistEntryMake("__item dense meat stack", url, ChecklistSubentryMake(title, "", description), 6).ChecklistEntrySetIDTag("Crimbo shrub familiar big red present")); - } - } -} - -void SFamiliarsPuckGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["in run"]) return; - if (my_path().id == PATH_G_LOVER) return; // cannot use puck (or submarine/yellow pixels) in g-lover - - ChecklistSubentry [int] puck_subentries; - item yellow_pixel = $item[yellow pixel]; - string url = ""; - familiar relevant_familiar = $familiar[Ms. Puck Man]; - if (!relevant_familiar.familiar_is_usable() && $familiar[Puck Man].familiar_is_usable()) - relevant_familiar = $familiar[Puck Man]; - if ($familiar[Ms. Puck Man].familiar_is_usable() || $familiar[Puck Man].familiar_is_usable()) - { - int power_pills_remaining = MAX(0, MIN(11, my_daycount() + 1) - get_property_int("_powerPillDrops")); - if (power_pills_remaining > 0) - { - string [int] description; - - string line = "Saves a turn each."; - if (my_familiar() != $familiar[Ms. Puck Man] && my_familiar() != $familiar[Puck Man] && url.length() == 0) - { - url = "familiar.php"; - line += " Drops from " + relevant_familiar + "."; - } - description.listAppend(line); - - puck_subentries.listAppend(ChecklistSubentryMake(pluralise(power_pills_remaining, "power pill", "power pills") + " obtainable", "", description)); - } - - if ($item[power pill].available_amount() > 0) - { - string header = $item[power pill].pluralise().capitaliseFirstLetter(); - int power_pill_uses_left = clampi(20 - get_property_int("_powerPillUses"), 0, 20); - if (power_pill_uses_left < $item[power pill].available_amount()) - { - if (power_pill_uses_left == 0) - header += " (not usable today)"; - else - header += " (" + power_pill_uses_left + " usable today)"; - } - resource_entries.listAppend(ChecklistEntryMake("__item power pill", "", ChecklistSubentryMake(header, "", "Use in combat to instakill without costing a turn.")).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Puck man familiar power pill free kill")); - } - } - if (yellow_pixel != $item[none] && yellow_pixel.available_amount() > 0 && in_ronin()) - { - string title = pluralise(yellow_pixel); - string [int] description; - url = "shop.php?whichshop=mystic"; //"place.php?whichplace=forestvillage&action=fv_mystic"; - //Pixel coin - 10 yellow pixels - 2k autosell (marginal) - //minature power pill - 15 yellow pixels - +100% all stats, 30 turns - //pixel star - 15 yellow pixels, 2 black pixels - 30 turns of +100% HP/MP/spell damage/weapon damage - //pixel banana - 10 yellow pixels, 1 black pixel - 2-size awesome food, 10 turns of +30% item - //pixel beer - 10 yellow pixels, 5 white pixels - 2-size awesome drunk, 10 turns of +3 stats/fight (15 mainstat) - boolean [item] items_to_always_show; - items_to_always_show[$item[yellow pixel potion]] = true; - if (!__misc_state["mysterious island available"]) - items_to_always_show[$item[yellow submarine]] = true; - - item [int] evalulation_order; - evalulation_order.listAppend($item[yellow pixel potion]); - evalulation_order.listAppend($item[pixel coin]); //before potions - - string [item] reasons; - reasons[$item[pixel coin]] = "Autosells for 2000 meat."; - reasons[$item[pixel star]] = "+100% HP/MP/spell/weapon damage. (30 turns)"; - reasons[$item[miniature power pill]] = "+100% stats. (30 turns)"; - reasons[$item[yellow pixel potion]] = "+20ML. (20 turns)"; - if (!__misc_state["mysterious island available"]) - reasons[$item[yellow submarine]] = "island unlock"; - //these (should) show up in mafia's consumption manager, so disabled - /*if (__misc_state["can eat just about anything"]) - reasons[$item[pixel banana]] = "2-size awesome food, 10 turns of +30% item."; - if (__misc_state["can drink just about anything"]) - reasons[$item[pixel beer]] = "2-size awesome drunk, 10 turns of +3 stats/fight.";*/ - - boolean [item] evaluated; - foreach key, it in evalulation_order - evaluated[it] = true; - foreach it in reasons - { - if (!(evaluated contains it)) - { - evaluated[it] = true; - evalulation_order.listAppend(it); - } - } - - foreach key, it in evalulation_order - { - string reason = reasons[it]; - if (reason.length() == 0) - continue; - if (it == $item[none]) - continue; - if (it.creatable_amount() == 0 && !items_to_always_show[it]) - continue; - string line; - line = it.capitaliseFirstLetter() + ": " + reason; - if (it.creatable_amount() == 0) - line = HTMLGenerateSpanFont(line, "grey"); - description.listAppend(line); - } - string [int] consumables; - if (__misc_state["can eat just about anything"]) - consumables.listAppend("food"); - if (__misc_state["can drink just about anything"]) - consumables.listAppend("drink"); - if (consumables.count() > 0) - { - string line = consumables.listJoinComponents(", ").capitaliseFirstLetter() + "."; - if ($item[yellow pixel].available_amount() < 10) - line = HTMLGenerateSpanFont(line, "grey"); - description.listAppend(line); - } - int importance = 9; - puck_subentries.listAppend(ChecklistSubentryMake(title, "", description)); - } - if (puck_subentries.count() > 0) - { - resource_entries.listAppend(ChecklistEntryMake("__familiar " + relevant_familiar, url, puck_subentries, 9).ChecklistEntrySetIDTag("Puck man familiar resource")); - } - -} - -void SFamiliarsGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (__misc_state["free runs usable"] && ($familiar[pair of stomping boots].familiar_is_usable() || ($skill[the ode to booze].skill_is_usable() && $familiar[Frumious Bandersnatch].familiar_is_usable()))) - { - int runaways_used = get_property_int("_banderRunaways"); - string name = runaways_used + " familiar runaways used"; - string [int] description; - string image_name = ""; - - string url = ""; - - if ($familiar[Frumious Bandersnatch].familiar_is_usable() && $skill[the ode to booze].skill_is_usable()) - { - image_name = "Frumious Bandersnatch"; - } - else if ($familiar[pair of stomping boots].familiar_is_usable()) - { - image_name = "pair of stomping boots"; - } - - if (!($familiars[Frumious Bandersnatch, pair of stomping boots] contains my_familiar())) - url = "familiar.php"; - - if (my_path().id != PATH_HEAVY_RAINS) - { - int snow_suit_runs = floor(numeric_modifier($item[snow suit], "familiar weight") / 5.0); - - if ($item[snow suit].available_amount() == 0) - snow_suit_runs = 0; - - if (snow_suit_runs >= 2) - description.listAppend("Snow Suit available (+" + snow_suit_runs + " runs)"); - else if ($item[sugar shield].available_amount() > 0) - description.listAppend("Sugar shield available (+2 runs)"); - } - - resource_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Bander-like familiar free run")); - } - - if (true) - { - int hipster_fights_available = __misc_state_int["hipster fights available"]; - - if (($familiar[artistic goth kid].familiar_is_usable() || $familiar[Mini-Hipster].familiar_is_usable()) && hipster_fights_available > 0 && my_path().id != PATH_LIVE_ASCEND_REPEAT && my_path().id != PATH_G_LOVER) - { - string name = ""; - string [int] description; - string hipster_image = __misc_state_string["hipster name"]; - - string hipster_name = __misc_state_string["hipster name"]; - if ($familiar[artistic goth kid].familiar_is_usable() && $familiar[Mini-Hipster].familiar_is_usable()) - { - hipster_name = "goth kid / mini-hipster"; - hipster_image = "__familiar Mini-hipster"; - } - - name = pluralise(hipster_fights_available, __misc_state_string["hipster name"] + " fight", hipster_name + " fights"); - - int [int] hipster_chances; - hipster_chances[7] = 50; - hipster_chances[6] = 40; - hipster_chances[5] = 30; - hipster_chances[4] = 20; - hipster_chances[3] = 10; - hipster_chances[2] = 10; - hipster_chances[1] = 10; - - string url = ""; - if (!($familiars[artistic goth kid,mini-hipster] contains my_familiar())) - url = "familiar.php"; - - description.listAppend(hipster_chances[hipster_fights_available] + "% chance of appearing."); - int importance = 0; - if (!__misc_state["in run"]) - importance = 6; - resource_entries.listAppend(ChecklistEntryMake(hipster_image, url, ChecklistSubentryMake(name, "", description), importance).ChecklistEntrySetIDTag("Hipster-like familiar hipster fights")); - } - } - - - if ($familiar[nanorhino].familiar_is_usable() && get_property_int("_nanorhinoCharge") == 100 && my_path().id != PATH_G_LOVER) - { - ChecklistSubentry [int] subentries; - string [int] description_banish; - - string url = ""; - - if (my_familiar() != $familiar[nanorhino]) - url = "familiar.php"; - - boolean tag_with_banish_tag = false; - if (get_property("_nanorhinoBanishedMonster") != "") description_banish.listAppend(get_property("_nanorhinoBanishedMonster").HTMLEscapeString().capitaliseFirstLetter() + " currently banished."); - if (get_property_int("_nanorhinoCharge") >= 100) - { - tag_with_banish_tag = true; - description_banish.listAppend("All day. Cast muscle combat skill" + (my_familiar() == $familiar[nanorhino] ? "" : " with nanorhino as your familiar") + "."); - } - if (__misc_state["have muscle class combat skill"]) - { - if (tag_with_banish_tag) - resource_entries.listAppend(ChecklistEntryMake("__familiar nanorhino", "", ChecklistSubentryMake("Nanorhino Banish", "", description_banish), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Nanorhino familiar banish")); - else - subentries.listAppend(ChecklistSubentryMake("Nanorhino Banish", "", description_banish)); - } - if (__misc_state["need to level"] && __misc_state["have mysticality class combat skill"]) - subentries.listAppend(ChecklistSubentryMake("Nanorhino Gray Goo", "", "130? mainstat, fire against non-item monster with >90 attack. Cast mysticality combat skill.")); - if (!$familiar[he-boulder].familiar_is_usable() && __misc_state["have moxie class combat skill"] && __misc_state["in run"]) - { - if ($effect[everything looks yellow].have_effect() > 0) - subentries.listAppend(ChecklistSubentryMake(HTMLGenerateSpanFont("Nanorhino Yellow Ray", "gray"), "", HTMLGenerateSpanFont("Cast moxie combat skill once everything looks yellow is gone.", "gray"))); - else - subentries.listAppend(ChecklistSubentryMake("Nanorhino Yellow Ray", "", "Cast moxie combat skill.")); - } - if (subentries.count() > 0) - resource_entries.listAppend(ChecklistEntryMake("__familiar nanorhino", url, subentries, 5).ChecklistEntrySetIDTag("Nanorhino familiar use charge")); - } - if (__misc_state["yellow ray available"] && !__misc_state["in run"]) //in-run version in Misc Tasks.ash - { - resource_entries.listAppend(ChecklistEntryMake(__misc_state_string["yellow ray image name"], "", ChecklistSubentryMake("Yellow ray available", "", "From " + __misc_state_string["yellow ray source"] + "."), 6).ChecklistEntrySetIDTag("Yellow-ray resource")); - } - - if (my_familiar() == $familiar[happy medium] || $familiar[happy medium].charges > 0 && $familiar[happy medium].familiar_is_usable()) //|| stuff - { - //FIXME request support for tracking medium combats. - string title; - string [int] description; - - int charges = $familiar[happy medium].charges; - int siphons = get_property_int("_mediumSiphons"); - - int adventures_to_next_at_most = 3 + siphons; - - if (charges == 3) - { - title = "Red medium"; - description.listAppend("4.25 turns/drunkenness."); - } - else if (charges == 2) - { - title = "Orange medium"; - description.listAppend("3.25 turns/drunkenness."); - description.listAppend(pluraliseWordy(adventures_to_next_at_most, "turn", "turns").capitaliseFirstLetter() + " (at most) to red."); - } - else if (charges == 1) - { - title = "Blue medium"; - description.listAppend("2.25 turns/drunkenness."); - description.listAppend(pluraliseWordy(adventures_to_next_at_most, "turn", "turns").capitaliseFirstLetter() + " (at most) to orange."); - } - else - { - title = "Uncharged medium"; - description.listAppend(pluraliseWordy(adventures_to_next_at_most, "turn", "turns").capitaliseFirstLetter() + " (at most) to blue. "); - } - string url; - if (my_familiar() != $familiar[happy medium]) - url = "familiar.php"; - - int importance = 6; - if (my_familiar() == $familiar[happy medium] || charges > 0) - importance = 0; - resource_entries.listAppend(ChecklistEntryMake("__familiar happy medium", url, ChecklistSubentryMake(title, "", description), importance).ChecklistEntrySetIDTag("Happy medium familiar siphon")); - } - if (my_familiar() == $familiar[steam-powered cheerleader] || $familiar[steam-powered cheerleader].familiar_is_usable() && get_property_int("_cheerleaderSteam") < 200) - { - string title; - string [int] description; - - int steam_remaining = get_property_int("_cheerleaderSteam"); - float multiplier = 1.0; - float next_multiplier_level = 1.0; - - int next_steam_level = 0; - - boolean has_socket_set = $familiar[steam-powered cheerleader].familiar_equipped_equipment() == $item[school spirit socket set]; - - if (steam_remaining >= 151) - { - multiplier = 1.4; - next_multiplier_level = 1.3; - next_steam_level = 150; - } - else if (steam_remaining >= 101) - { - multiplier = 1.3; - next_multiplier_level = 1.2; - next_steam_level = 100; - } - else if (steam_remaining >= 51) - { - multiplier = 1.2; - next_multiplier_level = 1.1; - next_steam_level = 50; - } - else if (steam_remaining >= 1) - { - multiplier = 1.1; - next_multiplier_level = 1.0; - next_steam_level = 0; - } - - int steam_at_this_level_remaining = steam_remaining - next_steam_level; - int turns_remaining_at_this_level = steam_at_this_level_remaining; - if (!has_socket_set) - turns_remaining_at_this_level = turns_remaining_at_this_level / 2; - - - - title = multiplier + "x fairy steam-powered cheerleader"; - - if (turns_remaining_at_this_level > 0) - description.listAppend(pluralise(turns_remaining_at_this_level, "turn remains", "turns remain") + " until " + next_multiplier_level + "x."); - - int importance = 6; - if (my_familiar() == $familiar[steam-powered cheerleader]) - importance = 0; - - - string url; - if (my_familiar() != $familiar[steam-powered cheerleader]) - url = "familiar.php"; - - - resource_entries.listAppend(ChecklistEntryMake("__familiar steam-powered cheerleader", url, ChecklistSubentryMake(title, "", description), importance).ChecklistEntrySetIDTag("Steam-powered cheerleader familiar steam")); - } - - if ($familiar[grim brother].familiar_is_usable() && !get_property_boolean("_grimBuff") && __misc_state["in run"]) //in aftercore, let the maximizer handle it? - { - string title; - string [int] description; - string url = "familiar.php?action=chatgrim&pwd=" + my_hash(); - - title = "Chat with grim brother"; - - description.listAppend("30 turns of +20% init or +HP/MP or +damage."); - int importance = 9; - resource_entries.listAppend(ChecklistEntryMake("__familiar grim brother", url, ChecklistSubentryMake(title, "", description), importance).ChecklistEntrySetIDTag("Grim brother familiar buff")); - } - - - SFamiliarsPuckGenerateResource(resource_entries); - - //FIXME small medium, organ grinder, charged boots - SFamiliarsGenerateEntry(resource_entries, resource_entries, false); -} - -void SFamiliarsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (my_familiar() == $familiar[none] && !__misc_state["single familiar run"] && !__misc_state["familiars temporarily blocked"] && !($locations[The Bandit Crossroads,The Towering Mountains,The Mystic Wood,The Putrid Swamp,The Cursed Village,The Sprawling Cemetery,The Old Rubee Mine,The Foreboding Cave,The Faerie Cyrkle,The Druidic Campsite,Near the Witch's House,The Evil Cathedral,The Barrow Mounds,The Cursed Village Thieves' Guild,The Troll Fortress,The Labyrinthine Crypt,The Lair of the Phoenix,The Dragon's Moor,Duke Vampire's Chateau,The Master Thief's Chalet,The Spider Queen's Lair,The Archwizard's Tower,The Ley Nexus,The Ghoul King's Catacomb,The Ogre Chieftain's Keep] contains __last_adventure_location)) - { - string image_name = "black cat"; - optional_task_entries.listAppend(ChecklistEntryMake(image_name, "familiar.php", ChecklistSubentryMake("Bring along a familiar", "", "")).ChecklistEntrySetIDTag("Bring familiar reminder")); - } - - if ($familiar[Crimbo Shrub].familiar_is_usable() && my_path().id != PATH_G_LOVER) - { - boolean configured = get_property("shrubGarland") != "" || get_property("shrubGifts") != "" || get_property("shrubLights") != "" || get_property("shrubTopper") != ""; - if (my_daycount() == 1 && get_property("_shrubDecorated") == "false") //default configuration exists, but - configured = false; - if (!configured && (__misc_state["in run"] || my_familiar() == $familiar[Crimbo Shrub]) && get_property("_shrubDecorated") == "false") - { - string [int] description; - - string [int] configuration_idea; - if (my_primestat() == $stat[muscle]) - configuration_idea.listAppend("Veiny Star"); - else if (my_primestat() == $stat[mysticality]) - configuration_idea.listAppend("LED Mandala"); - else if (my_primestat() == $stat[moxie]) - configuration_idea.listAppend("Angel With Sunglasses"); - - configuration_idea.listAppend("Frosted Lights"); //random pick really - - if (hippy_stone_broken()) - configuration_idea.listAppend("Barbed Wire"); - else - configuration_idea.listAppend("Popcorn Strands"); - - if (!__misc_state["yellow ray potentially available"] && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) //you really want the meat one in WOTSF (this works!) - configuration_idea.listAppend("Big Yellow-Wrapped Presents"); - else - configuration_idea.listAppend("Big Red-Wrapped Presents"); - - description.listAppend("Maybe " + configuration_idea.listJoinComponents(" / ") + "?"); - - string url = "familiar.php"; - - if ($item[box of old Crimbo decorations].available_amount() > 0) - url = "inv_use.php?pwd=" + my_hash() + "&whichitem=7958"; - - optional_task_entries.listAppend(ChecklistEntryMake("__item box of old Crimbo decorations", url, ChecklistSubentryMake("Configure your Crimbo Shrub", "", description), 6).ChecklistEntrySetIDTag("Crimbo shrub familiar decorate")); - } - /* - shrubGarland(user, now 'PvP', default ) - shrubGifts(user, now 'meat', default ) - shrubLights(user, now 'Cold', default ) - shrubTopper(user, now 'Moxie', default ) - */ - } - - SFamiliarsGenerateEntry(task_entries, optional_task_entries, true); -} diff --git a/Source/relay/TourGuide/Sets/Fax.ash b/Source/relay/TourGuide/Sets/Fax.ash deleted file mode 100644 index 07ba759a..00000000 --- a/Source/relay/TourGuide/Sets/Fax.ash +++ /dev/null @@ -1,312 +0,0 @@ - -string [int] SFaxGeneratePotentialFaxes(boolean suggest_less_powerful_faxes, boolean [monster] blocked_monsters) -{ - string [int] potential_faxes; - - record potential_fax { - monster target; - string reason; - // Faxes that will be useful, but not yet for some reason (i.e. quest not started). - boolean unready; - string unready_reason; - }; - - void add_fax(potential_fax it) - { - if (blocked_monsters[it.target]) { - return; - } - - string line = it.target.to_string().capitalisefirstletter() + " " + it.reason; - if (it.unready) - { - if (it.unready_reason != "") - { - line += " (" + it.unready_reason + ")"; - } - line = HTMLGenerateSpanFont(line, "gray"); - } - potential_faxes.listAppend(line); - } - - boolean can_arrow = false; - if (get_property_int("_badlyRomanticArrows") == 0 && (familiar_is_usable($familiar[obtuse angel]) || familiar_is_usable($familiar[reanimated reanimator]))) - can_arrow = true; - - if (my_path().id == PATH_G_LOVER) can_arrow = false; // cannot use arrow skills/fams in g-lover - - if (get_auto_attack() != 0) - { - potential_faxes.listAppend("Auto attack is on, disable it?"); - } - - if (__misc_state["in run"]) - { - //sleepy mariachi - if (familiar_is_usable($familiar[fancypants scarecrow]) || familiar_is_usable($familiar[mad hatrack])) - { - if ($item[spangly mariachi pants].available_amount() == 0 && in_hardcore() && $item[li'l ninja costume].available_amount() == 0) - { - string fax = ""; - fax += ChecklistGenerateModifierSpan("yellow ray"); - - if (familiar_is_usable($familiar[fancypants scarecrow])) - { - fax += "Makes scarecrow into superfairy"; - if (my_primestat() == $stat[moxie] && __misc_state["need to level"]) - { - fax += " and +3 mainstat/turn hat"; - } - } - else if (familiar_is_usable($familiar[mad hatrack])) - fax += "Makes hatrack into superfairy"; - fax += "."; - - add_fax(new potential_fax($monster[sleepy mariachi], HTMLGenerateIndentedText(fax))); - } - } - - //ninja snowman assassin (copy only) - if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && !blocked_monsters[$monster[ninja snowman assassin]]) - { - int equipment_missing_count = $items[ninja carabiner,ninja crampons,ninja rope].items_missing().count(); - if (equipment_missing_count > 0) - { - string fax = ""; - string modifier_text = "+150% init or more"; - if (equipment_missing_count == 3) - modifier_text += ", two copies"; - if (equipment_missing_count == 2) - modifier_text += ", one copy"; - fax += ChecklistGenerateModifierSpan(modifier_text); - if (equipment_missing_count == 3) - fax += "Copy twice for recreational mountain climbing.
"; - else if (equipment_missing_count == 2) - fax += "Copy once for recreational mountain climbing.
"; - fax += generateNinjaSafetyGuide(false); - if ($familiar[obtuse angel].familiar_is_usable() && $familiar[reanimated reanimator].familiar_is_usable()) - fax += "
Make sure to copy with angel, not the reanimator."; - - add_fax(new potential_fax($monster[ninja snowman assassin], HTMLGenerateIndentedText(fax))); - } - } - - int missing_ore = MAX(0, 3 - __quest_state["Level 8"].state_string["ore needed"].to_item().available_amount()); - if (!__quest_state["Level 8"].state_boolean["Past mine"] && missing_ore > 0)// && !$skill[unaccompanied miner].skill_is_usable()) - { - string line = ""; - line += ChecklistGenerateModifierSpan("+150% item or ideally YR"); - line += "Mining ores. Try to copy a few times."; - if (__misc_state_string["obtuse angel name"] != "") - { - string arrow_text = " (arrow?)"; - if (get_property_int("_badlyRomanticArrows") > 0) - arrow_text = HTMLGenerateSpanFont(arrow_text, "gray"); - line += arrow_text; - } - add_fax(new potential_fax($monster[mountain man], HTMLGenerateIndentedText(line))); - } - - - if (!(__quest_state["Level 12"].finished || __quest_state["Level 12"].state_boolean["Lighthouse Finished"] || $item[barrel of gunpowder].available_amount() == 5)) - { - string line = "(lighthouse quest"; - if ($item[barrel of gunpowder].available_amount() < 4) - { - line += "; copy"; - if (can_arrow) - line += "/arrow"; - } - line += ")"; - add_fax(new potential_fax($monster[Lobsterfrogman], line)); - } - - //orcish frat boy spy / war hippy - if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues") && !__quest_state["Level 12"].finished) - potential_faxes.listAppend("Bailey's Beetle (YR) / Hippy spy (30% drop) / Orcish frat boy spy (30% drop) - war outfit"); - - if (!__misc_state["can eat just about anything"]) //can't eat, can't fortune cookie - { - //Suggest kge, miner, baabaaburan: - if (!dispensary_available() && !have_outfit_components("Knob Goblin Elite Guard Uniform")) - { - add_fax(new potential_fax($monster[Knob Goblin Elite Guard Captain], "- ???")); - } - if (!__quest_state["Level 8"].state_boolean["Past mine"] && !have_outfit_components("Mining Gear") && __misc_state["can equip just about any weapon"]) - { - add_fax(new potential_fax($monster[7-Foot Dwarf Foreman], "- Mining gear for level 8 quest. Need YR or +234% items.")); - } - if (!locationAvailable($location[the hidden park]) && $item[stone wool].available_amount() < ($item[the nostril of the serpent].available_amount() == 0 && !get_property_ascension("lastTempleButtonsUnlock") ? 2 : 1)) - { - add_fax(new potential_fax($monster[Baa'baa'bu'ran], "- Stone wool for hidden city unlock. Need +100% items (or as much as you can get for extra wool)")); - } - } - - if (!__misc_state["can reasonably reach -25% combat"] && in_hardcore() && $item[Bram's choker].available_amount() == 0 && combat_rate_modifier() > -25.0 && !(__quest_state["Level 13"].in_progress || (__quest_state["Level 13"].finished && my_path().id != PATH_BUGBEAR_INVASION))) - { - string line = "- drops a -5% combat accessory."; - if (my_basestat($stat[mysticality]) < 50) - line += " (requires 50 myst)"; - add_fax(new potential_fax($monster[Bram the Stoker], line)); - } - - if (!in_hardcore() && $item[richard's star key].available_amount() + $item[richard's star key].creatable_amount() == 0 && !__quest_state["Level 13"].state_boolean["Richard's star key used"] && !($item[star].available_amount() >= 8 && $item[line].available_amount() >= 7)) - { - string copy_type = "arrow"; - if (my_path().id == PATH_HEAVY_RAINS) //arrows mean washaway in flooded areas - copy_type = "copy"; - add_fax(new potential_fax($monster[skinflute], "- +234% item, fight 4 times (" + copy_type + ") to skip HITS with pulls.")); - } - - if (suggest_less_powerful_faxes) - { - //giant swarm of ghuol whelps - if (__quest_state["Level 7"].state_boolean["cranny needs speed tricks"] && !blocked_monsters[$monster[giant swarm of ghuol whelps]]) - { - potential_fax fax = new potential_fax($monster[giant swarm of ghuol whelps], "- +ML - with a copy possibly"); - if (!__quest_state["Level 7"].started) - { - fax.unready = true; - fax.unready_reason = "wait until quest started"; - } - add_fax(fax); - } - //modern zmobie - if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"] && !blocked_monsters[$monster[modern zmobie]]) - { - potential_fax fax = new potential_fax($monster[modern zmobie], "- +ML - with a copy possibly"); - if (!__quest_state["Level 7"].started) - { - fax.unready = true; - fax.unready_reason = "wait until quest started"; - } - add_fax(fax); - } - - //screambat for sonar replacement - if ((3 - __quest_state["Level 4"].state_int["areas unlocked"]) > $item[sonar-in-a-biscuit].available_amount()) - { - potential_fax fax = new potential_fax($monster[screambat], "- unlocks a single bat lair area"); - if (!__quest_state["Level 4"].in_progress) - { - fax.unready = true; - fax.unready_reason = "quest not started"; - } - add_fax(fax); - } - //monstrous boiler - if (__quest_state["Level 11 Manor"].mafia_internal_step < 4 && $item[wine bomb].available_amount() == 0) - { - add_fax(new potential_fax($monster[monstrous boiler], "- charge up unstable fulminate.", $item[unstable fulminate].available_amount() == 0)); - } - if (true) //not sure about this - { - //marginal stuff: - //whitesnake, white lion - if (in_hardcore() && $items[wet stunt nut stew,mega gem].available_amount() == 0 && !__quest_state["Level 11 Palindome"].finished) - { - string [int] stew_source_monsters; - if ($item[bird rib].available_amount() == 0) - { - stew_source_monsters.listAppend("whitesnake"); - } - if ($item[lion oil].available_amount() == 0) - { - stew_source_monsters.listAppend("white lion"); - } - if (stew_source_monsters.count() > 0) - { - string description = stew_source_monsters.listJoinComponents("/").capitaliseFirstLetter() + " - run +300% item/food drops for wet stunt nut stew components. (marginal?)"; - - potential_faxes.listAppend(description); - } - } - } - //blur - if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && $item[drum machine].available_amount() == 0 && !__quest_state["Level 11 Desert"].state_boolean["Wormridden"] && in_hardcore()) - { - add_fax(new potential_fax($monster[blur], "- +234% item " + (item_drop_modifier() >= 234 ? "(have) " : "(don't have) ") + "for drum machine for possible desert exploration route.")); - } - - if (in_hardcore() && knoll_available() && __quest_state["Level 11 Hidden City"].state_boolean["need machete for liana"] && $item[forest tears].available_amount() == 0) - { - add_fax(new potential_fax($monster[forest spirit], "- +234% item - forest tears can meatsmith into a muculent machete for dense liana" + (($familiar[intergnat].familiar_is_usable() && my_level() <= 11) ? " (or use intergnat summon)" : ""))); - } - //green ops - //baa'baa'bu'ran - //grungy pirate - for guitar (need 400% item/YR) - //harem girl - - //FIXME rest - //f'c'le - cleanly pirate/curmudgeonly pirate/that other pirate (and insults) - //KGE - - //dairy goat? mostly for early milk of magnesium (stunt runs) - //possessed wine rack / cabinet - //pygmy shaman / accountant - if you absolutely have to - //barret / aerith for equipment - //racecar bob to olfact - - //brainsweeper for chef-in-the-box / bartender-in-the-box? - //gremlins? - - //FIXME handsome mariachi/etc? - } - } - else - { - //aftercore: - //potential_faxes.listAppend("Adventurer Echo - event chroner"); - add_fax(new potential_fax($monster[Clod Hopper], "(YR/+item) - floaty sand")); - add_fax(new potential_fax($monster[swarm of fudgewasps], "- fudge")); - } - - return potential_faxes; -} - -string [int] SFaxGeneratePotentialFaxes(boolean suggest_less_powerful_faxes) -{ - boolean [monster] blank; - return SFaxGeneratePotentialFaxes(suggest_less_powerful_faxes, blank); -} - -void SFaxGenerateEntry(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries) -{ - if (my_path().id == PATH_G_LOVER) return; // cannot use fax machine in g-lover - - string url = "clan_viplounge.php?action=faxmachine"; - - if (get_auto_attack() != 0) - { - url = "account.php?tab=combat"; - } - - if (__misc_state["fax available"] && $item[photocopied monster].available_amount() == 0) - optional_task_entries.listAppend(ChecklistEntryMake("fax machine", url, ChecklistSubentryMake("Fax", "", listJoinComponents(SFaxGeneratePotentialFaxes(true), "|
"))).ChecklistEntrySetIDTag("VIP fax machine suggestions")); - if ($skill[Rain Man].skill_is_usable() && my_rain() >= 50) - { - ChecklistEntry entry = ChecklistEntryMake("__skill rain man", "skills.php", ChecklistSubentryMake("Rain man copy", "50 rain drops", listJoinComponents(SFaxGeneratePotentialFaxes(true), "
"))); - entry.tags.id = "Heavy rains path rain man skill"; - - if (my_rain() > 93) - { - entry.importance_level = -10; - task_entries.listAppend(entry); - } - else - optional_task_entries.listAppend(entry); - } -} - -void SFaxGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (__misc_state["in aftercore"]) - SFaxGenerateEntry(resource_entries, resource_entries); -} - - -void SFaxGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!__misc_state["in aftercore"]) - SFaxGenerateEntry(task_entries, optional_task_entries); -} diff --git a/Source/relay/TourGuide/Sets/Florist.ash b/Source/relay/TourGuide/Sets/Florist.ash deleted file mode 100644 index e11f9a68..00000000 --- a/Source/relay/TourGuide/Sets/Florist.ash +++ /dev/null @@ -1,82 +0,0 @@ -import "relay/TourGuide/Plants.ash"; - -RegisterTaskGenerationFunction("SFloristGenerateTasks"); -void SFloristGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //Friar: - if (__iotms_usable[$item[Order of the Green Thumb Order Form]]) - { - string image_name = "sunflower face"; - ChecklistSubentry subentry; - subentry.header = "Plant florist plants in " + __last_adventure_location; - - PlantSuggestion [int] area_relevant_suggestions; - foreach key, suggestion in __plants_suggested_locations - { - - if (suggestion.loc != __last_adventure_location) - continue; - - area_relevant_suggestions.listAppend(suggestion); - } - - boolean single_mode_only = false; - if (area_relevant_suggestions.count() == 1) - { - single_mode_only = true; - PlantSuggestion suggestion = area_relevant_suggestions[0]; - string plant_name = suggestion.plant_name.capitaliseFirstLetter(); - - subentry.header = "Plant " + plant_name + " in " + __last_adventure_location; - } - - foreach key, suggestion in area_relevant_suggestions - { - string plant_name = suggestion.plant_name.capitaliseFirstLetter(); - Plant plant = __plant_properties[plant_name]; - - string line; - - if (single_mode_only) - { - line = plant.zone_effect + ", " + plant.terrain; - if (plant.territorial) - line = line + ", territorial"; - - if (suggestion.details != "") - line += "|*" + suggestion.details; - } - else - { - line = plant_name + " (" + plant.zone_effect + ", " + plant.terrain; - if (plant.territorial) - line = line + ", territorial"; - - line += ")"; - if (suggestion.details != "") - line += "|*" + suggestion.details; - } - - if (plant_name == "War Lily" || plant_name == "Rabid Dogwood" || plant_name == "Blustery Puffball") - { - if (monster_level_adjustment() + 30 > 150) - { - //subentry.header = "Optionally plant florist plants in " + __last_adventure_location; - image_name = "__item pirate fledges"; - - subentry.header += "?"; - line += "|" + HTMLGenerateSpanFont("Very dangerous", "red") + ", monsters "; - if (monster_level_adjustment() > 150) - line += "are"; - else - line += "will be"; - line += " stagger immune."; - } - } - - subentry.entries.listAppend(line); - } - if (subentry.entries.count() > 0) - task_entries.listAppend(ChecklistEntryMake(image_name, "place.php?whichplace=forestvillage&action=fv_friar", subentry, -11).ChecklistEntrySetIDTag("Florist friar plant suggestions")); - } -} diff --git a/Source/relay/TourGuide/Sets/Hole in the Sky.ash b/Source/relay/TourGuide/Sets/Hole in the Sky.ash deleted file mode 100644 index b4a44535..00000000 --- a/Source/relay/TourGuide/Sets/Hole in the Sky.ash +++ /dev/null @@ -1,303 +0,0 @@ - -boolean HITSStillRelevant() -{ - if (__misc_state["Example mode"]) - return true; - if (!__misc_state["in run"]) - return false; - if (__quest_state["Level 13"].state_boolean["Richard's star key used"]) - return false; - if (!__quest_state["Level 10"].finished && my_path().id != PATH_EXPLOSIONS) - return false; - if (my_path().id == PATH_COMMUNITY_SERVICE) - return false; - - return true; -} - -void QHitsInit() -{ - //This isn't really a quest... - QuestState state; - - state.quest_name = "Hole in the Sky"; - state.image_name = "Hole in the Sky"; - - - int charts_want = 0; - int stars_want = 0; - int lines_want = 0; - - if ($item[richard\'s star key].available_amount() == 0 && HITSStillRelevant()) - { - charts_want += 1; - stars_want += 8; - lines_want += 7; - } - - state.state_int["star charts needed"] = MAX(0, charts_want - $item[star chart].available_amount()); - state.state_int["stars needed"] = MAX(0, stars_want - $item[star].available_amount()); - state.state_int["lines needed"] = MAX(0, lines_want - $item[line].available_amount()); - - __quest_state["Hole in the Sky"] = state; -} - -void QHitsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!HITSStillRelevant()) - return; - ChecklistSubentry subentry; - subentry.header = "Hole in the Sky"; - - string active_url = ""; - //Super unclear code. Sorry. - //FIXME rewrite now that we don't need equipment - - int star_charts_needed = 0; - int stars_needed_base = 0; - int lines_needed_base = 0; - - string [int] item_names_needed; - - if ($item[richard\'s star key].available_amount() == 0) - { - star_charts_needed += 1; - stars_needed_base += 8; - lines_needed_base += 7; - item_names_needed.listAppend($item[richard\'s star key]); - } - int [int] stars_needed_options; - int [int] lines_needed_options; - string [int] needed_options_names; - if (needed_options_names.count() == 0) - { - stars_needed_options.listAppend(stars_needed_base + 0); - lines_needed_options.listAppend(lines_needed_base + 0); - } - - //Convert what we need total to what's remaining: - int star_charts_remaining = MAX(0, star_charts_needed - $item[star chart].available_amount()); - int [int] stars_remaining; - int [int] lines_remaining; - string [int] remaining_options_names; - - boolean have_met_stars_requirement = true; - boolean have_met_lines_requirement = true; - - foreach key in stars_needed_options - { - if (needed_options_names contains key) - remaining_options_names[key] = needed_options_names[key]; - stars_remaining[key] = MAX(0, stars_needed_options[key] - $item[star].available_amount()); - lines_remaining[key] = MAX(0, lines_needed_options[key] - $item[line].available_amount()); - - if (stars_remaining[key] > 0) - have_met_stars_requirement = false; - if (lines_remaining[key] > 0) - have_met_lines_requirement = false; - } - - if (__misc_state["Example mode"]) - { - star_charts_remaining = 1; - have_met_stars_requirement = false; - have_met_lines_requirement = false; - } - - if (have_met_stars_requirement) - { - //Have all stars, suggest star sword (least lines) - //Remove non-sword: - foreach key in remaining_options_names - { - if (remaining_options_names[key] != "star sword") - { - remove remaining_options_names[key]; - remove stars_remaining[key]; - remove lines_remaining[key]; - } - } - } - else if (have_met_lines_requirement) - { - //Have all lines, suggest star crossbow (least stars) - //Remove non-crossbow: - foreach key in remaining_options_names - { - if (remaining_options_names[key] != "star crossbow") - { - remove remaining_options_names[key]; - remove stars_remaining[key]; - remove lines_remaining[key]; - } - } - } - if (remaining_options_names.count() > 0) - { - item_names_needed.listAppend(remaining_options_names.listJoinComponents("/", "")); - } - - if (item_names_needed.count() == 0) - return; - - - if (!$location[the hole in the sky].locationAvailable()) - { - //find a way to space: - subentry.modifiers.listAppend("-combat"); - subentry.entries.listAppend("Run -combat on the top floor of the castle for the steam-powered model rocketship.|From steampunk non-combat, unlocks Hole in the Sky."); - active_url = "place.php?whichplace=giantcastle"; - - - subentry.entries.listAppend(generateTurnsToSeeNoncombat(95, 1, "", 9)); - } - else - { - active_url = "place.php?whichplace=beanstalk"; - //We've made it out to space: - subentry.entries.listAppend("Need " + item_names_needed.listJoinComponents(", ", "and") + "."); - - string [int] required_components; - if (star_charts_remaining > 0) - required_components.listAppend(pluralise(star_charts_remaining, $item[star chart])); - foreach key in stars_remaining - { - string [int] line; - if (stars_remaining[key] > 0) - line.listAppend(pluralise(stars_remaining[key], $item[star])); - if (lines_remaining[key] > 0) - line.listAppend(pluralise(lines_remaining[key], $item[line])); - string route = ""; - if (remaining_options_names contains key) - { - route = " (" + remaining_options_names[key]; - if (stars_remaining.count() > 1) - route += " route"; - route += ")"; - } - if (line.count() > 0) - required_components.listAppend(line.listJoinComponents(" / ") + route); - } - if (required_components.count() > 0) - { - if (star_charts_remaining == 1 && have_met_stars_requirement && have_met_lines_requirement && !in_hardcore()) - { - subentry.entries.listAppend("Can pull a star chart."); - } - //require more components: - if (remaining_options_names.count() <= 1) - subentry.entries.listAppend("Need " + required_components.listJoinComponents(", ", "")); - else - subentry.entries.listAppend("Need:|*" + required_components.listJoinComponents("|*", "or")); - - //FIXME if we need only one type, recommend a different monster to olfact - - if (star_charts_remaining > 0 && in_hardcore()) - { - //olfact nothing, interferes with astronomers - //they prefer interferometry - } - else if (!have_met_stars_requirement || !have_met_lines_requirement) - { - if (my_ascensions() % 2 == 0) - subentry.entries.listAppend("Olfact skinflute."); - else - subentry.entries.listAppend("Olfact camel's toe."); - } - - if (!have_met_stars_requirement || !have_met_lines_requirement) - subentry.modifiers.listAppend("+234% item"); - - if ($familiar[space jellyfish].familiar_is_usable()) - { - //Space Directions NC: - //39, 46 - int turns_spent = $location[the hole in the sky].turns_spent; - boolean nc_up = false; - int turns_to_next_nc = 0; - if (turns_spent < 2) - turns_to_next_nc = 2 - turns_spent; - else - turns_to_next_nc = 7 - (turns_spent - 2) % 7; - - if (turns_spent == 2) - nc_up = true; - else if ((turns_spent - 2) % 7 == 0) - nc_up = true; - if (nc_up) - { - //Apparently skipping the NC just makes it re-appear the next adventure? - if (true) //get_property("lastEncounter") != "Space Directions") - { - string line = ""; - string [int] choices; - boolean an = false; - if (star_charts_remaining > 0) - { - choices.listAppend("astronomer"); - an = true; - } - if (!have_met_stars_requirement || !have_met_lines_requirement) - { - choices.listAppend("camel's toe"); - } - if ($familiar[space jellyfish] != my_familiar()) - line = HTMLGenerateSpanFont("Bring along your space jellyfish", "red") + ", it'll let you choose a " + choices.listJoinComponents(", ", "or"); - else - line = "Jellyfish NC next adventure. Will let you fight a" + (an ? "n" : "") + " " + choices.listJoinComponents(", ", "or"); - /*if (star_charts_remaining > 0) - { - choices.listAppend("astronomer"); - line = HTMLGenerateSpanFont("Bring along your space jellyfish", colour) + ", it'll let you choose an astronomer/camel"; - } - else - line = HTMLGenerateSpanFont("Possibly bring along your space jellyfish", colour) + ", it'll let you choose an camel";*/ - line += " this adventure."; - if (!have_met_stars_requirement || !have_met_lines_requirement) - line += "|Though that will reduce your +item, so choose wisely."; - subentry.entries.listAppend(line); - } - } - else - { - if (get_property_int("singleFamiliarRun").to_familiar() != $familiar[space jellyfish] && $familiar[space jellyfish] == my_familiar()) - { - subentry.entries.listAppend(HTMLGenerateSpanFont("Switch to another familiar?", "red")); - } - string line = pluraliseWordy(turns_to_next_nc, "more turn", "more turns").capitaliseFirstLetter() + " to jellyfish choice NC."; - subentry.entries.listAppend(line); - } - } - - if (__quest_state["Level 11 Shen"].state_int.getFutureShenAssignments().listInvert() contains $location[The Hole in the Sky]) - subentry.entries.listAppend("Could wait before going here? Shen will send you here later."); - } - else { - active_url = "shop.php?whichshop=starchart"; - subentry.entries.listAppend("Can make Richard's Star Key."); - } - } - optional_task_entries.listAppend(ChecklistEntryMake("hole in the sky", active_url, subentry, $locations[the hole in the sky, the castle in the clouds in the sky (top floor)]).ChecklistEntrySetIDTag("Hole in the sky quest")); -} - - -void QHitsGenerateMissingItems(ChecklistEntry [int] items_needed_entries) -{ - if (!__misc_state["in run"] && !__misc_state["Example mode"]) - return; - if (__quest_state["Level 13"].state_boolean["Richard\'s star key used"] || $item[richard\'s star key].available_amount() > 0) - return; - - QuestState state = __quest_state["Hole in the Sky"]; - - string url = $location[the hole in the sky].getClickableURLForLocation(); - if (state.state_int["star charts needed"] + state.state_int["stars needed"] + state.state_int["lines needed"] == 0) - url = "shop.php?whichshop=starchart"; - else if (!$location[the hole in the sky].locationAvailable()) - url = $location[The Castle in the Clouds in the Sky (basement)].getClickableURLForLocation(); - string [int] oh_my_stars_and_gauze_garters; - oh_my_stars_and_gauze_garters.listAppend(MIN(1, $item[star chart].available_amount()) + "/1 star chart"); - oh_my_stars_and_gauze_garters.listAppend(MIN(8, $item[star].available_amount()) + "/8 stars"); - oh_my_stars_and_gauze_garters.listAppend(MIN(7, $item[line].available_amount()) + "/7 lines"); - items_needed_entries.listAppend(ChecklistEntryMake("__item richard\'s star key", url, ChecklistSubentryMake("Richard\'s star key", "", oh_my_stars_and_gauze_garters.listJoinComponents(", ", "and"))).ChecklistEntrySetIDTag("Council L13 tower door richard star key")); -} diff --git a/Source/relay/TourGuide/Sets/Holidays.ash b/Source/relay/TourGuide/Sets/Holidays.ash deleted file mode 100644 index 11649bb2..00000000 --- a/Source/relay/TourGuide/Sets/Holidays.ash +++ /dev/null @@ -1,94 +0,0 @@ -import "relay/TourGuide/Support/Holiday.ash"; - -void SHolidayGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - boolean [string] todays_holidays = getHolidaysToday(); - boolean [string] all_tomorrows_parties = getHolidaysTomorrow(); - - if (todays_holidays["Halloween"]) - { - if (__misc_state["in run"]) - { - string [int] description; - description.listAppend("Free stats/items from monsters on the first block."); - if (knoll_available() && !have_outfit_components("Filthy Hippy Disguise")) - { - item [int] missing_components = missing_outfit_components("Bugbear Costume"); - if (missing_components.count() > 0) - description.listAppend("If you need an outfit, buy a " + missing_components.listJoinComponents(", ", "and") + " from the knoll."); - } - optional_task_entries.listAppend(ChecklistEntryMake("__item plastic pumpkin bucket", "place.php?whichplace=town&action=town_trickortreat", ChecklistSubentryMake("Trick or treat for one block", "+" + my_primestat().to_lower_case(), description), $locations[trick-or-treating]).ChecklistEntrySetIDTag("Holiday halloween in-run")); - } - else - { - string [int] description; - description.listAppend("Wear an outfit, go from house to house."); - description.listAppend("Remember you can trick-or-treat while drunk."); - optional_task_entries.listAppend(ChecklistEntryMake("__item plastic pumpkin bucket", "place.php?whichplace=town&action=town_trickortreat", ChecklistSubentryMake("Trick or treat", "", description), $locations[trick-or-treating]).ChecklistEntrySetIDTag("Holiday halloween aftercore")); - } - } - if (all_tomorrows_parties["Halloween"] && !__misc_state["in run"]) - optional_task_entries.listAppend(ChecklistEntryMake("__item plastic pumpkin bucket", "", ChecklistSubentryMake("Save turns for Halloween tomorrow", "", ""), 8).ChecklistEntrySetIDTag("Holiday halloween soon reminder")); - - if (todays_holidays["Arrrbor Day"]) - { - string [int] description; - boolean [item] outfit_pieces_needed; - foreach it in $items[crotchety pants,Saccharine Maple pendant,willowy bonnet] - { - if (!it.haveAtLeastXOfItemEverywhere(1)) - outfit_pieces_needed[it] = true; - } - //FIXME detect collecting reward? - if ($items[bag of Crotchety Pine saplings,bag of Saccharine Maple saplings,bag of Laughing Willow saplings].available_amount() == 0) - { - description.listAppend("Choose a sapling type."); - string [int] suggestions; - if (outfit_pieces_needed[$item[crotchety pants]]) - suggestions.listAppend("Crotchety Pine"); - if (outfit_pieces_needed[$item[Saccharine Maple pendant]]) - suggestions.listAppend("Saccharine Maple"); - if (outfit_pieces_needed[$item[willowy bonnet]]) - suggestions.listAppend("Laughing Willow"); - if (suggestions.count() > 0) - description.listAppend("Could try " + suggestions.listJoinComponents(", ", "or") + " for the reward item" + (suggestions.count() > 1 ? "s" : "") + "."); - } - else - { - item [int] bag_types; - boolean have_a_bag_equipped = false; - int saplings_planted = get_property_int('_saplingsPlanted'); - - foreach it in $items[bag of Crotchety Pine saplings,bag of Saccharine Maple saplings,bag of Laughing Willow saplings] - { - if (it.available_amount() > 0) - bag_types.listAppend(it); - if (it.equipped_amount() > 0) - have_a_bag_equipped = true; - } - - int saplings_needed = 2; - if (outfit_pieces_needed.count() > 0) - saplings_needed = 100; - - int saplings_left = saplings_needed - saplings_planted; - - if (saplings_left <= 0) - return; // All done for today - - if (!have_a_bag_equipped) - { - description.listAppend("Equip your " + bag_types.listJoinComponents(", ", "or") + "."); - } - else if (outfit_pieces_needed.count() > 0) - { - description.listAppend(`Adventure for {pluralise(saplings_left,"more turn","more turns")} to collect the outfit piece next holiday.`); - } - else - { - description.listAppend(`Adventure for {pluralise(saplings_left,"more turn","more turns")} to collect the potion reward next holiday.`); - } - } - optional_task_entries.listAppend(ChecklistEntryMake("__item spooky sapling", "place.php?whichplace=woods", ChecklistSubentryMake("Plant trees", "", description), 8, $locations[The Arrrboretum]).ChecklistEntrySetIDTag("Holiday arrrbor day")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets/Level 13 Door.ash b/Source/relay/TourGuide/Sets/Level 13 Door.ash deleted file mode 100644 index 4fc089d9..00000000 --- a/Source/relay/TourGuide/Sets/Level 13 Door.ash +++ /dev/null @@ -1,17 +0,0 @@ - -void SLevel13DoorGenerateMissingItems(ChecklistEntry [int] tower_door_entries) -{ - if (__quest_state["Level 13"].state_boolean["past keys"]) return; - - if ($item[skeleton key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["skeleton key used"]) { - string line = "loose teeth (" + ($item[loose teeth].available_amount() == 0 ? "need" : "have") + ")"; - line += " + skeleton bone (" + ($item[skeleton bone].available_amount() == 0 ? "need" : "have") + ")"; - tower_door_entries.listAppend(ChecklistEntryMake("__item skeleton key", $location[the defiled nook].getClickableURLForLocation(), ChecklistSubentryMake("Skeleton key", "", line)).ChecklistEntrySetIDTag("Council L13 tower door skeleton key")); - } - - Q8bitRealmGenerateMissingItems(tower_door_entries); - - SDailyDungeonGenerateMissingItems(tower_door_entries); - - QHitsGenerateMissingItems(tower_door_entries); -} diff --git a/Source/relay/TourGuide/Sets/Lucky.ash b/Source/relay/TourGuide/Sets/Lucky.ash deleted file mode 100644 index 41005c12..00000000 --- a/Source/relay/TourGuide/Sets/Lucky.ash +++ /dev/null @@ -1,145 +0,0 @@ -string [int] luckyOptions(int cloversAvailable) { - // Generate lucky suggestions from available options. Ordered in rough - // order according to which ones are available when. - string [int] allTheLuckyStuff; - int cloversAdjusted = cloversAvailable; - - // Very basic protestors calculations with rough amounts for certain - // weird paths. Assumption in standard/unrestricted is 3-clover mob. - int protestorsRemaining = clampi(80 - get_property_int("zeppelinProtestors"), 0, 80); - if (__quest_state["Level 11"].mafia_internal_step < 3) protestorsRemaining = 80; - int protestorsPerClover = 27; // 3 clover mob - - switch (my_path()) { - case $path[Legacy of Loathing]: - protestorsPerClover = 20; // 4 clover mob - case $path[Avatar of Boris]: - protestorsPerClover = 16; // 5 clover mob - case $path[G-Lover]: - protestorsPerClover = 1; // cannot use clovers RIP - } - - int projectedZeppClovers = ceil(protestorsRemaining.to_float()/protestorsPerClover.to_float()); - - // Wand variable needed to ensure we know the # of letters remaining - int lettersStillNeeded = __misc_state_int["ruby w needed"] + __misc_state_int["metallic a needed"] + __misc_state_int["lowercase n needed"] + __misc_state_int["heavy d needed"]; - - // Variables needed for a-boo nonsense - int aBooHauntedness = __quest_state["Level 9"].state_int["a-boo peak hauntedness"]; - int cluesNeeded = ceil(MIN(aBooHauntedness, 100).to_float() / 30.0); - int aBooCloversNeeded = ceil(cluesNeeded/2); - - // Desert ultrahydrated remaining - int exploration = __quest_state["Level 11 Desert"].state_int["Desert Exploration"]; - int explorationRemaining = 100 - exploration; - int roughUHTurnsNeeded = ceil(explorationRemaining.to_float()/2.0); - - // Append the lucky thing you can get, if you actually need it. Priority is because: - - // - Ore is an early clover dump that (in modern meta) generally wants either an early MM or an - // early clover. If you can't solve ore otherwise, this saves an absurd amount of turns - // - Zeppelin is the most important clover dump in-run traditionally; saves a good 5-6 turns - // apiece, more in some paths - // - Wand is necessary in almost every path, and next-most-important after zepp/ore. Saves a - // good 3-ish turns on having to lose an NS fight and find the wand in the cemetary - // - Ultrahydrated saves 2-ish turns in some paths - // - Mick's saves about 2 turns in some paths as well, but less so generally - // - A-Boo clues save half a turn apiece because you save 1 turn on a two clover a-boo - - // Beyond these, there is a mild case for some of the elemental damage clovers, but I - // don't think they warrant adding. Possibly worth adding to the actual tower test - // tile if you're at the tower test, but even then. Meh. - - if (!__quest_state["Level 8"].state_boolean["Past mine"] && $location[Itznotyerzitz Mine].locationAvailable()) - allTheLuckyStuff.listAppend("Ore"); - if (protestorsRemaining > 10 && protestorsPerClover > 15) - allTheLuckyStuff.listAppend("Zeppelin Mob (x"+projectedZeppClovers+")"); - cloversAdjusted = MAX(cloversAdjusted - projectedZeppClovers, 3); - if (__misc_state["wand of nagamar needed"] && lettersStillNeeded > 0) - allTheLuckyStuff.listAppend("Wand of Nagamar"); - if (roughUHTurnsNeeded > 5) - allTheLuckyStuff.listAppend("Ultrahydrated"); - if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) - allTheLuckyStuff.listAppend("Mick's Icyvapohotness Inhaler"); - if (aBooHauntedness > 0) - allTheLuckyStuff.listAppend("A-Boo Clues (x"+aBooCloversNeeded+")"); - cloversAdjusted = MAX(cloversAdjusted - aBooCloversNeeded, 3); - - string [int] selectedOptions; - - foreach key, luckyStuff in allTheLuckyStuff { - if (key < cloversAdjusted) selectedOptions.listAppend(luckyStuff); - } - - return selectedOptions; -} - - -//Clovers and Lucky -RegisterResourceGenerationFunction("LuckyGenerateResource"); -void LuckyGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!__misc_state["in run"]) return; - { - string [int] description; - string url; - description.listAppend(HTMLGenerateSpanFont("Have a Lucky adventure!", "green")); - - // Figure out how many clovers you have available/possible and join the needed components - int cloversAvailable = clampi(3 - get_property_int("_cloversPurchased"), 0, 3); - int cloversPossible = $item[11-leaf clover].available_amount() + cloversAvailable; - description.listAppend(luckyOptions(cloversPossible).listJoinComponents(", ")); - - - - if ($item[11-leaf clover].available_amount() > 0) - { - url = invSearch("11-leaf clover"); - resource_entries.listAppend(ChecklistEntryMake("__item 11-leaf clover", url, ChecklistSubentryMake(pluralise($item[11-leaf clover]), "Inhale leaves for good luck", description), 2).ChecklistEntrySetCombinationTag("fortune")); - } - if ($item[[10883]astral energy drink].available_amount() > 0 && $item[11-leaf clover].available_amount() == 0) - { - url = invSearch("astral energy drink"); - resource_entries.listAppend(ChecklistEntryMake("__item [10883]astral energy drink", url, ChecklistSubentryMake(pluralise(available_amount($item[[10883]astral energy drink]),"astral energy drink", "astral energy drinks"), "Costs 5 spleen each", description), 2).ChecklistEntrySetCombinationTag("fortune")); - } - else if ($item[[10883]astral energy drink].available_amount() > 0 && $item[11-leaf clover].available_amount() > 0) - { - url = invSearch("astral energy drink"); - resource_entries.listAppend(ChecklistEntryMake("__item [10883]astral energy drink", url, ChecklistSubentryMake(pluralise(available_amount($item[[10883]astral energy drink]),"astral energy drink", "astral energy drinks"), "Costs 5 spleen each", ""), 2).ChecklistEntrySetCombinationTag("fortune")); - } - - // Add a reminder to buy clovers if you haven't yet - string [int] hermitDescription; - if (cloversAvailable > 0) - { - url = "hermit.php"; - string title = HTMLGenerateSpanFont("Hey! You! GRAB YOUR CLOVERS!", "green"); - hermitDescription.listAppend(cloversAvailable + " in stock at the Hermit"); - resource_entries.listAppend(ChecklistEntryMake("__item 11-leaf clover", url, ChecklistSubentryMake(title, hermitDescription), -11).ChecklistEntrySetIDTag("Clover resource")); - } - } -} - -RegisterTaskGenerationFunction("LuckyGenerateTasks"); -void LuckyGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($effect[lucky!].have_effect() > 0) { - string [int] description; - string main_title = HTMLGenerateSpanFont("You feel lucky, punk!", "green") + ""; - - // Figure out how many clovers you have available/possible and join the needed components - int cloversAvailable = clampi(3 - get_property_int("_cloversPurchased"), 0, 3); - int cloversPossible = $item[11-leaf clover].available_amount() + cloversAvailable; - - if (__misc_state["in run"] && my_path().id == 44) { // path is grey you lol - description.listAppend("1x ore, 1x freezerburned ice cube, 1x full-length mirror."); - } - else if (__misc_state["in run"]) { - description.listAppend(luckyOptions(cloversPossible).listJoinComponents(", ")); - } - else { - description.listAppend("I dunno. Full-length mirror?"); - } - task_entries.listAppend(ChecklistEntryMake("__item 11-leaf clover", "", ChecklistSubentryMake(main_title, description), -11).ChecklistEntrySetIDTag("Fortune adventure now")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets/Misc Items.ash b/Source/relay/TourGuide/Sets/Misc Items.ash deleted file mode 100644 index 36ab2929..00000000 --- a/Source/relay/TourGuide/Sets/Misc Items.ash +++ /dev/null @@ -1,1263 +0,0 @@ -import "relay/TourGuide/Support/Campground.ash" - -void SMiscItemsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($item[the crown of ed the undying].equipped_amount() > 0 && get_property("edPiece").length() == 0) { - string [int] description; - - if (__misc_state["need to level"]) { - if (my_primestat() == $stat[muscle]) - description.listAppend("Bear - +2 mainstat/fight"); - else if (my_primestat() == $stat[mysticality]) - description.listAppend("Owl - +2 mainstat/fight"); - else if (my_primestat() == $stat[moxie]) - description.listAppend("Puma - +2 mainstat/fight"); - description.listAppend("Hyena - +20 ML"); - } - description.listAppend("Mouse - +10% item, +20% meat"); - description.listAppend("Weasel - survive first hit, regenerate HP"); - optional_task_entries.listAppend(ChecklistEntryMake("__item the crown of ed the undying", "inventory.php?action=activateedhat", ChecklistSubentryMake("Configure the Crown of Ed the Undying", "", description), 5).ChecklistEntrySetIDTag("UNDYING crown config")); - } - - if (__misc_state["in run"]) { - //Suggest acquiring a stasis source: - //If you're not in ronin, you should acquire a source from hangk's. - //If you are: suckerpunch as DB -> dictionary -> facsimile dictionary -> seal tooth - - boolean currently_have_source = false; - if (my_class() == $class[disco bandit]) - currently_have_source = true; - else if ($items[dictionary,facsimile dictionary,seal tooth].item_amount() > 0) - currently_have_source = true; - - boolean have_reason = false; - //Try not to annoy anyone that doesn't currently have a reason to stasis: - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) //to always trigger the underworld - have_reason = true; - if ($effect[everything looks yellow].have_effect() == 0 && $familiar[he-boulder].familiar_is_usable()) //to reach the correct eye - have_reason = true; - if ($familiars[stocking mimic,cocoabo,star starfish,Animated Macaroni Duck,Midget Clownfish,Rock Lobster,Snow Angel,Twitching Space Critter,slimeling,mini-hipster] contains my_familiar()) //MP delaying. grill intentionally left off, because it doesn't act as often in later rounds(?) - have_reason = true; - if (__quest_state["Level 12"].state_boolean["War started"] && __quest_state["Level 12"].in_progress && !__quest_state["Level 12"].state_boolean["Junkyard Finished"]) - have_reason = true; - - if (!currently_have_source && have_reason) { - boolean try_for_seal_tooth = false; - if (in_ronin()) { - item pull_item = $item[none]; - foreach it in $items[dictionary,facsimile dictionary,seal tooth] { - if (it.available_amount() > 0) { - pull_item = it; - break; - } - } - if (pull_item != $item[none]) { - string [int] description; - description.listAppend("Useful for delaying in-fight."); - optional_task_entries.listAppend(ChecklistEntryMake("__item " + pull_item, "storage.php?which=3", ChecklistSubentryMake("Pull a " + pull_item, "", description), 5).ChecklistEntrySetIDTag("Stasis item suggestions pull")); - } else - try_for_seal_tooth = true; - } else { - try_for_seal_tooth = true; - } - if (my_path().id == PATH_NUCLEAR_AUTUMN) - try_for_seal_tooth = false; - - if (try_for_seal_tooth) { - string url = ""; - string [int] description; - if ($items[worthless trinket,worthless gewgaw,worthless knick-knack].available_amount() == 0) { - url = "shop.php?whichshop=generalstore"; - description.listAppend("Use chewing gum on a string."); - } else { - url = "hermit.php"; - description.listAppend("From the hermit."); - } - - description.listAppend("Useful for delaying in-fight."); - optional_task_entries.listAppend(ChecklistEntryMake("__item seal tooth", url, ChecklistSubentryMake("Acquire a seal tooth", "", description), 5).ChecklistEntrySetIDTag("Stasis item suggestions seal tooth")); - } - } - } -} - -void SMiscItemsGenerateResource(ChecklistEntry [int] resource_entries) -{ - int importance_level_item = 7; - int importance_level_unimportant_item = 8; - - boolean in_run = __misc_state["in run"] && in_ronin(); - - int navel_percent_chance_of_runaway = 20; - if (true) { - //Look up navel ring chances: - int [int] navel_ring_runaway_chance; - navel_ring_runaway_chance[0] = 100; - navel_ring_runaway_chance[1] = 100; - navel_ring_runaway_chance[2] = 100; - navel_ring_runaway_chance[3] = 80; - navel_ring_runaway_chance[4] = 80; - navel_ring_runaway_chance[5] = 80; - navel_ring_runaway_chance[6] = 50; - navel_ring_runaway_chance[7] = 50; - navel_ring_runaway_chance[8] = 50; - navel_ring_runaway_chance[9] = 20; - int navel_runaway_progress = get_property_int("_navelRunaways"); - - if (navel_ring_runaway_chance contains navel_runaway_progress) - navel_percent_chance_of_runaway = navel_ring_runaway_chance[navel_runaway_progress]; - } - boolean have_navel_type_equipment = false; - if (__iotms_usable[lookupItem("navel ring of navel gazing")]) { - have_navel_type_equipment = true; - string name = "Navel Ring runaways"; - - string url = ""; - if ($item[navel ring of navel gazing].equipped_amount() == 0) - url = "inventory.php?ftext=navel+ring+of+navel+gazing"; - - string [int] description; - description.listAppend(navel_percent_chance_of_runaway + "% chance of free runaway."); - resource_entries.listAppend(ChecklistEntryMake("__item navel ring of navel gazing", url, ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Navel ring of navel gazing")); - } - if (__iotms_usable[lookupItem("Greatest American Pants")]) { - have_navel_type_equipment = true; - string name = "Greatest American Pants"; - - string url = ""; - if ($item[greatest american pants].equipped_amount() == 0) - url = "inventory.php?ftext=greatest+american+pants"; - else - url = "inventory.php?action=activatesuperpants"; - - string [int] description; - description.listAppend(navel_percent_chance_of_runaway + "% chance of free runaway."); - - int buffs_remaining = 5 - get_property_int("_gapBuffs"); - if (buffs_remaining > 0) - description.listAppend(pluralise(buffs_remaining, "buff", "buffs") + " remaining."); - resource_entries.listAppend(ChecklistEntryMake("__item greatest american pants", url, ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Greatest american pants")); - } - if ($item[peppermint parasol].available_amount() > 0 && in_run && !have_navel_type_equipment) { - int parasol_progress = get_property_int("parasolUsed"); - string name = ""; - - name = parasol_progress + "/10 peppermint parasol uses"; - string [int] description; - description.listAppend(navel_percent_chance_of_runaway + "% chance of free runaway."); - resource_entries.listAppend(ChecklistEntryMake("__item peppermint parasol", "", ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Peppermint parasol resource")); - } - if ($item[pantsgiving].available_amount() > 0) { - ChecklistSubentry subentry = ChecklistSubentryMake("Pantsgiving", "", ""); - - string url = ""; - - if ($item[pantsgiving].equipped_amount() == 0) - url = "inventory.php?ftext=pantsgiving"; - - - int banishes_available = 5 - get_property_int("_pantsgivingBanish"); - if (banishes_available > 0 && $skill[Talk About Politics].skill_is_usable()) { - //subentry.entries.listAppend(pluralise(banishes_available, "banish", "banishes") + " available."); - string [int] tasks; - if ($item[pantsgiving].equipped_amount() == 0) - tasks.listAppend("equip pantsgiving"); - tasks.listAppend("cast talk about politics"); - resource_entries.listAppend(ChecklistEntryMake("__item pantsgiving", url, ChecklistSubentryMake(pluralise(banishes_available, "Pantsgiving banish", "Pantsgiving banishes"), "", tasks.listJoinComponents(", ").capitaliseFirstLetter() + "."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Pantsgiving banish")); - - } - - int pantsgiving_fullness_used = get_property_int("_pantsgivingFullness"); - int pantsgiving_adventures_used = get_property_int("_pantsgivingCount"); - int pantsgiving_pocket_crumbs_found = get_property_int("_pantsgivingCrumbs"); - int pantsgiving_potential_crumbs_remaining = 10 - pantsgiving_pocket_crumbs_found; - - int adventures_needed_for_fullness_boost = 5 * powi(10, pantsgiving_fullness_used); - int adventures_needed_for_fullness_boost_x2 = 5 * powi(10, 1 + pantsgiving_fullness_used); - int adventures_needed_for_fullness_boost_x3 = 5 * powi(10, 2 + pantsgiving_fullness_used); - int adventures_needed_for_fullness_boost_x4 = 5 * powi(10, 3 + pantsgiving_fullness_used); - - if (adventures_needed_for_fullness_boost > pantsgiving_adventures_used) { - int number_left = adventures_needed_for_fullness_boost - pantsgiving_adventures_used; - subentry.entries.listAppend(pluralise(number_left, "adventure", "adventures") + " until next fullness."); - } else { //already there - int number_left_for_next = -1; - string extra_fullness_available = "Fullness"; - if (pantsgiving_adventures_used >= adventures_needed_for_fullness_boost_x2) { - extra_fullness_available = "2x fullness"; - } else if (number_left_for_next == -1) - number_left_for_next = adventures_needed_for_fullness_boost_x2 - pantsgiving_adventures_used; - if (pantsgiving_adventures_used >= adventures_needed_for_fullness_boost_x3) { - extra_fullness_available = "3x fullness"; - } else if (number_left_for_next == -1) - number_left_for_next = adventures_needed_for_fullness_boost_x3 - pantsgiving_adventures_used; - if (pantsgiving_adventures_used >= adventures_needed_for_fullness_boost_x4) { - extra_fullness_available = "4x fullness (wh.. what?)"; - } else if (number_left_for_next == -1) - number_left_for_next = adventures_needed_for_fullness_boost_x4 - pantsgiving_adventures_used; - - if (availableFullness() == 0) { - subentry.entries.listAppend(extra_fullness_available + " available next adventure."); - } else - subentry.entries.listAppend(extra_fullness_available + " available when you're full."); - if (number_left_for_next != -1) - subentry.entries.listAppend(pluralise(number_left_for_next, "adventure", "adventures") + " until next stored fullness."); - } - - if (pantsgiving_potential_crumbs_remaining > 0 && $skill[pocket crumbs].skill_is_usable()) - subentry.entries.listAppend(pluralise(pantsgiving_potential_crumbs_remaining, " pocket crumb item", " pocket crumb items") + " left."); - - if (subentry.entries.count() > 0) { - ChecklistEntry entry = ChecklistEntryMake("__item pantsgiving", url, subentry); - entry.tags.id = "Pantsgiving resource"; - entry.should_indent_after_first_subentry = true; - resource_entries.listAppend(entry); - } - } - - - - if (__misc_state["free runs usable"] && in_run && $item[bottle of blank-out].available_amount() > 0) { - string [int] description; - string name; - int blankout_count = $item[bottle of blank-out].available_amount(); - name += pluralise(blankout_count, "blank-out", "blank-out"); - - if ($item[glob of blank-out].available_amount() == 0) - description.listAppend("Use blank-out for glob."); - if (get_property_boolean("_blankoutUsed")) - description.listAppend("Will have to wait until tomorrow to open."); - - resource_entries.listAppend(ChecklistEntryMake("__item Bottle of Blank-Out", "inventory.php?ftext=bottle+of+blank-out", ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Blank-out bottle resource")); - } - if (__misc_state["free runs usable"] && $item[glob of blank-out].available_amount() > 0) { - int uses_remaining = 5 - get_property_int("blankOutUsed"); - string [int] description; - string name; - description.listAppend("Use glob of blank-out in combat."); - if (!in_run) - description.listAppend("Will disappear when you ascend."); - - name = pluralise(uses_remaining, "blank-out runaway", "blank-out runaways"); - resource_entries.listAppend(ChecklistEntryMake("__item glob of blank-out", "", ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Blank-out glob free run")); - } - - if ($item[BitterSweetTarts].available_amount() > 0 && __misc_state["need to level"]) { - int stat_modifier = min(11, my_level()); - string [int] description; - description.listAppend("+" + stat_modifier + " stats/fight, 10 turns"); - if (my_level() < 11) { - description.listAppend("Wait until level 11 for full effectiveness"); - } - resource_entries.listAppend(ChecklistEntryMake("__item BitterSweetTarts", "inventory.php?ftext=bittersweettarts", ChecklistSubentryMake(pluralise($item[BitterSweetTarts]), "", description), importance_level_item).ChecklistEntrySetIDTag("Bittersweettarts resource")); - } - if ($item[polka pop].available_amount() > 0 && in_run) { - int item_and_meat_modifier = 5 * min(11, my_level()); - string [int] description; - description.listAppend("+" + item_and_meat_modifier + "% item, " + "+" + item_and_meat_modifier + "% meat"); - if (my_level() < 11) { - description.listAppend("Wait until level 11 for full effectiveness"); - } - resource_entries.listAppend(ChecklistEntryMake("__item polka pop", "", ChecklistSubentryMake(pluralise($item[polka pop]), "10 turns", description), importance_level_item).ChecklistEntrySetIDTag("Polka pop resource")); - } - - if ($item[frost flower].available_amount() > 0 && in_run && my_path().id != PATH_G_LOVER) { - string [int] description; - description.listAppend("+100% item, +200% meat, +25 ML, +100% init"); - resource_entries.listAppend(ChecklistEntryMake("__item frost flower", "inventory.php?ftext=frost+flower", ChecklistSubentryMake($item[frost flower].pluralise(), "50 turns", description), importance_level_item).ChecklistEntrySetIDTag("Frost flower resource")); - } - if (in_run) { - //Resolutions: - string [item] resolution_descriptions; - resolution_descriptions[$item[resolution: be happier]] = "+15% item (20 turns)"; - //resolution_descriptions[$item[resolution:be feistier]] = "+20 spell damage"; //information overload? - if (__misc_state["need to level"]) { - resolution_descriptions[$item[resolution: be stronger]] = "+2 muscle stats/combat (20 turns)"; - resolution_descriptions[$item[resolution: be smarter]] = "+2 mysticality stats/combat (20 turns)"; - resolution_descriptions[$item[resolution: be sexier]] = "+2 moxie stats/combat (20 turns)"; - } - resolution_descriptions[$item[resolution: be kinder]] = "+5 familiar weight (20 turns)"; - resolution_descriptions[$item[resolution: be luckier]] = "+5% item, +5% meat, +10% init, others (20 turns)"; //??? - if (my_path().id != PATH_SLOW_AND_STEADY) - resolution_descriptions[$item[resolution: be more adventurous]] = "+2 adventures at rollover"; - resolution_descriptions[$item[resolution: be wealthier]] = "+30% meat"; - - - - ChecklistSubentry [int] resolution_lines; - foreach it in resolution_descriptions { - if (it.available_amount() == 0) - continue; - string description = resolution_descriptions[it]; - - resolution_lines.listAppend(ChecklistSubentryMake(pluralise(it), "", description)); - } - if (resolution_lines.count() > 0) - resource_entries.listAppend(ChecklistEntryMake("__item resolution: be luckier", "inventory.php?ftext=resolution:+be", resolution_lines, importance_level_item).ChecklistEntrySetIDTag("Resolutions resource")); - - } - if (in_run) { - //doesn't show how much, because wahh I don't wanna write taffy code - string [item] taffy_descriptions; - taffy_descriptions[$item[pulled yellow taffy]] = "+meat, +item"; - if (__misc_state["need to level"]) { - taffy_descriptions[$item[pulled red taffy]] = "+moxie stats/fight"; - taffy_descriptions[$item[pulled orange taffy]] = "+muscle stats/fight"; - taffy_descriptions[$item[pulled violet taffy]] = "+mysticality stats/fight"; - } - taffy_descriptions[$item[pulled blue taffy]] = "+familiar weight, +familiar experience"; - string image_name = ""; - ChecklistSubentry [int] taffy_lines; - foreach it in taffy_descriptions { - if (it.available_amount() == 0) - continue; - string description = taffy_descriptions[it]; - if (image_name == "") - image_name = "__item " + it; - taffy_lines.listAppend(ChecklistSubentryMake(pluralise(it), "", description)); - } - if (taffy_lines.count() > 0) - resource_entries.listAppend(ChecklistEntryMake(image_name, "inventory.php?ftext=pulled", taffy_lines, importance_level_item).ChecklistEntrySetIDTag("Pulled taffy resource")); - - } - - - - if (in_run) { - if (7014.to_item().available_amount() > 0) //Louder than bomb - resource_entries.listAppend(ChecklistEntryMake("__item " + 7014.to_item().to_string(), "", ChecklistSubentryMake(pluralise(7014.to_item()), "", "Free run, 20-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Louder than bomb banish")); - if ($item[crystal skull].available_amount() > 0) - resource_entries.listAppend(ChecklistEntryMake("__item crystal skull", "", ChecklistSubentryMake(pluralise($item[crystal skull]), "", "Takes a turn, 20-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Crystal skull banish")); - - if ($item[harold's bell].available_amount() > 0 && $item[harold's bell].item_is_usable()) - resource_entries.listAppend(ChecklistEntryMake("__item harold's bell", "", ChecklistSubentryMake(pluralise($item[harold's bell]), "", "Takes a turn, 20-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Harold's bell banish")); - - if ($item[lost key].available_amount() > 0 && $item[lost key].item_is_usable()){ - string [int] details; - details.listAppend("Lost pill bottle is mini-fridge, take a nap, open the pill bottle."); - //FIXME does stunning work on tower monsters? - //if (!__quest_state["Level 13"].state_boolean["past tower monsters"] && (!$item[munchies pill].is_unrestricted() || !__misc_state["can eat just about anything"])) - //details.listAppend("The lost comb is turn on the TV, take a nap, pick up the comb. (towerkilling)"); - if ($classes[pastamancer,sauceror] contains my_class() && $skill[Transcendental Noodlecraft].skill_is_usable() && $skill[The Way of Sauce].skill_is_usable() && $skill[pulverize].skill_is_usable()) - details.listAppend("The lost glasses is mini-fridge, TV, glasses."); - resource_entries.listAppend(ChecklistEntryMake("__item lost key", "inventory.php?ftext=lost+key", ChecklistSubentryMake(pluralise($item[lost key]), "", details), importance_level_item).ChecklistEntrySetIDTag("Lost pill bottle resource")); - } - - if ($item[soft green echo eyedrop antidote].available_amount() > 0 && $skill[Transcendent Olfaction].skill_is_usable()) - resource_entries.listAppend(ChecklistEntryMake("__item soft green echo eyedrop antidote", "", ChecklistSubentryMake(pluralise($item[soft green echo eyedrop antidote]), "", "Removes unwanted effects; teleportitis-likes, debuffs, etc."), importance_level_unimportant_item).ChecklistEntrySetIDTag("SGEEA resource")); - - if ($item[sack lunch].available_amount() > 0) { - string [int] description; - int importance = importance_level_item; - if (my_level() < 11) { - description.listAppend("Wait until level 11+ to open for best food."); - importance = importance_level_unimportant_item; - } else { - description.listAppend("Safe to open."); - } - resource_entries.listAppend(ChecklistEntryMake("__item sack lunch", "inventory.php?ftext=sack+lunch", ChecklistSubentryMake(pluralise($item[sack lunch]), "", description), importance).ChecklistEntrySetIDTag("Sack lunch resource")); - } - - if (true) { - ChecklistSubentry [int] subentries; - string image_name = ""; - - string [item] descriptions; - descriptions[$item[NPZR chemistry set]] = "Open for 20 invisibility/irresistibility/irritability potions."; - descriptions[$item[invisibility potion]] = "-5% combat (20 turns)"; - descriptions[$item[irresistibility potion]] = "+5% combat (20 turns)"; - descriptions[$item[irritability potion]] = "+15 ML (20 turns)"; - - foreach it in $items[NPZR chemistry set,invisibility potion,irresistibility potion,irritability potion] { - if (it.available_amount() == 0) - continue; - if (image_name.length() == 0) - image_name = "__item " + it; - - subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", descriptions[it])); - } - - if (subentries.count() > 0) - resource_entries.listAppend(ChecklistEntryMake(image_name, "inventory.php?which=3", subentries, importance_level_item).ChecklistEntrySetIDTag("NPZR chemistry set resource")); - } - } - if ($item[smut orc keepsake box].available_amount() > 0 && !__quest_state["Level 9"].state_boolean["bridge complete"] && __misc_state["in run"]) - resource_entries.listAppend(ChecklistEntryMake("__item smut orc keepsake box", "inventory.php?ftext=smut+orc+keepsake+box", ChecklistSubentryMake(pluralise($item[smut orc keepsake box]), "", "Open for bridge building."), 0).ChecklistEntrySetIDTag("Smut orc keepsake box")); - - if ($item[wand of pigification].available_amount() > 0 && in_bad_moon() && __misc_state["in run"]) { - resource_entries.listAppend(ChecklistEntryMake("__item wand of pigification", "", ChecklistSubentryMake("Wand of pigification", "", "Use twice a day on monsters for good-level food."), 6).ChecklistEntrySetIDTag("Pigification wand resource")); - } - - int clovers_available = $items[11-leaf clover].available_amount() + $item[11-leaf clover].closet_amount(); - // Removing clover code and swapping to lucky code like TES has. - // if (my_path().id == PATH_BEES_HATE_YOU || my_path().id == PATH_G_LOVER) - // clovers_available = $item[ten-leaf clover].item_amount() + $item[ten-leaf clover].closet_amount(); - // if (clovers_available > 0 && in_run) { - // ChecklistSubentry subentry; - // subentry.header = pluralise(clovers_available, "clover", "clovers") + " available"; - - - // if (!__quest_state["Level 9"].state_boolean["bridge complete"]) - // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Orc logging camp, for bridge building. (3/3)", $location[the smut orc logging camp])); - // if ($item[a-boo clue].available_amount() < 4 && (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0 || !__quest_state["Level 9"].state_boolean["bridge complete"]) && my_path().id != PATH_G_LOVER) - // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("A-Boo clues. (2)", $location[a-boo peak])); - // if (__misc_state["wand of nagamar needed"] && $item[wand of nagamar].creatable_amount() == 0) - // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Wand of nagamar components (castle basement)", $location[the castle in the clouds in the sky (basement)])); - // boolean have_all_gum = $item[pack of chewing gum].available_amount() > 0 || ($item[jabañero-flavored chewing gum].available_amount() > 0 && $item[lime-and-chile-flavored chewing gum].available_amount() > 0 && $item[pickle-flavored chewing gum].available_amount() > 0 && $item[tamarind-flavored chewing gum].available_amount() > 0); - // if (__quest_state["Level 4"].state_int["areas unlocked"] + $item[sonar-in-a-biscuit].available_amount() < 2) - // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("2 sonar-in-a-biscuit (Guano Junction)", $location[guano junction])); - - // if (__quest_state["Level 11 Ron"].mafia_internal_step <= 2 && __quest_state["Level 11 Ron"].state_int["protestors remaining"] > 1) - // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Mob of zeppelin protestors NC", $location[A Mob of Zeppelin Protesters])); - // if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && !(get_property_boolean("lovebugsUnlocked") && $item[bottle of lovebug pheromones].is_unrestricted())) { //taking a gamble here - I'm assuming you'd never clover for ultrahydrated if you have lovebugs. even if you run out of ultrahydrated, you'll likely get it again in a hurry - // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Ultrahydrated (Oasis)", $location[the oasis])); - // } - // if (!__quest_state["Level 8"].state_boolean["Past mine"]) { - // item ore_needed = __quest_state["Level 8"].state_string["ore needed"].to_item(); - // if (ore_needed == $item[none]) - // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Mining ore. (1)", $location[itznotyerzitz mine])); - // else - // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability(ore_needed.capitaliseFirstLetter() + ". (1)", $location[itznotyerzitz mine])); - // } - // if (__misc_state["need to level"] && !__misc_state["Stat gain from NCs reduced"]) { - // location l = $location[none]; - // if (my_primestat() == $stat[moxie]) - // l = $location[the haunted ballroom]; - // else if (my_primestat() == $stat[mysticality]) - // l = $location[the haunted bathroom]; - // else if (my_primestat() == $stat[muscle]) - // l = $location[the haunted gallery]; - // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Powerlevelling (" + l + ")", l)); - // } - // //put relevant tower items here - - // resource_entries.listAppend(ChecklistEntryMake("clover", "", subentry, 7).ChecklistEntrySetCombinationTag("clovers").ChecklistEntrySetIDTag("Ten-leaf clover resource")); - // } - // Turning off because lucky pills are garbage now. - - // if (in_run && $item[lucky pill].have() && availableSpleen() > 0) { - // string [int] description; - // description.listAppend("Chew for clovers."); - // resource_entries.listAppend(ChecklistEntryMake("__item lucky pill", "inventory.php?ftext=lucky+pill", ChecklistSubentryMake(pluralise($item[lucky pill]), "", description), importance_level_unimportant_item).ChecklistEntrySetCombinationTag("clovers").ChecklistEntrySetIDTag("Lucky pill resource")); - // } - if (in_run) { - if ($item[gameinformpowerdailypro magazine].available_amount() > 0) { - string [int] description; - description.listAppend("Zero-turn free SGEAA and scrolls"); - resource_entries.listAppend(ChecklistEntryMake("__item gameinformpowerdailypro magazine", "inventory.php?ftext=gameinformpowerdailypro+magazine", ChecklistSubentryMake(pluralise($item[gameinformpowerdailypro magazine]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Gameinformpowerdailypro magazine")); - } - } - if ($item[divine champagne popper].available_amount() > 0 && in_run) { - resource_entries.listAppend(ChecklistEntryMake("__item divine champagne popper", "", ChecklistSubentryMake(pluralise($item[divine champagne popper]), "", "Free run, 5-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Champagne popper banish")); - } - if (__misc_state["need to level"]) { - if ($item[dance card].available_amount() > 0 && my_primestat() == $stat[moxie] && in_ronin()) { - string [int] description; - description.listAppend("Gain ~" + round(__misc_state_float["dance card average stats"]) + " mainstat from delayed adventure in the haunted ballroom."); - resource_entries.listAppend(ChecklistEntryMake("__item dance card", "inventory.php?ftext=dance+card", ChecklistSubentryMake(pluralise($item[dance card]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Powerlevel dance card")); - } - } - if ($item[stone wool].available_amount() > 0 && in_ronin() && $item[stone wool].item_is_usable()) { - string [int] description; - string url = "inventory.php?ftext=stone+wool"; - int quest_needed = 2; - if ($item[the nostril of the serpent].available_amount() > 0 || get_property_ascension("lastTempleButtonsUnlock")) - quest_needed -= 1; - if (locationAvailable($location[the hidden park]) || !in_run) - quest_needed = 0; - - if (quest_needed > 0) - description.listAppend(quest_needed + " to unlock hidden city."); - if (__misc_state["need to level"]) - description.listAppend("Cave bar."); - if (!get_property_ascension("lastTempleAdventures") && my_path().id != PATH_SLOW_AND_STEADY) { - string line = "+3 adventures, +3 duration to ten effects. (once/ascension)"; - if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) - line += "|Can use to extend effects at nuns."; - description.listAppend(line); - } - if (!__misc_state["in run"] && $effect[stone-faced].have_effect() > 0) - url = $location[the hidden temple].getClickableURLForLocation(); - if (description.count() > 0) - resource_entries.listAppend(ChecklistEntryMake("__item stone wool", url, ChecklistSubentryMake(pluralise($item[stone wool]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Stone wool resource")); - } - if ($item[the legendary beat].available_amount() > 0 && !get_property_boolean("_legendaryBeat")) { - resource_entries.listAppend(ChecklistEntryMake("__item The Legendary Beat", "inventory.php?ftext=the+legendary+beat", ChecklistSubentryMake("The Legendary Beat", "", "+50% item. (20 turns)"), importance_level_item).ChecklistEntrySetIDTag("Legendary beat resource")); - - } - item zap_wand_owned; - if (true) { - zap_wand_owned = $item[none]; - foreach wand in $items[aluminum wand,ebony wand,hexagonal wand,marble wand,pine wand] { - if (wand.available_amount() > 0) { - zap_wand_owned = wand; - break; - } - } - if (zap_wand_owned != $item[none]) { - string url = "wand.php?whichwand=" + zap_wand_owned.to_int(); - int zaps_used = get_property_int("_zapCount"); - string [int] details; - if (zaps_used == 0) - details.listAppend("Can zap safely."); - else { - float [int] chances; - chances[1] = 75.0; - chances[2] = 18.75; - chances[3] = 1.5625; - float chance = chances[zaps_used]; - - if (zaps_used >= 4) - details.listAppend("Warning: Cannot zap."); - else - details.listAppend("Warning: " + roundForOutput(100.0 - chance, 1) + "% chance of explosion."); - if ($item[Platinum Yendorian Express Card].available_amount() > 0 && !get_property_boolean("expressCardUsed")) - details.listAppend("Platinum Yendorian Express Card usable."); - } - resource_entries.listAppend(ChecklistEntryMake(zap_wand_owned, url, ChecklistSubentryMake(pluralise(zaps_used, "zap", "zaps") + " used with " + zap_wand_owned, "", details), 10).ChecklistEntrySetIDTag("Zapping resource")); - } - } - - if (!get_property_boolean("_defectiveTokenChecked") && get_property_ascension("lastArcadeAscension")) { - resource_entries.listAppend(ChecklistEntryMake("__item jackass plumber home game", "place.php?whichplace=arcade", ChecklistSubentryMake("Broken arcade game", "", "May find a defective game grid token."), importance_level_item).ChecklistEntrySetIDTag("Defective game grid token check")); - } - if ($item[picky tweezers].available_amount() > 0 && !get_property_boolean("_pickyTweezersUsed")) { - resource_entries.listAppend(ChecklistEntryMake("__item picky tweezers", "inventory.php?ftext=picky+tweezers", ChecklistSubentryMake("Picky tweezers", "", "Acquire a single atom."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Picky tweezers resource")); - } - if ($item[defective Game Grid token].available_amount() > 0 && !get_property_boolean("_defectiveTokenUsed")) { - string [int] description; - description.listAppend("+5 to everything. (5 turns)"); - - resource_entries.listAppend(ChecklistEntryMake("__item defective Game Grid token", "inventory.php?ftext=defective+game+grid+token", ChecklistSubentryMake("Defective Game Grid Token", "", description), importance_level_item).ChecklistEntrySetIDTag("Defective game grid token use")); - } - if ($item[Platinum Yendorian Express Card].available_amount() > 0 && !get_property_boolean("expressCardUsed")) { - string [int] description; - string line = "Extends buffs, restores MP"; - if (get_property_int("_zapCount") > 0 && zap_wand_owned != $item[none] && zap_wand_owned.available_amount() > 0) - line += ", cools down " + zap_wand_owned; - line += "."; - description.listAppend(line); - resource_entries.listAppend(ChecklistEntryMake("__item Platinum Yendorian Express Card", "", ChecklistSubentryMake("Platinum Yendorian Express Card", "", description), importance_level_item).ChecklistEntrySetIDTag("Platinum yendorian express card")); - } - - - if ($item[mojo filter].available_amount() > 0 && get_property_int("currentMojoFilters") <3 && in_run) { - int mojo_filters_usable = MIN(my_spleen_use(), MIN(3 - get_property_int("currentMojoFilters"), $item[mojo filter].available_amount())); - string line = "Removes one spleen each."; - if (mojo_filters_usable != $item[mojo filter].available_amount()) - line += "|" + pluralise(mojo_filters_usable, "filter", "filters") + " usable."; - - if (mojo_filters_usable > 0) - resource_entries.listAppend(ChecklistEntryMake("__item mojo filter", "inventory.php?ftext=mojo+filter", ChecklistSubentryMake(pluralise($item[mojo filter]), "", line), importance_level_unimportant_item).ChecklistEntrySetIDTag("Mojo filter resource")); - } - if ($item[distention pill].available_amount() > 0 && !get_property_boolean("_distentionPillUsed") && in_run) { - resource_entries.listAppend(ChecklistEntryMake("__item distention pill", "inventory.php?ftext=distention+pill", ChecklistSubentryMake(pluralise($item[distention pill]), "", "Adds one extra fullness.|Once/day."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Distention pill resource")); - } - if ($item[synthetic dog hair pill].available_amount() > 0 && !get_property_boolean("_syntheticDogHairPillUsed") && in_run) { - resource_entries.listAppend(ChecklistEntryMake("__item synthetic dog hair pill", "inventory.php?ftext=synthetic+dog+hair+pill", ChecklistSubentryMake(pluralise($item[synthetic dog hair pill]), "", "Adds one extra drunkenness.|Once/day."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Dog hair pill resource")); - } - if ($item[the lost pill bottle].available_amount() > 0 && in_run && my_path().id != PATH_BEES_HATE_YOU) { - string header = pluralise($item[the lost pill bottle]); - if ($item[the lost pill bottle].available_amount() == 1) - header = $item[the lost pill bottle]; - resource_entries.listAppend(ChecklistEntryMake("__item the lost pill bottle", "inventory.php?ftext=the+lost+pill+bottle", ChecklistSubentryMake(header, "", "Open it."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Lost pill bottle")); - } - if ($item[Boozehounds Anonymous token].available_amount() > 0 && in_run && (__quest_state["White Citadel"].started || (__quest_state["Spooky Forest"].started && my_path().id != PATH_COMMUNITY_SERVICE))) { - resource_entries.listAppend(ChecklistEntryMake("__item Boozehounds Anonymous token", invSearch($item[Boozehounds Anonymous token]), ChecklistSubentryMake($item[Boozehounds Anonymous token].pluralise(), "free booze", ""), importance_level_unimportant_item).ChecklistEntrySetIDTag("Boozehound token resource")); - } - if (__misc_state["need to level"] && in_ronin()) { - if ($item[Marvin's marvelous pill].available_amount() > 0 && __misc_state["need to level moxie"]) { - resource_entries.listAppend(ChecklistEntryMake("__item Marvin's marvelous pill", "", ChecklistSubentryMake(pluralise($item[Marvin's marvelous pill]), "", "+20% to moxie gains. (10 turns)"), importance_level_unimportant_item).ChecklistEntrySetIDTag("Marvin pill resource")); - } - if ($item[drum of pomade].available_amount() > 0 && __misc_state["need to level moxie"]) { - resource_entries.listAppend(ChecklistEntryMake("__item drum of pomade", "", ChecklistSubentryMake(pluralise($item[drum of pomade]), "", "+15% to moxie gains. (10 turns)"), importance_level_unimportant_item).ChecklistEntrySetIDTag("Pomade drum resource")); - } - if ($item[baobab sap].available_amount() > 0 && __misc_state["need to level muscle"]) { - resource_entries.listAppend(ChecklistEntryMake("__item baobab sap", "", ChecklistSubentryMake(pluralise($item[baobab sap]), "", "+20% to muscle gains. (10 turns)"), importance_level_unimportant_item).ChecklistEntrySetIDTag("Baobab sap resource")); - } - if ($item[desktop zen garden].available_amount() > 0 && __misc_state["need to level mysticality"]) { - resource_entries.listAppend(ChecklistEntryMake("__item desktop zen garden", "", ChecklistSubentryMake(pluralise($item[desktop zen garden]), "", "+20% to mysticality gains. (10 turns)"), importance_level_unimportant_item).ChecklistEntrySetIDTag("Desktop zen garden resource")); - } - } - if ($item[munchies pill].available_amount() > 0 && fullness_limit() > 0 && in_run && my_path().id != PATH_SLOW_AND_STEADY) { - resource_entries.listAppend(ChecklistEntryMake("__item munchies pill", "", ChecklistSubentryMake(pluralise($item[munchies pill]), "", "+3 turns from fortune cookies and other low-fullness foods."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Munchies pill resource")); - } - if ($item[snow cleats].available_amount() > 0 && in_run) - resource_entries.listAppend(ChecklistEntryMake("__item snow cleats", "", ChecklistSubentryMake(pluralise($item[snow cleats]), "", "-5% combat, 30 turns."), importance_level_item).ChecklistEntrySetIDTag("Snow cleats resource")); - - if ($item[vitachoconutriment capsule].available_amount() > 0 && get_property_int("_vitachocCapsulesUsed") <3 && in_run) { - string [int] adventures_remaining; - int capsules_remaining = $item[vitachoconutriment capsule].available_amount(); - int vita_used = get_property_int("_vitachocCapsulesUsed"); - if (vita_used < 1) { - adventures_remaining.listAppend("+5"); - vita_used += 1; - capsules_remaining -= 1; - } - if (vita_used < 2 && capsules_remaining > 0) { - adventures_remaining.listAppend("+3"); - vita_used += 1; - capsules_remaining -= 1; - } - if (vita_used < 3 && capsules_remaining > 0) { - adventures_remaining.listAppend("+1"); - } - string line; - line = adventures_remaining.listJoinComponents("/") + " adventures"; - if (adventures_remaining.count() == 1) { //hacky - if (adventures_remaining[0] == "+1") - line = "+1 adventure"; - } - line += "."; - resource_entries.listAppend(ChecklistEntryMake("__item vitachoconutriment capsule", "inventory.php?ftext=vitachoconutriment+capsule", ChecklistSubentryMake(pluralise($item[vitachoconutriment capsule]), "", line), importance_level_unimportant_item).ChecklistEntrySetIDTag("Vitachoconutriment capsule")); - } - if (in_run && lookupItem("tryptophan dart").available_amount() > 0 && in_ronin() && lookupItem("tryptophan dart").item_is_usable()) { - resource_entries.listAppend(ChecklistEntryMake("__item tryptophan dart", "", ChecklistSubentryMake(pluralise(lookupItem("tryptophan dart")), "", "Non-free all-day banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Tryptophan dart banish")); - } - if (in_run && __misc_state["free runs usable"] && get_property_int("_humanMuskUses") < 3 && lookupItem("human musk").available_amount() > 0 && lookupItem("human musk") != $item[none]) { - resource_entries.listAppend(ChecklistEntryMake("__item human musk", "", ChecklistSubentryMake(MIN(lookupItem("human musk").available_amount(), 3 - get_property_int("_humanMuskUses")).pluralise("human musk", "human musks"), "", "Free run/banish. Consumes item."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Human musk banish")); - } - - if ($item[drum machine].available_amount() > 0 && in_run && (my_adventures() <= 1 || (availableDrunkenness() < 0 && availableDrunkenness() > -4 && my_adventures() >= 1)) && __quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && $item[drum machine].item_is_usable()) { - //Daycount strategy that never works, suggest: - string line = (100.0 * ((item_drop_modifier_ignoring_plants() / 100.0 + 1.0) * (1.0 / 1000.0))).roundForOutput(2) + "% chance of spice melange."; - if (my_adventures() == 0) - line += "|Need one adventure."; - resource_entries.listAppend(ChecklistEntryMake("__item drum machine", "inventory.php?ftext=drum+machine", ChecklistSubentryMake(pluralise($item[drum machine]), "", line), importance_level_unimportant_item).ChecklistEntrySetIDTag("Drum machine spice melange")); - } - - - if ($items[stinky cheese sword,stinky cheese diaper,stinky cheese wheel,stinky cheese eye,Staff of Queso Escusado].available_amount() > 0) { - if (!get_property_boolean("_stinkyCheeseBanisherUsed")) - resource_entries.listAppend(ChecklistEntryMake("__item stinky cheese eye", "", ChecklistSubentryMake("Stinky cheese eye banish", "", "Free run."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Stinky cheese banish")); - - int stinky_cheese_charge = min(100, get_property_int("_stinkyCheeseCount")); - string title; - string [int] description; - string url; - url = invSearch("stinky cheese"); - int importance = importance_level_item; - - if (stinky_cheese_charge < 100) { - title = pluralise(stinky_cheese_charge, "/ 100 stinky cheese charge", "/ 100 stinky cheese charges"); - description.listAppend("+" + pluralise(stinky_cheese_charge / 10, "adventure", "adventures") + "/day pants (max +10)."); - description.listAppend("Or +" + stinky_cheese_charge / 5 + "% item/meat accessory (max +20%)."); - } else { - title = "Fully charged stinky cheese"; - description.listAppend("+10 adventures/day pants."); - description.listAppend("Or +20% item/meat accessory."); - importance = importance_level_unimportant_item; - } - description.listAppend("Or some other stinky things."); - - resource_entries.listAppend(ChecklistEntryMake("__item Ched", url, ChecklistSubentryMake(title, "", description), importance).ChecklistEntrySetIDTag("Stinky cheese resource")); - } - - if ($item[mayfly bait necklace].available_amount() > 0 && get_property_int("_mayflySummons") < 30) { - int uses_remaining = 30 - get_property_int("_mayflySummons"); - string url = $item[mayfly bait necklace].equipped() ? "" : "inventory.php?ftext=mayfly+bait+necklace"; - resource_entries.listAppend(ChecklistEntryMake("__item mayfly bait necklace", url, ChecklistSubentryMake(pluralise(uses_remaining, "mayfly summon available", "mayfly summons available"), "This probably does something useful", $item[mayfly bait necklace].equipped() ? "" : "Equip the necklace first."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Mayfly bait necklace")); - } - - if (in_run) { - // As of the ELG change, tatters are worse than other options. Only show if the user doesn't have those options. - if ($item[tattered scrap of paper].available_amount() > 0 && __misc_state["free runs usable"] && $item[tattered scrap of paper].item_is_usable() && !__iotms_usable[lookupItem("spring shoes")] && !__iotms_usable[lookupItem("spring shoes")] && $item[roman candelabra].available_amount() == 0) { - string [int] description; - description.listAppend(($item[tattered scrap of paper].available_amount() / 2.0).roundForOutput(1) + " free runs."); - if (in_bad_moon()) - description.listAppend("Or save for demon summoning."); - resource_entries.listAppend(ChecklistEntryMake("__item tattered scrap of paper", "", ChecklistSubentryMake(pluralise($item[tattered scrap of paper]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Tattered paper scrap free run")); - } - if (2371.to_item().available_amount() > 0 && __misc_state["free runs usable"]) { //green smoke bomb - item it = 2371.to_item(); - string [int] description; - description.listAppend((it.available_amount() * 0.9).roundForOutput(1) + " free runs."); - resource_entries.listAppend(ChecklistEntryMake("__item " + it, "", ChecklistSubentryMake(pluralise(it), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Green smoke bomb free run")); - } - if ($item[dungeoneering kit].available_amount() > 0) { - string line = "Open it."; - if ($item[dungeoneering kit].available_amount() > 1) - line = "Open them."; - resource_entries.listAppend(ChecklistEntryMake("__item dungeoneering kit", "inventory.php?ftext=dungeoneering+kit", ChecklistSubentryMake(pluralise($item[dungeoneering kit]), "", line), importance_level_unimportant_item).ChecklistEntrySetIDTag("Dungeoneering kit resource")); - } - if ($item[Box of familiar jacks].available_amount() > 0) - resource_entries.listAppend(ChecklistEntryMake("__item box of familiar jacks", "", ChecklistSubentryMake(pluralise($item[Box of familiar jacks]), "", "Gives current familiar equipment."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Box of familiar jacks resource")); - if ($item[csa fire-starting kit].available_amount() > 0 && !get_property_boolean("_fireStartingKitUsed")) { - string [int] description; - description.listAppend("All-day 4 HP/MP regeneration."); - if (hippy_stone_broken()) - description.listAppend("3 PVP fights."); - resource_entries.listAppend(ChecklistEntryMake("__item csa fire-starting kit", "inventory.php?ftext=csa+fire-starting+kit", ChecklistSubentryMake($item[csa fire-starting kit], "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("CSA fire-starting kit")); - } - - if ($item[transporter transponder].available_amount() > 0) { - string [int] options; - if (__misc_state["need to level"]) - options.listAppend("powerleveling"); - if (fullness_limit() > 0 || inebriety_limit() > 0) - options.listAppend("yellow ray in grimace for synthetic dog hair/distention pill"); - - string description = "Spaaaaace access."; - if (options.count() > 0) - description += "|" + options.listJoinComponents(", ", "and").capitaliseFirstLetter(); - resource_entries.listAppend(ChecklistEntryMake("__item transporter transponder", "", ChecklistSubentryMake(pluralise($item[transporter transponder]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Transporter transponder resource")); - } - } - - foreach it in $items[[10882]carton of astral energy drinks,astral hot dog dinner,astral six-pack] { - if (it.available_amount() == 0) - continue; - resource_entries.listAppend(ChecklistEntryMake("__item " + it, "inventory.php?ftext=" + it.replace_string(" ", "+"), ChecklistSubentryMake(pluralise(it), "", "Open for astral consumables."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Astral consumable open")); - } - - if ($item[map to safety shelter grimace prime].available_amount() > 0) { - string line = "Use for synthetic dog hair or distention pill."; - if (__misc_state["in aftercore"]) - line += "|Will disappear when you ascend."; - resource_entries.listAppend(ChecklistEntryMake("__item " + $item[map to safety shelter grimace prime], "inventory.php?ftext=map+to+safety+shelter+grimace+prime", ChecklistSubentryMake(pluralise($item[map to safety shelter grimace prime]), "", line), importance_level_unimportant_item).ChecklistEntrySetIDTag("Grimace shelter map resource")); - } - if ($item[rusty hedge trimmers].available_amount() > 0 && __quest_state["Level 9"].state_int["twin peak progress"] != 15 && in_run) { - string [int] description; - description.listAppend("Use to visit the Twin Peak non-combat."); - resource_entries.listAppend(ChecklistEntryMake("__item " + $item[rusty hedge trimmers], "inventory.php?ftext=rusty+hedge+trimmers", ChecklistSubentryMake(pluralise($item[rusty hedge trimmers]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Rusty hedge trimmers")); - } - - if (in_run && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) { - string image_name = ""; - string [int] autosell_list; - boolean [item] autosellable_items = $items[meat stack, dense meat stack, really dense meat stack, solid gold bowling ball, fancy seashell necklace, commemorative war stein,huge gold coin].makeConstantItemArrayMutable(); - if (!__iotms_usable[lookupItem("diabolic pizza cube")]) - autosellable_items[$item[space blanket]] = true; - autosellable_items[$item[1952 Mickey Mantle card]] = true; - if ($item[pixel coin] != $item[none]) - autosellable_items[$item[pixel coin]] = true; - foreach it in autosellable_items { - if (it.available_amount() == 0) - continue; - autosell_list.listAppend(it.pluralise()); - - if (image_name.length() == 0) - image_name = "__item " + it; - } - - string [int] open_list; - foreach it in $items[old coin purse, old leather wallet, black pension check, ancient vinyl coin purse, warm subject gift certificate,shiny stones] { - if (it.available_amount() == 0) - continue; - if (!it.item_is_usable()) continue; - open_list.listAppend(it.pluralise()); - - if (image_name.length() == 0) - image_name = "__item " + it; - } - - string url = ""; - string [int] description; - if (autosell_list.count() > 0) { - url = "sellstuff_ugly.php"; - description.listAppend("Autosell " + autosell_list.listJoinComponents(", ", "and") + "."); - } - if (open_list.count() > 0) { - url = "inventory.php?which=3"; - description.listAppend("Open " + open_list.listJoinComponents(", ", "and") + "."); - } - - if (description.count() > 0) { - resource_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake("Meat", "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Meat giving items resource")); - } - } - //Penultimate Fantasy chest? - - item odd_silver_coin = $item[odd silver coin]; - if (odd_silver_coin.available_amount() > 0 && in_run) { - string [int] description; - string [int][int] table; - //cinnamon cannoli - 2 - 1 fullness awesome food. not worthwhile? - //expensive champagne - 3 - 1-drunkness epic drink. not worthwhile? - //polo trophy - 3 - +50ML for 15 turns - //table.listAppend(listMake("polo trophy", "+50ML for 15 turns, marginal?", "3 coins")); //costs three adventures to find. I guess it'd only be relevant for cave bars? even then... - //fancy oil painting - 4 - bridge building. 10 progress - if (!__quest_state["Level 9"].state_boolean["bridge complete"] && (__quest_state["Level 9"].state_int["bridge fasteners needed"] > 0 || __quest_state["Level 9"].state_int["bridge lumber needed"] > 0)) - table.listAppend(listMake("fancy oil painting", "10 fasteners, 10 lumber", "4 coins")); - //solid gold rosary - 5 - better cyrpt progression. need details (-4.5 evil?) - if (!__quest_state["Level 7"].state_boolean["alcove finished"] || !__quest_state["Level 7"].state_boolean["cranny finished"] || !__quest_state["Level 7"].state_boolean["niche finished"] || !__quest_state["Level 7"].state_boolean["nook finished"]) - table.listAppend(listMake("solid gold rosary", "-4.5? evilness from cyrpt", "5 coins")); - //ornate dowsing rod - 5 - better desert exploration (+2%) - - if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && $item[ornate dowsing rod].available_amount() == 0) - table.listAppend(listMake("ornate dowsing rod", "+2% desert exploration", "5 coins")); - description.listAppend(HTMLGenerateSimpleTableLines(table)); - - resource_entries.listAppend(ChecklistEntryMake("__item " + odd_silver_coin, "shop.php?whichshop=cindy", ChecklistSubentryMake(odd_silver_coin.pluralise(), "", description), importance_level_item).ChecklistEntrySetIDTag("Odd silver coin shop")); - } - item grimstone_mask = $item[grimstone mask]; - if (grimstone_mask.available_amount() > 0 && in_run) { - string [int] description; - - description.listAppend("Wear to take you places."); - description.listAppend("The prince's ball (stepmother) lets you find odd silver coins.|Up to six, one adventure each."); - //description.listAppend("Rumpelstiltskin's for towerkilling with small golem.|Small golem is a 5k/round combat item.|Involves the semi-rare in village. Don't know the details, sorry."); //only somewhat relevant in obscure edge cases - if ($effect[Human-Fish Hybrid].have_effect() == 0 && __iotms_usable[$item[Little Geneticist DNA-Splicing Lab]] && !__misc_state["familiars temporarily blocked"]) - description.listAppend("Candy witch for human-fish hybrid. (+10 familiar weight)"); - if (get_property("grimstoneMaskPath") != "") - description.listAppend("Currently on the path of " + get_property("grimstoneMaskPath") + "."); - - resource_entries.listAppend(ChecklistEntryMake("__item " + grimstone_mask, "inventory.php?ftext=grimstone+mask", ChecklistSubentryMake(grimstone_mask.pluralise(), "", description), importance_level_item).ChecklistEntrySetIDTag("Grimstone mask resource")); - } - - if (__campground[$item[spinning wheel]] > 0 && !get_property_boolean("_spinningWheel")) { - string [int] description; - int meat_gained = powi(MIN(30, my_level()), 3); - description.listAppend("Will gain " + meat_gained + " meat."); - if (availableDrunkenness() >= 0) { - if (my_level() < 8) - description.listAppend("Wait until you've leveled up more."); - else if (my_level() < 13) - description.listAppend("Possibly wait until you've leveled up more?"); - } - resource_entries.listAppend(ChecklistEntryMake("__item spinning wheel", "campground.php?action=workshed", ChecklistSubentryMake("Spinning wheel meat", "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Campground spinning wheel")); - } - - if ($item[very overdue library book].available_amount() > 0 && in_run && __misc_state["need to level"] && $item[very overdue library book].item_is_usable()) { - resource_entries.listAppend(ChecklistEntryMake("__item very overdue library book", "inventory.php?ftext=very+overdue+library+book", ChecklistSubentryMake("Very overdue library book", "", "Open for 63 moxie/mysticality/muscle."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Overdue book resource")); - } - - if ($item[chest of the Bonerdagon].available_amount() > 0 && in_run && my_path().id != PATH_BEES_HATE_YOU) { - string description = "Open for 150 muscle/mysticality/moxie and 3k meat."; - if (!$familiar[ninja pirate zombie robot].have_familiar()) - description += "|Unless you want to make an NPZR this ascension."; - resource_entries.listAppend(ChecklistEntryMake("__item chest of the Bonerdagon", "inventory.php?ftext=chest+of+the+Bonerdagon", ChecklistSubentryMake("chest of the Bonerdagon", "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Bonerdagon chest resource")); - } - - if ($item[smoke grenade].available_amount() > 0 && in_run) { - string description = "Turn-costing banish. (lasts 20 turns, no stats, no items, no meat)"; - resource_entries.listAppend(ChecklistEntryMake("__item smoke grenade", "", ChecklistSubentryMake(pluralise($item[Smoke grenade]), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Smoke grenade banish")); - } - - if ($item[pile of ashes].available_amount() > 0 && in_run) { - string description = "-10% combat. (20 turns)"; - resource_entries.listAppend(ChecklistEntryMake("__item pile of ashes", "inventory.php?ftext=pile+of+ashes", ChecklistSubentryMake(pluralise($item[pile of ashes]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Pile of ashes resource")); - } - if (to_item("7259").available_amount() > 0 && in_run) { //crate of firebombs - string description = "Open for elemental damage combat items."; - resource_entries.listAppend(ChecklistEntryMake("__item " + to_item("7259"), "inventory.php?ftext=" + to_item("7259").replace_string(" ", "+"), ChecklistSubentryMake(pluralise(to_item("7259")), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Crate of firebombs resource")); - } - - if ($item[gym membership card].available_amount() > 0 && in_run && __misc_state["need to level"]) { - int importance = importance_level_item; - string description = "Gives 30 muscle/mysticality/moxie stats.|Once per day."; - if (my_level() < 4) { - description += "|Not usable until level 4."; - importance = importance_level_unimportant_item; - } - resource_entries.listAppend(ChecklistEntryMake("__item gym membership card", "inventory.php?ftext=gym+membership+card", ChecklistSubentryMake(pluralise($item[gym membership card]), "", description), importance_level_item).ChecklistEntrySetIDTag("Gym membership card")); - } - - if (!get_property_boolean("_warbearGyrocopterUsed")) { - if ($item[warbear gyrocopter].available_amount() > 0) { - string [int] description; - description.listAppend("Usable once/day for a gyro. Only breaks a quarter of the time."); - if (!in_ronin()) - description.listAppend("Could always send it to yourself."); - resource_entries.listAppend(ChecklistEntryMake("__item warbear gyrocopter", "curse.php?whichitem=7038", ChecklistSubentryMake(pluralise($item[warbear gyrocopter]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Warbear gyrocopter resource")); - - } else if ($item[broken warbear gyrocopter].available_amount() > 0) { - resource_entries.listAppend(ChecklistEntryMake("__item broken warbear gyrocopter", "inventory.php?ftext=broken+warbear+gyrocopter", ChecklistSubentryMake(pluralise($item[broken warbear gyrocopter]), "", "Gyrocopters dream of the sky. Set one free!"), importance_level_unimportant_item).ChecklistEntrySetIDTag("Warbear gyrocopter broken")); - - } - } - if ($item[burned government manual fragment].available_amount() > 0) { - resource_entries.listAppend(ChecklistEntryMake("__item burned government manual fragment", "inventory.php?ftext=burned+government+manual+fragment", ChecklistSubentryMake(pluralise($item[burned government manual fragment]), "", "Foreign language study.|Will disappear on ascension."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Burned government manual fragment")); - } - - // Adding scorpion/glark resources; changed slghtly from TES tile by adding tavern unlock to display - if ($item[bowl of scorpions].available_amount() > 0 && get_property_int("_drunkPygmyBanishes") < 11 && my_path().id != PATH_G_LOVER && get_property_ascension("hiddenTavernUnlock")) - { - int uses_remaining = MIN($item[bowl of scorpions].available_amount(), clampi(11 - get_property_int("_drunkPygmyBanishes"), 0, 11)); - resource_entries.listAppend(ChecklistEntryMake("__item bowl of scorpions", "inventory.php?which=3&ftext=bowl+of+scorpions", ChecklistSubentryMake(pluralise(uses_remaining,$item[bowl of scorpions]), "", "Free fight when brought to Bowling Alley."), importance_level_unimportant_item).ChecklistEntrySetIDTag("daily free fight")); - } - - if ($item[glark cable].available_amount() > 0 && get_property_int("_glarkCableUses") < 5 && my_path().id != PATH_G_LOVER) - { - int uses_remaining = MIN($item[glark cable].available_amount(), clampi(5 - get_property_int("_glarkCableUses"), 0, 5)); - resource_entries.listAppend(ChecklistEntryMake("__item glark cable", "inventory.php?which=3&ftext=glark+cable", ChecklistSubentryMake(pluralise(uses_remaining,$item[glark cable]), "", "Free fight on the Red Zeppelin."), importance_level_unimportant_item).ChecklistEntrySetIDTag("daily free fight")); - } - if ($item[lynyrd snare].available_amount() > 0 && get_property_int("_lynyrdSnareUses") < 3 && $item[lynyrd snare].item_is_usable()) { // && in_run && __misc_state["need to level"]) - int uses_remaining = MIN($item[lynyrd snare].available_amount(), clampi(3 - get_property_int("_lynyrdSnareUses"), 0, 3)); - resource_entries.listAppend(ChecklistEntryMake("__item lynyrd snare", "inventory.php?ftext=lynyrd+snare", ChecklistSubentryMake(pluralise(uses_remaining,$item[lynyrd snare]), "", "Free fight when used."), importance_level_unimportant_item).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Lynyrd snare free fight")); - } - if (in_run && $item[red box].available_amount() > 0 && $item[red box].item_is_usable()) { - resource_entries.listAppend(ChecklistEntryMake("__item red box", "inventory.php?ftext=red+box", ChecklistSubentryMake(pluralise($item[red box]), "", "Open for stuff."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Red box resource")); - } - - if (in_run && $item[llama lama gong].available_amount() > 0) { - //fiddle fiddle fiddle - //I'm not sure anyone should actually do this, so fiddly! - boolean need_pickpocket = true; - if (my_primestat() == $stat[moxie]) - need_pickpocket = false; - - string [int] description; - string [int] birdform_description; - - //options: - - string [int] possible_pickpocket_locations; - - if (need_pickpocket) { - //bird form for pickpocket in crypt, filthworms, golems - - if (__quest_state["Level 7"].state_boolean["nook needs speed tricks"]) - possible_pickpocket_locations.listAppend("Cyrpt Nook"); - if (!__quest_state["Level 12"].state_boolean["Orchard Finished"]) - possible_pickpocket_locations.listAppend("filthworms"); - - if (possible_pickpocket_locations.count() == 0) - birdform_description.listAppend("Gives pickpocketing ability."); - else - birdform_description.listAppend("Gives pickpocketing ability for stealing from the " + possible_pickpocket_locations.listJoinComponents(", ", "and") + "."); - } - - string [element][int] element_options; - - foreach e in $elements[] - element_options[e] = listMakeBlankString(); - if (!__quest_state["Level 6"].finished) - element_options[$element[hot]].listAppend("friars quest"); - - if (__quest_state["Level 9"].state_float["oil peak pressure"] > 0.0) - element_options[$element[sleaze]].listAppend("oil peak"); - - if (!__quest_state["Level 12"].finished && __quest_state["Level 12"].state_string["Side seemingly fighting for"] == "hippy") - element_options[$element[sleaze]].listAppend("frat boys"); - - - if (!__quest_state["Level 7"].finished) - element_options[$element[spooky]].listAppend("cyrpt"); - - - if (!__quest_state["Level 12"].state_boolean["War started"]) - element_options[$element[stench]].listAppend("starting war against hippies"); - if (!__quest_state["Level 12"].state_boolean["Orchard Finished"]) - element_options[$element[stench]].listAppend("filthworms"); - - if (__quest_state["Level 11 Manor"].mafia_internal_step < 2) - element_options[$element[spooky]].listAppend("spookyraven ballroom"); - if (get_property("questM20Necklace") != "finished" && $item[Lady Spookyraven's powder puff].available_amount() == 0) - element_options[$element[spooky]].listAppend("spookyraven bathroom"); - - - - string [element] element_to_potion; - - if (__misc_state["need to level"]) - element_to_potion[$element[hot]] = "+6 stats/fight"; - element_to_potion[$element[sleaze]] = "+20 ML"; - element_to_potion[$element[spooky]] = "+60% item"; - - if (!__quest_state["Level 12"].state_boolean["Nuns Finished"] && $item[glimmering raven feather].available_amount() == 0 && $effect[Melancholy Burden].have_effect() == 0) - element_to_potion[$element[stench]] = "+60% meat"; - - - //string [int][int] monster_fight_table; - //monster_fight_table.listAppend(listMake(HTMLGenerateSpanOfClass("Monster element", "r_bold"), HTMLGenerateSpanOfClass("Areas", "r_bold"), HTMLGenerateSpanOfClass("Gives potion", "r_bold"))); - foreach e in element_options { - if (element_options[e].count() == 0) - continue; - if (!(element_to_potion contains e)) - continue; - - //monster_fight_table.listAppend(listMake(e.to_string(), element_options[e].listJoinComponents("
"), element_to_potion[e])); - birdform_description.listAppend("Fight " + e + " monsters (" + element_options[e].listJoinComponents(", ", "and") + ") for " + element_to_potion[e] + " spleen potion."); - } - - //if (monster_fight_table.count() > 1) - //birdform_description.listAppend(HTMLGenerateSimpleTableLines(monster_fight_table)); - - //√against hot (friars) for +6 stats/fight potion - //against sleaze (oil peak) for +ML potion - //against spooky (cyrpt, spookyraven ballroom/bathroom) for +60% items from monsters potion - //against stench (filthworms, starting war against hippy) for +60% meat potion - - //cast boner battalion to handle birdform? - //can only cast vicious talon slash/All-You-Can-Beat Wing Buffet 14 times, 15 leads to the feather you don't want (property birdformRoc maybe?) - - //FIXME implement birdform reminders? (like AVOID CASTING X) - - if (my_maxmp() >= 200 && $skill[Summon "Boner Battalion"].skill_is_usable() && !get_property_boolean("_bonersSummoned")) - description.listAppend("Possibly cast the battalion to handle birdform."); //yojimbos_law wants this here, so.. - - if (birdform_description.count() > 0) - description.listAppend(HTMLGenerateSpanOfClass("Birdform", "r_bold") + "|*" + birdform_description.listJoinComponents("|*
")); - - resource_entries.listAppend(ChecklistEntryMake("__item llama lama gong", "inventory.php?ftext=llama+lama+gong", ChecklistSubentryMake(pluralise($item[llama lama gong]), "", description), importance_level_item).ChecklistEntrySetIDTag("Llama lama gong resource")); - - } - - if (!in_run && get_property("_bittycar").length() == 0 && $items[BittyCar HotCar, BittyCar MeatCar,BittyCar SoulCar].available_amount() > 0) { - string [int] available_items; - string [int] available_descriptions; - string [item] item_descriptions; - item_descriptions[$item[BittyCar HotCar]] = "hot damage"; - item_descriptions[$item[BittyCar MeatCar]] = "extra meat"; - item_descriptions[$item[BittyCar SoulCar]] = "HP/MP"; - - - foreach it in $items[BittyCar MeatCar,BittyCar SoulCar,BittyCar HotCar] { - if (it.available_amount() > 0) { - available_items.listAppend(it.to_string().replace_string("BittyCar ", "")); - available_descriptions.listAppend(item_descriptions[it]); - } - } - string description = "Reusable once/day for occasional " + available_descriptions.listJoinComponents(", ", "or") + " in combat."; - resource_entries.listAppend(ChecklistEntryMake("__item BittyCar MeatCar", "inventory.php?ftext=bittycar", ChecklistSubentryMake("BittyCar " + available_items.listJoinComponents(", ", "or") + " usable", "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Bittycars resource")); - } - - if (in_run && !__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "mysticality" && !get_property_ascension("lastGoofballBuy") && __quest_state["Level 3"].started && my_path().id != PATH_ZOMBIE_SLAYER && my_path().id != PATH_COMMUNITY_SERVICE) { - resource_entries.listAppend(ChecklistEntryMake("__item bottle of goofballs", "tavern.php?place=susguy", ChecklistSubentryMake("Bottle of goofballs obtainable", "", "For the lair stat test.|Costs nothing, but be careful..."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Goofballs resource")); - } - - if ($item[tonic djinn].available_amount() > 0 && in_ronin() && in_run && !get_property_boolean("_tonicDjinn") && my_path().id != PATH_G_LOVER) { - string [int] possibilities; - possibilities.listAppend("~450 meat (Wealth!)"); - if (__misc_state["need to level"]) { - string mainstat_choice; - if (my_primestat() == $stat[muscle]) - mainstat_choice = "Strength!"; - else if (my_primestat() == $stat[mysticality]) - mainstat_choice = "Wisdom!"; - else if (my_primestat() == $stat[moxie]) - mainstat_choice = "Panache!"; - - if (mainstat_choice.length() != 0) - possibilities.listAppend("~60 mainstats (" + mainstat_choice + ")"); - } - - string [int] description; - description.listAppend("Use for " + possibilities.listJoinComponents(", ", "or")); - - resource_entries.listAppend(ChecklistEntryMake("__item tonic djinn", "inventory.php?ftext=tonic+djinn", ChecklistSubentryMake("Tonic djinn", "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Tonic djinn resource")); - } - - // Removed an is_unrestricted check; I think this actually is fine, since this checks ownership, and - // you can't own it unless you are in a path where you can use it or the replica. - - if (__iotms_usable[lookupItem("V for Vivala mask")]) { - if (!get_property_boolean("_vmaskBanisherUsed")) { - string url; - string [int] description; - if (__misc_state["free runs usable"]) - description.listAppend("Once/day free run/banisher. (combat skill)"); - else - description.listAppend("Once/day banisher. (combat skill)"); - - if ($item[V for Vivala mask].equipped_amount() == 0) { - if ($item[replica V for Vivala mask].equipped_amount() == 0) { - description.listAppend("Equip V for Vivala mask first."); - url = "inventory.php?ftext=v+for+vivala"; - } - } - string line = "Costs "; - if (my_mp() < 30) - line += HTMLGenerateSpanFont("30 MP", "red"); - else - line += "30 MP"; - description.listAppend(line + "."); - resource_entries.listAppend(ChecklistEntryMake("__item V for Vivala mask", url, ChecklistSubentryMake("Creepy Grin usable", "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Vivala mask banish")); - } - if (get_property_int("_vmaskAdv") < 10) { - string url; - string [int] description; - int critAdvs_remaining = 10 - get_property_int("_vmaskAdv"); - - if ($item[V for Vivala mask].equipped_amount() == 0) { - if ($item[replica V for Vivala mask].equipped_amount() == 0) { - description.listAppend("Equip V for Vivala mask first."); - url = "inventory.php?ftext=v+for+vivala"; - } - } - description.listAppend("Land critical hits for chance of getting adventures."); - description.listAppend("Also a pseudopickpocket."); - resource_entries.listAppend(ChecklistEntryMake("__item V for Vivala mask", url, ChecklistSubentryMake(pluralise(critAdvs_remaining, "V for Vivala mask adventure available", "V for Vivala mask adventures available"), "+critical%", description), importance_level_item).ChecklistEntrySetIDTag("Vivala mask resource")); - } - } - - if ($item[moveable feast].available_amount() > 0 && $item[moveable feast].is_unrestricted() && get_property_int("_feastUsed") < 5) { - string [int] description; - string url = "inventory.php?ftext=moveable+feast"; - int feastings_left = clampi(5 - get_property_int("_feastUsed"), 0, 5); - - description.listAppend("Gives +10 familiar weight for twenty turns to a specific familiar."); - string [int] familiars_used_on = get_property("_feastedFamiliars").split_string_alternate(";"); //separator: ";" - if (in_run && __misc_state["free runs usable"]) { - string [int] familiars_could_imbue_for_del_shannon; - boolean [familiar] familiars_used_on_inverse; - foreach key, f_name in familiars_used_on { - familiar f = f_name.to_familiar(); - if (f != $familiar[none]) - familiars_used_on_inverse[f] = true; - } - foreach f in $familiars[pair of stomping boots,Frumious Bandersnatch] { - if (f.familiar_is_usable() && !(familiars_used_on_inverse contains f)) { - familiars_could_imbue_for_del_shannon.listAppend(f); - } - } - if (familiars_could_imbue_for_del_shannon.count() > 0) { - description.listAppend("Could feed " + familiars_could_imbue_for_del_shannon.listJoinComponents(", ", "or") + " for +2 free runs."); - } - } - - if (familiars_used_on.count() > 0) - description.listAppend("Already used on " + familiars_used_on.listJoinComponents(", ", "and") + "."); - resource_entries.listAppend(ChecklistEntryMake("__item moveable feast", url, ChecklistSubentryMake(pluralise(feastings_left, "moveable feasting", "moveable feastings"), "", description), importance_level_item).ChecklistEntrySetIDTag("Moveable feast resource")); - //_feastedFamiliars - } - - if ($item[cosmic calorie].available_amount() > 0 && in_run) { - string [int][int] table; - table.listAppend(listMake("Cost", "Item", "Effect")); - - string [item] celestial_descriptions; - celestial_descriptions[$item[celestial olive oil]] = "+1 all res"; - celestial_descriptions[$item[celestial carrot juice]] = "+30% item"; - celestial_descriptions[$item[celestial au jus]] = "+5% combat"; - celestial_descriptions[$item[celestial squid ink]] = "-5% combat"; - int [item] calories_required; - calories_required[$item[celestial olive oil]] = 20; - calories_required[$item[celestial carrot juice]] = 30; - calories_required[$item[celestial au jus]] = 50; - calories_required[$item[celestial squid ink]] = 60; - foreach it in $items[celestial olive oil,celestial carrot juice,celestial au jus,celestial squid ink] { - int amount = it.creatable_amount() + it.available_amount(); - - string [int] line; - line = listMake(calories_required[it], it, celestial_descriptions[it]); - if (amount == 0) { - foreach key, s in line { - line[key] = HTMLGenerateSpanFont(s, "grey"); - } - } - table.listAppend(line); - } - string [int] description; - description.listAppend(HTMLGenerateSimpleTableLines(table)); - resource_entries.listAppend(ChecklistEntryMake("__item cosmic calorie", "inventory.php?ftext=cosmic+calorie", ChecklistSubentryMake(pluralise($item[cosmic calorie]), "", description), importance_level_item).ChecklistEntrySetIDTag("Cosmic calorie resource")); - - } - - if ($item[portable cassette player].available_amount() > 0 && (__misc_state["in run"] || $item[portable cassette player].equipped_amount() > 0) && $item[portable cassette player].is_unrestricted()) { - string [int] description; - string url = ""; - int modulus = total_turns_played() % 40; - - string [effect] buff_descriptions; - buff_descriptions[$effect[Dark Orchestral Song]] = "+5 moxie"; - buff_descriptions[$effect[Pet Shop Song]] = "+10% init"; - buff_descriptions[$effect[Dangerous Zone Song]] = "+25% meat"; - buff_descriptions[$effect[Flashy Dance Song]] = "+10% item"; - - effect [int] buffs_activate_at; //NOT a linear list - buffs_activate_at[0] = $effect[Dark Orchestral Song]; - buffs_activate_at[10] = $effect[Pet Shop Song]; - buffs_activate_at[20] = $effect[Dangerous Zone Song]; - buffs_activate_at[30] = $effect[Flashy Dance Song]; - - boolean [effect] buffs_to_display_for_future = $effects[Dangerous Zone Song,Flashy Dance Song]; - - boolean [effect] buffs_to_not_bother_display_current_for = $effects[Dark Orchestral Song,Pet Shop Song]; //+10% init is like +1% chance of extra modern zmobies, which saves an extremely small fraction of a turn. ignore, because cognitive load + you might run better accessories instead, like +ML. plus, you have to use that weird fiddly technique because of +combat - string [int] future_buffs; - foreach mod_value, buff in buffs_activate_at { - string buff_description = buff_descriptions[buff]; - if (modulus >= mod_value && modulus < mod_value + 10) { - if (buffs_to_not_bother_display_current_for contains buff) { - continue; - } - int turns_remaining = 10 - modulus % 10; - string line = buff_description; - if (buff.have_effect() == 0) - line += " obtainable"; - else { - if (turns_remaining < buff.have_effect()) { - turns_remaining = buff.have_effect(); - line += " active"; - } - } - line += " for " + pluralise(turns_remaining, " more turn", " more turns"); - boolean have_other_song_active = false; - effect other_song = $effect[none]; - foreach e in $effects[Dark Orchestral Song,Pet Shop Song,Dangerous Zone Song,Flashy Dance Song] { - if (e != buff && e.have_effect() > 0) { - other_song = e; - have_other_song_active = true; - } - } - if (have_other_song_active) { - line += " after losing current"; - if (!(buffs_to_not_bother_display_current_for contains other_song)) - line += " " + buff_descriptions[other_song]; - line += " song. (unequip cassette for a turn)"; - } else - line += "."; - if (buff.have_effect() == 0 && !have_other_song_active && $item[portable cassette player].equipped_amount() == 0) - line += " (equip player)"; - description.listAppend(line); - continue; - } - if (buffs_to_display_for_future contains buff) { - int turns_until = mod_value - modulus; - if (turns_until < 0) - turns_until += 40; - future_buffs.listAppend(pluralise(turns_until, "more turn", "more turns") + " until " + buff_description); - } - } - if (future_buffs.count() > 0) - description.listAppend(future_buffs.listJoinComponents(", ").capitaliseFirstLetter() + "."); - - //description.listAppend("Modulus " + modulus + "."); - resource_entries.listAppend(ChecklistEntryMake("__item portable cassette player", url, ChecklistSubentryMake("Portable cassette player buffs", "", description), 10).ChecklistEntrySetIDTag("Portable cassette player")); - } - if (can_equip_outfit("Hodgman's Regal Frippery")) { - int underling_summons_remaining = clampi(5 - get_property_int("_hoboUnderlingSummons"), 0, 5); - if (underling_summons_remaining > 0) { - string url; - string [int] description; - description.listAppend("Combat skill while wearing the frippery. For a single fight, adds +100% meat (joke) or +100% item (dance)."); - if (!is_wearing_outfit("Hodgman's Regal Frippery")) { - url = invSearch("hodgman"); - description.listAppend("Equip frippery first."); - } - resource_entries.listAppend(ChecklistEntryMake("__skill Summon hobo underling", url, ChecklistSubentryMake(pluralise(underling_summons_remaining, "hobo underling summon", "hobo underling summons"), "", description), -1).ChecklistEntrySetIDTag("Hodgman regal frippery resource")); - } - } - if (lookupItem("license to chill").available_amount() > 0 && !get_property_boolean("_licenseToChillUsed") && mafiaIsPastRevision(18122)) { - resource_entries.listAppend(ChecklistEntryMake("__item License to Chill", "inventory.php?ftext=license+to+chill", ChecklistSubentryMake("License to Chill", "", "+5 adventures, extend effects by one turn, HP/MP restore, statgain."), 10).ChecklistEntrySetIDTag("License to chill")); - - } - if (lookupItem("etched hourglass").available_amount() > 0 && !get_property_boolean("_etchedHourglassUsed")) { - resource_entries.listAppend(ChecklistEntryMake("__item etched hourglass", "inventory.php?ftext=etched+hourglass", ChecklistSubentryMake("Etched Hourglass", "", "+5 adventures."), 10).ChecklistEntrySetIDTag("Etched hourglass resource")); - - } - if ($item[mafia middle finger ring].available_amount() > 0 && !get_property_boolean("_mafiaMiddleFingerRingUsed")) { - resource_entries.listAppend(ChecklistEntryMake("__item mafia middle finger ring", ($item[mafia middle finger ring].equipped_amount() == 0 ? $item[mafia middle finger ring].invSearch() : ""), ChecklistSubentryMake("Mafia middle finger ring banish/free run", "", "Once/day, 60 turn duration." + ($item[mafia middle finger ring].equipped_amount() == 0 ? " Equip first." : "")), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Mafia middle finger ring banish")); - - } - - if (get_property_int("_glitchMonsterFights") == 0 && lookupItem("[glitch season reward name]").item_amount() > 0) { - string [int] description; - int glitch_amount = lookupItem("[glitch season reward name]").item_amount(); - int glitch_monster_powah = 5 * glitch_amount * get_property_int("glitchItemImplementationCount"); - - description.listAppend("Has " + (glitch_monster_powah > 0 ? glitch_monster_powah : 1) + " HP/ATK/DEF. Gives " + (glitch_monster_powah > 0 ? glitch_monster_powah.to_string() : "no") + " HP/MP/meat."); //Has 0 defense if at 1 HP/ATK, but who cares... - - description.listAppend("Try to eat one (with chat macro) to fight it (not consumed)."); - - if (glitch_amount >= 2) - description.listAppend("Closet " + (glitch_amount > 2 ? "some" : "one") + " of them to decrease its power (...and reward)."); - - int glitch_in_closet = (get_property_boolean("autoSatisfyWithCloset") ? lookupItem("[glitch season reward name]").closet_amount() : 0); - if (glitch_in_closet >= 1) - description.listAppend("Uncloset " + (glitch_in_closet > 1 ? "some" : "one") + " to " + (glitch_amount > 1 ? "increase" : "multiply") + " its power and reward."); - - resource_entries.listAppend(ChecklistEntryMake("__item [glitch season reward name]", "inventory.php?ftext=%5Bglitch+season+reward+name%5D", ChecklistSubentryMake("[glitch season reward name] free fight", "", description), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Glitch reward free fight")); - } -} diff --git a/Source/relay/TourGuide/Sets/Misc Tasks.ash b/Source/relay/TourGuide/Sets/Misc Tasks.ash deleted file mode 100644 index ed191763..00000000 --- a/Source/relay/TourGuide/Sets/Misc Tasks.ash +++ /dev/null @@ -1,267 +0,0 @@ -import "relay/TourGuide/Support/Campground.ash" - -RegisterTaskGenerationFunction("SMiscTasksGenerateTasks"); -void SMiscTasksGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - //From tasks.ash. May be able to split off some of these into their own files: - if (__misc_state["yellow ray available"] && __misc_state["in run"]) //not-in-run version in Familiars.ash (???) - { - string [int] potential_targets; - - if (!have_outfit_components("Filthy Hippy Disguise") && !(get_property("sidequestOrchardCompleted") == "hippy" || get_property("sidequestOrchardCompleted") == "fratboy")) - potential_targets.listAppend("Mysterious Island Hippy for outfit. (allows hippy store access; free redorant for +combat)"); - if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues")) - potential_targets.listAppend("Hippy/frat war outfit?"); - //fax targets? - if (__misc_state["fax available"] || $skill[Rain Man].skill_is_usable()) - { - potential_targets.listAppend("Anything on the fax list."); - } - - if (!__quest_state["Level 10"].finished && $item[mohawk wig].available_amount() == 0 && (!lookupSkill("Comprehensive Cartography").skill_is_usable() || $item[model airship].available_amount() == 0) ) - potential_targets.listAppend("Burly Sidekick (Mohawk wig) - speed up top floor of castle."); - if (!__quest_state["Level 12"].state_boolean["Orchard Finished"]) - potential_targets.listAppend("Filthworms."); - - if (__quest_state["Boss Bat"].state_int["areas unlocked"] + $item[sonar-in-a-biscuit].available_amount() <3) - { - if ($item[enchanted bean].available_amount() == 0 && !__misc_state["beanstalk grown"]) - potential_targets.listAppend("Beanbat. (enchanted bean, sonar-in-a-biscuit)"); - else - potential_targets.listAppend("A bat. (sonar-in-a-biscuit)"); - } - - if (__misc_state["stench airport available"] && $item[filthy child leash].available_amount() == 0 && !__misc_state["familiars temporarily blocked"] && $items[ittah bittah hookah,astral pet sweater,snow suit,lead necklace].available_amount() == 0 && in_ronin() && my_path().id != PATH_HEAVY_RAINS && my_path().id != PATH_GELATINOUS_NOOB && my_path().id != PATH_G_LOVER) - { - potential_targets.listAppend("Horrible tourist family (barf mountain) - +5 familiar weight leash."); - } - - - if (item_drop_modifier_ignoring_plants() < 234.0 && !__misc_state["in aftercore"]) - potential_targets.listAppend("Anything with 30% drop if you can't 234%. (dwarf foreman, bob racecar, drum machines, etc)"); - - - if (__misc_state_string["yellow ray source"] == "Unleash Cowrruption" && $effect[Cowrruption].have_effect() == 0) - { - potential_targets.listAppend(HTMLGenerateSpanFont("Acquire cowrruption first.", "red")); - } - - optional_task_entries.listAppend(ChecklistEntryMake(__misc_state_string["yellow ray image name"], "", ChecklistSubentryMake("Fire yellow ray", "", potential_targets), 5).ChecklistEntrySetIDTag("Yellow ray suggestions")); - } - - if (__misc_state["in run"] && !have_mushroom_plot() && knoll_available() && __misc_state["can eat just about anything"] && fullness_limit() >= 4 && $item[spooky mushroom].available_amount() == 0 && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST && my_meat() >= 5000 && my_path().id != PATH_SLOW_AND_STEADY && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) - { - string [int] description; - description.listAppend("For spooky mushrooms, to cook a grue egg omelette. (epic food)|Will " + ((my_meat() < 5000) ? "need" : "cost") + " 5k meat. Plant a spooky spore."); - optional_task_entries.listAppend(ChecklistEntryMake("__item spooky mushroom", "knoll_mushrooms.php", ChecklistSubentryMake("Possibly plant a mushroom plot", "", description), 5).ChecklistEntrySetIDTag("Mushroom plot plant")); - - } - - if (!have_outfit_components("Filthy Hippy Disguise") && __misc_state["mysterious island available"] && __misc_state["in run"] && !__quest_state["Level 12"].finished && !__quest_state["Level 12"].state_boolean["War started"] && !have_outfit_components("Frat Warrior Fatigues") && my_path().id != PATH_EXPLOSION) - { - item [int] missing_pieces = missing_outfit_components("Filthy Hippy Disguise"); - - string [int] description; - string [int] modifiers; - boolean should_be_future_task = false; - - description.listAppend("Missing " + missing_pieces.listJoinComponents(", ", "and") + "."); - string next_line_intro = ""; - if (!__misc_state["yellow ray almost certainly impossible"]) - { - description.listAppend("Yellow-ray a hippy in the hippy camp if you can."); - next_line_intro = "Otherwise, "; - } - else if (my_level() < 9) - should_be_future_task = true; - - if (my_level() >= 9) - { - description.listAppend((next_line_intro + "run -combat " + (next_line_intro == "" ? " in the hippy camp" : "there") + ".").capitaliseFirstLetter()); - modifiers.listAppend("-combat"); - } - else - { - description.listAppend((next_line_intro + "wait for level 9 for the non-combats.").capitaliseFirstLetter()); - } - if ($familiar[slimeling].familiar_is_usable()) - modifiers.listAppend("slimeling?"); - - ChecklistEntry entry = ChecklistEntryMake("__item filthy knitted dread sack", "island.php", ChecklistSubentryMake("Acquire a filthy hippy disguise", modifiers, description), $locations[The Hippy Camp]); - entry.tags.id = "Filthy hippy disguise acquire"; - if (should_be_future_task) - future_task_entries.listAppend(entry); - else - optional_task_entries.listAppend(entry); - } - - if (__misc_state["in run"] && (inebriety_limit() == 0 || my_path().id == PATH_SLOW_AND_STEADY) && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) - { - string url = ""; - string [int] modifiers; - if (__misc_state["have hipster"] && get_property_int("_hipsterAdv") < 7) - { - modifiers.listAppend(__misc_state_string["hipster name"]); - } - string [int] description = listMake("At the end of the day, enter a combat, but don't finish it. Rollover will end it for you.", "This gives an extra chance to look for a non-combat."); - if (__quest_state["Level 3"].in_progress) - { - description.listAppend("Try using it to explore the typical tavern."); - url = "cellar.php"; - } - optional_task_entries.listAppend(ChecklistEntryMake("__item dead guy's watch", url, ChecklistSubentryMake("Use rollover runaway", modifiers, description), 8).ChecklistEntrySetIDTag("Rollover runaway suggestions")); - } - - //I'm not sure if you ever need a frat boy ensemble in-run, even if you're doing the hippy side on the war? If you need war hippy fatigues, the faster (?) way is acquire hippy outfit -> frat warrior fatigues -> start the war / use desert adventure for hippy fatigues. But if they're sure... - if (!have_outfit_components("Frat boy ensemble") && __misc_state["mysterious island available"] && __misc_state["in run"] && !__quest_state["Level 12"].finished && !__quest_state["Level 12"].started && $location[The Orcish Frat House].turnsAttemptedInLocation() >= 3 && ($location[The Orcish Frat House].combatTurnsAttemptedInLocation() > 0 || $location[The Orcish Frat House].noncombat_queue.contains_text("Sing This Explosion to Me") || $location[The Orcish Frat House].noncombat_queue.contains_text("Sing This Explosion to Me") || $location[The Orcish Frat House].noncombat_queue.contains_text("Murder by Death") || $location[The Orcish Frat House].noncombat_queue.contains_text("I Just Wanna Fly") || $location[The Orcish Frat House].noncombat_queue.contains_text("From Stoked to Smoked") || $location[The Orcish Frat House].noncombat_queue.contains_text("Purple Hazers"))) - { - //they don't have a frat boy ensemble, but they adventured in the pre-war frat house - //I'm assuming this means they want the outfit, for whatever reason. So, suggest it, until the level 12 starts: - item [int] missing_pieces = missing_outfit_components("Frat boy ensemble"); - - string [int] description; - string [int] modifiers; - description.listAppend("Missing " + missing_pieces.listJoinComponents(", ", "and") + "."); - if (my_level() >= 9) - { - modifiers.listAppend("-combat"); - description.listAppend("Run -combat."); - } - else - description.listAppend("Possibly wait until level 9, to unlock NCs in the area."); - optional_task_entries.listAppend(ChecklistEntryMake("__item orcish frat-paddle", "island.php", ChecklistSubentryMake("Acquire a frat boy ensemble?", modifiers, description), $locations[The Orcish Frat House]).ChecklistEntrySetIDTag("Frat boy ensemble acquire")); - } - - if ($item[strange leaflet].available_amount() > 0 && __misc_state["in run"] && !get_property_boolean("leafletCompleted")) - { - boolean leaflet_quest_probably_finished = false; - - if ($item[giant pinky ring].available_amount() > 0) //invalid in casual, but eh - leaflet_quest_probably_finished = true; - if ($item[Frobozz Real-Estate Company Instant House (TM)].available_amount() > 0 || __campground[$item[Frobozz Real-Estate Company Instant House (TM)]] > 0) - leaflet_quest_probably_finished = true; - - if (!leaflet_quest_probably_finished) - { - string [int] description; - boolean future_task = false; - description.listAppend("Quests Menu" + __html_right_arrow_character + "Leaflet (With Stats)"); - - if (__misc_state["need to level"]) - { - item relevant_lamp; - effect relevant_lamp_effect; - if (my_primestat() == $stat[muscle]) - { - relevant_lamp = $item[red LavaCo Lamp™]; - relevant_lamp_effect = $effect[Red Menace]; - } - else if (my_primestat() == $stat[mysticality]) - { - relevant_lamp = $item[blue LavaCo Lamp™]; - relevant_lamp_effect = $effect[Blue Eyed Devil]; - } - else if (my_primestat() == $stat[moxie]) - { - relevant_lamp = $item[green LavaCo Lamp™]; - relevant_lamp_effect = $effect[Green Peace]; - } - if (relevant_lamp != $item[none] && relevant_lamp_effect != $effect[none] && relevant_lamp.available_amount() > 0 && relevant_lamp_effect.have_effect() == 0) - { - future_task = true; - description.listAppend("Possibly wait until tomorrow. The " + relevant_lamp + " bonus will give extra stats."); - } - else if (relevant_lamp_effect.have_effect() > 0) - description.listAppend("Soon, before the lava lamp effect runs out."); - - item [int] items_equipping = generateEquipmentToEquipForExtraExperienceOnStat(my_primestat()); - if (items_equipping.count() > 0) - description.listAppend("Could equip " + items_equipping.listJoinComponents(", ", "or") + " for more stats."); - } - - ChecklistEntry entry = ChecklistEntryMake("__item strange leaflet", "", ChecklistSubentryMake("Strange leaflet quest", "", description)); - entry.tags.id = "Strange leaflet"; - if (future_task) - future_task_entries.listAppend(entry); - else - optional_task_entries.listAppend(entry); - } - } - - - - - - boolean have_spaghetti_breakfast = (($skill[spaghetti breakfast].skill_is_usable() && !get_property_boolean("_spaghettiBreakfast")) || $item[spaghetti breakfast].available_amount() > 0); - if (__misc_state["in run"] && __misc_state["can eat just about anything"] && !get_property_boolean("_spaghettiBreakfastEaten") && my_fullness() == 0 && have_spaghetti_breakfast && my_path().id != PATH_SLOW_AND_STEADY) - { - - string [int] adventure_gain; - adventure_gain[1] = "1"; - adventure_gain[2] = "1-2"; - adventure_gain[3] = "2"; - adventure_gain[4] = "2-3"; - adventure_gain[5] = "3"; - adventure_gain[6] = "3-4"; - adventure_gain[7] = "4"; - adventure_gain[8] = "4-5"; - adventure_gain[9] = "5"; - adventure_gain[10] = "5-6"; - adventure_gain[11] = "6"; - - string adventures_gained = adventure_gain[MAX(1, MIN(11, my_level()))]; - - string level_string = ""; - if (my_level() < 11) - level_string = " Gain levels for more."; - string url = "inventory.php?which=1"; - string [int] description; - description.listAppend("Inedible if you eat anything else.|" + adventures_gained + " adventures/fullness." + level_string); - if ($item[spaghetti breakfast].available_amount() == 0) - { - description.listAppend("Obtained by casting spaghetti breakfast."); - url = "skills.php"; - } - optional_task_entries.listAppend(ChecklistEntryMake("__item spaghetti breakfast", url, ChecklistSubentryMake("Eat " + $item[spaghetti breakfast] + " first", "", description), 8).ChecklistEntrySetIDTag("Spaghetti breakfast resource")); - } - - if (my_path().id != PATH_ACTUALLY_ED_THE_UNDYING && my_path().id != PATH_NUCLEAR_AUTUMN) - { - item upgraded_dwelling = $item[none]; - if ($item[Frobozz Real-Estate Company Instant House (TM)].available_amount() > 0 && (__campground[$item[big rock]] > 0 || __campground[$item[Newbiesport™ tent]] > 0 || __campground[$item[cottage]] > 0) && my_path().id != PATH_G_LOVER && my_path().id != PATH_BEES_HATE_YOU) - { - upgraded_dwelling = $item[Frobozz Real-Estate Company Instant House (TM)]; - } - else if ($item[Newbiesport™ tent].available_amount() > 0 && __campground[$item[big rock]] > 0 && my_path().id != PATH_G_LOVER) - { - upgraded_dwelling = $item[Newbiesport™ tent]; - } - if (upgraded_dwelling != $item[none]) - { - string [int] reasons; - reasons.listAppend("rollover"); - - if (__misc_state_int["total free rests possible"] > 0) - reasons.listAppend("free rests"); - - string description = "Better HP/MP restoration via " + reasons.listJoinComponents(", ", "and") + "."; - optional_task_entries.listAppend(ChecklistEntryMake("__item " + upgraded_dwelling, upgraded_dwelling.invSearch(), ChecklistSubentryMake("Use " + upgraded_dwelling, "", description), 8).ChecklistEntrySetIDTag("Campground dwelling uprgade")); - - } - } - - if (__misc_state["in run"] && $item[dry cleaning receipt].available_amount() > 0) - { - item receipt_item = $item[none]; - if (my_primestat() == $stat[muscle]) - receipt_item = $item[power sock]; - else if (my_primestat() == $stat[mysticality]) - receipt_item = $item[wool sock]; - else if (my_primestat() == $stat[moxie]) - receipt_item = $item[moustache sock]; - if (receipt_item != $item[none] && receipt_item.available_amount() == 0) - { - optional_task_entries.listAppend(ChecklistEntryMake("__item " + $item[dry cleaning receipt], "inventory.php?ftext=dry+cleaning+receipt", ChecklistSubentryMake("Use " + $item[dry cleaning receipt], "", "For " + receipt_item + " accessory."), 8).ChecklistEntrySetIDTag("Dry cleaning receipt resource")); - } - } -} diff --git a/Source/relay/TourGuide/Sets/Monorail.ash b/Source/relay/TourGuide/Sets/Monorail.ash deleted file mode 100644 index cc544be5..00000000 --- a/Source/relay/TourGuide/Sets/Monorail.ash +++ /dev/null @@ -1,19 +0,0 @@ -RegisterTaskGenerationFunction("SMonorailStationGenerateTasks"); -void SMonorailStationGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (in_bad_moon()) return; // No Breakfast Counter in Bad Moon - - if (__misc_state["can eat just about anything"] && get_property("muffinOnOrder") == "earthenware muffin tin") - task_entries.listAppend(ChecklistEntryMake("__item earthenware muffin tin", "place.php?whichplace=monorail&action=monorail_downtown", ChecklistSubentryMake("Get your muffin tin back", "", "Vist the monorail's breakfast counter"), -11).ChecklistEntrySetIDTag("Monorail get muffin tin")); - - if (get_property_boolean("_muffinOrderedToday") || get_property("muffinOnOrder") == "earthenware muffin tin") - return; - - item order = get_property("muffinOnOrder").lookupItem(); - if (order != $item[none]) { - task_entries.listAppend(ChecklistEntryMake("__item " + order.to_string(), "place.php?whichplace=monorail&action=monorail_downtown", ChecklistSubentryMake("Go grab your " + order.to_string()), -11).ChecklistEntrySetIDTag("Monorail muffin resource")); - } - else if (lookupItem("earthenware muffin tin").available_amount() > 0 && __misc_state["in run"]) { - optional_task_entries.listAppend(ChecklistEntryMake("__item earthenware muffin tin", "place.php?whichplace=monorail", ChecklistSubentryMake("Order a new muffin"), 5).ChecklistEntrySetIDTag("Monorail muffin resource")); - } -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets/Old Level 9 quest.ash b/Source/relay/TourGuide/Sets/Old Level 9 quest.ash deleted file mode 100644 index 3015cefc..00000000 --- a/Source/relay/TourGuide/Sets/Old Level 9 quest.ash +++ /dev/null @@ -1,61 +0,0 @@ - -void SOldLevel9GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if ($location[The Valley of Rof L'm Fao].turnsAttemptedInLocation() == 0) - return; - //if (__misc_state["in run"]) - //return; - QuestState state; - QuestStateParseMafiaQuestProperty(state, "questM15Lol", false); //don't issue a quest log load for this, no information gained - if (!state.in_progress) - return; - - string url = "place.php?whichplace=mountains"; - - string [int] description; - - if ($item[64735 scroll].item_amount() > 0) - { - description.listAppend("Use the 64735 scroll."); - url = "inventory.php?ftext=64735+scroll"; - } - else - { - description.listAppend("Make the 64735 scroll using the rampaging adding machine."); - - item [int] components_testing; - if ($item[64067 scroll].item_amount() == 0) - { - components_testing.listAppend($item[30669 scroll]); - components_testing.listAppend($item[33398 scroll]); - } - if ($item[668 scroll].item_amount() == 0) - { - components_testing.listAppend($item[334 scroll]); - components_testing.listAppend($item[334 scroll]); - } - string [int] components_needed; - int [item] amount_used; - foreach key in components_testing - { - item it = components_testing[key]; - if (it.item_amount() - amount_used[it] <= 0) - { - components_needed.listAppend(it.to_string()); - } - else - amount_used[it] += 1; - } - if (components_needed.count() > 0) - description.listAppend("Need " + components_needed.listJoinComponents(", ", "and") + "."); - - //suggest faxing? - if (__misc_state["fax equivalent accessible"]) - description.listAppend("Possibly fax the rampaging adding machine (with all scroll components) for one-turn quest."); - description.listAppend("Find rampaging adding machine, feed it 334 + 334, 30669 + 33398, 64067 + 668."); - description.listAppend("31337 scroll is 30669 + 668. (334 + 334)"); - } - ChecklistSubentry [int] subentries; - subentries.listAppend(ChecklistSubentryMake("A Quest, LOL", "", description)); - optional_task_entries.listAppend(ChecklistEntryMake("__item 64735 scroll", url, subentries, 10, $locations[the valley of rof l'm fao]).ChecklistEntrySetIDTag("Valley rof l'm fao quest")); -} diff --git a/Source/relay/TourGuide/Sets/Olfaction.ash b/Source/relay/TourGuide/Sets/Olfaction.ash deleted file mode 100644 index 96295d7d..00000000 --- a/Source/relay/TourGuide/Sets/Olfaction.ash +++ /dev/null @@ -1,120 +0,0 @@ -void SOlfactionGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - // I am keeping the recommender logic here because I like (most) of these suggestions. However, - // taking out the actual creating-the-tile shit until we refactor to the new olfaction limit - // and turn this into a resource thing rather than a highlighted task. - - if (!$skill[Transcendent Olfaction].skill_is_usable()) - return; - - //Add in some basic reminders to remove olfaction if adventuring in certain areas. - monster olfacted_monster = get_property_monster("olfactedMonster"); - if (olfacted_monster == $monster[none] || __last_adventure_location == $location[none]) - return; - - monster [location] location_wanted_monster; - - if (__misc_state["in run"]) - { - if ($item[talisman o' namsilat].available_amount() == 0 && !__quest_state["Level 11 Palindome"].finished) - location_wanted_monster[$location[belowdecks]] = $monster[gaudy pirate]; - if (!__quest_state["Level 8"].state_boolean["Past mine"]) - location_wanted_monster[$location[the goatlet]] = $monster[dairy goat]; - if (!__quest_state["Level 7"].state_boolean["niche finished"]) - location_wanted_monster[$location[the defiled niche]] = $monster[dirty old lihc]; - - if (!__quest_state["Azazel"].finished) - { - location_wanted_monster[$location[infernal rackets backstage]] = $monster[serialbus]; - location_wanted_monster[$location[the laugh floor]] = $monster[CH Imp]; - } - //Deliberately ignored - the quiet healer. (she's used to it) It's possible they may want to olfact the burly sidekick instead, and there's plenty of time in that area. - - if (!__quest_state["Level 11 Hidden City"].finished) - { - if (!__quest_state["Level 11 Hidden City"].state_boolean["Apartment finished"] && $effect[thrice-cursed].have_effect() == 0) - location_wanted_monster[$location[the hidden apartment building]] = $monster[pygmy shaman]; - - if (!__quest_state["Level 11 Hidden City"].state_boolean["Hospital finished"] && $items[surgical apron,bloodied surgical dungarees,surgical mask,head mirror,half-size scalpel].items_missing().count() > 0) - location_wanted_monster[$location[the hidden hospital]] = $monster[pygmy witch surgeon]; - - - if (!__quest_state["Level 11 Hidden City"].state_boolean["Office finished"] && $item[McClusky file (page 5)].available_amount() == 0 && $item[McClusky file (complete)].available_amount() == 0) - location_wanted_monster[$location[the hidden office building]] = $monster[pygmy witch accountant]; - - if (!__quest_state["Level 11 Hidden City"].state_boolean["Bowling alley finished"]) - location_wanted_monster[$location[the hidden bowling alley]] = $monster[pygmy bowler]; - } - if (!have_outfit_components("Knob Goblin Harem Girl Disguise")) - location_wanted_monster[$location[cobb's knob harem]] = $monster[Knob Goblin Harem Girl]; - //if (in_hardcore()) - //location_wanted_monster[$location[The Dark Neck of the Woods]] = $monster[Hellion]; - if ($skill[summon smithsness].skill_is_usable() && $item[dirty hobo gloves].available_amount() == 0 && $item[hand in glove].available_amount() == 0 && __misc_state["need to level"]) - { - location_wanted_monster[$location[The Sleazy Back Alley]] = $monster[drunken half-orc hobo]; - location_wanted_monster[$location[The Haunted Pantry]] = $monster[drunken half-orc hobo]; - } - location_wanted_monster[$location[fear man's level]] = $monster[morbid skull]; - - // RIP to my boy, the blooper - // if ($item[digital key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["digital key used"] && $item[white pixel].available_amount() + $item[white pixel].creatable_amount() < 27) - // location_wanted_monster[$location[8-bit realm]] = $monster[Blooper]; - - - if (!__quest_state["Level 11 Pyramid"].finished && olfacted_monster != $monster[tomb servant]) - location_wanted_monster[$location[the middle chamber]] = $monster[tomb rat]; - } - - if (!($monsters[ferocious roc,giant man-eating shark,Bristled Man-O-War,The Cray-Kin,Deadly Hydra] contains olfacted_monster)) - location_wanted_monster[$location[the old man's bathtime adventures]] = $monster[none]; - - - foreach l in location_wanted_monster - { - monster m = location_wanted_monster[l]; - if (l == $location[none]) - continue; - if (__last_adventure_location != l) - continue; - if (m == olfacted_monster) - continue; - - boolean all_other_monsters_banished = true; - foreach key, m2 in l.get_monsters() - { - if (m == m2) - continue; - if (!m2.is_banished()) - { - all_other_monsters_banished = false; - break; - } - } - if (all_other_monsters_banished) - continue; - - string [int] description; - - string line; - - if (m != $monster[none]) - line += "To olfact " + m.HTMLEscapeString() + " instead of " + olfacted_monster.HTMLEscapeString() + ".|"; - else - line += "To olfact in " + l + ".|"; - - if (in_ronin()) - line += $item[soft green echo eyedrop antidote].pluralise() + " available."; - - description.listAppend(line); - - - // Old suggestion recommendation; removing this bit because it isn't needed or necessary. We need to factor this - // as a "top" recommendation thing, with the relevant idea from your most recent zone and a few other ideas - // alongside the # of olfactions remaining. - - // task_entries.listAppend(ChecklistEntryMake("__item " + $item[soft green echo eyedrop antidote], "inventory.php?ftext=soft+green+echo+eyedrop+antidote", ChecklistSubentryMake("Remove " + $effect[on the trail], "", description), -11).ChecklistEntrySetIDTag("Olfaction better suggestion")); //TODO could differentiate by suggestion - - break; - } - -} diff --git a/Source/relay/TourGuide/Sets/PVP.ash b/Source/relay/TourGuide/Sets/PVP.ash deleted file mode 100644 index 0bac7f61..00000000 --- a/Source/relay/TourGuide/Sets/PVP.ash +++ /dev/null @@ -1,542 +0,0 @@ -import "relay/TourGuide/Support/Campground.ash" - -void SPVPGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (!hippy_stone_broken()) - return; - if (pvp_attacks_left() > 0 && today_is_pvp_season_end()) - { - optional_task_entries.listAppend(ChecklistEntryMake("__effect Swordholder", "peevpee.php?place=fight", ChecklistSubentryMake("Run all of your fights", "", listMake("Season ends today.", "Make sure to get the seasonal item if you haven't, as well."))).ChecklistEntrySetIDTag("PVP season end")); - } - - int [string] mini_names = current_pvp_stances(); - - ChecklistEntry entry; - - - string [int] attacking_description; - string [int] attacking_modifiers; - - string [int] overall_modifiers; - string [int] overall_description; - foreach mini in mini_names - { - string [int] modifiers; - string [int] description; - if (mini == "Maul Power") - { - if ($skill[Kung Fu Hustler].have_skill() && $effect[Kung Fu Fighting].have_effect() == 0) - attacking_description.listPrepend("run a combat without a weapon first"); - attacking_modifiers.listAppend("weapon damage"); - continue; - } - else if (mini == "15 Minutes of Fame" || mini == "Beary Famous" || mini == "Upward Mobility Contest" || mini == "Optimal PvP") - { - //attacking_description.listAppend("hit for fame"); - attacking_description.listAppend("maximise fightgen and hit for fame"); - continue; - } - else if (mini == "80 Days and Counting") - { - description.listAppend("Drink Around the Worlds."); - if (have_outfit_components("Hodgman's Regal Frippery")) - { - if (get_property_int("_hoboUnderlingSummons") < 5) - description.listAppend("Equip Hodgman's Regal Frippery, summon hobo underling, ask for a drink."); - } - else if (QuestState("questL12War").mafia_internal_step == 2) - { - description.listAppend("Finish the war."); - } - else if ($item[Spanish fly trap].available_amount() == 0) - { - modifiers.listAppend("-combat"); - if ($location[The Orcish Frat House].noncombat_queue.contains_text("I Just Wanna Fly") || $location[The Orcish Frat House (Bombed Back to the Stone Age)].noncombat_queue.contains_text("Me Just Want Fly")) - { - description.listAppend("Run -combat in The Obligatory Pirate's Cove, acquire Spanish fly trap."); - } - else - description.listAppend("Adventure in the Orcish Frat House until you meet the I Just Wanna Fly adventure.|Then run -combat in The Obligatory Pirate's Cove, acquire Spanish fly trap."); - } - else - { - string [int] tasks; - if ($item[Spanish fly trap].equipped_amount() == 0) - { - tasks.listAppend("equip Spanish fly trap"); - } - modifiers.listAppend("+item"); - tasks.listAppend("adventure in the Hippy Camp, collecting spanish flies");// + (my_level() >= 9 ? " (+combat)" : "")); - if ($item[Spanish fly].available_amount() >= 5) - tasks.listAppend("turn in " + pluralise($item[Spanish fly]) + " in the orcish frat house (-combat)"); - description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - } - } - else if (mini == "Totally Optimal") - { - if (__quest_state["Level 11 Ron"].state_int["protestors remaining"] > 0) - description.listAppend("Fight zeppelin protestors, and don't try to speed them up."); - else - description.listAppend("Ascend to fight more Zeppelin Protestors."); - } - else if (mini == "Optimal Drinking") - { - if (inebriety_limit() == 0) - description.listAppend("Ascend a path you can drink on."); - else - description.listAppend("When drinking, prefer drinks that have effects."); - } - else if (mini == "Familiar Rotation") - { - if (in_ronin()) - description.listAppend("Pick a different familiar than your last ascensions this season."); - else - description.listAppend("Ascend to rotate your familiar."); - } - else if (mini == "Foreigner Reference") - { - description.listAppend("Drink ice-cold Sir Schlitzs or ice-cold Willers." + (in_ronin() ? "|The Orcish Frat House has them. Run +400% item" + (my_level() >= 9 ? " and +15% combat." : "") : "")); - } - else if (mini == "Best Served Repeatedly") - { - description.listAppend("Attack the same target repeatedly. Ideally, lose."); - } - else if (mini == "Burrowing Deep" || mini == "Obviously Optimal") - { - if (__misc_state_int["Basement Floor"] > 400) - { - description.listAppend("Ascend to basement more."); - } - else if (__misc_state_int["Basement Floor"] <= 1) //this test could be better - { - description.listAppend("Unlock Fernswarthy's basement via your guild."); - } - else - { - int floors_remaining = 200 - __misc_state_int["Basement Floor"]; - if (floors_remaining < 0) - floors_remaining = 400 - __misc_state_int["Basement Floor"]; - description.listAppend("Collect a Pan-Dimensional Gargle Blaster from Fernswarthy's basement. " + pluraliseWordy(floors_remaining, "floor", "floors") + " to go."); - } - } - else if (mini == "Frostily Ephemeral" || mini == "Newest Born" || mini == "SELECT asc_time FROM zzz_players WHERE player_id=%playerid%" || mini == "Optimal Ascension") - { - description.listAppend("Ascend to reset timer."); - } - else if (mini == "Karrrmic Battle" || mini == "Karmic Battle") - { - description.listAppend("Ascend to gain more karma."); - } - else if (mini == "Back to Square One") - { - description.listAppend("Ascend."); - } - else if (mini == "Baker's Dozen") - { - description.listAppend("Adventure as often as possible in Madness Bakery."); - } - else if (mini == "Fahrenheit 451") - { - attacking_modifiers.listAppend("hot damage"); - attacking_modifiers.listAppend("hot spell damage"); - continue; - } - else if (mini == "I Like Pi") - { - description.listAppend("Eat key lime pies."); - } - else if (mini == "HTTP 301 Moved Permanently") - { - description.listAppend("Adventure in as many different locations as you can."); - } - else if (mini == "Quality Assurance") - { - description.listAppend("Defeat bug-phylum monsters."); - } - else if (mini == "Free.Willy.1993.1080p.BRRip.x265.torrent") - { - description.listAppend("Fight dolphins.|Farm sand dollars, turn them into dolphin whistles, and use them."); - } - else if (mini == "Installation Wizard") - { - modifiers.listAppend("+item"); - if (!canadia_available()) - { - description.listAppend("Farm dilapidated wizard hats from copied swamp owls.|Or ascend canadia moon sign."); - } - else - { - description.listAppend("Farm dilapidated wizard hats from swamp owls in The Weird Swamp Village."); - } - } - else if (mini == "Illegal Operation") - { - description.listAppend("Buy goofballs from the suspicious-looking guy. If they're too expensive, ascend to reset the price."); - } - else if (mini == "Fotoshop.CS11.Keygen.exe [legit]") - { - description.listAppend("Eat digital key lime pies."); - } - else if (mini == "Most Murderous" || mini == "Icy Revenge") - { - //FIXME list - description.listAppend("Defeat once/ascension bosses."); - } - else if (mini == "Grave Robbery" || mini == "Bear Hunter") - { - if ($item[wand of nagamar].available_amount() > 0) - description.listAppend("Ascend."); - else - description.listAppend("Avoid making the wand of nagamar, lose to the naughty sorceress (3), and look for the wand in the very unquiet garves"); - } - else if (mini == "Basket Reaver") - { - if (my_level() < 11) - { - description.listAppend("Level up."); - } - else - { - modifiers.listAppend("+5% combat"); - modifiers.listAppend("olfact black widow"); - modifiers.listAppend("+item"); - description.listAppend("Run +item% and farm black widows in the black forest."); - } - } - else if (mini == "Rule 42") - { - if ($location[the Haunted Bathroom].noncombat_queue.contains_text("Off the Rack")) //not perfect - continue; - modifiers.listAppend("-combat"); - if ($location[the Haunted Bathroom].locationAvailable()) - description.listAppend("Collect a towel in the Haunted Bathroom."); - else - description.listAppend("Unlock the Haunted Bathroom in Spookyraven Manor."); - } - else if (mini == "Tea for 2, 3, 4 or More") - { - boolean [item] tea = $items[Corpse Island iced tea,cup of lukewarm tea,cup of "tea",hippy herbal tea,Ice Island Long Tea,New Zealand iced tea]; - //description.listAppend("Drink tea.|" + ); - - string tooltip_text = tea.listInvert().listJoinComponents(", ", "or").capitaliseFirstLetter() + "."; - tooltip_text += "
Cheapest is cup of lukewarm tea.
Hippy herbal tea is guano coffee cup (bat guano, batrat, batrat burrow) + herbs (hippy store)."; - - string title = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class") + "Drink tea.", "r_tooltip_outer_class"); - description.listAppend(title); - } - else if (mini == "Scurvy Challenge") - { - boolean [item] fruit = $items[grapefruit,kumquat,lemon,lime,orange,pixel lemon,sea tangelo,tangerine,vinegar-soaked lemon slice]; - //description.listAppend("Drink tea.|" + ); - - string tooltip_text = fruit.listInvert().listJoinComponents(", ", "or").capitaliseFirstLetter() + "."; - tooltip_text += "
Check the hippy store, on the island."; - - string title = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class") + "Eat fruit.", "r_tooltip_outer_class"); - description.listAppend(title); - } - else if (mini == "Raw Carnivorery") - { - //FIXME This could be dynamic, I bet the game is dynamic. - boolean [item] meat = $items[beefy fish meat, glistening fish meat, slick fish meat, "meat" stick, raw mincemeat, alien meat, dead meat bun, consummate meatloaf, VYKEA meatballs]; - - string [int] entries; - foreach it in meat - { - string entry = it; - if (entries.count() == 0) entry = entry.capitaliseFirstLetter(); - if (it.fullness == 1) - entry = HTMLGenerateSpanOfClass(entry, "r_bold"); - entries.listAppend(entry); - } - - string tooltip_text = entries.listJoinComponents(", ", "or") + "."; - - string title = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class") + "Eat meat.", "r_tooltip_outer_class"); - description.listAppend(title); - } - else if (mini == "That Britney Spears Number") - { - string [int] tasks; - if ($item[wooden stakes].available_amount() == 0) - { - description.listAppend("Adventure in the Spooky Forest, collect wooden stakes from the noncombat."); - description.listAppend("Follow the old road " + __html_right_arrow_character + " Knock on the cottage door."); - modifiers.listAppend("-combat"); - } - else - { - if ($item[wooden stakes].equipped_amount() == 0) - { - tasks.listAppend("equip wooden stakes"); - } - modifiers.listAppend("olfact spooky vampire"); - tasks.listAppend("fight vampires in the Spooky Forest"); - description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - } - } - else if (mini == "The Purity is Right" || mini == "Polar Envy" || mini == "Purity") - { - attacking_description.listAppend("run zero effects"); - continue; - } - else if (mini == "Purrrity") - { - attacking_description.listAppend("run zero effects with R in their name"); - continue; - } - else if (mini == "The Optimal Stat") - { - attacking_modifiers.listAppend("+item drop"); - continue; - } - else if (mini == "A Nice Cold One" || mini == "Thirrrsty forrr Booze") - { - attacking_modifiers.listAppend("+booze drop"); - continue; - } - else if (mini == "Smellin' Like a Stinkin' Rose") - { - attacking_modifiers.listAppend("-combat"); - continue; - } - else if (mini == "Ready to Melt") - { - attacking_modifiers.listAppend("hot damage"); - attacking_modifiers.listAppend("hot spell damage"); - continue; - } - else if (mini == "Zero Tolerance") - { - description.listAppend("Don't drink booze."); - } - else if (mini == "Visiting the Cousins" || mini == "Visiting The Co@^&$`~") - { - if (knoll_available()) - description.listAppend("Adventure in the bugbear pens."); - else - description.listAppend("Ascend knoll moon sign."); - } - else if (mini == "Craft Brew is Optimal") - { - if (gnomads_available()) - description.listAppend("Drink from the Gnomish Microbrewery."); - else - description.listAppend("Ascend Gnomish moon sign."); - } - else if (mini == "Who Runs Bordertown?") - { - if (gnomads_available()) - description.listAppend("Adventure in the Thugnderdome."); - else - description.listAppend("Ascend Gnomish moon sign."); - } - else if (mini == "Pirate Wars!") - { - description.listAppend("Fight pirates, but not too many; the count resets every day."); - } - else if (mini == "Bilge Hunter") - { - description.listAppend("Run +300 ML and +combat, and fight drunken rat kings in the Typical Tavern basement."); - modifiers.listAppend("+300 ML"); - modifiers.listAppend("+combat"); - } - else if (mini == "Death to Ninja!") - { - string [int] tasks; - if (!is_wearing_outfit("Swashbuckling Getup")) - tasks.listAppend("equip swashbuckling getup"); - tasks.listAppend("fight ninja"); - description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); - } - else if (mini == "Swimming with the Fishes") - { - description.listAppend("Spend turns underwater."); - } - else if (mini == "(Fur) Shirts and Skins") - { - description.listAppend("Collect furs and skins from monsters. (+item)|The icy peak? Olfact yeti."); - } - else if (mini == "With Your Bare Hands") - { - description.listAppend("Fight beast-type monsters without a weapon equipped.|The icy peak (olfact yeti) or the dire warren?"); - } - else if (mini == "Northern Digestion" || mini == "Frozen Dinners") - { - if (canadia_available()) - { - if (availableFullness() > 0) - description.listAppend("Eat in Chez Snoteé."); - } - else - description.listAppend("Ascend canadia moon sign."); - } - else if (mini == "ERR_VOLUME_FULL") - { - description.listAppend("Don't eat anything."); - } - else if (mini == "Really Bloody") - { - if (inebriety_limit() == 0) - description.listAppend("Ascend to drink Bloody Mary."); - else - description.listAppend("Drink Bloody Mary."); - } - else if (mini == "System Clock Reset: It's 2006 again!") - { - if (inebriety_limit() == 0) - description.listAppend("Ascend to drink White Canadians."); - else - description.listAppend("Drink White Canadians."); - } - else if (mini == "Liver of the Damned") - { - if (inebriety_limit() == 0) - description.listAppend("Ascend to drink cursed bottles of rum."); - else - description.listAppend("Drink cursed bottles of rum."); - description.listAppend("Run -combat at the Poop Deck, set an open course to 1,1, open the cursed chests."); - modifiers.listAppend("-combat"); - } - else if (mini == "Beast Master") - { - attacking_modifiers.listAppend("familiar weight"); - continue; - } - else if (mini == "Letter of the Moment") - { - attacking_modifiers.listAppend("letter of the moment"); - continue; - } - else if (mini == "ASCII-7 of the moment") - { - attacking_modifiers.listAppend("letter a in equipment"); - continue; - } - else if (mini == "Barely Dressed") - { - attacking_description.listAppend("do not equip equipment"); - continue; - } - else if (mini == "DEFACE") - { - attacking_description.listAppend("wear equipment with A/B/C/D/E/F/numbers in them"); - continue; - } - else if (mini == "Dressed to the 9s") - { - attacking_description.listAppend("wear equipment with numbers in them"); - continue; - } - else if (mini == "Optimal Dresser") - { - attacking_description.listAppend("wear low-power shirt/hat/pants"); - continue; - } - else if (mini == "Dressed in Rrrags" || mini == "Outfit Compression") - { - attacking_description.listAppend("wear short-named equipment"); - continue; - } - else if (mini == "Hibernation Ready" || mini == "All Bundled Up") - { - attacking_modifiers.listAppend("cold resistance"); - continue; - } - else if (mini == "Loot Hunter" || mini == "The Optimal Stat") - { - attacking_modifiers.listAppend("+item"); - continue; - } - else if (mini == "Safari Chic") - { - attacking_modifiers.listAppend("equipment autosell value"); - continue; - } - else if (mini == "Checking It Twice") - { - attacking_description.listAppend("target players you haven't fought twice"); - continue; - } - else if (mini == "Ice Hunter") - { - description.listAppend("Fight ice skates. Either fax/wish/copy them, or olfact them in the The Skate Park underwater."); - } - else if (mini == "Bear Hugs All Around" || mini == "Sharing the Love (to stay warm)" || mini == "Fair Game") - { - description.listAppend("Maximise fightgen, attack as many unique opponents as possible."); - } - else if (mini == "Most Things Eaten") - { - string line = "Eat as many one-fullness foods as possible."; - if (__campground[$item[portable mayo clinic]] > 0 && availableDrunkenness() > 0) - line += "|Also use mayodiol."; - description.listAppend(line); - } - else if (mini == "Beta Tester" || mini == "Optimal War") - { - if (__quest_state["Level 12"].finished) - { - description.listAppend("Ascend to fight in war."); - } - else if (!__quest_state["Level 12"].started) - { - description.listAppend("Start the war."); - } - else - { - description.listAppend("Finish the war for the frat side, with five sidequests completed. (iron beta of industry reward)"); - } - } - else if (mini == "Snow Patrol") - { - if (__quest_state["Level 12"].finished) - { - description.listAppend("Ascend to fight in war."); - } - else if (!__quest_state["Level 12"].started) - { - description.listAppend("Start the war."); - } - else - { - modifiers.listAppend("+4 cold res"); - string line = "Fight on the battlefield"; - if (numeric_modifier("cold resistance") < 4) - line += HTMLGenerateSpanFont(" with +4 cold resistance", "red"); - line += "."; - description.listAppend(line); - } - } - else - { - if (my_id() == 1557284) - description.listAppend(HTMLGenerateSpanFont("Unhandled mini \"" + mini + "\".", "red")); - else - continue; - } - overall_modifiers.listAppendList(modifiers); - if (description.count() > 0) - overall_description.listAppend(description.listJoinComponents("|*")); - //entry.subentries.listAppend(ChecklistSubentryMake(mini, modifiers, description)); - } - if (overall_description.count() > 0) - { - entry.subentries.listAppend(ChecklistSubentryMake("Work on PVP minis", overall_modifiers, overall_description)); - } - if (attacking_modifiers.count() > 0) - attacking_description.listAppend("maximise " + attacking_modifiers.listJoinComponents(" / ")); - if (attacking_description.count() > 0) - { - entry.subentries.listAppend(ChecklistSubentryMake("When attacking", attacking_modifiers, attacking_description.listJoinComponents(", ", "and ").capitaliseFirstLetter() + ".")); - } - - if (entry.subentries.count() > 0) - { - entry.image_lookup_name = "__effect Swordholder"; - entry.url = "peevpee.php"; - entry.tags.id = "PVP suggestions"; - entry.importance_level = 6; - optional_task_entries.listAppend(entry); - } -} diff --git a/Source/relay/TourGuide/Sets/Powerlevel.ash b/Source/relay/TourGuide/Sets/Powerlevel.ash deleted file mode 100644 index 157ed3be..00000000 --- a/Source/relay/TourGuide/Sets/Powerlevel.ash +++ /dev/null @@ -1,140 +0,0 @@ -RegisterTaskGenerationFunction("SPowerlevelGenerateTasks"); -void SPowerlevelGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - if (__misc_state["need to level"] && my_path().id != PATH_EXPLOSION) - { - string url = ""; - int mcd_max_limit = 10; - boolean have_mcd = false; - if (canadia_available() || knoll_available() || gnomads_available() && __misc_state["desert beach available"] || in_bad_moon()) - have_mcd = true; - if (canadia_available()) - { - mcd_max_limit = 11; - url = "place.php?whichplace=canadia&action=lc_mcd"; - } - else if (knoll_available()) - { - if ($item[detuned radio].available_amount() > 0) - url = "inventory.php?ftext=detuned+radio"; - else - url = "shop.php?whichshop=gnoll"; - } - else if (gnomads_available()) - url = "gnomes.php?place=machine"; - //FIXME URLs for the other ones - if (current_mcd() < mcd_max_limit && have_mcd && monster_level_adjustment() < 150 && !in_bad_moon() && !(my_path().id == PATH_G_LOVER && knoll_available())) - { - optional_task_entries.listAppend(ChecklistEntryMake("__item detuned radio", url, ChecklistSubentryMake("Set monster control device to " + mcd_max_limit, "", roundForOutput(mcd_max_limit * __misc_state_float["ML to mainstat multiplier"], 2) + " mainstats/turn")).ChecklistEntrySetIDTag("Powerlevel MCD ML")); - } - } - - if (__misc_state["need to level"] && my_path().id != PATH_COMMUNITY_SERVICE) - { - ChecklistSubentry subentry; - - int main_substats = my_basestat(my_primesubstat()); - int substats_remaining = substatsForLevel(my_level() + 1) - main_substats; - - subentry.header = "Level to " + (my_level() + 1); - - subentry.entries.listAppend("Gain " + pluralise(substats_remaining, "substat", "substats") + "."); - - string url = ""; - - boolean spooky_airport_unlocked = __misc_state["spooky airport available"]; - boolean stench_airport_unlocked = __misc_state["stench airport available"]; - - if (__misc_state["Chateau Mantegna available"] && __misc_state_int["free rests remaining"] > 0) - url = "place.php?whichplace=chateau"; - else if (stench_airport_unlocked && monster_level_adjustment() >= 150) - url = $location[Uncle Gator's Country Fun-Time Liquid Waste Sluice].getClickableURLForLocation(); - else if (spooky_airport_unlocked && ($effect[jungle juiced].have_effect() > 0 || ($item[jungle juice].available_amount() > 0 && availableDrunkenness() > 0 && __misc_state["can drink just about anything"]))) - url = $location[the deep dark jungle].getClickableURLForLocation(); - else if (__misc_state["Chateau Mantegna available"]) - url = "place.php?whichplace=chateau"; - else if (__misc_state["sleaze airport available"]) - url = $location[sloppy seconds diner].getClickableURLForLocation(); - else if (spooky_airport_unlocked) - url = $location[the deep dark jungle].getClickableURLForLocation(); - else if ($item[GameInformPowerDailyPro walkthru].available_amount() > 0) - url = $location[[DungeonFAQ - Level 1]].getClickableURLForLocation(); - else if (my_primestat() == $stat[muscle] && $location[the haunted billiards room].locationAvailable()) - url = $location[the haunted gallery].getClickableURLForLocation(); - else if (my_primestat() == $stat[mysticality] && $location[the haunted bedroom].locationAvailable()) - url = $location[the haunted bathroom].getClickableURLForLocation(); - else if (my_primestat() == $stat[moxie] && $location[the haunted bedroom].locationAvailable()) - url = $location[the haunted ballroom].getClickableURLForLocation(); - - - //133.33333333333333 meat per stat - int maximum_allowed_to_donate = 10000 * my_level(); - int cost_to_donate_for_level = ceil(substats_remaining.to_float() / 1.5) * 200.0; - int min_cost_to_donate_for_level = ceil(substats_remaining.to_float() / 2.0) * 200.0; - if (min_cost_to_donate_for_level <= my_meat() && min_cost_to_donate_for_level <= maximum_allowed_to_donate) - { - string statue_name = ""; - if (my_primestat() == $stat[muscle] && $item[boris's key].available_amount() > 0) - { - statue_name = "Boris"; - if (cost_to_donate_for_level < 2000 || cost_to_donate_for_level < my_meat() * 0.2) - url = "da.php?place=gate1"; - } - else if (my_primestat() == $stat[mysticality] && $item[jarlsberg's key].available_amount() > 0 && my_path().id != PATH_AVATAR_OF_JARLSBERG) - { - statue_name = "Jarlsberg"; - if (cost_to_donate_for_level < 2000 || cost_to_donate_for_level < my_meat() * 0.2) - url = "da.php?place=gate2"; - } - else if (my_primestat() == $stat[moxie] && $item[sneaky pete's key].available_amount() > 0 && my_path().id != PATH_AVATAR_OF_SNEAKY_PETE) - { - statue_name = "Sneaky Pete"; - if (cost_to_donate_for_level < 2000 || cost_to_donate_for_level < my_meat() * 0.2) - url = "da.php?place=gate3"; - } - - if (statue_name != "" && !(!in_ronin() && cost_to_donate_for_level > 20000)) - { - buffer line = "Possibly donate ".to_buffer(); - if (cost_to_donate_for_level == min_cost_to_donate_for_level) - line.append(cost_to_donate_for_level); - else - { - line.append(min_cost_to_donate_for_level); - line.append(" to "); - line.append(cost_to_donate_for_level); - } - line.append(" meat to the statue of "); - line.append(statue_name); - line.append("."); - subentry.entries.listAppend(line); - - } - } - - - - string image_name = "player character"; - - if (false) - { - //vertically less imposing: - //disabled for now - player avatars look better. well, sneaky pete's avatar looks better... - image_name = "mini-adventurer blank female"; - - string [class] class_images; - class_images[$class[seal clubber]] = "mini-adventurer seal clubber female"; - class_images[$class[turtle tamer]] = "mini-adventurer turtle tamer female"; - class_images[$class[pastamancer]] = "mini-adventurer pastamancer female"; - class_images[$class[sauceror]] = "mini-adventurer sauceror female"; - class_images[$class[disco bandit]] = "mini-adventurer disco bandit female"; - class_images[$class[accordion thief]] = "mini-adventurer accordion thief female"; - - if (class_images contains my_class()) - image_name = class_images[my_class()]; - } - - - task_entries.listAppend(ChecklistEntryMake(image_name, url, subentry, 11).ChecklistEntrySetIDTag("Powerlevel suggestions")); - } -} diff --git a/Source/relay/TourGuide/Sets/Pulverise.ash b/Source/relay/TourGuide/Sets/Pulverise.ash deleted file mode 100644 index 93e17559..00000000 --- a/Source/relay/TourGuide/Sets/Pulverise.ash +++ /dev/null @@ -1,212 +0,0 @@ -static -{ - //NOTE: this array does not support non-tradeable, quest, or non-discardable items. It could, but then I'd have to filter those out later, and I'm not sure how fast get_related is. - int [item][item] __inverse_pulverisation; - - void initialisePulverisations() - { - foreach smashing_item in $items[] - { - if (!smashing_item.tradeable || smashing_item.quest || !smashing_item.discardable) - continue; - if (smashing_item.to_slot() == $slot[none]) - continue; - int [item] pulverisations = smashing_item.get_related("pulverize"); - if (pulverisations.count() == 0) - continue; - foreach smash_result, value in pulverisations - { - __inverse_pulverisation[smash_result][smashing_item] = value; - } - } - } - - initialisePulverisations(); -} - -record SmashableItem -{ - item it; - float products_found; -}; - -SmashableItem SmashableItemMake(item it, float products_found) -{ - SmashableItem result; - result.it = it; - result.products_found = products_found; - return result; -} - -void listAppend(SmashableItem [int] list, SmashableItem entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - - -void pulveriseAlterOutputList(string [int] output_list) -{ - //Alter lines so items aren't split up by word wrap: - int number_seen = 0; - foreach key in output_list - { - string line = output_list[key]; - - if (number_seen < output_list.count() - 1) //comma needs to be part of the group - line += ","; - line = HTMLGenerateDivOfClass(line, "r_word_wrap_group"); - - output_list[key] = line; - number_seen += 1; - } -} - -string [int] pulveriseGenerateOutputListForProducts(boolean [item] products_wanted, boolean [item] blacklist) -{ - int [item] smashables_found; - foreach product in products_wanted - { - foreach smashable in __inverse_pulverisation[product] - { - if (smashable.available_amount() == 0) - continue; - if (blacklist[smashable]) - continue; - int value = __inverse_pulverisation[product][smashable]; - smashables_found[smashable] += value; - } - } - - - SmashableItem [int] available_smashed_items; - - foreach smashable, product_count in smashables_found - { - float average_products_acquired = product_count.to_float() / 1000000.0; - available_smashed_items.listAppend(SmashableItemMake(smashable, average_products_acquired)); - } - - sort available_smashed_items by -(value.products_found * value.it.available_amount()); - - string [int] result; - foreach key in available_smashed_items - { - SmashableItem smashable_item = available_smashed_items[key]; - string line; - - line = smashable_item.it; - - result.listAppend(line); - } - - - - pulveriseAlterOutputList(result); - return result; -} - -void pulveriseAppendOutputListForProducts(string [int] description, string category, boolean [item] products_wanted, boolean [item] blacklist) -{ - string [int] output_list = pulveriseGenerateOutputListForProducts(products_wanted, blacklist); - - if (output_list.count() > 0) - { - description.listAppend(HTMLGenerateSpanOfClass(category.capitaliseFirstLetter() + ": ", "r_bold") + output_list.listJoinComponents(" ", "and") + "."); - } -} - -void SPulveriseGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!$skill[pulverize].skill_is_usable()) - return; - if (!in_ronin()) //list is far too long with your main inventory, and you can buy wads at this point - return; - - - /* - Smashable item types: - BRICKO brick - candycaine powder - chunk of depleted Grimacite - cold cluster - cold nuggets - cold powder - cold wad - corrupted stardust - effluvious emerald - epic wad - glacial sapphire - handful of Smithereens - hot cluster - hot nuggets - hot powder - hot wad - sea salt crystal - sleaze cluster - sleaze nuggets - sleaze powder - sleaze wad - spooky cluster - spooky nuggets - spooky powder - spooky wad - steamy ruby - stench cluster - stench nuggets - stench powder - stench wad - sugar shard - tawdry amethyst - twinkly nuggets - twinkly powder - twinkly wad - ultimate wad - unearthly onyx - useless powder - wad of Crovacite - */ - - - boolean [item] blacklist; - blacklist.listAppendList($items[fireman's helmet,fire axe,enchanted fire extinguisher,fire hose,rainbow pearl earring,rainbow pearl necklace,rainbow pearl ring,steaming evil,ring of detect boring doors,giant discarded torn-up glove,giant discarded plastic fork,giant discarded bottlecap,toy ray gun,toy space helmet,toy jet pack,MagiMechTech NanoMechaMech,astronaut pants,ancient hot dog wrapper,bram's choker]); - - if (!__quest_state["Level 12"].finished) - blacklist.listAppendList($items[reinforced beaded headband,bullet-proof corduroys,round purple sunglasses,beer helmet,distressed denim pants,bejeweled pledge pin]); - if (!__quest_state["Level 11 Hidden City"].state_boolean["Hospital finished"]) - blacklist.listAppendList($items[head mirror,surgical apron,bloodied surgical dungarees,surgical mask,half-size scalpel]); - - string [int] details; - - //not relevant for adventures anymore: - /*if (availableSpleen() > 0 && my_path().id != PATH_SLOW_AND_STEADY) - { - pulveriseAppendOutputListForProducts(details, "spleen wads", $items[cold wad,hot wad,sleaze wad,spooky wad,stench wad,twinkly wad], blacklist); - }*/ - - /*if (__misc_state["mysticality guild store available"] && $skill[Transcendental Noodlecraft].skill_is_usable() && $skill[The Way of Sauce].skill_is_usable()) //can make hi mein? - { - pulveriseAppendOutputListForProducts(details, "hi mein elemental nuggets", $items[cold nuggets,hot nuggets,sleaze nuggets,spooky nuggets,stench nuggets], blacklist); - }*/ - - - pulveriseAppendOutputListForProducts(details, "handful of smithereens", $items[handful of smithereens], blacklist); - - //Elemental powder, for +1 resistances? - //Elemental nuggets, for +3 tower test? (very marginal) - - if (details.count() > 0) - { - string title; - title = "Pulverisable equipment"; - string url = "craft.php?mode=smith"; - if ($item[tenderizing hammer].available_amount() == 0) - { - url = "shop.php?whichshop=meatsmith"; - details.listAppend("Acquire a tenderizing hammer."); - } - resource_entries.listAppend(ChecklistEntryMake("__skill pulverize", url, ChecklistSubentryMake(title, "", details), 10).ChecklistEntrySetIDTag("Pulverize suggestions")); - } -} diff --git a/Source/relay/TourGuide/Sets/Reminders.ash b/Source/relay/TourGuide/Sets/Reminders.ash deleted file mode 100644 index 997dae28..00000000 --- a/Source/relay/TourGuide/Sets/Reminders.ash +++ /dev/null @@ -1,407 +0,0 @@ - -void SRemindersGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - - if ($effect[Straight-Edgy].have_effect() > 0 && inebriety_limit() > 0 && availableDrunkenness() >= 0) { - int straight_edgy_adventures = 4.5 * (availableDrunkenness() + 1); - string header = "Stop drinking"; - if (my_inebriety() == 0) - header = "Don't drink anything"; - string [int] description; - description.listAppend("Will give " + straight_edgy_adventures + " adventures next time you log in since next rollover."); - if (__misc_state_int["adventures after rollover"] + straight_edgy_adventures > 190) //add some leeway for those who didn't know about it - description.listAppend("Is added " + "after".HTMLGenerateSpanOfClass("r_bold") + " the 200 cap."); - if ($familiar[Stooper].familiar_is_usable()) { - string line; - if (my_familiar() == $familiar[Stooper]) - line = "Keep the Stooper equipped to get the most out of this."; - else - line = "Equip the Stooper for additional adventures."; - description.listAppend(line); - } - - task_entries.listAppend(ChecklistEntryMake("__effect straight-edgy", "", ChecklistSubentryMake(header, "", description), -11).ChecklistEntrySetIDTag("Straight-edgy reminder")); - } - - if ($effect[beaten up].have_effect() > 0) - { - string [int] methods; - string url; - if ($skill[tongue of the walrus].skill_is_usable()) - { - methods.listAppend("Cast Tongue of the Walrus."); - url = "skills.php"; - } - else if (__misc_state["VIP available"] && __misc_state_int["hot tub soaks remaining"] > 0) - { - methods.listAppend("Soak in VIP hot tub."); - url = "clan_viplounge.php"; - } - else if ($skill[Shake it off].skill_is_usable()) - { - methods.listAppend("Cast shake it off."); - url = "skills.php"; - } - else if (__misc_state_int["free rests remaining"] > 0) - { - methods.listAppend("Free rest at " + __misc_state_string["resting description"] + "."); - url = __misc_state_string["resting url"]; - } - - foreach it in $items[tiny house,space tours tripple,personal massager,forest tears,csa all-purpose soap] - { - if (it.available_amount() > 0 && methods.count() == 0) - { - url = "inventory.php?which=1"; //may not be correct in all cases - methods.listAppend("Use " + it + "."); - break; - } - } - - boolean [location] ignoring_locations; - ignoring_locations[$location[The Crimbonium Mine]] = true; - - if (methods.count() > 0 && $effect[thrice-cursed].have_effect() == 0 && !((ignoring_locations contains __last_adventure_location) && __last_adventure_location != $location[none])) - task_entries.listAppend(ChecklistEntryMake("__effect beaten up", url, ChecklistSubentryMake("Remove beaten up", "", methods), -11).ChecklistEntrySetIDTag("Beaten up reminder")); - } - - if (true) - { - //Don't get poisoned. - effect [int] poison_effects; - poison_effects.listAppend($effect[Hardly poisoned at all]); - //if (!hippy_stone_broken()) //FIXME remove next PVP season - poison_effects.listAppend($effect[A Little Bit Poisoned]); - poison_effects.listAppend($effect[Somewhat Poisoned]); - poison_effects.listAppend($effect[Really Quite Poisoned]); - poison_effects.listAppend($effect[Majorly Poisoned]); - poison_effects.listAppend($effect[Toad In The Hole]); - - effect have_poison = $effect[none]; - foreach key in poison_effects - { - effect e = poison_effects[key]; - if (e.have_effect() > 0) - { - have_poison = e; - break; - } - } - if (have_poison != $effect[none] && my_path().id != PATH_G_LOVER) - { - string url = ""; - string [int] methods; - - /*if ($skill[disco nap].skill_is_usable() && $skill[adventurer of leisure].skill_is_usable()) - { - url = "skills.php"; - methods.listAppend("Cast Disco Nap."); - } - else*/ - if (true) - { - url = "shop.php?whichshop=doc"; - methods.listAppend("Use Doc Galaktik's anti-anti-antidote."); - if ($item[anti-anti-antidote].available_amount() > 0) - url = "inventory.php?ftext=anti-anti-antidote"; - } - - task_entries.listAppend(ChecklistEntryMake("__effect " + have_poison, url, ChecklistSubentryMake("Remove " + have_poison, "", methods), -11).ChecklistEntrySetIDTag("Poisoned reminder")); - } - } - if ($effect[teleportitis].have_effect() > 0) - { - string url = "inventory.php"; - string method = "Use a soft green echo eyedrop antidote."; - if ($item[soft green echo eyedrop antidote].available_amount()<1) - method = "Acquire & use a soft green echo eyedrop antidote."; - task_entries.listAppend(ChecklistEntryMake("__effect teleportitis", url, ChecklistSubentryMake("Remove Teleportitis", "", method), -11).ChecklistEntrySetIDTag("Teleportitis reminder")); - } - if ($effect[feeling lost].have_effect() > 0) - { - string url = "inventory.php"; - string method = "Use a soft green echo eyedrop antidote."; - if ($item[soft green echo eyedrop antidote].available_amount()<1) - method = "Acquire & use a soft green echo eyedrop antidote."; - task_entries.listAppend(ChecklistEntryMake("__effect Feeling Lost", url, ChecklistSubentryMake("Remove Feeling Lost", "", method), -11).ChecklistEntrySetIDTag("Feeling Lost reminder")); - } - if ($effect[Cunctatitis].have_effect() > 0 && $skill[disco nap].skill_is_usable() && $skill[adventurer of leisure].skill_is_usable()) - { - string url = "skills.php"; - string method = "Cast disco nap."; - task_entries.listAppend(ChecklistEntryMake("__effect Cunctatitis", url, ChecklistSubentryMake("Remove Cunctatitis", "", method), -11).ChecklistEntrySetIDTag("Cunctatitis reminder")); - } - - if ($effect[Down the Rabbit Hole].have_effect() > 0 && __last_adventure_location == $location[The Red Queen's Garden] && (!in_ronin() || $item["DRINK ME" potion].available_amount() > 0) && get_property_int("pendingMapReflections") <= 0) - { - string url = "mall.php"; - - if ($item["DRINK ME" potion].available_amount() > 0) - url = "inventory.php?ftext=drink+me"; - - task_entries.listAppend(ChecklistEntryMake("__item "DRINK ME" potion", url, ChecklistSubentryMake("Drink " + $item["DRINK ME" potion], "+madness", "Otherwise, no reflections of a map will drop."), -11).ChecklistEntrySetIDTag("Rabbit hole map reflections reminder")); - } - - if ($effect[Merry Smithsness].have_effect() == 0 && (!in_ronin() || $item[flaskfull of hollow].available_amount() > 0) && $items[Meat Tenderizer is Murder,Ouija Board\, Ouija Board,Hand that Rocks the Ladle,Saucepanic,Frankly Mr. Shank,Shakespeare's Sister's Accordion,Sheila Take a Crossbow,A Light that Never Goes Out,Half a Purse,loose purse strings,Hand in Glove].equipped_amount() > 0 && $item[flaskfull of hollow].item_is_usable()) - { - //They (can) have a flaskfull of hollow and have a smithsness item equipped, but no merry smithsness. - //So, suggest a high-priority task. - //I suppose in theory they could be saving the flaskfull of hollow for later, for +item? In that case, we would be annoying them. They can closet the flask, but that isn't perfect... - //Still, I feel as though having this reminder is better than not having it. - - //Four items are not on the list due to their marginal bonus: Hairpiece On Fire (+maximum MP), Vicar's Tutu (+maximum HP), Staff of the Headmaster's Victuals (+spell damage), Work is a Four Letter Sword (+weapon damage) - string url = "mall.php"; - - if ($item[flaskfull of hollow].available_amount() > 0) - url = "inventory.php?ftext=flaskfull+of+hollow"; - - task_entries.listAppend(ChecklistEntryMake("__item flaskfull of hollow", url, ChecklistSubentryMake("Drink " + $item[flaskfull of hollow], "", "Gives +25 smithsness"), -11).ChecklistEntrySetIDTag("Smithsness flaskfull of hollow reminder")); - } - - if ($effect[QWOPped Up].have_effect() > 0 && ((__misc_state["VIP available"] && __misc_state_int["hot tub soaks remaining"] > 0) || $skill[Shake It Off].skill_is_usable())) //only suggest if they have hot tub access; other route is a SGEEA, too valuable - { - string [int] description; - string url = ""; - if ($skill[Shake It Off].skill_is_usable()) - { - url = "skills.php"; - description.listAppend("Shake it off."); - } - else - { - url = "clan_viplounge.php"; - description.listAppend("Use hot tub."); - } - - task_entries.listAppend(ChecklistEntryMake("__effect qwopped up", url, ChecklistSubentryMake("Remove QWOPped up effect", "", description), -11).ChecklistEntrySetIDTag("QWOPped up reminder")); - } - - boolean [monster] awkwards; - awkwards[$monster[Dr. Awkward]] = true; - awkwards[$monster[Dr. Aquard]] = true; - - if ((awkwards contains get_property_monster("lastEncounter")) && $item[mega gem].equipped_amount() > 0 && ($items[2268, Staff of Ed\, almost].available_amount() > 0 || $item[2325].available_amount() > 0)) - { - //Just defeated Dr. Awkward. - //This will disappear once they adventure somewhere else. - string [int] description; - - description.listAppend("It's not useful now, wear a better accessory?"); - if ($item[talisman o' namsilat].equipped_amount() > 0) - description.listAppend("Possibly the talisman as well."); - - task_entries.listAppend(ChecklistEntryMake("__item mega gem", "inventory.php?which=2", ChecklistSubentryMake("Possibly unequip the Mega Gem", "", description), -11).ChecklistEntrySetIDTag("Mega gem off reminder")); - } - - if (__misc_state["need to level"]) - { - ChecklistEntry stat_items; - stat_items.image_lookup_name = ""; - stat_items.url = "inventory.php?which=3"; - stat_items.tags.id = "Powerleveling general reminders"; - stat_items.importance_level = 0; - - effect [item] item_effects; - string [item] item_descriptions; - - if ($effect[Purple Tongue].have_effect() == 0 && $effect[Green Tongue].have_effect() == 0 && $effect[Red Tongue].have_effect() == 0 && $effect[Blue Tongue].have_effect() == 0 && $effect[Black Tongue].have_effect() == 0) - { - item_descriptions[$item[orange snowcone]] = "+1.5 mainstat/fight (20 turns)"; - item_effects[$item[orange snowcone]] = $effect[Orange Tongue]; - } - - if (in_ronin()) - { - item_descriptions[$item[Effermint™ tablets]] = "+1.5 mainstat/fight (10 turns)"; - } - - if (__misc_state["need to level moxie"]) - { - item_descriptions[$item[Ye Olde Bawdy Limerick]] = "+2 moxie stats/fight (20 turns)"; - item_effects[$item[Ye Olde Bawdy Limerick]] = $effect[From Nantucket]; - - - item_descriptions[$item[resolution: be sexier]] = "+2 moxie stats/fight (20 turns)"; - item_effects[$item[resolution: be sexier]] = $effect[Irresistible Resolve]; - - //Always better used for +init, since the tower tests came into existence? - /*if (in_ronin() && !in_bad_moon() && my_primestat() == $stat[moxie]) //better used for +init otherwise - { - item_descriptions[$item[old bronzer]] = "+2 moxie stats/fight (25 turns)"; - item_effects[$item[old bronzer]] = $effect[Sepia Tan]; - }*/ - } - - if (__misc_state["need to level muscle"]) - { - item_descriptions[$item[Squat-Thrust Magazine]] = "+3 muscle stats/fight (20 turns)"; - item_effects[$item[Squat-Thrust Magazine]] = $effect[Squatting and Thrusting]; - - - item_descriptions[$item[resolution: be stronger]] = "+2 muscle stats/fight (20 turns)"; - item_effects[$item[resolution: be stronger]] = $effect[Strong Resolve]; - - - /*if (in_ronin() && !in_bad_moon()) - { - item_descriptions[$item[old eyebrow pencil]] = "+2 muscle stats/fight (25 turns)"; - item_effects[$item[old eyebrow pencil]] = $effect[Browbeaten]; - }*/ - } - if (__misc_state["need to level mysticality"]) - { - item_descriptions[$item[O'RLY Manual]] = "+4 mysticality stats/fight (20 turns)"; - item_effects[$item[O'RLY Manual]] = $effect[You Read The Manual]; - - - item_descriptions[$item[resolution: be smarter]] = "+2 mysticality stats/fight (20 turns)"; - item_effects[$item[resolution: be smarter]] = $effect[Brilliant Resolve]; - - - /*if (in_ronin() && !in_bad_moon()) - { - item_descriptions[$item[old rosewater cream]] = "+2 mysticality stats/fight (25 turns)"; - item_effects[$item[old rosewater cream]] = $effect[Rosewater Mark]; - }*/ - } - - if (my_level() >= 11) - { - item_descriptions[$item[BitterSweetTarts]] = "+5.5 " + my_primestat().to_lower_case() + " stats/fight (10 turns)"; - item_effects[$item[BitterSweetTarts]] = $effect[Full of Wist]; - } - - item [int] relevant_items; - string [int] relevant_descriptions; - foreach it in item_descriptions - { - if (it.item_amount() == 0) - continue; - if (!it.item_is_usable()) continue; - effect e = item_effects[it]; - if (e == $effect[none]) - e = it.to_effect(); - if (!e.effect_is_usable()) continue; - if (e.have_effect() > 0) - continue; - if (stat_items.image_lookup_name.length() == 0) - stat_items.image_lookup_name = "__item " + it; - //stat_items.subentries.listAppend(ChecklistSubentryMake("Use " + it, "", item_descriptions[it])); - relevant_items.listAppend(it); - relevant_descriptions.listAppend(item_descriptions[it]); - } - - ChecklistSubentry subentry; - if (relevant_items.count() > 0) - { - subentry.header = "Use " + relevant_items.listJoinComponents(", ", "and"); - subentry.entries.listAppend(relevant_descriptions.listJoinComponents(", ", "and")); - } - - - if (subentry.header != "") - stat_items.subentries.listAppend(subentry); - if (stat_items.subentries.count() > 0) - { - optional_task_entries.listAppend(stat_items); - } - } - - if ($item[evil eye].available_amount() > 0 && __quest_state["Level 7"].state_int["nook evilness"] > 25 && my_path().id != PATH_G_LOVER) - { - task_entries.listAppend(ChecklistEntryMake("__item " + $item[evil eye], "inventory.php?ftext=evil+eye", ChecklistSubentryMake("Use " + $item[evil eye], "", "Three cyrpt nook beeps."), -11).ChecklistEntrySetIDTag("Evil eye reminder")); - } - - if ($familiars[mini-hipster, artistic goth kid] contains my_familiar() && __misc_state["need to level"] && __misc_state_int["hipster fights available"] > 0 && !__misc_state["single familiar run"]) - { - task_entries.listAppend(ChecklistEntryMake("__familiar " + my_familiar(), "", ChecklistSubentryMake("Buff " + my_primestat(), "", "Extra stats from " + my_familiar() + " fights."), -11).ChecklistEntrySetIDTag("Hipster-like familiar scaling fight reminder")); - } - - boolean have_blacklight_bulb = (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && get_property("peteMotorbikeHeadlight") == "Blacklight Bulb"); - boolean have_alternate_uv_source = false; - if (have_blacklight_bulb) - have_alternate_uv_source = true; - if (my_path().id == PATH_LICENSE_TO_ADVENTURE && get_property_boolean("bondDesert")) - have_alternate_uv_source = true; - if (my_familiar() == lookupFamiliar("Melodramedary")) - have_alternate_uv_source = true; - if (__last_adventure_location == $location[the arid\, extra-dry desert] && !__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && __misc_state["in run"] && !have_alternate_uv_source && __quest_state["Level 11 Desert"].state_int["Desert Exploration"] < 99) - { - boolean have_uv_compass_equipped = __quest_state["Level 11 Desert"].state_boolean["Have UV-Compass eqipped"]; - - if (!have_uv_compass_equipped) - { - string title; - item compass_item = $item[UV-resistant compass]; - if ($item[ornate dowsing rod].available_amount() > 0) - compass_item = $item[ornate dowsing rod]; - - title = "Equip " + compass_item; - if (compass_item.available_amount() == 0) - title = "Find and equip " + compass_item; - task_entries.listAppend(ChecklistEntryMake("__item " + compass_item, "", ChecklistSubentryMake(title, "", "Explore more efficiently."), -11).ChecklistEntrySetIDTag("Desert UV-compass reminder")); - } - - } - if ($item[bottle of blank-out].available_amount() > 0 && $item[glob of blank-out].available_amount() == 0 && __misc_state["in run"] && __misc_state["free runs usable"] && !get_property_boolean("_blankoutUsed") && in_ronin()) - { - task_entries.listAppend(ChecklistEntryMake("__item " + $item[bottle of blank-out], "inventory.php?ftext=bottle+of+blank-out", ChecklistSubentryMake("Use " + $item[bottle of blank-out], "", "Acquire glob to run away with."), -11).ChecklistEntrySetIDTag("Blank-out bottle reminder")); - - } - if (__last_adventure_location == $location[the haunted ballroom] && $item[dance card].available_amount() > 0 && __misc_state["need to level"] && my_primestat() == $stat[moxie] && CounterLookup("Dance Card").CounterGetNextExactTurn() == -1) - { - string [int] description; - description.listAppend("Gives ~" + __misc_state_float["dance card average stats"].round() + " mainstat in four turns."); - if ($item[dance card].available_amount() > 1) - description.listAppend("Have " + $item[dance card].pluraliseWordy() + "."); - task_entries.listAppend(ChecklistEntryMake("__item " + $item[dance card], "inventory.php?ftext=dance+card", ChecklistSubentryMake("Use " + $item[dance card], "", description), -11).ChecklistEntrySetIDTag("Powerleveling dance card reminder")); - } - if (!__quest_state["Level 11 Hidden City"].finished && (__quest_state["Level 11 Hidden City"].state_boolean["Apartment finished"] || get_property_int("hiddenApartmentProgress") >= 7) && $effect[thrice-cursed].have_effect() > 0 && my_path().id != PATH_G_LOVER) - { - string curse_removal_method; - string url; - - if (__misc_state["VIP available"] && __misc_state_int["hot tub soaks remaining"] > 0) - { - curse_removal_method = "Relax in hot tub."; - url = "clan_viplounge.php"; - } - if ($skill[Shake It Off].skill_is_usable()) - { - curse_removal_method = "Cast shake it off."; - url = "skills.php"; - } - - if (curse_removal_method != "") - { - task_entries.listAppend(ChecklistEntryMake("__effect thrice-cursed", url, ChecklistSubentryMake("Remove Thrice-Cursed", "", curse_removal_method), -11).ChecklistEntrySetIDTag("Thrice-cursed reminder")); - } - } - - if (my_path().id == PATH_HEAVY_RAINS && my_familiar() != $familiar[none] && $slot[familiar].equipped_item() == $item[none]) - { - boolean [familiar] safely_underwater_familiars = $familiars[black cat,Barrrnacle,Emo Squid,Cuddlefish,Imitation Crab,Magic Dragonfish,Midget Clownfish,Rock Lobster,Urchin Urchin,Grouper Groupie,Squamous Gibberer,Dancing Frog,Adorable Space Buddy]; //cat can swim! - - if (!(safely_underwater_familiars contains my_familiar())) - { - //mafia has code to do this, but it doesn't always work - had it not equip on the blackbird once, another time after the L13 entryway - //plus they have to buy one anyways - string url = "familiar.php"; - string [int] description; - description.listAppend("Otherwise it'll (probably) be blocked."); - if ($item[miniature life preserver].available_amount() == 0) - { - description.listAppend("Buy from the general store."); - url = "shop.php?whichshop=generalstore"; - } - - task_entries.listAppend(ChecklistEntryMake("__item miniature life preserver", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Equip miniature life preserver", "red"), "", description), -11).ChecklistEntrySetIDTag("Heavy rains path life preserver reminder")); - } - } - - if (__last_adventure_location == $location[a maze of sewer tunnels] && $item[hobo code binder].equipped_amount() == 0 && haveAtLeastXOfItemEverywhere($item[hobo code binder], 1)) - { - task_entries.listAppend(ChecklistEntryMake("__item hobo code binder", "inventory.php?ftext=hobo+code+binder", ChecklistSubentryMake(HTMLGenerateSpanFont("Equip hobo code binder", "red"), "", "Speeds up sewer tunnel exploration."), -11).ChecklistEntrySetIDTag("Sewer maze hobo binder reminder")); - } - -} diff --git a/Source/relay/TourGuide/Sets/Sets import.ash b/Source/relay/TourGuide/Sets/Sets import.ash deleted file mode 100644 index 4affe372..00000000 --- a/Source/relay/TourGuide/Sets/Sets import.ash +++ /dev/null @@ -1,36 +0,0 @@ -import "relay/TourGuide/Support/Library.ash"; -import "relay/TourGuide/Sets/Lucky.ash"; -import "relay/TourGuide/Sets/Hole in the Sky.ash"; -import "relay/TourGuide/Sets/Familiars.ash"; -import "relay/TourGuide/Sets/Dispensary.ash"; -import "relay/TourGuide/Sets/Skills.ash"; -import "relay/TourGuide/Sets/Misc Items.ash"; -import "relay/TourGuide/Sets/Council.ash"; -import "relay/TourGuide/Sets/Copied Monsters.ash"; -import "relay/TourGuide/Sets/Pulverise.ash"; -import "relay/TourGuide/Sets/Aftercore.ash"; -import "relay/TourGuide/Sets/Daily Dungeon.ash"; -import "relay/TourGuide/Sets/Counters.ash"; -import "relay/TourGuide/Sets/Bounty Hunter Hunter.ash"; -import "relay/TourGuide/Sets/Old Level 9 quest.ash"; -import "relay/TourGuide/Sets/Fax.ash"; -import "relay/TourGuide/Sets/Dungeons of Doom.ash"; -import "relay/TourGuide/Sets/Olfaction.ash"; -import "relay/TourGuide/Sets/Holidays.ash"; -import "relay/TourGuide/Sets/Reminders.ash"; -import "relay/TourGuide/Sets/Events.ash"; -import "relay/TourGuide/Sets/Classes.ash"; -import "relay/TourGuide/Sets/Equipment.ash"; -import "relay/TourGuide/Sets/Calculate Universe.ash"; -import "relay/TourGuide/Sets/PVP.ash"; -import "relay/TourGuide/Sets/Demon Summon.ash"; -import "relay/TourGuide/Sets/Area Unlocks.ash"; -import "relay/TourGuide/Sets/Powerlevel.ash"; -import "relay/TourGuide/Sets/Florist.ash"; -import "relay/TourGuide/Sets/Misc Tasks.ash"; -import "relay/TourGuide/Sets/Sweet Synthesis.ash"; -import "relay/TourGuide/Sets/Buff Upkeep.ash"; -import "relay/TourGuide/Sets/Level 13 Door.ash"; -import "relay/TourGuide/Sets/Monorail.ash"; -import "relay/TourGuide/Sets/Sneaks.ash"; -import "relay/TourGuide/Sets/Active Banishes.ash"; diff --git a/Source/relay/TourGuide/Sets/Skills.ash b/Source/relay/TourGuide/Sets/Skills.ash deleted file mode 100644 index 9e687836..00000000 --- a/Source/relay/TourGuide/Sets/Skills.ash +++ /dev/null @@ -1,289 +0,0 @@ -string [int] SSkillsPotentialCraftingOptions() -{ - string [int] potential_options; - if ($item[knob cake].available_amount() == 0 && !__quest_state["Level 6"].finished && my_path().id != PATH_COMMUNITY_SERVICE) - potential_options.listAppend("knob cake"); - if (__misc_state["can eat just about anything"]) - potential_options.listAppend("food"); - if (__misc_state["can drink just about anything"]) - potential_options.listAppend("drink"); - if ($skill[advanced saucecrafting].skill_is_usable()) - potential_options.listAppend("sauceror potions"); - return potential_options; -} - -void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (skill_is_usable($skill[inigo's incantation of inspiration])) { - int inigos_casts_remaining = 5 - get_property_int("_inigosCasts"); - string description = SSkillsPotentialCraftingOptions().listJoinComponents(", ").capitaliseFirstLetter(); - if (inigos_casts_remaining > 0) - resource_entries.listAppend(ChecklistEntryMake("__effect Inigo's Incantation of Inspiration", "skills.php", ChecklistSubentryMake(pluralise(inigos_casts_remaining, "Inigo's cast", "Inigo's casts") + " remaining", "", description), 4).ChecklistEntrySetIDTag("Inigo inspiration skill reminder")); - } - if (true) { - ChecklistEntry craft_entry; - craft_entry.image_lookup_name = "__item tenderizing hammer"; - craft_entry.url = "craft.php?mode=discoveries"; - craft_entry.tags.id = "Free crafts resource"; - craft_entry.importance_level = 4; - - int free_crafts_left = 0; - int free_cooks_left = 0; - int free_mixes_left = 0; - if ($effect[Inigo's Incantation of Inspiration].have_effect() >= 5) { - free_crafts_left += $effect[Inigo's Incantation of Inspiration].have_effect() / 5; - } - if ($effect[craft tea].have_effect() >= 5) { - free_crafts_left += $effect[craft tea].have_effect() / 5; - } - if ($skill[rapid prototyping].skill_is_usable()) { - free_crafts_left += clampi(5 - get_property_int("_rapidPrototypingUsed"), 0, 5); - } - if (lookupSkill("Expert Corner-Cutter").skill_is_usable()) { - free_crafts_left += clampi(5 - get_property_int("_expertCornerCutterUsed"), 0, 5); - } - if (get_property_int("homebodylCharges") > 0) { - free_crafts_left += (get_property_int("homebodylCharges")); - } - // adding cookbookbat free crafts into crafting tile - if (lookupFamiliar("Cookbookbat").familiar_is_usable()) { - string [int] description; - free_cooks_left += clampi(5 - get_property_int("_cookbookbatCrafting"), 0, 5); - string title = "free cooking"; - if (free_cooks_left > 0) { - craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_cooks_left, title, title + "s") + " remaining", free_crafts_left > 0 ? "COOKING only" : "", description)); - } - } - // holiday multitasking - if (lookupSkill("Holiday Multitasking").skill_is_usable()) { - free_crafts_left += clampi(3 - get_property_int("_holidayMultitaskingUsed"), 0, 3); - } - // elf guard cooking - if (lookupSkill("Elf Guard Cooking").skill_is_usable()) { - string [int] description; - free_cooks_left += clampi(3 - get_property_int("_elfGuardCookingUsed"), 0, 3); - string title = "free cooking"; - if (free_cooks_left > 0) { - craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_cooks_left, title, title + "s") + " remaining", free_crafts_left > 0 ? "COOKING only" : "", description)); - } - } - // cocktails of the age of sail - if (lookupSkill("Old-School Cocktailcrafting").skill_is_usable()) { - string [int] description; - free_mixes_left += clampi(3 - get_property_int("_oldSchoolCocktailCraftingUsed"), 0, 3); - string title = "free mixing"; - if (free_mixes_left > 0) { - craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_mixes_left, title, title + "s") + " remaining", free_crafts_left > 0 ? "MIXING only" : "", description)); - } - } - - int free_smiths_left = 0; - if (__campground[$item[warbear auto-anvil]] > 0) { - free_smiths_left += clampi(5 - get_property_int("_warbearAutoAnvilCrafting"), 0, 5); - } - int jackhammer_crafts_later = 0; - if ($items[Loathing Legion abacus,Loathing Legion can opener,Loathing Legion chainsaw,Loathing Legion corkscrew,Loathing Legion defibrillator,Loathing Legion double prism,Loathing Legion electric knife,Loathing Legion flamethrower,Loathing Legion hammer,Loathing Legion helicopter,Loathing Legion jackhammer,Loathing Legion kitchen sink,Loathing Legion knife,Loathing Legion many-purpose hook,Loathing Legion moondial,Loathing Legion necktie,Loathing Legion pizza stone,Loathing Legion rollerblades,Loathing Legion tape measure,Loathing Legion tattoo needle,Loathing Legion universal screwdriver,Loathing Legion Knife].available_amount() > 0) { - int jackhammer_crafts = clampi(3 - get_property_int("_legionJackhammerCrafting"), 0, 3); - if ($item[Loathing Legion jackhammer].available_amount() == 0) - jackhammer_crafts_later = jackhammer_crafts; - else - free_smiths_left += jackhammer_crafts; - } - if ($item[Thor's Pliers].available_amount() > 0) { - free_smiths_left += clampi(10 - get_property_int("_thorsPliersCrafting"), 0, 10); - } - if (free_smiths_left > 0 || jackhammer_crafts_later > 0) { - craft_entry.url = "craft.php?mode=discoveries&what=smith"; - //free_smiths_left += free_crafts_left; //naaaah - //FIXME remind them to buy a hammer (if no loathing jackhammer) - string [int] description; - if (jackhammer_crafts_later > 0) - description.listAppend("Get " + jackhammer_crafts_later + " more by folding your loathing legion knife into jackhammer."); - string title = "free smithing"; - if (knoll_available()) //innabox makes normal smithing free - title = "free advanced smithing"; - craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_smiths_left, title, title + "s") + " remaining", free_crafts_left > 0 ? "SMITHING only" : "", description)); - } - - if (free_crafts_left > 0) { - string description = SSkillsPotentialCraftingOptions().listJoinComponents(", ").capitaliseFirstLetter(); - craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_crafts_left, "free craft", "free crafts") + " remaining", free_smiths_left > 0 || jackhammer_crafts_later > 0 ? "Any crafting mode, including smithing" : "", description)); - } - - if (craft_entry.subentries.count() > 0) - resource_entries.listAppend(craft_entry); - } - - ChecklistSubentry [int] subentries; - int importance = 11; - string url; - - string [skill] skills_to_details; - string [skill] skills_to_urls; - string [skill] skills_to_title_notes; - skill [string][int] property_summons_to_skills; - int [string] property_summon_limits; - - property_summon_limits["reagentSummons"] = 1; - property_summon_limits["noodleSummons"] = 1; - property_summon_limits["cocktailSummons"] = 1; - property_summon_limits["grimoire1Summons"] = 1; - property_summon_limits["grimoire2Summons"] = 1; - property_summon_limits["grimoire3Summons"] = 1; - property_summon_limits["_grimoireGeekySummons"] = 1; - property_summon_limits["_grimoireConfiscatorSummons"] = 1; - property_summon_limits["_candySummons"] = 1; - - if ($skill[advanced saucecrafting].have_skill() && $skill[advanced saucecrafting].skill_is_usable()) - property_summons_to_skills["reagentSummons"] = listMake($skill[advanced saucecrafting], $skill[the way of sauce]); - if ($skill[Pastamastery].have_skill() && $skill[Pastamastery].skill_is_usable()) - property_summons_to_skills["noodleSummons"] = listMake($skill[Pastamastery], $skill[Transcendental Noodlecraft]); - if ($skill[Advanced Cocktailcrafting].have_skill() && $skill[Advanced Cocktailcrafting].skill_is_usable()) - property_summons_to_skills["cocktailSummons"] = listMake($skill[Advanced Cocktailcrafting], $skill[Superhuman Cocktailcrafting]); - property_summons_to_skills["_coldOne"] = listMake($skill[Grab a Cold One]); - property_summons_to_skills["_spaghettiBreakfast"] = listMake($skill[spaghetti breakfast]); - property_summons_to_skills["_discoKnife"] = listMake($skill[that's not a knife]); - property_summons_to_skills["_lunchBreak"] = listMake($skill[lunch break]); - property_summons_to_skills["_psychokineticHugUsed"] = listMake($skill[Psychokinetic Hug]); - property_summons_to_skills["_pirateBellowUsed"] = listMake($skill[Pirate Bellow]); - property_summons_to_skills["_holidayFunUsed"] = listMake($skill[Summon Holiday Fun!]); - property_summons_to_skills["_summonCarrotUsed"] = listMake($skill[Summon Carrot]); - property_summons_to_skills["_summonAnnoyanceUsed"] = listMake($skill[summon annoyance]); - property_summons_to_skills["_perfectFreezeUsed"] = listMake($skill[Perfect Freeze]); - property_summons_to_skills["_communismUsed"] = listMake($skill[Communism!]); - property_summons_to_skills["_preventScurvy"] = listMake(lookupSkill("Prevent Scurvy and Sobriety")); - - skills_to_title_notes[$skill[summon annoyance]] = get_property_int("summonAnnoyanceCost") + " swagger"; - - - - - - if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) { - property_summons_to_skills["_petePartyThrown"] = listMake($skill[Throw Party]); - property_summons_to_skills["_peteRiotIncited"] = listMake($skill[Incite Riot]); - - int audience_max = 30; - int hate_useful_max = 25; //ashes and soda max out early; more audience hatred only gives crates and grenades, not of absolute importance - if ($item[Sneaky Pete's leather jacket].equipped_amount() > 0 || $item[Sneaky Pete's leather jacket (collar popped)].equipped_amount() > 0) { - audience_max = 50; - hate_useful_max = 41; - } - - if (my_audience() < audience_max) - skills_to_details[$skill[Throw Party]] = "Ideally have " + audience_max + " audience love before casting."; - else - skills_to_details[$skill[Throw Party]] = "Gain party supplies."; - - if (my_audience() > -hate_useful_max) - skills_to_details[$skill[Incite Riot]] = "Ideally have " + hate_useful_max + " audience hate before casting."; - else - skills_to_details[$skill[Incite Riot]] = "This fire is out of control"; - } - if (my_path().id == PATH_AVATAR_OF_JARLSBERG) { - property_summons_to_skills["_jarlsCreamSummoned"] = listMake($skill[Conjure Cream]); - property_summons_to_skills["_jarlsEggsSummoned"] = listMake($skill[Conjure Eggs]); - property_summons_to_skills["_jarlsDoughSummoned"] = listMake($skill[Conjure Dough]); - property_summons_to_skills["_jarlsVeggiesSummoned"] = listMake($skill[Conjure Vegetables]); - property_summons_to_skills["_jarlsCheeseSummoned"] = listMake($skill[Conjure Cheese]); - property_summons_to_skills["_jarlsPotatoSummoned"] = listMake($skill[Conjure Potato]); - property_summons_to_skills["_jarlsMeatSummoned"] = listMake($skill[Conjure Meat Product]); - property_summons_to_skills["_jarlsFruitSummoned"] = listMake($skill[Conjure Fruit]); - } - if (my_path().id == PATH_AVATAR_OF_BORIS) { - property_summons_to_skills["_demandSandwich"] = listMake($skill[Demand Sandwich]); - property_summon_limits["_demandSandwich"] = 3; - } - - property_summons_to_skills["_requestSandwichSucceeded"] = listMake($skill[Request Sandwich]); - - property_summons_to_skills["grimoire1Summons"] = listMake($skill[Summon Hilarious Objects]); - property_summons_to_skills["grimoire2Summons"] = listMake($skill[Summon Tasteful Items]); - property_summons_to_skills["grimoire3Summons"] = listMake($skill[Summon Alice's Army Cards]); - property_summons_to_skills["_grimoireGeekySummons"] = listMake($skill[Summon Geeky Gifts]); - if (mafiaIsPastRevision(14300)) { - property_summons_to_skills["_grimoireConfiscatorSummons"] = listMake($skill[Summon Confiscated Things]); - skills_to_urls[$skill[Summon Confiscated Things]] = "campground.php?action=bookshelf"; - } - property_summons_to_skills["_candySummons"] = listMake($skill[Summon Crimbo Candy]); - property_summons_to_skills["_summonResortPassesUsed"] = listMake($skill[Summon Kokomo Resort Pass]); - property_summons_to_skills["_incredibleSelfEsteemCast"] = listMake(lookupSkill("Incredible Self-Esteem")); - skills_to_details[lookupSkill("Incredible Self-Esteem")] = "Gives or extends affirmation buffs."; - if (__misc_state["in run"] && lookupItem("Daily Affirmation: Always be Collecting").available_amount() > 0 && lookupItem("Daily Affirmation: Always be Collecting").to_effect().have_effect() == 0) - skills_to_details[lookupSkill("Incredible Self-Esteem")] += "|Possibly use Always be Collecting affirmation before casting."; - - foreach s in $skills[Summon Hilarious Objects,Summon Tasteful Items,Summon Alice's Army Cards,Summon Geeky Gifts] - skills_to_urls[s] = "campground.php?action=bookshelf"; - - - - int muscle_basestat = my_basestat($stat[muscle]); - item summoned_knife = $item[none]; - if (muscle_basestat < 10) - summoned_knife = $item[boot knife]; - else if (muscle_basestat < 20) - summoned_knife = $item[broken beer bottle]; - else if (muscle_basestat < 40) - summoned_knife = $item[sharpened spoon]; - else if (muscle_basestat < 60) - summoned_knife = $item[candy knife]; - else - summoned_knife = $item[soap knife]; - if (summoned_knife.available_amount() > 0 && summoned_knife != $item[none]) { - //already have the knife, don't annoy them: - //(or ask them to closet the knife?) - remove property_summons_to_skills["_discoKnife"]; - //skills_to_details[$skill[that's not a knife]] = "Closet " + summoned_knife + " first."; - } - - foreach property in property_summons_to_skills { - if (property_summon_limits[property] != 0 && get_property_int(property) >= property_summon_limits[property] || get_property_boolean(property)) - continue; - foreach key in property_summons_to_skills[property] { - skill s = property_summons_to_skills[property][key]; - if (!s.skill_is_usable()) - continue; - - string line = s.to_string(); - string [int] description; - if (s.mp_cost() > 0) { - line += " (" + s.mp_cost() + " MP)"; - //description.listAppend(s.mp_cost() + " MP"); - } - if (skills_to_title_notes contains s) { - line += " (" + skills_to_title_notes[s] + " )"; - } - string details = skills_to_details[s]; - if (details != "") - description.listAppend(details); - - - if (url.length() == 0) { - if (skills_to_urls contains s) - url = skills_to_urls[s]; - else - url = "skills.php"; - } - - subentries.listAppend(ChecklistSubentryMake(line, "", description)); - break; - } - } - - if (subentries.count() > 0) { - subentries.listPrepend(ChecklistSubentryMake("Skill summons:")); - ChecklistEntry entry = ChecklistEntryMake("__item Knob Goblin love potion", url, subentries, importance); - entry.tags.id = "Daily summon skills resource"; - entry.should_indent_after_first_subentry = true; - resource_entries.listAppend(entry); - } - - - if (lookupSkill("Evoke Eldritch Horror").skill_is_usable() && !get_property_boolean("_eldritchHorrorEvoked")) { - resource_entries.listAppend(ChecklistEntryMake("__skill Evoke Eldritch Horror", "skillz.php", ChecklistSubentryMake("Evoke Eldritch Horror", "", "Free fight."), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Evoke eldritch horror skill free fight")); - } - if (!get_property_boolean("_eldritchTentacleFought") && my_path().id != PATH_EXPLOSIONS && my_path().id != PATH_COMMUNITY_SERVICE) { - resource_entries.listAppend(ChecklistEntryMake("__skill Evoke Eldritch Horror", "place.php?whichplace=forestvillage&action=fv_scientist", ChecklistSubentryMake("Science Tent Tentacle", "", "Free fight."), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Daily forest tentacle free fight")); - } - -} diff --git a/Source/relay/TourGuide/Sets/Sneaks.ash b/Source/relay/TourGuide/Sets/Sneaks.ash deleted file mode 100644 index ff807e79..00000000 --- a/Source/relay/TourGuide/Sets/Sneaks.ash +++ /dev/null @@ -1,395 +0,0 @@ -// STEPS TO HAVE NC FORCERS IN TILES -// This will require quite a few things. In order: -// - we will need to have a way for tourguide to tell that you have an NC forcer up for supernag -// - we will need to have a tile that shows good NCs to force -// - we will need to append NC forcers available to this - -// SYNTAX FOR NEW NC FORCERS -// In order to centralize, all NC forcers that were old were placed in this file. They utilize a -// new record type that should make it mildly easier to loop through the lot. - - record SneakSource { - string sourceName; - string url; - string imageLookupName; - boolean sneakCondition; - int sneakCount; - string tileDescription; - }; - -RegisterResourceGenerationFunction("SocialDistanceGenerator"); -void SocialDistanceGenerator(ChecklistEntry [int] resource_entries) -{ - // Saving some useful variables for use in the calculations. - int spleenRemaining = spleen_limit() - my_spleen_use(); - int stomachLeft = availableFullness(); - - SneakSource getSneakisol() { - SneakSource final; - - final.sourceName = "sneakisol"; - final.url = "main.php?eowkeeper=1"; - final.imageLookupName = "__item Eight Days a Week Pill Keeper"; - - // see # of free pillkeeepers remaining - int freeSneakLeft = get_property_boolean("_freePillKeeperUsed") ? 0 : 1; - - // calculate possible spleen-based sneaks - int spleenSneaks = floor(spleenRemaining / 3); - - // usable if we have pill keeper plus free sneaks or spleen sneaks available - final.sneakCondition = __iotms_usable[lookupItem("Eight Days a Week Pill Keeper")] && (freeSneakLeft + spleenSneaks > 0); - - // never noticed I didn't explicitly say this was pillkeeper in the tile lol - final.sneakCount = freeSneakLeft + spleenSneaks; - final.tileDescription = get_property_boolean("_freePillKeeperUsed") ? "" : `1x PillKeeper free sneak, `; - final.tileDescription = final.tileDescription + `{spleenSneaks}x sneaks for 3 spleen each`; - return final; - } - - SneakSource getStenchJellies() { - SneakSource final; - - final.sourceName = "stench jelly"; - final.url = ""; - final.imageLookupName = "__familiar space jellyfish"; - - // You can get more than 3 in a run, but 3 is a good fairway estimate. - int likelyJellies = 3; - - // Check if the familiar is usable & you have jellies in your inventory - boolean canUseJellyfish = $familiar[space jellyfish].familiar_is_usable(); - int jellyCount = $item[stench jelly].available_amount(); - int toastCount = $item[toast with stench jelly].available_amount(); - - // Check that you don't have full organs - int numberOfJelliesConsumable = min(stomachLeft + spleenRemaining, jellyCount + toastCount); - - // Compare current extractions to the likelyJellies variable - int currentExtractions = get_property_int("_spaceJellyfishDrops"); - int plausibleJellies = max(currentExtractions - likelyJellies, numberOfJelliesConsumable); - - // This is an or because it's possible to pull a stench jelly - final.sneakCondition = canUseJellyfish || plausibleJellies > 0; - - // Use plauisible jellies here, to make sure it's added if it's possible - final.sneakCount = plausibleJellies; - final.tileDescription = `{plausibleJellies}x stench jellies (have {clampi(toastCount,0,15)} on toast, {clampi(jellyCount,0,15)} as jelly)`; - return final; - } - - SneakSource getSpikos() { - SneakSource final; - - final.sourceName = 'spikolodon spikes'; - final.url = 'inventory.php?action=jparka'; - final.imageLookupName = "__item jurassic parka"; - - int spikosLeft = clampi(5 - get_property_int("_spikolodonSpikeUses"), 0, 5); - - final.sneakCondition = __iotms_usable[$item[Jurassic Parka]]; - final.sneakCount = spikosLeft; - final.tileDescription = `{spikosLeft}x spikolodon spikes left`; - return final; - - } - - SneakSource getClaras() { - SneakSource final; - - final.sourceName = `clara's bell`; - final.url = ''; - final.imageLookupName = "__item clara's bell"; - - final.sneakCondition = $item[clara's bell].available_amount() > 0 && !get_property_boolean("_claraBellUsed"); - final.sneakCount = get_property_boolean("_claraBellUsed") ? 0 : 1; - final.tileDescription = `{final.sneakCount}x clara's bell charge left`; - - return final; - } - - SneakSource getCinchos() { - SneakSource final; - - final.sourceName = `fiesta exits`; - final.url = ''; - final.imageLookupName = "__skill Cincho: Fiesta Exit"; - final.sneakCondition = __iotms_usable[$item[Cincho de Mayo]]; - - // _cinchUsed is a weird preference that actually means distance from 100% you are at in your current cinch. - - int freeRests = __misc_state_int["total free rests possible"]; - int cinchoRests = get_property_int('_cinchoRests'); - int cinchUsed = get_property_int('_cinchUsed'); - - // Resting when Cincho is full might burn some of the Cincho rests - int freeRestsRemaining = __misc_state_int["free rests remaining"]; - freeRests = min(freeRests, cinchoRests + freeRestsRemaining); - - // Calculating total available cinch - - int [int] cinchLevels = listMake(30,30,30,30,30,25,20,15,10,5); - - // Since the pref is weird, this tells you your current total cinch - int totalCinch = 100 - cinchUsed; - int rest = cinchoRests; - - // This while loop expands your possible cinch starting at rests you haven't used. - while (rest < freeRests) - { - int cinchAmount = rest >= count(cinchLevels) ? 5 : cinchLevels[rest]; - totalCinch += cinchAmount; - rest += 1; - } - - int possibleFiestaExits = floor(totalCinch/60); - - final.sneakCount = possibleFiestaExits; - final.tileDescription = `{possibleFiestaExits}x fiesta exits, with {totalCinch % 60} leftover cinch`; - return final; - } - - // Having generated these, we now get to generate a tile that combines them. - - SneakSource [string] sneakSources; - - sneakSources["cinco"] = getCinchos(); - sneakSources["spiko"] = getSpikos(); - sneakSources["jello"] = getStenchJellies(); - sneakSources["pillo"] = getSneakisol(); - sneakSources["claro"] = getClaras(); - - // Making it use the order we want; almost most recent to oldest, but pills on the bottom. - string [int] sneakOrder = listMake("cinco","spiko","jello","claro","pillo"); - - ChecklistEntry entry; - - entry.url = ""; - entry.image_lookup_name = "__effect Feeling Sneaky"; - entry.tags.id = "Sneak sources available"; - entry.importance_level = -2; - - string [int] description; - int totalSneaks = 0; - - string line = HTMLGenerateSpanOfClass("Force an NC with sneaky tricks!", "r_bold r_element_stench_desaturated"); - - foreach it, sneakType in sneakOrder - { - SneakSource sneaker = sneakSources[sneakType]; - if (sneaker.sneakCount > 0 && sneaker.sneakCondition) { - totalSneaks += sneaker.sneakCount; - entry.url = sneaker.url; - - line += "|*"+sneaker.tileDescription; - } - - } - - if (totalSneaks == 0) return; - - // Append all the lines to a description - description.listAppend(line); - - // Store the base description within the mouseover subentries - entry.subentries_on_mouse_over.listAppend(ChecklistSubentryMake(pluralise(totalSneaks, "sneak usable", "sneaks usable"), "", description)); - - // Add a description that falls away when you hoverover - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(totalSneaks, "sneak usable", "sneaks usable"), "", description)); - - // OK, now we're going to make a big table with the NC recommendations. Yeesh. - // This tile is complicated, dude! First, start by initializing variables. - // Ezan's table creators are formatted as string[int][int], where the first - // is the row and the second is the column... I think? - - int totalNCsRemaining = 0; - string [int][int] table; - - // In the synth tile, Ezan populates table_lines and builds out from there. I - // am doing the same because I don't fully understand the syntax. - string [int] tableLines; - - // This is a function that generates the right format for the table. Basically, - // it ingests the table title + a separated list of all sneak opportunities in - // that summarized title. - string populateSneakTable(string title, string [int] desc) { - string finalDesc = ""; - - // If nothing got added, just add an "all done!" to make the user feel better - if (desc.count() == 0) finalDesc = "All done!"; - - // Have to add line breaks here. - foreach k, d in desc { - finalDesc += d+"
"; - } - - // Finally, generate a little sub-tile that looks like this: - - // NAME OF SNEAKS - // 1 sneaksource - // 1 sneaksource - - // Where the name is bold and the sneaksources are tiny. In some future world, - // it might be nice to have coloring that grays those that are not available - // yet, but that is too much for this first implementation. - return HTMLGenerateSpanOfClass(title, "r_bold") + "
" + HTMLGenerateSpanOfStyle(finalDesc, "font-size:0.8em"); - } - - // We aren't going to do a loop here; we're just going to populate table_lines - // semi-manually, using logic that is roughly correct in each case. - - // START = DELAY SNEAKS - // 1x hidden apartment - // 1x hidden office - - // Initialize your string-int array of the sneaks. - string [int] sneakDelay; - - // You want to use prefs when possible to isolate that the user can use that sneak, then append to sneakDelay - if (get_property_int("hiddenApartmentProgress") < 7) sneakDelay.listAppend("1 hidden apartment"); - if (get_property_int("hiddenOfficeProgress") < 7) sneakDelay.listAppend("1 hidden office"); - - // Populate the sneaky table. - tableLines[1] = populateSneakTable("Delay Zones", sneakDelay); - - // Add the detected NCs to your total NCs remaining. - totalNCsRemaining += sneakDelay.count(); - - // NEXT = 95% COMBAT SNEAKS - // 12x friars NCs (-1 w/ carto) - // 1x castle basement - // 1x castle top - - string [int] sneak95; - - // Ripping some code from the friars tile to count NCs encountered. First, names of the relevant NCs. - boolean [string] necks_known_ncs = $strings[How Do We Do It? Quaint and Curious Volume!,Strike One!,Olive My Love To You\, Oh.,Dodecahedrariffic!]; - boolean [string] heart_known_ncs = $strings[Moon Over the Dark Heart,Running the Lode,I\, Martin,Imp Be Nimble\, Imp Be Quick]; - boolean [string] elbow_known_ncs = $strings[Deep Imp Act,Imp Art\, Some Wisdom,A Secret\, But Not the Secret You're Looking For,Butter Knife? I'll Take the Knife]; - - // Then, a tiny function to count the NCs found by zone for friars. - int countFriarNCs(boolean [string] known_ncs, location place) { - int ncs_found = 0; - - if (known_ncs.count() > 0) { - string [int] location_ncs = place.locationSeenNoncombats(); - - foreach key, s in location_ncs - { - if (known_ncs contains s) ncs_found += 1; - } - } - - return ncs_found; - - } - - // You can remove one from the needed NCs if they have carto in their run. - int cartoAdjustment = lookupSkill("Comprehensive Cartography").have_skill() ? 1 : 0; - - // Right now I think the raw logic off; I noted in the discord that we are having some small issues with - // it showing extra NCs in a few places. Not really sure what's up with that? An easy fix is to - // just set all of these to 0 in the event that questL06Friar = 'finished' -- I've implemented - // this fix, but I do think it's worth solving this at some point. - - int questPropMin = get_property('questL06Friar') == 'finished' ? 0 : 4; - - int necksNCsLeft = min(4 - countFriarNCs(necks_known_ncs, $location[The Dark Neck of the Woods]) - cartoAdjustment, questPropMin); - int heartNCsLeft = min(4 - countFriarNCs(heart_known_ncs, $location[The Dark Heart of the Woods]), questPropMin); - int elbowNCsLeft = min(4 - countFriarNCs(elbow_known_ncs, $location[The Dark Elbow of the Woods]), questPropMin); - - // Also correcting total NCs left here; we are using a "count" for this, and thus we only get 1 - // out of however many NCs actually are left in these zones, because it just counts the elements - // in the list rather than the # prepending the element in the list. - if (necksNCsLeft > 0) { - sneak95.listAppend(`{necksNCsLeft} Dark Neck`); - totalNCsRemaining += necksNCsLeft-1; - } - if (heartNCsLeft > 0) { - sneak95.listAppend(`{heartNCsLeft} Dark Heart`); - totalNCsRemaining += heartNCsLeft-1; - } - if (elbowNCsLeft > 0) { - sneak95.listAppend(`{elbowNCsLeft} Dark Elbow`); - totalNCsRemaining += elbowNCsLeft-1; - } - - // If the pref is any of these, you can still sneak the basement. - boolean [string] canSneakBasement = $strings[unstarted,started,step1,step2,step3,step4,step5,step6,step7]; - - if (canSneakBasement contains get_property("questL10Garbage")) sneak95.listAppend("1 castle basement"); - - // If the quest is unfinished, you can sneak the top floor. - if (get_property("questL10Garbage")!= "finished") sneak95.listAppend("1 castle top floor"); - - tableLines[2] = populateSneakTable("95% Combat", sneak95); - - totalNCsRemaining += sneak95.count(); - - // NEXT = 90% COMBAT SNEAKS - // 1x spookyraven bedroom - // 1x spookyraven bathroom - - string [int] sneak90; - - // I don't really think I need to import this but I'm tired and copy/pasting logic from the spookyraven tile seems fine. - QuestState dance_quest_state; - QuestStateParseMafiaQuestProperty(dance_quest_state, "questM21Dance"); - if ($item[Lady Spookyraven's powder puff].available_amount() == 0 && dance_quest_state.mafia_internal_step < 4) sneak90.listAppend("1 spookyraven bathroom"); - if ($item[Lady Spookyraven's dancing shoes].available_amount() == 0 && dance_quest_state.mafia_internal_step < 4) sneak90.listAppend("1 spookyraven gallery"); - - tableLines[3] = populateSneakTable("90% Combat", sneak90); - - totalNCsRemaining += sneak90.count(); - - // Here is how Ezan built the lines into a table. It's kind of cute. First, make a placeholder "builder" line. - string [int] building_line; - foreach key in tableLines - { - // For each key, you append it to the empty building lines. - building_line.listAppend(tableLines[key]); - - // However, if the key is even, you append to the table. This works, because you are appending a two-element - // item into the table, so it creates a string [int] that creates a row in the table. - if (key % 2 == 1) - { - table.listAppend(building_line); - - // Then, you clear out the building line, to reset the next table row - building_line = listMakeBlankString(); - } - } - // Then, at the end, you append the remainder to the table. - if (building_line.count() > 0) - table.listAppend(building_line); - - // Having done this, you now append the NCs remaining subentry to the end of the core entry, with an on_mouse_over bit as well. - - // However, I am going to be lazy, and not append either of these in the event the user is in CS/GG. - if (my_path().id != PATH_COMMUNITY_SERVICE && my_path().id != PATH_GREY_GOO) { - entry.subentries.listAppend(ChecklistSubentryMake(pluralise(totalNCsRemaining, "NC remaining","NCs remaining"), "", HTMLGenerateSpanOfClass("Mouse over for the best sneaks!", "r_bold r_element_spooky_desaturated"))); - entry.subentries_on_mouse_over.listAppend(ChecklistSubentryMake(pluralise(totalNCsRemaining, "NC remaining","NCs remaining"), "", table.HTMLGenerateSimpleTableLines(false))); - } - - if (entry.subentries.count() > 0) resource_entries.listAppend(entry); - -} - -RegisterTaskGenerationFunction("SneakActiveTask"); -void SneakActiveTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - // Use the new preference to tell if there's an NC forcer active - if (!get_property_boolean("noncombatForcerActive")) return; - - // If you are forcing an NC, build the reminder - ChecklistEntry entry; - - entry.url = ""; - entry.image_lookup_name = "__effect Feeling Sneaky"; - entry.tags.id = "Active sneak reminder"; - entry.importance_level = -11; - - entry.subentries.listAppend(ChecklistSubentryMake("Noncombat up next","","You're feeling sneaky; a noncombat will occur in the next zone where an NC is available. Don't waste it!")); - - task_entries.listAppend(entry); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Sets/Sweet Synthesis.ash b/Source/relay/TourGuide/Sets/Sweet Synthesis.ash deleted file mode 100644 index 5e4c8e13..00000000 --- a/Source/relay/TourGuide/Sets/Sweet Synthesis.ash +++ /dev/null @@ -1,320 +0,0 @@ - -static -{ - boolean [item] __simple_candy = $items[1702, 1962, 4341, 913, 1652, 2942, 3455, 3449, 3454, 3453, 3452, 3451, 4152, 1501, 5455, 5478, 5476, 5477, 1344, 5188, 4340, 1161, 912, 4342, 5454, 2941, 1346, 4192, 1494, 5456, 617, 3496, 2734, 933, 908, 3450, 1783, 2088, 2576, 907, 1767, 906, 911, 540, 263, 909, 905, 5180, 2309, 300, 2307, 298, 1163, 2306, 299, 2305, 297, 2304, 2308, 5892, 6792, 5435, 7677, 7785]; - boolean [item] __complex_candy = lookupItems("5495,5496,5494,5458,5421,4851,2197,1382,4334,4333,5424,3269,5422,921,5425,5423,3091,2955,5416,5419,5418,5417,5420,5381,5319,5400,4330,4332,5406,5405,4818,5402,5318,5384,4331,5320,5382,5398,5401,5397,5317,5385,5321,5383,3290,3760,2193,5413,5459,5483,3584,5395,5396,5482,4256,5484,2943,4329,3054,4758,4163,4466,4464,4465,4462,4467,4463,4623,5157,4395,4394,4393,4518,5189,4151,5023,3428,3423,3424,5457,3425,5480,5474,5479,5473,5481,5475,4164,3631,4853,5414,5415,3046,5345,1345,5103,2220,4746,4389,3125,4744,4273,3422,1999,3426,4181,4180,4176,4183,4179,4191,4182,4178,4745,5526,6835,6852,6833,6834,6836,7499,7915,8257,7914,6837,8151,3124,8149,8154,7919,6840,5736,6831,7917,8150,6404,6841,6904,6903,7918,7710,6399,9146,8537,6405,6843,7474,6172,9252,5913];"); -} - - - -int synthesis_price(item it) -{ - if (!it.tradeable) - return 999999999; - int price = it.historical_price(); - if (price <= 0) - return 999999999; - return price; -} - -Record CandyCombination -{ - item candy_1; - item candy_2; -}; - -CandyCombination CandyCombinationMake(item candy_1, item candy_2) -{ - CandyCombination cc; - cc.candy_1 = candy_1; - cc.candy_2 = candy_2; - return cc; -} - -static -{ - CandyCombination [int][int][int] __candy_combination_cache; -} - -CandyCombination [int] calculateSweetSynthesisCandyCombinations(int tier, int subid) -{ - if (__candy_combination_cache[tier][subid].count() > 0) - return __candy_combination_cache[tier][subid]; - - CandyCombination [int] result; - boolean [item] candy_1; - boolean [item] candy_2; - - if (tier == 1) - { - candy_1 = __simple_candy; - candy_2 = __simple_candy; - } - else if (tier == 2) - { - candy_1 = __simple_candy; - candy_2 = __complex_candy; - } - else if (tier == 3) - { - candy_1 = __complex_candy; - candy_2 = __complex_candy; - } - foreach item_1 in candy_1 - { - int item_1_id = item_1.to_int(); - - foreach item_2 in candy_2 - { - int item_2_id = item_2.to_int(); - if ((item_1_id + item_2_id) % 5 != (subid - 1)) - continue; - result[result.count()] = CandyCombinationMake(item_1, item_2); - } - } - sort result by (value.candy_1.synthesis_price() + value.candy_2.synthesis_price()); - __candy_combination_cache[tier][subid] = result; - return result; -} - -static -{ - string [effect] __sweet_synthesis_buff_descriptions; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Hot]] = "+9 hot res"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Cold]] = "+9 cold res"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Pungent]] = "+9 stench res"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Scary]] = "+9 spooky res"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Greasy]] = "+9 sleaze res"; - - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Strong]] = "+300% muscle"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Smart]] = "+300% myst"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Cool]] = "+300% moxie"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Hardy]] = "+300% max HP"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Energy]] = "+300% max MP"; - - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Greed]] = "+300% meat"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Collection]] = "+150% item"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Movement]] = "+50% muscle gain"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Learning]] = "+50% myst gain"; - __sweet_synthesis_buff_descriptions[$effect[Synthesis: Style]] = "+50% moxie gain"; - - int [effect] __sweet_synthesis_buff_tiers; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Hot]] = 1; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Cold]] = 1; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Pungent]] = 1; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Scary]] = 1; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Greasy]] = 1; - - __sweet_synthesis_buff_tiers[$effect[Synthesis: Strong]] = 2; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Smart]] = 2; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Cool]] = 2; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Hardy]] = 2; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Energy]] = 2; - - __sweet_synthesis_buff_tiers[$effect[Synthesis: Greed]] = 3; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Collection]] = 3; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Movement]] = 3; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Learning]] = 3; - __sweet_synthesis_buff_tiers[$effect[Synthesis: Style]] = 3; - - int [effect] __sweet_synthesis_buff_subid; - __sweet_synthesis_buff_subid[$effect[Synthesis: Hot]] = 1; - __sweet_synthesis_buff_subid[$effect[Synthesis: Cold]] = 2; - __sweet_synthesis_buff_subid[$effect[Synthesis: Pungent]] = 3; - __sweet_synthesis_buff_subid[$effect[Synthesis: Scary]] = 4; - __sweet_synthesis_buff_subid[$effect[Synthesis: Greasy]] = 5; - - __sweet_synthesis_buff_subid[$effect[Synthesis: Strong]] = 1; - __sweet_synthesis_buff_subid[$effect[Synthesis: Smart]] = 2; - __sweet_synthesis_buff_subid[$effect[Synthesis: Cool]] = 3; - __sweet_synthesis_buff_subid[$effect[Synthesis: Hardy]] = 4; - __sweet_synthesis_buff_subid[$effect[Synthesis: Energy]] = 5; - - __sweet_synthesis_buff_subid[$effect[Synthesis: Greed]] = 1; - __sweet_synthesis_buff_subid[$effect[Synthesis: Collection]] = 2; - __sweet_synthesis_buff_subid[$effect[Synthesis: Movement]] = 3; - __sweet_synthesis_buff_subid[$effect[Synthesis: Learning]] = 4; - __sweet_synthesis_buff_subid[$effect[Synthesis: Style]] = 5; - - effect [int] __sweet_synthesis_buff_output_order; - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Greed]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Collection]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Movement]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Learning]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Style]); - - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Strong]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Smart]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Cool]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Hardy]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Energy]); - - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Hot]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Cold]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Pungent]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Scary]); - __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Greasy]); -} - -RegisterResourceGenerationFunction("SSweetSynthesisGenerateResource"); -void SSweetSynthesisGenerateResource(ChecklistEntry [int] resource_entries) -{ - if (!$skill[Sweet Synthesis].skill_is_usable()) - return; - if (availableSpleen() == 0) - return; - - //Calculate potential combinations from inventory, if we're in-run. - //If we're in aftercore, suggest a cheap candy for each buff. Breath mints are forever, right? - - - //We only display a handful of combinations in-run, because honestly there's no room. - int setting_maximum_display_limit = 2; - - - string [int][int] table; - //table.listAppend(listMake(HTMLGenerateSpanOfClass("Effect", "r_bold"), HTMLGenerateSpanOfClass("Candies", "r_bold"))); - - int approximate_line_count = 0; - string [int] table_lines; - foreach key, e in __sweet_synthesis_buff_output_order - { - if (e == $effect[none]) - continue; - CandyCombination [int] combinations = calculateSweetSynthesisCandyCombinations(__sweet_synthesis_buff_tiers[e], __sweet_synthesis_buff_subid[e]); - - - //If we're in aftercore, show the cheapest combination. - //If we're in ronin, show all combinations we have components for. - CandyCombination [int] final_combinations; - //final_combinations = combinations; - if (in_ronin()) - { - //All we have enough for: - //int [int][item] combinations_seen; - - - /*item [int][int] second_stage_combinations; - //Sort on smaller list: - //Note that combinations is, like, 4426, 4371, 4450, 4465, 4489, 1919, 1952, 1913, 1890, 1862, 813, 790, 805, 832, and 856. - foreach key in combinations - { - item item_1 = combinations[key][0]; - - if (item_1.available_amount() + item_1.closet_amount() == 0) - continue; - item item_2 = combinations[key][1]; - if (item_2.available_amount() + item_2.closet_amount() == 0) - continue; - //if (!(item_1.available_amount() + item_1.closet_amount() > 0 && item_2.available_amount() + item_2.closet_amount() > 0 && !(item_1 == item_2 && item_1.available_amount() < 2))) - if (item_1 == item_2 && item_1.available_amount() + item_1.closet_amount() < 2) - continue; - second_stage_combinations.listAppend(combinations[key]); - } - sort second_stage_combinations by (value[0].synthesis_price() + value[1].synthesis_price()); //fast reject - we'll stop running once we reach the display limit - */ - boolean [string] combinations_seen_json; - foreach key, cc in combinations - { - if (final_combinations.count() >= setting_maximum_display_limit + 1) - break; - //So, using item_amount() is three times faster than available_amount(), even though it ignores a bunch of stuff. Which is a difference of 0.3 seconds vs 0.1 seconds. - if (cc.candy_1.item_amount() + cc.candy_1.closet_amount() == 0) - continue; - if (cc.candy_2.item_amount() + cc.candy_2.closet_amount() == 0) - continue; - if (cc.candy_1 == cc.candy_2 && cc.candy_1.item_amount() + cc.candy_1.closet_amount() < 2) - continue; - - //if (!(item_1.available_amount() + item_1.closet_amount() > 0 && item_2.available_amount() + item_2.closet_amount() > 0 && !(item_1 == item_2 && item_1.available_amount() < 2))) - //continue; - int [item] combination_presence; - combination_presence[cc.candy_1] += 1; - combination_presence[cc.candy_2] += 1; - //Use a JSON to discover if we've seen this combination before. Seems to be the fastest way to check if we've seen a map before? - //It shouldn't be too slow... right? Right? - string presence_json = combination_presence.to_json(); - boolean already_seen = (combinations_seen_json contains presence_json); - //Have we seen this particular combination yet? - //Lovely slow O(N^2) algorithm: - /*foreach key in combinations_seen - { - boolean identical = true; - foreach it, amount in combinations_seen[key] - { - if (combination_presence[it] != amount) - { - identical = false; - break; - } - } - if (identical) - { - already_seen = true; - break; - } - }*/ - if (already_seen) - { - continue; - } - - - final_combinations[final_combinations.count()] = cc; - //combinations_seen[combinations_seen.count()] = combination_presence; - combinations_seen_json[presence_json] = true; - } - } - else - { - //Find cheapest: - //This is already pre-sorted. - final_combinations[final_combinations.count()] = combinations[0]; - } - if (final_combinations.count() > 0) - { - buffer line; - foreach key in final_combinations - { - if (key >= setting_maximum_display_limit) //unrealistic to show that many - { - line.append("
[...]"); - break; - } - approximate_line_count += 1; - if (line.length() != 0) - line.append("
"); - line.append(final_combinations[key].candy_1); - line.append(" + "); - line.append(final_combinations[key].candy_2); - } - table_lines.listAppend(HTMLGenerateSpanOfClass(__sweet_synthesis_buff_descriptions[e], "r_bold") + "
" + HTMLGenerateSpanOfStyle(line, "font-size:0.8em;color:#333333")); - //table.listAppend(listMake(__sweet_synthesis_buff_descriptions[e], line)); - } - } - - if (table_lines.count() == 0) - return; - - string [int] building_line; - foreach key in table_lines - { - building_line.listAppend(table_lines[key]); - if (key % 2 == 1) - { - table.listAppend(building_line); - building_line = listMakeBlankString(); - } - } - if (building_line.count() > 0) - table.listAppend(building_line); - int estimated_margin = approximate_line_count * 1.2; - - ChecklistSubentry subentry = ChecklistSubentryMake("Sweet Synthesis Buff", "30 turns", "Costs one spleen and two candies."); - //ChecklistSubentry subentry = ChecklistSubentryMake("Sweet Synthesis Buff", "30 turns", HTMLGenerateSpanOfClass(HTMLGenerateTagWrap("span", table.HTMLGenerateSimpleTableLines(false), mapMake("class", "r_tooltip_inner_class r_tooltip_inner_class_margin", "style", "margin-top:-" + estimated_margin + "em;margin-left:-5em;")) + "Costs one spleen and two candies.", "r_tooltip_outer_class")); - ChecklistEntry entry = ChecklistEntryMake("__skill Sweet Synthesis", "runskillz.php?action=Skillz&whichskill=166&targetplayer=" + my_id() + "&pwd=" + my_hash() + "&quantity=1", subentry, 10); - entry.tags.id = "Sweet synthesis skill"; - entry.subentries_on_mouse_over.listAppend(ChecklistSubentryMake("Sweet Synthesis Buff", "30 turns", table.HTMLGenerateSimpleTableLines(false))); - - resource_entries.listAppend(entry); -} diff --git a/Source/relay/TourGuide/Settings.ash b/Source/relay/TourGuide/Settings.ash deleted file mode 100644 index cee0dec9..00000000 --- a/Source/relay/TourGuide/Settings.ash +++ /dev/null @@ -1,48 +0,0 @@ -//These settings are for development. Don't worry about editing them. -string __version = "2.2.2"; // pushed to 2.2.1 on jill/leaves tiles - -//Path and name of the .js file. In case you change either. -string __javascript = "TourGuide/TourGuide.js"; - -//Debugging: -boolean __setting_debug_mode = false; -boolean __setting_debug_enable_example_mode_in_aftercore = false; //for testing. Will give false information, so don't enable -boolean __setting_debug_show_all_internal_states = false; //displays usable images/__misc_state/__misc_state_string/__misc_state_int/__quest_state - -//Display settings: -boolean __setting_entire_area_clickable = false; -boolean __setting_side_negative_space_is_dark = true; -boolean __setting_fill_vertical = true; -int __setting_image_width_large = 100; -int __setting_image_width_medium = 70; -int __setting_image_width_small = 30; - -boolean __show_importance_bar = true; -boolean __setting_show_navbar = true; -boolean __setting_navbar_has_proportional_widths = false; //doesn't look very good, remove? -boolean __setting_gray_navbar = true; -boolean __setting_use_kol_css = false; //images/styles.css -boolean __setting_show_location_bar = true; -boolean __setting_enable_location_popup_box = true; -boolean __setting_location_bar_uses_last_location = false; //nextAdventure otherwise -boolean __setting_location_bar_fixed_layout = true; -boolean __setting_location_bar_limit_max_width = true; -float __setting_location_bar_max_width_per_entry = 0.35; -boolean __setting_enable_outputting_all_numberology_options = true; - -string __setting_unavailable_colour = "#7F7F7F"; -string __setting_line_colour = "#B2B2B2"; -string __setting_dark_colour = "#C0C0C0"; -string __setting_modifier_colour = "#404040"; -string __setting_navbar_background_colour = "#FFFFFF"; -string __setting_page_background_colour = "#F7F7F7"; - -string __setting_media_query_large_size = "@media (min-width: 500px)"; -string __setting_media_query_medium_size = "@media (min-width: 350px) and (max-width: 500px)"; -string __setting_media_query_small_size = "@media (max-width: 350px) and (min-width: 225px)"; -string __setting_media_query_tiny_size = "@media (max-width: 225px)"; - -float __setting_navbar_height_in_em = 2.3; -string __setting_navbar_height = __setting_navbar_height_in_em + "em"; -int __setting_horizontal_width = 600; -boolean __setting_ios_appearance = false; //no don't diff --git a/Source/relay/TourGuide/State.ash b/Source/relay/TourGuide/State.ash deleted file mode 100644 index 216c2306..00000000 --- a/Source/relay/TourGuide/State.ash +++ /dev/null @@ -1,962 +0,0 @@ -import "relay/TourGuide/Support/Campground.ash" -import "relay/TourGuide/QuestState.ash" -import "relay/TourGuide/Quests.ash" -import "relay/TourGuide/Sets.ash" -import "relay/TourGuide/Pulls.ash" -import "relay/TourGuide/Plants.ash" - -void setUpExampleState() -{ - __misc_state["in run"] = true; - - //Do a default reset of each quest: - - foreach quest_name in __quest_state - { - QuestState state = __quest_state[quest_name]; - QuestStateParseMafiaQuestPropertyValue(state, "started"); - __quest_state[quest_name] = state; - } - - __misc_state_int["pulls available"] = 17; -} - - -//We call this twice - once at the start, once after __quest_state["Level 13"] becomes available. I would just call it once but that could break things? (very old code) -void computeFatLootTokens() -{ - int dd_tokens_and_keys_available = 0; - int tokens_needed = 0; - int keys_missing = 0; - boolean need_boris_key = true; - boolean need_jarlsberg_key = true; - boolean need_sneaky_pete_key = true; - - if ($item[boris\'s key].available_amount() > 0) - need_boris_key = false; - if ($item[jarlsberg\'s key].available_amount() > 0) - need_jarlsberg_key = false; - if ($item[sneaky pete\'s key].available_amount() > 0) - need_sneaky_pete_key = false; - - if (__quest_state["Level 13"].state_boolean["Sneaky Pete's key used"]) - need_sneaky_pete_key = false; - if (__quest_state["Level 13"].state_boolean["Boris's key used"]) - need_boris_key = false; - if (__quest_state["Level 13"].state_boolean["Jarlsberg's key used"]) - need_jarlsberg_key = false; - - if (need_boris_key) - tokens_needed += 1; - if (need_jarlsberg_key) - tokens_needed += 1; - if (need_sneaky_pete_key) - tokens_needed += 1; - - keys_missing = tokens_needed; - tokens_needed -= $item[fat loot token].available_amount(); - tokens_needed = MAX(0, tokens_needed); - - dd_tokens_and_keys_available += $item[fat loot token].available_amount(); - dd_tokens_and_keys_available += $item[boris\'s key].available_amount(); - dd_tokens_and_keys_available += $item[jarlsberg\'s key].available_amount(); - dd_tokens_and_keys_available += $item[sneaky pete\'s key].available_amount(); - - __misc_state_int["fat loot tokens needed"] = MAX(0, tokens_needed); - __misc_state_int["hero keys missing"] = keys_missing; - __misc_state_int["DD Tokens and keys available"] = dd_tokens_and_keys_available; -} - - -void setUpState() -{ - __misc_state.listClear(); - __last_adventure_location = get_property_location("lastAdventure"); - if (__misc_state["Example mode"]) - { - int wanted_index = random_safe($locations[].count()); - int i = 0; - foreach l in $locations[] - { - if (i == wanted_index) - { - __last_adventure_location = l; - break; - } - i += 1; - } - } - if (__setting_debug_mode && __setting_debug_enable_example_mode_in_aftercore && get_property_boolean("kingLiberated")) - { - __misc_state["Example mode"] = true; - } - - __misc_state["in aftercore"] = get_property_boolean("kingLiberated"); - //if (get_property_ascension("lastKingLiberation") && my_ascensions() != 0) - //__misc_state["in aftercore"] = true; - __misc_state["in run"] = !__misc_state["in aftercore"]; - if (__misc_state["Example mode"]) - __misc_state["in run"] = true; - __misc_state["In valhalla"] = (my_class().to_string() == "Astral Spirit"); - - __misc_state["in CS aftercore"] = __misc_state["in aftercore"] && get_property("csServicesPerformed").split_string(",").count() == 11; - - - int adventures_after_rollover = my_adventures() + 40; - if (my_path().id != PATH_SLOW_AND_STEADY) { - adventures_after_rollover += numeric_modifier("adventures"); - adventures_after_rollover += get_property_int("extraRolloverAdventures"); - } - adventures_after_rollover = MAX(adventures_after_rollover, 0); //Who knows? - int adventures_after_rollover_post_cap = MIN(adventures_after_rollover, 200); - __misc_state_int["adventures after rollover"] = adventures_after_rollover_post_cap; - __misc_state_int["adventures lost to rollover"] = adventures_after_rollover - adventures_after_rollover_post_cap; - - if (my_turncount() >= 30 && get_property_int("singleFamiliarRun") != -1) - __misc_state["single familiar run"] = true; - if ($item[Clan VIP Lounge key].available_amount() > 0 && !in_bad_moon() && my_path() != $path[Legacy of Loathing]) - __misc_state["VIP available"] = true; - boolean fax_available = false; - if (__misc_state["VIP available"]) - { - if (!get_property_boolean("_photocopyUsed")) - fax_available = true; - __misc_state["fax accessible"] = true; - } - - if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_TRENDY) - { - __misc_state["fax accessible"] = false; - } - if (!$item[deluxe fax machine].is_unrestricted()) - __misc_state["fax accessible"] = false; - - if (!__misc_state["fax accessible"]) - fax_available = false; - __misc_state["fax available"] = fax_available; - - __misc_state["fax equivalent accessible"] = __misc_state["fax available"]; - if (my_path().id == PATH_HEAVY_RAINS && $skill[rain man].skill_is_usable()) - __misc_state["fax equivalent accessible"] = true; - - if (__misc_state["VIP available"]) - { - int soaks_remaining = MAX(0, 5 - get_property_int("_hotTubSoaks")); - __misc_state_int["hot tub soaks remaining"] = soaks_remaining; - } - - __misc_state["can eat just about anything"] = true; - if (my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_ZOMBIE_SLAYER || fullness_limit() == 0 || my_path().id == PATH_VAMPIRE || my_path().id == PATH_YOU_ROBOT || my_path().id == PATH_GELATINOUS_NOOB) - { - __misc_state["can eat just about anything"] = false; - } - - __misc_state["can drink just about anything"] = true; - if (my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_KOLHS || my_path().id == PATH_LICENSE_TO_ADVENTURE || inebriety_limit() == 0 || my_path().id == PATH_VAMPIRE || my_path().id == PATH_YOU_ROBOT) - { - __misc_state["can drink just about anything"] = false; - } - - - __misc_state["can equip just about any weapon"] = true; - if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_WAY_OF_THE_SURPRISING_FIST) - { - __misc_state["can equip just about any weapon"] = false; - } - - - __misc_state["MMJs buyable"] = false; - if (get_property_ascension("lastGuildStoreOpen")) - { - if (my_class() == $class[pastamancer] || my_class() == $class[sauceror] || (my_class() == $class[accordion thief] && my_level() >= 9)) - __misc_state["MMJs buyable"] = true; - } - - //Check for moxie/mysticality/muscle combat skills: - - foreach s in $skills[] - { - if (!s.combat) - continue; - if (!s.skill_is_usable()) - continue; - if (s.class == $class[accordion thief] || s.class == $class[disco bandit]) - __misc_state["have moxie class combat skill"] = true; - if (s.class == $class[pastamancer] || s.class == $class[sauceror]) - __misc_state["have mysticality class combat skill"] = true; - if (s.class == $class[seal clubber] || s.class == $class[turtle tamer]) - __misc_state["have muscle class combat skill"] = true; - } - - - - boolean yellow_ray_available = false; - string yellow_ray_source = ""; - string yellow_ray_image_name = "__effect everything looks yellow"; - boolean yellow_ray_potentially_available = false; - - if (__iotms_usable[lookupItem("Eight Days a Week Pill Keeper")] && (!get_property_boolean("_freePillKeeperUsed") || spleen_limit() - my_spleen_use() >= 3)) - { //One of the shortest, but also one of the worst, since you activate it BEFORE a fight starts - yellow_ray_available = true; - yellow_ray_source = "pill keeper Explodinall"; - } - foreach source in $items[4766,5229,6673,7013] - { - if (!(source.available_amount() > 0 || (source == $item[4766] && $item[4761].available_amount() > 0))) - continue; - yellow_ray_available = true; - yellow_ray_source = source.to_string(); - yellow_ray_image_name = "__item " + source.to_string(); - } - if ($item[micronova].available_amount() > 0) - { - yellow_ray_available = true; - yellow_ray_source = "micronova"; - yellow_ray_image_name = "__item micronova"; - } - if ($item[viral video].available_amount() > 0) - { - yellow_ray_available = true; - yellow_ray_source = "viral video"; - yellow_ray_image_name = "__item viral video"; - } - - if ($item[mayo lance].available_amount() > 0 && get_property_int("mayoLevel") > 0) - { - yellow_ray_available = true; - yellow_ray_source = "Mayo Lance"; - yellow_ray_image_name = "__item mayo lance"; - } - if ($skill[Unleash Cowrruption].have_skill()) - { - yellow_ray_available = true; - yellow_ray_source = "Unleash Cowrruption"; - yellow_ray_image_name = "__skill Unleash Cowrruption"; - } - if ($familiar[Crimbo Shrub].familiar_is_usable() && get_property("shrubGifts") == "yellow" && !(my_daycount() == 1 && get_property("_shrubDecorated") == "false")) - { - yellow_ray_available = true; - yellow_ray_source = "Crimbo Shrub"; - yellow_ray_image_name = "__item DNOTC Box"; //uncertain - } - if (familiar_is_usable($familiar[nanorhino]) && __misc_state["have moxie class combat skill"] && get_property_int("_nanorhinoCharge") == 100) - { - yellow_ray_available = true; - yellow_ray_source = "Nanorhino"; - yellow_ray_image_name = "nanorhino"; - } - if (lookupItem("unwrapped knock-off retro superhero cape").have() && __iotms_usable[lookupItem("unwrapped knock-off retro superhero cape")]) - { - yellow_ray_available = true; - yellow_ray_source = "Superhero cape skill Unleash the Devil's Kiss"; - yellow_ray_source += get_property("retroCapeSuperhero") != "heck" || get_property("retroCapeWashingInstructions") != "kiss" ? " (Heck General + Kiss me)" : ""; - yellow_ray_source += !lookupItem("unwrapped knock-off retro superhero cape").equipped() ? " (equip first)" : ""; - yellow_ray_image_name = "__item unwrapped knock-off retro superhero cape"; - } - if ($skill[Ball Lightning].skill_is_usable() && my_path().id == PATH_HEAVY_RAINS && my_lightning() >= 5) - { - yellow_ray_available = true; - yellow_ray_source = "Ball Lightning"; - yellow_ray_image_name = "__skill Ball Lightning"; - } - if ($skill[wrath of ra].skill_is_usable() && my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - { - yellow_ray_available = true; - yellow_ray_source = "Wrath of Ra"; - yellow_ray_image_name = "__skill wrath of ra"; - } - if (familiar_is_usable($familiar[he-boulder])) - { - yellow_ray_available = true; - yellow_ray_source = "He-Boulder"; - yellow_ray_image_name = "he-boulder"; - } - if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && $skill[Flash Headlight].skill_is_usable() && get_property("peteMotorbikeHeadlight") == "Ultrabright Yellow Bulb") - { - yellow_ray_available = true; - yellow_ray_source = "Flash Headlight"; - yellow_ray_image_name = "__skill Easy Riding"; - } - if (lookupSkill("disintegrate").have_skill() && my_maxmp() >= 150) - { - yellow_ray_available = true; - yellow_ray_source = "Disintegrate"; - yellow_ray_image_name = "__skill Disintegrate"; - } - - if (yellow_ray_available) - yellow_ray_potentially_available = true; - - if (my_path().id == PATH_KOLHS) - yellow_ray_potentially_available = true; - - - if ($effect[Everything looks yellow].have_effect() > 0) - yellow_ray_available = false; - if (!yellow_ray_available) - yellow_ray_source = ""; - __misc_state["yellow ray available"] = yellow_ray_available; - __misc_state_string["yellow ray source"] = yellow_ray_source; - __misc_state_string["yellow ray image name"] = yellow_ray_image_name; - __misc_state["yellow ray potentially available"] = yellow_ray_potentially_available; - - - if (in_bad_moon() && !__misc_state["yellow ray potentially available"] && !__misc_state["yellow ray available"]) - { - __misc_state["yellow ray almost certainly impossible"] = true; - } - - __misc_state["can cook for free"] = false; - if (__campground[$item[chef-in-the-box]] > 0 || __campground[$item[clockwork chef-in-the-box]] > 0 || $effect[Inigo's Incantation of Inspiration].have_effect() >= 5) - __misc_state["can cook for free"] = true; - - - __misc_state["can bartend for free"] = false; - if (__campground[$item[bartender-in-the-box]] > 0 || __campground[$item[clockwork bartender-in-the-box]] > 0 || $effect[Inigo's Incantation of Inspiration].have_effect() >= 5) - __misc_state["can bartend for free"] = true; - - if ($skill[Rapid Prototyping].skill_is_usable() && get_property_int("_rapidPrototypingUsed") < 5) - { - __misc_state["can cook for free"] = true; - __misc_state["can bartend for free"] = true; - } - if (lookupSkill("Expert Corner-Cutter").skill_is_usable() && get_property_int("_expertCornerCutterUsed") < 5) - { - __misc_state["can cook for free"] = true; - __misc_state["can bartend for free"] = true; - } - - boolean free_runs_usable = true; - if (my_path().id == PATH_BIG || my_path().id == PATH_POCKET_FAMILIARS) //more like "combat items not usable" but - free_runs_usable = false; - __misc_state["free runs usable"] = free_runs_usable; - - boolean blank_outs_usable = true; - if (my_path().id == PATH_AVATAR_OF_JARLSBERG) - blank_outs_usable = false; - if (!free_runs_usable) - blank_outs_usable = false; - __misc_state["blank outs usable"] = free_runs_usable; - - // TODO: reconfig this whole state thing re: free runs. - boolean free_runs_available = false; - if (familiar_is_usable($familiar[pair of stomping boots]) || ($skill[the ode to booze].skill_is_usable() && familiar_is_usable($familiar[Frumious Bandersnatch]))) - free_runs_available = true; - if ($item[goto].available_amount() > 0 || $item[tattered scrap of paper].available_amount() > 0) - free_runs_available = true; - if ($item[greatest american pants].available_amount() > 0 || $item[navel ring of navel gazing].available_amount() > 0 || $item[peppermint parasol].available_amount() > 0) - free_runs_available = true; - if ($item[divine champagne popper].available_amount() > 0 || 2371.to_item().available_amount() > 0 || 7014.to_item().available_amount() > 0 || $item[handful of Smithereens].available_amount() > 0) - free_runs_available = true; - if ($item[V for Vivala mask].available_amount() > 0 && !get_property_boolean("_vmaskBanisherUsed")) - free_runs_available = true; - if ($item[replica V for Vivala mask].available_amount() > 0 && !get_property_boolean("_vmaskBanisherUsed")) - free_runs_available = true; - if (blank_outs_usable) - { - if ($item[bottle of Blank-Out].available_amount() > 0 || get_property_int("blankOutUsed") > 0) - free_runs_available = true; - } - if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && $skill[Peel Out].skill_is_usable()) - { - - int total_free_peel_outs_available = 10; - if (get_property("peteMotorbikeTires") == "Racing Slicks") - total_free_peel_outs_available += 20; - int free_peel_outs_available = MAX(0, total_free_peel_outs_available - get_property_int("_petePeeledOut")); - if (free_peel_outs_available > 0) - free_runs_available = true; - } - if (my_path().id == PATH_HEAVY_RAINS && $skill[Lightning Strike].skill_is_usable()) - free_runs_available = true; - if (!free_runs_usable) - free_runs_available = false; - __misc_state["free runs available"] = free_runs_available; - - - string olfacted_monster = ""; - boolean some_olfact_available = false; - boolean some_reusable_olfact_available = false; - if ($skill[Transcendent Olfaction].skill_is_usable()) - { - some_olfact_available = true; - some_reusable_olfact_available = true; - olfacted_monster = get_property("olfactedMonster"); - } - if ($familiar[nosy nose].familiar_is_usable()) //weakened, but still relevant - { - some_olfact_available = true; - } - if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - { - some_olfact_available = true; - some_reusable_olfact_available = true; - } - __misc_state["have olfaction equivalent"] = some_olfact_available; - __misc_state_string["olfaction equivalent monster"] = olfacted_monster; - __misc_state["have reusable olfaction equivalent"] = some_reusable_olfact_available; - - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING || my_path().id == PATH_NUCLEAR_AUTUMN) - __misc_state["campground unavailable"] = true; - - boolean skills_temporarily_missing = false; - boolean familiars_temporarily_blocked = false; - boolean familiars_temporarily_missing = false; - if (in_bad_moon()) - { - skills_temporarily_missing = true; - familiars_temporarily_missing = true; - } - if (my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING || my_path().id == PATH_VAMPIRE) - { - skills_temporarily_missing = true; - familiars_temporarily_missing = true; - familiars_temporarily_blocked = true; - } - if (my_path().id == PATH_ZOMBIE_SLAYER) - { - skills_temporarily_missing = true; - } - if (my_path().id == PATH_CLASS_ACT || my_path().id == PATH_CLASS_ACT_2) - { - //not sure how mafia interprets "have_skill" under class act - skills_temporarily_missing = true; - } - if (my_path().id == PATH_TRENDY) - { - //not sure if this is correct - //skills_temporarily_missing = true; - //familiars_temporarily_missing = true; - } - if (my_path().id == PATH_AVATAR_OF_WEST_OF_LOATHING || my_path().id == PATH_NUCLEAR_AUTUMN || my_path().id == PATH_GELATINOUS_NOOB || my_path().id == PATH_G_LOVER) - { - skills_temporarily_missing = true; - } - if (my_path().id == PATH_LICENSE_TO_ADVENTURE || my_path().id == PATH_POCKET_FAMILIARS) - familiars_temporarily_blocked = true; - __misc_state["skills temporarily missing"] = skills_temporarily_missing; - __misc_state["familiars temporarily missing"] = familiars_temporarily_missing; - __misc_state["familiars temporarily blocked"] = familiars_temporarily_blocked; - - - __misc_state["AT skills available"] = true; - if (my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_ZOMBIE_SLAYER || ((my_path().id == PATH_CLASS_ACT || my_path().id == PATH_CLASS_ACT_2) && my_class() != $class[accordion thief])) - __misc_state["AT skills available"] = false; - - - __misc_state_float["Non-combat statgain multiplier"] = 1.0; - __misc_state_float["ML to mainstat multiplier"] = 1.0 / (2.0 * 3.0); - /*if (my_path().id == PATH_CLASS_ACT_2) - { - __misc_state_float["ML to mainstat multiplier"] = 1.0 / (2.0 * 2.0); - }*/ - if (false) - { - //this does not seem to be the case? FIXME spade please - __misc_state_float["Non-combat statgain multiplier"] = 0.5; - __misc_state["Stat gain from NCs reduced"] = false; - } - - int pulls_available = 0; - pulls_available = pulls_remaining(); - if (__setting_debug_mode && in_ronin()) - pulls_available = MAX(pulls_available, 4); - __misc_state_int["pulls available"] = pulls_available; - - //Calculate free rests available: - int rests_used = get_property_int("timesRested"); - int total_rests_available = total_free_rests(); - - __misc_state_int["total free rests possible"] = total_rests_available; - __misc_state_int["free rests remaining"] = MAX(total_rests_available - rests_used, 0); - - - //monster.monster_initiative() is usually what you need, but just in case: - __misc_state_float["init ML penalty"] = monsterExtraInitForML(monster_level_adjustment_ignoring_plants()); - - // Make a state variable re: zap wand ownership - __misc_state["zap wand owned"] = false; - - item zap_wand_owned; - - if (true) { - zap_wand_owned = $item[none]; - foreach wand in $items[aluminum wand,ebony wand,hexagonal wand,marble wand,pine wand] { - if (wand.available_amount() > 0) { - zap_wand_owned = wand; - break; - } - } - } - - if (zap_wand_owned != $item[none]) __misc_state["zap wand owned"] = true; - - int ngs_needed = 0; - - //stats: - - if (my_level() < 13 && !__misc_state["in aftercore"]) - { - __misc_state["need to level"] = true; - } - __misc_state["need to level muscle"] = false; - __misc_state["need to level mysticality"] = false; - __misc_state["need to level moxie"] = false; - - if (__misc_state["in run"]) - { - //62 muscle for antique machete/hidden hospital - //70 moxie, 70 mysticality for war outfits - if (my_primestat() == $stat[muscle] && __misc_state["need to level"]) - __misc_state["need to level muscle"] = true; - if (my_primestat() == $stat[mysticality] && __misc_state["need to level"]) - __misc_state["need to level mysticality"] = true; - if (my_primestat() == $stat[moxie] && __misc_state["need to level"]) - __misc_state["need to level moxie"] = true; - - if (my_basestat($stat[muscle]) < 62) - __misc_state["need to level muscle"] = true; - if (my_basestat($stat[mysticality]) < 70) - __misc_state["need to level mysticality"] = true; - if (my_basestat($stat[moxie]) < 70) - __misc_state["need to level moxie"] = true; - } - - //wand - - boolean wand_of_nagamar_needed = true; - if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_BUGBEAR_INVASION || my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_KOLHS || my_path().id == PATH_HEAVY_RAINS || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING || my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_THE_SOURCE || my_path().id == PATH_LICENSE_TO_ADVENTURE || my_path().id == PATH_POCKET_FAMILIARS || my_path().id == PATH_VAMPIRE || my_path().id == PATH_GREY_GOO || my_path().id == PATH_YOU_ROBOT || my_path().id == PATH_FALL_OF_THE_DINOSAURS || my_path().id == PATH_AVATAR_OF_SHADOWS_OVER_LOATHING || my_path().id == PATH_WEREPROFESSOR) - wand_of_nagamar_needed = false; - - int ruby_w_needed = 1; - int metallic_a_needed = 1; - int lowercase_n_needed = 1; - int heavy_d_needed = 1; - int [string] letters_needed; - letters_needed["w"] = 1; - letters_needed["a"] = 1; - letters_needed["n"] = 1; - letters_needed["d"] = 1; - letters_needed["g"] = 0; - - int [string] letters_available; - letters_available["w"] = $item[ruby w].available_amount() + $item[wa].available_amount(); - letters_available["a"] = $item[metallic a].available_amount() + $item[wa].available_amount(); - letters_available["n"] = $item[lowercase n].available_amount() + $item[nd].available_amount() + $item[ng].available_amount(); - letters_available["d"] = $item[heavy d].available_amount() + $item[nd].available_amount(); - letters_needed["n"] += ngs_needed; - letters_needed["g"] += ngs_needed; - - if ($item[wand of nagamar].available_amount() > 0) - wand_of_nagamar_needed = false; - - if (my_path().id == PATH_SEA) wand_of_nagamar_needed = false; - - if (!wand_of_nagamar_needed) - { - letters_needed["w"] -= 1; - letters_needed["a"] -= 1; - letters_needed["n"] -= 1; - letters_needed["d"] -= 1; - } - - letters_needed["w"] = MAX(0, letters_needed["w"] - letters_available["w"]); - letters_needed["a"] = MAX(0, letters_needed["a"] - letters_available["a"]); - letters_needed["n"] = MAX(0, letters_needed["n"] - letters_available["n"]); - letters_needed["d"] = MAX(0, letters_needed["d"] - letters_available["d"]); - - __misc_state["wand of nagamar needed"] = wand_of_nagamar_needed; - __misc_state_int["ruby w needed"] = letters_needed["w"]; - __misc_state_int["metallic a needed"] = letters_needed["a"]; - __misc_state_int["lowercase n needed"] = letters_needed["n"]; - __misc_state_int["lowercase n available"] = letters_available["n"]; - __misc_state_int["heavy d needed"] = letters_needed["d"]; - __misc_state_int["original g needed"] = letters_needed["g"]; - - - computeFatLootTokens(); - - boolean mysterious_island_unlocked = false; - if ($items[dingy dinghy, skeletal skiff].available_amount() > 0) //junk junk requires completing the quest first - mysterious_island_unlocked = true; - - if (get_property("peteMotorbikeGasTank") == "Extra-Buoyant Tank") - mysterious_island_unlocked = true; - if (get_property_ascension("lastIslandUnlock")) - mysterious_island_unlocked = true; - if (my_path().id == PATH_EXPLOSION) - mysterious_island_unlocked = true; //kinda - - __misc_state["mysterious island available"] = mysterious_island_unlocked; - - __misc_state["desert beach available"] = false; - if (get_property("peteMotorbikeGasTank") == "Large Capacity Tank") - __misc_state["desert beach available"] = true; - if (get_property_ascension("lastDesertUnlock")) - __misc_state["desert beach available"] = true; - if ($location[south of the border].locationAvailable()) - __misc_state["desert beach available"] = true; - if ($locations[The Shore\, Inc. Travel Agency,the arid\, extra-dry desert,the oasis, south of the border].turnsAttemptedInLocation() > 0) //weird issues with detecting the beach. check if we've ever adventured there as a back-up - __misc_state["desert beach available"] = true; - if (my_path().id == PATH_EXPLOSION) - __misc_state["desert beach available"] = true; - - string ballroom_song = ""; - if (get_property_ascension("lastQuartetAscension")) - { - //1 and 3 are a guess - if (get_property("lastQuartetRequest") == "1") - { - ballroom_song = "+ML"; - } - else if (get_property("lastQuartetRequest") == "2") - { - ballroom_song = "-combat"; - } - else if (get_property("lastQuartetRequest") == "3") - { - ballroom_song = "+item"; - } - } - __misc_state_string["ballroom song"] = ballroom_song; - - __misc_state["Torso aware"] = false; - if ($skill[12].skill_is_usable() || $skill[Best Dressed].skill_is_usable()) // Torso Aware(g)ness - __misc_state["Torso aware"] = true; - - int hipster_fights_used = get_property_int("_hipsterAdv"); - if (hipster_fights_used < 0) hipster_fights_used = 0; - if (hipster_fights_used > 7) hipster_fights_used = 7; - - if (familiar_is_usable($familiar[artistic goth kid])) //goth kid has crayon shavings, which help survivability, though it has that weirdness with early runaways (have to defeat a monster first) - { - __misc_state_string["hipster name"] = "goth kid"; - __misc_state_int["hipster fights available"] = 7 - hipster_fights_used; - __misc_state["have hipster"] = true; - } - else if (familiar_is_usable($familiar[Mini-Hipster])) - { - __misc_state_string["hipster name"] = "hipster"; - __misc_state_int["hipster fights available"] = 7 - hipster_fights_used; - __misc_state["have hipster"] = true; - } - __misc_state_string["obtuse angel name"] = ""; - if (familiar_is_usable($familiar[reanimated reanimator])) - __misc_state_string["obtuse angel name"] = "Reanimated Reanimator"; - else if (familiar_is_usable($familiar[obtuse angel])) - __misc_state_string["obtuse angel name"] = "Obtuse Angel"; - - if (get_property_ascension("lastPlusSignUnlock")) - __misc_state["dungeons of doom unlocked"] = true; - else - __misc_state["dungeons of doom unlocked"] = false; - - __misc_state["can use clovers"] = true; - if (in_bad_moon() && $item[11-leaf clover].available_amount() == 0) - __misc_state["can use clovers"] = false; - - - __misc_state["bookshelf accessible"] = true; - if (my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) - __misc_state["bookshelf accessible"] = false; - - - __misc_state["can pickpocket"] = false; - if (my_class() == $class[disco bandit] || my_class() == $class[accordion thief] || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || $item[tiny black hole].equipped_amount() > 0 || $effect[Form of...Bird!].have_effect() > 0) - __misc_state["can pickpocket"] = true; - - if (CounterLookup("Romantic Monster").CounterExists() || get_property_int("_romanticFightsLeft") > 0) - __misc_state_string["Romantic Monster Name"] = get_property("romanticTarget").HTMLEscapeString(); - - //Moxie Experience Percent - float dance_card_average_stat_gain = MIN(2.25 * my_basestat($stat[moxie]), 300.0) * __misc_state_float["Non-combat statgain multiplier"] * (1.0 + numeric_modifier("Moxie Experience Percent") / 100.0); - __misc_state_float["dance card average stats"] = dance_card_average_stat_gain; - - //don't know if there's any way to query this information directly, so indirectly calculate it from scaling monsters in the area: - __misc_state_int["Basement Floor"] = MAX(1, round(powf(MAX(0.0, ($monster[Ghost of Fernswarthy's Grandfather].raw_defense - monster_level_adjustment()).to_float() / 2.0), 5.0 / 7.0))); - - if (true) - { - //calculate if we need -combat sources: - int minus_combat_source_count = 0; - int minus_combat_from_accessories = 0; - - foreach it in __minus_combat_equipment - { - if (!(it.can_equip() && it.available_amount() > 0)) - continue; - if (it == $item[none]) - continue; - if (it == $item[over-the-shoulder folder holder]) - { - } - int value = -it.numeric_modifier("combat rate"); - if ($slots[acc1,acc2,acc3] contains it.to_slot()) - minus_combat_from_accessories += value; - else - minus_combat_source_count += value; - } - if ($item[over-the-shoulder folder holder].available_amount() > 0) - { - //check if we have the -combat folder: - boolean [item] equipped_folders; - foreach s in $slots[folder1,folder2,folder3,folder4,folder5] - { - equipped_folders[s.equipped_item()] = true; - } - if (!(equipped_folders contains $item[folder (Ex-Files)])) - { - if (equipped_folders contains $item[folder (skull and crossbones)]) - { - minus_combat_from_accessories += 5; - } - } - } - - minus_combat_source_count += MIN(3 * 5, minus_combat_from_accessories); //three at most - - if ($skill[smooth movement].skill_is_usable()) - minus_combat_source_count += 5; - if ($skill[the sonata of sneakiness].skill_is_usable()) - minus_combat_source_count += 5; - if ($items[crown of thrones,buddy bjorn].available_amount() > 0 && $familiar[grimstone golem].have_familiar() && !__misc_state["familiars temporarily blocked"]) - minus_combat_source_count += 5; - if (my_path().id == PATH_AVATAR_OF_BORIS && $skill[song of solitude].skill_is_usable()) - minus_combat_source_count += 5 * 4; - if (my_path().id == PATH_ZOMBIE_SLAYER && $skill[disquiet riot].skill_is_usable()) - minus_combat_source_count += 5 * 4; - if (my_path().id == PATH_AVATAR_OF_JARLSBERG && $skill[chocolatesphere].skill_is_usable()) - minus_combat_source_count += 5 * 3; - if (__iotms_usable[lookupItem("Asdon Martin keyfob")]) - minus_combat_source_count += 10; - if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) - { - if ($skill[Brood].skill_is_usable()) - minus_combat_source_count += 5 * 2; - if (get_property("peteMotorbikeMuffler") == "Extra-Quiet Muffler" && $skill[Rev Engine].skill_is_usable()) - minus_combat_source_count += 5 * 3; - } - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) - { - if ($skill[Shelter of Shed].have_skill()) - minus_combat_source_count += 5 * 4; - } - if (minus_combat_source_count >= 25) - __misc_state["can reasonably reach -25% combat"] = true; - } - if (my_path().id == PATH_LIVE_ASCEND_REPEAT) - __misc_state["can reasonably reach -25% combat"] = true; - - if (!in_bad_moon() && $item[hand turkey outline].is_unrestricted()) - { - foreach s in $strings[spooky,sleaze,hot,cold,stench] - { - if (get_property_boolean(s + "AirportAlways") || get_property_boolean("_" + s + "AirportToday")) - __misc_state[s + " airport available"] = true; - } - } - - if (get_property_boolean("chateauAvailable") && !in_bad_moon() && $item[Chateau Mantegna room key].is_unrestricted()) { - __misc_state["Chateau Mantegna available"] = true; - __misc_state_string["resting url Chateau Mantegna"] = "place.php?whichplace=chateau"; - } - - // you can also use the chateau in LoL, if you have it - if (get_property_boolean("chateauAvailable") && my_path() == $path[Legacy of Loathing]) { - __misc_state["Chateau Mantegna available"] = true; - __misc_state_string["resting url Chateau Mantegna"] = "place.php?whichplace=chateau"; - } - - if (get_property_boolean("getawayCampsiteUnlocked") && !in_bad_moon() && $item[Distant Woods Getaway Brochure].is_unrestricted()) { - __misc_state["Getaway Campsite available"] = true; - __misc_state_string["resting url Getaway Campsite"] = "place.php?whichplace=campaway"; - } - - - __misc_state_string["resting url campsite"] = "campground.php"; - - - //Calculate how much HP/MP will be gained if resting at your campground - float resting_hp_percent = numeric_modifier("resting hp percent") / 100.0; - float resting_mp_percent = numeric_modifier("resting mp percent") / 100.0; - - //FIXME trace down every rest effect and make this more accurate, instead of an initial guess. - - //If grimace or ronald is full, they double the gains of everything else. - //This is reported as a modifier of +100% - so with pagoda, that's +200% HP - //But, it's actually +300%, or 400% total. I could be wrong about this - my knowledge of rest mechanics is limited. - //So, we'll explicitly check for grimace or ronald being full, then recalculate. Not great, but should work okay? - //This is probably inaccurate in a great number of cases, due to the complication of resting. - - float overall_multiplier_hp = 1.0; - float overall_multiplier_mp = 1.0; - float bonus_resting_hp = numeric_modifier("bonus resting hp"); - float after_bonus_resting_hp = 0.0; - int grimace_light = moon_phase() / 2; - int ronald_light = moon_phase() % 8; - if (grimace_light == 4) { - resting_hp_percent -= 1.0; - overall_multiplier_hp += 1.0; - } - if (ronald_light == 4) { - resting_mp_percent -= 1.0; - overall_multiplier_mp += 1.0; - } - - if ($effect[L'instinct Félin].have_effect() > 0) { //not currently tracked by mafia. Seems to triple HP/MP gains. - overall_multiplier_hp *= 3.0; - overall_multiplier_mp *= 3.0; - } - - if (__campground contains $item[gauze hammock]) { - //Gauze hammock appears to be a flat addition applied after everything else, including grimace, pagoda, and l'instinct. - //It shows up it bonus resting hp - we'll remove that, and add it back at the end. - bonus_resting_hp -= 60.0; - after_bonus_resting_hp += 60.0; - } - - __misc_state_int["rest hp restore"] = after_bonus_resting_hp + overall_multiplier_hp * (numeric_modifier("base resting hp") * (1.0 + resting_hp_percent) + bonus_resting_hp); - __misc_state_int["rest mp restore"] = overall_multiplier_mp * (numeric_modifier("base resting mp") * (1.0 + resting_mp_percent) + numeric_modifier("bonus resting mp")); - - - if (__misc_state["Chateau Mantegna available"] && get_property_boolean("restUsingChateau")) { - __misc_state_string["resting url"] = __misc_state_string["resting url Chateau Mantegna"]; - __misc_state_string["resting description"] = "Chateau Mantegna"; - __misc_state["recommend resting at campsite"] = false; - } else if (__misc_state["Getaway Campsite available"] && get_property_boolean("restUsingCampAwayTent")) { - __misc_state_string["resting url"] = __misc_state_string["resting url Getaway Campsite"]; - __misc_state_string["resting description"] = "Getaway Campsite"; - __misc_state["recommend resting at campsite"] = false; - } else { - __misc_state_string["resting url"] = __misc_state_string["resting url campsite"]; - __misc_state_string["resting description"] = "your campsite"; - __misc_state["recommend resting at campsite"] = true; - } - - if (!__misc_state["recommend resting at campsite"]) { //chance of redemption - boolean still_have_reason_to_rest_at_campsite = __resting_bonuses.count() > 0 || __misc_state_int["rest hp restore"] > 250 || __misc_state_int["rest mp restore"] > 125; - __misc_state["recommend resting at campsite"] = still_have_reason_to_rest_at_campsite; - } - - - - if ($classes[seal clubber,turtle tamer] contains my_class()) - __misc_state["guild open"] = QuestState("questG09Muscle").finished; - else if ($classes[pastamancer,sauceror] contains my_class()) - __misc_state["guild open"] = QuestState("questG07Myst").finished; - else if ($classes[disco bandit,accordion thief] contains my_class()) - __misc_state["guild open"] = QuestState("questG08Moxie").finished; - if (guild_store_available()) - __misc_state["guild open"] = true; - - - __misc_state["muscle guild store available"] = false; - __misc_state["mysticality guild store available"] = false; - __misc_state["moxie guild store available"] = false; - if (guild_store_available()) - { - if ($classes[seal clubber, turtle tamer] contains my_class()) - __misc_state["muscle guild store available"] = true; - if ($classes[pastamancer, sauceror] contains my_class()) - __misc_state["mysticality guild store available"] = true; - if ($classes[disco bandit,accordion thief] contains my_class()) - __misc_state["moxie guild store available"] = true; - - if (my_class() == $class[accordion thief] && my_level() >= 9) - { - __misc_state["muscle guild store available"] = true; - __misc_state["mysticality guild store available"] = true; - } - } - - __misc_state["can purchase magical mystery juice"] = __misc_state["mysticality guild store available"]; - __misc_state["have some reasonable way of restoring MP"] = false; - - if (__misc_state["can purchase magical mystery juice"] || black_market_available() || dispensary_available() || true) - __misc_state["have some reasonable way of restoring MP"] = true; - - if (my_path().id == PATH_ONE_CRAZY_RANDOM_SUMMER) - __misc_state["monsters can be nearly impossible to kill"] = true; - - int tonic_price = $item[Doc Galaktik's Invigorating Tonic].npc_price(); - if (tonic_price == 0) - tonic_price = 90; //wrong, but w/e - __misc_state_float["meat per MP"] = tonic_price.to_float() / 10.0; - - float soda_cost = -1.0; - if (black_market_available()) - soda_cost = $item[black cherry soda].npc_price(); - else if (dispensary_available()) - soda_cost = $item[knob goblin seltzer].npc_price(); - else if (!in_ronin()) //can't buy from NPC, so have to use mall price: - soda_cost = 100; //$item[knob goblin seltzer].mall_price(); //don't issue a mall search, we don't need it - - if (soda_cost > 0.0) - { - __misc_state_float["meat per MP"] = MIN(__misc_state_float["meat per MP"], soda_cost / 10.0); - } - - if (__misc_state["can purchase magical mystery juice"]) - { - float juice_cost = $item[magical mystery juice].npc_price(); - float mp_restored = 5.0 + my_level().to_float() * 1.5; - - if (juice_cost > 0.0) - __misc_state_float["meat per MP"] = MIN(__misc_state_float["meat per MP"], juice_cost / mp_restored); - } - - //FIXME all avatar paths: - if (my_path().id == PATH_GELATINOUS_NOOB || my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_KOLHS || my_path().id == PATH_CLASS_ACT_2 || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING || my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_THE_SOURCE || my_path().id == PATH_EXPLOSIONS) - __misc_state["sea access blocked"] = true; - -} - - -void setUpQuestStateViaMafia() -{ - QuestsInit(); - SetsInit(); - - foreach key, function_name in __init_functions - call function_name(); - - //Opening guild quest - if (true) - { - //??? - QuestState state; - state.startable = true; - } -} - - -void finaliseSetUpState() -{ - //done after quest parsing - - if (__misc_state["Example mode"]) - { - __misc_state["need to level"] = true; - if (my_primestat() == $stat[muscle]) - __misc_state["need to level muscle"] = true; - if (my_primestat() == $stat[mysticality]) - __misc_state["need to level mysticality"] = true; - if (my_primestat() == $stat[moxie]) - __misc_state["need to level moxie"] = true; - } - - if (__misc_state_int["pulls available"] > 0) - { - PullsInit(); - } - computeFatLootTokens(); - - finaliseSetUpFloristState(); -} - -void setUpQuestState() -{ - if (__misc_state["In valhalla"]) - return; - setUpQuestStateViaMafia(); -} diff --git a/Source/relay/TourGuide/Strategy.ash b/Source/relay/TourGuide/Strategy.ash deleted file mode 100644 index 951bb0bd..00000000 --- a/Source/relay/TourGuide/Strategy.ash +++ /dev/null @@ -1,17 +0,0 @@ -void generateStrategy(Checklist [int] checklists) -{ - ChecklistEntry [int] entries; - - if (!__misc_state["in run"]) - return; - - - //What familiar to run. spleen items - //Turn generation. - //How to handle combat. - //How to restore HP. - //Where to get MP...? - - - checklists.listAppend(ChecklistMake("Strategy", entries)); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Support/AdventurePHP Locations.ash b/Source/relay/TourGuide/Support/AdventurePHP Locations.ash deleted file mode 100644 index 09897220..00000000 --- a/Source/relay/TourGuide/Support/AdventurePHP Locations.ash +++ /dev/null @@ -1,80 +0,0 @@ -//This file isn't used in guide at all, currently, but I'd thought I'd release it anyways. -//Classifies locations on whether they are adventure.php. Useful for scripts that need that information. Relevant for arrowing monsters, KOLHS, wandering monsters, semi-rare, etc. - -import "relay/TourGuide/Support/Math.ash"; - -static -{ - int [location] __adventure_php_locations; - void initialiseAdventurePHPLocations() - { - //Two methods: - //Look up every snarfblat, and assign ones that have locations. (this is faster) - //Load adventures.txt, find every adventure= entry, save those. (slower, but more accurate if they ever go past 1000 snarfblat) - //Using the first method, because our parsing of adventures.txt isn't perfect, and it'll take a few years before we go over snarfblat=1000 - if (true) - { - //0.985093583 total, 0.663535898 net, 1000 invocations - for i from 1 to 1000 //FIXME update this in a few years, we're nearing 500 or so right now - { - location l = i.to_location(); - if (l != $location[none]) - __adventure_php_locations[l] = i; - } - } - else - { - //2.571006588 total, 0.791600414 net, 1000 invocations - //Read from adventures.txt: - //This doesn't accurately read the file. No idea how to use file_to_map here. - string [string,string] adventures_txt; - file_to_map("data/adventures.txt", adventures_txt); - //print_html("adventures_txt = " + adventures_txt.to_json()); - foreach key in adventures_txt - { - foreach key2 in adventures_txt[key] - { - if (key2.contains_text("adventure=")) - { - int snarfblat = key2.replace_string("adventure=", "").to_int_silent(); - - location l = snarfblat.to_location(); - if (l != $location[none]) - __adventure_php_locations[l] = snarfblat; - } - //print_html("found (" + key + ")(" + key2 + ") \"" + adventures_txt[key][key2] + "\""); - } - } - } - } - initialiseAdventurePHPLocations(); -} - -boolean locationVisitsAdventurePHP(location l) -{ - if (l.to_url().contains_text("adventure.php")) - return true; - if (__adventure_php_locations contains l) - return true; - return false; -} - -boolean locationAllowsWanderingMonsters(location l) -{ - if ($locations[The Shore\, Inc. Travel Agency,Noob Cave,The Dire Warren] contains l) - return false; - if ($locations[The Daily Dungeon,An Overgrown Shrine (Northwest),An Overgrown Shrine (Southwest),An Overgrown Shrine (Northeast),An Overgrown Shrine (Southeast),A Massive Ziggurat] contains l) //warning: I have not personally verified these - return false; - if (l == $location[The X-32-F Combat Training Snowman]) - return false; - if ($locations[Gingerbread Industrial Zone,Gingerbread Train Station,Gingerbread Sewers,Gingerbread Upscale Retail District] contains l && l != $location[none]) - return false; - return l.locationVisitsAdventurePHP(); -} - -int snarfblatForLocation(location l) -{ - if (__adventure_php_locations contains l) - return __adventure_php_locations[l]; - return -1; -} diff --git a/Source/relay/TourGuide/Support/Banishers.ash b/Source/relay/TourGuide/Support/Banishers.ash deleted file mode 100644 index 3d3d470e..00000000 --- a/Source/relay/TourGuide/Support/Banishers.ash +++ /dev/null @@ -1,271 +0,0 @@ - -import "relay/TourGuide/Support/Library.ash" - -Record Banish -{ - monster banished_monster; - string banish_source; - int turn_banished; - int banish_turn_length; - string custom_reset_conditions; -}; - -// Added due to reasons, those reasons being "now you can banish phyla" -Record BanishedPhylum -{ - phylum banished_phylum; - string banish_source; - int turn_banished; - int banish_turn_length; - string custom_reset_conditions; -}; - -void listAppend(Banish [int] list, Banish entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -// It is annoying that I have to re-add this for the new record lol -void listAppend(BanishedPhylum [int] list, BanishedPhylum entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -int BanishTurnsLeft(Banish b) -{ - if (b.banish_turn_length == -1) - return 2147483647; - - // Some sources depend on effect or a state that is running out, and so the stated length should be returned directly - string banish_source = b.banish_source.to_lower_case(); - if (banish_source == "roar like a lion") return b.banish_turn_length; - - return b.turn_banished + b.banish_turn_length - my_turncount(); -} - -static -{ - int [string] __banish_source_length; - //FIXME request this be exposed in ASH? - //all of these must be lowercase. because. - __banish_source_length["banishing shout"] = -1; - __banish_source_length["batter up!"] = -1; - __banish_source_length["chatterboxing"] = 20; - __banish_source_length["classy monkey"] = 20; - __banish_source_length["cocktail napkin"] = 20; - __banish_source_length["crystal skull"] = 20; - __banish_source_length["deathchucks"] = -1; - __banish_source_length["dirty stinkbomb"] = -1; - __banish_source_length["divine champagne popper"] = 5; - __banish_source_length["harold's bell"] = 20; - __banish_source_length["howl of the alpha"] = -1; - __banish_source_length["ice house"] = -1; - __banish_source_length["louder than bomb"] = 20; - __banish_source_length["nanorhino"] = -1; - __banish_source_length["pantsgiving"] = 30; - __banish_source_length["peel out"] = -1; - __banish_source_length["pulled indigo taffy"] = 40; - __banish_source_length["smoke grenade"] = 20; - __banish_source_length["spooky music box mechanism"] = -1; - __banish_source_length["staff of the standalone cheese"] = -1; - __banish_source_length["stinky cheese eye"] = 10; - __banish_source_length["thunder clap"] = 40; - __banish_source_length["v for vivala mask"] = 10; - __banish_source_length["replica v for vivala mask"] = 10; - __banish_source_length["walk away from explosion"] = 30; - __banish_source_length["tennis ball"] = 30; - __banish_source_length["curse of vacation"] = -1; - __banish_source_length["ice hotel bell"] = -1; - __banish_source_length["bundle of "fragrant" herbs"] = -1; - __banish_source_length["snokebomb"] = 30; - __banish_source_length["beancannon"] = -1; - __banish_source_length["licorice rope"] = -1; - __banish_source_length["kgb tranquilizer dart"] = 20; - __banish_source_length["breathe out"] = 20; // is it listed as hot jelly, breathe out or space jellyfish ? - __banish_source_length["daily affirmation: be a mind master"] = 80; // how long does it last, exactly? is it still unknown? - __banish_source_length["spring-loaded front bumper"] = 30; - __banish_source_length["mafia middle finger ring"] = 60; - __banish_source_length["throw latte on opponent"] = 30; - __banish_source_length["tryptophan dart"] = -1; - __banish_source_length["baleful howl"] = -1; - __banish_source_length["reflex hammer"] = 30; - __banish_source_length["saber force"] = 30; - __banish_source_length["human musk"] = -1; - __banish_source_length["ultra smash"] = -1; // is it the right name? - __banish_source_length["b. l. a. r. t. spray (wide)"] = -1; - __banish_source_length["system sweep"] = -1; - __banish_source_length["feel hatred"] = 50; - __banish_source_length["show your boring familiar pictures"] = 100; - __banish_source_length["bowl a curveball"] = 5; - __banish_source_length["patriotic screech"] = 100; - __banish_source_length["roar like a lion"] = 30; // not sure it is needed; it should generally be not more than 30 - __banish_source_length["monkey slap"] = 1234567; // this, for some reason, was not properly respecting the reset condition. so imma just do this to hopefully solve it. - __banish_source_length["spring kick"] = -1; - - int [string] __banish_simultaneous_limit; - __banish_simultaneous_limit["beancannon"] = 5; - __banish_simultaneous_limit["banishing shout"] = 3; - __banish_simultaneous_limit["howl of the alpha"] = 3; - __banish_simultaneous_limit["staff of the standalone cheese"] = 5; -} - -Banish [int] __banishes_active_cache; -string __banishes_active_cache_cached_monsters_string; - -Banish [int] BanishesActive() -{ - //banishedMonsters(user, now 'a.m.c. gremlin:ice house:2890', default ) - - string banished_monsters_string = get_property("banishedMonsters"); - - if (banished_monsters_string == __banishes_active_cache_cached_monsters_string && __banishes_active_cache_cached_monsters_string != "") - return __banishes_active_cache; - - __banishes_active_cache_cached_monsters_string = ""; //invalidate the cache - - Banish [int] result; - - string [int] banished_monsters_string_split = banished_monsters_string.split_string(":"); - - foreach key, s in banished_monsters_string_split { - if (s.length() == 0) - continue; - if (key % 3 != 0) - continue; - //string [int] entry = s.split_string(":"); - - //if (entry.count() != 3) - //continue; - if (!(banished_monsters_string_split contains (key + 1)) || !(banished_monsters_string_split contains (key + 2))) - continue; - - Banish b; - b.banished_monster = banished_monsters_string_split[key + 0].to_monster(); - b.banish_source = banished_monsters_string_split[key + 1]; - b.turn_banished = banished_monsters_string_split[key + 2].to_int(); - b.banish_turn_length = 0; - - string banish_source = b.banish_source.to_lower_case(); - if (__banish_source_length contains banish_source) - b.banish_turn_length = __banish_source_length[banish_source]; - if (banish_source == "bowl a curveball") b.banish_turn_length = get_property_int("cosmicBowlingBallReturnCombats"); - if (banish_source == "roar like a lion") b.banish_turn_length = have_effect($effect[Hear Me Roar]); - if (banish_source == "batter up!" || banish_source == "deathchucks" || banish_source == "dirty stinkbomb" || banish_source == "nanorhino" || banish_source == "spooky music box mechanism" || banish_source == "ice hotel bell" || banish_source == "beancannon" || banish_source == "monkey slap") - b.custom_reset_conditions = "rollover"; - if (banish_source == "ice house" && (!$item[ice house].is_unrestricted() || in_bad_moon())) //not relevant - continue; - result.listAppend(b); - } - - __banishes_active_cache_cached_monsters_string = banished_monsters_string; - __banishes_active_cache = result; - - return result; -} - - -Banish [int] BanishesActiveInLocation(location l) -{ - boolean [monster] location_monsters; - foreach key, m in l.get_monsters() - location_monsters[m] = true; - Banish [int] banishes_active = BanishesActive(); - Banish [int] result; - foreach key, b in banishes_active { - if (location_monsters contains b.banished_monster) - result.listAppend(b); - } - return result; -} - -int BanishShortestBanishForLocation(location l) -{ - Banish [int] active_banishes = BanishesActiveInLocation(l); - int minimum = 2147483647; - foreach key, b in active_banishes { - minimum = MIN(minimum, b.BanishTurnsLeft()); - } - return minimum; -} - -Banish BanishForMonster(monster m) -{ - foreach key, b in BanishesActive() { - if (b.banished_monster == m) - return b; - } - Banish blank; - return blank; -} - -string BanishSourceForMonster(monster m) -{ - return BanishForMonster(m).banish_source; -} - -int [string] activeBanishNameCountsForLocation(location l) -{ - Banish [int] banishes_active = BanishesActive(); - - string [monster] names; - foreach key, banish in banishes_active { - if (banish.banished_monster.is_banished()) { //zuko wrote this code - names[banish.banished_monster] = banish.banish_source; - } - } - - int [string] banish_name_counts; - foreach key, m in l.get_monsters() { - if (names contains m) - banish_name_counts[names[m]] += 1; - if (my_path().id == PATH_ONE_CRAZY_RANDOM_SUMMER) { - foreach m2 in names { - if (m2.to_string().to_lower_case().contains_text(m.to_string().to_lower_case())) //FIXME complete hack, wrong, substrings, 1337, etc - banish_name_counts[names[m2]] += 1; - } - } - } - return banish_name_counts; -} - -boolean [string] activeBanishNamesForLocation(location l) -{ - boolean [string] result; - - foreach banish_name, count in l.activeBanishNameCountsForLocation() - result[banish_name] = (count > 0); - return result; -} - -Banish BanishByName(string name) -{ - foreach key, banish in BanishesActive() { - if (banish.banish_source == name) - return banish; - } - Banish blank; - return blank; -} - -int BanishLength(string banish_name) -{ - int length = __banish_source_length[banish_name.to_lower_case()]; - if (length < 0) - length = 2147483647; - return length; -} - -boolean BanishIsActive(string name) -{ - foreach key, banish in BanishesActive() { - if (banish.banish_source == name) - return true; - } - return false; -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Support/Campground.ash b/Source/relay/TourGuide/Support/Campground.ash deleted file mode 100644 index 466f4574..00000000 --- a/Source/relay/TourGuide/Support/Campground.ash +++ /dev/null @@ -1,154 +0,0 @@ -import "relay/TourGuide/Support/HTML.ash" - -record RestingBonus -{ - string header; - effect given_effect; - int duration; - int limit; - - //Special cases that have particularities not worth mentioning other than setting a quick boolean - boolean tasteful; //needs 1 or 0 adv. left of its given effect, and breaks after 3-5 uses -}; - - -RestingBonus RestingBonusMake(string header, effect given_effect, int duration, int limit) -{ - RestingBonus result; - result.header = header; - result.given_effect = given_effect; - result.duration = duration; - result.limit = limit; - - return result; -} - -RestingBonus RestingBonusMake(string header, effect given_effect, int duration) -{ - return RestingBonusMake(header, given_effect, duration, 0); -} - -RestingBonus RestingBonusMake(string header, int duration) -{ - return RestingBonusMake(header, $effect[none], duration); -} - -RestingBonus RestingBonusMake(string header) -{ - return RestingBonusMake(header, 0); -} - -RestingBonus RestingBonusMake() -{ - return RestingBonusMake(""); -} - -RestingBonus RestingBonusIsTasteful(RestingBonus RB) -{ - RB.tasteful = true; - return RB; -} - -RestingBonus [item] __resting_bonuses; -int [item] __campground = get_campground(); - -void RestingBonusInit() -{ - int holiday_bliss_givers = 0; - int [int] holiday_bliss = {1:5, 2:10, 3:20, 4:50}; - foreach furniture in __campground { - switch (furniture) { - /* - //want to be sure I have EVERYTHING - //The "useless to this situation" - case $item[big rock]: case $item[Newbiesport™ tent]: case $item[Barskin tent]: case $item[Cottage]: case $item[Frobozz Real-Estate Company Instant House (TM)]: case $item[Sandcastle]: case $item[House of twigs and spit]: - case $item[Beanbag chair]: case $item[bed of coals]: case $item[comfy coffin]: case $item[filth-encrusted futon]: case $item[frigid air mattress]: case $item[stained mattress]: case $item[gauze hammock]: case $item[sleeping stocking]: case $item[saltwaterbed]: - case $item[Meat Maid]: case $item[Clockwork Maid]: - case $item[Meat golem]: - case $item[Spooky scarecrow]: - case $item[Certificate of Participation]: - case $item[Feng Shui for Big Dumb Idiots]: - case $item[pagoda plans]: - case $item[Bonsai tree]: - case $item[Cuckoo clock]: - case $item[Tin roof (rusted)]: - case $item[Meat globe]: - case $item[Picture of you]: - case $item[E-Z Cook™ oven]: case $item[Dramatic™ range]: - case $item[My First Shaker™]: case $item[Queue Du Coq cocktailcrafting kit]: - case $item[Sushi-rolling mat]: - case $item[chef-in-the-box]: case $item[Clockwork Chef-in-the-box]: - case $item[Bartender-in-the-box]: case $item[Clockwork Bartender-in-the-box]: - case $item[Discount Telescope Warehouse gift certificate]: - case $item[Haunted doghouse]: - case $item[Potted tea tree]: - case $item[Source terminal]: - case $item[Witchess Set]: - case $item[Asdon Martin keyfob]: case $item[Portable Mayo Clinic]: case $item[Little Geneticist DNA-Splicing Lab]: case $item[Diabolic pizza cube]: case $item[Warbear LP-ROM burner]: case $item[Warbear jackhammer drill press]: case $item[Warbear induction oven]: case $item[Warbear high-efficiency still]: case $item[Warbear chemistry lab]: case $item[Warbear auto-anvil]: case $item[Spinning wheel]: case $item[Snow machine]: - case $item[jar of psychoses (The Crackpot Mystic)]: case $item[jar of psychoses (The Captain of the Gourd)]: case $item[jar of psychoses (The Meatsmith)]: case $item[jar of psychoses (The Pretentious Artist)]: case $item[jar of psychoses (The Suspicious-Looking Guy)]: case $item[jar of psychoses (The Old Man)]: case $item[jar of psychoses (Jick)]: - case $item[El Vibrato trapezoid]: - case $item[packet of pumpkin seeds]: case $item[Peppermint Pip Packet]: case $item[packet of dragon's teeth]: case $item[packet of beer seeds]: case $item[packet of winter seeds]: case $item[packet of thanksgarden seeds]: case $item[packet of tall grass seeds]: case $item[packet of mushroom spores]: - break; - default: - __resting_bonuses[furniture] = RestingBonusMake(); //they are in a mafia version where mafia recognizes the campground furniture, but we didn't add it to this list yet - break; - */ //Bad idea. get_campground() also lists what you'd get out of your campground at any given point, as items, and that looks too boring to list. Was already getting a lot anyway. Not deleted just in case - case $item[Giant pilgrim hat]: - __resting_bonuses[$item[Giant pilgrim hat]] = RestingBonusMake("a random effect", 15); - break; - case $item[BRICKO pyramid]: - __resting_bonuses[$item[BRICKO pyramid]] = RestingBonusMake("+100% weapon/spell dmg", $effect[Pyramid Power], 20, 3); - break; - case $item[Ginormous pumpkin]: - __resting_bonuses[$item[Ginormous pumpkin]] = RestingBonusMake("+20% Item, +10 Spooky Dmg, +10 ML", $effect[Juiced and Jacked], 10, 1); - break; - case $item[Giant Faraday cage]: - __resting_bonuses[$item[Giant Faraday cage]] = RestingBonusMake("+50 MP, 5-8 MP regen", $effect[Uncaged Power], 30, 1); - break; - case $item[Snow fort]: - __resting_bonuses[$item[Snow fort]] = RestingBonusMake("+25% Item, +50% Meat, +100 HP, +50 MP", $effect[Snow Fortified], 10, 1); - break; - case $item[Elevent]: - __resting_bonuses[$item[Elevent]] = RestingBonusMake("+11% stats, +11% init, +11% item, +11% meat, +11 weapon/spell dmg, +11 HP/MP, +11 DR", $effect[It's Ridiculous], 11, 1); - break; - case $item[Gingerbread house]: - case $item[Crimbo wreath]: - case $item[string of Crimbo lights]: - case $item[plastic Crimbo reindeer]: - __resting_bonuses[$item[Gingerbread house]] = RestingBonusMake("+20% Item, +20% Meat", $effect[Holiday Bliss], holiday_bliss [++holiday_bliss_givers], 1); - break; - case $item[Hobo fortress blueprints]: - __resting_bonuses[$item[Hobo fortress blueprints]] = RestingBonusMake("+5 hobo power", $effect[Hobonic], 10); - break; - case $item[Xiblaxian residence-cube]: - __resting_bonuses[$item[Xiblaxian residence-cube]] = RestingBonusMake("+100 MP, 10-20 MP regen", $effect[Hypercubed], 50, 1); - break; - case $item[House-sized mushroom]: - __resting_bonuses[$item[House-sized mushroom]] = RestingBonusMake("+25% stats, +25% init, +1 all res", $effect[Mushed], 20, 1); - break; - case $item[Lazybones™ recliner]: - __resting_bonuses[$item[Lazybones™ recliner]] = RestingBonusMake("+25% stats, +25 spooky dmg", $effect[Bonelording], 20, 1); - break; - case $item[Spirit bed]: - __resting_bonuses[$item[Spirit bed]] = RestingBonusMake("+20% MP", $effect[Spirit Schooled], 20, 1); - break; - case $item[Lucky cat statue]: - __resting_bonuses[$item[Lucky cat statue]] = RestingBonusMake("+5% Item", $effect[Lucky Cat Is Lucky], 5, 1); //SETS the remaining duration of that effect to 5 adv - break; - case $item[Confusing LED clock]: - __resting_bonuses[$item[Confusing LED clock]] = RestingBonusMake(HTMLGenerateSpanFont("+5 PVP fights, -5 adventures", "red"), $effect[none], 0, 1); - break; - case $item[Black-and-blue light]: - __resting_bonuses[$item[Black-and-blue light]] = RestingBonusMake("2-5 HP regen", $effect[Less Vincible], 5).RestingBonusIsTasteful(); - break; - case $item[Blue plasma ball]: - __resting_bonuses[$item[Blue plasma ball]] = RestingBonusMake("1-5 phys. react. passive dmg", $effect[Stuck-Up Hair], 5).RestingBonusIsTasteful(); - break; - case $item[Loudmouth Larry Lamprey]: - __resting_bonuses[$item[Loudmouth Larry Lamprey]] = RestingBonusMake("3-5 MP regen", $effect[In Tuna], 5).RestingBonusIsTasteful(); - break; - } - } -} - -RestingBonusInit(); diff --git a/Source/relay/TourGuide/Support/Checklist.ash b/Source/relay/TourGuide/Support/Checklist.ash deleted file mode 100644 index f7d0e1c9..00000000 --- a/Source/relay/TourGuide/Support/Checklist.ash +++ /dev/null @@ -1,849 +0,0 @@ -import "relay/TourGuide/Support/HTML.ash" -import "relay/TourGuide/Support/KOLImage.ash" -import "relay/TourGuide/Support/List.ash" -import "relay/TourGuide/Support/Page.ash" -import "relay/TourGuide/Support/Library.ash" -import "relay/TourGuide/Settings.ash" - - -record ChecklistSubentry -{ - string header; - string [int] modifiers; - string [int] entries; -}; - - -ChecklistSubentry ChecklistSubentryMake(string header, string [int] modifiers, string [int] entries) -{ - boolean all_subentries_are_empty = true; - foreach key in entries - { - if (entries[key] != "") - all_subentries_are_empty = false; - } - ChecklistSubentry result; - result.header = header; - result.modifiers = modifiers; - if (!all_subentries_are_empty) - result.entries = entries; - return result; -} - -ChecklistSubentry ChecklistSubentryMake(string header, string modifiers, string [int] entries) -{ - if (modifiers == "") - return ChecklistSubentryMake(header, listMakeBlankString(), entries); - else - return ChecklistSubentryMake(header, listMake(modifiers), entries); -} - - -ChecklistSubentry ChecklistSubentryMake(string header, string [int] entries) -{ - return ChecklistSubentryMake(header, listMakeBlankString(), entries); -} - -ChecklistSubentry ChecklistSubentryMake(string header, string [int] modifiers, string e1) -{ - return ChecklistSubentryMake(header, modifiers, listMake(e1)); -} - -ChecklistSubentry ChecklistSubentryMake(string header, string [int] modifiers, string e1, string e2) -{ - return ChecklistSubentryMake(header, modifiers, listMake(e1, e2)); -} - - -ChecklistSubentry ChecklistSubentryMake(string header, string modifiers, string e1) -{ - if (modifiers == "") - return ChecklistSubentryMake(header, listMakeBlankString(), listMake(e1)); - else - return ChecklistSubentryMake(header, listMake(modifiers), listMake(e1)); -} - -ChecklistSubentry ChecklistSubentryMake(string header) -{ - return ChecklistSubentryMake(header, "", ""); -} - -void listAppend(ChecklistSubentry [int] list, ChecklistSubentry entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listPrepend(ChecklistSubentry [int] list, ChecklistSubentry entry) -{ - int position = 0; - while (list contains position) - position -= 1; - list[position] = entry; -} - -ChecklistSubentry [int] listMake(ChecklistSubentry e1) -{ - ChecklistSubentry [int] result; - result.listAppend(e1); - return result; -} - - -record TagGroup -{ - string id; //For the "minimize" feature to keep track of the entries. Uses 'combination' instead if present. Uses the first entry's header if empty. - string combination; //Entries with identical combination tags will be combined into one, with the "first" taking precedence. -}; - -int CHECKLIST_DEFAULT_IMPORTANCE = 0; -record ChecklistEntry -{ - string image_lookup_name; - string url; - string [string] container_div_attributes; - ChecklistSubentry [int] subentries; - TagGroup tags; //meta-informations about the entry - boolean should_indent_after_first_subentry; - - boolean should_highlight; - - int importance_level; //Entries will be resorted by importance level before output, ascending order. Default importance is 0. Convention is to vary it from [-11, 11] for reasons that are clear and well supported in the narrative. - boolean only_show_as_extra_important_pop_up; //only valid if -11 importance or lower - only shows up as a pop-up, meant to inform the user they can scroll up to see something else (semi-rares) - ChecklistSubentry [int] subentries_on_mouse_over; //replaces subentries -}; - - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string url, ChecklistSubentry [int] subentries, TagGroup tags, int importance, boolean should_highlight) -{ - ChecklistEntry result; - result.image_lookup_name = image_lookup_name; - result.url = url; - result.subentries = subentries; - result.tags = tags; - result.importance_level = importance; - result.should_highlight = should_highlight; - return result; -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, TagGroup tags, int importance) -{ - return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, importance, false); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, TagGroup tags, int importance, boolean [location] highlight_if_last_adventured) -{ - boolean should_highlight = false; - - if (highlight_if_last_adventured contains __last_adventure_location) - should_highlight = true; - return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, importance, should_highlight); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, TagGroup tags) -{ - return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, CHECKLIST_DEFAULT_IMPORTANCE); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, TagGroup tags, boolean [location] highlight_if_last_adventured) -{ - return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, CHECKLIST_DEFAULT_IMPORTANCE, highlight_if_last_adventured); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, TagGroup tags, int importance) -{ - ChecklistSubentry [int] subentries; - subentries[subentries.count()] = subentry; - return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, importance); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, TagGroup tags, int importance, boolean [location] highlight_if_last_adventured) -{ - ChecklistSubentry [int] subentries; - subentries[subentries.count()] = subentry; - return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, importance, highlight_if_last_adventured); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, TagGroup tags) -{ - return ChecklistEntryMake(image_lookup_name, target_location, subentry, tags, CHECKLIST_DEFAULT_IMPORTANCE); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, TagGroup tags, boolean [location] highlight_if_last_adventured) -{ - ChecklistSubentry [int] subentries; - subentries[subentries.count()] = subentry; - return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, CHECKLIST_DEFAULT_IMPORTANCE, highlight_if_last_adventured); -} - - -//should we remove these? Players may have build their own ChecklistEntries, so if we do, we'd put a warning here during a release, and officially remove them on the next. -// Considering YOUR speed (yes, you, you know who you are), they'll have, what... a year..? <_< -// ... to change their custom ChecklistEntry / make the right edit(s) -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string url, ChecklistSubentry [int] subentries, int importance, boolean should_highlight) -{ - TagGroup tags; - return ChecklistEntryMake(image_lookup_name, url, subentries, tags, importance, should_highlight); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, int importance) -{ - return ChecklistEntryMake(image_lookup_name, target_location, subentries, importance, false); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, int importance, boolean [location] highlight_if_last_adventured) -{ - boolean should_highlight = false; - - if (highlight_if_last_adventured contains __last_adventure_location) - should_highlight = true; - return ChecklistEntryMake(image_lookup_name, target_location, subentries, importance, should_highlight); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries) -{ - return ChecklistEntryMake(image_lookup_name, target_location, subentries, CHECKLIST_DEFAULT_IMPORTANCE); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, boolean [location] highlight_if_last_adventured) -{ - return ChecklistEntryMake(image_lookup_name, target_location, subentries, CHECKLIST_DEFAULT_IMPORTANCE, highlight_if_last_adventured); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, int importance) -{ - ChecklistSubentry [int] subentries; - subentries[subentries.count()] = subentry; - return ChecklistEntryMake(image_lookup_name, target_location, subentries, importance); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, int importance, boolean [location] highlight_if_last_adventured) -{ - ChecklistSubentry [int] subentries; - subentries[subentries.count()] = subentry; - return ChecklistEntryMake(image_lookup_name, target_location, subentries, importance, highlight_if_last_adventured); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry) -{ - return ChecklistEntryMake(image_lookup_name, target_location, subentry, CHECKLIST_DEFAULT_IMPORTANCE); -} - -ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, boolean [location] highlight_if_last_adventured) -{ - ChecklistSubentry [int] subentries; - subentries[subentries.count()] = subentry; - return ChecklistEntryMake(image_lookup_name, target_location, subentries, CHECKLIST_DEFAULT_IMPORTANCE, highlight_if_last_adventured); -} - -//Secondary level of making checklist entries; setting properties and returning them. -ChecklistEntry ChecklistEntrySetIDTag(ChecklistEntry e, string id) -{ - e.tags.id = id; - return e; -} - -ChecklistEntry ChecklistEntrySetCombinationTag(ChecklistEntry e, string tag) -{ - e.tags.combination = tag; - return e; -} - - -void listAppend(ChecklistEntry [int] list, ChecklistEntry entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppendList(ChecklistEntry [int] list, ChecklistEntry [int] entries) -{ - foreach key in entries - list.listAppend(entries[key]); -} - -void listClear(ChecklistEntry [int] list) -{ - foreach i in list - { - remove list[i]; - } -} - - -record Checklist -{ - string title; - ChecklistEntry [int] entries; - - boolean disable_generating_id; //disable generating checklist anchor and title-based div identifier -}; - - -Checklist ChecklistMake(string title, ChecklistEntry [int] entries) -{ - Checklist cl; - cl.title = title; - cl.entries = entries; - return cl; -} - -Checklist ChecklistMake() -{ - Checklist cl; - return cl; -} - -void listAppend(Checklist [int] list, Checklist entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listRemoveKeys(Checklist [int] list, int [int] keys_to_remove) -{ - foreach i in keys_to_remove - { - int key = keys_to_remove[i]; - if (!(list contains key)) - continue; - remove list[key]; - } -} - - -string ChecklistGenerateModifierSpan(string [int] modifiers) -{ - if (modifiers.count() == 0) - return ""; - return HTMLGenerateSpanOfClass(modifiers.listJoinComponents(", "), "r_cl_modifier"); -} - -string ChecklistGenerateModifierSpan(string checklist_modifier) //no longer span, but I'm sure as hell not gonna change every instance of it :V -{ - return HTMLGenerateDivOfClass(checklist_modifier, "r_cl_modifier"); -} - - -void ChecklistInit() -{ - PageAddCSSClass("a", "r_cl_internal_anchor", ""); - PageAddCSSClass("", "r_cl_modifier_inline", "font-size:0.85em; color:" + __setting_modifier_colour + ";"); - PageAddCSSClass("", "r_cl_modifier", "font-size:0.85em; color:" + __setting_modifier_colour + "; display:block;"); - - PageAddCSSClass("", "r_cl_header", "text-align:center; font-size:1.15em; font-weight:bold;"); - PageAddCSSClass("", "r_cl_subheader", "font-size:1.07em; font-weight:bold;"); - PageAddCSSClass("", "r_cl_entry_id", "font-size:1.07em; font-weight:bold; display:none;"); - PageAddCSSClass("div", "r_cl_entry_first_subheader", "display:flex;flex-direction:row;align-items:flex-start;width:100%;"); - PageAddCSSClass("div", "r_cl_entry_container", "display:flex; flex-direction:row; align-items:flex-start; padding-top: var(--cl_entry_container_padding); padding-bottom: var(--cl_entry_container_padding);"); - - string gradient = "background: #ffffff;background: -moz-linear-gradient(left, #ffffff 50%, #F0F0F0 75%, #F0F0F0 100%);background: -webkit-gradient(linear, left top, right top, color-stop(50%,#ffffff), color-stop(75%,#F0F0F0), color-stop(100%,#F0F0F0));background: -webkit-linear-gradient(left, #ffffff 50%,#F0F0F0 75%,#F0F0F0 100%);background: -o-linear-gradient(left, #ffffff 50%,#F0F0F0 75%,#F0F0F0 100%);background: -ms-linear-gradient(left, #ffffff 50%,#F0F0F0 75%,#F0F0F0 100%);background: linear-gradient(to right, #ffffff 50%,#F0F0F0 75%,#F0F0F0 100%);filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#F0F0F0',GradientType=1 );"; //help - PageAddCSSClass("", "container_highlighted", gradient + "margin-right: calc(0px - var(--cl_container_padding)); padding-right: var(--cl_container_padding);"); //counter the checklist_container's padding, so that the gradient won't stop mid-way - PageAddCSSClass("", "close_highlight", "margin-right: calc(0px - var(--cl_container_padding)); padding-right: var(--cl_container_padding);"); - - PageAddCSSClass("div", "r_cl_entry_image", "width: var(--image-width); flex:none;"); - PageAddCSSClass("div", "r_cl_entry_content_container", "flex-grow:1;display:flex;flex-direction:column;text-align:left;align-items:flex-start;"); - PageAddCSSClass("", "hr_like", "border: 0px; border-top: 1px; border-style:solid; border-color: " + __setting_line_colour + ";"); - - //subentries-on-mouseover - PageAddCSSClass("", "r_cl_entry_content_container.entry_hoverable", ""); - PageAddCSSClass("", "r_cl_entry_content_container.entry_hovered", "display:none;"); - PageAddCSSClass("", "r_cl_entry_container:hover .r_cl_entry_content_container.entry_hoverable", "display:none;"); - PageAddCSSClass("", "r_cl_entry_container:hover .r_cl_entry_content_container.entry_hovered", "display:flex;"); - - //collapsing feature - PageAddCSSClass("button", "r_cl_minimize_button", "background-color:antiquewhite;padding:0px;font-size:11px;height:18px;width:18px;flex-shrink:0;position:relative;z-index:2;color:#7F7F7F;cursor:pointer;"); - PageAddCSSClass("button", "r_cl_minimize_button:hover", "background-color:black;"); - - if (true) - { - PageAddCSSClass("", "#Guide_body.opacity_full .r_cl_entry_container.r_cl_collapsed .r_cl_entry_image" - + ", #Guide_body.opacity_full .r_cl_entry_container.r_cl_collapsed .r_cl_subheader" - + ", #Guide_body.opacity_full .r_cl_entry_container.r_cl_collapsed .r_cl_modifier", "opacity:1;"); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_full .r_cl_entry_image" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_full .r_cl_subheader" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_full .r_cl_modifier", "opacity:1;", 1); - - PageAddCSSClass("", "#Guide_body.opacity_half .r_cl_entry_container.r_cl_collapsed .r_cl_entry_image" - + ", #Guide_body.opacity_half .r_cl_entry_container.r_cl_collapsed .r_cl_subheader" - + ", #Guide_body.opacity_half .r_cl_entry_container.r_cl_collapsed .r_cl_modifier", "opacity:0.5;"); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_half .r_cl_entry_image" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_half .r_cl_subheader" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_half .r_cl_modifier", "opacity:0.5;", 1); - - - //.image_auto on #Guide_body is already the normal behaviour, so don't do anything here (THANKFULLY). - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_large", "display:block;", 1, __setting_media_query_large_size); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_medium" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_small", "display:none;", 1, __setting_media_query_large_size); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_medium", "display:block;", 1, __setting_media_query_medium_size); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_large" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_small", "display:none;", 1, __setting_media_query_medium_size); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_small", "display:block;", 1, __setting_media_query_small_size); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_large" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_medium", "display:none;" , 1, __setting_media_query_small_size); - - PageAddCSSClass("", "#Guide_body.image_none .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_large" - + ", #Guide_body.image_none .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_medium" - + ", #Guide_body.image_none .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_small", "display:none;"); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_none .r_cl_image_container_large" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_none .r_cl_image_container_medium" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_none .r_cl_image_container_small", "display:none;", 1); - - PageAddCSSClass("", "#Guide_body.image_small .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_large" - + ", #Guide_body.image_small .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_medium", "display:none;"); - PageAddCSSClass("", "#Guide_body.image_small .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_small", "display:block;"); - PageAddCSSClass("", "#Guide_body.image_small .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_small", "display:none;", 0, __setting_media_query_tiny_size); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_small .r_cl_image_container_large" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_small .r_cl_image_container_medium", "display:none;", 1); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_small .r_cl_image_container_small", "display:block;", 1); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_small .r_cl_image_container_small", "display:none;", 1, __setting_media_query_tiny_size); - - - PageAddCSSClass("", "#Guide_body.collapsing_entries .r_cl_entry_container.r_cl_collapsed .r_cl_subheader" - + ", #Guide_body.collapsing_entries .r_cl_entry_container.r_cl_collapsed .r_cl_modifier", "display:block;"); - PageAddCSSClass("", "#Guide_body.collapsing_entries .r_cl_entry_container.r_cl_collapsed .r_cl_entry_id", "display:none;"); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_entries .r_cl_subheader" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_entries .r_cl_modifier", "display:block;", 1); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_entries .r_cl_entry_id", "display:none;", 1); - - PageAddCSSClass("", "#Guide_body.collapsing_modifiers .r_cl_entry_container.r_cl_collapsed .r_cl_subheader", "display:block;"); - PageAddCSSClass("", "#Guide_body.collapsing_modifiers .r_cl_entry_container.r_cl_collapsed .r_cl_modifier" - + ", #Guide_body.collapsing_modifiers .r_cl_entry_container.r_cl_collapsed .r_cl_entry_id", "display:none;"); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_modifiers .r_cl_subheader", "display:block;", 1); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_modifiers .r_cl_modifier" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_modifiers .r_cl_entry_id", "display:none;", 1); - - PageAddCSSClass("", "#Guide_body.collapsing_replace .r_cl_entry_container.r_cl_collapsed .r_cl_subheader" - + ", #Guide_body.collapsing_replace .r_cl_entry_container.r_cl_collapsed .r_cl_modifier", "display:none;"); - PageAddCSSClass("", "#Guide_body.collapsing_replace .r_cl_entry_container.r_cl_collapsed .r_cl_entry_id", "display:block;"); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_replace .r_cl_subheader" - + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_replace .r_cl_modifier", "display:none;", 1); - PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_replace .r_cl_entry_id", "display:block;", 1); - - PageAddCSSClass("", "r_cl_entry_container.r_cl_collapsed .r_cl_collapsable", "display:none;"); - } - - - PageAddCSSClass("", "r_cl_image_container_large", "display:block;"); - PageAddCSSClass("", "r_cl_image_container_medium", "display:none;"); - PageAddCSSClass("", "r_cl_image_container_small", "display:none;"); - - PageAddCSSClass("div", "r_cl_checklist_container", "margin:0px; padding-left: var(--cl_container_padding); padding-right: var(--cl_container_padding); border:1px; border-style: solid; border-color:" + __setting_line_colour + ";border-left:0px; border-right:0px;background-color:#FFFFFF; padding-top:5px;"); - - //media queries: - if (true) - { - PageAddCSSClass("", "r_cl_image_container_large", "display:none", 0, __setting_media_query_medium_size); - PageAddCSSClass("", "r_cl_image_container_medium", "display:block;", 0, __setting_media_query_medium_size); - PageAddCSSClass("", "r_cl_image_container_small", "display:none;", 0, __setting_media_query_medium_size); - - PageAddCSSClass("", "r_cl_image_container_large", "display:none", 0, __setting_media_query_small_size); - PageAddCSSClass("", "r_cl_image_container_medium", "display:none;", 0, __setting_media_query_small_size); - PageAddCSSClass("", "r_cl_image_container_small", "display:block;", 0, __setting_media_query_small_size); - - PageAddCSSClass("", "r_cl_image_container_large", "display:none", 0, __setting_media_query_tiny_size); - PageAddCSSClass("", "r_cl_image_container_medium", "display:none;", 0, __setting_media_query_tiny_size); - PageAddCSSClass("", "r_cl_image_container_small", "display:none;", 0, __setting_media_query_tiny_size); - - - PageAddCSSClass("", "r_indention", "margin-left:" + (__setting_indention_width_in_em / 2.0) + "em;", 0, __setting_media_query_small_size); - PageAddCSSClass("", "r_indention", "margin-left:" + (__setting_indention_width_in_em / 2.0) + "em;", 0, __setting_media_query_tiny_size); - } -} - -//Creates if not found: -Checklist lookupChecklist(Checklist [int] checklists, string title) -{ - foreach key in checklists - { - Checklist cl = checklists[key]; - if (cl.title == title) - return cl; - } - //Not found, create one. - Checklist cl = ChecklistMake(); - cl.title = title; - checklists.listAppend(cl); - return cl; -} - -void ChecklistFormatSubentry(ChecklistSubentry subentry) { - foreach i in subentry.entries { - string [int] line_split = split_string_alternate(subentry.entries[i], "\\|"); - foreach l in line_split { - if (stringHasPrefix(line_split[l], "*")) { - // Indent - line_split[l] = HTMLGenerateIndentedText(substring(line_split[l], 1)); - } - } - - // Recombine - buffer building_line; - boolean first = true; - boolean last_was_indention = false; - foreach key in line_split { - string line = line_split[key]; - if (!contains_text(line, "class=\"r_indention\"") && !first && !last_was_indention) { - building_line.append("
"); - } - last_was_indention = contains_text(line, "class=\"r_indention\""); - building_line.append(line); - first = false; - } - subentry.entries[i] = to_string(building_line); - } -} - -buffer ChecklistEntryGenerateContentHTML(ChecklistEntry entry, ChecklistSubentry [int] subentries, string [string] anchor_attributes) { - buffer entry_content; - - string entry_id = entry.tags.id; - - boolean first = true; - boolean indented_after_first_subentry = false; - boolean entry_is_just_a_title = true; - foreach j, subentry in subentries { - if (subentry.header == "") - continue; - - if (first) - { - string subheader = HTMLGenerateSpanOfClass(subentry.header, "r_cl_subheader"); - subheader += HTMLGenerateSpanOfClass(entry_id, "r_cl_entry_id"); - - buffer first_subheader; - if (anchor_attributes.count() > 0 && !__setting_entire_area_clickable) - subheader = HTMLGenerateTagWrap("a", subheader, anchor_attributes); - first_subheader.append(subheader); - - //minimize button - boolean entry_has_content_to_minimize = false; - int indented_entries; - foreach j, subentry in subentries { - if (subentry.header == "") - continue; - - if (entry.should_indent_after_first_subentry) - indented_entries++; - if (subentry.entries.count() > 0 || indented_entries >= 2) { - entry_has_content_to_minimize = true; - break; - } - } - - first_subheader.append(HTMLGenerateTagWrap("div", "", string [string] {"style":"flex-grow:1;"})); //fill empty space to ensure the button(s) are on the right end - - if (entry_has_content_to_minimize) { - first_subheader.append(HTMLGenerateTagWrap("button", "▼", string [string] {"class":"r_cl_minimize_button toggle_" + entry_id,"alt":"Minimize","title":"Minimize","id":"toggle_" + entry_id,"onclick":"alterSubentryMinimization(event)", "oncontextmenu":"callSettingsContextualMenu(event)"})); - } - - entry_content.append(HTMLGenerateTagWrap("div", first_subheader, string [string] {"class":"r_cl_entry_first_subheader"})); - } - else if (entry.should_indent_after_first_subentry && !indented_after_first_subentry) - { - entry_content.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_indention r_cl_collapsable"))); // + entry_id - indented_after_first_subentry = true; - } - - if (anchor_attributes.count() > 0 && !__setting_entire_area_clickable) { - if (subentry.modifiers.count() + subentry.entries.count() > 0 && entry_is_just_a_title) { - entry_is_just_a_title = false; - entry_content.append(HTMLGenerateTagPrefix("a", anchor_attributes)); - } - } - - if (!first) - entry_content.append(HTMLGenerateDivOfClass(subentry.header, "r_cl_subheader")); - - if (subentry.modifiers.count() > 0) - entry_content.append(subentry.modifiers.listJoinComponents(", ").HTMLGenerateDivOfClass("r_indention r_cl_modifier")); - - if (subentry.entries.count() > 0) - { - buffer subentry_text; - for intra_k from 0 to subentry.entries.count() - 1 - { - if (intra_k > 0) - subentry_text.append("
"); - string line = subentry.entries[listKeyForIndex(subentry.entries, intra_k)]; - - subentry_text.append(line); - } - entry_content.append(HTMLGenerateTagWrap("div", subentry_text, mapMake("class", "r_indention" + (indented_after_first_subentry ? "" : " r_cl_collapsable") ))); // + entry_id - } - - first = false; - } - if (indented_after_first_subentry) - entry_content.append(""); - if (anchor_attributes.count() > 0 && !__setting_entire_area_clickable && !entry_is_just_a_title) - entry_content.append(""); - return entry_content; -} - -/** -Generates HTML for a checklist and appends it to the DOM -@param cl The checklist being appended to the DOM -@param output_borders Whether or not to add borders -*/ -buffer ChecklistGenerate(Checklist cl, boolean output_borders) { - ChecklistEntry [int] entries = cl.entries; - - //Combine entries with identical combination tags: - ChecklistEntry [string] combination_tag_entries; - foreach key, entry in entries { - if (entry.tags.combination == "") continue; - if (entry.only_show_as_extra_important_pop_up) continue; //do not support this feature with this - if (entry.should_indent_after_first_subentry) continue; - if (entry.subentries_on_mouse_over.count() > 0) continue; - if (entry.container_div_attributes.count() > 0) continue; - - entry.importance_level -= 1; //combined entries gain a hack; a level above everything else - - if (!(combination_tag_entries contains entry.tags.combination)) { - entry.tags.id = cl.title + "_" + entry.tags.combination; - combination_tag_entries[entry.tags.combination] = entry; - continue; - } - - ChecklistEntry master_entry = combination_tag_entries[entry.tags.combination]; - - if (entry.should_highlight) { - master_entry.should_highlight = true; - } - - if (master_entry.url == "" && entry.url != "") { - master_entry.url = entry.url; - } - - if (entry.importance_level < master_entry.importance_level) - { - master_entry.importance_level = entry.importance_level; - master_entry.image_lookup_name = entry.image_lookup_name; - if (entry.url != "") - master_entry.url = entry.url; - - //Put that entry's subentries at the start - ChecklistSubentry [int] new_master_subentries = entry.subentries; - foreach key, subentry in master_entry.subentries { - new_master_subentries.listAppend(subentry); - } - master_entry.subentries = new_master_subentries; - } - else - { - foreach key, subentry in entry.subentries { - master_entry.subentries.listAppend(subentry); - } - } - - remove entries[key]; - } - - //Sort by importance: - sort entries by value.importance_level; - - //Format subentries: - foreach index in entries { - ChecklistEntry entry = entries[index]; - foreach subentryIndex in entry.subentries { - ChecklistFormatSubentry(entry.subentries[subentryIndex]); - } - foreach subentryIndex in entry.subentries_on_mouse_over { - ChecklistFormatSubentry(entry.subentries_on_mouse_over[subentryIndex]); - } - } - - boolean skip_first_entry = false; - string special_subheader = ""; - if (entries.count() > 0) { - if (entries[0].image_lookup_name == "special subheader") { - if (entries[0].subentries.count() > 0) { - special_subheader = entries[0].subentries[0].header; - skip_first_entry = true; - } - } - } - - buffer result; - string [string] main_container_map; - main_container_map["class"] = "r_cl_checklist_container"; - if (!cl.disable_generating_id) - main_container_map["id"] = HTMLConvertStringToAnchorID(cl.title + " checklist container"); - if (output_borders) - main_container_map["style"] = "margin-top:12px;margin-bottom:24px;"; //spacing - else - main_container_map["style"] = "border:0px;"; - result.append(HTMLGenerateTagPrefix("div", main_container_map)); - - - string anchor = cl.title; - if (!cl.disable_generating_id) - anchor = HTMLGenerateTagWrap("a", "", mapMake("id", HTMLConvertStringToAnchorID(cl.title), "class", "r_cl_internal_anchor")) + cl.title; - - result.append(HTMLGenerateDivOfClass(anchor, "r_cl_header")); - - if (special_subheader != "") - result.append(ChecklistGenerateModifierSpan(special_subheader)); - - int starting_intra_i = 1; - if (skip_first_entry) - starting_intra_i++; - int intra_i = 0; - int entries_output = 0; - boolean last_was_highlighted = false; - foreach i, entry in entries - { - if (++intra_i < starting_intra_i) - continue; - entries_output++; - string [string] anchor_attributes; - if (entry.url != "") - anchor_attributes = {"target":"mainpane", "href":entry.url, "class":"r_a_undecorated"}; - - buffer entry_content; - string container_class = "r_cl_entry_container"; - if (entry.should_highlight) - container_class += " container_highlighted"; - if (intra_i > starting_intra_i) - { - container_class += " hr_like"; - if (last_was_highlighted && !entry.should_highlight) - container_class += " close_highlight"; - } - last_was_highlighted = entry.should_highlight; - - if (true) //"Correct" the entry ID - { - string entry_id; - if (entry.tags.combination != "") //not supposed to happen, but still can - entry_id = entry.tags.combination; - else if (entry.tags.id != "") - entry_id = entry.tags.id; - else - entry_id = "unIDed_" + entry.subentries[0].header; - entry_id = create_matcher("[ \\-.,#]", entry_id).replace_all("_"); - entry.tags.id = entity_encode(entry_id); - } - - buffer image_container; - - if (true) //image - { - image_container.append(KOLImageGenerateImageHTML(entry.image_lookup_name, true, Vec2iMake(__setting_image_width_large, 75), "r_cl_image_container_large")); - image_container.append(KOLImageGenerateImageHTML(entry.image_lookup_name, true, Vec2iMake(__setting_image_width_medium, 50), "r_cl_image_container_medium")); - image_container.append(KOLImageGenerateImageHTML(entry.image_lookup_name, true, Vec2iMake(__setting_image_width_small, 50), "r_cl_image_container_small")); - if (anchor_attributes.count() > 0 && !__setting_entire_area_clickable) - image_container = HTMLGenerateTagWrap("a", image_container, anchor_attributes); - image_container = HTMLGenerateTagWrap("div", image_container, mapMake("class", "r_cl_entry_image")); - } - - buffer content; - - if (true) //content (text) - { - string base_content = entry.ChecklistEntryGenerateContentHTML(entry.subentries, anchor_attributes); - if (entry.subentries_on_mouse_over.count() == 0) - base_content = HTMLGenerateTagWrap("div", base_content, mapMake("class", "r_cl_entry_content_container")); - else - { - base_content = HTMLGenerateTagWrap("div", base_content, mapMake("class", "r_cl_entry_content_container entry_hoverable")); - - string hover_content = entry.ChecklistEntryGenerateContentHTML(entry.subentries_on_mouse_over, anchor_attributes); - hover_content = HTMLGenerateTagWrap("div", hover_content, mapMake("class", "r_cl_entry_content_container entry_hovered")); - content.append(hover_content); - } - content.append(base_content); - } - - buffer generated_subentry_html; - generated_subentry_html.append(image_container); - generated_subentry_html.append(content); - - if (entry.container_div_attributes contains "class") - { - if (!entry.container_div_attributes["class"].contains_text(container_class)) //can happen with entries being pinned in the importance bar, passing here twice - entry.container_div_attributes["class"] += " " + container_class; - } - else - entry.container_div_attributes["class"] = container_class; - entry.container_div_attributes["class"] += " " + entry.tags.id; - entry_content.append(HTMLGenerateTagWrap("div", generated_subentry_html, entry.container_div_attributes)); - - - if (anchor_attributes.count() > 0 && __setting_entire_area_clickable) - entry_content = HTMLGenerateTagWrap("a", entry_content, anchor_attributes); - - result.append(entry_content); - } - result.append(""); - - return result; -} - -/** -Attaches checklist to DOM. -@param checklist The checklist being appended. -*/ -buffer ChecklistGenerate(Checklist checklist) { - return ChecklistGenerate(checklist, true); -} - - -Record ChecklistCollection -{ - Checklist [string] checklists; -}; - -//NOTE: WILL DESTRUCTIVELY EDIT CHECKLISTS GIVEN TO IT -//mostly because there's no easy way to copy an object in ASH -//without manually writing a copy function and insuring it is synched -Checklist [int] ChecklistCollectionMergeWithLinearList(ChecklistCollection collection, Checklist [int] other_checklists) -{ - Checklist [int] result; - - boolean [string] seen_titles; - foreach key, checklist in other_checklists - { - seen_titles[checklist.title] = true; - result.listAppend(checklist); - } - foreach key, checklist in collection.checklists - { - if (seen_titles contains checklist.title) - { - foreach key, checklist2 in result - { - if (checklist2.title == checklist.title) - { - checklist2.entries.listAppendList(checklist.entries); - break; - } - } - } - else - { - result.listAppend(checklist); - } - } - - return result; -} - -Checklist lookup(ChecklistCollection collection, string name) -{ - if (collection.checklists contains name) - return collection.checklists[name]; - - Checklist c = ChecklistMake(); - c.title = name; - collection.checklists[c.title] = c; - return c; -} diff --git a/Source/relay/TourGuide/Support/Cornucopias.ash b/Source/relay/TourGuide/Support/Cornucopias.ash deleted file mode 100644 index d5430ccb..00000000 --- a/Source/relay/TourGuide/Support/Cornucopias.ash +++ /dev/null @@ -1,27 +0,0 @@ -static -{ - int [int][string] __thanksgarden_cornucopia_rewards = {15:{"raw stuffing":1,"raw sweet potato":1,"cashew":5},18:{"raw mincemeat":1,"raw sweet potato":1,"raw stuffing":1,"cashew":4},21:{"raw cranberry sauce":1,"raw gravy":1,"raw mincemeat":1,"raw potato":1,"raw sweet potato":1,"cashew":2},24:{"raw stuffing":1,"raw bread":1,"cashew":5},27:{"raw turkey":1,"raw bread":1,"raw stuffing":1,"raw potato":1,"cashew":3},30:{"raw sweet potato":1,"raw green beans":1,"raw mincemeat":1,"cashew":4},33:{"raw sweet potato":1,"raw mincemeat":1,"raw bread":1,"raw gravy":1,"raw green beans":1,"cashew":2},36:{"raw turkey":1,"raw sweet potato":1,"raw green beans":1,"cashew":4},39:{"raw cranberry sauce":1,"raw potato":1,"raw sweet potato":1,"cashew":4},42:{"raw bread":1,"raw mincemeat":1,"raw cranberry sauce":1,"raw potato":1,"cashew":3},45:{"raw potato":1,"raw green beans":1,"cashew":5},48:{"raw green beans":1,"raw cranberry sauce":1,"raw bread":1,"raw mincemeat":1,"raw turkey":1,"cashew":2},51:{"raw green beans":1,"raw mincemeat":1,"raw cranberry sauce":1,"cashew":4},54:{"raw sweet potato":1,"raw cranberry sauce":1,"raw gravy":1,"raw green beans":1,"cashew":3},57:{"raw gravy":1,"raw potato":1,"raw sweet potato":1,"raw stuffing":1,"raw cranberry sauce":1,"cashew":2},60:{"raw gravy":1,"raw cranberry sauce":1,"raw green beans":1,"raw mincemeat":1,"cashew":3},63:{"raw gravy":1,"raw turkey":1,"raw stuffing":1,"cashew":4},66:{"raw bread":1,"raw stuffing":1,"raw turkey":1,"raw gravy":1,"raw potato":1,"cashew":2},69:{"raw sweet potato":1,"raw mincemeat":1,"raw green beans":1,"raw stuffing":1,"cashew":3},72:{"raw sweet potato":1,"raw turkey":1,"raw bread":1,"raw mincemeat":1,"raw potato":1,"cashew":2},75:{"raw turkey":1,"raw gravy":1,"raw potato":1,"cashew":4},78:{"raw stuffing":1,"raw green beans":1,"raw bread":1,"raw sweet potato":1,"raw potato":1,"cashew":2},81:{"raw green beans":1,"raw bread":1,"raw stuffing":1,"raw potato":1,"cashew":3},84:{"raw cranberry sauce":1,"raw gravy":1,"raw bread":1,"raw turkey":1,"raw potato":1,"cashew":2},87:{"raw potato":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":4},90:{"raw sweet potato":1,"raw bread":1,"raw gravy":1,"raw cranberry sauce":1,"raw stuffing":1,"cashew":2},93:{"raw sweet potato":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":4},96:{"raw gravy":1,"raw turkey":1,"raw potato":1,"raw stuffing":1,"raw bread":1,"cashew":2},99:{"raw mincemeat":1,"raw green beans":1,"raw sweet potato":1,"cashew":4},102:{"raw potato":1,"raw green beans":1,"raw turkey":1,"cashew":4},105:{"raw potato":1,"raw cranberry sauce":1,"raw turkey":1,"raw bread":1,"raw gravy":1,"cashew":2},108:{"raw mincemeat":1,"raw cranberry sauce":1,"raw stuffing":1,"raw bread":1,"raw green beans":1,"cashew":2},111:{"raw turkey":1,"raw gravy":1,"raw green beans":1,"cashew":4},114:{"raw potato":1,"raw green beans":1,"raw bread":1,"raw turkey":1,"raw stuffing":1,"cashew":2},117:{"raw green beans":1,"raw sweet potato":1,"raw mincemeat":1,"raw turkey":1,"cashew":3},120:{"raw green beans":1,"raw gravy":1,"raw stuffing":1,"cashew":4},123:{"raw mincemeat":1,"raw cranberry sauce":1,"raw turkey":1,"cashew":4},126:{"raw sweet potato":1,"raw mincemeat":1,"raw stuffing":1,"raw potato":1,"raw cranberry sauce":1,"cashew":2},129:{"raw cranberry sauce":1,"raw turkey":1,"raw bread":1,"cashew":4},132:{"raw turkey":1,"raw mincemeat":1,"cashew":5},135:{"raw stuffing":1,"raw cranberry sauce":1,"raw turkey":1,"cashew":4},138:{"raw potato":1,"raw turkey":1,"raw stuffing":1,"cashew":4},141:{"raw potato":1,"raw gravy":1,"cashew":5},144:{"raw mincemeat":1,"raw stuffing":1,"raw cranberry sauce":1,"raw green beans":1,"raw turkey":1,"cashew":2},147:{"raw sweet potato":1,"raw stuffing":1,"raw turkey":1,"raw gravy":1,"cashew":3},150:{"raw green beans":1,"raw potato":1,"cashew":5},153:{"raw cranberry sauce":1,"raw sweet potato":1,"raw mincemeat":1,"raw turkey":1,"raw gravy":1,"cashew":2},156:{"raw potato":1,"raw sweet potato":1,"raw mincemeat":1,"raw turkey":1,"cashew":3},159:{"raw gravy":1,"raw cranberry sauce":1,"cashew":5},162:{"raw gravy":1,"raw potato":1,"raw bread":1,"raw mincemeat":1,"cashew":3},165:{"raw cranberry sauce":1,"raw stuffing":1,"cashew":5},168:{"raw cranberry sauce":1,"raw sweet potato":1,"raw potato":1,"cashew":4},171:{"raw gravy":1,"raw mincemeat":1,"raw bread":1,"cashew":4},174:{"raw mincemeat":1,"raw green beans":1,"raw sweet potato":1,"raw cranberry sauce":1,"cashew":3},177:{"raw green beans":1,"raw gravy":1,"raw mincemeat":1,"cashew":4},180:{"raw bread":1,"raw stuffing":1,"raw green beans":1,"cashew":4},183:{"raw gravy":1,"raw bread":1,"cashew":5},186:{"raw gravy":1,"raw green beans":1,"raw turkey":1,"cashew":4},189:{"raw cranberry sauce":1,"raw bread":1,"raw potato":1,"raw stuffing":1,"cashew":3},192:{"raw cranberry sauce":1,"raw gravy":1,"cashew":5},195:{"raw turkey":1,"raw gravy":1,"cashew":5},198:{"raw bread":1,"raw turkey":1,"raw green beans":1,"cashew":4},201:{"raw stuffing":1,"raw bread":1,"raw gravy":1,"raw potato":1,"raw cranberry sauce":1,"cashew":2},204:{"raw turkey":1,"raw cranberry sauce":1,"cashew":5},207:{"raw sweet potato":1,"raw green beans":1,"raw cranberry sauce":1,"cashew":4},210:{"raw turkey":1,"raw mincemeat":1,"raw stuffing":1,"raw cranberry sauce":1,"raw bread":1,"cashew":2},213:{"raw mincemeat":1,"raw gravy":1,"raw green beans":1,"raw turkey":1,"raw bread":1,"cashew":2},216:{"raw sweet potato":1,"raw turkey":1,"raw green beans":1,"raw stuffing":1,"raw potato":1,"cashew":2},219:{"raw gravy":1,"raw turkey":1,"raw potato":1,"raw green beans":1,"raw stuffing":1,"cashew":2},222:{"raw stuffing":1,"raw bread":1,"raw mincemeat":1,"cashew":4},225:{"raw stuffing":1,"raw green beans":1,"raw bread":1,"raw turkey":1,"cashew":3},228:{"raw turkey":1,"raw green beans":1,"raw sweet potato":1,"raw cranberry sauce":1,"cashew":3},231:{"raw cranberry sauce":1,"raw sweet potato":1,"cashew":5},234:{"raw cranberry sauce":1,"raw turkey":1,"raw bread":1,"raw sweet potato":1,"raw stuffing":1,"cashew":2},237:{"raw stuffing":1,"raw sweet potato":1,"cashew":5},240:{"raw stuffing":1,"raw potato":1,"raw sweet potato":1,"raw mincemeat":1,"cashew":3},243:{"raw green beans":1,"raw sweet potato":1,"raw gravy":1,"raw bread":1,"raw stuffing":1,"cashew":2},246:{"raw bread":1,"raw sweet potato":1,"raw stuffing":1,"raw green beans":1,"cashew":3},249:{"raw turkey":1,"raw gravy":1,"raw mincemeat":1,"cashew":4},252:{"raw potato":1,"raw cranberry sauce":1,"raw green beans":1,"raw stuffing":1,"raw turkey":1,"cashew":2},255:{"raw mincemeat":1,"raw gravy":1,"raw potato":1,"raw green beans":1,"cashew":3},258:{"raw turkey":1,"raw gravy":1,"raw mincemeat":1,"raw green beans":1,"raw stuffing":1,"cashew":2},261:{"raw cranberry sauce":1,"raw bread":1,"cashew":5},264:{"raw cranberry sauce":1,"raw turkey":1,"cashew":5},267:{"raw cranberry sauce":1,"raw sweet potato":1,"raw stuffing":1,"raw bread":1,"raw turkey":1,"cashew":2},270:{"raw stuffing":1,"raw turkey":1,"raw bread":1,"cashew":4},273:{"raw green beans":1,"raw gravy":1,"raw potato":1,"raw cranberry sauce":1,"raw turkey":1,"cashew":2},276:{"raw stuffing":1,"raw sweet potato":1,"cashew":5},279:{"raw gravy":1,"raw cranberry sauce":1,"raw potato":1,"cashew":4},282:{"raw potato":1,"raw bread":1,"raw sweet potato":1,"raw cranberry sauce":1,"cashew":3},285:{"raw cranberry sauce":1,"raw turkey":1,"raw stuffing":1,"raw mincemeat":1,"cashew":3},288:{"raw sweet potato":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":4},291:{"raw turkey":1,"raw bread":1,"raw gravy":1,"raw sweet potato":1,"raw mincemeat":1,"cashew":2},294:{"raw mincemeat":1,"raw turkey":1,"raw potato":1,"cashew":4},297:{"raw gravy":1,"raw green beans":1,"cashew":5},300:{"raw stuffing":1,"raw potato":1,"raw bread":1,"raw sweet potato":1,"cashew":3},22:{"raw potato":1,"raw mincemeat":1,"raw green beans":1,"raw cranberry sauce":1,"raw stuffing":1,"cashew":2},25:{"raw gravy":1,"raw turkey":1,"cashew":5},28:{"raw mincemeat":1,"raw green beans":1,"raw potato":1,"cashew":4},31:{"raw turkey":1,"raw cranberry sauce":1,"raw sweet potato":1,"raw green beans":1,"cashew":3},34:{"raw potato":1,"raw cranberry sauce":1,"raw gravy":1,"raw turkey":1,"raw bread":1,"cashew":2},37:{"raw cranberry sauce":1,"raw gravy":1,"cashew":5},40:{"raw mincemeat":1,"raw potato":1,"raw stuffing":1,"raw cranberry sauce":1,"cashew":3},43:{"raw stuffing":1,"raw mincemeat":1,"raw gravy":1,"raw potato":1,"raw sweet potato":1,"cashew":2},46:{"raw potato":1,"raw green beans":1,"cashew":5},49:{"raw mincemeat":1,"raw potato":1,"raw turkey":1,"raw gravy":1,"cashew":3},52:{"raw potato":1,"raw turkey":1,"cashew":5},55:{"raw gravy":1,"raw stuffing":1,"raw mincemeat":1,"raw sweet potato":1,"raw potato":1,"cashew":2},58:{"raw mincemeat":1,"raw green beans":1,"raw stuffing":1,"raw turkey":1,"cashew":3},61:{"raw sweet potato":1,"raw mincemeat":1,"cashew":5},64:{"raw bread":1,"raw stuffing":1,"raw turkey":1,"raw sweet potato":1,"cashew":3},67:{"raw potato":1,"raw bread":1,"raw sweet potato":1,"cashew":4},70:{"raw turkey":1,"raw stuffing":1,"cashew":5},73:{"raw stuffing":1,"raw gravy":1,"raw potato":1,"cashew":4},76:{"raw mincemeat":1,"raw sweet potato":1,"raw bread":1,"raw potato":1,"cashew":3},79:{"raw potato":1,"raw gravy":1,"raw turkey":1,"cashew":4},82:{"raw bread":1,"raw cranberry sauce":1,"raw green beans":1,"raw potato":1,"cashew":3},85:{"raw cranberry sauce":1,"raw green beans":1,"raw sweet potato":1,"cashew":4},88:{"raw mincemeat":1,"raw turkey":1,"raw gravy":1,"cashew":4},91:{"raw green beans":1,"raw potato":1,"raw bread":1,"raw gravy":1,"raw stuffing":1,"cashew":2},94:{"raw turkey":1,"raw mincemeat":1,"raw gravy":1,"cashew":4},97:{"raw bread":1,"raw green beans":1,"cashew":5},100:{"raw cranberry sauce":1,"raw mincemeat":1,"raw turkey":1,"cashew":4},103:{"raw bread":1,"raw stuffing":1,"raw potato":1,"raw turkey":1,"cashew":3},106:{"raw green beans":1,"raw mincemeat":1,"raw sweet potato":1,"raw gravy":1,"raw turkey":1,"cashew":2},109:{"raw green beans":1,"raw gravy":1,"raw sweet potato":1,"cashew":4},112:{"raw stuffing":1,"raw cranberry sauce":1,"raw mincemeat":1,"raw turkey":1,"cashew":3},115:{"raw sweet potato":1,"raw stuffing":1,"raw gravy":1,"raw potato":1,"raw turkey":1,"cashew":2},118:{"raw cranberry sauce":1,"raw bread":1,"cashew":5},121:{"raw mincemeat":1,"raw bread":1,"raw green beans":1,"raw sweet potato":1,"raw stuffing":1,"cashew":2},124:{"raw gravy":1,"raw stuffing":1,"raw sweet potato":1,"raw mincemeat":1,"raw potato":1,"cashew":2},127:{"raw green beans":1,"raw bread":1,"raw gravy":1,"cashew":4},130:{"raw mincemeat":1,"raw cranberry sauce":1,"raw gravy":1,"raw turkey":1,"raw potato":1,"cashew":2},133:{"raw stuffing":1,"raw bread":1,"raw turkey":1,"raw gravy":1,"cashew":3},136:{"raw turkey":1,"raw gravy":1,"raw green beans":1,"raw bread":1,"raw potato":1,"cashew":2},139:{"raw potato":1,"raw sweet potato":1,"raw turkey":1,"raw bread":1,"cashew":3},142:{"raw turkey":1,"raw bread":1,"cashew":5},145:{"raw cranberry sauce":1,"raw mincemeat":1,"raw sweet potato":1,"raw green beans":1,"cashew":3},148:{"raw mincemeat":1,"raw gravy":1,"raw potato":1,"cashew":4},151:{"raw bread":1,"raw cranberry sauce":1,"cashew":5},154:{"raw stuffing":1,"raw sweet potato":1,"raw mincemeat":1,"cashew":4},157:{"raw mincemeat":1,"raw stuffing":1,"cashew":5},160:{"raw gravy":1,"raw mincemeat":1,"cashew":5},163:{"raw turkey":1,"raw sweet potato":1,"raw gravy":1,"cashew":4},166:{"raw mincemeat":1,"raw potato":1,"raw cranberry sauce":1,"raw bread":1,"cashew":3},169:{"raw bread":1,"raw mincemeat":1,"raw gravy":1,"cashew":4},172:{"raw stuffing":1,"raw turkey":1,"raw potato":1,"raw bread":1,"raw mincemeat":1,"cashew":2},175:{"raw cranberry sauce":1,"raw turkey":1,"cashew":5},178:{"raw green beans":1,"raw bread":1,"raw gravy":1,"cashew":4},181:{"raw bread":1,"raw turkey":1,"raw sweet potato":1,"cashew":4},184:{"raw turkey":1,"raw gravy":1,"raw stuffing":1,"raw sweet potato":1,"raw potato":1,"cashew":2},187:{"raw green beans":1,"raw turkey":1,"raw gravy":1,"raw potato":1,"cashew":3},190:{"raw mincemeat":1,"raw potato":1,"raw bread":1,"cashew":4},193:{"raw gravy":1,"raw cranberry sauce":1,"raw sweet potato":1,"raw stuffing":1,"cashew":3},196:{"raw gravy":1,"raw turkey":1,"raw potato":1,"cashew":4},199:{"raw stuffing":1,"raw mincemeat":1,"raw sweet potato":1,"cashew":4},202:{"raw potato":1,"raw turkey":1,"raw green beans":1,"raw stuffing":1,"raw mincemeat":1,"cashew":2},205:{"raw potato":1,"raw green beans":1,"cashew":5},208:{"raw sweet potato":1,"raw stuffing":1,"raw mincemeat":1,"raw bread":1,"raw green beans":1,"cashew":2},211:{"raw gravy":1,"raw turkey":1,"cashew":5},214:{"raw mincemeat":1,"raw bread":1,"raw gravy":1,"raw sweet potato":1,"raw turkey":1,"cashew":2},217:{"raw green beans":1,"raw mincemeat":1,"raw gravy":1,"raw potato":1,"raw cranberry sauce":1,"cashew":2},220:{"raw gravy":1,"raw green beans":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":3},223:{"raw bread":1,"raw mincemeat":1,"cashew":5},226:{"raw stuffing":1,"raw bread":1,"cashew":5},229:{"raw green beans":1,"raw stuffing":1,"raw cranberry sauce":1,"raw bread":1,"raw potato":1,"cashew":2},232:{"raw cranberry sauce":1,"raw green beans":1,"raw bread":1,"raw stuffing":1,"cashew":3},235:{"raw cranberry sauce":1,"raw stuffing":1,"cashew":5},238:{"raw gravy":1,"raw turkey":1,"raw bread":1,"raw mincemeat":1,"raw green beans":1,"cashew":2},241:{"raw gravy":1,"raw mincemeat":1,"raw green beans":1,"cashew":4},244:{"raw cranberry sauce":1,"raw stuffing":1,"raw gravy":1,"raw green beans":1,"cashew":3},247:{"raw stuffing":1,"raw green beans":1,"raw gravy":1,"raw potato":1,"cashew":3},250:{"raw gravy":1,"raw stuffing":1,"raw cranberry sauce":1,"raw sweet potato":1,"raw potato":1,"cashew":2},253:{"raw stuffing":1,"raw turkey":1,"raw potato":1,"raw bread":1,"cashew":3},256:{"raw mincemeat":1,"raw bread":1,"raw gravy":1,"raw turkey":1,"raw sweet potato":1,"cashew":2},259:{"raw sweet potato":1,"raw bread":1,"raw turkey":1,"cashew":4},262:{"raw stuffing":1,"raw sweet potato":1,"raw turkey":1,"raw potato":1,"cashew":3},265:{"raw stuffing":1,"raw green beans":1,"raw sweet potato":1,"cashew":4},268:{"raw turkey":1,"raw cranberry sauce":1,"raw stuffing":1,"raw potato":1,"raw gravy":1,"cashew":2},271:{"raw gravy":1,"raw turkey":1,"raw stuffing":1,"cashew":4},274:{"raw sweet potato":1,"raw potato":1,"raw gravy":1,"raw cranberry sauce":1,"cashew":3},277:{"raw turkey":1,"raw bread":1,"raw cranberry sauce":1,"raw stuffing":1,"cashew":3},280:{"raw potato":1,"raw bread":1,"raw turkey":1,"raw gravy":1,"raw sweet potato":1,"cashew":2},283:{"raw stuffing":1,"raw potato":1,"raw mincemeat":1,"cashew":4},286:{"raw green beans":1,"raw gravy":1,"raw sweet potato":1,"raw stuffing":1,"raw mincemeat":1,"cashew":2},289:{"raw gravy":1,"raw mincemeat":1,"raw bread":1,"cashew":4},292:{"raw sweet potato":1,"raw cranberry sauce":1,"raw potato":1,"raw gravy":1,"cashew":3},295:{"raw green beans":1,"raw cranberry sauce":1,"raw turkey":1,"cashew":4},298:{"raw mincemeat":1,"raw potato":1,"raw sweet potato":1,"cashew":4},301:{"raw bread":1,"raw potato":1,"raw green beans":1,"raw cranberry sauce":1,"cashew":3},304:{"raw green beans":1,"raw cranberry sauce":1,"raw gravy":1,"raw mincemeat":1,"cashew":3},307:{"raw bread":1,"raw cranberry sauce":1,"raw gravy":1,"raw mincemeat":1,"cashew":3},310:{"raw potato":1,"raw turkey":1,"cashew":5},313:{"raw sweet potato":1,"raw bread":1,"raw cranberry sauce":1,"raw gravy":1,"raw turkey":1,"cashew":2},316:{"raw stuffing":1,"raw bread":1,"cashew":5},319:{"raw mincemeat":1,"raw turkey":1,"cashew":5},322:{"raw potato":1,"raw turkey":1,"raw mincemeat":1,"raw stuffing":1,"cashew":3},325:{"raw potato":1,"raw gravy":1,"cashew":5},328:{"raw stuffing":1,"raw sweet potato":1,"raw green beans":1,"raw gravy":1,"raw bread":1,"cashew":2},331:{"raw turkey":1,"raw cranberry sauce":1,"cashew":5},334:{"raw mincemeat":1,"raw potato":1,"raw bread":1,"raw sweet potato":1,"raw turkey":1,"cashew":2},337:{"raw turkey":1,"raw mincemeat":1,"cashew":5},340:{"raw turkey":1,"raw mincemeat":1,"raw cranberry sauce":1,"raw bread":1,"cashew":3},343:{"raw gravy":1,"raw sweet potato":1,"raw bread":1,"raw potato":1,"raw green beans":1,"cashew":2},346:{"raw stuffing":1,"raw sweet potato":1,"raw mincemeat":1,"cashew":4},349:{"raw cranberry sauce":1,"raw stuffing":1,"raw green beans":1,"raw sweet potato":1,"raw gravy":1,"cashew":2},352:{"raw mincemeat":1,"raw sweet potato":1,"cashew":5},355:{"raw gravy":1,"raw potato":1,"raw bread":1,"raw mincemeat":1,"raw sweet potato":1,"cashew":2},358:{"raw turkey":1,"raw cranberry sauce":1,"raw bread":1,"cashew":4},361:{"raw stuffing":1,"raw green beans":1,"raw cranberry sauce":1,"raw bread":1,"raw potato":1,"cashew":2},364:{"raw green beans":1,"raw potato":1,"raw turkey":1,"raw cranberry sauce":1,"cashew":3},367:{"raw stuffing":1,"raw bread":1,"raw green beans":1,"raw gravy":1,"raw potato":1,"cashew":2},370:{"raw green beans":1,"raw stuffing":1,"raw gravy":1,"raw turkey":1,"cashew":3},373:{"raw bread":1,"raw gravy":1,"raw cranberry sauce":1,"cashew":4},376:{"raw green beans":1,"raw turkey":1,"raw sweet potato":1,"raw potato":1,"cashew":3},379:{"raw mincemeat":1,"raw gravy":1,"cashew":5},382:{"raw stuffing":1,"raw bread":1,"cashew":5},385:{"raw gravy":1,"raw mincemeat":1,"raw turkey":1,"raw potato":1,"raw stuffing":1,"cashew":2},388:{"raw cranberry sauce":1,"raw mincemeat":1,"raw sweet potato":1,"raw stuffing":1,"cashew":3},391:{"raw turkey":1,"raw potato":1,"raw green beans":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":2},394:{"raw gravy":1,"raw potato":1,"raw stuffing":1,"cashew":4},397:{"raw bread":1,"raw green beans":1,"raw turkey":1,"raw potato":1,"raw mincemeat":1,"cashew":2},400:{"raw potato":1,"raw bread":1,"raw turkey":1,"cashew":4},403:{"raw potato":1,"raw sweet potato":1,"raw mincemeat":1,"raw green beans":1,"raw turkey":1,"cashew":2},406:{"raw cranberry sauce":1,"raw gravy":1,"cashew":5},409:{"raw turkey":1,"raw sweet potato":1,"raw potato":1,"raw cranberry sauce":1,"raw bread":1,"cashew":2},412:{"raw cranberry sauce":1,"raw sweet potato":1,"cashew":5},415:{"raw gravy":1,"raw mincemeat":1,"raw bread":1,"raw sweet potato":1,"raw stuffing":1,"cashew":2},418:{"raw bread":1,"raw sweet potato":1,"raw cranberry sauce":1,"raw gravy":1,"cashew":3},421:{"raw sweet potato":1,"raw stuffing":1,"raw mincemeat":1,"cashew":4},424:{"raw cranberry sauce":1,"raw green beans":1,"cashew":5},427:{"raw sweet potato":1,"raw potato":1,"raw cranberry sauce":1,"raw mincemeat":1,"raw green beans":1,"cashew":2},430:{"raw potato":1,"raw mincemeat":1,"raw gravy":1,"raw green beans":1,"raw stuffing":1,"cashew":2},433:{"raw stuffing":1,"raw mincemeat":1,"raw sweet potato":1,"raw cranberry sauce":1,"cashew":3},436:{"raw mincemeat":1,"raw turkey":1,"raw sweet potato":1,"raw bread":1,"cashew":3},439:{"raw potato":1,"raw cranberry sauce":1,"cashew":5},442:{"raw sweet potato":1,"raw potato":1,"raw stuffing":1,"cashew":4},445:{"raw gravy":1,"raw turkey":1,"raw green beans":1,"raw potato":1,"cashew":3},448:{"raw mincemeat":1,"raw potato":1,"cashew":5},451:{"raw stuffing":1,"raw turkey":1,"raw cranberry sauce":1,"raw green beans":1,"cashew":3},454:{"raw gravy":1,"raw green beans":1,"cashew":5},457:{"raw sweet potato":1,"raw turkey":1,"cashew":5},460:{"raw green beans":1,"raw sweet potato":1,"raw stuffing":1,"cashew":4},463:{"raw gravy":1,"raw potato":1,"raw green beans":1,"raw sweet potato":1,"raw turkey":1,"cashew":2},466:{"raw gravy":1,"raw sweet potato":1,"raw bread":1,"cashew":4},469:{"raw gravy":1,"raw bread":1,"raw mincemeat":1,"raw cranberry sauce":1,"cashew":3},472:{"raw sweet potato":1,"raw cranberry sauce":1,"raw bread":1,"raw gravy":1,"raw mincemeat":1,"cashew":2},475:{"raw bread":1,"raw gravy":1,"raw mincemeat":1,"cashew":4},478:{"raw cranberry sauce":1,"raw bread":1,"raw sweet potato":1,"cashew":4},481:{"raw gravy":1,"raw green beans":1,"cashew":5},484:{"raw green beans":1,"raw mincemeat":1,"raw turkey":1,"raw sweet potato":1,"raw potato":1,"cashew":2},487:{"raw green beans":1,"raw stuffing":1,"raw sweet potato":1,"raw potato":1,"raw gravy":1,"cashew":2},490:{"raw green beans":1,"raw stuffing":1,"raw cranberry sauce":1,"raw turkey":1,"raw gravy":1,"cashew":2},493:{"raw potato":1,"raw gravy":1,"raw cranberry sauce":1,"raw sweet potato":1,"raw mincemeat":1,"cashew":2},496:{"raw turkey":1,"raw bread":1,"raw gravy":1,"cashew":4},499:{"raw green beans":1,"raw turkey":1,"cashew":5},502:{"raw green beans":1,"raw sweet potato":1,"raw bread":1,"raw gravy":1,"raw turkey":1,"cashew":2},505:{"raw sweet potato":1,"raw stuffing":1,"raw mincemeat":1,"raw turkey":1,"cashew":3},508:{"raw green beans":1,"raw cranberry sauce":1,"cashew":5},511:{"raw mincemeat":1,"raw turkey":1,"raw stuffing":1,"raw potato":1,"cashew":3},514:{"raw turkey":1,"raw cranberry sauce":1,"cashew":5},517:{"raw green beans":1,"raw mincemeat":1,"cashew":5},520:{"raw turkey":1,"raw stuffing":1,"raw bread":1,"raw potato":1,"raw cranberry sauce":1,"cashew":2},523:{"raw cranberry sauce":1,"raw turkey":1,"raw mincemeat":1,"cashew":4},526:{"raw stuffing":1,"raw green beans":1,"raw gravy":1,"raw potato":1,"cashew":3},529:{"raw green beans":1,"raw gravy":1,"raw stuffing":1,"raw bread":1,"raw mincemeat":1,"cashew":2},532:{"raw turkey":1,"raw stuffing":1,"raw sweet potato":1,"cashew":4},535:{"raw bread":1,"raw turkey":1,"cashew":5},538:{"raw cranberry sauce":1,"raw green beans":1,"raw turkey":1,"raw gravy":1,"cashew":3},541:{"raw mincemeat":1,"raw sweet potato":1,"raw turkey":1,"raw gravy":1,"cashew":3},544:{"raw stuffing":1,"raw bread":1,"raw turkey":1,"cashew":4},547:{"raw gravy":1,"raw green beans":1,"cashew":5},550:{"raw stuffing":1,"raw bread":1,"raw gravy":1,"raw cranberry sauce":1,"raw sweet potato":1,"cashew":2},553:{"raw sweet potato":1,"raw mincemeat":1,"raw gravy":1,"raw cranberry sauce":1,"cashew":3},556:{"raw potato":1,"raw gravy":1,"raw mincemeat":1,"raw stuffing":1,"raw bread":1,"cashew":2},559:{"raw stuffing":1,"raw green beans":1,"raw bread":1,"cashew":4},562:{"raw potato":1,"raw stuffing":1,"raw mincemeat":1,"raw green beans":1,"cashew":3},565:{"raw mincemeat":1,"raw green beans":1,"raw turkey":1,"raw gravy":1,"cashew":3},568:{"raw green beans":1,"raw sweet potato":1,"raw gravy":1,"raw cranberry sauce":1,"cashew":3},571:{"raw bread":1,"raw sweet potato":1,"raw potato":1,"raw turkey":1,"raw cranberry sauce":1,"cashew":2},574:{"raw cranberry sauce":1,"raw potato":1,"raw bread":1,"raw sweet potato":1,"raw mincemeat":1,"cashew":2},577:{"raw green beans":1,"raw stuffing":1,"cashew":5},580:{"raw sweet potato":1,"raw bread":1,"cashew":5},583:{"raw gravy":1,"raw cranberry sauce":1,"raw sweet potato":1,"raw potato":1,"cashew":3},586:{"raw mincemeat":1,"raw sweet potato":1,"raw gravy":1,"cashew":4},589:{"raw sweet potato":1,"raw gravy":1,"raw green beans":1,"cashew":4},592:{"raw potato":1,"raw sweet potato":1,"raw cranberry sauce":1,"raw stuffing":1,"raw mincemeat":1,"cashew":2},595:{"raw stuffing":1,"raw gravy":1,"cashew":5},598:{"raw bread":1,"raw mincemeat":1,"raw green beans":1,"raw gravy":1,"raw turkey":1,"cashew":2},601:{"raw mincemeat":1,"raw bread":1,"raw turkey":1,"raw potato":1,"raw cranberry sauce":1,"cashew":2},604:{"raw green beans":1,"raw turkey":1,"cashew":5},607:{"raw sweet potato":1,"raw cranberry sauce":1,"raw stuffing":1,"raw potato":1,"cashew":3},610:{"raw green beans":1,"raw sweet potato":1,"raw turkey":1,"cashew":4},613:{"raw gravy":1,"raw cranberry sauce":1,"raw green beans":1,"cashew":4},616:{"raw mincemeat":1,"raw green beans":1,"raw sweet potato":1,"raw cranberry sauce":1,"cashew":3},619:{"raw potato":1,"raw cranberry sauce":1,"raw bread":1,"raw gravy":1,"raw sweet potato":1,"cashew":2},622:{"raw mincemeat":1,"raw potato":1,"raw cranberry sauce":1,"raw sweet potato":1,"raw bread":1,"cashew":2},625:{"raw potato":1,"raw stuffing":1,"cashew":5},628:{"raw mincemeat":1,"raw green beans":1,"raw cranberry sauce":1,"raw stuffing":1,"raw gravy":1,"cashew":2},631:{"raw green beans":1,"raw stuffing":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":3},634:{"raw mincemeat":1,"raw bread":1,"cashew":5},637:{"raw sweet potato":1,"raw potato":1,"raw mincemeat":1,"raw bread":1,"cashew":3},640:{"raw potato":1,"raw mincemeat":1,"cashew":5},643:{"raw turkey":1,"raw sweet potato":1,"raw potato":1,"raw green beans":1,"raw mincemeat":1,"cashew":2},646:{"raw sweet potato":1,"raw turkey":1,"cashew":5},649:{"raw gravy":1,"raw stuffing":1,"cashew":5},652:{"raw turkey":1,"raw gravy":1,"raw sweet potato":1,"raw cranberry sauce":1,"cashew":3},655:{"raw turkey":1,"raw sweet potato":1,"raw mincemeat":1,"cashew":4},658:{"raw cranberry sauce":1,"raw gravy":1,"cashew":5},661:{"raw sweet potato":1,"raw mincemeat":1,"raw stuffing":1,"raw bread":1,"raw green beans":1,"cashew":2},664:{"raw sweet potato":1,"raw potato":1,"raw gravy":1,"raw mincemeat":1,"raw cranberry sauce":1,"cashew":2},667:{"raw gravy":1,"raw potato":1,"raw green beans":1,"cashew":4},670:{"raw sweet potato":1,"raw stuffing":1,"raw turkey":1,"raw gravy":1,"raw potato":1,"cashew":2},673:{"raw bread":1,"raw turkey":1,"raw stuffing":1,"raw mincemeat":1,"cashew":3},676:{"raw cranberry sauce":1,"raw gravy":1,"raw stuffing":1,"raw mincemeat":1,"cashew":3},679:{"raw mincemeat":1,"raw bread":1,"cashew":5},682:{"raw bread":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":4},685:{"raw gravy":1,"raw cranberry sauce":1,"raw bread":1,"raw sweet potato":1,"cashew":3},688:{"raw gravy":1,"raw potato":1,"raw sweet potato":1,"cashew":4},691:{"raw mincemeat":1,"raw green beans":1,"raw gravy":1,"cashew":4},694:{"raw mincemeat":1,"raw turkey":1,"cashew":5},697:{"raw sweet potato":1,"raw gravy":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":3},700:{"raw gravy":1,"raw bread":1,"cashew":5},703:{"raw bread":1,"raw mincemeat":1,"raw gravy":1,"raw sweet potato":1,"cashew":3},706:{"raw mincemeat":1,"raw cranberry sauce":1,"raw potato":1,"raw stuffing":1,"raw green beans":1,"cashew":2},709:{"raw bread":1,"raw gravy":1,"cashew":5},712:{"raw bread":1,"raw sweet potato":1,"raw mincemeat":1,"cashew":4},715:{"raw cranberry sauce":1,"raw turkey":1,"raw bread":1,"raw mincemeat":1,"raw gravy":1,"cashew":2},718:{"raw mincemeat":1,"raw bread":1,"raw turkey":1,"raw gravy":1,"cashew":3},721:{"raw turkey":1,"raw stuffing":1,"raw cranberry sauce":1,"raw sweet potato":1,"raw potato":1,"cashew":2},724:{"raw bread":1,"raw green beans":1,"raw turkey":1,"raw mincemeat":1,"raw potato":1,"cashew":2},727:{"raw green beans":1,"raw sweet potato":1,"cashew":5},730:{"raw turkey":1,"raw cranberry sauce":1,"raw bread":1,"raw sweet potato":1,"raw green beans":1,"cashew":2},733:{"raw cranberry sauce":1,"raw potato":1,"cashew":5},736:{"raw sweet potato":1,"raw cranberry sauce":1,"raw bread":1,"raw potato":1,"raw mincemeat":1,"cashew":2},739:{"raw mincemeat":1,"raw cranberry sauce":1,"raw turkey":1,"cashew":4},742:{"raw mincemeat":1,"raw stuffing":1,"raw bread":1,"raw potato":1,"cashew":3},745:{"raw gravy":1,"raw bread":1,"raw potato":1,"cashew":4},748:{"raw green beans":1,"raw bread":1,"cashew":5},751:{"raw green beans":1,"raw gravy":1,"cashew":5},754:{"raw bread":1,"raw mincemeat":1,"raw stuffing":1,"raw gravy":1,"cashew":3},757:{"raw gravy":1,"raw green beans":1,"raw potato":1,"raw sweet potato":1,"cashew":3},760:{"raw gravy":1,"raw mincemeat":1,"raw turkey":1,"raw sweet potato":1,"raw green beans":1,"cashew":2},763:{"raw green beans":1,"raw mincemeat":1,"cashew":5},766:{"raw turkey":1,"raw cranberry sauce":1,"raw sweet potato":1,"raw gravy":1,"raw mincemeat":1,"cashew":2},769:{"raw gravy":1,"raw turkey":1,"raw cranberry sauce":1,"raw stuffing":1,"raw mincemeat":1,"cashew":2},772:{"raw sweet potato":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":4},775:{"raw stuffing":1,"raw cranberry sauce":1,"cashew":5},778:{"raw cranberry sauce":1,"raw bread":1,"raw turkey":1,"raw stuffing":1,"raw sweet potato":1,"cashew":2},781:{"raw potato":1,"raw mincemeat":1,"raw sweet potato":1,"raw bread":1,"raw turkey":1,"cashew":2},784:{"raw stuffing":1,"raw green beans":1,"raw sweet potato":1,"raw turkey":1,"raw potato":1,"cashew":2},787:{"raw green beans":1,"raw mincemeat":1,"raw cranberry sauce":1,"raw turkey":1,"raw stuffing":1,"cashew":2},790:{"raw turkey":1,"raw bread":1,"raw stuffing":1,"raw potato":1,"cashew":3},793:{"raw stuffing":1,"raw green beans":1,"cashew":5},796:{"raw turkey":1,"raw cranberry sauce":1,"raw gravy":1,"cashew":4},799:{"raw turkey":1,"raw potato":1,"raw sweet potato":1,"cashew":4},802:{"raw bread":1,"raw potato":1,"cashew":5},805:{"raw gravy":1,"raw bread":1,"raw stuffing":1,"raw potato":1,"raw green beans":1,"cashew":2},808:{"raw gravy":1,"raw stuffing":1,"raw cranberry sauce":1,"raw green beans":1,"raw sweet potato":1,"cashew":2},811:{"raw sweet potato":1,"raw bread":1,"raw stuffing":1,"raw cranberry sauce":1,"raw turkey":1,"cashew":2},814:{"raw bread":1,"raw turkey":1,"cashew":5},817:{"raw cranberry sauce":1,"raw stuffing":1,"cashew":5},820:{"raw potato":1,"raw mincemeat":1,"raw stuffing":1,"raw cranberry sauce":1,"cashew":3},823:{"raw gravy":1,"raw green beans":1,"raw potato":1,"raw turkey":1,"cashew":3},826:{"raw stuffing":1,"raw cranberry sauce":1,"raw green beans":1,"cashew":4},829:{"raw mincemeat":1,"raw potato":1,"raw turkey":1,"cashew":4},832:{"raw stuffing":1,"raw cranberry sauce":1,"cashew":5},835:{"raw sweet potato":1,"raw bread":1,"raw cranberry sauce":1,"raw gravy":1,"raw potato":1,"cashew":2},838:{"raw mincemeat":1,"raw cranberry sauce":1,"raw turkey":1,"raw green beans":1,"cashew":3},841:{"raw sweet potato":1,"raw cranberry sauce":1,"raw green beans":1,"raw stuffing":1,"cashew":3},844:{"raw green beans":1,"raw turkey":1,"raw stuffing":1,"cashew":4},847:{"raw potato":1,"raw gravy":1,"cashew":5},850:{"raw mincemeat":1,"raw cranberry sauce":1,"raw bread":1,"raw stuffing":1,"raw green beans":1,"cashew":2},853:{"raw gravy":1,"raw stuffing":1,"raw mincemeat":1,"raw potato":1,"cashew":3},856:{"raw mincemeat":1,"raw bread":1,"raw stuffing":1,"raw cranberry sauce":1,"cashew":3},859:{"raw turkey":1,"raw mincemeat":1,"raw potato":1,"raw sweet potato":1,"raw bread":1,"cashew":2},862:{"raw mincemeat":1,"raw green beans":1,"raw potato":1,"raw turkey":1,"cashew":3},865:{"raw gravy":1,"raw cranberry sauce":1,"raw stuffing":1,"cashew":4},868:{"raw green beans":1,"raw stuffing":1,"raw potato":1,"raw bread":1,"raw mincemeat":1,"cashew":2},871:{"raw turkey":1,"raw green beans":1,"cashew":5},874:{"raw stuffing":1,"raw turkey":1,"cashew":5},877:{"raw gravy":1,"raw turkey":1,"cashew":5},880:{"raw sweet potato":1,"raw potato":1,"raw gravy":1,"raw stuffing":1,"cashew":3},883:{"raw mincemeat":1,"raw stuffing":1,"raw gravy":1,"raw bread":1,"raw sweet potato":1,"cashew":2},886:{"raw mincemeat":1,"raw turkey":1,"raw potato":1,"raw cranberry sauce":1,"cashew":3},889:{"raw gravy":1,"raw potato":1,"raw bread":1,"raw stuffing":1,"cashew":3},892:{"raw stuffing":1,"raw cranberry sauce":1,"raw bread":1,"raw green beans":1,"raw sweet potato":1,"cashew":2},895:{"raw cranberry sauce":1,"raw bread":1,"raw stuffing":1,"raw green beans":1,"cashew":3},898:{"raw turkey":1,"raw bread":1,"raw potato":1,"raw mincemeat":1,"cashew":3},901:{"raw mincemeat":1,"raw green beans":1,"raw potato":1,"cashew":4},904:{"raw potato":1,"raw gravy":1,"raw turkey":1,"cashew":4},907:{"raw stuffing":1,"raw cranberry sauce":1,"raw green beans":1,"cashew":4},910:{"raw green beans":1,"raw bread":1,"raw stuffing":1,"cashew":4},913:{"raw cranberry sauce":1,"raw sweet potato":1,"raw potato":1,"raw gravy":1,"raw green beans":1,"cashew":2},916:{"raw green beans":1,"raw cranberry sauce":1,"raw bread":1,"cashew":4},919:{"raw potato":1,"raw turkey":1,"raw mincemeat":1,"raw cranberry sauce":1,"raw green beans":1,"cashew":2},922:{"raw mincemeat":1,"raw stuffing":1,"raw bread":1,"cashew":4},925:{"raw cranberry sauce":1,"raw potato":1,"raw green beans":1,"cashew":4},20:{"raw turkey":1,"raw sweet potato":1,"raw gravy":1,"cashew":4},23:{"raw green beans":1,"raw gravy":1,"raw sweet potato":1,"cashew":4},26:{"raw sweet potato":1,"raw turkey":1,"raw cranberry sauce":1,"raw potato":1,"cashew":3},29:{"raw sweet potato":1,"raw turkey":1,"cashew":5},32:{"raw sweet potato":1,"raw cranberry sauce":1,"cashew":5},35:{"raw gravy":1,"raw mincemeat":1,"raw bread":1,"raw stuffing":1,"cashew":3},38:{"raw gravy":1,"raw bread":1,"raw turkey":1,"raw potato":1,"cashew":3},41:{"raw mincemeat":1,"raw turkey":1,"raw bread":1,"raw sweet potato":1,"cashew":3},44:{"raw cranberry sauce":1,"raw green beans":1,"cashew":5},47:{"raw cranberry sauce":1,"raw mincemeat":1,"raw stuffing":1,"raw turkey":1,"raw potato":1,"cashew":2},50:{"raw green beans":1,"raw turkey":1,"raw potato":1,"raw stuffing":1,"cashew":3},53:{"raw gravy":1,"raw mincemeat":1,"cashew":5},56:{"raw cranberry sauce":1,"raw gravy":1,"cashew":5},59:{"raw bread":1,"raw cranberry sauce":1,"cashew":5},62:{"raw cranberry sauce":1,"raw bread":1,"raw stuffing":1,"raw sweet potato":1,"raw green beans":1,"cashew":2},65:{"raw gravy":1,"raw sweet potato":1,"raw mincemeat":1,"raw green beans":1,"raw cranberry sauce":1,"cashew":2},68:{"raw stuffing":1,"raw mincemeat":1,"raw bread":1,"raw potato":1,"cashew":3},71:{"raw sweet potato":1,"raw mincemeat":1,"raw green beans":1,"raw gravy":1,"raw bread":1,"cashew":2},74:{"raw mincemeat":1,"raw cranberry sauce":1,"raw turkey":1,"raw green beans":1,"raw stuffing":1,"cashew":2},77:{"raw gravy":1,"raw potato":1,"cashew":5},80:{"raw gravy":1,"raw potato":1,"raw stuffing":1,"cashew":4},83:{"raw mincemeat":1,"raw turkey":1,"raw green beans":1,"raw cranberry sauce":1,"cashew":3},86:{"raw mincemeat":1,"raw stuffing":1,"raw potato":1,"raw turkey":1,"raw green beans":1,"cashew":2},89:{"raw cranberry sauce":1,"raw turkey":1,"raw green beans":1,"raw bread":1,"cashew":3},92:{"raw potato":1,"raw green beans":1,"cashew":5},95:{"raw bread":1,"raw stuffing":1,"raw sweet potato":1,"raw cranberry sauce":1,"raw potato":1,"cashew":2},98:{"raw bread":1,"raw gravy":1,"raw green beans":1,"cashew":4},101:{"raw cranberry sauce":1,"raw bread":1,"raw stuffing":1,"cashew":4},104:{"raw bread":1,"raw mincemeat":1,"raw sweet potato":1,"raw green beans":1,"raw gravy":1,"cashew":2},107:{"raw cranberry sauce":1,"raw sweet potato":1,"raw mincemeat":1,"raw potato":1,"raw turkey":1,"cashew":2},110:{"raw potato":1,"raw stuffing":1,"raw sweet potato":1,"raw mincemeat":1,"raw gravy":1,"cashew":2},113:{"raw stuffing":1,"raw gravy":1,"cashew":5},116:{"raw mincemeat":1,"raw stuffing":1,"raw turkey":1,"raw potato":1,"cashew":3},119:{"raw gravy":1,"raw turkey":1,"cashew":5},122:{"raw stuffing":1,"raw sweet potato":1,"raw mincemeat":1,"raw green beans":1,"raw turkey":1,"cashew":2},125:{"raw cranberry sauce":1,"raw potato":1,"raw turkey":1,"cashew":4},128:{"raw turkey":1,"raw potato":1,"cashew":5},131:{"raw cranberry sauce":1,"raw mincemeat":1,"raw gravy":1,"cashew":4},134:{"raw bread":1,"raw green beans":1,"cashew":5},137:{"raw green beans":1,"raw potato":1,"cashew":5},140:{"raw potato":1,"raw sweet potato":1,"raw cranberry sauce":1,"cashew":4},143:{"raw bread":1,"raw cranberry sauce":1,"raw gravy":1,"cashew":4},146:{"raw turkey":1,"raw cranberry sauce":1,"raw sweet potato":1,"raw bread":1,"cashew":3},149:{"raw green beans":1,"raw stuffing":1,"cashew":5},152:{"raw green beans":1,"raw potato":1,"cashew":5},155:{"raw gravy":1,"raw cranberry sauce":1,"raw stuffing":1,"cashew":4},158:{"raw green beans":1,"raw turkey":1,"raw potato":1,"raw cranberry sauce":1,"raw stuffing":1,"cashew":2},161:{"raw potato":1,"raw stuffing":1,"cashew":5},164:{"raw gravy":1,"raw bread":1,"raw turkey":1,"raw potato":1,"cashew":3},167:{"raw sweet potato":1,"raw green beans":1,"cashew":5},170:{"raw green beans":1,"raw turkey":1,"raw gravy":1,"raw sweet potato":1,"raw bread":1,"cashew":2},173:{"raw gravy":1,"raw bread":1,"raw green beans":1,"raw mincemeat":1,"raw sweet potato":1,"cashew":2},176:{"raw stuffing":1,"raw gravy":1,"raw bread":1,"raw cranberry sauce":1,"cashew":3},179:{"raw mincemeat":1,"raw stuffing":1,"cashew":5},182:{"raw stuffing":1,"raw gravy":1,"cashew":5},185:{"raw green beans":1,"raw sweet potato":1,"raw bread":1,"raw mincemeat":1,"raw cranberry sauce":1,"cashew":2},188:{"raw green beans":1,"raw turkey":1,"raw stuffing":1,"cashew":4},191:{"raw stuffing":1,"raw gravy":1,"raw potato":1,"cashew":4},194:{"raw stuffing":1,"raw potato":1,"cashew":5},197:{"raw bread":1,"raw potato":1,"cashew":5},200:{"raw turkey":1,"raw cranberry sauce":1,"cashew":5},203:{"raw green beans":1,"raw mincemeat":1,"cashew":5},206:{"raw sweet potato":1,"raw cranberry sauce":1,"raw potato":1,"raw green beans":1,"cashew":3},209:{"raw turkey":1,"raw potato":1,"cashew":5},212:{"raw potato":1,"raw turkey":1,"raw green beans":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":2},215:{"raw gravy":1,"raw bread":1,"raw potato":1,"raw mincemeat":1,"raw cranberry sauce":1,"cashew":2},218:{"raw bread":1,"raw cranberry sauce":1,"raw gravy":1,"raw turkey":1,"cashew":3},221:{"raw bread":1,"raw sweet potato":1,"raw gravy":1,"cashew":4},224:{"raw stuffing":1,"raw bread":1,"raw cranberry sauce":1,"raw green beans":1,"cashew":3},227:{"raw bread":1,"raw stuffing":1,"raw potato":1,"raw turkey":1,"raw gravy":1,"cashew":2},230:{"raw cranberry sauce":1,"raw stuffing":1,"raw mincemeat":1,"cashew":4},233:{"raw gravy":1,"raw stuffing":1,"raw turkey":1,"raw potato":1,"raw mincemeat":1,"cashew":2},236:{"raw green beans":1,"raw mincemeat":1,"raw gravy":1,"raw turkey":1,"raw stuffing":1,"cashew":2},239:{"raw sweet potato":1,"raw turkey":1,"raw potato":1,"raw cranberry sauce":1,"cashew":3},242:{"raw sweet potato":1,"raw turkey":1,"raw cranberry sauce":1,"cashew":4},245:{"raw sweet potato":1,"raw cranberry sauce":1,"cashew":5},248:{"raw stuffing":1,"raw potato":1,"raw green beans":1,"cashew":4},251:{"raw cranberry sauce":1,"raw stuffing":1,"raw sweet potato":1,"cashew":4},254:{"raw bread":1,"raw cranberry sauce":1,"raw sweet potato":1,"cashew":4},257:{"raw potato":1,"raw turkey":1,"cashew":5},260:{"raw sweet potato":1,"raw stuffing":1,"raw gravy":1,"raw bread":1,"raw turkey":1,"cashew":2},263:{"raw gravy":1,"raw green beans":1,"raw potato":1,"cashew":4},266:{"raw gravy":1,"raw green beans":1,"raw potato":1,"raw mincemeat":1,"raw turkey":1,"cashew":2},269:{"raw stuffing":1,"raw bread":1,"raw mincemeat":1,"raw turkey":1,"cashew":3},272:{"raw green beans":1,"raw mincemeat":1,"raw bread":1,"raw gravy":1,"raw sweet potato":1,"cashew":2},275:{"raw stuffing":1,"raw potato":1,"raw cranberry sauce":1,"raw mincemeat":1,"cashew":3},278:{"raw green beans":1,"raw gravy":1,"raw stuffing":1,"raw turkey":1,"raw cranberry sauce":1,"cashew":2},281:{"raw sweet potato":1,"raw bread":1,"raw green beans":1,"raw stuffing":1,"cashew":3},284:{"raw turkey":1,"raw green beans":1,"cashew":5},287:{"raw cranberry sauce":1,"raw mincemeat":1,"raw turkey":1,"raw green beans":1,"raw bread":1,"cashew":2},290:{"raw bread":1,"raw turkey":1,"raw sweet potato":1,"raw stuffing":1,"cashew":3},293:{"raw mincemeat":1,"raw bread":1,"cashew":5},296:{"raw sweet potato":1,"raw potato":1,"raw stuffing":1,"raw gravy":1,"cashew":3},299:{"raw bread":1,"raw sweet potato":1,"raw potato":1,"raw stuffing":1,"cashew":3},302:{"raw stuffing":1,"raw cranberry sauce":1,"raw green beans":1,"cashew":4},303:{"raw potato":1,"raw bread":1,"cashew":5},306:{"raw bread":1,"raw potato":1,"raw turkey":1,"raw stuffing":1,"cashew":3},309:{"raw cranberry sauce":1,"raw green beans":1,"cashew":5},312:{"raw sweet potato":1,"raw mincemeat":1,"raw cranberry sauce":1,"raw green beans":1,"raw turkey":1,"cashew":2},315:{"raw green beans":1,"raw mincemeat":1,"raw gravy":1,"cashew":4},318:{"raw gravy":1,"raw stuffing":1,"raw cranberry sauce":1,"cashew":4},321:{"raw sweet potato":1,"raw stuffing":1,"cashew":5},324:{"raw cranberry sauce":1,"raw mincemeat":1,"raw turkey":1,"raw potato":1,"raw gravy":1,"cashew":2},327:{"raw stuffing":1,"raw mincemeat":1,"raw bread":1,"raw gravy":1,"cashew":3},330:{"raw bread":1,"raw gravy":1,"raw turkey":1,"raw green beans":1,"cashew":3},333:{"raw potato":1,"raw cranberry sauce":1,"raw stuffing":1,"cashew":4},336:{"raw cranberry sauce":1,"raw turkey":1,"raw mincemeat":1,"raw stuffing":1,"cashew":3},339:{"raw sweet potato":1,"raw green beans":1,"raw stuffing":1,"cashew":4},342:{"raw bread":1,"raw green beans":1,"raw turkey":1,"raw cranberry sauce":1,"raw gravy":1,"cashew":2},345:{"raw sweet potato":1,"raw gravy":1,"raw turkey":1,"raw mincemeat":1,"cashew":3},348:{"raw turkey":1,"raw sweet potato":1,"raw gravy":1,"raw cranberry sauce":1,"cashew":3},356:{"raw potato":1,"raw cranberry sauce":1,"raw stuffing":1,"raw sweet potato":1,"cashew":3},359:{"raw cranberry sauce":1,"raw sweet potato":1,"cashew":5},362:{"raw mincemeat":1,"raw cranberry sauce":1,"raw turkey":1,"raw bread":1,"raw potato":1,"cashew":2},365:{"raw gravy":1,"raw bread":1,"cashew":5},368:{"raw turkey":1,"raw potato":1,"raw stuffing":1,"raw sweet potato":1,"cashew":3},371:{"raw sweet potato":1,"raw turkey":1,"raw potato":1,"cashew":4},374:{"raw sweet potato":1,"raw cranberry sauce":1,"raw mincemeat":1,"raw stuffing":1,"raw bread":1,"cashew":2},377:{"raw turkey":1,"raw potato":1,"raw gravy":1,"raw stuffing":1,"raw bread":1,"cashew":2},380:{"raw turkey":1,"raw potato":1,"raw mincemeat":1,"raw bread":1,"raw stuffing":1,"cashew":2},383:{"raw green beans":1,"raw turkey":1,"raw stuffing":1,"raw sweet potato":1,"cashew":3},386:{"raw green beans":1,"raw mincemeat":1,"raw gravy":1,"cashew":4},389:{"raw potato":1,"raw sweet potato":1,"raw stuffing":1,"raw mincemeat":1,"cashew":3},392:{"raw bread":1,"raw green beans":1,"raw mincemeat":1,"raw potato":1,"cashew":3},395:{"raw sweet potato":1,"raw potato":1,"raw green beans":1,"raw gravy":1,"cashew":3},398:{"raw bread":1,"raw green beans":1,"raw sweet potato":1,"cashew":4},401:{"raw cranberry sauce":1,"raw bread":1,"raw turkey":1,"cashew":4},404:{"raw cranberry sauce":1,"raw gravy":1,"raw sweet potato":1,"cashew":4},407:{"raw mincemeat":1,"raw green beans":1,"cashew":5},410:{"raw potato":1,"raw mincemeat":1,"cashew":5},413:{"raw green beans":1,"raw stuffing":1,"raw mincemeat":1,"cashew":4},305:{"raw turkey":1,"raw stuffing":1,"raw sweet potato":1,"raw potato":1,"raw green beans":1,"cashew":2},308:{"raw potato":1,"raw green beans":1,"cashew":5},311:{"raw green beans":1,"raw mincemeat":1,"raw cranberry sauce":1,"raw potato":1,"cashew":3},314:{"raw turkey":1,"raw bread":1,"cashew":5},317:{"raw turkey":1,"raw sweet potato":1,"raw cranberry sauce":1,"raw green beans":1,"cashew":3},320:{"raw cranberry sauce":1,"raw green beans":1,"raw sweet potato":1,"cashew":4},323:{"raw bread":1,"raw sweet potato":1,"cashew":5},326:{"raw cranberry sauce":1,"raw bread":1,"raw sweet potato":1,"cashew":4},329:{"raw mincemeat":1,"raw stuffing":1,"raw potato":1,"cashew":4},332:{"raw potato":1,"raw gravy":1,"cashew":5},335:{"raw sweet potato":1,"raw stuffing":1,"cashew":5},338:{"raw bread":1,"raw stuffing":1,"raw cranberry sauce":1,"raw gravy":1,"raw sweet potato":1,"cashew":2},341:{"raw turkey":1,"raw cranberry sauce":1,"raw mincemeat":1,"raw gravy":1,"cashew":3},344:{"raw bread":1,"raw potato":1,"raw mincemeat":1,"raw green beans":1,"cashew":3},347:{"raw mincemeat":1,"raw green beans":1,"raw turkey":1,"raw gravy":1,"cashew":3},350:{"raw potato":1,"raw mincemeat":1,"raw sweet potato":1,"raw gravy":1,"cashew":3},353:{"raw sweet potato":1,"raw gravy":1,"raw turkey":1,"raw green beans":1,"cashew":3},416:{"raw turkey":1,"raw bread":1,"raw green beans":1,"raw cranberry sauce":1,"cashew":3},419:{"raw potato":1,"raw stuffing":1,"raw sweet potato":1,"raw gravy":1,"cashew":3},422:{"raw cranberry sauce":1,"raw bread":1,"raw gravy":1,"raw turkey":1,"raw mincemeat":1,"cashew":2},425:{"raw gravy":1,"raw potato":1,"cashew":5},428:{"raw turkey":1,"raw sweet potato":1,"cashew":5},431:{"raw turkey":1,"raw green beans":1,"cashew":5}}; -} - -int [string] lookupCornucopiaReward(int lookup_number) -{ - return __thanksgarden_cornucopia_rewards[lookup_number]; -} - -//Path number is the same as my_path().id. -int [string] lookupCornucopiaReward(int path_id, class player_class, int daycount, int previous_cornucopias_used) -{ - int class_number = player_class.to_int(); - int lookup_number = 3 * ((previous_cornucopias_used + 1) + path_id) + 5 * daycount + 7 * class_number; - return lookupCornucopiaReward(lookup_number); -} - -int [string] lookupCornucopiaReward(int previous_cornucopias_used) -{ - return lookupCornucopiaReward(my_path().id, my_class(), my_daycount(), previous_cornucopias_used); -} - -int [string] lookupNextCornucopiaReward() -{ - return lookupCornucopiaReward(get_property_int("cornucopiasOpened")); -} diff --git a/Source/relay/TourGuide/Support/Cost To Acquire.ash b/Source/relay/TourGuide/Support/Cost To Acquire.ash deleted file mode 100644 index 74f0be99..00000000 --- a/Source/relay/TourGuide/Support/Cost To Acquire.ash +++ /dev/null @@ -1,110 +0,0 @@ - -int [item] __cost_to_acquire_override; -void set_cost_to_acquire_override(item it, int override_value) -{ - __cost_to_acquire_override[it] = override_value; -} -//FIXME this needs improvement -//FIXME do not cache if we're using historical_price and then they do a mall search. maybe don't cache at all...? well, we should, but only if it's been seen more than a handful of times? we can't easily detect if our previous prices changed for every item without incurring the same hit as a calculation... does the cache help at all, even in extremely high use scenarios? -float [item] __cost_to_acquire_price_cache; -float [item] __cost_to_acquire_price_cache_thirty_days; -float cost_to_acquire(item it, boolean allow_caching, float mall_search_if_historical_value_is_over, boolean [item] previously_evaluated_items) -{ - //Reusable hack: - if ($items[tiny plastic sword,vesper,bodyslam,cherry bomb,dirty martini,grogtini,sangria del diablo,skewered cherry,skewered jumbo olive,skewered lime] contains it && it.available_amount() > 0) - { - return 0.0; - } - previously_evaluated_items[it] = true; - if (__cost_to_acquire_override contains it) - return __cost_to_acquire_override[it]; - if (allow_caching && (__cost_to_acquire_price_cache contains it)) - { - return __cost_to_acquire_price_cache[it]; - } - if (allow_caching && mall_search_if_historical_value_is_over <= 30.0 && (__cost_to_acquire_price_cache_thirty_days contains it)) - return __cost_to_acquire_price_cache_thirty_days[it]; - float [int] price_sources; - if (it.tradeable && !($items[glass of "milk",cup of "tea",thermos of "whiskey",lucky lindy,bee's knees,sockdollager,ish kabibble, hot socks, phonus balonus,sloppy jalopy] contains it)) //' - { - if (it.historical_age() > mall_search_if_historical_value_is_over) - { - price_sources.listAppend(it.mall_price()); - } - else if (it.historical_price() > 0) - { - price_sources.listAppend(it.historical_price()); - } - } - if (it.is_npc_item() && it.npc_price() > 0) - price_sources.listAppend(it.npc_price()); - - int [item] ingredients = it.get_ingredients(); - if (ingredients.count() > 0) - { - boolean ignore_ingredients = false; - float making_cost = 0.0; - foreach ingredient, amount in ingredients - { - if (previously_evaluated_items contains ingredient) - { - ignore_ingredients = true; - break; - } - float acquire_cost = ingredient.cost_to_acquire(allow_caching, mall_search_if_historical_value_is_over, previously_evaluated_items); - if (acquire_cost < 0) - { - ignore_ingredients = true; - break; - } - making_cost += acquire_cost * amount; - } - string craft_type = it.craft_type(); - - if (craft_type.contains_text("Mixing (fancy)")) - { - if (can_interact()) - making_cost += $item[bartender-in-the-box].cost_to_acquire(true, mall_search_if_historical_value_is_over, previously_evaluated_items) / 40.0; - else - making_cost += 3000.0; //adventure cost hack FIXME - } - if (craft_type.contains_text("Cooking (fancy)")) - { - if (can_interact()) - making_cost += $item[chef-in-the-box].cost_to_acquire(true, mall_search_if_historical_value_is_over, previously_evaluated_items) / 40.0; - else - making_cost += 3000.0; //adventure cost hack FIXME - } - //FIXME other craft types - if (!ignore_ingredients) - price_sources.listAppend(making_cost); - } - float cost = -1.0; - foreach key, v in price_sources - { - if (v < cost || cost == -1.0) - cost = v; - } - if (mall_search_if_historical_value_is_over < 1.0) - __cost_to_acquire_price_cache[it] = cost; - else if (mall_search_if_historical_value_is_over <= 30.0) - __cost_to_acquire_price_cache_thirty_days[it] = cost; - return cost; -} - -float cost_to_acquire(item it, boolean allow_caching, float mall_search_if_historical_value_is_over) -{ - boolean [item] empty_list; - return cost_to_acquire(it, allow_caching, mall_search_if_historical_value_is_over, empty_list); -} - -float cost_to_acquire(item it, float mall_search_if_historical_value_is_over) -{ - return cost_to_acquire(it, false, mall_search_if_historical_value_is_over); -} - -float cost_to_acquire(item it) -{ - //acquire, brock, acquire: - return cost_to_acquire(it, 30.0); -} diff --git a/Source/relay/TourGuide/Support/Counter.ash b/Source/relay/TourGuide/Support/Counter.ash deleted file mode 100644 index 1a10c4ea..00000000 --- a/Source/relay/TourGuide/Support/Counter.ash +++ /dev/null @@ -1,699 +0,0 @@ -import "relay/TourGuide/Support/List.ash" -import "relay/TourGuide/Support/Math.ash" -import "relay/TourGuide/Support/Library.ash" -import "relay/TourGuide/Support/AdventurePHP Locations.ash" - -Record Counter -{ - string name; - string location_id; //number or * - string mafia_informed_type; //"wander" seen - string [int] mafia_gifs; - int [int] exact_turns; //sorted order - int range_start_turn; - int range_end_turn; - boolean found_start_turn_range; - boolean found_end_turn_range; - - boolean initialised; - boolean waiting_for_adventure_php; -}; - -Counter CounterMake() -{ - Counter c; - c.range_start_turn = -1; - c.range_end_turn = -1; - c.initialised = true; - - return c; -} - -//If false, use exact_turns. If true, range_start_turn/range_end_turn. (this isn't ideal, sorry) -boolean CounterIsRange(Counter c) -{ - if (!c.initialised) - return false; - //if (c.range_start_turn < 0 && c.range_end_turn < 0) //seems to be an errornous test when we go past our window - //return false; - if (c.exact_turns.count() == 0 && (c.found_start_turn_range || c.found_end_turn_range)) - return true; - return false; -} - -int CounterGetNextExactTurn(Counter c) -{ - if (!c.initialised) - return -1; - if (c.CounterIsRange()) - return -1; - if (c.exact_turns.count() == 0) - return -1; - return c.exact_turns[0]; -} - -boolean CounterIsExact(Counter c) -{ - return c.CounterGetNextExactTurn() > 0; -} - -boolean CounterMayHitNextTurn(Counter c) -{ - //FIXME use CounterMayHitInXTurns to implement this once we're sure it works - if (!c.initialised) - return false; - if (c.exact_turns.count() > 0) - { - foreach key, turn in c.exact_turns - { - if (turn == 0) - return true; - } - return false; - } - else if (!c.found_start_turn_range && !c.found_end_turn_range) - { - return false; - } - //turn range: - else if (c.found_start_turn_range) - { - if (c.range_start_turn <= 0) - return true; - else - return false; - } - else if (c.found_end_turn_range) - return true; //maaaybe? - return false; -} - -boolean CounterMayHitInXTurns(Counter c, int turns_limit) -{ - if (!c.initialised) - return false; - if (c.exact_turns.count() > 0) - { - foreach key, turn in c.exact_turns - { - if (turn <= turns_limit) - return true; - } - return false; - } - else if (!c.found_start_turn_range && !c.found_end_turn_range) - { - return false; - } - //turn range: - else if (c.found_start_turn_range) - { - if (c.range_start_turn <= turns_limit && c.range_end_turn >= 0) - return true; - else - return false; - } - else if (c.found_end_turn_range && c.range_end_turn >= 0) - { - return true; //maaaybe? - } - return false; -} - -Vec2i CounterGetWindowRange(Counter c) //x is min, y is max -{ - if (!c.CounterIsRange()) - return Vec2iMake(-1, -1); - return Vec2iMake(c.range_start_turn, c.range_end_turn); -} - -//DOES NOT HANDLE COUNTER RANGES: -boolean CounterWillHitExactlyInTurnRange(Counter c, int start_turn_range, int end_turn_range) -{ - if (!c.initialised) - return false; - - Vec2i turn_range = Vec2iMake(start_turn_range, end_turn_range); - - foreach key in c.exact_turns - { - int turn = c.exact_turns[key]; - if (turn_range.Vec2iValueInRange(turn)) - return true; - } - return false; -} - -boolean CounterWillHitNextTurn(Counter c) -{ - if (c.name == "Holiday Monster") //mafia's tracking of these breaks, so, don't rely on it. thinking of El Dia de Los Muertos Borrachos specifically - return false; - if (c.CounterIsRange()) - { - Vec2i range = c.CounterGetWindowRange(); - if (c.name == "Semi-rare" && range.y <= 0) - return false; //there's probably a lot of other ones where being negative means it won't happen - if (range.y <= 0) - return true; - } - if (c.CounterWillHitExactlyInTurnRange(0, 0)) - return true; - return false; -} - - -boolean CounterExists(Counter c) -{ - if (!c.initialised) - return false; - if (c.CounterIsRange()) - return true; - if (c.exact_turns.count() > 0) - return true; - return false; -} - -buffer CounterDescription(Counter c) -{ - if (!c.initialised) - { - return "Uninitialised".to_buffer(); - } - buffer description; - description.append(c.name); - if (!c.CounterExists()) - description.append(" (invalid)"); - if (c.location_id != "") - { - description.append(" (location "); - description.append(c.location_id); - description.append(")"); - } - if (c.mafia_gifs.count() > 0) - { - description.append(" (gif "); - description.append(c.mafia_gifs.listJoinComponents(", ", "and")); - description.append(")"); - } - description.append(" in "); - if (c.CounterIsRange()) - { - description.append("["); - description.append(c.range_start_turn); - description.append(", "); - description.append(c.range_end_turn); - description.append("]"); - } - else - { - description.append(c.exact_turns.listJoinComponents(", ", "or")); - } - description.append(" turns"); - return description; -} - - -void CountersParseProperty(string property_name, Counter [string] counters, boolean are_temp_counters) -{ - foreach key in counters - { - remove counters[key]; - } - - string counter_string = get_property(property_name); - /*_tempRelayCounters uses | as a separator, relayCounters does not: -> get _tempRelayCounters - -15:Romantic Monster window begin loc=*:lparen.gif|25:Romantic Monster window end loc=* type=wander:rparen.gif|7:Digitize Monster loc=* type=wander:watch.gif|7:Digitize Monster loc=* type=wander:watch.gif|7:Digitize Monster loc=* type=wander:watch.gif| - -> get relayCounters - -70:Semirare window begin:lparen.gif:80:Semirare window end loc=*:rparen.gif - */ - string [int] counter_split = split_string(counter_string.replace_string("|", ":"), ":"); //FIXME | properly - //print_html("counter_split = " + counter_split.to_json()); - //Parse counters: - for i from 0 to (counter_split.count() - 1) by 3 - { - if (i + 3 > counter_split.count()) - break; - if (counter_split[i].length() == 0) - continue; - int turn_number = to_int_silent(counter_split[i]); - if (are_temp_counters) - turn_number += my_turncount(); - int turns_until_counter = turn_number - my_turncount(); - string counter_name_raw = counter_split[i + 1]; - string counter_gif = counter_split[i + 2]; - string location_id; - string type; - string intermediate_name = counter_name_raw; - //print_html("intermediate_name = " + intermediate_name + ", turn_number = " + turn_number + ", turns_until_counter = " + turns_until_counter); - - //Parse loc, remove it from intermediate name: - //loc=* type=wander - - string [string] set_properties; - - string [int][int] properties_found = intermediate_name.group_string(" ([^= ]*)=([^ ]*)"); - //print_html("intermediate_name = " + intermediate_name + " properties_found = " + properties_found.to_json()); - - foreach key in properties_found - { - string entire_match = properties_found[key][0]; - set_properties[properties_found[key][1]] = properties_found[key][2]; - intermediate_name = intermediate_name.replace_string(entire_match, ""); - } - if (set_properties contains "loc") - location_id = set_properties["loc"]; - if (set_properties contains "type") - type = set_properties["type"]; - - /*string [int][int] location_match = group_string(intermediate_name, " loc=([0-9*]*)"); - if (location_match.count() > 0) - { - location_id = location_match[0][1]; - string end_string = " loc=" + location_id; - if (intermediate_name.stringHasSuffix(end_string)) - { - int clip_pos = intermediate_name.length() - end_string.length(); - if (clip_pos > 0) - intermediate_name = intermediate_name.substring(0, clip_pos); - else - intermediate_name = ""; - } - }*/ - - boolean is_window_start = false; - boolean is_window_end = false; - //Convert intermediate name to our internal representation: - if (intermediate_name.contains_text("window begin")) - { - //generic window - intermediate_name = intermediate_name.substring(0, intermediate_name.index_of(" window begin")); - is_window_start = true; - } - else if (intermediate_name.contains_text("window end")) - { - //generic window - intermediate_name = intermediate_name.substring(0, intermediate_name.index_of(" window end")); - is_window_end = true; - } - - - string final_name = intermediate_name; - final_name = final_name.entity_encode(); - - //Now create and edit our counter: - - Counter c = CounterMake(); - if (counters contains final_name) - c = counters[final_name]; - if (are_temp_counters) - c.waiting_for_adventure_php = true; - - c.name = final_name; - boolean should_add_gif = true; - if (c.mafia_gifs.count() > 0) - { - foreach key in c.mafia_gifs - { - if (c.mafia_gifs[key] == counter_gif) - should_add_gif = false; - } - } - if (should_add_gif) - c.mafia_gifs.listAppend(counter_gif); - c.location_id = location_id; - c.mafia_informed_type = type; - - if (is_window_start) - { - c.range_start_turn = turns_until_counter; - if (!c.found_end_turn_range) //haven't found an end turn range - implicitly set it to the start - c.range_end_turn = turns_until_counter; - c.found_start_turn_range = true; - } - else if (is_window_end) - { - c.range_end_turn = turns_until_counter; - c.found_end_turn_range = true; - } - else - { - if (c.name == "Dance Card" && turns_until_counter < 0) //bug: dance card is still in relayCounters after being met - { - continue; - } - //if (turns_until_counter >= 0) - if (true) - { - if (turns_until_counter >= 0 || c.name != "Semi-rare") - c.exact_turns.listAppend(MAX(0, turns_until_counter)); - sort c.exact_turns by value; - } - } - - counters[final_name] = c; - } - - /*if (my_path().id == PATH_LIVE_ASCEND_REPEAT && !(counters contains "Semi-rare")) - { - //We already have this information: - //(won't always be accurate) - Counter c = CounterMake(); - c.name = "Semi-rare"; - int next_turn = 75; - while (next_turn < my_turncount()) - { - next_turn += 110; - } - next_turn -= my_turncount(); - c.exact_turns.listAppend(next_turn); - counters["Semi-rare"] = c; - }*/ -} - -Counter [string] __active_counters; //Try to avoid referencing directly -Counter [string] __active_temp_counters; - -boolean __counters_inited = false; -int __counters_turn_inited = -1; -string __counters_inited_property_value; -void CountersInit() -{ - if (__counters_inited && __counters_turn_inited == my_turncount() && __counters_inited_property_value == get_property("relayCounters")) - return; - __counters_inited = true; - __counters_turn_inited = my_turncount(); - __counters_inited_property_value = get_property("relayCounters"); - - //parse counters: - //Examples: - //relayCounters(user, now '1378:Fortune Cookie:fortune.gif', default ) - //relayCounters(user, now '1539:Semirare window begin loc=*:lparen.gif:1579:Semirare window end loc=*:rparen.gif', default ) - //relayCounters(user, now '70:Semirare window begin:lparen.gif:80:Semirare window end loc=*:rparen.gif', default ) - //relayCounters(user, now '1750:Romantic Monster window begin loc=*:lparen.gif:1760:Romantic Monster window end loc=*:rparen.gif', default ) - //relayCounters(user, now '7604:Fortune Cookie:fortune.gif:7584:Fortune Cookie:fortune.gif', default ) - //relayCounters(user, now '450:Fortune Cookie:fortune.gif:458:Fortune Cookie:fortune.gif:401:Dance Card loc=109:guildapp.gif', default ) - //relayCounters(user, now '1271:Nemesis Assassin window begin loc=*:lparen.gif:1286:Nemesis Assassin window end loc=*:rparen.gif:1331:Fortune Cookie:fortune.gif', default ) - //relayCounters(user, now '695:Nemesis Assassin window begin loc=*:lparen.gif:710:Nemesis Assassin window end loc=*:rparen.gif:780:Fortune Cookie:fortune.gif:685:Dance Card loc=109:guildapp.gif', default ) - //70:Semirare window begin:lparen.gif:80:Semirare window end loc=*:rparen.gif:57:Digitize Monster:watch.gif:57:Romantic Monster window begin loc=*:lparen.gif:67:Romantic Monster window end loc=*:rparen.gif - - foreach key in __active_counters - { - remove __active_counters[key]; - } - foreach key in __active_temp_counters - { - remove __active_temp_counters[key]; - } - CountersParseProperty("relayCounters", __active_counters, false); - CountersParseProperty("_tempRelayCounters", __active_temp_counters, true); - - //print_html("__active_counters = " + __active_counters.to_json()); - -} - -Counter CounterLookup(string counter_name, Error found, boolean allow_temp_counters) -{ - CountersInit(); - if (__active_counters contains counter_name) - { - return __active_counters[counter_name]; - } - else if (allow_temp_counters && __active_temp_counters contains counter_name) - { - return __active_temp_counters[counter_name]; - } - else - { - found.ErrorSet(); - return CounterMake(); - } -} - - -Counter CounterLookup(string counter_name, Error found) -{ - return CounterLookup(counter_name, found, false); -} - -Counter CounterLookup(string counter_name, boolean allow_temp_counters) -{ - return CounterLookup(counter_name, ErrorMake(), allow_temp_counters); -} - -Counter CounterLookup(string counter_name) -{ - return CounterLookup(counter_name, ErrorMake()); -} - -string [int] CounterGetAllNames(boolean allow_temp_counters) -{ - string [int] names; - foreach name in __active_counters - names.listAppend(name); - if (allow_temp_counters) - { - foreach name in __active_temp_counters - names.listAppend(name); - } - return names; -} - -string [int] CounterGetAllNames() -{ - return CounterGetAllNames(false); -} - -void CountersReparse() -{ - __counters_inited = false; - CountersInit(); -} - - - -//Bee is wrong, mafia does not track properly. -boolean [string] __wandering_monster_counter_names = $strings[Romantic Monster,Rain Monster,Holiday Monster,Nemesis Assassin,WoL Monster,Digitize Monster,Enamorang Monster,portscan.edu]; -string [string] __wandering_monster_property_lookups {"Romantic Monster":"romanticTarget", "Digitize Monster": "_sourceTerminalDigitizeMonster", "Enamorang Monster":"enamorangMonster"}; - -//This is for ascension automation scripts. Call this immediately before adventuring in an adventure.php zone. -//This will enable tracking of zero-adventure encounters that mean a wandering monster will not appear next turn. Affects CounterWanderingMonsterMayHitNextTurn() only. -int __last_turn_definitely_visited_adventure_php = -1; -void CounterAdviseAboutToVisitAdventurePHP() -{ - __last_turn_definitely_visited_adventure_php = my_turncount(); -} - -void CounterAdviseLastTurnAttemptedAdventurePHP(int turn) -{ - __last_turn_definitely_visited_adventure_php = turn; -} - -boolean CounterWanderingMonsterMayHitNextTurn() -{ - monster last_monster = get_property_monster("lastEncounter"); - - if (my_path().id == PATH_THE_SOURCE) - { - int interval = get_property_int("sourceInterval"); - if (interval == 200 || interval == 400) - return true; - } - if (get_property("questG04Nemesis") == "step17") //first wanderer in nemesis quest - return true; - - if (__last_turn_definitely_visited_adventure_php == -1 && $monsters[Black Crayon Beast,Black Crayon Beetle,Black Crayon Constellation,Black Crayon Golem,Black Crayon Demon,Black Crayon Man,Black Crayon Elemental,Black Crayon Crimbo Elf,Black Crayon Fish,Black Crayon Goblin,Black Crayon Hippy,Black Crayon Hobo,Black Crayon Shambling Monstrosity,Black Crayon Manloid,Black Crayon Mer-kin,Black Crayon Frat Orc,Black Crayon Penguin,Black Crayon Pirate,Black Crayon Flower,Black Crayon Slime,Black Crayon Undead Thing,Black Crayon Spiraling Shape,angry bassist,blue-haired girl,evil ex-girlfriend,peeved roommate,random scenester] contains last_monster) //bit of a hack - if they just fought a hipster monster (hopefully not faxing it), then the wandering monster isn't up this turn. though... __last_turn_definitely_visited_adventure_php should handle that... - { - return false; - } - if (my_turncount() == __last_turn_definitely_visited_adventure_php && __last_turn_definitely_visited_adventure_php != -1) //that adventure didn't advance the counter; no wandering monsters. also, does lights out override wanderers? but, what if there are TWO wandering monsters? the plot thickens - { - string last_encounter = get_property("lastEncounter"); - location last_location = get_property_location("lastAdventure"); - if (!($strings[Lights Out,Wooof! Wooooooof!,Playing Fetch*,Your Dog Found Something Again,Gunbowwowder,Seeing-Eyes Dog] contains last_encounter) && !(last_location != $location[none] && !last_location.locationAllowsWanderingMonsters())) - return false; - } - //FIXME use CounterWanderingMonsterMayHitInXTurns to implement this once we're sure it works - foreach s in __wandering_monster_counter_names - { - if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug - if (s == "Romantic Monster" && get_property_int("_romanticFightsLeft") == 0) //If mafia's tracking doesn't recognise the monster, then we can override by decrementing the romantic fights left. Added because of the machine elf tunnels. - continue; - Counter c = CounterLookup(s); - if (c.CounterExists() && c.CounterMayHitNextTurn()) - { - return true; - } - } - if (get_property_int("_romanticFightsLeft") > 0 && !CounterLookup("Romantic Monster").CounterExists() && my_path().id != PATH_ONE_CRAZY_RANDOM_SUMMER) //mafia will clear the romantic monster window if it goes out of bounds - return true; - - //Disabled for now, because this is hard to predict: - /*boolean [string] holidays = getHolidaysToday(); - foreach s in $strings[Feast of Boris,El Dia de Los Muertos Borrachos] - { - if (!holidays[s]) continue; - if (!CounterLookup("Holiday Monster").CounterExists()) - { - return true; - } - }*/ - return false; -} - -//only_detect_by_counter_names or in other words "not source agents", which we use in exactly one place for an obscure situation. -boolean CounterWanderingMonsterMayHitInXTurns(int turns, boolean only_detect_by_counter_names) -{ - if (CounterWanderingMonsterMayHitNextTurn() && !only_detect_by_counter_names) - return true; - foreach s in __wandering_monster_counter_names - { - if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug - if (CounterLookup(s).CounterExists() && CounterLookup(s).CounterMayHitInXTurns(turns)) - return true; - } - //if (get_property_int("_romanticFightsLeft") > 0 && !CounterLookup("Romantic Monster").CounterExists() && my_path().id != PATH_ONE_CRAZY_RANDOM_SUMMER) //mafia will clear the romantic monster window if it goes out of bounds - //return true; - return false; -} -boolean CounterWanderingMonsterMayHitInXTurns(int turns) -{ - return CounterWanderingMonsterMayHitInXTurns(turns, false); -} - -boolean CounterWanderingMonsterWillHitInXTurns(int turns) -{ - //CounterWillHitExactlyInTurnRange - foreach s in __wandering_monster_counter_names - { - if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug - if (CounterLookup(s).CounterExists() && CounterLookup(s).CounterWillHitExactlyInTurnRange(0, turns)) - return true; - } - return false; -} - -Counter [int] CounterWanderingMonsterWindowsActiveInXTurns(int turns) -{ - Counter [int] result; - foreach s in __wandering_monster_counter_names - { - if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug - Counter c = CounterLookup(s); - if (c.CounterExists() && c.CounterMayHitInXTurns(turns)) - result[result.count()] = c; - } - return result; -} - -Counter [int] CounterWanderingMonsterWindowsActiveNextTurn() -{ - Counter [int] result; - if (!CounterWanderingMonsterMayHitNextTurn()) - return result; - foreach s in __wandering_monster_counter_names - { - if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug - Counter c = CounterLookup(s); - if (c.CounterExists() && c.CounterMayHitNextTurn()) - result[result.count()] = c; - } - return result; -} - -boolean [monster] CounterWanderingMonstersActiveNextTurn() -{ - boolean [monster] result; - foreach key, c in CounterWanderingMonsterWindowsActiveNextTurn() - { - if (__wandering_monster_property_lookups contains c.name) - result[get_property_monster(__wandering_monster_property_lookups[c.name])] = true; - //result - } - //FIXME determine Rain Monster,Holiday Monster,Nemesis Assassin,Bee,WoL Monster - return result; -} - -boolean [monster] CounterWanderingMonstersActiveInXTurns(int turns) -{ - boolean [monster] result; - foreach key, c in CounterWanderingMonsterWindowsActiveInXTurns(turns) - { - if (__wandering_monster_property_lookups contains c.name) - result[get_property_monster(__wandering_monster_property_lookups[c.name])] = true; - //result - } - //FIXME determine Rain Monster,Holiday Monster,Nemesis Assassin,Bee,WoL Monster - return result; -} - -boolean CounterWanderingMonsterCountersHaveRange() -{ - foreach s in __wandering_monster_counter_names - { - if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug - Counter c = CounterLookup(s); - if (!c.CounterExists()) - continue; - if (c.CounterIsRange()) - return true; - } - return false; -} - - -boolean CounterWanderingMonsterWillHitNextTurn() -{ - if (!CounterWanderingMonsterMayHitNextTurn()) - return false; - foreach key, c in CounterWanderingMonsterWindowsActiveNextTurn() - { - if (c.CounterWillHitNextTurn()) - { - return true; - } - } - return false; -} - -boolean CounterWanderingMonstersCurrentlyActiveNextTurnAreFree() -{ - boolean [monster] monsters = CounterWanderingMonstersActiveNextTurn(); - if (monsters.count() == 0) - return false; - foreach m in monsters - { - if (!m.monster_has_zero_turn_cost()) - return false; - } - return true; -} - - -boolean CounterWanderingMonstersCurrentlyAroundAreFree() -{ - boolean [monster] monsters = CounterWanderingMonstersActiveInXTurns(10000); //FIXME better - if (monsters.count() == 0) - return false; - foreach m in monsters - { - if (!m.monster_has_zero_turn_cost()) - return false; - } - return true; -} - -boolean CounterWanderingMonstersCurrentlyAroundAreExact() //not exclusively, but at least one is -{ - foreach key, c in CounterWanderingMonsterWindowsActiveInXTurns(10000) //FIXME better - { - if (c.CounterExists() && !c.CounterIsRange()) - return true; - } - return false; -} - -CountersInit(); diff --git a/Source/relay/TourGuide/Support/Equipment Requirement.ash b/Source/relay/TourGuide/Support/Equipment Requirement.ash deleted file mode 100644 index 6f991e20..00000000 --- a/Source/relay/TourGuide/Support/Equipment Requirement.ash +++ /dev/null @@ -1,61 +0,0 @@ -import "relay/TourGuide/Support/Library.ash"; - -Record EquipmentStatRequirement -{ - stat requirement_stat; - int requirement_amount; -}; -static -{ - EquipmentStatRequirement [item] __equipment_stat_requirements; -} - -void initialiseEquipmentRequirements() -{ - if (__equipment_stat_requirements.count() > 0) - return; - Record equipment_txt_entry - { - int power; - string requirement; - string weapon_description; - }; - equipment_txt_entry [item] entries; - file_to_map("data/equipment.txt", entries); - - foreach it, entry in entries - { - if (entry.requirement == "" || entry.requirement == "none") - continue; - int requirement_integer = entry.requirement.split_string(" ")[1].to_int_silent(); - if (requirement_integer <= 0) - continue; - stat known_stat = $stat[none]; - if (entry.requirement.contains_text("Mus: ")) - { - known_stat = $stat[muscle]; - } - else if (entry.requirement.contains_text("Mys: ")) - { - known_stat = $stat[mysticality]; - } - else if (entry.requirement.contains_text("Mox: ")) - { - known_stat = $stat[moxie]; - } - if (known_stat != $stat[none]) - { - EquipmentStatRequirement requirement; - requirement.requirement_stat = known_stat; - requirement.requirement_amount = requirement_integer; - - __equipment_stat_requirements[it] = requirement; - //__equipment_stat_requirements[it][known_stat] = requirement_integer; - } - } -} -EquipmentStatRequirement StatRequirementForEquipment(item it) -{ - initialiseEquipmentRequirements(); - return __equipment_stat_requirements[it]; -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Support/Error.ash b/Source/relay/TourGuide/Support/Error.ash deleted file mode 100644 index 2dd0befb..00000000 --- a/Source/relay/TourGuide/Support/Error.ash +++ /dev/null @@ -1,31 +0,0 @@ - -//Allows error checking. The intention behind this design is Errors are passed in to a method. The method then sets the error if anything went wrong. -record Error -{ - boolean was_error; - string explanation; -}; - -Error ErrorMake(boolean was_error, string explanation) -{ - Error err; - err.was_error = was_error; - err.explanation = explanation; - return err; -} - -Error ErrorMake() -{ - return ErrorMake(false, ""); -} - -void ErrorSet(Error err, string explanation) -{ - err.was_error = true; - err.explanation = explanation; -} - -void ErrorSet(Error err) -{ - ErrorSet(err, "Unknown"); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Support/Fold Groups.ash b/Source/relay/TourGuide/Support/Fold Groups.ash deleted file mode 100644 index a0e132ca..00000000 --- a/Source/relay/TourGuide/Support/Fold Groups.ash +++ /dev/null @@ -1,31 +0,0 @@ - - - -static -{ - boolean [item][item] __fold_groups; - - void generateFoldables() - { - string [int] foldgroups_file = file_to_array("data/foldgroups.txt"); - - foreach key, line in foldgroups_file - { - if (line.contains_text("#")) continue; //wrong, but I don't - string [int] line_split = line.split_string("\t"); - if (line_split.count() < 2) continue; - for i from 1 to line_split.count() - 1 - { - string v = line_split[i]; - item it = v.to_item(); - if (it == $item[none]) continue; - - foreach it2 in it.get_related("fold") - { - __fold_groups[it][it2] = true; - } - } - } - } - generateFoldables(); -} diff --git a/Source/relay/TourGuide/Support/HTML.ash b/Source/relay/TourGuide/Support/HTML.ash deleted file mode 100644 index acfdc29b..00000000 --- a/Source/relay/TourGuide/Support/HTML.ash +++ /dev/null @@ -1,190 +0,0 @@ -import "relay/TourGuide/Support/List.ash" - - -float __setting_indention_width_in_em = 1.45; -string __setting_indention_width = __setting_indention_width_in_em + "em"; - -string __html_right_arrow_character = "►"; - -buffer HTMLGenerateTagPrefix(string tag, string [string] attributes) -{ - buffer result; - result.append("<"); - result.append(tag); - foreach attribute_name, attribute_value in attributes - { - //string attribute_value = attributes[attribute_name]; - result.append(" "); - result.append(attribute_name); - if (attribute_value != "") - { - boolean is_integer = attribute_value.is_integer(); //don't put quotes around integer attributes (i.e. width, height) - - result.append("="); - if (!is_integer) - result.append("\""); - result.append(attribute_value); - if (!is_integer) - result.append("\""); - } - } - result.append(">"); - return result; -} - -buffer HTMLGenerateTagPrefix(string tag) -{ - buffer result; - result.append("<"); - result.append(tag); - result.append(">"); - return result; -} - -buffer HTMLGenerateTagSuffix(string tag) -{ - buffer result; - result.append(""); - return result; -} - -buffer HTMLGenerateTagWrap(string tag, string source, string [string] attributes) -{ - buffer result; - result.append(HTMLGenerateTagPrefix(tag, attributes)); - result.append(source); - result.append(HTMLGenerateTagSuffix(tag)); - return result; -} - -buffer HTMLGenerateTagWrap(string tag, string source) -{ - buffer result; - result.append(HTMLGenerateTagPrefix(tag)); - result.append(source); - result.append(HTMLGenerateTagSuffix(tag)); - return result; -} - -buffer HTMLGenerateDivOfClass(string source, string class_name) -{ - if (class_name == "") - return HTMLGenerateTagWrap("div", source); - else - return HTMLGenerateTagWrap("div", source, mapMake("class", class_name)); -} - -buffer HTMLGenerateDivOfClass(string source, string class_name, string extra_style) -{ - return HTMLGenerateTagWrap("div", source, mapMake("class", class_name, "style", extra_style)); -} - -buffer HTMLGenerateDivOfStyle(string source, string style) -{ - if (style == "") - return HTMLGenerateTagWrap("div", source); - - return HTMLGenerateTagWrap("div", source, mapMake("style", style)); -} - -buffer HTMLGenerateDiv(string source) -{ - return HTMLGenerateTagWrap("div", source); -} - -buffer HTMLGenerateSpan(string source) -{ - return HTMLGenerateTagWrap("span", source); -} - -buffer HTMLGenerateSpanOfClass(string source, string class_name) -{ - if (class_name == "") - return HTMLGenerateTagWrap("span", source); - else - return HTMLGenerateTagWrap("span", source, mapMake("class", class_name)); -} - -buffer HTMLGenerateSpanOfStyle(string source, string style) -{ - if (style == "") - { - buffer out; - out.append(source); - return out; - } - return HTMLGenerateTagWrap("span", source, mapMake("style", style)); -} - -buffer HTMLGenerateSpanFont(string source, string font_colour, string font_size) -{ - if (font_colour == "" && font_size == "") - { - buffer out; - out.append(source); - return out; - } - - buffer style; - - if (font_colour != "") - { - //style += "color:" + font_colour + ";"; - style.append("color:"); - style.append(font_colour); - style.append(";"); - } - if (font_size != "") - { - //style += "font-size:" + font_size + ";"; - style.append("font-size:"); - style.append(font_size); - style.append(";"); - } - return HTMLGenerateSpanOfStyle(source, style.to_string()); -} - -buffer HTMLGenerateSpanFont(string source, string font_colour) -{ - return HTMLGenerateSpanFont(source, font_colour, ""); -} - -string HTMLConvertStringToAnchorID(string id) -{ - if (id.length() == 0) - return id; - - id = to_string(replace_string(id, " ", "_")); - //ID and NAME must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".") - - //FIXME do that - return id; -} - -string HTMLEscapeString(string line) -{ - return entity_encode(line); -} - -string HTMLStripTags(string html) -{ - matcher pattern = create_matcher("<[^>]*>", html); - return pattern.replace_all(""); -} - - -string [string] generateMainLinkMap(string url) -{ - return mapMake("class", "r_a_undecorated", "href", url, "target", "mainpane"); -} - - - -string HTMLGreyOutTextUnlessTrue(string text, boolean conditional) -{ - if (conditional) - return text; - return HTMLGenerateSpanFont(text, "gray"); -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Support/Holiday.ash b/Source/relay/TourGuide/Support/Holiday.ash deleted file mode 100644 index 3e807322..00000000 --- a/Source/relay/TourGuide/Support/Holiday.ash +++ /dev/null @@ -1,85 +0,0 @@ -boolean [string] getHolidaysForDate(string realworld_date, int game_day) -{ - boolean [string] holidays; - - if (realworld_date == "0202") - holidays["Groundhog Day"] = true; - //april fools - else if (realworld_date == "0401") - holidays["April Fool's Day"] = true; - //Talk Like a Pirate Day - september 19th - else if (realworld_date == "0919") - holidays["Talk Like a Pirate Day"] = true; - else if (realworld_date == "1031") - holidays["Halloween"] = true; - else if (realworld_date == "0214") - holidays["Valentine's Day"] = true; - else if (realworld_date == "0525") - holidays["Towel Day"] = true; - else if (realworld_date == "0704") - holidays["Dependence Day"] = true; - - //Crimbo - if (now_to_string("M").to_int_silent() == 12) - holidays["Crimbo"] = true; - - //Friday the 13th - if (format_today_to_string("EEE d") == "Fri 13") - holidays["Friday the 13th"] = true; - - - - //Festival of Jarlsberg - acquire the party hat? - Jarlsuary 1 - if (game_day == 0) - holidays["Festival of Jarlsberg"] = true; - //Valentine's Day! - Frankuary 4 - else if (game_day == 11) - holidays["Valentine's Day"] = true; - //St. Sneaky Pete's Day - Starch 3 - else if (game_day == 18) - holidays["St. Sneaky Pete's Day"] = true; - //Oyster Egg Day - April 2 - else if (game_day == 25) - holidays["Oyster Egg Day"] = true; - //El Dia de Los Muertos Borrachos? just wandering monsters... - Martinus 2 - else if (game_day == 33) - holidays["El Dia de Los Muertos Borrachos"] = true; - //Generic Summer Holiday - Bill 3 - else if (game_day == 42) - holidays["Generic Summer Holiday"] = true; - //Dependence Day - Bor 4 - else if (game_day == 51) - holidays["Dependence Day"] = true; - //Arrrbor Day - Petember 4 - else if (game_day == 59) - holidays["Arrrbor Day"] = true; - //Labór Day - Carlvember 6 - else if (game_day == 69) - holidays["Labór Day"] = true; - //Halloween / halloween tomorrow, save adventures? - Porktober 8 - else if (game_day == 79) - holidays["Halloween"] = true; - //feast of boris...? - Boozember 7 - else if (game_day == 86) - holidays["Feast of Boris"] = true; - //Yuletide? - Dougtember 4 - else if (game_day == 91) - holidays["Yuletide"] = true; - - - return holidays; -} - -boolean [string] getHolidaysToday() -{ - boolean [string] holidays = getHolidaysForDate(format_today_to_string("MMdd"), gameday_to_int()); //FIXME Y10K error - if (holiday() != "") - holidays[holiday()] = true; - return holidays; -} - -boolean [string] getHolidaysTomorrow() -{ - //FIXME support next real-world day - return getHolidaysForDate("", ((gameday_to_int() + 1) % 96)); -} diff --git a/Source/relay/TourGuide/Support/IOTMs.ash b/Source/relay/TourGuide/Support/IOTMs.ash deleted file mode 100644 index c8f8e42c..00000000 --- a/Source/relay/TourGuide/Support/IOTMs.ash +++ /dev/null @@ -1,320 +0,0 @@ -import "relay/TourGuide/QuestState.ash" -import "relay/TourGuide/Support/Campground.ash" - -boolean [item] __iotms_usable; - -void replicaCheck(string iotmName) { - // helper function for checking ownership of either the item or the - // legacy of loathing replica of said item - - int amountItem = lookupItem(iotmName).available_amount(); - int amountReplica = lookupItem("replica "+iotmName).available_amount(); - - if ((amountItem + amountReplica) > 0) { - __iotms_usable[lookupItem(iotmName)] = true; - } - else { - __iotms_usable[lookupItem(iotmName)] = false; - } -} - -void initialiseIOTMsUsable() -{ - foreach key in __iotms_usable - remove __iotms_usable[key]; - - if (in_bad_moon()) - return; - - // ... for futureproofing, we should probably just make a thing in the library that explicitly denotes no-campground paths - // and incorporate them here. Not really sure why ezan didn't, it's possible mafia tracking is just uniquely wrong in ed? - - if (my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) - { - //Campground items: - foreach it in $items[source terminal, haunted doghouse, Witchess Set, potted tea tree, portable mayo clinic, Little Geneticist DNA-Splicing Lab, cornucopia, A Guide to Burning Leaves] - { - if (__campground[it] > 0) - __iotms_usable[it] = true; - } - // Workshed - if (__campground[lookupItem("Asdon Martin keyfob")] > 0) - __iotms_usable[lookupItem("Asdon Martin keyfob")] = true; - if (__campground[lookupItem("diabolic pizza cube")] > 0) - __iotms_usable[lookupItem("diabolic pizza cube")] = true; - if (__campground[lookupItem("cold medicine cabinet")] > 0) - __iotms_usable[lookupItem("cold medicine cabinet")] = true; - if (__campground[lookupItem("model train set")] > 0) - __iotms_usable[lookupItem("model train set")] = true; - - // This didn't appear in my LoL test run; I am making this more explicit and hopefully this works. - if (__campground[lookupItem("Little Geneticist DNA-Splicing Lab")] > 0) - __iotms_usable[lookupItem("Little Geneticist DNA-Splicing Lab")] = true; - if (__campground[lookupItem("Replica Little Geneticist DNA-Splicing Lab")] > 0) - __iotms_usable[lookupItem("Little Geneticist DNA-Splicing Lab")] = true; - - // __iotms_usable for gardens tracks whether the user has the garden installed. - // Gardens start returning 0 instead of 1 when the items are picked, so checking - // presence of the key is more useful than checking the value. - foreach garden in $items[packet of mushroom spores, packet of rock seeds] - { - if (__campground contains garden) - __iotms_usable[garden] = true; - } - } - if (florist_available() && $item[hand turkey outline].is_unrestricted()) //May 2013 - //Order of the Green Thumb Order Form is not marked as out of standard. - __iotms_usable[$item[Order of the Green Thumb Order Form]] = true; - if (get_property_boolean("sleazeAirportAlways") || get_property_boolean("_sleazeAirportToday")) //May 2014 - __iotms_usable[$item[airplane charter: Spring Break Beach]] = true; - if (get_property_boolean("spookyAirportAlways") || get_property_boolean("_spookyAirportToday")) //Oct 2014 - __iotms_usable[$item[airplane charter: Conspiracy Island]] = true; - if (get_property_boolean("chateauAvailable")) //Jan 2015 - __iotms_usable[$item[Chateau Mantegna room key]] = true; - if (get_property_boolean("lovebugsUnlocked") && $item[hand turkey outline].is_unrestricted()) //Feb 2015 - __iotms_usable[$item[bottle of lovebug pheromones]] = true; - if (get_property_boolean("stenchAirportAlways") || get_property_boolean("_stenchAirportToday")) //Apr 2015 - __iotms_usable[$item[airplane charter: Dinseylandfill]] = true; - // if (lookupItem("Deck of Every Card").available_amount() > 0) //Jul 2015 - // __iotms_usable[$item[Deck of Every Card]] = true; - if (get_property_boolean("hotAirportAlways") || get_property_boolean("_hotAirportToday")) //Aug 2015 - __iotms_usable[$item[Airplane charter: That 70s Volcano]] = true; - if (get_property_boolean("barrelShrineUnlocked")) //Sep 2015 - __iotms_usable[$item[shrine to the Barrel god]] = true; - if (get_property_boolean("coldAirportAlways") || get_property_boolean("_coldAirportToday")) //Nov 2015 - __iotms_usable[$item[Airplane charter: The Glaciest]] = true; - if (get_property_boolean("snojoAvailable")) //Jan 2016 - __iotms_usable[$item[X-32-F snowman crate]] = true; - if (get_property_boolean("telegraphOfficeAvailable")) //Feb 2016 - __iotms_usable[$item[LT&T telegraph office deed]] = true; - if (get_property_boolean("hasDetectiveSchool")) //Jul 2016 - __iotms_usable[$item[detective school application]] = true; - if (lookupItem("protonic accelerator pack").available_amount() > 0) //Aug 2016 - __iotms_usable[lookupItem("protonic accelerator pack")] = true; - if (lookupItem("Time-Spinner").available_amount() > 0) //Sep 2016 - __iotms_usable[lookupItem("Time-Spinner")] = true; - if (get_property_boolean("gingerbreadCityAvailable") || get_property_boolean("_gingerbreadCityToday")) //Dec 2016 - __iotms_usable[$item[Build-a-City Gingerbread kit]] = true; - if (get_property_boolean("loveTunnelAvailable")) //Feb 2017 - __iotms_usable[lookupItem("heart-shaped crate")] = true; - if (get_property_boolean("spacegateAlways") || get_property_boolean("_spacegateToday")) //Apr 2017 - __iotms_usable[lookupItem("Spacegate access badge")] = true; - if (lookupItem("kremlin's greatest briefcase").available_amount() > 0) //Jun 2017 - __iotms_usable[lookupItem("kremlin's greatest briefcase")] = true; - if (get_property_boolean("horseryAvailable")) //Aug 2017-18 - __iotms_usable[lookupItem("Horsery contract")] = true; - // if (lookupItem("genie bottle").available_amount() > 0) //Sep 2017 - // __iotms_usable[lookupItem("genie bottle")] = true; - if (lookupItem("portable pantogram").available_amount() > 0) //Nov 2017 - __iotms_usable[lookupItem("portable pantogram")] = true; - // if (lookupItem("January's Garbage Tote").available_amount() > 0) //Jan 2018 - // __iotms_usable[lookupItem("January's Garbage Tote")] = true; - if (get_property_boolean("_frToday") || get_property_boolean("frAlways")) //Apr 2018 - __iotms_usable[lookupItem("FantasyRealm membership packet")] = true; - if (get_property_boolean("_neverendingPartyToday") || get_property_boolean("neverendingPartyAlways")) //Sep 2018 - __iotms_usable[lookupItem("Neverending Party invitation envelope")] = true; - if (lookupItem("latte lovers member's mug").available_amount() > 0) //Oct 2018 - __iotms_usable[lookupItem("latte lovers member's mug")] = true; - if (get_property_boolean("_voteToday") || get_property_boolean("voteAlways") || lookupItem(""I Voted!" sticker").available_amount() > 0) //Nov 2018 - __iotms_usable[lookupItem("voter registration form")] = true; - if (get_property_boolean("daycareOpen")) //Dec 2018 - __iotms_usable[lookupItem("Boxing Day care package")] = true; - if (lookupItem("vampyric cloake").available_amount() > 0) //Mar 2019 - __iotms_usable[lookupItem("vampyric cloake")] = true; - // if (lookupItem("Fourth of May Cosplay Saber").available_amount() > 0) //May 2019 - // __iotms_usable[lookupItem("Fourth of May Cosplay Saber")] = true; - // if (lookupItem("hewn moon-rune spoon").available_amount() > 0) //Jun 2019 - // __iotms_usable[lookupItem("hewn moon-rune spoon")] = true; - if (get_property_boolean("getawayCampsiteUnlocked")) //Aug 2019 - __iotms_usable[lookupItem("Distant Woods Getaway Brochure")] = true; - if (lookupItem("Eight Days a Week Pill Keeper").available_amount() > 0) //Oct 2019 - __iotms_usable[lookupItem("Eight Days a Week Pill Keeper")] = true; - if (lookupItem("Bird-a-Day calendar").available_amount() > 0) //Jan 2020 - __iotms_usable[lookupItem("Bird-a-Day calendar")] = true; - if (lookupItem("unwrapped knock-off retro superhero cape").available_amount() > 0) //Nov 2020 - __iotms_usable[lookupItem("unwrapped knock-off retro superhero cape")] = true; - if (lookupItem("Potted power plant").available_amount() > 0) //Mar 2021 - __iotms_usable[lookupItem("Potted power plant")] = true; - if (lookupItem("cosmic bowling ball").available_amount() > 0 || get_property_int("_cosmicBowlingSkillsUsed") > 0) //Jan 2022 - // change to use tracking property if/when mafia adds one from coolitems.php - __iotms_usable[lookupItem("cosmic bowling ball")] = true; - - if (lookupItem("unbreakable umbrella").available_amount() > 0) //Mar 2022 - __iotms_usable[lookupItem("unbreakable umbrella")] = true; - - if (available_amount($item[jurassic parka]) > 0) // adding because of a strange issue w/ Sneaks.ash... - __iotms_usable[$item[jurassic parka]] = true; - - if ($item[Clan VIP Lounge key].item_amount() > 0) - { - //FIXME all - __iotms_usable[lookupItem("Clan Carnival Game")] = true; - __iotms_usable[$item[clan floundry]] = true; - } - - if (lookupItem("candy cane sword cane").available_amount() > 0) //Dec 2023 - __iotms_usable[lookupItem("candy cane sword cane")] = true; - - if (lookupItem("spring shoes").available_amount() > 0) //Feb 2024 - __iotms_usable[lookupItem("spring shoes")] = true; - - if (lookupItem("everfull dart holster").available_amount() > 0) //Mar 2024 - __iotms_usable[lookupItem("everfull dart holster")] = true; - - if (lookupItem("apriling band helmet").available_amount() > 0) //Apr 2024 - __iotms_usable[lookupItem("apriling band helmet")] = true; - - if (lookupItem("mayam calendar").available_amount() > 0) //May 2024 - __iotms_usable[lookupItem("mayam calendar")] = true; - - if (lookupItem("roman candelabra").available_amount() > 0) //Jun 2024 - __iotms_usable[lookupItem("roman candelabra")] = true; - - if (lookupItem("tearaway pants").available_amount() > 0) //Aug 2024 - __iotms_usable[lookupItem("tearaway pants")] = true; - - //Can't use many things in G-Lover - if (my_path().id == PATH_G_LOVER) //Path 33 - { - __iotms_usable[lookupItem("Bird-a-Day calendar")] = false; - __iotms_usable[lookupItem("Deck of Every Card")] = false; - __iotms_usable[lookupItem("Fourth of May Cosplay Saber")] = false; - __iotms_usable[lookupItem("hewn moon-rune spoon")] = false; - __iotms_usable[lookupItem("Potted power plant")] = false; - __iotms_usable[lookupItem("protonic accelerator pack")] = false; - __iotms_usable[lookupItem("Time-Spinner")] = false; - __iotms_usable[lookupItem("unbreakable umbrella")] = false; - __iotms_usable[lookupItem("Underground Fireworks Shop")] = false; //can't use any items here - __iotms_usable[lookupItem("unwrapped knock-off retro superhero cape")] = false; - __iotms_usable[lookupItem("vampyric cloake")] = false; - } - if (my_path().id == PATH_EXPLOSIONS) //Path 37 - { - __iotms_usable[lookupItem("Spacegate access badge")] = false; - } - - // Remove non-standard. Do this prior to replicaChecks, since replicas allow - // usage of non-standard IOTMs. - foreach it in __iotms_usable - { - if (!it.is_unrestricted() || it == $item[none]) - remove __iotms_usable[it]; - } - - // Legacy of Loathing introduced a whole host of replica IOTMs. In order - // to properly support LoL, it was decided that the easiest way to work - // this is to reinstitute __iotms_usable for the last few years of IOTMs - // and make it so that ownership of the replica flags as ownership of the - // real deal. Alternative would've been to make every item check a boolean - // that checks ownership of either/or, and this feels... less bad, to me. - - // One note -- familiars are the same as the real deal, so they don't need - // checks (I don't think?). This only applies for items explicitly formatted - // as "replica [itemname]". Another note -- we did not add a path check here, - // mostly owing to the fact that the replicaCheck function also works for - // the real iotms, which means it'll properly populate __iotms_usable... - // even outside of LoL. - - // One last note -- I have noted where each is used in TourGuide. This is - // mostly a check for me personally, to make sure I have looked at each. - // We could delete the "no tile" entries at any time. I just didn't want to! - - // 2005 - replicaCheck("miniature gravy-covered maypole"); # no tile - replicaCheck("wax lips"); # no tile - - // 2006 - - // This won't show up for the natural tome, because you never have the tome item in your inventory. Just pings for replica. - replicaCheck("Tome of Snowcone Summoning"); # handled in tomes.ash - replicaCheck("jewel-eyed wizard hat"); # no tile - replicaCheck("plastic pumpkin bucket"); # no tile; fixed in passive damage engines - - // 2007 - replicaCheck("V for Vivala mask"); # handled in Misc Items.ash - replicaCheck("navel ring of navel gazing"); # handled in Misc Items.ash - replicaCheck("bottle-rocket crossbow"); # no tile - - // 2008 - replicaCheck("little box of fireworks"); # no tile - replicaCheck("haiku katana"); # no tile - - // 2009 - replicaCheck("Elvish Sunglasses"); # no tile - - // 2010 - replicaCheck("Juju Mojo Mask"); # no tile - replicaCheck("Greatest American Pants"); # handled in Misc Items.ash - - // 2011 - replicaCheck("Operation Patriot Shield"); # no tile - replicaCheck("plastic vampire fangs"); # handled in own tile - - // 2012 - replicaCheck("Libram of Resolutions"); # handled in tomes.ash - replicaCheck("Camp Scout backpack"); # no tile - - // 2013 - replicaCheck("over-the-shoulder Folder Holder"); # no tile - replicaCheck("Smith's Tome"); # handled in tomes.ash - - // 2014 - // replicaCheck(""); # handled in DNA.ash; already used __iotms_usable! - // 2015 - if (lookupItem("replica Little Geneticist DNA-Splicing Lab").available_amount() > 0) - __iotms_usable[$item[Little Geneticist DNA-Splicing Lab]] = true; - - // 2015 - if (get_property_boolean("replicaChateauAvailable")) - __iotms_usable[$item[Chateau Mantegna room key]] = true; # handled in daily + state - replicaCheck("Deck of Every Card"); # handled in tile & lvl8 - - // 2016 - if (get_property_boolean("replicaWitchessSetAvailable")) - __iotms_usable[$item[Witchess Set]] = true; # handled in own tile - replicaCheck("Source terminal"); # handled in own tile - - // 2017 - replicaCheck("genie bottle"); # handled in own tile - - // 2018 - replicaCheck("January's Garbage Tote"); # handled in own tile - if (get_property_boolean("replicaNeverendingPartyAlways")) - __iotms_usable[$item[Neverending Party invitation envelope]] = true; # handled in own tile - - // 2019 - replicaCheck("Kramco Sausage-o-Matic™"); # handled in own tile - replicaCheck("Fourth of May Cosplay Saber"); # handled in own tile & lvl 12 - replicaCheck("hewn moon-rune spoon"); # handled in own tile - - // 2020 - replicaCheck("Powerful Glove"); # handled in own tile - replicaCheck("Cargo Cultist Shorts"); # handled in own tile - - // 2021 - replicaCheck("miniature crystal ball"); # handled in own tile - replicaCheck("emotion chip"); # handled in own (annoying) tile - replicaCheck("industrial fire extinguisher"); # handled in own tile & lvl 11 - - // 2022 - replicaCheck("designer sweatpants"); # handled in own tile - replicaCheck("Jurassic Parka"); # handled in own tile - - // 2023 - replicaCheck("Cincho de Mayo"); # handled in own tile & sneaks.ash - replicaCheck("2002 Mr. Store Catalog"); # handled in own tile - replicaCheck("August Scepter"); # handled in own tile - - // Swap parka to false if you aren't torso aware. You cannot use the __misc_state - // shortcuts here, because this comes before it in execution. That's a sad - // disadvantage of all our bundling, did not remotely realize state wasn't - // instantiated before this. That means the parka stuff hasn't shown up since - // Legacy of Loathing lmao. - if (!$skill[12].have_skill()) - { - __iotms_usable[lookupItem("Jurassic Parka")] = false; - } - -} - -initialiseIOTMsUsable(); diff --git a/Source/relay/TourGuide/Support/Ingredients.ash b/Source/relay/TourGuide/Support/Ingredients.ash deleted file mode 100644 index d7b74204..00000000 --- a/Source/relay/TourGuide/Support/Ingredients.ash +++ /dev/null @@ -1,308 +0,0 @@ - -/* -Discovery - get_ingredients() takes up to 5.8ms per call, scaling to inventory size. Fixing the code in mafia might be possible, but it's old and looks complicated. -This implementation is not 1:1 compatible, as it doesn't take into account your current status, but we don't generally need that information(?). -*/ - -//Relevant prototype: -//int [item] get_ingredients_fast(item it) - - -static -{ - int [item][item] __item_ingredients; - boolean [item] __item_is_purchasable_from_a_store; -} - - - -boolean parseDatafileItem(int [item] out, string item_name) -{ - if (item_name == "") return false; - - item it = item_name.to_item(); - if (it != $item[none]) - { - out[it] += 1; - } - else if (item_name.contains_text("(")) - { - //Do complicated parsing. - //NOTE: "CRIMBCO Employee Handbook (chapter 1)" and "snow berries (7)" are both valid entries that mean different things. - string [int][int] matches = item_name.group_string("(.*?) \\(([0-9]*)\\)"); - if (matches[0].count() == 3) - { - it = matches[0][1].to_item(); - int amount = matches[0][2].to_int(); - if (it != $item[none] && amount > 0) - { - out[it] += amount; - } - } - } - return true; -} - - -Record ConcoctionMapEntry -{ - //Only way I know how to parse this file with file_to_map. string [int] won't work, string [string] won't... - string craft_type; - string mixing_item_1; - string mixing_item_2; - string mixing_item_3; - string mixing_item_4; - string mixing_item_5; - string mixing_item_6; - string mixing_item_7; - string mixing_item_8; - string mixing_item_9; - string mixing_item_10; - string mixing_item_11; - string mixing_item_12; - string mixing_item_13; - string mixing_item_14; - string mixing_item_15; - string mixing_item_16; - string mixing_item_17; - string mixing_item_18; -}; - -void parseConcoction(int [item] ingredients, ConcoctionMapEntry c) -{ - //If this ever shows up somewhere, please understand, it's not my fault file_to_map works this way. - if (!parseDatafileItem(ingredients, c.mixing_item_1)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_2)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_3)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_4)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_5)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_6)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_7)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_8)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_9)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_10)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_11)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_12)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_13)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_14)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_15)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_16)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_17)) - return; - if (!parseDatafileItem(ingredients, c.mixing_item_18)) - return; -} - -void initialiseItemIngredients() -{ - if (__item_ingredients.count() > 0) return; - - //Parse concoctions: - //Highest observed so far: 17. - if (true) - { - string [string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string] concoctions_map_2; - file_to_map("data/concoctions.txt", concoctions_map_2); - foreach crafting_thing, crafting_type, mixing_item_1, mixing_item_2, mixing_item_3, mixing_item_4, mixing_item_5, mixing_item_6, mixing_item_7, mixing_item_8, mixing_item_9, mixing_item_10, mixing_item_11, mixing_item_12, mixing_item_13, mixing_item_14, mixing_item_15, mixing_item_16, mixing_item_17, mixing_item_18 in concoctions_map_2 - { - if (crafting_type == "SUSHI" || crafting_type == "VYKEA") continue; //not really items - if (crafting_type == "CLIPART") continue; //bucket of wine is not made of three turtle totems - item it = crafting_thing.to_item(); - if (it == $item[none]) - { - int [item] item_results; - parseDatafileItem(item_results, crafting_thing); - if (item_results.count() == 0) - { - //print_html("Unknown crafting_thing " + crafting_thing); - continue; - } - foreach it2 in item_results - it = it2; - } - if (crafting_type.contains_text("ROW")) - __item_is_purchasable_from_a_store[it] = true; - if (__item_ingredients contains it) continue; //mafia uses first defined entry - - int [item] ingredients; - //Create map entry: - ConcoctionMapEntry c; - c.craft_type = crafting_type; - c.mixing_item_1 = mixing_item_1; - c.mixing_item_2 = mixing_item_2; - c.mixing_item_3 = mixing_item_3; - c.mixing_item_4 = mixing_item_4; - c.mixing_item_5 = mixing_item_5; - c.mixing_item_6 = mixing_item_6; - c.mixing_item_7 = mixing_item_7; - c.mixing_item_8 = mixing_item_8; - c.mixing_item_9 = mixing_item_9; - c.mixing_item_10 = mixing_item_10; - c.mixing_item_11 = mixing_item_11; - c.mixing_item_12 = mixing_item_12; - c.mixing_item_13 = mixing_item_13; - c.mixing_item_14 = mixing_item_14; - c.mixing_item_15 = mixing_item_15; - c.mixing_item_16 = mixing_item_16; - c.mixing_item_17 = mixing_item_17; - c.mixing_item_18 = mixing_item_18; - - parseConcoction(ingredients, c); - - if (ingredients.count() > 0) - __item_ingredients[it] = ingredients; - } - } - else - { - //Not compatible. - //Concoction manager seems to read the first entry, not the second. file_to_map reads the second. Example: spooky wad. - //Or maybe it's just random which the concoction manager uses? Example: bloody beer vs. spooky wad. Or it picks the one we can make...? - ConcoctionMapEntry [string] concoctions_map; - file_to_map("data/concoctions.txt", concoctions_map); - foreach crafting_thing in concoctions_map - { - ConcoctionMapEntry c = concoctions_map[crafting_thing]; - item it = crafting_thing.to_item(); - if (it == $item[none]) - continue; - - int [item] ingredients; - - parseConcoction(ingredients, c); - - if (__item_ingredients contains it) continue; //mafia uses first defined entry - if (ingredients.count() > 0) - __item_ingredients[it] = ingredients; - } - } - //Parse coinmasters: - - /*Record CoinmastersMapEntry - { - string buy_or_sell_type; - int amount; - item it; - string row_id; - }; - CoinmastersMapEntry [string] coinmasters_map;*/ - string [string,string,int,string] coinmasters_map; - file_to_map("data/coinmasters.txt", coinmasters_map); - //print_html("coinmasters_map = " + coinmasters_map.to_json()); - foreach master_name, type, amount, item_string in coinmasters_map - { - //FIXME track if coinmaster is accessible? - //print_html(master_name + ", " + type + ", " + amount + ", " + item_string); - if (type != "buy") continue; - coinmaster c = master_name.to_coinmaster(); - if (c == $coinmaster[none]) - { - //Hmm.... - //print_html(master_name + " is not a coinmaster"); - continue; - } - if (c.item == $item[none]) //bat-fabricator - continue; - item it = item_string.to_item(); - if (it == $item[none]) - { - //peppermint tailings (10) at the moment - //FIXME write this - continue; - } - - if (it == $item[none]) - continue; - - __item_is_purchasable_from_a_store[it] = true; - if (__item_ingredients contains it) continue; - - int [item] ingredients; - ingredients[c.item] = amount; - __item_ingredients[it] = ingredients; - } - -} - - -int [item] get_ingredients_fast(item it) -{ - //return it.get_ingredients(); - if (__item_ingredients.count() == 0) - initialiseItemIngredients(); - if (!(__item_ingredients contains it)) - { - //This is six milliseconds per call, but only if the item has an ingredient(?), so be wary: - int [item] ground_truth = it.get_ingredients(); - if (ground_truth.count() > 0) //We could cache it if it's empty, except sometimes that changes. - __item_ingredients[it] = ground_truth; - } - return __item_ingredients[it]; -} - -boolean item_is_purchasable_from_a_store(item it) -{ - return __item_is_purchasable_from_a_store[it]; -} - -boolean item_cannot_be_asdon_martined_because_it_was_purchased_from_a_store(item it) -{ - if ($items[wasabi pocky,tobiko pocky,natto pocky,wasabi-infused sake,tobiko-infused sake,natto-infused sake] contains it) return false; - return it.item_is_purchasable_from_a_store(); -} - -void testItemIngredients() -{ - initialiseItemIngredients(); - print_html(__item_ingredients.count() + " ingredients known."); - foreach it in $items[] - { - int [item] ground_truth_ingredients = it.get_ingredients(); - int [item] our_ingredients = get_ingredients_fast(it); - if (ground_truth_ingredients.count() == 0 && our_ingredients.count() == 0) continue; - - boolean passes = true; - if (ground_truth_ingredients.count() != our_ingredients.count()) - { - passes = false; - if (ground_truth_ingredients.count() == 0 && our_ingredients.count() > 0) //probably just a coinmaster - continue; - } - else - { - foreach it2, amount in ground_truth_ingredients - { - if (our_ingredients[it2] != amount) - { - passes = false; - break; - } - } - } - if (!passes) - { - print_html(it + ": " + ground_truth_ingredients.to_json() + " vs " + our_ingredients.to_json()); - } - } -} - -/*void main() -{ - testItemIngredients(); -}*/ diff --git a/Source/relay/TourGuide/Support/Item Filter.ash b/Source/relay/TourGuide/Support/Item Filter.ash deleted file mode 100644 index 647055d7..00000000 --- a/Source/relay/TourGuide/Support/Item Filter.ash +++ /dev/null @@ -1,114 +0,0 @@ - -static -{ - item [string][int] __if_potions_with_numeric_modifiers; - - - /*void ItemFilterInitialise() - { - boolean [string] modifier_names = $strings[Meat Drop,Initiative,Muscle,Mysticality,Moxie,Muscle Percent,Mysticality Percent,Moxie Percent]; - - foreach modifier_name in modifier_names - { - __if_potions_with_numeric_modifiers[modifier_name] = listMakeBlankItem(); - } - foreach it in $items[] - { - if (it.inebriety > 0 || it.fullness > 0 || it.spleen > 0) continue; - effect e = it.to_effect(); - if (e == $effect[none]) continue; - foreach modifier_name in modifier_names - { - if (e.numeric_modifier(modifier_name) > 0.0) - { - __if_potions_with_numeric_modifiers[modifier_name].listAppend(it); - } - } - } - } - - - ItemFilterInitialise();*/ -} - - -void ItemFilterInitialisePotionsForModifier(string numeric_modifier) -{ - if (__if_potions_with_numeric_modifiers contains numeric_modifier) - return; - __if_potions_with_numeric_modifiers[numeric_modifier] = listMakeBlankItem(); - - foreach it in $items[] - { - if (it.inebriety > 0 || it.fullness > 0 || it.spleen > 0) continue; - effect e = it.to_effect(); - if (e == $effect[none]) continue; - if (e.numeric_modifier(numeric_modifier) != 0.0) - { - __if_potions_with_numeric_modifiers[numeric_modifier].listAppend(it); - } - } -} - - -item [int] ItemFilterGetPotionsWithNumericModifiers(string [int] modifiers) -{ - item [int] potions; - boolean [item] seen_potions; - foreach key, modifier_string in modifiers - { - item [int] first_layer_list; - if (!(__if_potions_with_numeric_modifiers contains modifier_string)) - ItemFilterInitialisePotionsForModifier(modifier_string); - - first_layer_list = __if_potions_with_numeric_modifiers[modifier_string]; - - - foreach key, it in first_layer_list - { - if (!it.is_unrestricted()) - continue; - if (seen_potions contains it) - continue; - potions.listAppend(it); - seen_potions[it] = true; - } - } - - return potions; -} - -item [int] ItemFilterGetPotionsCouldPullToAddToNumericModifier(string [int] modifiers, float minimum_modifier, boolean [item] blacklist) -{ - item [int] relevant_potions_first_layer = ItemFilterGetPotionsWithNumericModifiers(modifiers); - - item [int] relevant_potions; - foreach key, it in relevant_potions_first_layer - { - if (it.available_amount() > 0) continue; - if (!it.tradeable && it.storage_amount() == 0) continue; - if (!it.item_is_usable()) continue; - effect e = it.to_effect(); - if (e.have_effect() > 0) continue; - if (!e.effect_is_usable()) continue; - float v = 0; - foreach key, modifier_string in modifiers - v += e.numeric_modifier(modifier_string); - if (v != 0.0 && v >= minimum_modifier && !(blacklist contains it)) - { - relevant_potions.listAppend(it); - } - } - if (modifiers.count() == 2) - sort relevant_potions by -(value.effect_modifier("effect").numeric_modifier(modifiers[0]) + value.effect_modifier("effect").numeric_modifier(modifiers[1])); - else - sort relevant_potions by -value.effect_modifier("effect").numeric_modifier(modifiers[0]); - - return relevant_potions; -} - - -item [int] ItemFilterGetPotionsCouldPullToAddToNumericModifier(string modifier_string, float minimum_modifier, boolean [item] blacklist) -{ - return ItemFilterGetPotionsCouldPullToAddToNumericModifier(listMake(modifier_string), minimum_modifier, blacklist); -} diff --git a/Source/relay/TourGuide/Support/KOLImage.ash b/Source/relay/TourGuide/Support/KOLImage.ash deleted file mode 100644 index bfbbe004..00000000 --- a/Source/relay/TourGuide/Support/KOLImage.ash +++ /dev/null @@ -1,777 +0,0 @@ -import "relay/TourGuide/Support/Math.ash" -import "relay/TourGuide/Support/HTML.ash" -import "relay/TourGuide/Support/Library.ash" -import "relay/TourGuide/Support/Page.ash" - -boolean __setting_show_alignment_guides = false; -//Library for displaying KOL images -//Each image is referred to by a string via KOLImageLookup, or KOLImageGenerateImageHTML -//There's a list of pre-set images in KOLImagesInit. Otherwise, it tries to look up the string as an item, then as a familiar, and then as an effect. If any matches are found, that image is output. (uses KoLmafia's internal database) -//Also "__item item name", "__familiar familiar name", and "__effect effect name" explicitly request those images. -//"__half lookup name" will reduce the image to half-size. -//NOTE: To use KOLImageGenerateImageHTML with should_centre set to true, the page must have the class "r_centre" set as "margin-left:auto; margin-right:auto;text-align:center;" - -Record ServerImageStats -{ - int width; - int height; - int minimum_y_coordinate; - int maximum_y_coordinate; -}; - -ServerImageStats ServerImageStatsMake(int width, int height, int minimum_y_coordinate, int maximum_y_coordinate) -{ - ServerImageStats result; - result.width = width; - result.height = height; - result.minimum_y_coordinate = minimum_y_coordinate; - result.maximum_y_coordinate = maximum_y_coordinate; - return result; -} - -ServerImageStats ServerImageStatsMake() -{ - return ServerImageStatsMake(-1,-1,-1,-1); -} - -record KOLImage -{ - string url; - - Vec2i base_image_size; - Rect crop; - - Rect [int] erase_zones; //rectangular zones which are generated as white divs on the output. Erases specific sections of the image. Can be offset by one pixel depending on the browser, sorry. -}; - - -KOLImage KOLImageMake(string url, Vec2i base_image_size, Rect crop) -{ - KOLImage result; - result.url = url; - result.base_image_size = base_image_size; - result.crop = crop; - return result; -} - -KOLImage KOLImageMake(string url, Vec2i base_image_size) -{ - return KOLImageMake(url, base_image_size, RectZero()); -} - -KOLImage KOLImageMake(string url) -{ - return KOLImageMake(url, Vec2iZero(), RectZero()); -} - -KOLImage KOLImageMake() -{ - return KOLImageMake("", Vec2iZero(), RectZero()); -} - - -static -{ - KOLImage [string] __kol_images; - - void initialiseConstantKOLImages() - { - // One note. In order to figure out RectMake here, you open up the respective images in an image editing program - // and figure out X/Y coordinates. I believe it's Xmin, Ymin, Xmax, Ymax. This is generally better than most - // other possible bespoke solutions. Thanks once again go to Ezandora, the queen of human civilization. - - KOLimage [string] building_images; - building_images["typical tavern"] = KOLImageMake("images/otherimages/woods/tavern0.gif", Vec2iMake(100,100), RectMake(0,39,99,97)); - building_images["boss bat"] = KOLImageMake("images/adventureimages/bossbat.gif", Vec2iMake(100,100), RectMake(0,27,99,74)); - building_images["bugbear"] = KOLImageMake("images/adventureimages/fallsfromsky.gif", Vec2iMake(100,150)); - - building_images["twin peak"] = KOLImageMake("images/otherimages/orcchasm/highlands_main.gif", Vec2iMake(500, 250), RectMake(153,128,237,214)); - building_images["a-boo peak"] = KOLImageMake("images/otherimages/orcchasm/highlands_main.gif", Vec2iMake(500, 250), RectMake(40,134,127,218)); - building_images["oil peak"] = KOLImageMake("images/otherimages/orcchasm/highlands_main.gif", Vec2iMake(500, 250), RectMake(261,117,345,213)); - building_images["highland lord"] = KOLImageMake("images/otherimages/orcchasm/highlands_main.gif", Vec2iMake(500, 250), RectMake(375,73,457,144)); - building_images["orc chasm"] = KOLImageMake("images/otherimages/mountains/chasm.gif", Vec2iMake(100, 100), RectMake(0, 41, 99, 95)); - - building_images["spooky forest"] = KOLImageMake("images/otherimages/woods/forest.gif", Vec2iMake(100, 100), RectMake(12,39,91,93)); - building_images["council"] = KOLImageMake("images/otherimages/council.gif", Vec2iMake(100, 100), RectMake(0,26,99,73)); - - - building_images["daily dungeon"] = KOLImageMake("images/otherimages/town/dd1.gif", Vec2iMake(100,100), RectMake(28,44,71,86)); - building_images["clover"] = KOLImageMake("images/itemimages/clover.gif", Vec2iMake(30,30)); - - building_images["mayfly bait"] = KOLImageMake("images/itemimages/mayflynecklace.gif", Vec2iMake(30,30)); - building_images["spooky putty"] = KOLImageMake("images/itemimages/sputtysheet.gif", Vec2iMake(30,30)); - - building_images["fax machine"] = KOLImageMake("images/otherimages/clanhall/faxmachine.gif", Vec2iMake(100,100), RectMake(34,28,62,54)); - - building_images["unknown"] = KOLImageMake("images/itemimages/confused.gif", Vec2iMake(30,30)); - - building_images["goth kid"] = KOLImageMake("images/itemimages/crayongoth.gif", Vec2iMake(30,30)); - building_images["hipster"] = KOLImageMake("images/itemimages/minihipster.gif", Vec2iMake(30,30)); - - - building_images[""] = KOLImageMake("images/itemimages/blank.gif", Vec2iMake(30,30)); - building_images["blank"] = KOLImageMake("images/itemimages/blank.gif", Vec2iMake(30,30)); - building_images["demon summon"] = KOLImageMake("images/otherimages/manor/chamber.gif", Vec2iMake(100,100), RectMake(14, 12, 88, 66)); - - building_images["cobb's knob"] = KOLImageMake("images/otherimages/plains/knob2.gif", Vec2iMake(100,100), RectMake(12,43,86,78)); - - building_images["generic dwelling"] = KOLImageMake("images/otherimages/campground/rest4.gif", Vec2iMake(100,100), RectMake(0,26,95,99)); - - - building_images["forest friars"] = KOLImageMake("images/otherimages/woods/stones0.gif", Vec2iMake(100,100), RectMake(0, 24, 99, 99)); - building_images["cyrpt"] = KOLImageMake("images/otherimages/plains/cyrpt.gif", Vec2iMake(100,100), RectMake(0, 33, 99, 99)); - building_images["trapper"] = KOLImageMake("images/otherimages/thetrapper.gif", Vec2iMake(60,100), RectMake(0,11,59,96)); - - building_images["castle"] = KOLImageMake("images/otherimages/stalktop/beanstalk.gif", Vec2iMake(500,400), RectMake(234,158,362,290)); //experimental - half sized castle - building_images["penultimate fantasy airship"] = KOLImageMake("images/otherimages/stalktop/beanstalk.gif", Vec2iMake(500,400), RectMake(75, 231, 190, 367)); - building_images["lift, bro"] = KOLImageMake("images/adventureimages/fitposter.gif", Vec2iMake(100,100)); - //building_images["castle stairs up"] = KOLImageMake("images/adventureimages/giantstairsup.gif", Vec2iMake(100,100), RectMake(0, 8, 99, 85)); - building_images["castle stairs up"] = KOLImageMake("images/adventureimages/giantstairsup.gif", Vec2iMake(100,100), RectMake(20, 10, 74, 83)); - building_images["castle stairs up"].erase_zones.listAppend(RectMake(70, 78, 76, 84)); - - - building_images["goggles? yes!"] = KOLImageMake("images/adventureimages/steamposter.gif", Vec2iMake(100,100)); - //building_images["hole in the sky"] = KOLImageMake("images/otherimages/stalktop/beanstalk.gif", Vec2iMake(500,400), RectMake(403, 4, 487, 92)); - building_images["hole in the sky"] = KOLImageMake("images/otherimages/stalktop/beanstalk.gif", Vec2iMake(250,200), RectMake(201, 2, 243, 46)); - - building_images["macguffin"] = KOLImageMake("images/itemimages/macguffin.gif", Vec2iMake(30,30)); - building_images["island war"] = KOLImageMake("images/otherimages/sigils/warhiptat.gif", Vec2iMake(50,50), RectMake(0,12,49,35)); - building_images["naughty sorceress"] = KOLImageMake("images/adventureimages/sorcform1.gif", Vec2iMake(100,100)); - building_images["naughty sorceress lair"] = KOLImageMake("images/otherimages/main/map6.gif", Vec2iMake(100,100), RectMake(6,0,50,43)); - - building_images["king imprismed"] = KOLImageMake("images/otherimages/lair/kingprism1.gif", Vec2iMake(100,100)); - building_images["astral gash"] = KOLImageMake("images/otherimages/gash.gif", Vec2iMake(100,100)); - building_images["campsite"] = KOLImageMake("images/otherimages/plains/plains1.gif", Vec2iMake(100,100)); - building_images["trophy"] = KOLImageMake("images/otherimages/trophy/not_wearing_any_pants.gif", Vec2iMake(100,100)); - building_images["hidden temple"] = KOLImageMake("images/otherimages/woods/temple.gif", Vec2iMake(100,100), RectMake(16, 40, 89, 96)); - building_images["florist friar"] = KOLImageMake("images/adventureimages/floristfriar.gif", Vec2iMake(100,100), RectMake(31, 7, 77, 92)); - - - building_images["plant rutabeggar"] = KOLImageMake("images/otherimages/friarplants/plant2.gif", Vec2iMake(50,100), RectMake(1, 24, 47, 96)); - - building_images["plant stealing magnolia"] = KOLImageMake("images/otherimages/friarplants/plant12.gif", Vec2iMake(49,100), RectMake(3, 15, 43, 94)); - - building_images["plant shuffle truffle"] = KOLImageMake("images/otherimages/friarplants/plant24.gif", Vec2iMake(66,100), RectMake(4, 35, 63, 88)); - building_images["plant horn of plenty"] = KOLImageMake("images/otherimages/friarplants/plant22.gif", Vec2iMake(62,100), RectMake(4, 14, 58, 86)); - - building_images["plant rabid dogwood"] = KOLImageMake("images/otherimages/friarplants/plant1.gif", Vec2iMake(57,100), RectMake(3, 16, 55, 98)); - building_images["plant rad-ish radish"] = KOLImageMake("images/otherimages/friarplants/plant3.gif", Vec2iMake(48,100), RectMake(4, 14, 42, 96)); - building_images["plant war lily"] = KOLImageMake("images/otherimages/friarplants/plant11.gif", Vec2iMake(49,100), RectMake(5, 5, 45, 98)); - - building_images["plant canned spinach"] = KOLImageMake("images/otherimages/friarplants/plant13.gif", Vec2iMake(48,100), RectMake(3, 24, 46, 94)); - building_images["plant blustery puffball"] = KOLImageMake("images/otherimages/friarplants/plant21.gif", Vec2iMake(54,100), RectMake(3, 38, 50, 90)); - building_images["plant wizard's wig"] = KOLImageMake("images/otherimages/friarplants/plant23.gif", Vec2iMake(53,100), RectMake(2, 15, 48, 90)); - - building_images["plant up sea daisy"] = KOLImageMake("images/otherimages/friarplants/plant40.gif", Vec2iMake(64,100), RectMake(3, 6, 60, 92)); - building_images["sunflower face"] = KOLImageMake("images/otherimages/friarplants/plant40.gif", Vec2iMake(64,100), RectMake(6, 6, 58, 52)); - - building_images["ringing phone"] = KOLImageMake("images/otherimages/spookyraven/srphonering.gif", Vec2iMake(30, 51), RectMake(0, 16, 30, 46)); - - building_images["basic hot dog"] = KOLImageMake("images/itemimages/jarl_regdog.gif", Vec2iMake(30,30)); - building_images["Island War Arena"] = KOLImageMake("images/otherimages/bigisland/6.gif", Vec2iMake(100,100), RectMake(17, 28, 89, 76)); - building_images["Island War Lighthouse"] = KOLImageMake("images/otherimages/bigisland/17.gif", Vec2iMake(100,100), RectMake(30, 34, 68, 97)); - building_images["Island War Nuns"] = KOLImageMake("images/otherimages/bigisland/19.gif", Vec2iMake(100,100), RectMake(20, 43, 78, 87)); - building_images["Island War Farm"] = KOLImageMake("images/otherimages/bigisland/15.gif", Vec2iMake(100,100), RectMake(8, 50, 93, 88)); - building_images["Island War Orchard"] = KOLImageMake("images/otherimages/bigisland/3.gif", Vec2iMake(100,100), RectMake(20, 36, 99, 87)); - - building_images["Island War Junkyard"] = KOLImageMake("images/otherimages/bigisland/25.gif", Vec2iMake(100,100), RectMake(0, 4, 99, 89)); - building_images["Island War Junkyard"].erase_zones.listAppend(RectMake(0, 2, 20, 6)); - building_images["Island War Junkyard"].erase_zones.listAppend(RectMake(9, 41, 95, 52)); - - - building_images["spookyraven manor"] = KOLImageMake("images/otherimages/town/manor.gif", Vec2iMake(100,100), RectMake(0, 22, 99, 99)); - - building_images["spookyraven manor"].erase_zones.listAppend(RectMake(23, 18, 53, 28)); - - - building_images["spookyraven manor locked"] = KOLImageMake("images/otherimages/town/pantry.gif", Vec2iMake(80,80), RectMake(0, 26, 79, 79)); - - building_images["haunted billiards room"] = KOLImageMake("images/otherimages/manor/sm4.gif", Vec2iMake(100,100), RectMake(12, 10, 93, 63)); - - building_images["haunted library"] = KOLImageMake("images/otherimages/manor/sm7.gif", Vec2iMake(100,100), RectMake(14, 5, 92, 55)); - - building_images["haunted bedroom"] = KOLImageMake("images/otherimages/manor/sm2_1b.gif", Vec2iMake(100,100), RectMake(18, 28, 91, 86)); - building_images["Haunted Ballroom"] = KOLImageMake("images/otherimages/manor/sm2_5.gif", Vec2iMake(100,200), RectMake(19, 11, 74, 76)); - - building_images["Palindome"] = KOLImageMake("images/otherimages/plains/the_palindome.gif", Vec2iMake(96,86), RectMake(0, 17, 96, 83)); - - - building_images["high school"] = KOLImageMake("images/otherimages/town/kolhs.gif", Vec2iMake(100,100), RectMake(0, 26, 99, 92)); - //building_images["Toot Oriole"] = KOLImageMake("images/otherimages/oriole.gif", Vec2iMake(60,100), RectMake(0, 12, 59, 85)); - building_images["Toot Oriole"] = KOLImageMake("images/otherimages/mountains/noobsingtop.gif", Vec2iMake(200,100), RectMake(52, 18, 131, 49)); //I love this GIF - - building_images["bookshelf"] = KOLImageMake("images/otherimages/campground/bookshelf.gif", Vec2iMake(100,100), RectMake(0, 26, 99, 99)); - building_images["pirate quest"] = KOLImageMake("images/otherimages/trophy/party_on_the_big_boat.gif", Vec2iMake(100,100), RectMake(18, 3, 87, 64)); - building_images["ship wheel"] = KOLImageMake("images/adventureimages/shipwheel.gif", Vec2iMake(100,100)); - building_images["meat"] = KOLImageMake("images/itemimages/meat.gif", Vec2iMake(30,30)); - building_images["monk"] = KOLImageMake("images/itemimages/monkhead.gif", Vec2iMake(30,30)); - - - building_images["Pyramid"] = KOLImageMake("images/otherimages/desertbeach/pyramid.gif", Vec2iMake(60,70), RectMake(12, 11, 47, 38)); - building_images["Pyramid"].erase_zones.listAppend(RectMake(14, 19, 19, 22)); - building_images["Pyramid"].erase_zones.listAppend(RectMake(41, 12, 45, 16)); - - - //building_images["hidden city"] = KOLImageMake("images/otherimages/hiddencity//hiddencitybg.gif", Vec2iMake(600,400), RectMake(114, 38, 213, 159)); //building, don't like - //building_images["hidden city"] = KOLImageMake("images/otherimages/hiddencity//hiddencitybg.gif", Vec2iMake(600,400), RectMake(7, 240, 77, 294)); //shrine, too close to hidden temple - building_images["hidden city"] = KOLImageMake("images/otherimages/hiddencity//hiddencitybg.gif", Vec2iMake(600,400), RectMake(426, 13, 504, 61)); //hidden tavern, small, better - building_images["Dispensary"] = KOLImageMake("images/adventureimages/knobwindow.gif", Vec2iMake(100,100)); - - - building_images["Wine Racks"] = KOLImageMake("images/otherimages/manor/cellar4.gif", Vec2iMake(100,100), RectMake(17, 11, 96, 65)); - building_images["Wine Racks"].erase_zones.listAppend(RectMake(17, 11, 33, 12)); - building_images["Wine Racks"].erase_zones.listAppend(RectMake(39, 61, 42, 66)); - building_images["Wine Racks"].erase_zones.listAppend(RectMake(70, 61, 74, 66)); - building_images["Wine Racks"].erase_zones.listAppend(RectMake(94, 45, 97, 54)); - building_images["Wine Racks"].erase_zones.listAppend(RectMake(17, 49, 18, 53)); - - - building_images["black forest"] = KOLImageMake("images/otherimages/woods/bforest.gif", Vec2iMake(100,100), RectMake(0, 19, 99, 99)); - - building_images["possessed wine rack"] = KOLImageMake("images/adventureimages/winerack.gif", Vec2iMake(100,100), RectMake(0, 0, 99, 99)); - building_images["cabinet of Dr. Limpieza"] = KOLImageMake("images/adventureimages/laundrycabinet.gif", Vec2iMake(100,100), RectMake(0, 0, 99, 99)); - building_images["monstrous boiler"] = KOLImageMake("images/adventureimages/boiler.gif", Vec2iMake(100,100), RectMake(0, 0, 99, 99)); - - - - building_images["Dad Sea Monkee"] = KOLImageMake("images/adventureimages/dad_machine.gif", Vec2iMake(400,300), RectMake(150,212,245,260)); - building_images["Shub-Jigguwatt"] = KOLImageMake("images/adventureimages/shub-jigguwatt.gif", Vec2iMake(300,300), RectMake(19, 17, 267, 288)); - building_images["Yog-Urt"] = KOLImageMake("images/adventureimages/yog-urt.gif", Vec2iMake(300,300), RectMake(36, 88, 248, 299)); - building_images["Sea"] = KOLImageMake("images/adventureimages/wizardfish.gif", Vec2iMake(100,100), RectMake(18, 23, 61, 72)); - building_images["Sea"].erase_zones.listAppend(RectMake(18, 23, 27, 28)); - building_images["Sea"].erase_zones.listAppend(RectMake(48, 23, 62, 35)); - building_images["Sea Monkey Castle"] = KOLImageMake("images/otherimages/ocean/monkeycastle.gif", Vec2iMake(100,100), RectMake(29, 36, 66, 82)); - building_images["Sea Monkey Castle"].erase_zones.listAppend(RectMake(29, 36, 39, 39)); - building_images["Sea Monkey Castle"].erase_zones.listAppend(RectMake(60, 36, 66, 42)); - building_images["Mom Monkey Castle Window"] = KOLImageMake("images/adventureimages/momwindow.gif", Vec2iMake(100,100), RectMake(15, 16, 81, 78)); - building_images["Mom Monkey Castle Window"].erase_zones.listAppend(RectMake(71, 16, 81, 21)); - building_images["Mom Monkey Castle Window"].erase_zones.listAppend(RectMake(81, 16, 81, 43)); - building_images["Mom Monkey Castle Window"].erase_zones.listAppend(RectMake(15, 16, 25, 24)); - building_images["Mom Monkey Castle Window"].erase_zones.listAppend(RectMake(15, 16, 21, 28)); - building_images["Skate Park"] = KOLImageMake("images/otherimages/ocean/rumble_a.gif", Vec2iMake(100,100), RectMake(20, 37, 79, 94)); - building_images["Skate Park"].erase_zones.listAppend(RectMake(20, 37, 40, 71)); - building_images["Skate Park"].erase_zones.listAppend(RectMake(20, 37, 45, 53)); - building_images["Skate Park"].erase_zones.listAppend(RectMake(57, 44, 79, 52)); - building_images["Skate Park"].erase_zones.listAppend(RectMake(64, 37, 79, 69)); - building_images["Skate Park"].erase_zones.listAppend(RectMake(20, 77, 22, 94)); - building_images["Skate Park"].erase_zones.listAppend(RectMake(20, 85, 27, 94)); - building_images["Skate Park"].erase_zones.listAppend(RectMake(57, 93, 79, 94)); - building_images["Spooky little girl"] = KOLImageMake("images/adventureimages/axelgirl.gif", Vec2iMake(100,100), RectMake(37, 25, 63, 74)); - - //hermit.gif and oldman.gif are almost identical. twins? - - building_images["astral spirit"] = KOLImageMake("images/otherimages/spirit.gif", Vec2iMake(60,100)); - building_images["Disco Bandit"] = KOLImageMake("images/otherimages/discobandit_f.gif", Vec2iMake(60,100), RectMake(0,6,59,87)); - building_images["Seal Clubber"] = KOLImageMake("images/otherimages/sealclubber_f.gif", Vec2iMake(60,100), RectMake(0,9,59,92)); - building_images["Turtle Tamer"] = KOLImageMake("images/otherimages/turtletamer_f.gif", Vec2iMake(60,100), RectMake(0,5,59,93)); - building_images["Pastamancer"] = KOLImageMake("images/otherimages/pastamancer_f.gif", Vec2iMake(60,100), RectMake(0,0,59,91)); - building_images["Sauceror"] = KOLImageMake("images/otherimages/sauceror_f.gif", Vec2iMake(60,100), RectMake(0,5,59,90)); - building_images["Accordion Thief"] = KOLImageMake("images/otherimages/accordionthief_f.gif", Vec2iMake(60,100), RectMake(0,2,59,99)); - building_images["Avatar of Sneaky Pete"] = KOLImageMake("images/otherimages/peteavatar_f.gif", Vec2iMake(60,100), RectMake(1,7,59,96)); - building_images["Avatar of Jarlsberg"] = KOLImageMake("images/otherimages/jarlsberg_avatar_f.gif", Vec2iMake(60,100), RectMake(0,6,59,96)); - building_images["Avatar of Boris"] = KOLImageMake("images/otherimages/boris_avatar_f.gif", Vec2iMake(60,100), RectMake(0,4,59,93)); - building_images["Zombie Master"] = KOLImageMake("images/otherimages/zombavatar_f.gif", Vec2iMake(60,100), RectMake(10,3,55,99)); - building_images["WereProfessor"] = KOLImageMake("images/otherimages/wereprofavatar_f.gif", Vec2iMake(60,100), RectMake(9,7,50,98)); - building_images["Hourglass"] = KOLImageMake("images/itemimages/hourglass.gif", Vec2iMake(30,30)); - - building_images["Nemesis Disco Bandit"] = KOLImageMake("images/adventureimages/newwave.gif", Vec2iMake(100,100)); - building_images["Nemesis Seal Clubber"] = KOLImageMake("images/adventureimages/1_1.gif", Vec2iMake(100,100)); - building_images["Nemesis Turtle Tamer"] = KOLImageMake("images/adventureimages/2_1.gif", Vec2iMake(100,100)); - building_images["Nemesis Pastamancer"] = KOLImageMake("images/adventureimages/3_1.gif", Vec2iMake(100,100)); - building_images["Nemesis Sauceror"] = KOLImageMake("images/adventureimages/4_1.gif", Vec2iMake(100,100)); - building_images["Nemesis Accordion Thief"] = KOLImageMake("images/adventureimages/6_1.gif", Vec2iMake(100,100)); - building_images["Nemesis Actually Ed the Undying"] = KOLImageMake("images/itemimages/blackcheck.gif", Vec2iMake(30,30)); //being old, his true enemy is his ever-decreasing pension - - building_images["sword guy"] = KOLImageMake("images/otherimages/leftswordguy.gif", Vec2iMake(80,100)); - building_images["Jick"] = KOLImageMake("images/otherimages/customavatars/1.gif", Vec2iMake(60,100)); - building_images["Superhuman Cocktailcrafting"] = KOLImageMake("images/itemimages/fruitym.gif", Vec2iMake(30,30)); - - // Big thanks to Beldur for looking up the right dimensions. A true king of kings. - building_images["Vanya's Castle"] = KOLImageMake("images/otherimages/8bitrealm.gif", Vec2iMake(400,400), RectMake(285,115,400,207)); - building_images["Megalo-City"] = KOLImageMake("images/otherimages/8bitrealm.gif", Vec2iMake(400,400), RectMake(227,0,310,99)); - building_images["The Fungus Plains"] = KOLImageMake("images/otherimages/8bitrealm.gif", Vec2iMake(400,400), RectMake(290,250,386,315)); - building_images["Hero's Field"] = KOLImageMake("images/otherimages/8bitrealm.gif", Vec2iMake(400,400), RectMake(64,17,178,117)); - - building_images["inexplicable door"] = KOLImageMake("images/otherimages/woods/8bitdoor.gif", Vec2iMake(100,100), RectMake(15, 43, 85, 99)); - building_images["Dungeons of Doom"] = KOLImageMake("images/otherimages/town/ddoom.gif", Vec2iMake(100,100), RectMake(31, 33, 68, 99)); - - building_images["chinatown"] = KOLImageMake("images/otherimages/jung/jung_chinaback.gif", Vec2iMake(450,500), RectMake(188, 202, 229, 270)); - building_images["chinatown"].erase_zones.listAppend(RectMake(227, 247, 231, 256)); - - - building_images["barrel god"] = KOLImageMake("images/otherimages/bgshrine.gif", Vec2iMake(100,100), RectMake(29, 39, 69, 81)); - - building_images["__skill Easy Riding"] = KOLImageMake("images/itemimages/motorbike.gif", Vec2iMake(30,30)); - building_images["__skill jump shark"] = KOLImageMake("images/itemimages/sharkfin.gif", Vec2iMake(30,30)); - building_images["__skill Natural Dancer"] = KOLImageMake("images/itemimages/dance3.gif", Vec2iMake(30,30)); - building_images["__skill Check Mirror"] = KOLImageMake("images/itemimages/bikemirror.gif", Vec2iMake(30,30)); - building_images["__skill Ball Lightning"] = KOLImageMake("images/itemimages/balllightning.gif", Vec2iMake(30,30)); - building_images["__skill rain man"] = KOLImageMake("images/itemimages/rainman.gif", Vec2iMake(30,30)); - building_images["__skill Wisdom of Thoth"] = KOLImageMake("images/itemimages/thoth.gif", Vec2iMake(30,30)); - - building_images["lair registration desk"] = KOLImageMake("images/otherimages/nstower/nstower_regdesk.gif", Vec2iMake(100,61), RectMake(30, 3, 68, 41)); - - - building_images["mini-adventurer blank female"] = KOLImageMake("images/itemimages/miniadv0f.gif", Vec2iMake(30,30)); - building_images["mini-adventurer seal clubber female"] = KOLImageMake("images/itemimages/miniadv1f.gif", Vec2iMake(30,30)); - building_images["mini-adventurer turtle tamer female"] = KOLImageMake("images/itemimages/miniadv2f.gif", Vec2iMake(30,30)); - building_images["mini-adventurer pastamancer female"] = KOLImageMake("images/itemimages/miniadv3f.gif", Vec2iMake(30,30)); - building_images["mini-adventurer sauceror female"] = KOLImageMake("images/itemimages/miniadv4f.gif", Vec2iMake(30,30)); - building_images["mini-adventurer disco bandit female"] = KOLImageMake("images/itemimages/miniadv5f.gif", Vec2iMake(30,30)); - building_images["mini-adventurer accordion thief female"] = KOLImageMake("images/itemimages/miniadv6f.gif", Vec2iMake(30,30)); - - building_images["Lady Spookyraven"] = KOLImageMake("images/otherimages/spookyraven/sr_ladys.gif", Vec2iMake(65,65), RectMake(0, 0, 64, 37)); - building_images["Yeti"] = KOLImageMake("images/adventureimages/yeti.gif", Vec2iMake(100,100), RectMake(12, 0, 80, 98)); - building_images["Lights Out"] = KOLImageMake("images/adventureimages/lightning.gif", Vec2iMake(100,100), RectMake(0, 10, 99, 96)); - building_images["stench airport kiosk"] = KOLImageMake("images/otherimages/dinseylandfill_bg.gif", Vec2iMake(500,500), RectMake(163, 438, 225, 494)); - - foreach key in building_images - { - __kol_images[key.to_lower_case()] = building_images[key]; - } - - } - initialiseConstantKOLImages(); -} - -boolean __kol_images_has_inited = false; -//Does not need to be called directly. -void KOLImagesInit() -{ - if (__kol_images_has_inited) - return; - - PageAddCSSClass("div", "r_image_container", "overflow:hidden;position:relative;top:0px;left:0px;"); - __kol_images_has_inited = true; - KOLimage [string] building_images; - - string class_name = my_class().to_string().to_lower_case(); - string class_nemesis_name = "nemesis " + class_name; - - if (__kol_images contains class_name) - building_images["player character"] = __kol_images[class_name]; - else - building_images["player character"] = __kol_images["disco bandit"]; - - if (__kol_images contains class_nemesis_name) - building_images["nemesis"] = __kol_images[class_nemesis_name]; - else - building_images["nemesis"] = __kol_images["jick"]; - - - - foreach key in building_images - { - __kol_images[key.to_lower_case()] = building_images[key]; - } -} - - - -KOLImage KOLImageLookup(string lookup_name) -{ - KOLImagesInit(); - if (!(__kol_images contains lookup_name)) - { - //Automatically look up items, familiars, and effects by name: - item it = lookup_name.to_item(); - familiar f = lookup_name.to_familiar(); - effect e = lookup_name.to_effect(); - monster m = $monster[none]; - skill s = $skill[none]; - string secondary_lookup_name = lookup_name; - if (lookup_name.stringHasPrefix("__item ")) - { - secondary_lookup_name = lookup_name.substring(7); - f = $familiar[none]; - e = $effect[none]; - it = secondary_lookup_name.to_item(); - } - else if (lookup_name.stringHasPrefix("__familiar ")) - { - secondary_lookup_name = lookup_name.substring(11); - it = $item[none]; - e = $effect[none]; - f = secondary_lookup_name.to_familiar(); - } - else if (lookup_name.stringHasPrefix("__effect ")) - { - secondary_lookup_name = lookup_name.substring(9); - f = $familiar[none]; - it = $item[none]; - e = secondary_lookup_name.to_effect(); - } - else if (lookup_name.stringHasPrefix("__monster ")) - { - secondary_lookup_name = lookup_name.substring(10); - f = $familiar[none]; - it = $item[none]; - e = $effect[none]; - m = secondary_lookup_name.to_monster(); - } - else if (lookup_name.stringHasPrefix("__skill ")) - { - secondary_lookup_name = lookup_name.substring(8); - f = $familiar[none]; - it = $item[none]; - e = $effect[none]; - s = secondary_lookup_name.to_skill(); - } - //Disabled for now - skill images are a new feature. - /*if (lookup_name.stringHasPrefix("__skill ")) - { - secondary_lookup_name = lookup_name.substring(8); - skill s = secondary_lookup_name.to_skill(); - - __kol_images[lookup_name] = KOLImageMake("images/itemimages/" + s.image, Vec2iMake(30,30)); - return __kol_images[lookup_name]; - }*/ - secondary_lookup_name = secondary_lookup_name.to_lower_case(); - if (it != $item[none] && it.smallimage != "" && it.to_string().to_lower_case() == secondary_lookup_name) - { - __kol_images[lookup_name] = KOLImageMake("images/itemimages/" + it.smallimage, Vec2iMake(30,30)); - } - else if (f != $familiar[none] && f.image != "" && f.to_string().to_lower_case() == secondary_lookup_name) - { - __kol_images[lookup_name] = KOLImageMake("images/itemimages/" + f.image, Vec2iMake(30,30)); - } - else if (e != $effect[none] && e.image != "" && e.to_string().to_lower_case() == secondary_lookup_name) - { - __kol_images[lookup_name] = KOLImageMake("images/itemimages/" + e.image, Vec2iMake(30,30)); - } - else if (m != $monster[none] && m.image != "" && m.to_string().to_lower_case() == secondary_lookup_name) - { - __kol_images[lookup_name] = KOLImageMake("images/adventureimages/" + m.image, Vec2iMake(100, 100)); - } - else if (s != $skill[none] && s.image != "" && s.to_string().to_lower_case() == secondary_lookup_name) - { - __kol_images[lookup_name] = KOLImageMake("images/itemimages/" + s.image, Vec2iMake(30,30)); - } - else - { - if (__setting_debug_mode) - print("Unknown image \"" + lookup_name + "\""); - return KOLImageMake(); - } - } - return __kol_images[lookup_name]; -} - -Vec2i __kol_image_generate_image_html_return_final_size; -buffer KOLImageGenerateImageHTML(string lookup_name, boolean should_centre, Vec2i max_image_dimensions, string container_additional_class) -{ - KOLImagesInit(); - lookup_name = to_lower_case(lookup_name); - - boolean half_sized_output = false; - boolean item_sized_output = false; - lookup_name = lookup_name.to_lower_case(); - if (lookup_name.stringHasPrefix("__half ")) - { - lookup_name = lookup_name.substring(7); - half_sized_output = true; - } - if (lookup_name.stringHasPrefix("__itemsize ")) - { - lookup_name = lookup_name.substring(11); - item_sized_output = true; - } - - __kol_image_generate_image_html_return_final_size = Vec2iZero(); - - KOLImage kol_image = KOLImageLookup(lookup_name); - buffer result; - if (kol_image.url == "") - return "".to_buffer(); - - Vec2i image_size = Vec2iCopy(kol_image.base_image_size); - Rect image_crop = RectCopy(kol_image.crop); - - - - boolean have_size = true; - boolean have_crop = true; - if (image_size.x == 0 || image_size.y == 0) - have_size = false; - if (image_crop.max_coordinate.x == 0 || image_crop.max_coordinate.y == 0) - have_crop = false; - - - float scale_ratio = 1.0; - if (have_size || have_crop) - { - Vec2i effective_image_size = image_size; - - if (half_sized_output) - { - effective_image_size.x = round(effective_image_size.x.to_float() * 0.5); - effective_image_size.y = round(effective_image_size.y.to_float() * 0.5); - } - if (item_sized_output) - { - //FIXME this will result in incorrect proportions for nonsquare images - //also crop? what crop? - effective_image_size.x = MIN(effective_image_size.x, 30.0); - effective_image_size.y = MIN(effective_image_size.y, 30.0); - } - if (have_crop) - effective_image_size = Vec2iMake(image_crop.max_coordinate.x - image_crop.min_coordinate.x + 1, image_crop.max_coordinate.y - image_crop.min_coordinate.y + 1); - - if (half_sized_output && have_crop) - { - image_crop.min_coordinate.x = round(image_crop.min_coordinate.x.to_float() * 0.5); - image_crop.min_coordinate.y = round(image_crop.min_coordinate.y.to_float() * 0.5); - image_crop.max_coordinate.x = round(image_crop.max_coordinate.x.to_float() * 0.5); - image_crop.max_coordinate.y = round(image_crop.max_coordinate.y.to_float() * 0.5); - } - - if (effective_image_size.x > max_image_dimensions.x || effective_image_size.y > max_image_dimensions.y) - { - //Scale down, to match limitations: - float image_ratio = 1.0; - if (effective_image_size.x != 0.0 && effective_image_size.y != 0.0) - { - image_ratio = effective_image_size.y.to_float() / effective_image_size.x.to_float(); - //Try width-major: - Vec2i new_image_size = Vec2iMake(max_image_dimensions.x.to_float(), max_image_dimensions.x.to_float() * image_ratio); - if (new_image_size.x > max_image_dimensions.x || new_image_size.y > max_image_dimensions.y) //too big, try vertical-major: - { - new_image_size = Vec2iMake(max_image_dimensions.y.to_float() / image_ratio, max_image_dimensions.y); - } - //Find ratio: - if (new_image_size.x != 0.0) - { - scale_ratio = new_image_size.x.to_float() / effective_image_size.x.to_float(); - } - } - } - } - if (scale_ratio > 1.0) scale_ratio = 1.0; - if (scale_ratio < 1.0) - { - image_size.x = round(image_size.x.to_float() * scale_ratio); - image_size.y = round(image_size.y.to_float() * scale_ratio); - image_crop.min_coordinate.x = ceil(image_crop.min_coordinate.x.to_float() * scale_ratio); - image_crop.min_coordinate.y = ceil(image_crop.min_coordinate.y.to_float() * scale_ratio); - image_crop.max_coordinate.x = floor(image_crop.max_coordinate.x.to_float() * scale_ratio); - image_crop.max_coordinate.y = floor(image_crop.max_coordinate.y.to_float() * scale_ratio); - } - - boolean outputting_div = false; - boolean outputting_erase_zones = false; - Vec2i div_dimensions; - - if (container_additional_class != "") - outputting_div = true; - if (have_size) - { - div_dimensions = image_size; - if (have_crop) - { - outputting_div = true; - div_dimensions = Vec2iMake(image_crop.max_coordinate.x - image_crop.min_coordinate.x + 1, - image_crop.max_coordinate.y - image_crop.min_coordinate.y + 1); - } - else if (image_size.x > 100) - { - //Automatically crop to 100 pixels wide: - outputting_div = true; - div_dimensions = image_size; - div_dimensions.x = min(100, div_dimensions.x); - } - if (kol_image.erase_zones.count() > 0) - { - outputting_div = true; - outputting_erase_zones = true; - } - } - - if (outputting_div) - { - string style = ""; - - if (have_size) - style = "width:" + div_dimensions.x + "px; height:" + div_dimensions.y + "px;"; - if (__setting_show_alignment_guides) - style += "background:purple;"; - - string [int] classes; - classes.listAppend("r_image_container"); - - if (should_centre) - classes.listAppend("r_centre"); - if (container_additional_class != "") - classes.listAppend(container_additional_class); - result.append(HTMLGenerateTagPrefix("div", mapMake("class", classes.listJoinComponents(" "), "style", style))); - } - - string [string] img_tag_attributes; - img_tag_attributes["src"] = kol_image.url; - if (have_size) - { - img_tag_attributes["width"] = image_size.x; - img_tag_attributes["height"] = image_size.y; - - __kol_image_generate_image_html_return_final_size = image_size; - - } - - //Needs to be optimized to use buffers first. - /*string unadorned_name = lookup_name; - int breakout = 50; - while (unadorned_name != "" && unadorned_name.stringHasPrefix("__") && breakout > 0) - { - int space_index = unadorned_name.index_of(" ") + 1; - if (space_index < 0 || space_index > unadorned_name.length()) - space_index = unadorned_name.length(); - unadorned_name = unadorned_name.substring(space_index); - breakout -= 1; - }*/ - - img_tag_attributes["alt"] = lookup_name.HTMLEscapeString(); - //img_tag_attributes["title"] = unadorned_name.HTMLEscapeString(); - - if (have_crop && outputting_div) - { - //cordinates are upper-left - //format is clip:rect(top-edge,right-edge,bottom-edge,left-edge); - - int top_edge = image_crop.min_coordinate.y; - int bottom_edge = image_crop.max_coordinate.y; - int left_edge = image_crop.min_coordinate.x; - int right_edge = image_crop.max_coordinate.x; - - int margin_top = -(image_crop.min_coordinate.y); - int margin_bottom = -(image_size.y - image_crop.max_coordinate.y); - int margin_left = -(image_crop.min_coordinate.x); - int margin_right = -(image_size.x - image_crop.max_coordinate.x); - img_tag_attributes["style"] = "margin: " + margin_top + "px " + margin_right + "px " + margin_bottom + "px " + margin_left + "px;"; - - - - __kol_image_generate_image_html_return_final_size = Vec2iMake(right_edge - left_edge, bottom_edge - top_edge); - } - - if (__setting_show_alignment_guides) - img_tag_attributes["style"] += "opacity: 0.5;"; - - result.append(HTMLGenerateTagPrefix("img", img_tag_attributes)); - - if (outputting_erase_zones) - { - foreach i in kol_image.erase_zones - { - Rect zone = RectCopy(kol_image.erase_zones[i]); - Vec2i dimensions = Vec2iMake(zone.max_coordinate.x - zone.min_coordinate.x + 1, zone.max_coordinate.y - zone.min_coordinate.y + 1); - //print_html("zone = " + zone.to_json()); - if (scale_ratio < 1.0) - { - dimensions.x = round(dimensions.x.to_float() * scale_ratio); - dimensions.y = round(dimensions.y.to_float() * scale_ratio); - zone.min_coordinate.x = round(zone.min_coordinate.x.to_float() * scale_ratio); - zone.min_coordinate.y = round(zone.min_coordinate.y.to_float() * scale_ratio); - zone.max_coordinate.x = round(zone.max_coordinate.x.to_float() * scale_ratio); - zone.max_coordinate.y = round(zone.max_coordinate.y.to_float() * scale_ratio); - } - - int top = 0; - int left = 0; - - top = -image_crop.min_coordinate.y; - left = -image_crop.min_coordinate.x; - - top += zone.min_coordinate.y; - left += zone.min_coordinate.x; - //Output a white div over this area: - buffer style; - style.append("width:"); - style.append(dimensions.x); - style.append("px;height:"); - style.append(dimensions.y); - style.append("px;"); - if (__setting_show_alignment_guides) - style.append("background:pink;"); - else - style.append("background:#FFFFFF;"); - - style.append("z-index:2;position:absolute;top:"); - style.append(top); - style.append("px;left:"); - style.append(left); - style.append("px;"); - - result.append(HTMLGenerateDivOfStyle("", style)); - } - } - - if (outputting_div) - result.append(""); - return result; -} - -buffer KOLImageGenerateImageHTML(string lookup_name, boolean should_centre, Vec2i max_image_dimensions) -{ - return KOLImageGenerateImageHTML(lookup_name, should_centre, max_image_dimensions, ""); -} - -buffer KOLImageGenerateImageHTML(string lookup_name, boolean should_centre) -{ - return KOLImageGenerateImageHTML(lookup_name, should_centre, Vec2iMake(65535, 65535)); -} - -static -{ - //Rect [string] __minimum_bounding_box_of_image_url; - int [string] __minimum_y_of_image_url; - ServerImageStats [string] __server_image_stats; - - void initialiseMinimumBoundingBoxOfImageURL() - { - //Rect rm(int min_x, int min_y, int max_x, int max_y) { return RectMake(min_x, min_y, max_x, max_y); } - //Vec2i vm(int x, int y) { return Vec2iMake(x, y); } - //Rect test = rm(0,0,0,0); - ServerImageStats im(int width, int height, int min_y, int max_y) { return ServerImageStatsMake(width, height, min_y, max_y); } - ServerImageStats im(int min_y, int max_y) { return ServerImageStatsMake(100, 100, min_y, max_y); } - - ServerImageStats [string] ism; - int [string] ysm; - -ism["borgelf1.gif"] = im(11, 74);ism["borgelf4.gif"] = im(19, 82);ism["borgelf2.gif"] = im(25, 87);ism["borgelf3.gif"] = im(14, 78);ism["handymanjay.gif"] = im(5, 92);ism["1335.gif"] = im(7, 93);ism["miner.gif"] = im(1, 95);ism["foreman.gif"] = im(2, 94);ism["gremlinamc.gif"] = im(12, 78);ism["abcrusher.gif"] = im(12, 89);ism["adv_smart1.gif"] = im(0, 97);ism["lower_b.gif"] = im(16, 74);ism["electriceel.gif"] = im(1, 98);ism["1boy2cups.gif"] = im(2, 91);ism["advecho.gif"] = im(0, 99);ism["whitebat.gif"] = im(33, 70);ism["mar_alert.gif"] = im(0, 99);ism["alielf.gif"] = im(4, 95);ism["spelunkalien.gif"] = im(17, 81);ism["muthamster.gif"] = im(5, 95);ism["spelunkalienq.gif"] = im(150, 150, 17, 141);ism["spelunkufo.gif"] = im(21, 78);ism["steve.gif"] = im(0, 98);ism["catfish.gif"] = im(41, 91);ism["giant_alphabet.gif"] = im(1, 97);ism["elf_amateur.gif"] = im(10, 83);ism["ninja.gif"] = im(13, 85);ism["pirate2.gif"] = im(6, 93);ism["crimbominer3.gif"] = im(2, 97);ism["amokputty.gif"] = im(5, 84);ism["srpainting2.gif"] = im(20, 82);ism["regret3.gif"] = im(27, 79);ism["oldguardstatue.gif"] = im(0, 97);ism["pebbleman.gif"] = im(2, 89);ism["mariner.gif"] = im(5, 93);ism["protspirit.gif"] = im(7, 86);ism["guardstatue.gif"] = im(0, 98);ism["bb_horror.gif"] = im(125, 100, 5, 89);ism["anemone.gif"] = im(0, 97);ism["bb_doctor.gif"] = im(7, 83);ism["angel.gif"] = im(6, 87);ism["angerman.gif"] = im(200, 250, 15, 242);ism["anglerbush.gif"] = im(0, 97);ism["mh_bassist.gif"] = im(2, 97);ism["angbugbear.gif"] = im(6, 91);ism["bb_caveman.gif"] = im(4, 92);ism["mush_angry.gif"] = im(8, 89);ism["pinata.gif"] = im(0, 97);ism["madpoet.gif"] = im(7, 93);ism["raccoon.gif"] = im(6, 93);ism["hunter7.gif"] = im(0, 98);ism["stenchtourist.gif"] = im(0, 93);ism["nightstand2.gif"] = im(13, 91);ism["darkstand.gif"] = im(1, 98);ism["nightstand.gif"] = im(2, 96);ism["nightstand4.gif"] = im(1, 99);ism["fear2.gif"] = im(1, 95);ism["nightstand3.gif"] = im(7, 95);ism["spittoon.gif"] = im(3, 99);ism["smiley.gif"] = im(30, 67);ism["annoyfairy.gif"] = im(15, 76);ism["spiderserver.gif"] = im(7, 94);ism["lizardman.gif"] = im(4, 94);ism["aquabat.gif"] = im(150, 100, 15, 79);ism["aquaconda.gif"] = im(5, 91);ism["aquagoblin.gif"] = im(0, 99);ism["2headseal.gif"] = im(9, 81);ism["mush_armor.gif"] = im(7, 91);ism["adv_spooky4.gif"] = im(4, 96);ism["adv_stench3.gif"] = im(5, 95);ism["astronomer.gif"] = im(6, 93);ism["aquadargon.gif"] = im(200, 200, 6, 190);ism["elf_auteur.gif"] = im(15, 78);ism["disco_awkward.gif"] = im(4, 95);ism["axehandle.gif"] = im(9, 89);ism["axewound.gif"] = im(9, 87);ism["saucezombie.gif"] = im(0, 97);ism["stone_serpent.gif"] = im(0, 98);ism["stone_sheep.gif"] = im(21, 81);ism["baconsnake.gif"] = im(4, 96);ism["badascii.gif"] = im(35, 61);ism["pa_potatoes.gif"] = im(8, 95);ism["baglady.gif"] = im(0, 99);ism["warhipmo.gif"] = im(44, 98);ism["baiowulf.gif"] = im(8, 94);ism["spelunkbanana.gif"] = im(150, 150, 0, 149);ism["bangyomama.gif"] = im(2, 89);ism["banjowizard.gif"] = im(0, 99);ism["banshee.gif"] = im(6, 98);ism["bar.gif"] = im(13, 88);ism["ratsworth.gif"] = im(0, 96);ism["basaltamander.gif"] = im(0, 99);ism["ballbat.gif"] = im(7, 60);ism["reindeer.gif"] = im(0, 99);ism["basicgolem.gif"] = im(6, 89);ism["spelunkbat.gif"] = im(15, 77);ism["bb_bat.gif"] = im(27, 81);ism["adv_spooky3.gif"] = im(1, 93);ism["batrat.gif"] = im(25, 75);ism["snakeboss5.gif"] = im(150, 150, 13, 141);ism["bb_mech.gif"] = im(1, 98);ism["aboo_wars.gif"] = im(3, 98);ism["gremlinbat.gif"] = im(11, 83);ism["bazookafish.gif"] = im(25, 68);ism["beanbat.gif"] = im(28, 63);ism["topi2.gif"] = im(9, 93);ism["earbeast.gif"] = im(14, 80);ism["eyebeast.gif"] = im(17, 99);ism["beaver.gif"] = im(13, 77);ism["spelunkbee.gif"] = im(3, 86);ism["beeswarm.gif"] = im(3, 97);ism["beethoven.gif"] = im(5, 94);ism["beebeegunner.gif"] = im(16, 70);ism["beebeeking.gif"] = im(16, 79);ism["beebeequeue.gif"] = im(4, 97);ism["beefybat.gif"] = im(18, 58);ism["beelephant.gif"] = im(0, 89);ism["batter.gif"] = im(0, 99);ism["warfratbg.gif"] = im(0, 95);ism["straw_stench.gif"] = im(15, 93);ism["bellhop.gif"] = im(17, 89);ism["carpet.gif"] = im(33, 75);ism["novelist.gif"] = im(2, 92);ism["wraith2.gif"] = im(15, 89);ism["biclops.gif"] = im(4, 92);ism["spider1.gif"] = im(15, 78);ism["bigmeat.gif"] = im(0, 94);ism["whelps2.gif"] = im(1, 98);ism["twins_bigwheel.gif"] = im(200, 100, 5, 95);ism["aquaniewski.gif"] = im(0, 97);ism["bigface.gif"] = im(14, 92);ism["vib2.gif"] = im(3, 97);ism["blimp.gif"] = im(8, 94);ism["blackadder.gif"] = im(12, 79);ism["blackcat.gif"] = im(4, 90);ism["cray_beast.gif"] = im(200, 200, 41, 171);ism["cray_bug.gif"] = im(200, 200, 43, 152);ism["cray_const.gif"] = im(200, 200, 15, 193);ism["cray_elf.gif"] = im(200, 200, 22, 181);ism["cray_demon.gif"] = im(200, 200, 32, 178);ism["cray_elemental.gif"] = im(200, 200, 8, 191);ism["cray_fish.gif"] = im(200, 200, 30, 145);ism["cray_plant.gif"] = im(200, 200, 9, 184);ism["cray_orc.gif"] = im(200, 200, 32, 169);ism["cray_goblin.gif"] = im(200, 200, 32, 167);ism["cray_construct.gif"] = im(200, 200, 23, 183);ism["cray_hippy.gif"] = im(200, 200, 19, 163);ism["cray_hobo.gif"] = im(200, 200, 1, 198);ism["cray_dude.gif"] = im(200, 200, 7, 182);ism["cray_humanoid.gif"] = im(200, 200, 12, 188);ism["cray_merkin.gif"] = im(200, 200, 17, 172);ism["cray_penguin.gif"] = im(200, 200, 31, 185);ism["cray_pirate.gif"] = im(200, 200, 18, 179);ism["cray_horror.gif"] = im(200, 200, 1, 197);ism["cray_slime.gif"] = im(200, 200, 61, 166);ism["cray_weird.gif"] = im(200, 200, 27, 186);ism["cray_undead.gif"] = im(200, 200, 22, 162);ism["blackfriar.gif"] = im(5, 97);ism["blknight.gif"] = im(4, 90);ism["witchywoman.gif"] = im(1, 99);ism["bb_ninja.gif"] = im(5, 91);ism["panther.gif"] = im(11, 93);ism["blpudding.gif"] = im(47, 98);ism["blackwidow.gif"] = im(0, 99);ism["pengblackop.gif"] = im(3, 98);ism["blackbush.gif"] = im(15, 98);ism["sawblade.gif"] = im(0, 98);ism["firebat.gif"] = im(1, 97);ism["squid.gif"] = im(3, 95);ism["bluecultist.gif"] = im(0, 99);ism["mh_bluehair.gif"] = im(1, 98);ism["blur.gif"] = im(4, 97);ism["boaraffe.gif"] = im(0, 99);ism["naskar2.gif"] = im(5, 95);ism["bogleech.gif"] = im(10, 91);ism["bogskeleton.gif"] = im(1, 95);ism["bogart.gif"] = im(11, 91);ism["elf_boltcutters.gif"] = im(5, 78);ism["foss_wyrm.gif"] = im(200, 200, 0, 196);ism["bookbat.gif"] = im(22, 65);ism["boothslime.gif"] = im(2, 97);ism["bootycrab.gif"] = im(20, 85);ism["boozegiant.gif"] = im(5, 92);ism["borgabeeping.gif"] = im(0, 96);ism["bossbat.gif"] = im(26, 73);ism["deadbossbat.gif"] = im(7, 94);ism["crimonster3.gif"] = im(4, 96);ism["cricket.gif"] = im(5, 97);ism["box.gif"] = im(9, 87);ism["pa_muffin.gif"] = im(13, 87);ism["mystwander5.gif"] = im(5, 99);ism["broombrain.gif"] = im(6, 95);ism["bram.gif"] = im(8, 92);ism["breadgolem.gif"] = im(6, 90);ism["breakdancer.gif"] = im(0, 97);ism["brick_sleaze.gif"] = im(24, 96);ism["brick_cold.gif"] = im(1, 95);ism["brick_hot.gif"] = im(0, 99); -ism["brick_spooky.gif"] = im(4, 95);ism["kok_tender.gif"] = im(21, 97);ism["brick_stench.gif"] = im(4, 94);ism["brickoairship.gif"] = im(300, 300, 6, 295);ism["brickobat.gif"] = im(3, 68);ism["brickocathedral.gif"] = im(500, 450, 17, 443);ism["brickoelephant.gif"] = im(150, 150, 34, 132);ism["brickogchicken.gif"] = im(600, 450, 15, 444);ism["brickoctopus.gif"] = im(150, 150, 9, 143);ism["brickoblob.gif"] = im(57, 94);ism["brickooyster.gif"] = im(16, 91);ism["brickopython.gif"] = im(450, 100, 11, 87);ism["brickoturtle.gif"] = im(22, 77);ism["brickovacuum.gif"] = im(200, 200, 17, 182);ism["casebat.gif"] = im(40, 63);ism["bath_bubble.gif"] = im(17, 76);ism["iceguy5.gif"] = im(0, 97);ism["broctopus.gif"] = im(0, 99);ism["bronzechef.gif"] = im(0, 99);ism["babyseal.gif"] = im(6, 84);ism["togafrat.gif"] = im(2, 96);ism["twins_bubble.gif"] = im(13, 94);ism["bb_ghost.gif"] = im(5, 89);ism["bb_captain.gif"] = im(150, 150, 3, 143);ism["bb_drone.gif"] = im(2, 97);ism["bb_mortician.gif"] = im(9, 91);ism["robosurgeon.gif"] = im(14, 88);ism["bb_science.gif"] = im(6, 88);ism["binbox.gif"] = im(4, 91);ism["bugbugbear.gif"] = im(6, 91);ism["bulletbill.gif"] = im(15, 83);ism["bullseal.gif"] = im(9, 95);ism["ratbunch.gif"] = im(1, 92);ism["pa_meat.gif"] = im(5, 96);ism["bunsen.gif"] = im(9, 87);ism["sidekick.gif"] = im(5, 97);ism["adv_hot3.gif"] = im(18, 95);ism["snakeboss4.gif"] = im(150, 150, 19, 133);ism["bishop.gif"] = im(54, 94);ism["bush.gif"] = im(8, 93);ism["bushippy.gif"] = im(8, 94);ism["hedgerow.gif"] = im(25, 79);ism["pa_knife.gif"] = im(1, 87);ism["buzzerker.gif"] = im(11, 84);ism["buzzy.gif"] = im(0, 97);ism["chum1.gif"] = im(7, 91);ism["chumchief.gif"] = im(7, 94);ism["carnivore.gif"] = im(6, 96);ism["animbear.gif"] = im(0, 99);ism["laundrycabinet.gif"] = im(1, 98);ism["cactuary.gif"] = im(0, 97);ism["cakelord.gif"] = im(0, 98);ism["cameltoe.gif"] = im(5, 97);ism["cancan.gif"] = im(4, 97);ism["pecantree.gif"] = im(1, 98);ism["yamgolem.gif"] = im(0, 97);ism["gourd_cangoblin.gif"] = im(9, 88);ism["carbuncletop.gif"] = im(1, 92);ism["cargocrab.gif"] = im(7, 94);ism["dillplant.gif"] = im(2, 99);ism["carniv.gif"] = im(5, 94);ism["pa_eggs.gif"] = im(22, 86);ism["thecastle.gif"] = im(21, 78);ism["catalien.gif"] = im(21, 89);ism["spelunkcaveman.gif"] = im(7, 91);ism["cavedan.gif"] = im(0, 97);ism["cavefrat.gif"] = im(2, 95);ism["cavehippy.gif"] = im(0, 97);ism["cavesorority.gif"] = im(0, 95);ism["cavewomyn.gif"] = im(0, 94);ism["butt.gif"] = im(16, 81);ism["pengcement.gif"] = im(2, 97);ism["centurion.gif"] = im(7, 80);ism["adv_hot2.gif"] = im(2, 96);ism["chimp.gif"] = im(6, 90);ism["chalkdust.gif"] = im(6, 98);ism["hunter10.gif"] = im(1, 97);ism["c10chatty.gif"] = im(0, 96);ism["strix.gif"] = im(4, 93);ism["adv_stench2.gif"] = im(1, 97);ism["adv_fast1.gif"] = im(4, 93);ism["chefboy.gif"] = im(0, 98);ism["chester.gif"] = im(1, 97);ism["robotceo.gif"] = im(5, 92);ism["chocohare.gif"] = im(23, 93);ism["ccprairie.gif"] = im(1, 97);ism["soupgolem.gif"] = im(3, 93);ism["ciggirl.gif"] = im(0, 99);ism["animelf3.gif"] = im(19, 80);ism["cavebars.gif"] = im(0, 98);ism["clancy.gif"] = im(9, 94);ism["bathtub.gif"] = im(50, 97);ism["claygolem.gif"] = im(1, 98);ism["aboo_wiz.gif"] = im(3, 96);ism["cleanroomdemon.gif"] = im(5, 95);ism["cleanpirate.gif"] = im(3, 94);ism["girlpirate.gif"] = im(7, 91);ism["colaoff1.gif"] = im(4, 94);ism["colasol1.gif"] = im(6, 96);ism["rock_hopper.gif"] = im(0, 99);ism["whiskers.gif"] = im(8, 84);ism["clubfish.gif"] = im(1, 90);ism["prim_bact.gif"] = im(0, 98);ism["coaltergeist.gif"] = im(5, 91);ism["kg_oven.gif"] = im(8, 97);ism["spelunkcobra.gif"] = im(14, 77);ism["cocktailshrimp.gif"] = im(0, 99);ism["dvcoldbear1.gif"] = im(3, 97);ism["coldcutter.gif"] = im(2, 94);ism["dvcoldghost1.gif"] = im(0, 96);ism["coldhobo1.gif"] = im(5, 89);ism["wood_cold.gif"] = im(13, 96);ism["dvcoldskel1.gif"] = im(1, 95);ism["dvcoldvamp1.gif"] = im(3, 94);ism["dvcoldwolf1.gif"] = im(1, 98);ism["dvcoldzom1.gif"] = im(5, 98);ism["minegolem.gif"] = im(4, 89);ism["spider2.gif"] = im(20, 83);ism["pianist.gif"] = im(0, 98);ism["lilgoth.gif"] = im(19, 96);ism["2zombies.gif"] = im(6, 92);ism["conhippy.gif"] = im(2, 94);ism["regret1.gif"] = im(2, 90);ism["pa_cutter.gif"] = im(21, 76);ism["crimonster2.gif"] = im(0, 99);ism["coolerwino.gif"] = im(0, 97);ism["coppertender.gif"] = im(6, 91);ism["fatzombie.gif"] = im(9, 93);ism["prim_alga.gif"] = im(0, 98);ism["makeupwraith.gif"] = im(11, 81);ism["bakula.gif"] = im(7, 90);ism["drunkula.gif"] = im(100, 175, 5, 166);ism["drunkula_hm.gif"] = im(300, 175, 2, 159);ism["courtesan.gif"] = im(5, 95);ism["cowskeleton.gif"] = im(1, 97);ism["creep.gif"] = im(13, 91);ism["craggybart.gif"] = im(3, 91);ism["crate.gif"] = im(10, 89);ism["stone_raven.gif"] = im(21, 85);ism["bastard.gif"] = im(3, 94);ism["adv_smooth2.gif"] = im(3, 94);ism["clown.gif"] = im(3, 97);ism["creepydoll.gif"] = im(4, 96);ism["dianoga.gif"] = im(11, 87);ism["twins_ginger.gif"] = im(1, 98);ism["creepygirl.gif"] = im(32, 97);ism["pa_torch.gif"] = im(3, 92);ism["crimbomega.gif"] = im(400, 550, 7, 545);ism["spelunkcroc.gif"] = im(6, 89);ism["croqueteer.gif"] = im(1, 90);ism["dustmote.gif"] = im(20, 86);ism["hippy3.gif"] = im(8, 94);ism["crustpirate.gif"] = im(1, 95);ism["crys_rock.gif"] = im(200, 150, 2, 137);ism["cubistbull.gif"] = im(0, 99);ism["spelunkhawk.gif"] = im(3, 95);ism["curmpirate.gif"] = im(6, 93);ism["cybercop.gif"] = im(2, 97);ism["prim_cyru.gif"] = im(0, 98);ism["dad_machine.gif"] = im(400, 300, 6, 294);ism["daftpunk.gif"] = im(3, 97);ism["biggoat.gif"] = im(2, 98);ism["ooze.gif"] = im(45, 93);ism["dirtyape.gif"] = im(0, 99);ism["mush_dancing.gif"] = im(11, 91);ism["chad.gif"] = im(3, 93);ism["rorshach.gif"] = im(8, 79);ism["bath_showerhead.gif"] = im(2, 97);ism["venomtrout.gif"] = im(47, 99);ism["vice.gif"] = im(20, 85);ism["shiv_dead.gif"] = im(3, 94);ism["deathray.gif"] = im(4, 98);ism["lumberjack.gif"] = im(5, 92);ism["whiteshark.gif"] = im(15, 71);ism["5_4a.gif"] = im(200, 200, 0, 197);ism["demfridge.gif"] = im(1, 99);ism["jigsaw.gif"] = im(12, 83);ism["demoninja.gif"] = im(17, 89);ism["liana.gif"] = im(13, 90);ism["wanderacc1.gif"] = im(1, 97);ism["hunter8.gif"] = im(0, 97);ism["goldfarmer.gif"] = im(9, 91);ism["smoochboss4.gif"] = im(100, 200, 11, 191);ism["spelunkdevil.gif"] = im(0, 99);ism["digitalug.gif"] = im(17, 87);ism["dinnertroll.gif"] = im(13, 87);ism["direpigeon.gif"] = im(0, 98);ism["hippy2.gif"] = im(8, 93);ism["dirtyoldlihc.gif"] = im(6, 99);ism["bandit.gif"] = im(1, 95);ism["dinbox.gif"] = im(16, 91);ism["c10files.gif"] = im(7, 98);ism["divingbelle.gif"] = im(0, 99);ism["js_oh.gif"] = im(5, 91);ism["pede.gif"] = im(20, 81);ism["dogalien.gif"] = im(3, 92);ism["catdog.gif"] = im(17, 85);ism["iceguy2.gif"] = im(8, 97);ism["doncrimbo.gif"] = im(0, 99);ism["donerbagon.gif"] = im(200, 200, 1, 189);ism["dwarf_dopey.gif"] = im(0, 99);ism["doubtman.gif"] = im(200, 200, 2, 193);ism["doughbat.gif"] = im(41, 63);ism["aquard.gif"] = im(0, 99);ism["drawkward.gif"] = im(4, 95);ism["braddarb.gif"] = im(5, 96);ism["droll.gif"] = im(18, 87);ism["dropbase.gif"] = im(12, 80);ism["drownedsailor.gif"] = im(1, 97);ism["drownedbeat.gif"] = im(0, 95);ism["ducknicedrunk.gif"] = im(1, 94);ism["drunkgoat.gif"] = im(2, 98);ism["pyg_drunk.gif"] = im(9, 99);ism["drunkminer.gif"] = im(0, 98);ism["hobo.gif"] = im(5, 91);ism["rat.gif"] = im(33, 67);ism["ratking.gif"] = im(200, 200, 7, 185);ism["kok_drunk.gif"] = im(0, 93);ism["zomhobo.gif"] = im(5, 91);ism["aboo_dipshit.gif"] = im(1, 97);ism["straw_spooky.gif"] = im(39, 91);ism["dwarfgnome.gif"] = im(17, 84);ism["dweebie.gif"] = im(5, 94);ism["colaoff2.gif"] = im(4, 94);ism["colasol2.gif"] = im(6, 96);ism["eve.gif"] = im(0, 93);ism["eagle.gif"] = im(0, 98);ism["ed.gif"] = im(1, 98);ism["ed2.gif"] = im(1, 98);ism["ed3.gif"] = im(1, 98);ism["ed4.gif"] = im(1, 98);ism["ed5.gif"] = im(1, 98);ism["ed6.gif"] = im(22, 98);ism["ed7.gif"] = im(46, 98);ism["edwing.gif"] = im(24, 83);ism["eldiablo.gif"] = im(0, 99);ism["elders.gif"] = im(11, 85);ism["submarine.gif"] = im(8, 86);ism["nightstand5.gif"] = im(22, 82);ism["topi3.gif"] = im(7, 90);ism["elfhobo1.gif"] = im(28, 97);ism["warfratbg2.gif"] = im(0, 95);ism["elp_and_cros.gif"] = im(300, 150, 5, 146);ism["skinyeti.gif"] = im(4, 90);ism["armor.gif"] = im(0, 98);ism["inflatiger.gif"] = im(7, 98);ism["c10confcall.gif"] = im(2, 94);ism["grayblob3.gif"] = im(150, 200, 21, 178);ism["cow.gif"] = im(0, 99);ism["adv_strong3.gif"] = im(9, 91);ism["gremlinglasses.gif"] = im(7, 94);ism["stairmaster.gif"] = im(12, 94);ism["mc_respect3.gif"] = im(4, 94);ism["mc_soy3.gif"] = im(0, 97);ism["mc_tofu3.gif"] = im(1, 98);ism["cultist.gif"] = im(3, 98);ism["mh_evilex.gif"] = im(0, 99);ism["oliveevil.gif"] = im(13, 85);ism["spagcult2.gif"] = im(1, 95);ism["spagcult3.gif"] = im(0, 99);ism["spagcult1.gif"] = im(0, 98);ism["spagcult2k.gif"] = im(1, 95);ism["spagcult4.gif"] = im(0, 99);ism["spagcult1k.gif"] = im(0, 98);ism["trumpetmariachi.gif"] = im(2, 97);ism["vihuelamariachi.gif"] = im(2, 96);ism["crimbominer1.gif"] = im(0, 99);ism["skihippy.gif"] = im(3, 94);ism["fratboard.gif"] = im(3, 91);ism["wcorcs.gif"] = im(0, 97); -ism["witchy2.gif"] = im(0, 99);ism["darkeye.gif"] = im(5, 91);ism["guai.gif"] = im(11, 85);ism["facworker4.gif"] = im(3, 95);ism["facworker3.gif"] = im(1, 97);ism["facworker1.gif"] = im(3, 97);ism["facworker2.gif"] = im(1, 93);ism["badskel1.gif"] = im(20, 84);ism["archfiend.gif"] = im(10, 84);ism["fallsfromsky.gif"] = im(100, 150, 2, 143);ism["fallsfromsky_hm.gif"] = im(200, 300, 7, 285);ism["jewels.gif"] = im(8, 82);ism["kobolds.gif"] = im(0, 97);ism["fandancer.gif"] = im(6, 91);ism["fanslime.gif"] = im(2, 94);ism["bathslug.gif"] = im(1, 98);ism["hunter5.gif"] = im(1, 98);ism["hunter9.gif"] = im(1, 93);ism["fearman.gif"] = im(200, 200, 12, 185);ism["bath_octopus.gif"] = im(0, 98);ism["wacken.gif"] = im(200, 200, 23, 186);ism["manyeyes.gif"] = im(4, 81);ism["felonia.gif"] = im(0, 98);ism["haiku2.gif"] = im(6, 91);ism["bath_pelican.gif"] = im(1, 97);ism["ferrelf.gif"] = im(5, 90);ism["finger.gif"] = im(2, 96);ism["asparagus.gif"] = im(9, 89);ism["mush_flaming.gif"] = im(0, 99);ism["duckskate.gif"] = im(2, 98);ism["filthworm2.gif"] = im(24, 75);ism["filthworm3.gif"] = im(19, 70);ism["hippy1.gif"] = im(8, 89);ism["stinkpirate1.gif"] = im(3, 97);ism["adv_hot1.gif"] = im(1, 97);ism["firetruck.gif"] = im(300, 150, 7, 145);ism["duckfirebreath.gif"] = im(7, 91);ism["fisherfish.gif"] = im(3, 97);ism["stinkpirate3.gif"] = im(1, 93);ism["giant_fitness.gif"] = im(9, 97);ism["bigskeleton5.gif"] = im(250, 100, 0, 99);ism["meatblob.gif"] = im(10, 79);ism["samurai.gif"] = im(0, 99);ism["flametroll.gif"] = im(1, 96);ism["flange.gif"] = im(12, 78);ism["flashypirate.gif"] = im(4, 94);ism["cvfleaman.gif"] = im(5, 90);ism["woodsman.gif"] = im(9, 96);ism["disco_flexible.gif"] = im(3, 97);ism["caveelf3.gif"] = im(25, 85);ism["horstray.gif"] = im(19, 89);ism["seagulls.gif"] = im(3, 91);ism["stabbats.gif"] = im(0, 97);ism["bunny.gif"] = im(49, 94);ism["gourd_fnord.gif"] = im(200, 200, 23, 171);ism["giant_foodie.gif"] = im(4, 97);ism["forspirit.gif"] = im(21, 74);ism["bigskeleton4.gif"] = im(200, 100, 0, 99);ism["mime.gif"] = im(0, 97);ism["artteacher.gif"] = im(4, 95);ism["accboss.gif"] = im(0, 98);ism["warfrata.gif"] = im(1, 96);ism["mush_freaked.gif"] = im(9, 91);ism["frenchturtle.gif"] = im(19, 72);ism["bonefish.gif"] = im(40, 97);ism["frog.gif"] = im(53, 99);ism["frosty.gif"] = im(0, 99);ism["straw_cold.gif"] = im(12, 91);ism["mystwander3.gif"] = im(8, 94);ism["duckfrozen.gif"] = im(2, 96);ism["snakeboss1.gif"] = im(150, 150, 21, 133);ism["fruitgolem.gif"] = im(8, 97);ism["anger3.gif"] = im(0, 99);ism["fudgemonkey2.gif"] = im(0, 99);ism["fudgeoyster.gif"] = im(0, 99);ism["fudgepoodle.gif"] = im(2, 96);ism["fudgevulture.gif"] = im(0, 99);ism["fudgeweasel.gif"] = im(11, 86);ism["bigmirror.gif"] = im(0, 99);ism["fun-gal1.gif"] = im(0, 99);ism["funkparticle.gif"] = im(8, 94);ism["solebrother.gif"] = im(19, 76);ism["stinkpirate2.gif"] = im(3, 96);ism["shiv_fur.gif"] = im(1, 94);ism["giant_furry.gif"] = im(0, 98);ism["gimp.gif"] = im(15, 90);ism["gamblinman.gif"] = im(1, 95);ism["muggers.gif"] = im(2, 98);ism["ganger.gif"] = im(16, 88);ism["garbagetourist.gif"] = im(3, 94);ism["gargantulihc.gif"] = im(1, 93);ism["ghuol_skinny.gif"] = im(16, 90);ism["gelcube.gif"] = im(12, 97);ism["generalseal.gif"] = im(150, 100, 2, 97);ism["duckgeneric.gif"] = im(4, 94);ism["merkinballer2.gif"] = im(1, 99);ism["smoochboss1.gif"] = im(100, 200, 8, 189);ism["phantom.gif"] = im(1, 95);ism["cvghost.gif"] = im(4, 92);ism["spelunkghost.gif"] = im(11, 91);ism["ghostminer.gif"] = im(1, 98);ism["elizabeth.gif"] = im(10, 86);ism["fernghost.gif"] = im(1, 92);ism["worker.gif"] = im(2, 94);ism["adv_spooky1.gif"] = im(8, 91);ism["ghuol_reg.gif"] = im(11, 85);ism["giantbee.gif"] = im(2, 84);ism["pterodactyl.gif"] = im(6, 91);ism["globe.gif"] = im(0, 95);ism["friedegg.gif"] = im(2, 82);ism["centipede.gif"] = im(21, 81);ism["moth.gif"] = im(5, 95);ism["isopod.gif"] = im(35, 95);ism["python.gif"] = im(4, 93);ism["bath_whale.gif"] = im(14, 82);ism["manyspiders.gif"] = im(1, 94);ism["watertentacle.gif"] = im(6, 93);ism["tweezers.gif"] = im(6, 93);ism["headpumpkin.gif"] = im(5, 96);ism["rubberspider.gif"] = im(15, 84);ism["sandworm.gif"] = im(2, 99);ism["giantskel.gif"] = im(0, 99);ism["tarantula.gif"] = im(1, 97);ism["giantsquid.gif"] = im(0, 98);ism["whelps3.gif"] = im(0, 99);ism["tardigrade.gif"] = im(4, 91);ism["zomfish.gif"] = im(2, 86);ism["crimonster5.gif"] = im(0, 92);ism["gingerbreadman.gif"] = im(0, 99);ism["gladiator.gif"] = im(1, 96);ism["juiceglass.gif"] = im(12, 87);ism["wood_hot.gif"] = im(3, 95);ism["ghuol_fat.gif"] = im(13, 87);ism["gnarlgnome.gif"] = im(9, 79);ism["gnasgnome.gif"] = im(6, 77);ism["gnefgnome.gif"] = im(12, 83);ism["dk_builder.gif"] = im(9, 97);ism["dk_cross.gif"] = im(3, 94);ism["dk_swatter.gif"] = im(3, 95);ism["dk_gearhead.gif"] = im(1, 97);ism["dk_piechef.gif"] = im(0, 99);ism["dk_plunger.gif"] = im(3, 93);ism["gnollmage.gif"] = im(3, 95);ism["dk_juggler.gif"] = im(1, 97);ism["dk_warchef.gif"] = im(0, 98);ism["gnomester.gif"] = im(5, 91);ism["gnugnome.gif"] = im(10, 84);ism["gourd_goblin.gif"] = im(7, 92);ism["goldenring.gif"] = im(17, 86);ism["goomba.gif"] = im(9, 89);ism["goosealaying.gif"] = im(0, 99);ism["1_4a.gif"] = im(200, 200, 2, 198);ism["1_1.gif"] = im(18, 93);ism["1_2.gif"] = im(10, 92);ism["1_3.gif"] = im(10, 93);ism["giant_goth.gif"] = im(3, 96);ism["gourami.gif"] = im(51, 93);ism["gov_agent.gif"] = im(11, 94);ism["scientist.gif"] = im(3, 95);ism["adv_stench1.gif"] = im(6, 97);ism["grasselemental.gif"] = im(0, 99);ism["grasspirate.gif"] = im(0, 95);ism["rober.gif"] = im(8, 91);ism["zomshovel.gif"] = im(4, 94);ism["adv_sleaze1.gif"] = im(3, 90);ism["duckgreasy.gif"] = im(0, 91);ism["wolfoftheair.gif"] = im(200, 150, 8, 136);ism["wolfoftheair_hm.gif"] = im(200, 150, 7, 135);ism["warhipgr.gif"] = im(5, 93);ism["porkbun.gif"] = im(14, 79);ism["gritpirate.gif"] = im(1, 97);ism["surv_grizzled.gif"] = im(3, 91);ism["wingedyeti.gif"] = im(200, 100, 0, 99);ism["groast.gif"] = im(5, 94);ism["grouchewie.gif"] = im(7, 90);ism["cultistgroup.gif"] = im(4, 96);ism["groupie.gif"] = im(16, 85);ism["dwarf_grumpy.gif"] = im(0, 99);ism["grungypirate.gif"] = im(11, 95);ism["guardturtle1.gif"] = im(29, 89);ism["plesio.gif"] = im(1, 98);ism["gurgle.gif"] = im(150, 100, 0, 99);ism["animturtle.gif"] = im(100, 120, 4, 118);ism["beeguy.gif"] = im(0, 96);ism["gothic.gif"] = im(4, 96);ism["adv_sleaze2.gif"] = im(6, 89);ism["drunkyam.gif"] = im(0, 99);ism["hamsterpus.gif"] = im(2, 88);ism["mariachi1.gif"] = im(2, 97);ism["shiv_hangman.gif"] = im(3, 93);ism["hunter12.gif"] = im(3, 97);ism["skullabra.gif"] = im(1, 91);ism["tureen.gif"] = im(6, 87);ism["crystalgolem.gif"] = im(1, 92);ism["heatseal.gif"] = im(0, 99);ism["warfratar2.gif"] = im(10, 88);ism["nachogolem.gif"] = im(0, 98);ism["hellion.gif"] = im(3, 95);ism["sealguard.gif"] = im(13, 95);ism["sealpup.gif"] = im(29, 81);ism["hepcat.gif"] = im(1, 98);ism["hunter6.gif"] = im(3, 96);ism["hermeticseal.gif"] = im(5, 88);ism["c10slideshow.gif"] = im(10, 89);ism["highpriest.gif"] = im(0, 99);ism["warbear31.gif"] = im(0, 99);ism["snakes.gif"] = im(2, 83);ism["hockeyelem.gif"] = im(6, 90);ism["hodgman.gif"] = im(1, 96);ism["holoarmy.gif"] = im(2, 92);ism["honeypot.gif"] = im(5, 92);ism["hooded.gif"] = im(4, 96);ism["stenchfamily.gif"] = im(4, 96);ism["prim_amoe.gif"] = im(0, 98);ism["dvhotbear1.gif"] = im(5, 94);ism["dvhotghost1.gif"] = im(4, 93);ism["hothobo1.gif"] = im(3, 92);ism["dvhotskel1.gif"] = im(13, 99);ism["dvhotvamp1.gif"] = im(0, 98);ism["dvhotwolf1.gif"] = im(12, 98);ism["dvhotzom1.gif"] = im(1, 98);ism["mimic4.gif"] = im(1, 97);ism["ghuol_huge.gif"] = im(5, 95);ism["giantmosquito.gif"] = im(0, 98);ism["iceguy1.gif"] = im(1, 98);ism["bridgetroll.gif"] = im(2, 97);ism["vib6.gif"] = im(7, 98);ism["caveelf2.gif"] = im(18, 73);ism["huntingseal.gif"] = im(9, 85);ism["poolghost.gif"] = im(0, 99);ism["hypnotist.gif"] = im(0, 97);ism["medicus.gif"] = im(3, 92);ism["bb_vamp.gif"] = im(3, 93);ism["adv_cold2.gif"] = im(0, 98);ism["icecreamtruck.gif"] = im(400, 150, 9, 142);ism["icecube.gif"] = im(12, 94);ism["iceskate.gif"] = im(4, 96);ism["adv_cold3.gif"] = im(8, 93);ism["mummycat.gif"] = im(1, 96);ism["illegal_alien.gif"] = im(24, 96);ism["vib3.gif"] = im(0, 99);ism["drunktofurkey.gif"] = im(0, 99);ism["seal_larva.gif"] = im(63, 93);ism["seal_baby.gif"] = im(47, 93);ism["meatbug.gif"] = im(7, 89);ism["inkubus.gif"] = im(7, 97);ism["mariachi2.gif"] = im(2, 91);ism["adv_strong2.gif"] = im(5, 92);ism["encount.gif"] = im(3, 93);ism["jacobsadder.gif"] = im(0, 99);ism["orquette1.gif"] = im(13, 86);ism["jamfish.gif"] = im(0, 98);ism["pilot.gif"] = im(3, 97);ism["jetski.gif"] = im(15, 94);ism["jockohomo.gif"] = im(0, 98);ism["merkindragger2.gif"] = im(1, 99);ism["doubt3.gif"] = im(0, 99);ism["orangutan.gif"] = im(8, 97);ism["scabie_jungle.gif"] = im(2, 92);ism["thejunk.gif"] = im(19, 86);ism["js_bender.gif"] = im(5, 91);ism["js_melter.gif"] = im(11, 95);ism["js_sharpener.gif"] = im(7, 90);ism["orquette2.gif"] = im(13, 86);ism["keese.gif"] = im(25, 66);ism["tooold.gif"] = im(1, 97);ism["clownfish.gif"] = im(22, 82);ism["killingbird.gif"] = im(0, 98);ism["adv_smart3.gif"] = im(15, 94);ism["snaknight.gif"] = im(0, 97);ism["wolfknight.gif"] = im(3, 97);ism["knight.gif"] = im(7, 91);ism["kg_accountant.gif"] = im(12, 98);ism["kg_alchemist.gif"] = im(15, 94);ism["kg_asstchef.gif"] = im(0, 99);ism["kg_bbqteam.gif"] = im(1, 99);ism["kg_beancounter.gif"] = im(12, 97);ism["kg_guard.gif"] = im(10, 94);ism["kg_guardcaptain.gif"] = im(10, 94);ism["zomelite.gif"] = im(6, 90); -ism["kg_embezzler.gif"] = im(12, 97);ism["kg_haremgirl.gif"] = im(15, 89);ism["kg_haremguard.gif"] = im(14, 94);ism["kg_king.gif"] = im(0, 98);ism["kg_madsci.gif"] = im(11, 91);ism["kg_madam.gif"] = im(16, 97);ism["kg_masterchef.gif"] = im(0, 99);ism["kg_mba.gif"] = im(16, 98);ism["kg_mutant.gif"] = im(13, 97);ism["kg_poseur.gif"] = im(28, 94);ism["kg_souschef.gif"] = im(0, 98);ism["kg_verymadsci.gif"] = im(15, 92);ism["slanding.gif"] = im(5, 91);ism["yeti.gif"] = im(1, 95);ism["koopa.gif"] = im(5, 93);ism["kublakhan.gif"] = im(5, 92);ism["adv_fast3.gif"] = im(4, 92);ism["limp.gif"] = im(8, 94);ism["labmonkey.gif"] = im(16, 91);ism["n00b.gif"] = im(6, 91);ism["lower_k.gif"] = im(7, 81);ism["headwolf.gif"] = im(0, 98);ism["grayblob2.gif"] = im(9, 93);ism["larrysignfield.gif"] = im(9, 95);ism["filthworm1.gif"] = im(49, 83);ism["laser.gif"] = im(9, 97);ism["lavagolem.gif"] = im(5, 89);ism["lavalamprey.gif"] = im(3, 95);ism["lavalos.gif"] = im(200, 300, 7, 290);ism["lavatory.gif"] = im(0, 98);ism["statbike.gif"] = im(2, 96);ism["linbox.gif"] = im(17, 91);ism["lemonfish.gif"] = im(17, 74);ism["adv_sleaze4.gif"] = im(3, 97);ism["lfruitgol.gif"] = im(33, 84);ism["licosnake.gif"] = im(5, 94);ism["lich.gif"] = im(3, 98);ism["bb_liquidmetal.gif"] = im(7, 92);ism["liquidmetal.gif"] = im(1, 97);ism["grayblob1.gif"] = im(40, 88);ism["canoeman.gif"] = im(13, 66);ism["wanderacc2.gif"] = im(1, 98);ism["pa_bread.gif"] = im(7, 95);ism["lobsterman.gif"] = im(1, 98);ism["lollicat.gif"] = im(12, 91);ism["lolligator.gif"] = im(18, 85);ism["lollipede.gif"] = im(11, 77);ism["lolliphaunt.gif"] = im(12, 91);ism["spelunklolm.gif"] = im(250, 300, 3, 269);ism["lollirus2.gif"] = im(9, 91);ism["vib5.gif"] = im(1, 97);ism["coalition.gif"] = im(2, 89);ism["soggyraven.gif"] = im(0, 99);ism["lordspooky.gif"] = im(7, 97);ism["lotswife.gif"] = im(1, 97);ism["lizardfish.gif"] = im(31, 61);ism["regret2.gif"] = im(1, 95);ism["kok_lovers.gif"] = im(5, 97);ism["lower_h.gif"] = im(13, 87);ism["catstatue.gif"] = im(15, 84);ism["lumbersup.gif"] = im(5, 92);ism["lumberjill.gif"] = im(5, 92);ism["lumberjuan.gif"] = im(0, 92);ism["4_4a.gif"] = im(200, 200, 13, 168);ism["4_1.gif"] = im(21, 70);ism["4_2.gif"] = im(19, 92);ism["4_3.gif"] = im(3, 97);ism["lynyrd.gif"] = im(9, 91);ism["skinner.gif"] = im(2, 96);ism["adv_strong1.gif"] = im(5, 94);ism["madbugbear.gif"] = im(6, 95);ism["prim_flag.gif"] = im(0, 98);ism["madwino.gif"] = im(6, 94);ism["madiator.gif"] = im(2, 96);ism["dragonfish.gif"] = im(0, 99);ism["mech.gif"] = im(1, 98);ism["spelunkmagma.gif"] = im(7, 84);ism["cropcircle.gif"] = im(2, 93);ism["hairclog.gif"] = im(0, 94);ism["magfield.gif"] = im(1, 93);ism["tofurkey.gif"] = im(2, 92);ism["maltliquorgolem.gif"] = im(0, 99);ism["mammon.gif"] = im(200, 200, 11, 193);ism["redbuttons.gif"] = im(1, 93);ism["audrey.gif"] = im(0, 98);ism["wraith5.gif"] = im(10, 90);ism["bandolero.gif"] = im(0, 99);ism["mar_bruiser.gif"] = im(4, 93);ism["mariachi3.gif"] = im(1, 96);ism["wraith3.gif"] = im(9, 88);ism["promoter.gif"] = im(2, 93);ism["wasp.gif"] = im(13, 96);ism["mayorghost.gif"] = im(200, 150, 3, 146);ism["mayorghost_hm.gif"] = im(200, 150, 5, 147);ism["beggar.gif"] = im(0, 98);ism["duckmeandrunk.gif"] = im(3, 96);ism["med_dung.gif"] = im(5, 94);ism["med_mugman.gif"] = im(3, 92);ism["med_muggirl.gif"] = im(5, 89);ism["med_potter.gif"] = im(3, 91);ism["med_strawman.gif"] = im(0, 97);ism["med_stucco.gif"] = im(12, 96);ism["mimic3.gif"] = im(11, 89);ism["cvmedusa.gif"] = im(4, 91);ism["megafrog.gif"] = im(15, 89);ism["vib1.gif"] = im(0, 98);ism["lawngnome1.gif"] = im(14, 80);ism["nemesisthug.gif"] = im(7, 90);ism["merkinalphabet.gif"] = im(6, 93);ism["merkinballer.gif"] = im(4, 98);ism["merkinswitcher.gif"] = im(4, 98);ism["merkinburglar.gif"] = im(1, 95);ism["merkindiver.gif"] = im(1, 95);ism["merkindrifter.gif"] = im(4, 98);ism["merkinhealer.gif"] = im(3, 95);ism["merkinjuicer.gif"] = im(4, 98);ism["merkinminer.gif"] = im(1, 95);ism["merkinmonitor.gif"] = im(6, 93);ism["merkindragger.gif"] = im(4, 98);ism["merkinposeur.gif"] = im(1, 95);ism["merkinpunisher.gif"] = im(1, 95);ism["merkinraider.gif"] = im(3, 95);ism["merkinresearcher.gif"] = im(6, 93);ism["merkinspear.gif"] = im(1, 95);ism["merkinscav.gif"] = im(1, 95);ism["merkinghost.gif"] = im(13, 85);ism["merkinteacher.gif"] = im(2, 99);ism["merkintippler.gif"] = im(1, 99);ism["merkintrainer.gif"] = im(4, 98);ism["mercenary.gif"] = im(6, 95);ism["pengmesmer.gif"] = im(3, 99);ism["adv_smart2.gif"] = im(6, 98);ism["adv_fast2.gif"] = im(1, 96);ism["lowerm.gif"] = im(9, 90);ism["minecrab.gif"] = im(0, 99);ism["mineboss2.gif"] = im(1, 96);ism["mineboss1.gif"] = im(2, 97);ism["mineworker1.gif"] = im(3, 92);ism["mineworker2.gif"] = im(3, 92);ism["twins_mism.gif"] = im(100, 200, 17, 198);ism["badportrait.gif"] = im(0, 98);ism["pengarson.gif"] = im(2, 97);ism["mobcapo.gif"] = im(8, 95);ism["pengcapo.gif"] = im(3, 98);ism["pengdemo.gif"] = im(2, 98);ism["pengthug.gif"] = im(2, 98);ism["peng_ent.gif"] = im(3, 98);ism["pengbook.gif"] = im(2, 98);ism["penggoon.gif"] = im(2, 98);ism["penggun.gif"] = im(3, 98);ism["pengchef.gif"] = im(3, 98);ism["pengpsycho.gif"] = im(3, 98);ism["pengracket.gif"] = im(3, 99);ism["pengsmasher.gif"] = im(0, 98);ism["hazmatpeng.gif"] = im(0, 98);ism["pengprano.gif"] = im(0, 99);ism["pengphone.gif"] = im(0, 98);ism["warhipar2.gif"] = im(6, 89);ism["modelskeleton.gif"] = im(1, 99);ism["modernzombie.gif"] = im(8, 91);ism["moyster.gif"] = im(7, 93);ism["moneybee.gif"] = im(11, 75);ism["elf_wrench.gif"] = im(17, 87);ism["monsterhearse.gif"] = im(250, 200, 22, 186);ism["boiler.gif"] = im(4, 95);ism["monty.gif"] = im(4, 95);ism["moonshriner.gif"] = im(0, 99);ism["fear1.gif"] = im(0, 99);ism["wraith1.gif"] = im(8, 83);ism["motherseal.gif"] = im(9, 91);ism["otherimages/slimetube/stboss.gif"] = im(30, 30, 29, 30);ism["motorhead.gif"] = im(2, 95);ism["mountainman.gif"] = im(3, 97);ism["lawngnome3.gif"] = im(1, 99);ism["lawngnome2.gif"] = im(26, 98);ism["mrcheeng.gif"] = im(0, 97);ism["mrchoch.gif"] = im(0, 98);ism["adv_strong4.gif"] = im(17, 91);ism["adv_cold4.gif"] = im(0, 99);ism["chemteacher.gif"] = im(0, 98);ism["swampturtle.gif"] = im(0, 99);ism["muff.gif"] = im(10, 78);ism["mumblebee.gif"] = im(27, 74);ism["spelunkmumm.gif"] = im(3, 92);ism["mush_beefy.gif"] = im(6, 89);ism["antlerelf.gif"] = im(12, 97);ism["elfblob.gif"] = im(5, 98);ism["elflimbs.gif"] = im(17, 97);ism["elfclaw.gif"] = im(25, 96);ism["mutantgila.gif"] = im(3, 96);ism["mutantsnake.gif"] = im(19, 95);ism["mutantcactus.gif"] = im(0, 96);ism["elfhulk.gif"] = im(3, 97);ism["alielephant.gif"] = im(10, 97);ism["mutantalielf.gif"] = im(1, 97);ism["bb_vassist.gif"] = im(3, 95);ism["nastybear.gif"] = im(1, 97);ism["fear3.gif"] = im(1, 99);ism["sorcform1.gif"] = im(0, 99);ism["sorcblob.gif"] = im(200, 200, 28, 197);ism["bigsaus.gif"] = im(39, 59);ism["warfratmd2.gif"] = im(2, 96);ism["navyseal.gif"] = im(0, 98);ism["giant_neckbeard.gif"] = im(3, 95);ism["neil.gif"] = im(6, 95);ism["flytrap.gif"] = im(0, 96);ism["mc_respect2.gif"] = im(0, 97);ism["mc_respect1.gif"] = im(0, 97);ism["snakenest.gif"] = im(8, 88);ism["newt.gif"] = im(43, 97);ism["emofrat.gif"] = im(0, 97);ism["ninjawaiter.gif"] = im(5, 95);ism["ninjarice.gif"] = im(7, 95);ism["snowman.gif"] = im(7, 95);ism["ninja_ass.gif"] = im(3, 91);ism["ninjamop.gif"] = im(10, 98);ism["ninjacloud.gif"] = im(3, 97);ism["nhobo1.gif"] = im(7, 94);ism["hunter2.gif"] = im(0, 99);ism["tropicalskel.gif"] = im(0, 98);ism["novia.gif"] = im(5, 99);ism["novio.gif"] = im(11, 97);ism["nurseshark.gif"] = im(15, 71);ism["whirlwind.gif"] = im(8, 91);ism["tourist.gif"] = im(9, 92);ism["octopus.gif"] = im(0, 96);ism["octorok.gif"] = im(10, 93);ism["headghost.gif"] = im(4, 94);ism["adv_stench4.gif"] = im(0, 97);ism["kg_offdutyguard.gif"] = im(13, 95);ism["officialseal.gif"] = im(17, 91);ism["oilbaron.gif"] = im(0, 99);ism["oilcartel2.gif"] = im(200, 100, 5, 97);ism["oilslick.gif"] = im(29, 61);ism["oiltycoon.gif"] = im(1, 99);ism["straw_sleaze.gif"] = im(37, 93);ism["olscratch.gif"] = im(2, 97);ism["noart.gif"] = im(7, 91);ism["dk_oneeye.gif"] = im(2, 95);ism["oneeyed.gif"] = im(4, 91);ism["fratboy.gif"] = im(2, 91);ism["fratskirt.gif"] = im(2, 91);ism["fratbong.gif"] = im(2, 91);ism["lilfratboy.gif"] = im(7, 86);ism["oscus.gif"] = im(5, 97);ism["bandsaw.gif"] = im(11, 87);ism["tableoutlaw.gif"] = im(8, 93);ism["outlawboss.gif"] = im(0, 97);ism["surv_overarmed.gif"] = im(0, 98);ism["pimp.gif"] = im(17, 90);ism["elpriest.gif"] = im(1, 97);ism["stonebros.gif"] = im(2, 96);ism["warfratpr.gif"] = im(19, 85);ism["ptowels.gif"] = im(0, 99);ism["hunter3.gif"] = im(1, 99); -ism["peanut.gif"] = im(0, 98);ism["mh_roommate.gif"] = im(2, 97);ism["pencil.gif"] = im(5, 93);ism["smoochboss3.gif"] = im(100, 200, 17, 191);ism["defense_sphere.gif"] = im(3, 97);ism["pestopuddle.gif"] = im(46, 91);ism["perpbat.gif"] = im(5, 88);ism["bystander.gif"] = im(1, 96);ism["somepig.gif"] = im(3, 88);ism["pinebat.gif"] = im(33, 69);ism["piranhadon.gif"] = im(29, 97);ism["wood_stench.gif"] = im(3, 90);ism["adv_spooky2.gif"] = im(4, 95);ism["plaidghost.gif"] = im(7, 95);ism["plaque.gif"] = im(0, 99);ism["drunkcrancan.gif"] = im(1, 99);ism["drunkfrat.gif"] = im(1, 96);ism["animelf2.gif"] = im(20, 81);ism["poolter.gif"] = im(1, 97);ism["poolter2.gif"] = im(2, 98);ism["popnlocker.gif"] = im(0, 98);ism["porkbutterfly.gif"] = im(9, 88);ism["porksword.gif"] = im(17, 87);ism["adv_sleaze3.gif"] = im(8, 90);ism["abom.gif"] = im(6, 95);ism["crancan.gif"] = im(21, 95);ism["mystwander2.gif"] = im(9, 95);ism["mystwander1.gif"] = im(8, 95);ism["tomatosoup.gif"] = im(6, 89);ism["eyewash.gif"] = im(11, 91);ism["mystwander4.gif"] = im(1, 97);ism["mangler.gif"] = im(5, 95);ism["organ.gif"] = im(1, 99);ism["silverware.gif"] = im(0, 99);ism["toybox.gif"] = im(7, 89);ism["winerack.gif"] = im(4, 98);ism["question.gif"] = im(0, 86);ism["pouooze.gif"] = im(33, 88);ism["primp.gif"] = im(7, 90);ism["fly.gif"] = im(4, 92);ism["surv_primitive.gif"] = im(2, 91);ism["chalmers.gif"] = im(1, 98);ism["bigskeleton.gif"] = im(0, 98);ism["giant_procrast.gif"] = im(5, 98);ism["profjacking.gif"] = im(2, 96);ism["elf_propaganda.gif"] = im(11, 84);ism["protag.gif"] = im(6, 95);ism["protspect.gif"] = im(0, 99);ism["spurt.gif"] = im(0, 99);ism["elf_provocateur.gif"] = im(10, 83);ism["pterodact.gif"] = im(250, 150, 14, 136);ism["pufferfish.gif"] = im(0, 98);ism["pumpedbass.gif"] = im(17, 69);ism["shiv_pumpkin.gif"] = im(6, 97);ism["giant_punk.gif"] = im(0, 98);ism["pyg_squad.gif"] = im(0, 99);ism["pyg_blowgunner.gif"] = im(31, 99);ism["pyg_bowler.gif"] = im(29, 98);ism["pyg_headhunter.gif"] = im(28, 99);ism["pyg_janitor.gif"] = im(41, 99);ism["pyg_orderlies.gif"] = im(18, 98);ism["pyg_shaman.gif"] = im(24, 97);ism["pyg_acct.gif"] = im(33, 99);ism["pyg_lawyer.gif"] = im(27, 98);ism["pyg_nurse.gif"] = im(20, 98);ism["pyg_surgeon.gif"] = im(21, 99);ism["wood_spooky.gif"] = im(28, 90);ism["animelf4.gif"] = im(19, 78);ism["upper_q.gif"] = im(8, 88);ism["beequeen.gif"] = im(13, 87);ism["spelunkbeeq.gif"] = im(200, 150, 5, 149);ism["filthworm4.gif"] = im(0, 97);ism["qbasicele.gif"] = im(0, 97);ism["healer.gif"] = im(9, 93);ism["wanderacc3.gif"] = im(0, 99);ism["mmoaddict.gif"] = im(12, 94);ism["naskar1.gif"] = im(5, 95);ism["weightrack.gif"] = im(27, 95);ism["elf_raconteur.gif"] = im(7, 80);ism["radiator.gif"] = im(0, 99);ism["hunter13.gif"] = im(7, 93);ism["anger1.gif"] = im(0, 99);ism["ragingbull.gif"] = im(2, 94);ism["adding.gif"] = im(2, 89);ism["mh_scenester.gif"] = im(1, 96);ism["ratbat.gif"] = im(19, 67);ism["duckrattle.gif"] = im(2, 96);ism["smoochboss2.gif"] = im(100, 200, 13, 191);ism["raven.gif"] = im(18, 93);ism["giant_raver.gif"] = im(0, 99);ism["wallpaper.gif"] = im(17, 83);ism["foss_baboon.gif"] = im(1, 97);ism["foss_bat.gif"] = im(38, 69);ism["foss_demon.gif"] = im(150, 150, 2, 130);ism["foss_spider.gif"] = im(150, 150, 32, 130);ism["foss_serpent.gif"] = im(1, 96);ism["redbutler.gif"] = im(4, 95);ism["redfox.gif"] = im(5, 94);ism["redherring.gif"] = im(7, 94);ism["redskeleton.gif"] = im(5, 97);ism["redsnapper.gif"] = im(6, 90);ism["regretman.gif"] = im(200, 200, 9, 180);ism["regbat.gif"] = im(35, 66);ism["headlessskel.gif"] = im(15, 89);ism["mistress.gif"] = im(2, 99);ism["giant_renfair.gif"] = im(1, 97);ism["reneccorman.gif"] = im(1, 97);ism["doubt2.gif"] = im(6, 92);ism["kok_waiter.gif"] = im(2, 95);ism["revbugbear.gif"] = im(1, 98);ism["merkinswitcher2.gif"] = im(1, 99);ism["duckgolem.gif"] = im(2, 92);ism["rock_guy.gif"] = im(31, 96);ism["popweasel.gif"] = im(0, 99);ism["scorpion.gif"] = im(8, 91);ism["rock_snake.gif"] = im(1, 97);ism["caveelf1.gif"] = im(21, 78);ism["rock_fish.gif"] = im(24, 77);ism["rollerskate.gif"] = im(2, 92);ism["muse.gif"] = im(2, 96);ism["rollingstone.gif"] = im(4, 90);ism["roncopper.gif"] = im(3, 96);ism["realdolphin.gif"] = im(14, 92);ism["duckfat.gif"] = im(0, 99);ism["rudolfus.gif"] = im(3, 97);ism["rulergolem.gif"] = im(0, 99);ism["runningman.gif"] = im(2, 94);ism["bum.gif"] = im(8, 95);ism["elf_saboteur.gif"] = im(22, 79);ism["ferret.gif"] = im(2, 90);ism["toothgoat.gif"] = im(0, 95);ism["stkiwi.gif"] = im(8, 85);ism["lime.gif"] = im(15, 77);ism["sadiator.gif"] = im(3, 92);ism["safarijack.gif"] = im(1, 97);ism["salamander.gif"] = im(51, 97);ism["salaminder.gif"] = im(26, 88);ism["salaryninja.gif"] = im(4, 96);ism["pirate1.gif"] = im(6, 93);ism["adv_smooth1.gif"] = im(5, 92);ism["zompirate.gif"] = im(7, 93);ism["bb_scav.gif"] = im(7, 93);ism["gummifish.gif"] = im(0, 99);ism["schoolofmany.gif"] = im(3, 94);ism["wizardfish.gif"] = im(1, 99);ism["scimitarfish.gif"] = im(16, 73);ism["duckscorch.gif"] = im(0, 98);ism["spelunkscorp.gif"] = im(3, 89);ism["hunter4.gif"] = im(2, 92);ism["scoutseal.gif"] = im(12, 86);ism["screambat.gif"] = im(24, 79);ism["screwgolem.gif"] = im(3, 98);ism["seacow.gif"] = im(17, 73);ism["seacowboy.gif"] = im(0, 98);ism["adv_smooth4.gif"] = im(2, 95);ism["secrobot.gif"] = im(11, 87);ism["securityslime.gif"] = im(4, 96);ism["crimbominer2.gif"] = im(9, 81);ism["sadpoet.gif"] = im(5, 93);ism["atm.gif"] = im(7, 94);ism["serialbus.gif"] = im(1, 94);ism["grodseal.gif"] = im(3, 93);ism["fireservant1.gif"] = im(0, 99);ism["sewergator.gif"] = im(11, 78);ism["sewersnake.gif"] = im(5, 91);ism["sewertruck.gif"] = im(400, 150, 6, 143);ism["sororghost1.gif"] = im(1, 97);ism["sororeton1.gif"] = im(3, 89);ism["sororpire1.gif"] = im(7, 97);ism["sororwolf1.gif"] = im(6, 97);ism["sororbie1.gif"] = im(5, 95);ism["shadowseal.gif"] = im(8, 91);ism["sheetghost.gif"] = im(5, 95);ism["shopkeep.gif"] = im(7, 91);ism["shub-jigguwatt.gif"] = im(300, 300, 20, 283);ism["tacoelf_sign.gif"] = im(27, 94);ism["caveelf4.gif"] = im(14, 77);ism["sk8gnome.gif"] = im(23, 77);ism["boardskate.gif"] = im(3, 91);ism["animrat.gif"] = im(1, 93);ism["catskel.gif"] = im(20, 84);ism["hamskel.gif"] = im(73, 95);ism["monkeyskel.gif"] = im(17, 77);ism["crimonster6.gif"] = im(3, 95);ism["steward.gif"] = im(3, 97);ism["spelunkskel.gif"] = im(10, 91);ism["mopskeleton.gif"] = im(6, 96);ism["buttleton.gif"] = im(3, 97);ism["sketchyvan.gif"] = im(200, 100, 0, 99);ism["skinflute.gif"] = im(27, 76);ism["skeleton.gif"] = im(6, 93);ism["skullbat.gif"] = im(31, 66);ism["skulldozer.gif"] = im(450, 300, 12, 278);ism["skullery.gif"] = im(0, 97);ism["dvsleazebear1.gif"] = im(5, 89);ism["dvsleazeghost1.gif"] = im(11, 88);ism["slhobo1.gif"] = im(1, 97);ism["dvsleazeskel1.gif"] = im(9, 92);ism["dvsleazevamp1.gif"] = im(3, 96);ism["dvsleazewolf1.gif"] = im(2, 97);ism["dvsleazezom1.gif"] = im(4, 93);ism["kg_sleepingguard.gif"] = im(0, 98);ism["dwarf_sleepy.gif"] = im(37, 95);ism["mar_sleepy.gif"] = im(0, 99);ism["slime1_1.gif"] = im(0, 98);ism["slime2_1.gif"] = im(0, 96);ism["slime3_1.gif"] = im(2, 97);ism["slime4_1.gif"] = im(3, 95);ism["slime5_1.gif"] = im(0, 98);ism["wood_sleaze.gif"] = im(16, 79);ism["holglob.gif"] = im(34, 89);ism["slithering.gif"] = im(15, 81);ism["ssd_burger.gif"] = im(0, 99);ism["ssd_cocktail.gif"] = im(0, 98);ism["ssd_sundae.gif"] = im(1, 98);ism["eliot.gif"] = im(5, 97);ism["mimic2.gif"] = im(23, 87);ism["smartskel.gif"] = im(4, 94);ism["smellothewisp.gif"] = im(4, 98);ism["smokemonster.gif"] = im(5, 96);ism["smoochman3.gif"] = im(100, 150, 16, 127);ism["smoochman1.gif"] = im(7, 93);ism["smoochman2.gif"] = im(1, 97);ism["adv_smooth3.gif"] = im(3, 97);ism["scabie_jazz.gif"] = im(2, 89);ism["smutorc_jacker.gif"] = im(6, 95);ism["smutorc_nailer.gif"] = im(8, 96);ism["smutorc_pervert.gif"] = im(7, 93);ism["smutorc_layer.gif"] = im(5, 97);ism["smutorc_screwer.gif"] = im(9, 97);ism["spelunksnake.gif"] = im(20, 83);ism["firesnake.gif"] = im(0, 99);ism["snakeboss6.gif"] = im(150, 150, 26, 131);ism["snapdragon.gif"] = im(1, 98);ism["snowqueen.gif"] = im(0, 98);ism["adv_cold1.gif"] = im(9, 93);ism["sodium.gif"] = im(3, 92);ism["6_4a.gif"] = im(200, 200, 11, 189);ism["6_1.gif"] = im(10, 91);ism["6_2.gif"] = im(3, 96);ism["6_3.gif"] = im(2, 98);ism["sonofsailor.gif"] = im(1, 99);ism["warfratmd.gif"] = im(4, 96);ism["warfratcm.gif"] = im(1, 96);ism["tree_hickory.gif"] = im(0, 98);ism["drunkstuffing.gif"] = im(0, 99);ism["spacebeast1.gif"] = im(8, 83);ism["spacebeast3.gif"] = im(14, 91);ism["spacemarine.gif"] = im(1, 95);ism["aboo_trek.gif"] = im(1, 97);ism["3_4a.gif"] = im(200, 200, 3, 193);ism["3_1.gif"] = im(2, 95);ism["3_2.gif"] = im(4, 97);ism["3_3.gif"] = im(0, 93);ism["spamwitch.gif"] = im(3, 95);ism["pa_spatula.gif"] = im(7, 98);ism["wretchedseal.gif"] = im(54, 94);ism["hunter11.gif"] = im(3, 95);ism["jellyfish.gif"] = im(6, 96);ism["spelastronaut.gif"] = im(2, 96);ism["spelunkspider.gif"] = im(21, 88);ism["topi1.gif"] = im(3, 93);ism["gourd_spider.gif"] = im(10, 83);ism["gremlinspider.gif"] = im(7, 88);ism["spelunkspiderq.gif"] = im(150, 100, 1, 96);ism["gourd_spidergob.gif"] = im(1, 97);ism["spiderhut.gif"] = im(200, 150, 9, 140);ism["bb_spider.gif"] = im(125, 100, 3, 86);ism["spikeskel.gif"] = im(7, 92);ism["spiritalclock.gif"] = im(0, 99);ism["spiritbug.gif"] = im(10, 92);ism["spiritfaucet.gif"] = im(5, 93);ism["5_1.gif"] = im(3, 99);ism["5_2.gif"] = im(0, 99);ism["5_3.gif"] = im(0, 99);ism["spiritpea.gif"] = im(18, 78);ism["sponge.gif"] = im(0, 98);ism["dvspookybear1.gif"] = im(1, 95);ism["dvspookyghost1.gif"] = im(4, 94);ism["sgguard.gif"] = im(16, 77);ism["sgninja.gif"] = im(22, 80);ism["sgwarlock.gif"] = im(8, 83);ism["spookyhobo1.gif"] = im(3, 89);ism["mummy.gif"] = im(6, 89);ism["musicbox.gif"] = im(2, 90);ism["dvspookyskel1.gif"] = im(13, 97);ism["vampire.gif"] = im(10, 91);ism["dvspookyvamp1.gif"] = im(35, 65);ism["dvspookywolf1.gif"] = im(8, 94);ism["dvspookyzom1.gif"] = im(39, 93);ism["manor.gif"] = im(12, 89);ism["sporto.gif"] = im(1, 99);ism["princess.gif"] = im(8, 95);ism["steamelemental.gif"] = im(3, 94);ism["straw_hot.gif"] = im(5, 91);ism["giant_steampunk.gif"] = im(0, 99);ism["2_4a.gif"] = im(200, 200, 11, 189);ism["2_1.gif"] = im(10, 90);ism["2_2.gif"] = im(12, 96);ism["2_3.gif"] = im(16, 93);ism["dvstenchbear1.gif"] = im(1, 99);ism["dvstenchghost1.gif"] = im(0, 97);ism["stenchhobo1.gif"] = im(12, 97);ism["dvstenchskel1.gif"] = im(2, 99);ism["dvstenchvamp1.gif"] = im(0, 98);ism["dvstenchwolf1.gif"] = im(1, 99);ism["dvstenchzom1.gif"] = im(0, 98);ism["steven.gif"] = im(5, 91); -ism["stickymummy.gif"] = im(3, 94);ism["disco_stiff.gif"] = im(2, 91);ism["crimonster4.gif"] = im(3, 94);ism["stomper.gif"] = im(0, 99);ism["stone_pirate.gif"] = im(3, 93);ism["stormcow.gif"] = im(0, 99);ism["strangler.gif"] = im(1, 98);ism["algae.gif"] = im(1, 97);ism["crimboelf.gif"] = im(27, 96);ism["moosehead.gif"] = im(7, 93);ism["stuffgolem.gif"] = im(3, 91);ism["paulblart.gif"] = im(2, 99);ism["suckubus.gif"] = im(6, 92);ism["tree_juniper.gif"] = im(0, 99);ism["colasoldier.gif"] = im(1, 95);ism["supervirus.gif"] = im(9, 95);ism["witchy1.gif"] = im(0, 99);ism["mar_surprised.gif"] = im(0, 99);ism["mc_soy2.gif"] = im(0, 94);ism["mc_soy1.gif"] = im(0, 98);ism["beav_jack.gif"] = im(9, 92);ism["beav_shaman.gif"] = im(0, 97);ism["beav_warrior.gif"] = im(7, 90);ism["duckstinky.gif"] = im(0, 98);ism["swampentity.gif"] = im(5, 95);ism["swampgator.gif"] = im(19, 81);ism["swamphag.gif"] = im(0, 97);ism["swampowl.gif"] = im(0, 99);ism["swampskunk.gif"] = im(3, 95);ism["swarmers.gif"] = im(1, 95);ism["ralphbat.gif"] = im(2, 84);ism["ants.gif"] = im(1, 97);ism["fudgewasps.gif"] = im(0, 98);ism["whelps1.gif"] = im(10, 85);ism["aswarm.gif"] = im(7, 93);ism["kg_lice.gif"] = im(3, 93);ism["mutantants.gif"] = im(9, 87);ism["beatles.gif"] = im(5, 94);ism["skullswarm.gif"] = im(50, 93);ism["swisshen.gif"] = im(0, 98);ism["t9000.gif"] = im(3, 99);ism["cacotap.gif"] = im(21, 80);ism["tacofish.gif"] = im(17, 82);ism["tacoelf_taco.gif"] = im(12, 86);ism["tacoelf_cart.gif"] = im(9, 82);ism["kasemhead.gif"] = im(2, 96);ism["biggnat.gif"] = im(21, 70);ism["hatskel.gif"] = im(0, 99);ism["adv_fast4.gif"] = im(11, 86);ism["c10spreadsheet.gif"] = im(8, 98);ism["tektite.gif"] = im(21, 77);ism["skel10.gif"] = im(300, 100, 0, 98);ism["terrorbot.gif"] = im(5, 88);ism["tetched.gif"] = im(1, 98);ism["madpirate.gif"] = im(6, 93);ism["fudgeman.gif"] = im(200, 200, 19, 186);ism["theaquaman.gif"] = im(0, 99);ism["boris.gif"] = im(6, 89);ism["aojarls.gif"] = im(6, 93);ism["sneakypete.gif"] = im(13, 90);ism["batinspats.gif"] = im(200, 100, 6, 96);ism["beefhemoth.gif"] = im(200, 100, 0, 98);ism["c10bge.gif"] = im(11, 86);ism["thisdude.gif"] = im(0, 93);ism["c10faces.gif"] = im(0, 99);ism["beelzebozo.gif"] = im(0, 98);ism["colollilossus.gif"] = im(270, 270, 3, 264);ism["bath_craykin.gif"] = im(0, 99);ism["darkness.gif"] = im(0, 98);ism["theemperor.gif"] = im(5, 93);ism["skelmanager.gif"] = im(5, 97);ism["snakeboss2.gif"] = im(5, 94);ism["hunter15.gif"] = im(0, 92);ism["fudgewizard.gif"] = im(0, 99);ism["bunionghost.gif"] = im(4, 92);ism["thegunk.gif"] = im(3, 95);ism["hermit.gif"] = im(30, 30, 29, 30);ism["landscaper.gif"] = im(0, 99);ism["snitch.gif"] = im(150, 300, 13, 275);ism["adv_hot4.gif"] = im(10, 97);ism["theluter.gif"] = im(11, 93);ism["theman.gif"] = im(0, 94);ism["darkmariachi.gif"] = im(2, 97);ism["masterat.gif"] = im(40, 97);ism["adv_smart4.gif"] = im(13, 97);ism["thenuge.gif"] = im(4, 94);ism["rainking.gif"] = im(250, 300, 10, 287);ism["sagittarian.gif"] = im(3, 95);ism["theserver.gif"] = im(0, 97);ism["sierpinski.gif"] = im(0, 89);ism["snakeboss3.gif"] = im(150, 150, 5, 136);ism["timebandit.gif"] = im(9, 88);ism["thepinch.gif"] = im(100, 150, 4, 147);ism["thething.gif"] = im(250, 200, 3, 195);ism["thethorax.gif"] = im(200, 100, 4, 92);ism["c10tropes.gif"] = im(0, 99);ism["ukskeleton.gif"] = im(200, 200, 15, 187);ism["ukskeleton_hm.gif"] = im(200, 200, 2, 195);ism["unknownghost.gif"] = im(0, 99);ism["c10cooler.gif"] = im(0, 98);ism["wholekingdom.gif"] = im(200, 200, 2, 195);ism["they.gif"] = im(0, 99);ism["tnbot1.gif"] = im(1, 95);ism["bigskeleton3.gif"] = im(150, 100, 0, 99);ism["thug1thug2.gif"] = im(200, 100, 1, 93);ism["anger2.gif"] = im(0, 99);ism["tigerlily.gif"] = im(1, 96);ism["spelunktiki.gif"] = im(1, 93);ism["mc_tofu2.gif"] = im(2, 97);ism["mc_tofu1.gif"] = im(2, 95);ism["gourd_can.gif"] = im(14, 90);ism["gourd_canspider.gif"] = im(150, 100, 9, 87);ism["mimic1.gif"] = im(17, 83);ism["animelf1.gif"] = im(19, 79);ism["tipsypirate.gif"] = im(0, 98);ism["tpgeist.gif"] = im(0, 97);ism["shiv_tp.gif"] = im(6, 94);ism["tombasp.gif"] = im(0, 99);ism["mummybat.gif"] = im(34, 60);ism["tombrat.gif"] = im(33, 78);ism["tombratking.gif"] = im(200, 200, 17, 176);ism["tombguy.gif"] = im(0, 98);ism["mastiff.gif"] = im(34, 95);ism["toothpirate.gif"] = im(2, 96);ism["toothskel.gif"] = im(5, 90);ism["topiarychi.gif"] = im(2, 95);ism["topiaryduck.gif"] = im(10, 89);ism["topiary.gif"] = im(0, 98);ism["topiarygopher.gif"] = im(7, 93);ism["topiarykiwi.gif"] = im(17, 92);ism["tree_baobab.gif"] = im(3, 96);ism["c10tmz.gif"] = im(0, 99);ism["orquette3.gif"] = im(6, 92);ism["vib4.gif"] = im(2, 96);ism["toxbeast1.gif"] = im(2, 98);ism["animelf5.gif"] = im(18, 76);ism["crimonster1.gif"] = im(1, 98);ism["travoltron.gif"] = im(200, 200, 4, 197);ism["treadmill.gif"] = im(9, 91);ism["bb_chef.gif"] = im(5, 92);ism["triadwizard.gif"] = im(1, 96);ism["tribalgoblin.gif"] = im(11, 89);ism["trixiepixie.gif"] = im(6, 99);ism["triffid.gif"] = im(2, 96);ism["tarkinhead.gif"] = im(0, 98);ism["monahead.gif"] = im(0, 99);ism["twins_troll.gif"] = im(0, 98);ism["trollipop.gif"] = im(100, 150, 5, 145);ism["trophyfish.gif"] = im(0, 98);ism["tsnake.gif"] = im(5, 94);ism["tumbleweed.gif"] = im(4, 93);ism["turtlemech.gif"] = im(14, 89);ism["turtletrapper.gif"] = im(1, 95);ism["twigberry.gif"] = im(3, 89);ism["bigskeleton2.gif"] = im(0, 99);ism["tex.gif"] = im(0, 98);ism["unclehobo.gif"] = im(10, 92);ism["macaroni.gif"] = im(4, 84);ism["pengundercover.gif"] = im(2, 98);ism["shiv_underworld.gif"] = im(200, 200, 17, 170);ism["ellsburyboss.gif"] = im(150, 150, 15, 124);ism["lensgoblin.gif"] = im(3, 94);ism["surv_unhinged.gif"] = im(6, 95);ism["unholydiver.gif"] = im(0, 99);ism["surv_unlikely.gif"] = im(7, 89);ism["c10database.gif"] = im(2, 95);ism["unstill.gif"] = im(8, 92);ism["ram.gif"] = im(13, 85);ism["urchin.gif"] = im(10, 90);ism["eyesdown.gif"] = im(45, 62);ism["usher.gif"] = im(11, 88);ism["spelunkvampire.gif"] = im(13, 85);ism["vampclam.gif"] = im(11, 91);ism["duckvampire.gif"] = im(3, 95);ism["vandalkid.gif"] = im(9, 91);ism["cvcreature.gif"] = im(100, 200, 4, 196);ism["gremlinveg.gif"] = im(5, 93);ism["velvetug.gif"] = im(19, 91);ism["vendorslime.gif"] = im(0, 95);ism["turtleghost.gif"] = im(23, 84);ism["mantrap.gif"] = im(4, 97);ism["easel.gif"] = im(5, 95);ism["gnauga.gif"] = im(14, 92);ism["victor.gif"] = im(15, 88);ism["qmark.gif"] = im(4, 93);ism["gar.gif"] = im(6, 93);ism["prim_fung.gif"] = im(0, 98);ism["music.gif"] = im(2, 95);ism["iceguy4.gif"] = im(7, 98);ism["smallartist.gif"] = im(40, 97);ism["wimp.gif"] = im(15, 90);ism["wackypirate.gif"] = im(1, 97);ism["iceguy3.gif"] = im(1, 98);ism["mush_shrieking.gif"] = im(1, 93);ism["waiterninja.gif"] = im(5, 95);ism["wallofbones.gif"] = im(250, 150, 3, 138);ism["wallofskin.gif"] = im(250, 125, 1, 115);ism["warfratc.gif"] = im(1, 95);ism["warfrata2.gif"] = im(1, 96);ism["warfratb.gif"] = im(0, 95);ism["warfratc2.gif"] = im(1, 95);ism["warfratb2.gif"] = im(0, 95);ism["warfratsp2.gif"] = im(0, 97);ism["warfratgr.gif"] = im(5, 96);ism["warfratar.gif"] = im(5, 89);ism["warfratmo.gif"] = im(24, 89);ism["warfratgr2.gif"] = im(2, 91);ism["streaker.gif"] = im(3, 95);ism["warfratsp.gif"] = im(3, 98);ism["warhipb.gif"] = im(6, 96);ism["warhipac2.gif"] = im(1, 96);ism["warhipar.gif"] = im(0, 99);ism["warhipds.gif"] = im(8, 93);ism["warhipsh2.gif"] = im(0, 98);ism["warhipfs2.gif"] = im(3, 95);ism["warhipc2.gif"] = im(5, 94);ism["warhipa2.gif"] = im(0, 98);ism["warhipfs.gif"] = im(2, 94);ism["warhipb2.gif"] = im(6, 96);ism["warhipmd.gif"] = im(0, 90);ism["warhipa.gif"] = im(0, 98);ism["warhipmd2.gif"] = im(0, 91);ism["warhipc.gif"] = im(5, 92);ism["warhipsh.gif"] = im(1, 97);ism["warhipac.gif"] = im(5, 96);ism["hippyspy.gif"] = im(8, 89);ism["warhipcm.gif"] = im(2, 94);ism["warbear11.gif"] = im(2, 97);ism["warbear21.gif"] = im(0, 99);ism["nightstand1.gif"] = im(4, 96);ism["warehouseclerk.gif"] = im(2, 95);ism["warehouseguard.gif"] = im(0, 98);ism["warehousejanitor.gif"] = im(3, 92);ism["warehouseguy.gif"] = im(3, 94);ism["wartdinsey.gif"] = im(150, 150, 0, 148);ism["wartpirate.gif"] = im(2, 92);ism["werewolf.gif"] = im(4, 98);ism["wigwasp.gif"] = im(8, 93);ism["wastoid.gif"] = im(8, 93);ism["waterspider.gif"] = im(23, 80);ism["waterseal.gif"] = im(0, 99);ism["richpirate.gif"] = im(3, 93);ism["weatherug.gif"] = im(3, 91);ism["weremoose.gif"] = im(2, 90);ism["weretaco.gif"] = im(29, 82);ism["hunter14.gif"] = im(4, 95);ism["wetseal.gif"] = im(6, 80); -ism["aboo_who.gif"] = im(2, 97);ism["tree_willow.gif"] = im(2, 95);ism["surv_whiny.gif"] = im(3, 91);ism["pa_whisk.gif"] = im(4, 91);ism["whitebonedemon.gif"] = im(200, 100, 12, 98);ism["chocgolem.gif"] = im(9, 92);ism["whiteelephant.gif"] = im(11, 88);ism["lion.gif"] = im(6, 93);ism["zombie2.gif"] = im(5, 94);ism["whitesnake.gif"] = im(10, 87);ism["wildgirl.gif"] = im(0, 97);ism["seahorse.gif"] = im(4, 96);ism["wiresculpture.gif"] = im(0, 97);ism["elf_wires.gif"] = im(12, 89);ism["mush_wizard.gif"] = im(0, 99);ism["tree_magnolia.gif"] = im(1, 99);ism["wraith4.gif"] = im(14, 81);ism["doubt1.gif"] = im(0, 98);ism["ravendesk.gif"] = im(0, 94);ism["susguy.gif"] = im(1, 96);ism["wumpus.gif"] = im(0, 99);ism["beergolem.gif"] = im(4, 97);ism["stonegolem.gif"] = im(3, 97);ism["dimhorror.gif"] = im(2, 96);ism["shopteacher.gif"] = im(1, 98);ism["hydra.gif"] = im(6, 99);ism["polprisoner.gif"] = im(9, 89);ism["pr0n.gif"] = im(11, 87);ism["yakisoba.gif"] = im(0, 97);ism["yakcourier.gif"] = im(3, 96);ism["yakguard.gif"] = im(3, 96);ism["yeastbeast.gif"] = im(4, 93);ism["spelunkyeti.gif"] = im(1, 97);ism["yog-urt.gif"] = im(300, 300, 107, 290);ism["yomama.gif"] = im(300, 300, 3, 289);ism["c10inbox.gif"] = im(9, 94);ism["otherimages/shadows/20.gif"] = im(30, 30, 29, 30);ism["zrex.gif"] = im(150, 100, 0, 99);ism["zimmerman.gif"] = im(4, 98);ism["zombie.gif"] = im(3, 84);ism["zol.gif"] = im(11, 90);ism["zomlizard.gif"] = im(4, 94);ism["zmobaby.gif"] = im(2, 86);ism["zombiechef.gif"] = im(1, 97);ism["zomclown.gif"] = im(3, 97);ism["duckzombie.gif"] = im(1, 96);ism["zomsnow.gif"] = im(7, 91);ism["zomfrat.gif"] = im(12, 84);ism["zomknoll.gif"] = im(10, 87);ism["zomgoth.gif"] = im(0, 94);ism["zomhippy.gif"] = im(4, 92);ism["zombiehoa.gif"] = im(150, 150, 1, 148);ism["zombiehoa_hm.gif"] = im(200, 200, 0, 199);ism["zomchef.gif"] = im(1, 92);ism["zomnoob.gif"] = im(4, 93);ism["zomhealer.gif"] = im(1, 93);ism["zomwaltz.gif"] = im(0, 97);ism["zomyeast.gif"] = im(9, 98);ism["hunter1.gif"] = im(3, 96);ism["zombo.gif"] = im(0, 98); - - - - foreach s, v in ysm - { - __minimum_y_of_image_url["images/adventureimages/" + s] = v; - } - foreach s, v in ism - { - __server_image_stats["images/adventureimages/" + s] = v; - } - } - initialiseMinimumBoundingBoxOfImageURL(); -} - -ServerImageStats ServerImageStatsOfImageURL(string url) -{ - if (__server_image_stats contains url) - { - return __server_image_stats[url]; - } - return ServerImageStatsMake(); -} - -int KOLImageMinimumYOfImageURL(string url) -{ - if (__server_image_stats contains url) - { - return __server_image_stats[url].minimum_y_coordinate; - } - return 0; -} diff --git a/Source/relay/TourGuide/Support/Library 2.ash b/Source/relay/TourGuide/Support/Library 2.ash deleted file mode 100644 index a7d5e584..00000000 --- a/Source/relay/TourGuide/Support/Library 2.ash +++ /dev/null @@ -1,398 +0,0 @@ -import "relay/TourGuide/Support/LocationAvailable.ash" -import "relay/TourGuide/Support/Equipment Requirement.ash" -import "relay/TourGuide/Support/HTML.ash" -import "relay/TourGuide/Support/Statics 2.ash" -import "relay/TourGuide/Support/Ingredients.ash" -import "relay/TourGuide/Support/Counter.ash" - - - -string HTMLGenerateFutureTextByLocationAvailability(string base_text, location place) -{ - if (!place.locationAvailable() && place != $location[none]) - { - base_text = HTMLGenerateSpanOfClass(base_text, "r_future_option"); - } - return base_text; -} - -string HTMLGenerateFutureTextByLocationAvailability(location place) -{ - return HTMLGenerateFutureTextByLocationAvailability(place.to_string(), place); -} - -//Alternate name, since last time I tried making this function then discovered the "generate future text" options which I cleverly named in such a way that I would never find it -string HTMLGreyOutIfLocationUnavailable(string source, location l) -{ - return HTMLGenerateFutureTextByLocationAvailability(source, l); -} -string HTMLBoldIfTrue(string base_text, boolean conditional) -{ - if (conditional) - return HTMLGenerateSpanOfClass(base_text, "r_bold"); - return base_text; -} - - -boolean can_equip_replacement(item it) -{ - if (it.equipped_amount() > 0) - return true; - if (it.item_type() == "chefstaff" && !($skill[Spirit of Rigatoni].have_skill() || my_class() == $class[Avatar of Jarlsberg] || (my_class() == $class[sauceror] && $item[special sauce glove].equipped_amount() > 0))) - return false; - boolean can_equip = it.can_equip(); - if (can_equip) - return true; - if (my_class() == $class[pastamancer]) - { - //Bind Undead Elbow Macaroni -> equalises muscle - //Bind Penne Dreadful -> equalises moxie - EquipmentStatRequirement requirement = it.StatRequirementForEquipment(); - - if (requirement.requirement_stat == $stat[none]) - return true; - if (my_basestat(requirement.requirement_stat) >= requirement.requirement_amount) - return true; - if (requirement.requirement_stat == $stat[mysticality]) - return false; - - if (requirement.requirement_stat == $stat[muscle]) - { - if ($skill[bind undead elbow macaroni].have_skill() && my_basestat($stat[mysticality]) >= requirement.requirement_amount) - return true; - } - else if (requirement.requirement_stat == $stat[moxie]) - { - if ($skill[Bind Penne Dreadful].have_skill() && my_basestat($stat[mysticality]) >= requirement.requirement_amount) - return true; - } - } - return can_equip; -} - -boolean can_equip_outfit(string outfit_name) -{ - if (!have_outfit_components(outfit_name)) - return false; - item [int] outfit_pieces = outfit_pieces(outfit_name); - foreach key, it in outfit_pieces - { - if (!it.can_equip_replacement()) - return false; - } - return true; -} - - -//Probably not a good place for it: -boolean asdonMartinFailsFuelableTestsPrivate(item craft, boolean [item] ingredients_blacklisted, boolean [item] crafts_seen) -{ - //if ($items[wad of dough,flat dough] contains craft) return false; - if (craft.craft_type().contains_text("(fancy)")) - return true; - crafts_seen[craft] = true; - boolean all_npc = true; - foreach it, amount in craft.get_ingredients_fast() - { - //print_html(craft + ": " + it); - if (ingredients_blacklisted[it]) return true; - if (!it.is_npc_item()) - all_npc = false; - - if (it.item_amount() >= amount) continue; - if (crafts_seen[it]) //wad of dough, flat dough, jolly roger charrrm - { - continue; - } - if (it.asdonMartinFailsFuelableTestsPrivate(ingredients_blacklisted, crafts_seen)) - return true; - } - if (craft.get_ingredients_fast().count() == 0) - all_npc = false; - if (all_npc && crafts_seen.count() == 0) //hmm... what if it's a second level all-NPC? - { - return true; - } - return false; -} - -boolean asdonMartinFailsFuelableTests(item craft, boolean [item] ingredients_blacklisted) -{ - boolean [item] crafts_seen; //slower than a "last item" test, but necessary (spooky wads) - return asdonMartinFailsFuelableTestsPrivate(craft, ingredients_blacklisted, crafts_seen); -} - -item [int] asdonMartinGenerateListOfFuelables() -{ - item [int] fuelables; - boolean [item] blacklist; - if (!QuestState("questL11Black").finished) //FIXME no - blacklist[$item[blackberry]] = true; //FIXME test properly? - blacklist[$item[stunt nuts]] = true; - blacklist[$item[wet stew]] = true; //FIXME I guess maybe not after - blacklist[$item[goat cheese]] = true; - blacklist[$item[turkey blaster]] = true; - blacklist[$item[hot wing]] = true; - blacklist[$item[glass of goat's milk]] = true; - blacklist[$item[soft green echo eyedrop antidote martini]] = true; //if it's not created, FIXME - blacklist[$item[warm gravy]] = true; //don't steal my boat - foreach it in $items[Falcon™ Maltese Liquor, hardboiled egg] - blacklist[it] = true; //don't steal my -combat - blacklist[$item[loaf of soda bread]] = true; //elsewhere - foreach it in $items[hot buttered roll,ketchup,catsup] - blacklist[it] = true; //hermit - - //These aren't directly feedable, but indirectly make things: - blacklist[$item[source essence]] = true; //that's silly - blacklist[$item[white pixel]] = true; //no! - blacklist[$item[cashew]] = true; - - if (my_path().id != PATH_LICENSE_TO_ADVENTURE && inebriety_limit() > 0) //FIXME the test for can drink just about - { - foreach it in $items[bottle of gin,bottle of rum,bottle of vodka,bottle of whiskey,bottle of tequila] //too useful for crafting? - blacklist[it] = true; - } - foreach it in $items[bottle of Calcutta Emerald,bottle of Lieutenant Freeman,bottle of Jorge Sinsonte,bottle of Definit,bottle of Domesticated Turkey,boxed champagne,bottle of Ooze-O,bottle of Pete's Sake,tangerine,kiwi,cocktail onion,kumquat,tonic water,raspberry] //nash crosby's still's results isn't feedable - blacklist[it] = true; - foreach it in __pvpable_food_and_drinks - { - if (blacklist[it]) continue; - if (it.is_npc_item()) continue; - if (it.historical_price() >= 20000) continue; - if (it.item_amount() == 0) - { - if (it.creatable_amount() == 0) - continue; - if (it.asdonMartinFailsFuelableTests(blacklist)) - { - continue; - } - } - if (my_path().id == PATH_LICENSE_TO_ADVENTURE && false) - { - if (it.inebriety > 0 && it.image == "martini.gif") - continue; - } - if (it.item_cannot_be_asdon_martined_because_it_was_purchased_from_a_store()) //the asdon martin wishes it was an AE86, so those work - { - //print_html("Rejecting " + it); - continue; - } - /*int [item] ingredients = it.get_ingredients_fast(); - if (ingredients.count() > 0) - { - boolean reject = false; - //Various things count as being from a "store": - foreach it in lookupItems("yellow pixel,handful of barley,spacegate research") - { - if (ingredients[it] > 0) - { - reject = true; - break; - } - } - if (reject) - continue; - }*/ - float average_adventures = it.averageAdventuresForConsumable(); - if (average_adventures == 0.0) - continue; - - float soda_bread_efficiency = to_float($item[wad of dough].npc_price() + $item[soda water].npc_price()) / 6.0; - if (soda_bread_efficiency < 1.0) soda_bread_efficiency = 100000.0; - if (it.autosell_price() > 0 && it.autosell_price().to_float() / average_adventures > soda_bread_efficiency) - { - continue; - } - fuelables.listAppend(it); - } - sort fuelables by -value.averageAdventuresForConsumable() * ((value.asdonMartinFailsFuelableTests(blacklist) ? 0 : value.creatable_amount()) + value.item_amount()); - return fuelables; -} - - - - -boolean craftableUsingOnlyActiveNPCStoresPrivate(item it, boolean [item] crafts_seen) -{ - if (it.npc_price() > 0) - return true; - - int [item] ingredients = it.get_ingredients_fast(); - if (ingredients.count() == 0) return false; - - if (crafts_seen[it]) - return true; - - crafts_seen[it] = true; - - foreach ingredient in ingredients - { - if (!craftableUsingOnlyActiveNPCStoresPrivate(ingredient, crafts_seen)) - { - return false; - } - } - return true; -} - -boolean craftableUsingOnlyActiveNPCStores(item it) -{ - boolean [item] crafts_seen; - return craftableUsingOnlyActiveNPCStoresPrivate(it, crafts_seen); -} - - -int CatBurglarChargesLeftToday() -{ - //FIXME this is totally wrong I think, fix this mafia - int charge = get_property_int("_catBurglarCharge"); - - int heists_gained_today = 0; - int limit = 10; - int c = charge; - while (c >= limit) - { - heists_gained_today += 1; - c -= limit; - limit *= 2; - } - int heists_complete = get_property_int("_catBurglarHeistsComplete"); - //print_html("heists_gained_today = " + heists_gained_today + ", heists_complete = " + heists_complete); - return get_property_int("catBurglarBankHeists") + heists_gained_today - heists_complete; -} - - -int PathCommunityServiceEstimateTurnsTakenForTask(string service_name) -{ - int turns = 60; - if (service_name == "Donate Blood") - { - turns = 60 - (my_maxhp() - (my_buffedstat($stat[muscle]) + 3)) / 30; - } - else if (service_name == "Coil Wire") - { - turns = 60; - } - else if (service_name == "Make Margaritas") - { - float item_drop = numeric_modifier("Item Drop"); - //Mafia adds item drop modifiers depending on our location. - //set_location() is slow, we want to avoid it. - //Manually correct: - if ($skill[Speluck].have_skill() && my_location().environment == "underground") - { - item_drop -= 5.0; - if ($effect[Steely-Eyed Squint].have_effect() > 0) - item_drop -= 5.0; - } - turns = 60 - (floor(item_drop / 30) + floor(numeric_modifier("Booze Drop") / 15)); - } - else if (service_name == "Feed The Children (But Not Too Much)" || service_name == "Build Playground Mazes" || service_name == "Feed Conspirators") - { - stat using_stat; - if (service_name == "Feed The Children (But Not Too Much)") - { - using_stat = $stat[muscle]; - } - else if (service_name == "Build Playground Mazes") - { - using_stat = $stat[mysticality]; - } - else if (service_name == "Feed Conspirators") - { - using_stat = $stat[moxie]; - } - int basestat = my_basestat(using_stat); - boolean relevant_thrall_active = false; - if (my_thrall() == $thrall[Elbow Macaroni] && using_stat == $stat[muscle]) - { - basestat = my_basestat($stat[mysticality]); - relevant_thrall_active = true; - } - if (my_thrall() == $thrall[Penne Dreadful] && using_stat == $stat[moxie]) - { - basestat = my_basestat($stat[mysticality]); - relevant_thrall_active = true; - } - - turns = 60 - (my_buffedstat(using_stat) - basestat) / 30; - } - else if (service_name == "Reduce Gazelle Population") - { - float modifier_1 = numeric_modifier("Weapon Damage"); - float modifier_2 = numeric_modifier("Weapon Damage Percent"); - - foreach s in $slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3,familiar] - { - item it = s.equipped_item(); - if (it.to_slot() != $slot[weapon]) continue; - int power = it.get_power(); - float addition = to_float(power) * 0.15; - - modifier_1 -= addition; - } - if ($effect[bow-legged swagger].have_effect() > 0) - { - modifier_1 *= 2; - modifier_2 *= 2; - } - turns = 60 - (floor(modifier_1 / 50 + 0.001) + floor(modifier_2 / 50 + 0.001)); - } - else if (service_name == "Make Sausage") - { - turns = 60 - (floor(numeric_modifier("Spell Damage") / 50 + 0.001) + floor(numeric_modifier("Spell Damage Percent") / 50 + 0.001)); - } - else if (service_name == "Clean Steam Tunnels") - { - turns = 60 - round(numeric_modifier("Hot Resistance")); - } - else if (service_name == "Breed More Collies") - { - int current_familiar_weight = my_familiar().effective_familiar_weight() + round(numeric_modifier("familiar weight")); - turns = 60 - floor(current_familiar_weight / 5); - } - else if (service_name == "Be a Living Statue") - { - int combat_rate_raw = round(numeric_modifier("Combat Rate")); - int combat_rate_inverse = 0; - if (combat_rate_raw < 0) combat_rate_inverse = -combat_rate_raw; - if (combat_rate_inverse > 25) combat_rate_inverse = (combat_rate_inverse - 25) * 5 + 25; - turns = 60 - (combat_rate_inverse / 5) * 3; - } - - turns = clampi(turns, 1, 60); - - return turns; -} - - - -Record KramcoSausageFightInformation -{ - boolean goblin_will_appear; - int turns_to_next_guaranteed_fight; - float probability_of_sausage_fight; -}; - -KramcoSausageFightInformation KramcoCalculateSausageFightInformation() { - KramcoSausageFightInformation information; - int goblinsFought = get_property_int("_sausageFights"); - int turnsSinceLastGoblin = total_turns_played() - get_property_int("_lastSausageMonsterTurn"); - - int nextGuaranteedGoblin = 4 + goblinsFought * 3 + MAX(0, goblinsFought - 5) * MAX(0, goblinsFought - 5) * MAX(0, goblinsFought - 5); - int turnsToNextGuaranteedFight = MAX(0, nextGuaranteedGoblin - turnsSinceLastGoblin); - - if (goblinsFought == 0) { - turnsToNextGuaranteedFight = 0; - } - - int goblinMultiplier = MAX(0, goblinsFought - 5); - float probabilityOfFight = to_float(turnsSinceLastGoblin + 1) / (5.0 + to_float(goblinsFought) * 3.0 + to_float(goblinMultiplier) * to_float(goblinMultiplier) * to_float(goblinMultiplier)); - - information.turns_to_next_guaranteed_fight = MAX(0, nextGuaranteedGoblin - turnsSinceLastGoblin); - information.probability_of_sausage_fight = clampf(probabilityOfFight, 0.0, 1.0); - information.goblin_will_appear = (turnsToNextGuaranteedFight == 0); - - return information; -} diff --git a/Source/relay/TourGuide/Support/Library.ash b/Source/relay/TourGuide/Support/Library.ash deleted file mode 100644 index 4cc94f55..00000000 --- a/Source/relay/TourGuide/Support/Library.ash +++ /dev/null @@ -1,1721 +0,0 @@ -import "relay/TourGuide/Support/Math.ash" -import "relay/TourGuide/Support/List.ash" -import "relay/TourGuide/Support/Strings.ash" -import "relay/TourGuide/Support/Statics.ash" - -boolean mafiaIsPastRevision(int revision_number) -{ - if (get_revision() <= 0) //get_revision reports zero in certain cases; assume they're on a recent version - return true; - return (get_revision() >= revision_number); -} - - -boolean have_familiar_replacement(familiar f) -{ - //have_familiar bugs in avatar of sneaky pete for now, so: - if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) - return false; - return f.have_familiar(); -} - -//Similar to have_familiar, except it also checks trendy (not sure if have_familiar supports trendy) and 100% familiar runs -boolean familiar_is_usable(familiar f) -{ - //r13998 has most of these - if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING || my_path().id == PATH_LICENSE_TO_ADVENTURE || my_path().id == PATH_POCKET_FAMILIARS || my_path().id == PATH_VAMPIRE) - return false; - if (my_path().id == PATH_ZOMBIE_SLAYER && !f.attributes.contains_text("undead")) - return false; - if (!is_unrestricted(f)) - return false; - if (my_path().id == PATH_G_LOVER && !f.contains_text("g") && !f.contains_text("G")) - return false; - //On second thought, this is terrible: - /*int single_familiar_run = get_property_int("singleFamiliarRun"); - if (single_familiar_run != -1 && my_turncount() >= 30) //after 30 turns, they're probably sure - { - if (f == single_familiar_run.to_familiar()) - return true; - return false; - }*/ - if (my_path().id == PATH_TRENDY) - { - if (!is_trendy(f)) - return false; - } - else if (my_path().id == PATH_BEES_HATE_YOU) - { - if (f.to_string().contains_text("b") || f.to_string().contains_text("B")) //bzzzz! - return false; //so not green - } - return have_familiar(f); -} - -//inigo's used to show up as have_skill while under restrictions, possibly others -boolean skill_is_usable(skill s) -{ - if (!s.have_skill()) - return false; - if (!s.is_unrestricted()) - return false; - if (my_path().id == PATH_G_LOVER && (!s.passive || s == $skill[meteor lore]) && !s.contains_text("g") && !s.contains_text("G")) - return false; - if ($skills[rapid prototyping] contains s) - return $item[hand turkey outline].is_unrestricted(); - return true; -} - -boolean a_skill_is_usable(boolean [skill] skills) -{ - foreach s in skills - { - if (s.skill_is_usable()) return true; - } - return false; -} - -boolean skill_is_currently_castable(skill s) -{ - //FIXME accordion thief songs, MP, a lot of things - if (s == $skill[Utensil Twist] && $slot[weapon].equipped_item().item_type() != "utensil") - { - return false; - } - return true; -} - -boolean item_is_usable(item it) -{ - if (!it.is_unrestricted()) - return false; - if (my_path().id == PATH_G_LOVER && !it.contains_text("g") && !it.contains_text("G")) - return false; - if (my_path().id == PATH_BEES_HATE_YOU && (it.contains_text("b") || it.contains_text("B"))) - return false; - return true; -} - -//available_amount() except it tests against item_is_usable() -int usable_amount(item it) -{ - if (!it.item_is_usable()) return 0; - return it.available_amount(); -} - -boolean effect_is_usable(effect e) -{ - if (my_path().id == PATH_G_LOVER && !e.contains_text("g") && !e.contains_text("G")) - return false; - return true; -} - -boolean in_ronin() -{ - return !can_interact(); -} - - -boolean [item] makeConstantItemArrayMutable(boolean [item] array) -{ - boolean [item] result; - foreach k in array - result[k] = array[k]; - - return result; -} - -boolean [location] makeConstantLocationArrayMutable(boolean [location] locations) -{ - boolean [location] result; - foreach k in locations - result[k] = locations[k]; - - return result; -} - -boolean [skill] makeConstantSkillArrayMutable(boolean [skill] array) -{ - boolean [skill] result; - foreach k in array - result[k] = array[k]; - - return result; -} - -boolean [effect] makeConstantEffectArrayMutable(boolean [effect] array) -{ - boolean [effect] result; - foreach k in array - result[k] = array[k]; - - return result; -} - -//Same as my_primestat(), except refers to substat -stat my_primesubstat() -{ - if (my_primestat() == $stat[muscle]) - return $stat[submuscle]; - else if (my_primestat() == $stat[mysticality]) - return $stat[submysticality]; - else if (my_primestat() == $stat[moxie]) - return $stat[submoxie]; - return $stat[none]; -} - -item [int] items_missing(boolean [item] items) -{ - item [int] result; - foreach it in items - { - if (it.available_amount() == 0) - result.listAppend(it); - } - return result; -} - -skill [int] skills_missing(boolean [skill] skills) -{ - skill [int] result; - foreach s in skills - { - if (!s.have_skill()) - result.listAppend(s); - } - return result; -} - -int storage_amount(boolean [item] items) -{ - int count = 0; - foreach it in items - { - count += it.storage_amount(); - } - return count; -} - -int closet_amount(boolean [item] items) -{ - int count = 0; - foreach it in items - { - count += it.closet_amount(); - } - return count; -} - -int display_amount(boolean [item] items) -{ - int count = 0; - foreach it in items - { - count += it.display_amount(); - } - return count; -} - -int stash_amount(boolean [item] items) -{ - int count = 0; - foreach it in items - { - count += it.stash_amount(); - } - return count; -} - -int available_amount(boolean [item] items) -{ - //Usage: - //$items[disco ball, corrupted stardust].available_amount() - //Returns the total number of all items. - int count = 0; - foreach it in items - { - count += it.available_amount(); - } - return count; -} - -int creatable_amount(boolean [item] items) -{ - //Usage: - //$items[disco ball, corrupted stardust].available_amount() - //Returns the total number of all items. - int count = 0; - foreach it in items - { - count += it.creatable_amount(); - } - return count; -} - -int item_amount(boolean [item] items) -{ - int count = 0; - foreach it in items - { - count += it.item_amount(); - } - return count; -} - -int have_effect(boolean [effect] effects) -{ - int count = 0; - foreach e in effects - count += e.have_effect(); - return count; -} - -int available_amount(item [int] items) -{ - int count = 0; - foreach key in items - { - count += items[key].available_amount(); - } - return count; -} - -int available_amount_ignoring_storage(item it) -{ - if (!in_ronin()) - return it.available_amount() - it.storage_amount(); - else - return it.available_amount(); -} - -int available_amount_ignoring_closet(item it) -{ - if (get_property_boolean("autoSatisfyWithCloset")) - return it.available_amount() - it.closet_amount(); - else - return it.available_amount(); -} - -int available_amount_including_closet(item it) -{ - if (get_property_boolean("autoSatisfyWithCloset")) - return it.available_amount(); - else - return it.available_amount() + it.closet_amount(); -} - -//Display case, etc -//WARNING: Does not take into account your shop. Conceptually, the shop is things you're getting rid of... and they might be gone already. -int item_amount_almost_everywhere(item it) -{ - return it.closet_amount() + it.display_amount() + it.equipped_amount() + it.item_amount() + it.storage_amount(); -} - -//Similar to item_amount_almost_everywhere, but won't trigger a display case load unless it has to: -boolean haveAtLeastXOfItemEverywhere(item it, int amount) -{ - int total = 0; - total += it.item_amount(); - if (total >= amount) return true; - total += it.equipped_amount(); - if (total >= amount) return true; - total += it.closet_amount(); - if (total >= amount) return true; - total += it.storage_amount(); - if (total >= amount) return true; - total += it.display_amount(); - if (total >= amount) return true; - - return false; -} - -int equipped_amount(boolean [item] items) -{ - int count = 0; - foreach it in items - { - count += it.equipped_amount(); - } - return count; -} - -int [item] creatable_items(boolean [item] items) -{ - int [item] creatable_items; - foreach it in items - { - if (it.creatable_amount() == 0) - continue; - creatable_items[it] = it.creatable_amount(); - } - return creatable_items; -} - - -item [slot] equipped_items() -{ - item [slot] result; - foreach s in $slots[] - { - item it = s.equipped_item(); - if (it == $item[none]) - continue; - result[s] = it; - } - return result; -} - -//Have at least one of these familiars: -boolean have_familiar_replacement(boolean [familiar] familiars) -{ - foreach f in familiars - { - if (f.have_familiar()) - return true; - } - return false; -} - -item [int] missing_outfit_components(string outfit_name) -{ - item [int] outfit_pieces = outfit_pieces(outfit_name); - item [int] missing_components; - foreach key in outfit_pieces - { - item it = outfit_pieces[key]; - if (it.available_amount() == 0) - missing_components.listAppend(it); - } - return missing_components; -} - - -//have_outfit() will tell you if you have an outfit, but only if you pass stat checks. This does not stat check: -boolean have_outfit_components(string outfit_name) -{ - return (outfit_name.missing_outfit_components().count() == 0); -} - -//Non-API-related functions: - -boolean playerIsLoggedIn() -{ - return !(my_hash().length() == 0 || my_id() == 0) || __setting_debug_mode; -} - -int substatsForLevel(int level) -{ - if (level == 1) - return 0; - return pow2i(pow2i(level - 1) + 4); -} - -int availableFullness() -{ - int limit = fullness_limit(); - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING && limit == 0 && $skill[Replacement Stomach].have_skill()) - { - limit += 5; - } - return limit - my_fullness(); -} - -int availableDrunkenness() -{ - int limit = inebriety_limit(); - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING && limit == 0 && $skill[Replacement Liver].have_skill()) - { - limit += 5; - } - if (limit == 0) return 0; //certain edge cases - return limit - my_inebriety(); -} - -int availableSpleen() -{ - int limit = spleen_limit(); - if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING && limit == 0) - { - limit += 5; //always true - //mafia resets the limits to zero in the underworld because it does, so anti-mafia: - foreach s in $skills[Extra Spleen,Another Extra Spleen,Yet Another Extra Spleen,Still Another Extra Spleen,Just One More Extra Spleen,Okay Seriously\, This is the Last Spleen] - { - if (s.have_skill()) - limit += 5; - } - } - return limit - my_spleen_use(); -} - -item [int] missingComponentsToMakeItemPrivateImplementation(item it, int it_amounted_needed, int recursion_limit_remaining) -{ - item [int] result; - if (recursion_limit_remaining <= 0) //possible loop - return result; - if ($items[dense meat stack,meat stack] contains it) return listMake(it); //meat from yesterday + fairy gravy boat? hmm... no - if (it.available_amount() >= it_amounted_needed) - return result; - int [item] ingredients = get_ingredients_fast(it); - if (ingredients.count() == 0) - { - for i from 1 to (it_amounted_needed - it.available_amount()) - result.listAppend(it); - } - foreach ingredient in ingredients - { - int ingredient_amounted_needed = ingredients[ingredient]; - if (ingredient.available_amount() >= ingredient_amounted_needed) //have enough - continue; - //split: - item [int] r = missingComponentsToMakeItemPrivateImplementation(ingredient, ingredient_amounted_needed, recursion_limit_remaining - 1); - if (r.count() > 0) - { - result.listAppendList(r); - } - } - return result; -} - -item [int] missingComponentsToMakeItem(item it, int it_amounted_needed) -{ - return missingComponentsToMakeItemPrivateImplementation(it, it_amounted_needed, 30); -} - - -item [int] missingComponentsToMakeItem(item it) -{ - return missingComponentsToMakeItem(it, 1); -} - -string [int] missingComponentsToMakeItemInHumanReadableFormat(item it) -{ - item [int] parts = missingComponentsToMakeItem(it); - - int [item] parts_inverted; - foreach key, it2 in parts - { - parts_inverted[it2] += 1; - } - string [int] result; - foreach it2, amount in parts_inverted - { - string line = amount; - line += " more "; - if (amount > 1) - line += it2.plural; - else - line += it2.to_string(); - result.listAppend(line); - } - return result; -} - -//For tracking time deltas. Won't accurately compare across day boundaries and isn't monotonic (be wary of negative deltas), but still useful for temporal rate limiting. -int getMillisecondsOfToday() -{ - //To replicate value in GCLI: - //ash (now_to_string("H").to_int() * 60 * 60 * 1000 + now_to_string("m").to_int() * 60 * 1000 + now_to_string("s").to_int() * 1000 + now_to_string("S").to_int()) - return now_to_string("H").to_int_silent() * 60 * 60 * 1000 + now_to_string("m").to_int_silent() * 60 * 1000 + now_to_string("s").to_int_silent() * 1000 + now_to_string("S").to_int_silent(); -} - -//WARNING: Only accurate for up to five turns. -//It also will not work properly in certain areas, and possibly across day boundaries. Actually, it's kind of a hack. -//But now we have turns_spent so no need to worry. -int combatTurnsAttemptedInLocation(location place) -{ - int count = 0; - if (place.combat_queue != "") - count += place.combat_queue.split_string_alternate("; ").count(); - return count; -} - -int noncombatTurnsAttemptedInLocation(location place) -{ - int count = 0; - if (place.noncombat_queue != "") - count += place.noncombat_queue.split_string_alternate("; ").count(); - return count; -} - -int turnsAttemptedInLocation(location place) -{ - return place.turns_spent; -} - -int turnsAttemptedInLocation(boolean [location] places) -{ - int count = 0; - foreach place in places - count += place.turnsAttemptedInLocation(); - return count; -} - -string [int] locationSeenNoncombats(location place) -{ - return place.noncombat_queue.split_string_alternate("; "); -} - -string [int] locationSeenCombats(location place) -{ - return place.combat_queue.split_string_alternate("; "); -} - -string lastNoncombatInLocation(location place) -{ - if (place.noncombat_queue != "") - return place.locationSeenNoncombats().listLastObject(); - return ""; -} - -string lastCombatInLocation(location place) -{ - if (place.noncombat_queue != "") - return place.locationSeenCombats().listLastObject(); - return ""; -} - -static -{ - int [location] __place_delays; - __place_delays[$location[the spooky forest]] = 5; - __place_delays[$location[the haunted bedroom]] = 6; //a guess from spading - __place_delays[$location[the boss bat's lair]] = 4; - __place_delays[$location[the oasis]] = 5; - __place_delays[$location[the hidden park]] = 6; //6? does turkey blaster give four turns sometimes...? - __place_delays[$location[the haunted gallery]] = 5; //FIXME this is a guess, spade - __place_delays[$location[the haunted bathroom]] = 5; - __place_delays[$location[the haunted ballroom]] = 5; //FIXME rumored - __place_delays[$location[the penultimate fantasy airship]] = 25; - __place_delays[$location[the "fun" house]] = 10; - __place_delays[$location[The Castle in the Clouds in the Sky (Ground Floor)]] = 10; - __place_delays[$location[the outskirts of cobb's knob]] = 10; - __place_delays[$location[the hidden apartment building]] = 8; - __place_delays[$location[the hidden office building]] = 10; - __place_delays[$location[the copperhead club]] = 14; - __place_delays[$location[the upper chamber]] = 5; -} - -int totalDelayForLocation(location place) -{ - //the haunted billiards room does not contain delay - //also failure at 16 skill - - if (__place_delays contains place) - return __place_delays[place]; - return -1; -} - -int delayRemainingInLocation(location place) -{ - int delay_for_place = place.totalDelayForLocation(); - - if (delay_for_place == -1) - return -1; - - int turns_attempted = place.turns_spent; - - return MAX(0, delay_for_place - turns_attempted); -} - -int turnsCompletedInLocation(location place) -{ - return place.turnsAttemptedInLocation(); //FIXME make this correct -} - -//Backwards compatibility: -//We want to be able to support new content with daily builds. But, we don't want to ask users to run a daily build. -//So these act as replacements for new content. Unknown lookups are given as $type[none] The goal is to have compatibility with the last major release. -//We use this instead of to_item() conversion functions, so we can easily identify them in the source. -item lookupItem(string name) -{ - return name.to_item(); -} - -boolean [item] lookupItems(string names) //CSV input -{ - boolean [item] result; - string [int] item_names = split_string_alternate(names, ","); - foreach key in item_names - { - item it = item_names[key].to_item(); - if (it == $item[none]) - continue; - result[it] = true; - } - return result; -} - -boolean [item] lookupItemsArray(boolean [string] names) -{ - boolean [item] result; - - foreach item_name in names - { - item it = item_name.to_item(); - if (it == $item[none]) - continue; - result[it] = true; - } - return result; -} - -skill lookupSkill(string name) -{ - return name.to_skill(); -} - -boolean [skill] lookupSkills(string names) //CSV input -{ - boolean [skill] result; - string [int] skill_names = split_string_alternate(names, ","); - foreach key in skill_names - { - skill s = skill_names[key].to_skill(); - if (s == $skill[none]) - continue; - result[s] = true; - } - return result; -} - - -//lookupSkills(string) will be called instead if we keep the same name, so use a different name: -boolean [skill] lookupSkillsInt(boolean [int] skill_ids) -{ - boolean [skill] result; - foreach skill_id in skill_ids - { - skill s = skill_id.to_skill(); - if (s == $skill[none]) - continue; - result[s] = true; - } - return result; -} - -effect lookupEffect(string name) -{ - return name.to_effect(); -} - -familiar lookupFamiliar(string name) -{ - return name.to_familiar(); -} - -location lookupLocation(string name) -{ - return name.to_location(); - /*l = name.to_location(); - if (__setting_debug_mode && l == $location[none]) - print_html("Unable to find location \"" + name + "\""); - return l;*/ -} - -boolean [location] lookupLocations(string names_string) -{ - boolean [location] result; - - string [int] names = names_string.split_string(","); - foreach key, name in names - { - if (name.length() == 0) - continue; - location l = name.to_location(); - if (l != $location[none]) - result[l] = true; - } - - return result; -} - -monster lookupMonster(string name) -{ - return name.to_monster(); -} - -boolean [monster] lookupMonsters(string names_string) -{ - boolean [monster] result; - - string [int] names = names_string.split_string(","); - foreach key, name in names - { - if (name.length() == 0) - continue; - monster m = name.to_monster(); - if (m != $monster[none]) - result[m] = true; - } - - return result; -} - -class lookupClass(string name) -{ - return name.to_class(); -} - -boolean monsterDropsItem(monster m, item it) -{ - //record [int] drops = m.item_drops_array(); - foreach key in m.item_drops_array() - { - if (m.item_drops_array()[key].drop == it) - return true; - } - return false; -} - - -Record StringHandle -{ - string s; -}; - -Record FloatHandle -{ - float f; -}; - - -buffer generateTurnsToSeeNoncombat(int combat_rate, int noncombats_in_zone, string task, int max_turns_between_nc, int extra_starting_turns) -{ - float turn_estimation = -1.0; - float combat_rate_modifier = combat_rate_modifier(); - float noncombat_rate = 1.0 - (combat_rate + combat_rate_modifier).to_float() / 100.0; - - - if (noncombats_in_zone > 0) - { - float minimum_nc_rate = 0.0; - if (max_turns_between_nc != 0) - minimum_nc_rate = 1.0 / max_turns_between_nc.to_float(); - if (noncombat_rate < minimum_nc_rate) - noncombat_rate = minimum_nc_rate; - - if (noncombat_rate > 0.0) - turn_estimation = noncombats_in_zone.to_float() / noncombat_rate; - } - else - turn_estimation = 0.0; - - turn_estimation += extra_starting_turns; - - - buffer result; - - if (turn_estimation == -1.0) - { - result.append("Impossible"); - } - else - { - result.append("~"); - result.append(turn_estimation.roundForOutput(1)); - if (turn_estimation == 1.0) - result.append(" turn"); - else - result.append(" turns"); - } - - if (task != "") - { - result.append(" to "); - result.append(task); - } - else - { - if (turn_estimation == -1.0) - { - } - else if (turn_estimation == 1.0) - result.append(" remains"); - else - result.append(" remain"); - } - if (noncombats_in_zone > 0) - { - result.append(" at "); - result.append(combat_rate_modifier.floor()); - result.append("% combat rate"); - } - result.append("."); - - return result; -} - -buffer generateTurnsToSeeNoncombat(int combat_rate, int noncombats_in_zone, string task, int max_turns_between_nc) -{ - return generateTurnsToSeeNoncombat(combat_rate, noncombats_in_zone, task, max_turns_between_nc, 0); -} - -buffer generateTurnsToSeeNoncombat(int combat_rate, int noncombats_in_zone, string task) -{ - return generateTurnsToSeeNoncombat(combat_rate, noncombats_in_zone, task, 0); -} - - -int damageTakenByElement(int base_damage, float elemental_resistance) -{ - if (base_damage < 0) - return 1; - - float effective_base_damage = MAX(30, base_damage).to_float(); - - return MAX(1, ceil(base_damage.to_float() - effective_base_damage * elemental_resistance)); -} - -int damageTakenByElement(int base_damage, element e) -{ - float elemental_resistance = e.elemental_resistance() / 100.0; - - //mafia might already do this for us already, but I haven't checked: - - if (e == $element[cold] && $effect[coldform].have_effect() > 0) - elemental_resistance = 1.0; - else if (e == $element[hot] && $effect[hotform].have_effect() > 0) - elemental_resistance = 1.0; - else if (e == $element[sleaze] && $effect[sleazeform].have_effect() > 0) - elemental_resistance = 1.0; - else if (e == $element[spooky] && $effect[spookyform].have_effect() > 0) - elemental_resistance = 1.0; - else if (e == $element[stench] && $effect[stenchform].have_effect() > 0) - elemental_resistance = 1.0; - - - return damageTakenByElement(base_damage, elemental_resistance); -} - -boolean locationHasPlant(location l, string plant_name) -{ - string [int] plants_in_place = get_florist_plants()[l]; - foreach key in plants_in_place - { - if (plants_in_place[key] == plant_name) - return true; - } - return false; -} - -float initiative_modifier_ignoring_plants() -{ - //FIXME strange bug here, investigate - //seen in cyrpt - float init = initiative_modifier(); - - location my_location = my_location(); - if (my_location != $location[none] && (my_location.locationHasPlant("Impatiens") || my_location.locationHasPlant("Shuffle Truffle"))) - init -= 25.0; - - return init; -} - -float item_drop_modifier_ignoring_plants() -{ - float item_modifier = item_drop_modifier(); - - location my_location = my_location(); - if (my_location != $location[none]) - { - if (my_location.locationHasPlant("Rutabeggar") || my_location.locationHasPlant("Stealing Magnolia")) - item_modifier -= 25.0; - if (my_location.locationHasPlant("Kelptomaniac")) - item_modifier -= 40.0; - } - return item_modifier; -} - -int monster_level_adjustment_ignoring_plants() //this is unsafe to use in heavy rains -{ - //FIXME strange bug possibly here, investigate - int ml = monster_level_adjustment(); - - location my_location = my_location(); - - if (my_location != $location[none]) - { - string [3] location_plants = get_florist_plants()[my_location]; - foreach key in location_plants - { - string plant = location_plants[key]; - if (plant == "Rabid Dogwood" || plant == "War Lily" || plant == "Blustery Puffball") - { - ml -= 30; - break; - } - } - - } - return ml; -} - -int water_level_of_location(location l) -{ - int water_level = 1; - if (l.recommended_stat >= 40) //FIXME is this threshold spaded? - water_level += 1; - if (l.environment == "indoor") - water_level += 2; - if (l.environment == "underground" || l == $location[the lower chambers]) //per-location fix - water_level += 4; - water_level += numeric_modifier("water level"); - - water_level = clampi(water_level, 1, 6); - if (l.environment == "underwater") //or does the water get the rain instead? nobody knows, rain man - water_level = 0; //the aquaman hates rain man, they have a fight, aquaman wins - return water_level; -} - -float washaway_rate_of_location(location l) -{ - //Calculate washaway chance: - int current_water_level = l.water_level_of_location(); - - int washaway_chance = current_water_level * 5; - if ($item[fishbone catcher's mitt].equipped_amount() > 0) - washaway_chance -= 15; //GUESS - - if ($effect[Fishy Whiskers].have_effect() > 0) - { - //washaway_chance -= ?; //needs spading - } - return clampNormalf(washaway_chance / 100.0); -} - -int monster_level_adjustment_for_location(location l) -{ - int ml = monster_level_adjustment_ignoring_plants(); - - if (l.locationHasPlant("Rabid Dogwood") || l.locationHasPlant("War Lily") || l.locationHasPlant("Blustery Puffball")) - { - ml += 30; - } - - if (my_path().id == PATH_HEAVY_RAINS) - { - //complicated: - //First, cancel out the my_location() rain: - int my_location_water_level_ml = monster_level_adjustment() - numeric_modifier("Monster Level"); - ml -= my_location_water_level_ml; - - //Now, calculate the water level for the location: - int water_level = water_level_of_location(l); - - //Add that as ML: - if (!($locations[oil peak,the typical tavern cellar] contains l)) //kind of hacky to put this here, sorry - { - ml += water_level * 10; - } - } - - return ml; -} - -float initiative_modifier_for_location(location l) -{ - float base = initiative_modifier_ignoring_plants(); - - if (l.locationHasPlant("Impatiens") || l.locationHasPlant("Shuffle Truffle")) - base += 25.0; - return base; -} - -float item_drop_modifier_for_location(location l) -{ - int base = item_drop_modifier_ignoring_plants(); - if (l.locationHasPlant("Rutabeggar") || l.locationHasPlant("Stealing Magnolia")) - base += 25.0; - if (l.locationHasPlant("Kelptomaniac")) - base += 40.0; - return base; -} - -int monsterExtraInitForML(int ml) -{ - if (ml < 21) - return 0.0; - else if (ml < 41) - return 0.0 + 1.0 * (ml - 20.0); - else if (ml < 61) - return 20.0 + 2.0 * (ml - 40.0); - else if (ml < 81) - return 60.0 + 3.0 * (ml - 60.0); - else if (ml < 101) - return 120.0 + 4.0 * (ml - 80.0); - else - return 200.0 + 5.0 * (ml - 100.0); -} - -int stringCountSubstringMatches(string str, string substring) -{ - int count = 0; - int position = 0; - int breakout = 100; - int str_length = str.length(); //uncertain whether this is a constant time operation - while (breakout > 0 && position + 1 < str_length) - { - position = str.index_of(substring, position + 1); - if (position != -1) - count += 1; - else - break; - breakout -= 1; - } - return count; -} - -effect to_effect(item it) -{ - return it.effect_modifier("effect"); -} - - - -boolean weapon_is_club(item it) -{ - if (it.to_slot() != $slot[weapon]) return false; - if (it.item_type() == "club") - return true; - if (it.item_type() == "sword" && $effect[Iron Palms].have_effect() > 0) - return true; - return false; -} - -buffer prepend(buffer in_buffer, buffer value) -{ - buffer result; - result.append(value); - result.append(in_buffer); - in_buffer.set_length(0); - in_buffer.append(result); - return result; -} - -buffer prepend(buffer in_buffer, string value) -{ - return prepend(in_buffer, value.to_buffer()); -} - -float pressurePenaltyForLocation(location l, Error could_get_value) -{ - float pressure_penalty = 0.0; - - if (my_location() != l) - { - ErrorSet(could_get_value); - return -1.0; - } - - pressure_penalty = MAX(0, -numeric_modifier("item drop penalty")); - return pressure_penalty; -} - -int XiblaxianHoloWristPuterTurnsUntilNextItem() -{ - int drops = get_property_int("_holoWristDrops"); - int progress = get_property_int("_holoWristProgress"); - - //_holoWristProgress resets when drop happens - if (!mafiaIsPastRevision(15148)) - return -1; - int next_turn_hit = 5 * (drops + 1) + 6; - if (!mafiaIsPastRevision(15493)) //old behaviour - { - if (drops != 0) - next_turn_hit += 1; - } - return MAX(0, next_turn_hit - progress); -} - -int ka_dropped(monster m) -{ - if (m.phylum == $phylum[dude] || m.phylum == $phylum[hobo] || m.phylum == $phylum[hippy] || m.phylum == $phylum[pirate]) - return 2; - if (m.phylum == $phylum[goblin] || m.phylum == $phylum[humanoid] || m.phylum == $phylum[beast] || m.phylum == $phylum[bug] || m.phylum == $phylum[orc] || m.phylum == $phylum[elemental] || m.phylum == $phylum[elf] || m.phylum == $phylum[penguin]) - return 1; - return 0; -} - - -boolean is_underwater_familiar(familiar f) -{ - return $familiars[Barrrnacle,Emo Squid,Cuddlefish,Imitation Crab,Magic Dragonfish,Midget Clownfish,Rock Lobster,Urchin Urchin,Grouper Groupie,Squamous Gibberer,Dancing Frog,Adorable Space Buddy] contains f; -} - -float calculateCurrentNinjaAssassinMaxDamage() -{ - - //float assassin_ml = 155.0 + monster_level_adjustment(); - float assassin_ml = $monster[ninja snowman assassin].base_attack + 5.0; - float damage_absorption = raw_damage_absorption(); - float damage_reduction = damage_reduction(); - float moxie = my_buffedstat($stat[moxie]); - float cold_resistance = numeric_modifier("cold resistance"); - float v = 0.0; - - //spaded by yojimboS_LAW - //also by soirana - - float myst_class_extra_cold_resistance = 0.0; - if (my_class() == $class[pastamancer] || my_class() == $class[sauceror] || my_class() == $class[avatar of jarlsberg]) - myst_class_extra_cold_resistance = 0.05; - //Direct from the spreadsheet: - if (cold_resistance < 9) - v = ((((MAX((assassin_ml - moxie), 0.0) - damage_reduction) + 120.0) * MAX(0.1, MIN((1.1 - sqrt((damage_absorption/1000.0))), 1.0))) * ((1.0 - myst_class_extra_cold_resistance) - ((0.1) * MAX((cold_resistance - 5.0), 0.0)))); - else - v = ((((MAX((assassin_ml - moxie), 0.0) - damage_reduction) + 120.0) * MAX(0.1, MIN((1.1 - sqrt((damage_absorption/1000.0))), 1.0))) * (0.1 - myst_class_extra_cold_resistance + (0.5 * (powf((5.0/6.0), (cold_resistance - 9.0)))))); - - - - return v; -} - -float calculateCurrentNinjaAssassinMaxEnvironmentalDamage() -{ - float v = 0.0; - int ml_level = monster_level_adjustment_ignoring_plants(); - if (ml_level >= 25) - { - float expected_assassin_damage = 0.0; - - expected_assassin_damage = ((150 + ml_level) * (ml_level - 25)).to_float() / 500.0; - - expected_assassin_damage = expected_assassin_damage + ceiling(expected_assassin_damage / 11.0); //upper limit - - //FIXME add in resists later - //Resists don't work properly. They have an effect, but it's different. I don't know how much exactly, so for now, ignore this: - //I think they're probably just -5 like above - //expected_assassin_damage = damageTakenByElement(expected_assassin_damage, $element[cold]); - - expected_assassin_damage = ceil(expected_assassin_damage); - - v += expected_assassin_damage; - } - return v; -} - -//mafia describes "merkin" for the "mer-kin" phylum, which "to_phylum()" does not interpret -//hmm... maybe file a request for to_phylum() to parse that -phylum getDNASyringePhylum() -{ - string phylum_text = get_property("dnaSyringe"); - if (phylum_text == "merkin") - return $phylum[mer-kin]; - else - return phylum_text.to_phylum(); -} - -int nextLibramSummonMPCost() -{ - int libram_summoned = get_property_int("libramSummons"); - int next_libram_summoned = libram_summoned + 1; - int libram_mp_cost = MAX(1 + (next_libram_summoned * (next_libram_summoned - 1)/2) + mana_cost_modifier(), 1); - return libram_mp_cost; -} - -int equippable_amount(item it) -{ - if (!it.can_equip()) return it.equipped_amount(); - if (it.available_amount() == 0) return 0; - if ($slots[acc1, acc2, acc3] contains it.to_slot() && it.available_amount() > 1 && !it.boolean_modifier("Single equip")) - return MIN(3, it.available_amount()); - if (it.to_slot() == $slot[weapon] && it.weapon_hands() == 1) - { - int weapon_maximum = 1; - if ($skill[double-fisted skull smashing].skill_is_usable()) - weapon_maximum += 1; - if (my_familiar() == $familiar[disembodied hand]) - weapon_maximum += 1; - return MIN(weapon_maximum, it.available_amount()); - } - return 1; -} - -boolean haveSeenBadMoonEncounter(int encounter_id) -{ - if (!get_property_ascension("lastBadMoonReset")) //badMoonEncounter values are not reset when you ascend - return false; - string zero = ""; //Encounters under 10 are listed as "01", "02", "03"... - if (encounter_id < 10) - zero = "0"; - return get_property_boolean("badMoonEncounter" + zero + encounter_id); -} - -//FIXME make this use static etc. Probably extend Item Filter.ash to support equipment. -item [int] generateEquipmentForExtraExperienceOnStat(stat desired_stat, boolean require_can_equip_currently) -{ - //boolean [item] experience_percent_modifiers; - /*string numeric_modifier_string; - if (desired_stat == $stat[muscle]) - { - //experience_percent_modifiers = $items[trench lighter,fake washboard]; - numeric_modifier_string = "Muscle"; - } - else if (desired_stat == $stat[mysticality]) - { - //experience_percent_modifiers = lookupItems("trench lighter,basaltamander buckler"); - numeric_modifier_string = "Mysticality"; - } - else if (desired_stat == $stat[moxie]) - { - //experience_percent_modifiers = $items[trench lighter,backwoods banjo]; - numeric_modifier_string = "Moxie"; - } - else - return listMakeBlankItem(); - if (numeric_modifier_string != "") - numeric_modifier_string += " Experience Percent";*/ - - item [slot] item_slots; - string numeric_modifier_string = desired_stat + " Experience Percent"; - - //foreach it in experience_percent_modifiers - foreach it in equipmentWithNumericModifier(numeric_modifier_string) - { - slot s = it.to_slot(); - if (s == $slot[shirt] && !($skill[12].have_skill() || $skill[Best Dressed].have_skill())) // Torso Aware(g)ness - continue; - if (it.available_amount() > 0 && (!require_can_equip_currently || it.can_equip()) && item_slots[it.to_slot()].numeric_modifier(numeric_modifier_string) < it.numeric_modifier(numeric_modifier_string)) - { - item_slots[it.to_slot()] = it; - } - } - - item [int] items_could_equip; - foreach s, it in item_slots - items_could_equip.listAppend(it); - return items_could_equip; -} - - -item [int] generateEquipmentToEquipForExtraExperienceOnStat(stat desired_stat) -{ - item [int] items_could_equip = generateEquipmentForExtraExperienceOnStat(desired_stat, true); - item [int] items_equipping; - foreach key, it in items_could_equip - { - if (it.equipped_amount() == 0) - { - items_equipping.listAppend(it); - } - } - return items_equipping; -} - - - -float averageAdventuresForConsumable(item it, boolean assume_monday) -{ - float adventures = 0.0; - string [int] adventures_string = it.adventures.split_string("-"); - foreach key, v in adventures_string - { - float a = v.to_float(); - if (a < 0) - continue; - adventures += a * (1.0 / to_float(adventures_string.count())); - } - if (it == lookupItem("affirmation cookie")) - adventures += 3; - if (it == $item[White Citadel burger]) - { - if (in_bad_moon()) - adventures = 2; //worst case scenario - else - adventures = 9; //saved across lifetimes - } - - if ($skill[saucemaven].have_skill() && ($items[hot hi mein,cold hi mein,sleazy hi mein,spooky hi mein,stinky hi mein,Hell ramen,fettucini Inconnu,gnocchetti di Nietzsche,spaghetti with Skullheads,spaghetti con calaveras,Fleetwood mac 'n' cheese,haunted hell ramen] contains it)) - { - if ($classes[sauceror,pastamancer] contains my_class()) - adventures += 5; - else - adventures += 3; - } - - - if ($skill[pizza lover].have_skill() && it.to_lower_case().contains_text("pizza")) - { - adventures += it.fullness; - } - if (it.to_lower_case().contains_text("lasagna") && !assume_monday) - adventures += 5; - //FIXME lasagna properly - return adventures; -} - -float averageAdventuresForConsumable(item it) -{ - return averageAdventuresForConsumable(it, false); -} - -boolean [string] getInstalledSourceTerminalSingleChips() -{ - string [int] chips = get_property("sourceTerminalChips").split_string_alternate(","); - boolean [string] result; - foreach key, s in chips - result[s] = true; - return result; -} - -boolean [skill] getActiveSourceTerminalSkills() -{ - string skill_1_name = get_property("sourceTerminalEducate1"); - string skill_2_name = get_property("sourceTerminalEducate2"); - - boolean [skill] skills_have; - if (skill_1_name != "") - skills_have[skill_1_name.replace_string(".edu", "").to_skill()] = true; - if (skill_2_name != "") - skills_have[skill_2_name.replace_string(".edu", "").to_skill()] = true; - return skills_have; -} - -boolean monsterIsGhost(monster m) -{ - if (m.attributes.contains_text("GHOST")) - return true; - /*if ($monsters[Ancient ghost,Ancient protector spirit,Banshee librarian,Battlie Knight Ghost,Bettie Barulio,Chalkdust wraith,Claybender Sorcerer Ghost,Cold ghost,Contemplative ghost,Dusken Raider Ghost,Ghost,Ghost miner,Hot ghost,Lovesick ghost,Marcus Macurgeon,Marvin J. Sunny,Mayor Ghost,Mayor Ghost (Hard Mode),Model skeleton,Mortimer Strauss,Plaid ghost,Protector Spectre,Sexy sorority ghost,Sheet ghost,Sleaze ghost,Space Tourist Explorer Ghost,Spirit of New Wave (Inner Sanctum),Spooky ghost,Stench ghost,The ghost of Phil Bunion,Whatsian Commando Ghost,Wonderful Winifred Wongle] contains m) - return true; - if ($monsters[boneless blobghost,the ghost of Vanillica \"Trashblossom\" Gorton,restless ghost,The Icewoman,the ghost of Monsieur Baguelle,The ghost of Lord Montague Spookyraven,The Headless Horseman,The ghost of Ebenoozer Screege,The ghost of Sam McGee,The ghost of Richard Cockingham,The ghost of Jim Unfortunato,The ghost of Waldo the Carpathian,the ghost of Oily McBindle] contains m) - return true; - if (lookupMonster("Emily Koops, a spooky lime") == m) - return true;*/ - return false; -} - -boolean item_is_pvp_stealable(item it) -{ - if (it == $item[amulet of yendor]) - return true; - if (!it.tradeable) - return false; - if (!it.discardable) - return false; - if (it.quest) - return false; - if (it.gift) - return false; - return true; -} - -int effective_familiar_weight(familiar f) -{ - if (f == $familiar[none]) return 0; - int weight = f.familiar_weight(); - - boolean is_moved = false; - string [int] familiars_used_on = get_property("_feastedFamiliars").split_string_alternate(";"); - foreach key, f_name in familiars_used_on - { - if (f_name.to_familiar() == f) - { - is_moved = true; - break; - } - } - if (is_moved) - weight += 10; - return weight; -} - -boolean year_is_leap_year(int year) -{ - if (year % 4 != 0) return false; - if (year % 100 != 0) return true; - if (year % 400 != 0) return false; - return true; -} - -boolean today_is_pvp_season_end() -{ - string today = format_today_to_string("MMdd"); - if (today == "0228") - { - int year = format_today_to_string("yyyy").to_int(); - boolean is_leap_year = year_is_leap_year(year); - if (!is_leap_year) - return true; - } - else if (today == "0229") //will always be true, but won't always be there - return true; - else if (today == "0430") - return true; - else if (today == "0630") - return true; - else if (today == "0831") - return true; - else if (today == "1031") - return true; - else if (today == "1231") - return true; - return false; -} - -boolean monster_has_zero_turn_cost(monster m) -{ - if (m.attributes.contains_text("FREE")) - return true; - if (m == lookupMonster("sausage goblin") && m != $monster[none]) return true; - if (lookupMonsters("LOV Engineer,LOV Enforcer,LOV Equivocator") contains m) return true; - - if ($monsters[lynyrd] contains m) return true; //not marked as FREE in attributes - //if ($monsters[Black Crayon Beast,Black Crayon Beetle,Black Crayon Constellation,Black Crayon Golem,Black Crayon Demon,Black Crayon Man,Black Crayon Elemental,Black Crayon Crimbo Elf,Black Crayon Fish,Black Crayon Goblin,Black Crayon Hippy,Black Crayon Hobo,Black Crayon Shambling Monstrosity,Black Crayon Manloid,Black Crayon Mer-kin,Black Crayon Frat Orc,Black Crayon Penguin,Black Crayon Pirate,Black Crayon Flower,Black Crayon Slime,Black Crayon Undead Thing,Black Crayon Spiraling Shape,broodling seal,Centurion of Sparky,heat seal,hermetic seal,navy seal,Servant of Grodstank,shadow of Black Bubbles,Spawn of Wally,watertight seal,wet seal,lynyrd,BRICKO airship,BRICKO bat,BRICKO cathedral,BRICKO elephant,BRICKO gargantuchicken,BRICKO octopus,BRICKO ooze,BRICKO oyster,BRICKO python,BRICKO turtle,BRICKO vacuum cleaner,Witchess Bishop,Witchess King,Witchess Knight,Witchess Ox,Witchess Pawn,Witchess Queen,Witchess Rook,Witchess Witch,The ghost of Ebenoozer Screege,The ghost of Lord Montague Spookyraven,The ghost of Waldo the Carpathian,The Icewoman,The ghost of Jim Unfortunato,the ghost of Sam McGee,the ghost of Monsieur Baguelle,the ghost of Vanillica "Trashblossom" Gorton,the ghost of Oily McBindle,boneless blobghost,The ghost of Richard Cockingham,The Headless Horseman,Emily Koops\, a spooky lime,time-spinner prank,random scenester,angry bassist,blue-haired girl,evil ex-girlfriend,peeved roommate] contains m) - //return true; - if (m == $monster[X-32-F Combat Training Snowman] && get_property_int("_snojoFreeFights") < 10) - return true; - if (my_familiar() == $familiar[machine elf] && my_location() == $location[the deep machine tunnels] && get_property_int("_machineTunnelsAdv") < 5) - return true; - if (lookupMonsters("terrible mutant,slime blob,government bureaucrat,angry ghost,annoyed snake") contains m && get_property_int("_voteFreeFights") < 3) - return true; - return false; -} - -static -{ - int [location] __location_combat_rates; -} -void initialiseLocationCombatRates() -{ - if (__location_combat_rates.count() > 0) - return; - int [location] rates; - file_to_map("data/combats.txt", __location_combat_rates); - //needs spading: - foreach l in $locations[the spooky forest] - __location_combat_rates[l] = 85; - __location_combat_rates[$location[the black forest]] = 95; //can't remember if this is correct - __location_combat_rates[$location[inside the palindome]] = 80; //this is not accurate, there's probably a turn cap or something - __location_combat_rates[$location[The Haunted Billiards Room]] = 85; //completely and absolutely wrong and unspaded; just here to make another script work - foreach l in $locations[the haunted gallery, the haunted bathroom, the haunted ballroom] - __location_combat_rates[l] = 90; //or 95? can't remember - __location_combat_rates[$location[Twin Peak]] = 90; //FIXME assumption - //print_html("__location_combat_rates = " + __location_combat_rates.to_json()); -} -//initialiseLocationCombatRates(); -int combatRateOfLocation(location l) -{ - initialiseLocationCombatRates(); - //Some revamps changed the combat rate; here we have some not-quite-true-but-close assumptions: - if (l == $location[the haunted ballroom]) - return 95; - if (__location_combat_rates contains l) - { - int rate = __location_combat_rates[l]; - if (rate < 0) - rate = 100; - return rate; - } - return 100; //Unknown - - /*float base_rate = l.appearance_rates()[$monster[none]]; - if (base_rate == 0.0) - return 0; - return base_rate + combat_rate_modifier();*/ -} - -//Specifically checks whether you can eat this item right now - fullness/drunkenness, meat, etc. -boolean CafeItemEdible(item it) -{ - //Mafia does not seem to support accessing its cafe data via ASH. - //So, do the same thing. There's four mafia supports - Chez Snootee, Crimbo Cafe, Hell's Kitchen, and MicroBrewery. - if (it.fullness > availableFullness()) - return false; - if (it.inebriety > availableDrunkenness()) - return false; - //FIXME rest - if (it == $item[Jumbo Dr. Lucifer] && in_bad_moon() && my_meat() >= 150) - return true; - return false; -} - -static -{ - int [string] __lta_social_capital_purchases; - void initialiseLTASocialCapitalPurchases() - { - __lta_social_capital_purchases["bondAdv"] = 1; - __lta_social_capital_purchases["bondBeach"] = 1; - __lta_social_capital_purchases["bondBeat"] = 1; - __lta_social_capital_purchases["bondBooze"] = 2; - __lta_social_capital_purchases["bondBridge"] = 3; - __lta_social_capital_purchases["bondDR"] = 1; - __lta_social_capital_purchases["bondDesert"] = 5; - __lta_social_capital_purchases["bondDrunk1"] = 2; - __lta_social_capital_purchases["bondDrunk2"] = 3; - __lta_social_capital_purchases["bondHP"] = 1; - __lta_social_capital_purchases["bondHoney"] = 5; - __lta_social_capital_purchases["bondInit"] = 1; - __lta_social_capital_purchases["bondItem1"] = 1; - __lta_social_capital_purchases["bondItem2"] = 2; - __lta_social_capital_purchases["bondItem3"] = 4; - __lta_social_capital_purchases["bondJetpack"] = 3; - __lta_social_capital_purchases["bondMPregen"] = 3; - __lta_social_capital_purchases["bondMartiniDelivery"] = 1; - __lta_social_capital_purchases["bondMartiniPlus"] = 3; - __lta_social_capital_purchases["bondMartiniTurn"] = 1; - __lta_social_capital_purchases["bondMeat"] = 1; - __lta_social_capital_purchases["bondMox1"] = 1; - __lta_social_capital_purchases["bondMox2"] = 3; - __lta_social_capital_purchases["bondMus1"] = 1; - __lta_social_capital_purchases["bondMus2"] = 3; - __lta_social_capital_purchases["bondMys1"] = 1; - __lta_social_capital_purchases["bondMys2"] = 3; - __lta_social_capital_purchases["bondSpleen"] = 4; - __lta_social_capital_purchases["bondStat"] = 2; - __lta_social_capital_purchases["bondStat2"] = 4; - __lta_social_capital_purchases["bondStealth"] = 3; - __lta_social_capital_purchases["bondStealth2"] = 4; - __lta_social_capital_purchases["bondSymbols"] = 3; - __lta_social_capital_purchases["bondWar"] = 3; - __lta_social_capital_purchases["bondWeapon2"] = 3; - __lta_social_capital_purchases["bondWpn"] = 1; - } - initialiseLTASocialCapitalPurchases(); -} - -int licenseToAdventureSocialCapitalAvailable() -{ - int total_social_capital = 0; - total_social_capital += 1 + MIN(23, get_property_int("bondPoints")); - foreach level in $ints[3,6,9,12,15] - { - if (my_level() >= level) - total_social_capital += 1; - } - total_social_capital += 2 * get_property_int("bondVillainsDefeated"); - - - - int social_capital_used = 0; - foreach property_name, value in __lta_social_capital_purchases - { - if (get_property_boolean(property_name)) - social_capital_used += value; - } - //print_html("total_social_capital = " + total_social_capital + ", social_capital_used = " + social_capital_used); - - return total_social_capital - social_capital_used; -} - - - -monster convertEncounterToMonster(string encounter) -{ - boolean [string] intergnat_strings; - intergnat_strings[" WITH SCIENCE!"] = true; - intergnat_strings["ELDRITCH HORROR "] = true; - intergnat_strings[" WITH BACON!!!"] = true; - intergnat_strings[" NAMED NEIL"] = true; - intergnat_strings[" AND TESLA!"] = true; - foreach s in intergnat_strings - { - if (encounter.contains_text(s)) - encounter = encounter.replace_string(s, ""); - } - if (encounter == "The Junk") //not a junksprite - return $monster[Junk]; - if ((encounter.stringHasPrefix("the ") || encounter.stringHasPrefix("The")) && encounter.to_monster() == $monster[none]) - { - encounter = encounter.substring(4); - //print_html("now \"" + encounter + "\""); - } - //if (encounter == "the X-32-F Combat Training Snowman") - //return $monster[X-32-F Combat Training Snowman]; - if (encounter == "clingy pirate") - return $monster[clingy pirate (male)]; //always accurate for my personal data - return encounter.to_monster(); -} - -//Returns [0, 100] -float resistanceLevelToResistancePercent(float level) -{ - float m = 0; - if (my_primestat() == $stat[mysticality]) - m = 5; - if (level <= 3) return 10 * level + m; - return 90 - 50 * powf(5.0 / 6.0, level - 4) + m; -} - - -//Mafia's text output doesn't handle very long strings with no spaces in them - they go horizontally past the text box. This is common for to_json()-types. -//So, add spaces every so often if we need them: -buffer processStringForPrinting(string str) -{ - buffer out; - int limit = 50; - int comma_limit = 25; - int characters_since_space = 0; - for i from 0 to str.length() - 1 - { - if (str.length() == 0) break; - string c = str.char_at(i); - out.append(c); - - if (c == " ") - characters_since_space = 0; - else - { - characters_since_space++; - if (characters_since_space >= limit || (c == "," && characters_since_space >= comma_limit)) //prefer adding spaces after a comma - { - characters_since_space = 0; - out.append(" "); - } - } - } - return out; -} -void printSilent(string line, string font_colour) -{ - print_html("" + line.processStringForPrinting() + ""); -} - -void printSilent(string line) -{ - print_html(line.processStringForPrinting()); -} - -//have_equipped() exists -boolean equipped(item it) -{ - return it.equipped_amount() > 0; -} - -boolean have(item it) -{ - return it.available_amount() > 0; -} - -boolean canAccessMall() -{ - if (!can_interact()) return false; - if (!get_property_boolean("autoSatisfyWithMall")) return false; - if (my_ascensions() == 0 && !get_property_ascension("lastDesertUnlock")) return false; - return true; -} - - -// In Mafia r26631, the locations list was refactored and some locations were renamed. These are -// helper functions to get the right zone on either old or new versions. - -location fratHouseInDisguise() { - location house = to_location("Frat House In Disguise"); - if (house == $location[none]) { - house = to_location("Frat House (Frat Disguise)"); - } - return house; -} - -location hippyCampInDisguise() { - location camp = to_location("Hippy Camp In Disguise"); - if (camp == $location[none]) { - camp = to_location("Hippy Camp (Hippy Disguise)"); - } - return camp; -} - -boolean isAprilFools() { - return (now_to_string("MMdd") == "0401"); -} diff --git a/Source/relay/TourGuide/Support/List.ash b/Source/relay/TourGuide/Support/List.ash deleted file mode 100644 index c47b5ce3..00000000 --- a/Source/relay/TourGuide/Support/List.ash +++ /dev/null @@ -1,1109 +0,0 @@ -//WARNING: All listAppend functions are flawed. -//Specifically, there's a possibility of a hole that causes order to be incorrect. -//But, the only way to fix that is to traverse the list to determine the maximum key. -//That would take forever... - -string listLastObject(string [int] list) -{ - if (list.count() == 0) - return ""; - return list[list.count() - 1]; -} - -void listAppend(string [int] list, string entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppendList(string [int] list, string [int] entries) -{ - foreach key in entries - list.listAppend(entries[key]); -} - -string [int] listUnion(string [int] list, string [int] list2) -{ - string [int] result; - foreach key, s in list - result.listAppend(s); - foreach key, s in list2 - result.listAppend(s); - return result; -} - -void listAppendList(boolean [item] destination, boolean [item] source) -{ - foreach it, value in source - destination[it] = value; -} - -void listAppendList(boolean [string] destination, boolean [string] source) -{ - foreach key, value in source - destination[key] = value; -} - -void listAppendList(boolean [skill] destination, boolean [skill] source) -{ - foreach key, value in source - destination[key] = value; -} - -void listAppend(item [int] list, item entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppendList(item [int] list, item [int] entries) -{ - foreach key in entries - list.listAppend(entries[key]); -} - - - -void listAppend(int [int] list, int entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(float [int] list, float entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(location [int] list, location entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(element [int] list, element entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppendList(location [int] list, location [int] entries) -{ - foreach key in entries - list.listAppend(entries[key]); -} - -void listAppend(effect [int] list, effect entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(skill [int] list, skill entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(familiar [int] list, familiar entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(monster [int] list, monster entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(phylum [int] list, phylum entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(buffer [int] list, buffer entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(slot [int] list, slot entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(thrall [int] list, thrall entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - - - - - -void listAppend(string [int][int] list, string [int] entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(skill [int][int] list, skill [int] entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(familiar [int][int] list, familiar [int] entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(int [int][int] list, int [int] entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(item [int][int] list, item [int] entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void listAppend(skill [int] list, boolean [skill] entry) -{ - foreach v in entry - list.listAppend(v); -} - -void listAppend(item [int] list, boolean [item] entry) -{ - foreach v in entry - list.listAppend(v); -} - -void listPrepend(string [int] list, string entry) -{ - int position = 0; - while (list contains position) - position -= 1; - list[position] = entry; -} - -void listPrepend(skill [int] list, skill entry) -{ - int position = 0; - while (list contains position) - position -= 1; - list[position] = entry; -} - -void listAppendList(skill [int] list, skill [int] entries) -{ - foreach key in entries - list.listAppend(entries[key]); -} - -void listPrepend(location [int] list, location entry) -{ - int position = 0; - while (list contains position) - position -= 1; - list[position] = entry; -} - -void listPrepend(item [int] list, item entry) -{ - int position = 0; - while (list contains position) - position -= 1; - list[position] = entry; -} - - -void listClear(string [int] list) -{ - foreach i in list - { - remove list[i]; - } -} - -void listClear(int [int] list) -{ - foreach i in list - { - remove list[i]; - } -} - -void listClear(item [int] list) -{ - foreach i in list - { - remove list[i]; - } -} - -void listClear(location [int] list) -{ - foreach i in list - { - remove list[i]; - } -} - -void listClear(monster [int] list) -{ - foreach i in list - { - remove list[i]; - } -} - -void listClear(skill [int] list) -{ - foreach i in list - { - remove list[i]; - } -} - - -void listClear(boolean [string] list) -{ - foreach i in list - { - remove list[i]; - } -} - - -string [int] listMakeBlankString() -{ - string [int] result; - return result; -} - -item [int] listMakeBlankItem() -{ - item [int] result; - return result; -} - -skill [int] listMakeBlankSkill() -{ - skill [int] result; - return result; -} - -location [int] listMakeBlankLocation() -{ - location [int] result; - return result; -} - -monster [int] listMakeBlankMonster() -{ - monster [int] result; - return result; -} - -familiar [int] listMakeBlankFamiliar() -{ - familiar [int] result; - return result; -} - -int [int] listMakeBlankInt() -{ - int [int] result; - return result; -} - -string [int] listMake(string ... entries) -{ - string [int] result; - foreach _, e in entries - { - result.listAppend(e); - } - return result; -} - -int [int] listMake(int ... entries) -{ - int [int] result; - foreach _, e in entries - { - result.listAppend(e); - } - return result; -} - -item [int] listMake(item ... entries) -{ - item [int] result; - foreach _, e in entries - { - result.listAppend(e); - } - return result; -} - -skill [int] listMake(skill ... entries) -{ - skill [int] result; - foreach _, e in entries - { - result.listAppend(e); - } - return result; -} - -monster [int] listMake(monster ... entries) -{ - monster [int] result; - foreach _, e in entries - { - result.listAppend(e); - } - return result; -} - -string listJoinComponents(string [int] list, string joining_string, string and_string) -{ - buffer result; - boolean first = true; - int number_seen = 0; - foreach i, value in list - { - if (first) - { - result.append(value); - first = false; - } - else - { - if (!(list.count() == 2 && and_string != "")) - result.append(joining_string); - if (and_string != "" && number_seen == list.count() - 1) - { - result.append(" "); - result.append(and_string); - result.append(" "); - } - result.append(value); - } - number_seen = number_seen + 1; - } - return result.to_string(); -} - -string listJoinComponents(string [int] list, string joining_string) -{ - return listJoinComponents(list, joining_string, ""); -} - -string listJoinComponents(item [int] list, string joining_string, string and_string) -{ - //lazy: - //convert items to strings, join that - string [int] list_string; - foreach key in list - list_string.listAppend(list[key].to_string()); - return listJoinComponents(list_string, joining_string, and_string); -} - -string listJoinComponents(item [int] list, string joining_string) -{ - return listJoinComponents(list, joining_string, ""); -} - -string listJoinComponents(monster [int] list, string joining_string, string and_string) -{ - string [int] list_string; - foreach key in list - list_string.listAppend(list[key].to_string()); - return listJoinComponents(list_string, joining_string, and_string); -} -string listJoinComponents(monster [int] list, string joining_string) -{ - return listJoinComponents(list, joining_string, ""); -} - -string listJoinComponents(effect [int] list, string joining_string, string and_string) -{ - string [int] list_string; - foreach key in list - list_string.listAppend(list[key].to_string()); - return listJoinComponents(list_string, joining_string, and_string); -} - -string listJoinComponents(effect [int] list, string joining_string) -{ - return listJoinComponents(list, joining_string, ""); -} - - -string listJoinComponents(familiar [int] list, string joining_string, string and_string) -{ - string [int] list_string; - foreach key in list - list_string.listAppend(list[key].to_string()); - return listJoinComponents(list_string, joining_string, and_string); -} - -string listJoinComponents(familiar [int] list, string joining_string) -{ - return listJoinComponents(list, joining_string, ""); -} - - - -string listJoinComponents(location [int] list, string joining_string, string and_string) -{ - //lazy: - //convert locations to strings, join that - string [int] list_string; - foreach key in list - list_string.listAppend(list[key].to_string()); - return listJoinComponents(list_string, joining_string, and_string); -} - -string listJoinComponents(location [int] list, string joining_string) -{ - return listJoinComponents(list, joining_string, ""); -} - -string listJoinComponents(phylum [int] list, string joining_string, string and_string) -{ - string [int] list_string; - foreach key in list - list_string.listAppend(list[key].to_string()); - return listJoinComponents(list_string, joining_string, and_string); -} - -string listJoinComponents(phylum [int] list, string joining_string) -{ - return listJoinComponents(list, joining_string, ""); -} - - - -string listJoinComponents(skill [int] list, string joining_string, string and_string) -{ - string [int] list_string; - foreach key in list - list_string.listAppend(list[key].to_string()); - return listJoinComponents(list_string, joining_string, and_string); -} - -string listJoinComponents(skill [int] list, string joining_string) -{ - return listJoinComponents(list, joining_string, ""); -} - -string listJoinComponents(int [int] list, string joining_string, string and_string) -{ - //lazy: - //convert ints to strings, join that - string [int] list_string; - foreach key in list - list_string.listAppend(list[key].to_string()); - return listJoinComponents(list_string, joining_string, and_string); -} - -string listJoinComponents(int [int] list, string joining_string) -{ - return listJoinComponents(list, joining_string, ""); -} - - -void listRemoveKeys(string [int] list, int [int] keys_to_remove) -{ - foreach i in keys_to_remove - { - int key = keys_to_remove[i]; - if (!(list contains key)) - continue; - remove list[key]; - } -} - -int listSum(int [int] list) -{ - int v = 0; - foreach key in list - { - v += list[key]; - } - return v; -} - - -string [int] listCopy(string [int] l) -{ - string [int] result; - foreach key in l - result[key] = l[key]; - return result; -} - -int [int] listCopy(int [int] l) -{ - int [int] result; - foreach key in l - result[key] = l[key]; - return result; -} - -monster [int] listCopy(monster [int] l) -{ - monster [int] result; - foreach key in l - result[key] = l[key]; - return result; -} - -element [int] listCopy(element [int] l) -{ - element [int] result; - foreach key in l - result[key] = l[key]; - return result; -} - -skill [int] listCopy(skill [int] l) -{ - skill [int] result; - foreach key in l - result[key] = l[key]; - return result; -} - -boolean [monster] listCopy(boolean [monster] l) -{ - boolean [monster] result; - foreach key in l - result[key] = l[key]; - return result; -} - -//Strict, in this case, means the keys start at 0, and go up by one per entry. This allows easy consistent access -boolean listKeysMeetStrictRequirements(string [int] list) -{ - int expected_value = 0; - foreach key in list - { - if (key != expected_value) - return false; - expected_value += 1; - } - return true; -} -string [int] listCopyStrictRequirements(string [int] list) -{ - string [int] result; - foreach key in list - result.listAppend(list[key]); - return result; -} - -string [string] mapMake() -{ - string [string] result; - return result; -} - -string [string] mapMake(string key1, string value1) -{ - string [string] result; - result[key1] = value1; - return result; -} - -string [string] mapMake(string key1, string value1, string key2, string value2) -{ - string [string] result; - result[key1] = value1; - result[key2] = value2; - return result; -} - -string [string] mapMake(string key1, string value1, string key2, string value2, string key3, string value3) -{ - string [string] result; - result[key1] = value1; - result[key2] = value2; - result[key3] = value3; - return result; -} - -string [string] mapMake(string key1, string value1, string key2, string value2, string key3, string value3, string key4, string value4) -{ - string [string] result; - result[key1] = value1; - result[key2] = value2; - result[key3] = value3; - result[key4] = value4; - return result; -} - -string [string] mapMake(string key1, string value1, string key2, string value2, string key3, string value3, string key4, string value4, string key5, string value5) -{ - string [string] result; - result[key1] = value1; - result[key2] = value2; - result[key3] = value3; - result[key4] = value4; - result[key5] = value5; - return result; -} - - -string [string] mapMake(string key1, string value1, string key2, string value2, string key3, string value3, string key4, string value4, string key5, string value5, string key6, string value6) -{ - string [string] result; - result[key1] = value1; - result[key2] = value2; - result[key3] = value3; - result[key4] = value4; - result[key5] = value5; - result[key6] = value6; - return result; -} - -string [string] mapCopy(string [string] map) -{ - string [string] result; - foreach key in map - result[key] = map[key]; - return result; -} - -boolean mapsAreEqual(string [string] map1, string [string] map2) -{ - if (map1.count() != map2.count()) - { - //print_html("map1.c = " + map1.count() + " which is not " + map2.count()); - return false; - } - foreach key1, v in map1 - { - if (!(map2 contains key1)) - { - //print_html("map2 lacks " + key1); - return false; - } - if (map2[key1] != v) - { - //print_html("map2 v(" + map2[key1] + " does not equal " + key1 + " (" + v + ")"); - return false; - } - } - return true; -} - -boolean [string] listInvert(string [int] list) -{ - boolean [string] result; - foreach key in list - { - result[list[key]] = true; - } - return result; -} - - -boolean [int] listInvert(int [int] list) -{ - boolean [int] result; - foreach key in list - { - result[list[key]] = true; - } - return result; -} - -boolean [location] listInvert(location [int] list) -{ - boolean [location] result; - foreach key in list - { - result[list[key]] = true; - } - return result; -} - -boolean [item] listInvert(item [int] list) -{ - boolean [item] result; - foreach key in list - { - result[list[key]] = true; - } - return result; -} - -boolean [monster] listInvert(monster [int] list) -{ - boolean [monster] result; - foreach key in list - { - result[list[key]] = true; - } - return result; -} - -boolean [familiar] listInvert(familiar [int] list) -{ - boolean [familiar] result; - foreach key in list - { - result[list[key]] = true; - } - return result; -} - -int [int] listConvertToInt(string [int] list) -{ - int [int] result; - foreach key in list - result[key] = list[key].to_int(); - return result; -} - -item [int] listConvertToItem(string [int] list) -{ - item [int] result; - foreach key in list - result[key] = list[key].to_item(); - return result; -} - -string listFirstObject(string [int] list) -{ - foreach key in list - return list[key]; - return ""; -} - -//(I'm assuming maps have a consistent enumeration order, which may not be the case) -int listKeyForIndex(string [int] list, int index) -{ - int i = 0; - foreach key in list - { - if (i == index) - return key; - i += 1; - } - return -1; -} - -int listKeyForIndex(location [int] list, int index) -{ - int i = 0; - foreach key in list - { - if (i == index) - return key; - i += 1; - } - return -1; -} - -int listKeyForIndex(familiar [int] list, int index) -{ - int i = 0; - foreach key in list - { - if (i == index) - return key; - i += 1; - } - return -1; -} - -int listKeyForIndex(item [int] list, int index) -{ - int i = 0; - foreach key in list - { - if (i == index) - return key; - i += 1; - } - return -1; -} - -int listKeyForIndex(monster [int] list, int index) -{ - int i = 0; - foreach key in list - { - if (i == index) - return key; - i += 1; - } - return -1; -} - -int listKeyForIndex(int [int] list, int index) -{ - int i = 0; - foreach key in list - { - if (i == index) - return key; - i += 1; - } - return -1; -} - -int llistKeyForIndex(string [int][int] list, int index) -{ - int i = 0; - foreach key in list - { - if (i == index) - return key; - i += 1; - } - return -1; -} - -string listGetRandomObject(string [int] list) -{ - if (list.count() == 0) - return ""; - if (list.count() == 1) - return list[listKeyForIndex(list, 0)]; - return list[listKeyForIndex(list, random(list.count()))]; -} - -item listGetRandomObject(item [int] list) -{ - if (list.count() == 0) - return $item[none]; - if (list.count() == 1) - return list[listKeyForIndex(list, 0)]; - return list[listKeyForIndex(list, random(list.count()))]; -} - -location listGetRandomObject(location [int] list) -{ - if (list.count() == 0) - return $location[none]; - if (list.count() == 1) - return list[listKeyForIndex(list, 0)]; - return list[listKeyForIndex(list, random(list.count()))]; -} - -familiar listGetRandomObject(familiar [int] list) -{ - if (list.count() == 0) - return $familiar[none]; - if (list.count() == 1) - return list[listKeyForIndex(list, 0)]; - return list[listKeyForIndex(list, random(list.count()))]; -} - -monster listGetRandomObject(monster [int] list) -{ - if (list.count() == 0) - return $monster[none]; - if (list.count() == 1) - return list[listKeyForIndex(list, 0)]; - return list[listKeyForIndex(list, random(list.count()))]; -} - -int listGetRandomObject(int [int] list) -{ - if (list.count() == 0) - return -1; - if (list.count() == 1) - return list[listKeyForIndex(list, 0)]; - return list[listKeyForIndex(list, random(list.count()))]; -} - - -boolean listContainsValue(monster [int] list, monster vo) -{ - foreach key, v2 in list - { - if (v2 == vo) - return true; - } - return false; -} - -boolean listContainsValue(string [int] list, string vo) -{ - foreach key, v2 in list - { - if (v2 == vo) - return true; - } - return false; -} - -string [int] listInvert(boolean [string] list) -{ - string [int] out; - foreach m, value in list - { - if (value) - out.listAppend(m); - } - return out; -} - -int [int] listInvert(boolean [int] list) -{ - int [int] out; - foreach m, value in list - { - if (value) - out.listAppend(m); - } - return out; -} - -skill [int] listInvert(boolean [skill] list) -{ - skill [int] out; - foreach m, value in list - { - if (value) - out.listAppend(m); - } - return out; -} - -monster [int] listInvert(boolean [monster] monsters) -{ - monster [int] out; - foreach m, value in monsters - { - if (value) - out.listAppend(m); - } - return out; -} - -location [int] listInvert(boolean [location] list) -{ - location [int] out; - foreach k, value in list - { - if (value) - out.listAppend(k); - } - return out; -} - -familiar [int] listInvert(boolean [familiar] list) -{ - familiar [int] out; - foreach k, value in list - { - if (value) - out.listAppend(k); - } - return out; -} - -item [int] listInvert(boolean [item] list) -{ - item [int] out; - foreach k, value in list - { - if (value) - out.listAppend(k); - } - return out; -} - -skill [int] listConvertStringsToSkills(string [int] list) -{ - skill [int] out; - foreach key, s in list - { - out.listAppend(s.to_skill()); - } - return out; -} - -monster [int] listConvertStringsToMonsters(string [int] list) -{ - monster [int] out; - foreach key, s in list - { - out.listAppend(s.to_monster()); - } - return out; -} - -int [int] stringToIntIntList(string input, string delimiter) -{ - int [int] out; - if (input == "") - return out; - foreach key, v in input.split_string(delimiter) - { - if (v == "") continue; - out.listAppend(v.to_int()); - } - return out; -} - -int [int] stringToIntIntList(string input) -{ - return stringToIntIntList(input, ","); -} diff --git a/Source/relay/TourGuide/Support/Location Choice.ash b/Source/relay/TourGuide/Support/Location Choice.ash deleted file mode 100644 index 4cc83862..00000000 --- a/Source/relay/TourGuide/Support/Location Choice.ash +++ /dev/null @@ -1,75 +0,0 @@ -record LocationChoice -{ - location place; - string [int] reasons; - int importance; -}; - -LocationChoice LocationChoiceMake(location place, string [int] reasons, int importance) -{ - LocationChoice result; - result.place = place; - result.reasons = reasons; - result.importance = importance; - return result; -} - -LocationChoice LocationChoiceMake(location place, string reason, int importance) -{ - return LocationChoiceMake(place, listMake(reason), importance); -} - -LocationChoice LocationChoiceMake(location place, string reason) -{ - return LocationChoiceMake(place, reason, 0); -} - -void listAppend(LocationChoice [int] list, LocationChoice entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -void LocationChoiceSort(LocationChoice [int] list) -{ - sort list by value.importance; -} - -string [int] LocationChoiceGenerateDescription(LocationChoice [int] list) -{ - string [int] description; - foreach key in list - { - LocationChoice lc = list[key]; - string [int] explanation = lc.reasons; - - if (explanation.count() == 0) - continue; - string first = lc.place.to_string(); - if (lc.place == $location[none]) - first = ""; - - string line; - if (explanation.count() > 1) - { - line = first + HTMLGenerateIndentedText(HTMLGenerateDiv(explanation.listJoinComponents("
"))); - } - else - { - line = listFirstObject(explanation); - if (line.stringHasPrefix("|") || first == "") - line = first + line; - else - line = first + ": " + line; - } - //string line = first + HTMLGenerateIndentedText(HTMLGenerateDiv(explanation.listJoinComponents(HTMLGenerateDivOfStyle("", "border-top:1px solid;width:30%;")))); - if (!locationAvailable(lc.place) && lc.place != $location[none]) - { - line = HTMLGenerateDivOfClass(line, "r_future_option"); - } - description.listAppend(line); - } - return description; -} \ No newline at end of file diff --git a/Source/relay/TourGuide/Support/LocationAvailable.ash b/Source/relay/TourGuide/Support/LocationAvailable.ash deleted file mode 100644 index e054b7e4..00000000 --- a/Source/relay/TourGuide/Support/LocationAvailable.ash +++ /dev/null @@ -1,1197 +0,0 @@ -//Library for checking if any given location is unlocked. -//Similar to canadv.ash, except there's no code for using items and no URLs are (currently) visited. This limits our accuracy. -//Currently, most locations are missing, sorry. -import "relay/TourGuide/Support/Error.ash" -import "relay/TourGuide/Support/List.ash" -import "relay/TourGuide/Support/Library.ash" -import "relay/TourGuide/Support/Campground.ash" -import "relay/TourGuide/Settings.ash" -import "relay/TourGuide/QuestState.ash" - - -boolean [location] __la_location_is_available; -boolean [string] __la_zone_is_unlocked; - -boolean __la_commons_were_inited = false; -int __la_turncount_initialised_on = -1; - - -float [monster] appearance_rates_adjusted(location l, boolean account_for_queue) -{ - float [monster] source = l.appearance_rates(account_for_queue); - - boolean lawyers_relocated = get_property_ascension("relocatePygmyLawyer"); - boolean janitors_relocated = get_property_ascension("relocatePygmyJanitor"); - if (l == $location[the hidden park]) - { - if (!janitors_relocated && source contains $monster[pygmy janitor]) - remove source[$monster[pygmy janitor]]; - if (!lawyers_relocated && source contains $monster[pygmy witch lawyer]) - remove source[$monster[pygmy witch lawyer]]; - } - if (($locations[The Hidden Apartment Building,The Hidden Bowling Alley,The Hidden Hospital,The Hidden Office Building] contains l)) - { - if (janitors_relocated && (source contains $monster[pygmy janitor])) - remove source[$monster[pygmy janitor]]; - if (lawyers_relocated && (source contains $monster[pygmy witch lawyer])) - remove source[$monster[pygmy witch lawyer]]; - } - if ($locations[domed city of grimacia,domed city of ronaldus] contains l) - { - //appearance_rates() currently doesn't handle the relation between aliens and moonlight - boolean [monster] aliens; - boolean [monster] survivors; - float actual_percent_aliens = 0.0; - - - if (l == $location[domed city of grimacia]) - { - aliens = $monsters[cat-alien,dog-alien,alielf]; - survivors = $monsters[unhinged survivor,grizzled survivor,whiny survivor]; - int grimace_phase = moon_phase() / 2; - int grimace_darkness = abs(grimace_phase - 4); - int grimace_light = 4 - grimace_darkness; - if (grimace_light < 2) - actual_percent_aliens = 0.0; - else - actual_percent_aliens = 8.0 * grimace_light; - } - else - { - aliens = $monsters[dogcat,hamsterpus,ferrelf]; - survivors = $monsters[unlikely survivor,overarmed survivor,primitive survivor]; - int ronald_phase = moon_phase() % 8; - int ronald_darkness = abs(ronald_phase - 4); - int ronald_light = 4 - ronald_darkness; - if (ronald_light < 2) - actual_percent_aliens = 0.0; - else - actual_percent_aliens = 8.0 * ronald_light; - } - //Readjust: - if (actual_percent_aliens == 0.0) - { - foreach m, rate in source - { - if (aliens contains m) - remove source[m]; - } - } - else - { - float source_percent_aliens = 0.0; - float source_percent_survivors = 0.0; - foreach m, rate in source - { - if (aliens contains m) - source_percent_aliens += rate; - if (survivors contains m) - source_percent_survivors += rate; - } - foreach m, rate in source - { - if (aliens contains m && source_percent_aliens != 0.0) - source[m] = rate / source_percent_aliens * actual_percent_aliens; - if (survivors contains m && source_percent_survivors != 0.0) - source[m] = rate / source_percent_survivors * (100.0 - actual_percent_aliens); - } - } - - } - if (l == $location[The Nemesis' Lair]) - { - boolean [monster] all_monsters_to_remove = $monsters[hellseal guardian,Gorgolok\, the Infernal Seal (Inner Sanctum),warehouse worker,Stella\, the Turtle Poacher (Inner Sanctum),evil spaghetti cult zealot,Spaghetti Elemental (Inner Sanctum),security slime,Lumpy\, the Sinister Sauceblob (Inner Sanctum),daft punk,Spirit of New Wave (Inner Sanctum),mariachi bruiser,Somerset Lopez\, Dread Mariachi (Inner Sanctum)]; - - boolean [monster] monsters_not_to_remove; - if (my_class() == $class[seal clubber]) - monsters_not_to_remove = $monsters[hellseal guardian,Gorgolok\, the Infernal Seal (Inner Sanctum)]; - else if (my_class() == $class[turtle tamer]) - monsters_not_to_remove = $monsters[warehouse worker,Stella\, the Turtle Poacher (Inner Sanctum)]; - else if (my_class() == $class[pastamancer]) - monsters_not_to_remove = $monsters[evil spaghetti cult zealot,Spaghetti Elemental (Inner Sanctum)]; - else if (my_class() == $class[sauceror]) - monsters_not_to_remove = $monsters[security slime,Lumpy\, the Sinister Sauceblob (Inner Sanctum)]; - else if (my_class() == $class[disco bandit]) - monsters_not_to_remove = $monsters[daft punk,Spirit of New Wave (Inner Sanctum)]; - else if (my_class() == $class[accordion thief]) - monsters_not_to_remove = $monsters[mariachi bruiser,Somerset Lopez\, Dread Mariachi (Inner Sanctum)]; - foreach m in all_monsters_to_remove - { - if (monsters_not_to_remove contains m) - continue; - remove source[m]; - } - } - - - //change the NC rate manually when we suspect mafia got it wrong - float original_combat_rate = 100.0 - source[$monster[none]]; - float new_combat_rate = -1.0; - - if (l == $location[the sleazy back alley]) //FIXME is mafia's data files incorrect, or the wiki's? - new_combat_rate = clampf(80.0 + combat_rate_modifier(), 0, 100); - - // @todo Update this once mafia is fixed. - if ($locations[The Dark Elbow of the Woods,The Dark Heart of the Woods,The Dark Neck of the Woods] contains l) - new_combat_rate = clampf(95.0 + combat_rate_modifier(), 0, 100); - - if (l == $location[Inside the Palindome]) - if (!questPropertyPastInternalStepNumber("questL11Palindome", 3)) - new_combat_rate = 100.0; - - //Readjust: - if (new_combat_rate == 0.0) - { - foreach m, rate in source - if (rate > 0.0) - source[m] = 0.0; - source[$monster[none]] = 100.0; - } - else if (original_combat_rate != new_combat_rate && new_combat_rate > 0.0 && original_combat_rate > 0.0) - { - source[$monster[none]] = 100.0 - new_combat_rate; - - float ratio = new_combat_rate / original_combat_rate; - foreach m, rate in source - { - if (m == $monster[none]) - continue; - if (rate > 0.0) - source[m] = rate * ratio; - } - } - - //for monsters which always appear every X adventures, which mafia returns as 0 when not about to get them. - //Currently doesn't support cases when mafia is not aware that the encounter is periodically scheduled. Currently "peanut" from the calaginous abyss - void averagePediodicSuperlikely(monster superlikely_monster, int frequency) - { - float combat_rate = clampf(100.0 - source[$monster[none]], 0.0, 100.0); - if (combat_rate == 0.0) return; - if (source[superlikely_monster] != 0) return; - - float superlikely_average_occurence = 1.0 / frequency; - source[superlikely_monster] = superlikely_average_occurence * combat_rate; - //If, let's say, we have 4 monsters (25% occurence), with a superlikely occuring every 2 turns (1 / 2 = 50%) - //the 4 monsters' 25% (obviously giving 100%) + the SL's 50% give 150% combat chance: 3/2 the combat rate. - //if we divide the 4 monsters' rate by 3/2, we get 16.6. Not quite. - //To get them to 12.5% (which, when *4, gives 50%, which, when added the SL's rate, equals the combat rate), - //we say that the ratio is 1 + (1 / (x-1)) - //here this gives 1 + (1 / (2-1)) = 200% = 2/1 the combat rate - //25% (the 4 monsters' appearance rate) / (2/1) = 12.5% - float excess_ratio = 1.0 + 1.0 / (frequency - 1); - - foreach m, v in source - { - if (m == $monster[none] || m == superlikely_monster) - continue; - if (v > 0.0) - source[m] = v / excess_ratio * combat_rate / 100.0; - } - } - - if ($locations[Guano Junction,the Batrat and Ratbat Burrow,the Beanbat Chamber] contains l) - $monster[screambat].averagePediodicSuperlikely(8); - - if (l == $location[kokomo resort]) - $monster[Brick Mulligan, the Bartender].averagePediodicSuperlikely(25); - - if (l == $location[The Post-Mall]) - $monster[sentient ATM].averagePediodicSuperlikely(11); - - - return source; -} - -float [monster] appearance_rates_adjusted(location l) -{ - return appearance_rates_adjusted(l, false); -} - - -float [monster] appearance_rates_cancel_nc(float [monster] base_rates) -{ - if (base_rates[$monster[none]] == 100.0) return base_rates; - - float combat_rate_sum = 0.0; - foreach m, rate in base_rates - { - if (m == $monster[none]) - continue; - if (rate > 0.0) - combat_rate_sum += rate; - } - if (combat_rate_sum != 100.0 && combat_rate_sum != 0.0) - { - float divisor = combat_rate_sum / 100.0; - - foreach m, rate in base_rates - { - if (m == $monster[none]) - continue; - if (rate > 0.0) - base_rates[m] /= divisor; - } - } - - return base_rates; -} - -float [monster] appearance_rates_adjusted_cancel_nc(location l) -{ - float [monster] base_rates = appearance_rates_adjusted(l); - return base_rates.appearance_rates_cancel_nc(); -} - -//Do not call - internal implementation detail. -boolean locationAvailablePrivateCheck(location loc, Error able_to_find) -{ - string zone = loc.zone; - - if (zone == "KOL High School") - { - if (my_path().id == PATH_KOLHS) - return true; - return false; - } - if (zone == "Mothership") - { - if (my_path().id == PATH_BUGBEAR_INVASION) - return true; - return false; - } - if (zone == "BadMoon") - { - if (in_bad_moon()) - return true; - return false; - } - if ($strings[Crimbo05,Crimbo14,Crimbo15,Crimbo16] contains zone) - return false; - if (zone == "Woods" && !__la_zone_is_unlocked["Woods"]) - return false; - if (loc.parentdesc == "Batfellow Area") - return limit_mode() == "batman"; - if (zone == "Spelunky Area") - return limit_mode() == "spelunky"; - if (zone == "Twitch") - return get_property_boolean("timeTowerAvailable"); - if (zone == "The Prince's Ball") - return get_property("grimstoneMaskPath").to_lower_case() == "stepmother" && get_property_int("cinderellaMinutesToMidnight") > 0; - - if (loc == $location[The Hippy Camp]) - { - //FIXME we don't know who won the war, do we? so only give information if the war hasn't started - if (get_property_ascension("lastIslandUnlock")) - { - if (!QuestState("questL12War").started) return true; - } - else - return false; - } - - switch (loc) - { - case $location[The Castle in the Clouds in the Sky (Ground floor)]: - return get_property_ascension("lastCastleGroundUnlock"); - case $location[The Castle in the Clouds in the Sky (Top floor)]: - return get_property_ascension("lastCastleTopUnlock"); - case $location[The Haunted Kitchen]: - case $location[The Haunted Conservatory]: - return questPropertyPastInternalStepNumber("questM20Necklace", 1); - case $location[The Haunted Billiards Room]: - if ($item[7301].available_amount() > 0) - return true; - else - return false; - //return get_property_ascension("lastManorUnlock"); - case $location[The Haunted Bedroom]: - case $location[The Haunted Bathroom]: - case $location[the haunted gallery]: - return get_property_ascension("lastSecondFloorUnlock") && QuestState("questM21Dance").started; - case $location[the haunted ballroom]: - return questPropertyPastInternalStepNumber("questM21Dance", 4); - case $location[The Haunted Laboratory]: - case $location[The Haunted Nursery]: - case $location[The Haunted Storage Room]: - return questPropertyPastInternalStepNumber("questM17Babies", 1); - case $location[The Haunted Boiler Room]: - case $location[The Haunted Laundry Room]: - case $location[The Haunted Wine Cellar]: - return questPropertyPastInternalStepNumber("questL11Manor", 2); - case $location[summoning chamber]: - return get_property("questL11Manor") == "finished"; - case $location[the batrat and ratbat burrow]: - return questPropertyPastInternalStepNumber("questL04Bat", 2); - case $location[the beanbat chamber]: - return questPropertyPastInternalStepNumber("questL04Bat", 3); - case $location[The Unquiet Garves]: - return true; - case $location[The VERY Unquiet Garves]: - return get_property("questL07Cyrptic") == "finished"; - case $location[The Wreck of the Edgar Fitzsimmons]: - return questPropertyPastInternalStepNumber("questS02Monkees", 2); - case $location[the boss bat\'s lair]: - if (get_property("questL04Bat") == "finished") return false; //area closes - if ($location[the boss bat\'s lair].combatTurnsAttemptedInLocation() > 0) - return true; - return questPropertyPastInternalStepNumber("questL04Bat", 4); - case $location[cobb\'s knob barracks]: - case $location[cobb\'s knob kitchens]: - case $location[cobb\'s knob harem]: - case $location[cobb\'s knob treasury]: - string quest_value = get_property("questL05Goblin"); - if (quest_value == "finished") - return true; - else if (questPropertyPastInternalStepNumber("questL05Goblin", 1)) - { - //Inference - quest is started. If map is missing, area must be unlocked - if ($item[cobb\'s knob map].available_amount() > 0) - return false; - else //no map, must be available - return true; - } - //unstarted, impossible - return false; - case $location[Vanya\'s Castle Chapel]: - if ($item[map to Vanya\'s Castle].available_amount() > 0) - return true; - return false; - case $location[lair of the ninja snowmen]: - case $location[the extreme slope]: - return questPropertyPastInternalStepNumber("questL08Trapper", 3); - case $location[the hidden park]: - return questPropertyPastInternalStepNumber("questL11Worship", 4); - case $location[the hidden temple]: - return get_property_ascension("lastTempleUnlock"); - case $location[the spooky forest]: - return __la_zone_is_unlocked["Woods"]; - case $location[The Smut Orc Logging Camp]: - return questPropertyPastInternalStepNumber("questL09Topping", 1); - case $location[the black forest]: - return questPropertyPastInternalStepNumber("questL11MacGuffin", 1); - case $location[guano junction]: - case $location[the bat hole entrance]: - return questPropertyPastInternalStepNumber("questL04Bat", 1); - case $location[itznotyerzitz mine]: - return questPropertyPastInternalStepNumber("questL08Trapper", 2); - case $location[the arid, extra-dry desert]: - return (questPropertyPastInternalStepNumber("questL11MacGuffin", 3) || $item[your father\'s MacGuffin diary].available_amount() > 0); - case $location[the oasis]: - return (get_property_int("desertExploration") > 0) && (questPropertyPastInternalStepNumber("questL11MacGuffin", 3) || $item[your father\'s MacGuffin diary].available_amount() > 0); - case $location[the defiled alcove]: - return questPropertyPastInternalStepNumber("questL07Cyrptic", 1) && get_property_int("cyrptAlcoveEvilness") > 0; - case $location[the defiled cranny]: - return questPropertyPastInternalStepNumber("questL07Cyrptic", 1) && get_property_int("cyrptCrannyEvilness") > 0; - case $location[the defiled niche]: - return questPropertyPastInternalStepNumber("questL07Cyrptic", 1) && get_property_int("cyrptNicheEvilness") > 0; - case $location[the defiled nook]: - return questPropertyPastInternalStepNumber("questL07Cyrptic", 1) && get_property_int("cyrptNookEvilness") > 0; - case $location[south of the border]: - case $location[The Shore\, Inc. Travel Agency]: - return get_property_ascension("lastDesertUnlock"); - case $location[Portal to Terrible Parents]: - case $location[Rumpelstiltskin\'s Workshop]: - case $location[Ye Olde Medievale Villagee]: - return (get_property("grimstoneMaskPath") == "gnome"); - case $location[the mansion of dr. weirdeaux]: - case $location[the secret government laboratory]: - case $location[the deep dark jungle]: - return $item[airplane charter: Conspiracy Island].is_unrestricted() && (get_property_boolean("_spookyAirportToday") || get_property_boolean("spookyAirportAlways")); - case $location[the fun-guy mansion]: - case $location[sloppy seconds diner]: - case $location[the sunken party yacht]: - return $item[airplane charter: Spring Break Beach].is_unrestricted() && (get_property_boolean("_sleazeAirportToday") || get_property_boolean("sleazeAirportAlways")); - case $location[Pirates of the Garbage Barges]: - case $location[Barf Mountain]: - case $location[The Toxic Teacups]: - case $location[Uncle Gator\'s Country Fun-Time Liquid Waste Sluice]: - return $item[airplane charter: Dinseylandfill].is_unrestricted() && (get_property_boolean("_stenchAirportToday") || get_property_boolean("stenchAirportAlways")); - case $location[The SMOOCH Army HQ]: - case $location[The Velvet / Gold Mine]: - case $location[LavaCo™ Lamp Factory]: - case $location[The Bubblin\' Caldera]: - return $item[airplane charter: That 70s Volcano].is_unrestricted() && (get_property_boolean("_hotAirportToday") || get_property_boolean("hotAirportAlways")); - case $location[The Ice Hotel]: - case $location[VYKEA]: - case $location[The Ice Hole]: - return $item[airplane charter: The Glaciest].is_unrestricted() && (get_property_boolean("_coldAirportToday") || get_property_boolean("coldAirportAlways")); - case $location[Kokomo Resort]: - return $effect[Tropical Contact High].have_effect() > 0; - case $location[Dreadsylvanian Woods]: - case $location[Dreadsylvanian Village]: - case $location[Dreadsylvanian Castle]: - //FIXME not correct - does not take account whether the dungeon is open and the areas are unlocked - return get_clan_id() > 0 && my_level() >= 15; - case $location[A Barroom Brawl]: - return questPropertyPastInternalStepNumber("questL03Rat", 1); - case $location[The Laugh Floor]: - case $location[Pandamonium Slums]: - case $location[Infernal Rackets Backstage]: - return get_property("questL06Friar") == "finished"; - case $location[The Degrassi Knoll Restroom]: - case $location[The Degrassi Knoll Bakery]: - case $location[The Degrassi Knoll Gym]: - case $location[The Degrassi Knoll Garage]: - return !knoll_available(); - case $location[Thugnderdome]: - return gnomads_available() && my_basestat(my_primestat()) >= 25; - case $location[outskirts of camp logging camp]: - case $location[camp logging camp]: - return canadia_available(); - ///FIXME test grimstone masks against their progress? - case $location[Sweet-Ade Lake]: - case $location[Eager Rice Burrows]: - case $location[Gumdrop Forest]: - return get_property("grimstoneMaskPath") == "witch"; - case $location[The Inner Wolf Gym]: - case $location[Unleash Your Inner Wolf]: - return get_property("grimstoneMaskPath") == "wolf"; - case $location[A Deserted Stretch of I-911]: - return get_property("grimstoneMaskPath") == "hare"; - case $location[A-Boo Peak]: - case $location[Twin Peak]: - case $location[Oil Peak]: - return questPropertyPastInternalStepNumber("questL09Topping", 2); - case $location[The Icy Peak]: - return get_property("questL08Trapper") == "finished"; //FIXME is it finished, or after defeating groar? - case $location[the bugbear pen]: - return knoll_available() && questPropertyPastInternalStepNumber("questM03Bugbear", 1) && get_property("questM03Bugbear") != "finished"; - case $location[post-quest bugbear pens]: - return knoll_available() && get_property("questM03Bugbear") == "finished"; - case $location[the thinknerd warehouse]: - return questPropertyPastInternalStepNumber("questM22Shirt", 1); - case $location[The Overgrown Lot]: - return questPropertyPastInternalStepNumber("questM24Doc", 1); - case $location[The Skeleton Store]: - if (questPropertyPastInternalStepNumber("questM23Meatsmith", 1)) - return true; - //otherwise, don't know - break; - case $location[the old landfill]: - return questPropertyPastInternalStepNumber("questM19Hippy", 1); - case $location[The Hidden Apartment Building]: - return get_property_int("hiddenApartmentProgress") >= 1; - case $location[The Hidden Bowling Alley]: - return get_property_int("hiddenBowlingAlleyProgress") >= 1; - case $location[The Hidden Hospital]: - return get_property_int("hiddenHospitalProgress") >= 1; - case $location[The Hidden Office Building]: - return get_property_int("hiddenOfficeProgress") >= 1; - case $location[The Enormous Greater-Than Sign]: - return my_basestat(my_primestat()) >= 45 && !get_property_ascension("lastPlusSignUnlock"); - case $location[The dungeons of doom]: - return my_basestat(my_primestat()) >= 45 && get_property_ascension("lastPlusSignUnlock"); - case $location[The "Fun" House]: - return questPropertyPastInternalStepNumber("questG04Nemesis", 6); //FIXME 6 is wrong, but I don't know the right value - case $location[The Dark Neck of the Woods]: - case $location[The Dark Heart of the Woods]: - case $location[The Dark Elbow of the Woods]: - return QuestState("questL06Friar").in_progress; - case $location[The Goatlet]: - return questPropertyPastInternalStepNumber("questL08Trapper", 1); - case $location[The Penultimate Fantasy Airship]: - return questPropertyPastInternalStepNumber("questL10Garbage", 2); - case $location[anger man\'s level]: - case $location[fear man\'s level]: - case $location[doubt man\'s level]: - case $location[regret man\'s level]: - return __campground[$item[jar of psychoses (The Crackpot Mystic)]] > 0; - case $location[the gourd!]: - return __campground[$item[jar of psychoses (The Captain of the Gourd)]] > 0; - case $location[The Nightmare Meatrealm]: - return __campground[$item[jar of psychoses (The Meatsmith)]] > 0; - case $location[A Kitchen Drawer]: - case $location[A Grocery Bag]: - return __campground[$item[jar of psychoses (The Pretentious Artist)]] > 0; - case $location[Chinatown Shops]: //needs tracking for the quest? maybe use the items? - return __campground[$item[jar of psychoses (The Suspicious-Looking Guy)]] > 0 && $item[strange goggles].available_amount() == 0; - case $location[Triad Factory]: - return $item[zaibatsu lobby card].available_amount() > 0 && $item[strange goggles].available_amount() == 0 && __campground[$item[jar of psychoses (The Suspicious-Looking Guy)]] > 0; - //case $location[1st Floor, Shiawase-Mitsuhama Building]: - //case $location[2nd Floor, Shiawase-Mitsuhama Building]: - //case $location[3rd Floor, Shiawase-Mitsuhama Building]: - case $location[Chinatown Tenement]: - return $item[test site key].available_amount() > 0 && __campground[$item[jar of psychoses (The Suspicious-Looking Guy)]] > 0; - case $location[whitey\'s grove]: - return questPropertyPastInternalStepNumber("questG02Whitecastle", 1) || questPropertyPastInternalStepNumber("questL11Palindome", 4); //FIXME what step for questL11Palindome? - case $location[The Road to the White Citadel]: - return questPropertyPastInternalStepNumber("questG02Whitecastle", 2) && !questPropertyPastInternalStepNumber("questG02Whitecastle", 11); // the road closes when the White Citadel is found - case $location[the Obligatory pirate\'s cove]: - return get_property_ascension("lastIslandUnlock") && !(QuestState("questL12War").mafia_internal_step >= 2 && !QuestState("questL12War").finished); - case $location[Inside the Palindome]: - return $item[talisman o\' namsilat].equipped_amount() > 0; //technically - case $location[The Valley of Rof L\'m Fao]: - return QuestState("questL09Topping").finished; - case $location[Swamp Beaver Territory]: - return get_property_boolean("maraisBeaverUnlock"); - case $location[The Corpse Bog]: - return get_property_boolean("maraisCorpseUnlock"); - case $location[The Dark and Spooky Swamp]: - return get_property_boolean("maraisDarkUnlock"); - case $location[The Weird Swamp Village]: - return get_property_boolean("maraisVillageUnlock"); - case $location[The Wildlife Sanctuarrrrrgh]: - return get_property_boolean("maraisWildlifeUnlock"); - case $location[The Ruined Wizard Tower]: - return get_property_boolean("maraisWizardUnlock"); - case $location[The Edge of the Swamp]: - return QuestState("questM18Swamp").started; - case $location[madness bakery]: - return QuestState("questM25Armorer").started; - case $location[sonofa beach]: - return QuestState("questL12War").mafia_internal_step >= 2; - case $location[the spooky gravy burrow]: - return QuestState("questM03Bugbear").mafia_internal_step >= 3; - case $location[The Copperhead Club]: - return QuestState("questL11MacGuffin").mafia_internal_step >= 3; //FIXME no idea, diary? - case $location[A mob of zeppelin protesters]: - return QuestState("questL11MacGuffin").mafia_internal_step >= 3; //FIXME no idea, diary? - case $location[The Red Zeppelin]: - return QuestState("questL11MacGuffin").mafia_internal_step >= 3 && get_property_int("zeppelinProtestors") >= 80; //FIXME not quite right, diary?; also NC needs to be visited first - case $location[The F\'c\'le]: - return QuestState("questM12Pirate").mafia_internal_step >= 6; - case $location[Belowdecks]: - return QuestState("questM12Pirate").finished; - default: - break; - } - - ErrorSet(able_to_find, ""); - return false; -} - -void locationAvailablePrivateInit() -{ - if (__la_commons_were_inited && __la_turncount_initialised_on == my_turncount()) - return; - - if (__la_location_is_available.count() > 0) - { - foreach key in __la_location_is_available - { - remove __la_location_is_available[key]; - } - } - if (__la_zone_is_unlocked.count() > 0) - { - foreach key in __la_zone_is_unlocked - { - remove __la_zone_is_unlocked[key]; - } - } - - boolean [location] locations_always_available = $locations[the haunted pantry,the sleazy back alley,the outskirts of cobb's knob,the limerick dungeon,The Haiku Dungeon,The Daily Dungeon,noob cave,the dire warren]; - foreach loc in locations_always_available - { - if (loc == $location[none]) - continue; - __la_location_is_available[loc] = true; - } - - if (questPropertyPastInternalStepNumber("questL02Larva", 1) || questPropertyPastInternalStepNumber("questG02Whitecastle", 1)) - __la_zone_is_unlocked["Woods"] = true; - - string zones_never_accessible_string = "Gyms,Crimbo06,Crimbo07,Crimbo08,Crimbo09,Crimbo10,The Candy Diorama,Crimbo12,WhiteWed"; - - item [location] locations_unlocked_by_item; - effect [location] locations_unlocked_by_effect; - - item [string] zones_unlocked_by_item; - effect [string] zones_unlocked_by_effect; - - locations_unlocked_by_item[$location[Cobb\'s Knob Laboratory]] = $item[Cobb\'s Knob lab key]; - locations_unlocked_by_item[$location[The Knob Shaft]] = $item[Cobb\'s Knob lab key]; - locations_unlocked_by_item[$location[Cobb\'s Knob Menagerie\, Level 1]] = $item[Cobb\'s Knob Menagerie key]; - locations_unlocked_by_item[$location[Cobb\'s Knob Menagerie\, Level 2]] = $item[Cobb\'s Knob Menagerie key]; - locations_unlocked_by_item[$location[Cobb\'s Knob Menagerie\, Level 3]] = $item[Cobb\'s Knob Menagerie key]; - - locations_unlocked_by_item[$location[The Haunted Library]] = $item[7302]; //library key - locations_unlocked_by_item[$location[The Castle in the Clouds in the Sky (Basement)]] = $item[S.O.C.K.]; - locations_unlocked_by_item[$location[the hole in the sky]] = $item[steam-powered model rocketship]; - if (my_path().id == PATH_EXPLOSION) - { - locations_unlocked_by_item[$location[The Castle in the Clouds in the Sky (Basement)]] = $item[none]; - locations_unlocked_by_item[$location[the hole in the sky]] = $item[none]; - } - - locations_unlocked_by_item[$location[Vanya\'s Castle Foyer]] = $item[map to Vanya\'s Castle]; - - zones_unlocked_by_item["Magic Commune"] = $item[map to the Magic Commune]; - zones_unlocked_by_item["Landscaper"] = $item[Map to The Landscaper\'s Lair]; - zones_unlocked_by_item["Kegger"] = $item[map to the Kegger in the Woods]; - zones_unlocked_by_item["Ellsbury's Claim"] = $item[Map to Ellsbury\'s Claim]; - zones_unlocked_by_item["Memories"] = $item[empty agua de vida bottle]; - zones_unlocked_by_item["Casino"] = $item[casino pass]; - - zones_unlocked_by_effect["Astral"] = $effect[Half-Astral]; - zones_unlocked_by_effect["Spaaace"] = $effect[Transpondent]; - zones_unlocked_by_effect["RabbitHole"] = $effect[Down the Rabbit Hole]; - zones_unlocked_by_effect["Wormwood"] = $effect[Absinthe-Minded]; - zones_unlocked_by_effect["Suburbs"] = $effect[Dis Abled]; - - string [int] zones_never_accessible = split_string_alternate(zones_never_accessible_string, ","); - - boolean [string] zone_accessibility_status = zones_never_accessible.listInvert(); - foreach s in zone_accessibility_status //invert - { - zone_accessibility_status[s] = false; - } - - - foreach loc in $locations[Shivering Timbers,A Skeleton Invasion!,The Cannon Museum,A Swarm of Yeti-Mounted Skeletons,The Bonewall,A Massive Flying Battleship,A Supply Train,The Bone Star,Grim Grimacite Site,A Pile of Old Servers,The Haunted Sorority House,Fightin' Fire,Super-Intense Mega-Grassfire,Fierce Flying Flames,Lord Flameface's Castle Entryway,Lord Flameface's Castle Belfry,Lord Flameface's Throne Room,A Stinking Abyssal Portal,A Scorching Abyssal Portal,A Terrifying Abyssal Portal,A Freezing Abyssal Portal,An Unsettling Abyssal Portal,A Yawning Abyssal Portal,The Space Odyssey Discotheque,The Spirit World,The Crimbonium Mining Camp,WarBear Fortress (First Level),WarBear Fortress (Second Level),WarBear Fortress (Third Level)] - { - __la_location_is_available[loc] = false; - } - - foreach loc in locations_unlocked_by_item - { - if (locations_unlocked_by_item[loc].available_amount() > 0 || locations_unlocked_by_item[loc] == $item[none]) - __la_location_is_available[loc] = true; - else - __la_location_is_available[loc] = false; - } - foreach loc in locations_unlocked_by_effect - { - if (locations_unlocked_by_effect[loc].have_effect() > 0) - __la_location_is_available[loc] = true; - else - __la_location_is_available[loc] = false; - } - - foreach zone in zones_unlocked_by_item - { - if (zones_unlocked_by_item[zone].available_amount() > 0) - zone_accessibility_status[zone] = true; - else - zone_accessibility_status[zone] = false; - } - foreach zone in zones_unlocked_by_effect - { - if (zones_unlocked_by_effect[zone].have_effect() > 0) - zone_accessibility_status[zone] = true; - else - zone_accessibility_status[zone] = false; - } - - - - - foreach loc in $locations[] - { - if (zone_accessibility_status contains (loc.zone)) - __la_location_is_available[loc] = zone_accessibility_status[loc.zone]; - } - - - __la_commons_were_inited = true; - __la_turncount_initialised_on = my_turncount(); -} - -boolean locationAvailable(location loc, Error able_to_find) -{ - locationAvailablePrivateInit(); - if ((__la_location_is_available contains loc)) - return __la_location_is_available[loc]; - - boolean [int] could_find; - boolean is_available = locationAvailablePrivateCheck(loc, able_to_find); - if (able_to_find.was_error) - return false; - __la_location_is_available[loc] = is_available; - - return is_available; -} - -boolean locationAvailable(location loc) -{ - return locationAvailable(loc, ErrorMake()); -} - -void locationAvailableResetCache() -{ - __la_commons_were_inited = false; -} - - - -string [location] LAConvertLocationLookupToLocations(string [string] lookup_map) -{ - string [location] result; - foreach location_name in lookup_map - { - location l = location_name.to_location(); - if (l == $location[none]) - { - if (__setting_debug_mode) - print_html("Location \"" + location_name + "\" does not appear to exist anymore."); - continue; - } - result[l] = lookup_map[location_name]; - } - - return result; -} -static -{ - string [location] __constant_clickable_urls; - void initialiseConstantClickableURLs() - { - string [string] lookup_map; - - lookup_map["Pump Up Muscle"] = "place.php?whichplace=knoll_friendly&action=dk_gym"; - lookup_map["Richard's Hobo Mysticality"] = "clan_hobopolis.php?place=3"; - lookup_map["Richard's Hobo Moxie"] = "clan_hobopolis.php?place=3"; - lookup_map["Richard's Hobo Muscle"] = "clan_hobopolis.php?place=3"; - lookup_map["South of the Border"] = "place.php?whichplace=desertbeach"; - lookup_map["The Oasis"] = "place.php?whichplace=desertbeach"; - lookup_map["The Arid, Extra-Dry Desert"] = "place.php?whichplace=desertbeach"; - lookup_map["The Shore, Inc. Travel Agency"] = "place.php?whichplace=desertbeach"; - lookup_map["The Upper Chamber"] = "pyramid.php"; - lookup_map["The Middle Chamber"] = "pyramid.php"; - lookup_map["The Lower Chambers"] = "pyramid.php"; - lookup_map["Goat Party"] = "casino.php"; - lookup_map["Pirate Party"] = "casino.php"; - lookup_map["Lemon Party"] = "casino.php"; - lookup_map["The Roulette Tables"] = "casino.php"; - lookup_map["The Poker Room"] = "casino.php"; - lookup_map["The Haiku Dungeon"] = "da.php"; - lookup_map["The Limerick Dungeon"] = "da.php"; - lookup_map["The Enormous Greater-Than Sign"] = "da.php"; - lookup_map["The Dungeons of Doom"] = "da.php"; - lookup_map["The Daily Dungeon"] = "da.php"; - lookup_map["[DungeonFAQ - Level 1]"] = "place.php?whichplace=faqdungeon"; - lookup_map["[DungeonFAQ - Level 2]"] = "place.php?whichplace=faqdungeon"; - lookup_map["[DungeonFAQ - Level 3]"] = "place.php?whichplace=faqdungeon"; - lookup_map["A Maze of Sewer Tunnels"] = "clan_hobopolis.php"; - lookup_map["Hobopolis Town Square"] = "clan_hobopolis.php?place=2"; - lookup_map["Burnbarrel Blvd."] = "clan_hobopolis.php?place=4"; - lookup_map["Exposure Esplanade"] = "clan_hobopolis.php?place=5"; - lookup_map["The Heap"] = "clan_hobopolis.php?place=6"; - lookup_map["The Ancient Hobo Burial Ground"] = "clan_hobopolis.php?place=7"; - lookup_map["The Purple Light District"] = "clan_hobopolis.php?place=8"; - lookup_map["The Slime Tube"] = "clan_slimetube.php"; - lookup_map["Dreadsylvanian Woods"] = "clan_dreadsylvania.php"; - lookup_map["Dreadsylvanian Village"] = "clan_dreadsylvania.php"; - lookup_map["Dreadsylvanian Castle"] = "clan_dreadsylvania.php"; - lookup_map["The Briny Deeps"] = "place.php?whichplace=thesea"; - lookup_map["The Brinier Deepers"] = "place.php?whichplace=thesea"; - lookup_map["The Briniest Deepests"] = "place.php?whichplace=thesea"; - lookup_map["An Octopus's Garden"] = "seafloor.php"; - lookup_map["The Wreck of the Edgar Fitzsimmons"] = "seafloor.php"; - lookup_map["Madness Reef"] = "seafloor.php"; - lookup_map["The Mer-Kin Outpost"] = "seafloor.php"; - lookup_map["The Skate Park"] = "seafloor.php"; - lookup_map["The Marinara Trench"] = "seafloor.php"; - lookup_map["Anemone Mine"] = "seafloor.php"; - lookup_map["The Dive Bar"] = "seafloor.php"; - lookup_map["The Coral Corral"] = "seafloor.php"; - lookup_map["Mer-kin Elementary School"] = "sea_merkin.php?seahorse=1"; - lookup_map["Mer-kin Library"] = "sea_merkin.php?seahorse=1"; - lookup_map["Mer-kin Gymnasium"] = "sea_merkin.php?seahorse=1"; - lookup_map["Mer-kin Colosseum"] = "sea_merkin.php?seahorse=1"; - lookup_map["The Caliginous Abyss"] = "seafloor.php"; - lookup_map["Anemone Mine (Mining)"] = "seafloor.php"; - lookup_map["The Sleazy Back Alley"] = "place.php?whichplace=town_wrong"; - lookup_map["The Copperhead Club"] = "place.php?whichplace=town_wrong"; - lookup_map["The Haunted Kitchen"] = "place.php?whichplace=manor1"; - lookup_map["The Haunted Conservatory"] = "place.php?whichplace=manor1"; - lookup_map["The Haunted Library"] = "place.php?whichplace=manor1"; - lookup_map["The Haunted Billiards Room"] = "place.php?whichplace=manor1"; - lookup_map["The Haunted Pantry"] = "place.php?whichplace=manor1"; - lookup_map["The Haunted Gallery"] = "place.php?whichplace=manor2"; - lookup_map["The Haunted Bathroom"] = "place.php?whichplace=manor2"; - lookup_map["The Haunted Bedroom"] = "place.php?whichplace=manor2"; - lookup_map["The Haunted Ballroom"] = "place.php?whichplace=manor2"; - lookup_map["The Haunted Boiler Room"] = "place.php?whichplace=manor4"; - lookup_map["The Haunted Laundry Room"] = "place.php?whichplace=manor4"; - lookup_map["The Haunted Wine Cellar"] = "place.php?whichplace=manor4"; - lookup_map["The Haunted Laboratory"] = "place.php?whichplace=manor3"; - lookup_map["The Haunted Nursery"] = "place.php?whichplace=manor3"; - lookup_map["The Haunted Storage Room"] = "place.php?whichplace=manor3"; - lookup_map["Summoning Chamber"] = "place.php?whichplace=manor4"; - lookup_map["The Hidden Apartment Building"] = "place.php?whichplace=hiddencity"; - lookup_map["The Hidden Hospital"] = "place.php?whichplace=hiddencity"; - lookup_map["The Hidden Office Building"] = "place.php?whichplace=hiddencity"; - lookup_map["The Hidden Bowling Alley"] = "place.php?whichplace=hiddencity"; - lookup_map["The Hidden Park"] = "place.php?whichplace=hiddencity"; - lookup_map["An Overgrown Shrine (Northwest)"] = "place.php?whichplace=hiddencity"; - lookup_map["An Overgrown Shrine (Southwest)"] = "place.php?whichplace=hiddencity"; - lookup_map["An Overgrown Shrine (Northeast)"] = "place.php?whichplace=hiddencity"; - lookup_map["An Overgrown Shrine (Southeast)"] = "place.php?whichplace=hiddencity"; - lookup_map["A Massive Ziggurat"] = "place.php?whichplace=hiddencity"; - lookup_map["The Typical Tavern Cellar"] = "cellar.php"; - lookup_map["The Spooky Forest"] = "place.php?whichplace=woods"; - lookup_map["The Hidden Temple"] = "place.php?whichplace=woods"; - lookup_map["A Barroom Brawl"] = "tavern.php"; - lookup_map["8-Bit Realm"] = "place.php?whichplace=woods"; - lookup_map["Whitey's Grove"] = "place.php?whichplace=woods"; - lookup_map["The Road to the White Citadel"] = "place.php?whichplace=woods"; - lookup_map["The Black Forest"] = "place.php?whichplace=woods"; - lookup_map["The Old Landfill"] = "place.php?whichplace=woods"; - lookup_map["The Bat Hole Entrance"] = "place.php?whichplace=bathole"; - lookup_map["Guano Junction"] = "place.php?whichplace=bathole"; - lookup_map["The Batrat and Ratbat Burrow"] = "place.php?whichplace=bathole"; - lookup_map["The Beanbat Chamber"] = "place.php?whichplace=bathole"; - lookup_map["The Boss Bat's Lair"] = "place.php?whichplace=bathole"; - lookup_map["The Red Queen's Garden"] = "place.php?whichplace=rabbithole"; - lookup_map["The Clumsiness Grove"] = "suburbandis.php"; - lookup_map["The Maelstrom of Lovers"] = "suburbandis.php"; - lookup_map["The Glacier of Jerks"] = "suburbandis.php"; - lookup_map["The Degrassi Knoll Restroom"] = "place.php?whichplace=knoll_hostile"; - lookup_map["The Degrassi Knoll Bakery"] = "place.php?whichplace=knoll_hostile"; - lookup_map["The Degrassi Knoll Gym"] = "place.php?whichplace=knoll_hostile"; - lookup_map["The Degrassi Knoll Garage"] = "place.php?whichplace=knoll_hostile"; - lookup_map["The \"Fun\" House"] = "place.php?whichplace=plains"; - lookup_map["The Unquiet Garves"] = "place.php?whichplace=cemetery"; - lookup_map["The VERY Unquiet Garves"] = "place.php?whichplace=cemetery"; - lookup_map["Tower Ruins"] = "fernruin.php"; - lookup_map["Fernswarthy's Basement"] = "basement.php"; - lookup_map["Cobb's Knob Barracks"] = "cobbsknob.php"; - lookup_map["Cobb's Knob Kitchens"] = "cobbsknob.php"; - lookup_map["Cobb's Knob Harem"] = "cobbsknob.php"; - lookup_map["Cobb's Knob Treasury"] = "cobbsknob.php"; - lookup_map["Throne Room"] = "cobbsknob.php"; - lookup_map["Cobb's Knob Laboratory"] = "cobbsknob.php?action=tolabs"; - lookup_map["The Knob Shaft"] = "cobbsknob.php?action=tolabs"; - lookup_map["The Knob Shaft (Mining)"] = "cobbsknob.php?action=tolabs"; - lookup_map["Cobb's Knob Menagerie, Level 1"] = "cobbsknob.php?action=tomenagerie"; - lookup_map["Cobb's Knob Menagerie, Level 2"] = "cobbsknob.php?action=tomenagerie"; - lookup_map["Cobb's Knob Menagerie, Level 3"] = "cobbsknob.php?action=tomenagerie"; - lookup_map["The Dark Neck of the Woods"] = "friars.php"; - lookup_map["The Dark Heart of the Woods"] = "friars.php"; - lookup_map["The Dark Elbow of the Woods"] = "friars.php"; - lookup_map["Friar Ceremony Location"] = "friars.php"; - lookup_map["Pandamonium Slums"] = "pandamonium.php"; - lookup_map["The Laugh Floor"] = "pandamonium.php?action=beli"; - lookup_map["Infernal Rackets Backstage"] = "pandamonium.php?action=infe"; - lookup_map["The Defiled Nook"] = "crypt.php"; - lookup_map["The Defiled Cranny"] = "crypt.php"; - lookup_map["The Defiled Alcove"] = "crypt.php"; - lookup_map["The Defiled Niche"] = "crypt.php"; - lookup_map["Haert of the Cyrpt"] = "crypt.php"; - lookup_map["The Orcish Frat House"] = "island.php"; - lookup_map["Frat House In Disguise"] = "island.php"; - lookup_map["Frat House (frat disguise)"] = "island.php"; - lookup_map["The Frat House (Bombed Back to the Stone Age)"] = "island.php"; - lookup_map["The Hippy Camp"] = "island.php"; - lookup_map["Hippy Camp In Disguise"] = "island.php"; - lookup_map["Hippy Camp (hippy disguise)"] = "island.php"; - lookup_map["The Hippy Camp (Bombed Back to the Stone Age)"] = "island.php"; - lookup_map["The Obligatory Pirate's Cove"] = "island.php"; - lookup_map["Barrrney's Barrr"] = "place.php?whichplace=cove"; - lookup_map["The F'c'le"] = "place.php?whichplace=cove"; - lookup_map["The Poop Deck"] = "place.php?whichplace=cove"; - lookup_map["Belowdecks"] = "place.php?whichplace=cove"; - lookup_map["Post-War Junkyard"] = "island.php"; - lookup_map["McMillicancuddy's Farm"] = "island.php"; - lookup_map["The Battlefield (Frat Uniform)"] = "bigisland.php"; - lookup_map["The Battlefield (Hippy Uniform)"] = "bigisland.php"; - lookup_map["Wartime Frat House"] = "island.php"; - lookup_map["Wartime Frat House (Hippy Disguise)"] = "island.php"; - lookup_map["Wartime Hippy Camp"] = "island.php"; - lookup_map["Wartime Hippy Camp (Frat Disguise)"] = "island.php"; - lookup_map["Next to that Barrel with Something Burning in it"] = "bigisland.php?place=junkyard"; - lookup_map["Near an Abandoned Refrigerator"] = "bigisland.php?place=junkyard"; - lookup_map["Over Where the Old Tires Are"] = "bigisland.php?place=junkyard"; - lookup_map["Out by that Rusted-Out Car"] = "bigisland.php?place=junkyard"; - lookup_map["Sonofa Beach"] = "bigisland.php?place=lighthouse"; - lookup_map["The Themthar Hills"] = "bigisland.php?place=nunnery"; - lookup_map["McMillicancuddy's Barn"] = "bigisland.php?place=farm"; - lookup_map["McMillicancuddy's Pond"] = "bigisland.php?place=farm"; - lookup_map["McMillicancuddy's Back 40"] = "bigisland.php?place=farm"; - lookup_map["McMillicancuddy's Other Back 40"] = "bigisland.php?place=farm"; - lookup_map["McMillicancuddy's Granary"] = "bigisland.php?place=farm"; - lookup_map["McMillicancuddy's Bog"] = "bigisland.php?place=farm"; - lookup_map["McMillicancuddy's Family Plot"] = "bigisland.php?place=farm"; - lookup_map["McMillicancuddy's Shady Thicket"] = "bigisland.php?place=farm"; - lookup_map["The Hatching Chamber"] = "bigisland.php?place=orchard"; - lookup_map["The Feeding Chamber"] = "bigisland.php?place=orchard"; - lookup_map["The Royal Guard Chamber"] = "bigisland.php?place=orchard"; - lookup_map["The Filthworm Queen's Chamber"] = "bigisland.php?place=orchard"; - lookup_map["Noob Cave"] = "tutorial.php"; - lookup_map["The Dire Warren"] = "tutorial.php"; - lookup_map["The Valley of Rof L'm Fao"] = "place.php?whichplace=mountains"; - lookup_map["Mt. Molehill"] = "place.php?whichplace=mountains"; - lookup_map["The Barrel Full of Barrels"] = "barrel.php"; - lookup_map["The Smut Orc Logging Camp"] = "place.php?whichplace=orc_chasm"; - lookup_map["The Thinknerd Warehouse"] = "place.php?whichplace=mountains"; - lookup_map["A Mob of Zeppelin Protesters"] = "place.php?whichplace=zeppelin"; - lookup_map["The Red Zeppelin"] = "place.php?whichplace=zeppelin"; - lookup_map["A-Boo Peak"] = "place.php?whichplace=highlands"; - lookup_map["Twin Peak"] = "place.php?whichplace=highlands"; - lookup_map["Oil Peak"] = "place.php?whichplace=highlands"; - lookup_map["Itznotyerzitz Mine"] = "place.php?whichplace=mclargehuge"; - lookup_map["The Goatlet"] = "place.php?whichplace=mclargehuge"; - lookup_map["Lair of the Ninja Snowmen"] = "place.php?whichplace=mclargehuge"; - lookup_map["The eXtreme Slope"] = "place.php?whichplace=mclargehuge"; - lookup_map["Mist-Shrouded Peak"] = "place.php?whichplace=mclargehuge"; - lookup_map["The Icy Peak"] = "place.php?whichplace=mclargehuge"; - lookup_map["Itznotyerzitz Mine (in Disguise)"] = "place.php?whichplace=mclargehuge"; - lookup_map["The Penultimate Fantasy Airship"] = "place.php?whichplace=beanstalk"; - lookup_map["The Castle in the Clouds in the Sky (Basement)"] = "place.php?whichplace=giantcastle"; - lookup_map["The Castle in the Clouds in the Sky (Ground Floor)"] = "place.php?whichplace=giantcastle"; - lookup_map["The Castle in the Clouds in the Sky (Top Floor)"] = "place.php?whichplace=giantcastle"; - lookup_map["The Hole in the Sky"] = "place.php?whichplace=beanstalk"; - lookup_map["The Broodling Grounds"] = "volcanoisland.php"; - lookup_map["The Outer Compound"] = "volcanoisland.php"; - lookup_map["The Temple Portico"] = "volcanoisland.php"; - lookup_map["Convention Hall Lobby"] = "volcanoisland.php"; - lookup_map["Outside the Club"] = "volcanoisland.php"; - lookup_map["The Island Barracks"] = "volcanoisland.php"; - lookup_map["The Nemesis' Lair"] = "volcanoisland.php"; - lookup_map["The Bugbear Pen"] = "place.php?whichplace=knoll_friendly"; - lookup_map["The Spooky Gravy Burrow"] = "place.php?whichplace=knoll_friendly"; - lookup_map["The Stately Pleasure Dome"] = "place.php?whichplace=wormwood"; - lookup_map["The Mouldering Mansion"] = "place.php?whichplace=wormwood"; - lookup_map["The Rogue Windmill"] = "place.php?whichplace=wormwood"; - lookup_map["The Primordial Soup"] = "place.php?whichplace=memories"; - lookup_map["The Jungles of Ancient Loathing"] = "place.php?whichplace=memories"; - lookup_map["Seaside Megalopolis"] = "place.php?whichplace=memories"; - lookup_map["Domed City of Ronaldus"] = "place.php?whichplace=spaaace"; - lookup_map["Domed City of Grimacia"] = "place.php?whichplace=spaaace"; - lookup_map["Hamburglaris Shield Generator"] = "place.php?whichplace=spaaace"; - lookup_map["The Arrrboretum"] = "place.php?whichplace=woods"; - lookup_map["Spectral Pickle Factory"] = "place.php?whichplace=plains"; - lookup_map["Lollipop Forest"] = ""; - lookup_map["Fudge Mountain"] = ""; - lookup_map["WarBear Fortress (First Level)"] = ""; - lookup_map["WarBear Fortress (Second Level)"] = ""; - lookup_map["WarBear Fortress (Third Level)"] = ""; - lookup_map["Elf Alley"] = ""; - lookup_map["CRIMBCO cubicles"] = ""; - lookup_map["CRIMBCO WC"] = ""; - lookup_map["Crimbo Town Toy Factory (2005)"] = ""; - lookup_map["The Don's Crimbo Compound"] = ""; - lookup_map["Atomic Crimbo Toy Factory"] = ""; - lookup_map["Crimbo Town Toy Factory (2007)"] = ""; - lookup_map["Sinister Dodecahedron"] = ""; - lookup_map["Crimbo Town Toy Factory (2009)"] = ""; - lookup_map["Simple Tool-Making Cave"] = ""; - lookup_map["Spooky Fright Factory"] = ""; - lookup_map["Crimborg Collective Factory"] = ""; - lookup_map["Crimbo Town Toy Factory (2012)"] = ""; - lookup_map["Market Square, 28 Days Later"] = ""; - lookup_map["The Mall of Loathing, 28 Days Later"] = ""; - lookup_map["Wrong Side of the Tracks, 28 Days Later"] = ""; - lookup_map["The Icy Peak in The Recent Past"] = ""; - lookup_map["Shivering Timbers"] = ""; - lookup_map["A Skeleton Invasion!"] = ""; - lookup_map["The Cannon Museum"] = ""; - lookup_map["A Swarm of Yeti-Mounted Skeletons"] = ""; - lookup_map["The Bonewall"] = ""; - lookup_map["A Massive Flying Battleship"] = ""; - lookup_map["A Supply Train"] = ""; - lookup_map["The Bone Star"] = ""; - lookup_map["Grim Grimacite Site"] = ""; - lookup_map["A Pile of Old Servers"] = ""; - lookup_map["The Haunted Sorority House"] = ""; - lookup_map["Fightin' Fire"] = ""; - lookup_map["Super-Intense Mega-Grassfire"] = ""; - lookup_map["Fierce Flying Flames"] = ""; - lookup_map["Lord Flameface's Castle Entryway"] = ""; - lookup_map["Lord Flameface's Castle Belfry"] = ""; - lookup_map["Lord Flameface's Throne Room"] = ""; - lookup_map["A Stinking Abyssal Portal"] = ""; - lookup_map["A Scorching Abyssal Portal"] = ""; - lookup_map["A Terrifying Abyssal Portal"] = ""; - lookup_map["A Freezing Abyssal Portal"] = ""; - lookup_map["An Unsettling Abyssal Portal"] = ""; - lookup_map["A Yawning Abyssal Portal"] = ""; - lookup_map["The Space Odyssey Discotheque"] = ""; - lookup_map["The Spirit World"] = ""; - lookup_map["Some Scattered Smoking Debris"] = "place.php?whichplace=crashsite"; - lookup_map["Anger Man's Level"] = "place.php?whichplace=junggate_3"; - lookup_map["Fear Man's Level"] = "place.php?whichplace=junggate_3"; - lookup_map["Doubt Man's Level"] = "place.php?whichplace=junggate_3"; - lookup_map["Regret Man's Level"] = "place.php?whichplace=junggate_3"; - lookup_map["The Nightmare Meatrealm"] = "place.php?whichplace=junggate_6"; - lookup_map["A Kitchen Drawer"] = "place.php?whichplace=junggate_5"; - lookup_map["A Grocery Bag"] = "place.php?whichplace=junggate_5"; - lookup_map["Chinatown Shops"] = "place.php?whichplace=junggate_1"; - lookup_map["Triad Factory"] = "place.php?whichplace=junggate_1"; - lookup_map["1st Floor, Shiawase-Mitsuhama Building"] = "place.php?whichplace=junggate_1"; - lookup_map["2nd Floor, Shiawase-Mitsuhama Building"] = "place.php?whichplace=junggate_1"; - lookup_map["3rd Floor, Shiawase-Mitsuhama Building"] = "place.php?whichplace=junggate_1"; - lookup_map["Chinatown Tenement"] = "place.php?whichplace=junggate_1"; - lookup_map["The Gourd!"] = "place.php?whichplace=junggate_2"; - lookup_map["A Deserted Stretch of I-911"] = "place.php?whichplace=ioty2014_hare"; - lookup_map["The Prince's Restroom"] = "place.php?whichplace=ioty2014_cindy"; - lookup_map["The Prince's Dance Floor"] = "place.php?whichplace=ioty2014_cindy"; - lookup_map["The Prince's Kitchen"] = "place.php?whichplace=ioty2014_cindy"; - lookup_map["The Prince's Balcony"] = "place.php?whichplace=ioty2014_cindy"; - lookup_map["The Prince's Lounge"] = "place.php?whichplace=ioty2014_cindy"; - lookup_map["The Prince's Canapes table"] = "place.php?whichplace=ioty2014_cindy"; - lookup_map["The Inner Wolf Gym"] = "place.php?whichplace=ioty2014_wolf"; - lookup_map["Unleash Your Inner Wolf"] = "place.php?whichplace=ioty2014_wolf"; - lookup_map["The Crimbonium Mining Camp"] = "place.php?whichplace=desertbeach"; - lookup_map["Kokomo Resort"] = "place.php?whichplace=desertbeach"; - lookup_map["The Crimbonium Mine"] = "mining.php?mine=5"; - lookup_map["The Secret Council Warehouse"] = "tutorial.php"; - lookup_map["The Skeleton Store"] = "place.php?whichplace=town_market"; - lookup_map["Madness Bakery"] = "place.php?whichplace=town_right"; - lookup_map["Investigating a Plaintive Telegram"] = "place.php?whichplace=town_right"; - lookup_map["The Fungal Nethers"] = "place.php?whichplace=nemesiscave"; - lookup_map["Thugnderdome"] = "gnomes.php"; - lookup_map["The Overgrown Lot"] = "place.php?whichplace=town_wrong"; - lookup_map["The Canadian Wildlife Preserve"] = "place.php?whichplace=mountains"; - foreach s in $strings[The Hallowed Halls,Shop Class,Chemistry Class,Art Class] - lookup_map[s] = "place.php?whichplace=KOLHS"; - foreach s in $strings[The Edge of the Swamp,The Dark and Spooky Swamp,The Corpse Bog,The Ruined Wizard Tower,The Wildlife Sanctuarrrrrgh,Swamp Beaver Territory,The Weird Swamp Village] - lookup_map[s] = "place.php?whichplace=marais"; - foreach s in $strings[Ye Olde Medievale Villagee,Portal to Terrible Parents,Rumpelstiltskin's Workshop] - lookup_map[s] = "place.php?whichplace=ioty2014_rumple"; - - foreach s in $strings[The Cave Before Time,An Illicit Bohemian Party,Moonshiners' Woods,The Roman Forum,The Post-Mall,The Rowdy Saloon,The Spooky Old Abandoned Mine,Globe Theatre Main Stage,Globe Theatre Backstage,12 West Main,KoL Con Clan Party House] - lookup_map[s] = "place.php?whichplace=twitch"; - foreach s in $strings[The Fun-Guy Mansion,Sloppy Seconds Diner,The Sunken Party Yacht] - lookup_map[s] = "place.php?whichplace=airport_sleaze"; - foreach s in $strings[The Mansion of Dr. Weirdeaux,The Deep Dark Jungle,The Secret Government Laboratory] - lookup_map[s] = "place.php?whichplace=airport_spooky"; - foreach s in $strings[Pirates of the Garbage Barges,Barf Mountain,The Toxic Teacups,Uncle Gator's Country Fun-Time Liquid Waste Sluice] - lookup_map[s] = "place.php?whichplace=airport_stench"; - foreach s in $strings[The SMOOCH Army HQ,The Velvet / Gold Mine,LavaCo™ Lamp Factory,The Bubblin' Caldera] - lookup_map[s] = "place.php?whichplace=airport_hot"; - foreach s in $strings[The Ice Hotel,VYKEA,The Ice Hole] - lookup_map[s] = "place.php?whichplace=airport_cold"; - lookup_map["The Velvet / Gold Mine (Mining)"] = "mining.php?mine=6"; - foreach s in $strings[The Mines,The Jungle,The Ice Caves,The Temple Ruins,Hell,The Snake Pit,The Spider Hole,The Ancient Burial Ground,The Beehive,the crashed u. f. o.,The City of Goooold,LOLmec's Lair,Yomama's Throne] - lookup_map[s] = "place.php?whichplace=spelunky"; - - foreach s in $strings[Medbay,Waste Processing,Sonar,Science Lab,Morgue,Special Ops,Engineering,Navigation,Galley] - lookup_map[s] = "place.php?whichplace=bugbearship"; - foreach s in $strings[Sweet-Ade Lake,Eager Rice Burrows,Gumdrop Forest] - lookup_map[s] = "place.php?whichplace=ioty2014_candy"; - foreach s in $strings[Gingerbread Industrial Zone,Gingerbread Train Station,Gingerbread Sewers,Gingerbread Upscale Retail District] - lookup_map[s] = "place.php?whichplace=gingerbreadcity"; - - foreach s in $strings[Fastest Adventurer Contest,Strongest Adventurer Contest,Smartest Adventurer Contest,Smoothest Adventurer Contest,A Crowd of (Stat) Adventurers,Hottest Adventurer Contest,Coldest Adventurer Contest,Spookiest Adventurer Contest,Stinkiest Adventurer Contest,Sleaziest Adventurer Contest,A Crowd of (Element) Adventurers,The Hedge Maze,Tower Level 1,Tower Level 2,Tower Level 3,Tower Level 4,Tower Level 5,The Naughty Sorceress' Chamber] - lookup_map[s] = "place.php?whichplace=nstower"; - - lookup_map["Trick-or-treating"] = "place.php?whichplace=town&action=town_trickortreat"; - lookup_map["The Deep Machine Tunnels"] = "place.php?whichplace=dmt"; - - lookup_map["The Ruins of the Fully Automated Crimbo Factory"] = "place.php?whichplace=crimbo2015"; - lookup_map["The X-32-F Combat Training Snowman"] = "place.php?whichplace=snojo"; - foreach s in $strings[Your Bung Chakra,Your Guts Chakra,Your Liver Chakra,Your Nipple Chakra,Your Nose Chakra,Your Hat Chakra] - lookup_map[s] = "place.php?whichplace=crimbo2016m"; - foreach s in $strings[Crimbo's Sack,Crimbo's Boots,Crimbo's Jelly,Crimbo's Reindeer,Crimbo's Beard,Crimbo's Hat] - lookup_map[s] = "place.php?whichplace=crimbo2016c"; - foreach s in $strings[The Cheerless Spire (Level 1), The Cheerless Spire (Level 2), The Cheerless Spire (Level 3), The Cheerless Spire (Level 4), The Cheerless Spire (Level 5)] - lookup_map[s] = "place.php?whichplace=crimbo17_silentnight"; - foreach s in $strings[The Bandit Crossroads,The Putrid Swamp,Near the Witch's House,The Troll Fortress,The Sprawling Cemetery,The Cursed Village,The Foreboding Cave,The Faerie Cyrkle,The Evil Cathedral,The Towering Mountains,The Mystic Wood,The Druidic Campsite,The Old Rubee Mine] - lookup_map[s] = "place.php?whichplace=realm_fantasy"; - foreach s in $strings[PirateRealm Island,Sailing the PirateRealm Seas] - lookup_map[s] = "place.php?whichplace=realm_pirate"; - lookup_map["An Eldritch Horror"] = "place.php?whichplace=town"; - lookup_map["The Neverending Party"] = "place.php?whichplace=town_wrong"; - lookup_map["Through the Spacegate"] = "place.php?whichplace=spacegate"; - lookup_map["The Exploaded Battlefield"] = "place.php?whichplace=exploathing"; - __constant_clickable_urls = LAConvertLocationLookupToLocations(lookup_map); - } - initialiseConstantClickableURLs(); -} - -string [location] __variable_clickable_urls; -string getClickableURLForLocation(location l, Error unable_to_find_url) -{ - if (l == $location[none]) - return ""; - if (__constant_clickable_urls contains l) - return __constant_clickable_urls[l]; - - if (__variable_clickable_urls.count() == 0) - { - //Initialize: - //We use to_location() lookups here because $location[] will halt the script if the location name changes. - //Probably could move this to an external data file. - string [string] lookup_map; - - //Conditionals only: - if ($location[cobb\'s knob barracks].locationAvailable()) - lookup_map["The Outskirts of Cobb's Knob"] = "cobbsknob.php"; - else - lookup_map["The Outskirts of Cobb's Knob"] = "place.php?whichplace=plains"; - - if (knoll_available()) - lookup_map["Post-Quest Bugbear Pens"] = "place.php?whichplace=knoll_friendly"; - else - lookup_map["Post-Quest Bugbear Pens"] = "place.php?whichplace=knoll_hostile"; - - if ($item[talisman o\' namsilat].equipped_amount() > 0) - lookup_map["Inside the Palindome"] = "place.php?whichplace=palindome"; - else - lookup_map["Inside the Palindome"] = "inventory.php?ftext=talisman+o\'+namsilat"; - //antique maps are weird: - lookup_map["The Electric Lemonade Acid Parade"] = "inv_use.php?pwd=" + my_hash() + "&whichitem=4613"; - foreach s in $strings[Professor Jacking's Small-O-Fier,Professor Jacking's Huge-A-Ma-tron] - lookup_map[s] = "inv_use.php?pwd=" + my_hash() + "&whichitem=4560"; - - //Parse into locations: - __variable_clickable_urls = LAConvertLocationLookupToLocations(lookup_map); - } - if (__variable_clickable_urls contains l) - return __variable_clickable_urls[l]; - - ErrorSet(unable_to_find_url); - return ""; -} - -string getClickableURLForLocation(location l) -{ - return l.getClickableURLForLocation(ErrorMake()); -} - -string getClickableURLForLocationIfAvailable(location l) -{ - Error able_to_find; - boolean found = l.locationAvailable(able_to_find); - if (able_to_find.was_error) //assume it's available, since we don't know - found = true; - if (found) - return l.getClickableURLForLocation(); - else - return ""; -} - - - -void locationAvailableRunDiagnostics() -{ - location [string][int] unknown_locations_by_zone; - - foreach loc in $locations[] - { - Error able_to_find; - locationAvailable(loc, able_to_find); - if (!able_to_find.was_error) - continue; - if (!(unknown_locations_by_zone contains (loc.zone))) - unknown_locations_by_zone[loc.zone] = listMakeBlankLocation(); - unknown_locations_by_zone[loc.zone].listAppend(loc); - } - if (unknown_locations_by_zone.count() > 0) - { - print_html("Unknown locations in location availability tester:"); - foreach zone in unknown_locations_by_zone - { - print(zone + ":"); - foreach key in unknown_locations_by_zone[zone] - { - location loc = unknown_locations_by_zone[zone][key]; - print_html("      " + loc); - } - } - } - /*print_html("Missing URLs:"); - foreach loc in $locations[] - { - if (loc.parent == "Removed") continue; - if (loc.getClickableURLForLocation() == "") - print_html(loc.parent + ": " + loc.zone + ": " + loc); - }*/ -} - -/*void main() -{ - locationAvailableRunDiagnostics(); -}*/ diff --git a/Source/relay/TourGuide/Support/Math.ash b/Source/relay/TourGuide/Support/Math.ash deleted file mode 100644 index 2a72127e..00000000 --- a/Source/relay/TourGuide/Support/Math.ash +++ /dev/null @@ -1,395 +0,0 @@ -import "relay/TourGuide/Support/Error.ash" - -//Coordinate system is upper-left origin. - -int INT32_MAX = 2147483647; - - - -float clampf(float v, float min_value, float max_value) -{ - if (v > max_value) - return max_value; - if (v < min_value) - return min_value; - return v; -} - -float clampNormalf(float v) -{ - return clampf(v, 0.0, 1.0); -} - -int clampi(int v, int min_value, int max_value) -{ - if (v > max_value) - return max_value; - if (v < min_value) - return min_value; - return v; -} - -float clampNormali(int v) -{ - return clampi(v, 0, 1); -} - -//random() will halt the script if range is <= 1, which can happen when picking a random object out of a variable-sized list. -//There's also a hidden bug where values above 2147483647 will be treated as zero. -int random_safe(int range) -{ - if (range < 2 || range > 2147483647) - return 0; - return random(range); -} - -float randomf() -{ - return random_safe(2147483647).to_float() / 2147483647.0; -} - -//to_int will print a warning, but not halt, if you give it a non-int value. -//This function prevents the warning message. -//err is set if value is not an integer. -int to_int_silent(string value, Error err) -{ - //to_int() supports floating-point values. is_integer() will return false. - //So manually strip out everything past the dot. - //We probably should just ask for to_int() to be silent in the first place. - int dot_position = value.index_of("."); - if (dot_position != -1 && dot_position > 0) //two separate concepts - is it valid, and is it past the first position. I like testing against both, for safety against future changes. - { - value = value.substring(0, dot_position); - } - - if (is_integer(value)) - return to_int(value); - ErrorSet(err, "Unknown integer \"" + value + "\"."); - return 0; -} - -int to_int_silent(string value) -{ - return to_int_silent(value, ErrorMake()); -} - -//Silly conversions in case we chose the wrong function, removing the need for a int -> string -> int hit. -int to_int_silent(int value) -{ - return value; -} - -int to_int_silent(float value) -{ - return value; -} - - -float sqrt(float v, Error err) -{ - if (v < 0.0) - { - ErrorSet(err, "Cannot take square root of value " + v + " less than 0.0"); - return -1.0; //mathematically incorrect, but prevents halting. should return NaN - } - return square_root(v); -} - -float sqrt(float v) -{ - return sqrt(v, ErrorMake()); -} - -float fabs(float v) -{ - if (v < 0.0) - return -v; - return v; -} - -int abs(int v) -{ - if (v < 0) - return -v; - return v; -} - -int ceiling(float v) -{ - return ceil(v); -} - -int pow2i(int v) -{ - return v * v; -} - -float pow2f(float v) -{ - return v * v; -} - -//x^p -float powf(float x, float p) -{ - return x ** p; -} - -//x^p -int powi(int x, int p) -{ - return x ** p; -} - -record Vec2i -{ - int x; //or width - int y; //or height -}; - -Vec2i Vec2iMake(int x, int y) -{ - Vec2i result; - result.x = x; - result.y = y; - - return result; -} - -Vec2i Vec2iCopy(Vec2i v) -{ - return Vec2iMake(v.x, v.y); -} - -Vec2i Vec2iZero() -{ - return Vec2iMake(0,0); -} - -boolean Vec2iValueInInterval(Vec2i v, int value) -{ - if (value >= v.x && value <= v.y) - return true; - return false; -} - -boolean Vec2iValueInRange(Vec2i v, int value) -{ - return Vec2iValueInInterval(v, value); -} - -boolean Vec2iEquals(Vec2i a, Vec2i b) -{ - if (a.x != b.x) return false; - if (a.y != b.y) return false; - return true; -} - -string Vec2iDescription(Vec2i v) -{ - buffer out; - out.append("["); - out.append(v.x); - out.append(", "); - out.append(v.y); - out.append("]"); - return out.to_string(); -} - -Vec2i Vec2iIntersection(Vec2i a, Vec2i b) -{ - Vec2i result; - result.x = max(a.x, b.x); - result.y = min(a.y, b.y); - return result; -} - -boolean Vec2iIntersectsWithVec2i(Vec2i a, Vec2i b) -{ - //Assumed [min, max]: - if (a.y < b.x) return false; - if (a.x > b.y) return false; - return true; -} - -record Vec2f -{ - float x; //or width - float y; //or height -}; - -Vec2f Vec2fMake(float x, float y) -{ - Vec2f result; - result.x = x; - result.y = y; - - return result; -} - -Vec2f Vec2fCopy(Vec2f v) -{ - return Vec2fMake(v.x, v.y); -} - -Vec2f Vec2fZero() -{ - return Vec2fMake(0.0, 0.0); -} - -boolean Vec2fValueInRange(Vec2f v, float value) -{ - if (value >= v.x && value <= v.y) - return true; - return false; -} - -Vec2f Vec2fMultiply(Vec2f v, float c) -{ - return Vec2fMake(v.x * c, v.y * c); -} -Vec2f Vec2fAdd(Vec2f v, float c) -{ - return Vec2fMake(v.x + c, v.y + c); -} -float Vec2fAverage(Vec2f v) -{ - return (v.x + v.y) * 0.5; -} - - - -string Vec2fDescription(Vec2f v) -{ - buffer out; - out.append("["); - out.append(v.x); - out.append(", "); - out.append(v.y); - out.append("]"); - return out.to_string(); -} - - -record Rect -{ - Vec2i min_coordinate; - Vec2i max_coordinate; -}; - -Rect RectMake(Vec2i min_coordinate, Vec2i max_coordinate) -{ - Rect result; - result.min_coordinate = Vec2iCopy(min_coordinate); - result.max_coordinate = Vec2iCopy(max_coordinate); - return result; -} - -Rect RectCopy(Rect r) -{ - return RectMake(r.min_coordinate, r.max_coordinate); -} - -Rect RectMake(int min_x, int min_y, int max_x, int max_y) -{ - return RectMake(Vec2iMake(min_x, min_y), Vec2iMake(max_x, max_y)); -} - -Rect RectZero() -{ - return RectMake(Vec2iZero(), Vec2iZero()); -} - - -void listAppend(Rect [int] list, Rect entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -//Allows for fractional digits, not just whole numbers. Useful for preventing "+233.333333333333333% item"-type output. -//Outputs 3.0, 3.1, 3.14, etc. -float round(float v, int additional_fractional_digits) -{ - if (additional_fractional_digits < 1) - return v.round().to_float(); - float multiplier = powf(10.0, additional_fractional_digits); - return to_float(round(v * multiplier)) / multiplier; -} - -//Similar to round() addition above, but also converts whole float numbers into integers for output -string roundForOutput(float v, int additional_fractional_digits) -{ - v = round(v, additional_fractional_digits); - int vi = v.to_int(); - if (vi.to_float() == v) - return vi.to_string(); - else - return v.to_string(); -} - - -float floor(float v, int additional_fractional_digits) -{ - if (additional_fractional_digits < 1) - return v.floor().to_float(); - float multiplier = powf(10.0, additional_fractional_digits); - return to_float(floor(v * multiplier)) / multiplier; -} - -string floorForOutput(float v, int additional_fractional_digits) -{ - v = floor(v, additional_fractional_digits); - int vi = v.to_int(); - if (vi.to_float() == v) - return vi.to_string(); - else - return v.to_string(); -} - - -float TriangularDistributionCalculateCDF(float x, float min, float max, float centre) -{ - //piecewise function: - if (x < min) return 0.0; - else if (x > max) return 1.0; - else if (x >= min && x <= centre) - { - float divisor = (max - min) * (centre - min); - if (divisor == 0.0) - return 0.0; - - return pow2f(x - min) / divisor; - } - else if (x <= max && x > centre) - { - float divisor = (max - min) * (max - centre); - if (divisor == 0.0) - return 0.0; - - - return 1.0 - pow2f(max - x) / divisor; - } - else //probably only happens with weird floating point values, assume chance of zero: - return 0.0; -} - -//assume a centre equidistant from min and max -float TriangularDistributionCalculateCDF(float x, float min, float max) -{ - return TriangularDistributionCalculateCDF(x, min, max, (min + max) * 0.5); -} - -float averagef(float a, float b) -{ - return (a + b) * 0.5; -} - -boolean numberIsInRangeInclusive(int v, int min, int max) -{ - if (v < min) return false; - if (v > max) return false; - return true; -} diff --git a/Source/relay/TourGuide/Support/Modifiers.ash b/Source/relay/TourGuide/Support/Modifiers.ash deleted file mode 100644 index 13ccb8db..00000000 --- a/Source/relay/TourGuide/Support/Modifiers.ash +++ /dev/null @@ -1,111 +0,0 @@ -//Allows fast querying of which effects have which numeric_modifier()s. - -//Modifiers are lower case. -static -{ - boolean [effect][string] __modifiers_for_effect; - boolean [string][effect] __effects_for_modifiers; - boolean [effect] __effect_contains_non_constant_modifiers; //meaning, numeric_modifier() cannot be cached -} -void initialiseModifiers() -{ - if (__modifiers_for_effect.count() != 0) return; - //boolean [string] modifier_types; - //boolean [string] modifier_values; - foreach e in $effects[] - { - string string_modifiers = e.string_modifier("Modifiers"); - if (string_modifiers == "") continue; - if (string_modifiers.contains_text("Avatar: ")) continue; //FIXME parse properly? - string [int] first_level_split = string_modifiers.split_string(", "); - - foreach key, entry in first_level_split - { - //print_html(entry); - //if (!entry.contains_text(":")) - - string modifier_type; - string modifier_value; - if (entry.contains_text(": ")) - { - string [int] entry_split = entry.split_string(": "); - modifier_type = entry_split[0]; - modifier_value = entry_split[1]; - } - else - modifier_type = entry; - - - string modifier_type_converted = modifier_type; - - //convert modifier_type to modifier_type_converted: - //FIXME is this all of them? - if (modifier_type_converted == "Combat Rate (Underwater)") - modifier_type_converted = "Underwater Combat Rate"; - else if (modifier_type_converted == "Experience (familiar)") - modifier_type_converted = "Familiar Experience"; - else if (modifier_type_converted == "Experience (Moxie)") - modifier_type_converted = "Moxie Experience"; - else if (modifier_type_converted == "Experience (Muscle)") - modifier_type_converted = "Muscle Experience"; - else if (modifier_type_converted == "Experience (Mysticality)") - modifier_type_converted = "Mysticality Experience"; - else if (modifier_type_converted == "Experience Percent (Moxie)") - modifier_type_converted = "Moxie Experience Percent"; - else if (modifier_type_converted == "Experience Percent (Muscle)") - modifier_type_converted = "Muscle Experience Percent"; - else if (modifier_type_converted == "Experience Percent (Mysticality)") - modifier_type_converted = "Mysticality Experience Percent"; - else if (modifier_type_converted == "Mana Cost (stackable)") - modifier_type_converted = "Stackable Mana Cost"; - else if (modifier_type_converted == "Familiar Weight (hidden)") - modifier_type_converted = "Hidden Familiar Weight"; - else if (modifier_type_converted == "Meat Drop (sporadic)") - modifier_type_converted = "Sporadic Meat Drop"; - else if (modifier_type_converted == "Item Drop (sporadic)") - modifier_type_converted = "Sporadic Item Drop"; - - modifier_type_converted = modifier_type_converted.to_lower_case(); - __modifiers_for_effect[e][modifier_type_converted] = true; - __effects_for_modifiers[modifier_type_converted][e] = true; - if (modifier_value.contains_text("[") || modifier_value.contains_text("\"")) - __effect_contains_non_constant_modifiers[e] = true; - if (modifier_type_converted ≈ "muscle percent") - { - __modifiers_for_effect[e]["muscle"] = true; - __effects_for_modifiers["muscle"][e] = true; - } - if (modifier_type_converted ≈ "mysticality percent") - { - __modifiers_for_effect[e]["mysticality"] = true; - __effects_for_modifiers["mysticality"][e] = true; - } - if (modifier_type_converted ≈ "moxie percent") - { - __modifiers_for_effect[e]["moxie"] = true; - __effects_for_modifiers["moxie"][e] = true; - } - - /*if (e.numeric_modifier(modifier_type_converted) == 0.0 && modifier_value.length() > 0 && e.string_modifier(modifier_type_converted) == "")// && !__effect_contains_non_constant_modifiers[e]) - { - //print_html("No match on \"" + modifier_type_converted + "\""); - print_html("No match on \"" + modifier_type_converted + "\" for " + e + " (" + string_modifiers + ")"); - }*/ - //modifier_types[modifier_type] = true; - //modifier_values[modifier_value] = true; - } - //return; - } - /*print_html("Types:"); - foreach type in modifier_types - { - print_html(type); - } - print_html(""); - print_html("Values:"); - foreach value in modifier_values - { - print_html(value); - }*/ -} -initialiseModifiers(); diff --git a/Source/relay/TourGuide/Support/Monster Data.ash b/Source/relay/TourGuide/Support/Monster Data.ash deleted file mode 100644 index ac8b802d..00000000 --- a/Source/relay/TourGuide/Support/Monster Data.ash +++ /dev/null @@ -1,133 +0,0 @@ -//Extra data on monsters. -//We use the convention that $element[none] is physical. -record MonsterData -{ - //An example: Battlie Knight Ghost attack with both hot and physical. - //Useful to know when calculating Shoot Ghost. - boolean [element] basic_attack_elements; - boolean is_protonic_ghost; - float shoot_ghost_hp_attack_percentage; -}; - - -static -{ - MonsterData [monster] __monster_data; - - void initialiseMonsterData() - { - foreach m in $monsters[] - { - MonsterData blank; - __monster_data[m] = blank; - } - - //Now, hardcoded: - //Attack elements: - __monster_data[$monster[Battlie Knight Ghost]].basic_attack_elements = $elements[hot, none]; - __monster_data[$monster[Claybender Sorcerer Ghost]].basic_attack_elements = $elements[spooky, none]; - __monster_data[$monster[Dusken Raider Ghost]].basic_attack_elements = $elements[sleaze,none]; - __monster_data[$monster[Space Tourist Explorer Ghost]].basic_attack_elements = $elements[sleaze,cold,hot,none]; - __monster_data[$monster[Whatsian Commando Ghost]].basic_attack_elements = $elements[sleaze,none]; - - __monster_data[$monster[The ghost of Ebenoozer Screege]].basic_attack_elements = $elements[spooky]; - __monster_data[$monster[The ghost of Lord Montague Spookyraven]].basic_attack_elements = $elements[stench]; - __monster_data[$monster[The ghost of Waldo the Carpathian]].basic_attack_elements = $elements[hot]; - __monster_data[$monster[The Icewoman]].basic_attack_elements = $elements[cold]; - __monster_data[$monster[The ghost of Jim Unfortunato]].basic_attack_elements = $elements[sleaze]; - __monster_data[$monster[The ghost of Sam McGee]].basic_attack_elements = $elements[hot]; - __monster_data[$monster[Emily Koops\, a spooky lime]].basic_attack_elements = $elements[spooky]; - __monster_data[$monster[the ghost of Monsieur Baguelle]].basic_attack_elements = $elements[hot]; - __monster_data[$monster[The ghost of Vanillica "Trashblossom" Gorton]].basic_attack_elements = $elements[stench]; - __monster_data[$monster[the ghost of Oily McBindle]].basic_attack_elements = $elements[sleaze]; - __monster_data[$monster[boneless blobghost]].basic_attack_elements = $elements[spooky]; - __monster_data[$monster[The ghost of Richard Cockingham]].basic_attack_elements = $elements[spooky]; - __monster_data[$monster[The Headless Horseman]].basic_attack_elements = $elements[spooky]; - - __monster_data[$monster[chalkdust wraith]].basic_attack_elements = $elements[none]; - __monster_data[$monster[plaid ghost]].basic_attack_elements = $elements[none,sleaze]; - - //Protonic: - foreach m in $monsters[The ghost of Ebenoozer Screege, Emily Koops\, a spooky lime, the ghost of Monsieur Baguelle, The ghost of Lord Montague Spookyraven, The ghost of Waldo the Carpathian, The Icewoman, The ghost of Jim Unfortunato, The ghost of Sam McGee, The ghost of Vanillica "Trashblossom" Gorton, the ghost of Oily McBindle, boneless blobghost, The ghost of Richard Cockingham, The Headless Horseman] - __monster_data[m].is_protonic_ghost = true; - //We think each protonic monster uses a different HP multiplier. - //Emily and Jim, for instance, do way more damage than everyone else. - //It starts at monster ID 1946, which has 40%, and counts up by 5%. So the actual formula is: - //percentage = 0.05 * (monster_id - 1946) + 0.4 - __monster_data[$monster[boneless blobghost]].shoot_ghost_hp_attack_percentage = 0.45; - __monster_data[$monster[the ghost of Monsieur Baguelle]].shoot_ghost_hp_attack_percentage = 0.5; - __monster_data[$monster[The ghost of Ebenoozer Screege]].shoot_ghost_hp_attack_percentage = 0.65; - __monster_data[$monster[The ghost of Vanillica "Trashblossom" Gorton]].shoot_ghost_hp_attack_percentage = 0.75; - __monster_data[$monster[The ghost of Waldo the Carpathian]].shoot_ghost_hp_attack_percentage = 0.9; - __monster_data[$monster[Emily Koops\, a spooky lime]].shoot_ghost_hp_attack_percentage = 0.95; - - //These are from historical logs: - __monster_data[$monster[the ghost of Oily McBindle]].shoot_ghost_hp_attack_percentage = 0.4; //sleaze - __monster_data[$monster[The Headless Horseman]].shoot_ghost_hp_attack_percentage = 0.55; //spooky - __monster_data[$monster[The Icewoman]].shoot_ghost_hp_attack_percentage = 0.60; //cold - __monster_data[$monster[The ghost of Lord Montague Spookyraven]].shoot_ghost_hp_attack_percentage = 0.70; //stench - __monster_data[$monster[The ghost of Sam McGee]].shoot_ghost_hp_attack_percentage = 0.8; //hot - __monster_data[$monster[The ghost of Richard Cockingham]].shoot_ghost_hp_attack_percentage = 0.85; //spooky - __monster_data[$monster[The ghost of Jim Unfortunato]].shoot_ghost_hp_attack_percentage = 1.0; //sleaze - - } - initialiseMonsterData(); -} - -//Calculations: -float expectedDamageFromGhostAfterCastingShootGhost(monster m) -{ - if (!m.attributes.contains_text("GHOST")) //no ghost - return 0; - /* - Our guess for how shoot ghost works: - After you cast it, the ghost will always hit you. It still uses its regular attacks, with corresponding elements, but always deals a percentage of your maximum HP as damage. Your resistances, DA, and DR apply, as per usual. - Approximate full formula: - damage = (maximum_hp * ghost_specific_multiplier - DR) * resistance * DA - Each ghost has a specific multiplier. We're assuming non-protonic ghosts are 30%. But I've only checked a few. The protonic ones vary. - Oh, and then the monster does 84 damage instead of 80 and you have nooo idea why and you get beaten up. - */ - float percentage_multiplier = 0.3; - if (__monster_data[m].is_protonic_ghost) - { - //Different ghosts have different multipliers: - percentage_multiplier = 0.5; - if (__monster_data[m].shoot_ghost_hp_attack_percentage != 0.0) - percentage_multiplier = __monster_data[m].shoot_ghost_hp_attack_percentage; - } - float expected_damage = ceil(my_maxhp() * percentage_multiplier); - //Apply DR, resistance, and DA, in that order: - //We saw 2940 when we expected 2939. But then we saw 2939. So maybe these ceils do or do not happen. Or it's random rounding. - //Same with expected 4119, obtained 4120 and 4119. Fixed that by switching the order of resistance and damage absorption. So maybe resistance is applied before DA, then rrounded at each step...? - expected_damage = ceil(expected_damage - numeric_modifier("Damage Reduction")); - //Umm... something to note: Battlie Knight Ghosts will attack with hot damage, even though they're spooky aligned. - //Plus, they might just attack with physical damage. - //So, we need to know what types of damage each ghost does. - expected_damage = MAX(1, expected_damage); - if (__monster_data[m].basic_attack_elements.count() > 0 && !(__monster_data[m].basic_attack_elements contains $element[none])) - { - //They do elemental attacks only. Probably a protonic ghost. - float minimum_damage_seen = expected_damage; - //Go through each element: - foreach e in __monster_data[m].basic_attack_elements - { - float resistance = numeric_modifier(e + " resistance"); - if (m == $monster[The ghost of Jim Unfortunato]) //this is a guess - resistance -= 2.0; - if (m == $monster[The ghost of Waldo the Carpathian]) //this is a guess - resistance -= 1.0; - if (m == $monster[The ghost of Lord Montague Spookyraven]) //this is wrong, but I don't know what's correct - resistance -= 1.0; - //FIXME suspect others are the same - resistance = MAX(0, resistance); - - float resistance_percent = resistanceLevelToResistancePercent(resistance);//elemental_resistance(e); - float damage = MAX(1, ceil(expected_damage * (1.0 - resistance_percent / 100.0))); - if (damage < minimum_damage_seen) - minimum_damage_seen = damage; - } - expected_damage = minimum_damage_seen; - } - expected_damage = ceil(expected_damage * (1.0 - damage_absorption_percent() / 100.0)); - return MAX(1, ceil(expected_damage)); -} diff --git a/Source/relay/TourGuide/Support/Numberology.ash b/Source/relay/TourGuide/Support/Numberology.ash deleted file mode 100644 index 9d063fb4..00000000 --- a/Source/relay/TourGuide/Support/Numberology.ash +++ /dev/null @@ -1,120 +0,0 @@ -static -{ - int [string] __moon_sign_id_lookup; - void initialiseMoonSignIDLookup() - { - __moon_sign_id_lookup[""] = 0; - __moon_sign_id_lookup["None"] = 0; - __moon_sign_id_lookup["Mongoose"] = 1; - __moon_sign_id_lookup["Wallaby"] = 2; - __moon_sign_id_lookup["Vole"] = 3; - __moon_sign_id_lookup["Platypus"] = 4; - __moon_sign_id_lookup["Opossum"] = 5; - __moon_sign_id_lookup["Marmot"] = 6; - __moon_sign_id_lookup["Wombat"] = 7; - __moon_sign_id_lookup["Blender"] = 8; - __moon_sign_id_lookup["Packrat"] = 9; - __moon_sign_id_lookup["Bad Moon"] = 10; //confirmed - } - initialiseMoonSignIDLookup(); -} - -Record NumberologyCacheState -{ - int b; - int c; - int [int] input_to_outputs; - int [int] input_deltas; -}; - -NumberologyCacheState NumberologyCacheStateMake() -{ - NumberologyCacheState r; - r.b = -1; - r.c = -1; - return r; -} - -static -{ - NumberologyCacheState __numberology_cache = NumberologyCacheStateMake(); -} - -void calculateNumberologyInputValuesForOutputs(boolean [int] desired_digits_in, int [int] digit_inputs_to_outputs_out, int [int] digit_inputs_to_deltas_out) -{ - if (!(__moon_sign_id_lookup contains my_sign())) //not computable - return; - - boolean [int] desired_digits_left; - foreach digit in desired_digits_in - { - desired_digits_left[digit] = true; - digit_inputs_to_deltas_out[digit] = 99; - } - int mood_sign_id = __moon_sign_id_lookup[my_sign()]; - - int b = my_spleen_use() + my_level(); - int c = (my_ascensions() + mood_sign_id) * b + my_adventures(); - - if (__numberology_cache.b == b && __numberology_cache.c == c) - { - //Cache lookup: - foreach digit in desired_digits_in - { - if (__numberology_cache.input_to_outputs contains digit) - { - digit_inputs_to_outputs_out[digit] = __numberology_cache.input_to_outputs[digit]; - remove desired_digits_left[digit]; - } - else if (__numberology_cache.input_deltas contains digit) - { - digit_inputs_to_deltas_out[digit] = __numberology_cache.input_deltas[digit]; - remove desired_digits_left[digit]; - } - } - } - if (desired_digits_left.count() == 0) - return; - - int last_x = -1; - //Brute force method: - for x from 0 to 99 - { - int v = x * b + c; - int last_two_digits = v % 100; - if (desired_digits_left contains last_two_digits) - { - remove desired_digits_left[last_two_digits]; - remove digit_inputs_to_deltas_out[last_two_digits]; - digit_inputs_to_outputs_out[last_two_digits] = x; - if (desired_digits_left.count() == 0) - { - last_x = x; - break; - } - } - foreach digit in desired_digits_left - { - int delta = digit - last_two_digits; - if (delta <= 0) - digit_inputs_to_deltas_out[digit] = min(digit_inputs_to_deltas_out[digit], -delta); - else - { - delta = digit - (last_two_digits + 100); - if (delta <= 0) - digit_inputs_to_deltas_out[digit] = min(digit_inputs_to_deltas_out[digit], -delta); - } - } - } - - //Save cache: - if (__numberology_cache.b != b || __numberology_cache.c != c) - __numberology_cache = NumberologyCacheStateMake(); - __numberology_cache.b = b; - __numberology_cache.c = c; - foreach input, output in digit_inputs_to_outputs_out - __numberology_cache.input_to_outputs[input] = output; - foreach input, delta in digit_inputs_to_deltas_out - __numberology_cache.input_deltas[input] = delta; -} - diff --git a/Source/relay/TourGuide/Support/Page.ash b/Source/relay/TourGuide/Support/Page.ash deleted file mode 100644 index 4053a72f..00000000 --- a/Source/relay/TourGuide/Support/Page.ash +++ /dev/null @@ -1,434 +0,0 @@ -import "relay/TourGuide/Support/HTML.ash" -import "relay/TourGuide/Settings.ash" - -record CSSEntry -{ - string tag; - string class_name; - string definition; - int importance; -}; - -CSSEntry CSSEntryMake(string tag, string class_name, string definition, int importance) -{ - CSSEntry entry; - entry.tag = tag; - entry.class_name = class_name; - entry.definition = definition; - entry.importance = importance; - return entry; -} - -record CSSBlock -{ - CSSEntry [int] defined_css_classes; - string identifier; -}; - -CSSBlock CSSBlockMake(string identifier) -{ - CSSBlock result; - result.identifier = identifier; - return result; -} - -buffer CSSBlockGenerate(CSSBlock block) -{ - buffer result; - - if (block.defined_css_classes.count() > 0) - { - boolean output_identifier = (block.identifier != ""); - if (output_identifier) - { - result.append("\t\t\t"); - result.append(block.identifier); - result.append(" {\n"); - } - sort block.defined_css_classes by value.importance; - - foreach key in block.defined_css_classes - { - CSSEntry entry = block.defined_css_classes[key]; - result.append("\t\t\t"); - if (output_identifier) - result.append("\t"); - - if (entry.class_name == "") - result.append(entry.tag + " { " + entry.definition + " }"); - else - { - result.append(entry.tag + ( entry.class_name.char_at(0) != "#" && entry.class_name.char_at(0) != "." ? "." : "") + entry.class_name + " { " + entry.definition + " }"); - } - result.append("\n"); - } - if (output_identifier) - result.append("\n\t\t\t}\n"); - } - return result; -} - -void listAppend(CSSEntry [int] list, CSSEntry entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -record Page -{ - string title; - buffer head_contents; - buffer body_contents; - string [string] body_attributes; //[attribute_name] -> attribute_value - - CSSBlock [string] defined_css_blocks; //There is always an implicit "" block. -}; - - -Page __global_page; - - - -Page Page() -{ - return __global_page; -} - -buffer PageGenerateBodyContents(Page page_in) -{ - return page_in.body_contents; -} - -buffer PageGenerateBodyContents() -{ - return Page().PageGenerateBodyContents(); -} - -buffer PageGenerateStyle(Page page_in) -{ - buffer result; - - if (page_in.defined_css_blocks.count() > 0) - { - if (true) - { - result.append("\t\t"); - result.append(HTMLGenerateTagPrefix("style", mapMake("type", "text/css"))); - result.append("\n"); - } - result.append(page_in.defined_css_blocks[""].CSSBlockGenerate()); //write first - foreach identifier in page_in.defined_css_blocks - { - CSSBlock block = page_in.defined_css_blocks[identifier]; - if (identifier == "") //skip, already written - continue; - result.append(block.CSSBlockGenerate()); - } - if (true) - { - result.append("\t\t\n"); - } - } - return result; -} - -buffer PageGenerateStyle() -{ - return Page().PageGenerateStyle(); -} - -buffer PageGenerate(Page page_in) -{ - buffer result; - - result.append("\n"); //HTML 5 target - result.append("\n"); - - //Head: - result.append("\t\n"); - result.append("\t\t"); - result.append(page_in.title); - result.append("\n"); - if (page_in.head_contents.length() != 0) - { - result.append("\t\t"); - result.append(page_in.head_contents); - result.append("\n"); - } - //Write CSS styles: - result.append(PageGenerateStyle(page_in)); - result.append("\t\n"); - - //Body: - result.append("\t"); - result.append(HTMLGenerateTagPrefix("body", page_in.body_attributes)); - result.append("\n\t\t"); - result.append(page_in.body_contents); - result.append("\n"); - - result.append("\t\n"); - - - result.append(""); - - return result; -} - -void PageGenerateAndWriteOut(Page page_in) -{ - write(PageGenerate(page_in)); -} - -void PageSetTitle(Page page_in, string title) -{ - page_in.title = title; -} - -void PageAddCSSClass(Page page_in, string tag, string class_name, string definition, int importance, string block_identifier) -{ - //print_html("Adding block_identifier \"" + block_identifier + "\""); - if (!(page_in.defined_css_blocks contains block_identifier)) - page_in.defined_css_blocks[block_identifier] = CSSBlockMake(block_identifier); - page_in.defined_css_blocks[block_identifier].defined_css_classes.listAppend(CSSEntryMake(tag, class_name, definition, importance)); -} - -void PageAddCSSClass(Page page_in, string tag, string class_name, string definition, int importance) -{ - PageAddCSSClass(page_in, tag, class_name, definition, importance, ""); -} - -void PageAddCSSClass(Page page_in, string tag, string class_name, string definition) -{ - PageAddCSSClass(page_in, tag, class_name, definition, 0); -} - - -void PageWriteHead(Page page_in, string contents) -{ - page_in.head_contents.append(contents); -} - -void PageWriteHead(Page page_in, buffer contents) -{ - page_in.head_contents.append(contents); -} - - -void PageWrite(Page page_in, string contents) -{ - page_in.body_contents.append(contents); -} - -void PageWrite(Page page_in, buffer contents) -{ - page_in.body_contents.append(contents); -} - -void PageSetBodyAttribute(Page page_in, string attribute, string value) -{ - page_in.body_attributes[attribute] = value; -} - - -//Global: - -buffer PageGenerate() -{ - return PageGenerate(Page()); -} - -void PageGenerateAndWriteOut() -{ - write(PageGenerate()); -} - -void PageSetTitle(string title) -{ - PageSetTitle(Page(), title); -} - -void PageAddCSSClass(string tag, string class_name, string definition) -{ - PageAddCSSClass(Page(), tag, class_name, definition); -} - -void PageAddCSSClass(string tag, string class_name, string definition, int importance) -{ - PageAddCSSClass(Page(), tag, class_name, definition, importance); -} - -void PageAddCSSClass(string tag, string class_name, string definition, int importance, string block_identifier) -{ - PageAddCSSClass(Page(), tag, class_name, definition, importance, block_identifier); -} - -void PageWriteHead(string contents) -{ - PageWriteHead(Page(), contents); -} - -void PageWriteHead(buffer contents) -{ - PageWriteHead(Page(), contents); -} - -//Writes to body: - -void PageWrite(string contents) -{ - PageWrite(Page(), contents); -} - -void PageWrite(buffer contents) -{ - PageWrite(Page(), contents); -} - -void PageSetBodyAttribute(string attribute, string value) -{ - PageSetBodyAttribute(Page(), attribute, value); -} - - -void PageInit() -{ - PageAddCSSClass("a", "r_a_undecorated", "text-decoration:none;color:inherit;"); - PageAddCSSClass("", "r_centre", "margin-left:auto; margin-right:auto;text-align:center;"); - PageAddCSSClass("", "r_bold", "font-weight:bold;"); - PageAddCSSClass("", "r_end_floating_elements", "clear:both;"); - - PageAddCSSClass("", "r_element_important", "color: red;"); - - PageAddCSSClass("", "r_element_good", "color: rgb(0, 128, 0);"); - PageAddCSSClass("", "r_element_awesome", "color: rgb(0, 0, 255);"); - PageAddCSSClass("", "r_element_epic", "color: rgb(138, 43, 226);"); - - PageAddCSSClass("", "r_element_stench", "color:green;"); - PageAddCSSClass("", "r_element_hot", "color:red;"); - PageAddCSSClass("", "r_element_cold", "color:blue;"); - PageAddCSSClass("", "r_element_sleaze", "color:purple;"); - PageAddCSSClass("", "r_element_spooky", "color:gray;"); - - //50% desaturated versions of above: - PageAddCSSClass("", "r_element_stench_desaturated", "color:#427F40;"); - PageAddCSSClass("", "r_element_hot_desaturated", "color:#FF7F81;"); - PageAddCSSClass("", "r_element_cold_desaturated", "color:#6B64FF;"); - PageAddCSSClass("", "r_element_sleaze_desaturated", "color:#7F407F;"); - PageAddCSSClass("", "r_element_spooky_desaturated", "color:gray;"); - - PageAddCSSClass("", "r_indention", "margin-left:" + __setting_indention_width + ";"); - - //Simple table lines: - PageAddCSSClass("div", "r_stl_container", "display:table;"); - PageAddCSSClass("div", "r_stl_container_row", "display:table-row;"); - PageAddCSSClass("div", "r_stl_entry", "padding:0px;margin:0px;display:table-cell;"); - PageAddCSSClass("div", "r_stl_spacer", "width:1em;"); -} - - - -string HTMLGenerateIndentedText(string text, string width) -{ - return HTMLGenerateDivOfClass(text, "r_indention"); -} - -string HTMLGenerateIndentedText(string [int] text) -{ - - buffer building_text; - foreach key in text - { - string line = text[key]; - building_text.append(HTMLGenerateDiv(line)); - } - - return HTMLGenerateIndentedText(to_string(building_text), __setting_indention_width); -} - -string HTMLGenerateIndentedText(string text) -{ - return HTMLGenerateIndentedText(text, __setting_indention_width); -} - - -string HTMLGenerateSimpleTableLines(string [int][int] lines, boolean dividers_are_visible) -{ - buffer result; - - int max_columns = 0; - foreach i in lines - { - max_columns = max(max_columns, lines[i].count()); - } - - //div-based layout: - int intra_i = 0; - int last_cell_count = 0; - result.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_stl_container"))); - foreach i in lines - { - if (intra_i > 0) - { - result.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_stl_container_row"))); - for i from 1 to last_cell_count //no colspan with display:table, generate extra (zero-padding, zero-margin) cells: - { - string separator = ""; - if (dividers_are_visible) - separator = "
"; - else - separator = "
"; //laziness - generate an invisible HR, so there's still spacing - result.append(HTMLGenerateDivOfClass(separator, "r_stl_entry")); - } - result.append(""); - last_cell_count = 0; - } - result.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_stl_container_row"))); - int intra_j = 0; - foreach j in lines[i] - { - string entry = lines[i][j]; - if (intra_j > 0) - { - result.append(HTMLGenerateDivOfClass("", "r_stl_entry r_stl_spacer")); - last_cell_count += 1; - } - result.append(HTMLGenerateDivOfClass(entry, "r_stl_entry")); - last_cell_count += 1; - - intra_j += 1; - } - - result.append(""); - intra_i += 1; - } - result.append(""); - return result.to_string(); -} - -string HTMLGenerateSimpleTableLines(string [int][int] lines) -{ - return HTMLGenerateSimpleTableLines(lines, true); -} - -string HTMLGenerateElementSpan(element e, string additional_text, boolean desaturated) -{ - string line = e; - if (additional_text != "") - line += " " + additional_text; - return HTMLGenerateSpanOfClass(line, "r_element_" + e + (desaturated ? "_desaturated" : "")); -} - -string HTMLGenerateElementSpan(element e, string additional_text) -{ - return HTMLGenerateElementSpan(e, additional_text, false); -} -string HTMLGenerateElementSpanDesaturated(element e, string additional_text) -{ - return HTMLGenerateElementSpan(e, additional_text, true); -} -string HTMLGenerateElementSpanDesaturated(element e) -{ - return HTMLGenerateElementSpanDesaturated(e, ""); -} diff --git a/Source/relay/TourGuide/Support/Passive Damage.ash b/Source/relay/TourGuide/Support/Passive Damage.ash deleted file mode 100644 index 27cf214f..00000000 --- a/Source/relay/TourGuide/Support/Passive Damage.ash +++ /dev/null @@ -1,271 +0,0 @@ -//Active attacks, stinging damage. - -int PDS_DAMAGE_TYPE_NONE = 0; -int PDS_DAMAGE_TYPE_ACTIVE = 1; -int PDS_DAMAGE_TYPE_STINGING = 2; - -int PDS_SOURCE_TYPE_NONE = 0; -int PDS_SOURCE_TYPE_EFFECT = 1; -int PDS_SOURCE_TYPE_COMBAT_ITEM = 2; -int PDS_SOURCE_TYPE_EQUIPMENT = 3; -int PDS_SOURCE_TYPE_COMBAT_SKILL = 4; -int PDS_SOURCE_TYPE_FAMILIAR = 5; -int PDS_SOURCE_TYPE_BJORN_FAMILIAR = 6; //also crown - -record PassiveDamageSource -{ - int damage_type; - int source_type; //item, etc - float chance_of_acting; - int max_rounds_act; //0 for unlimited - - Vec2f [element] damage_range; - - - effect source_effect; //if effect - item source_effect_potion; //if effect - skill source_effect_skill; //if effect - item source_equipment; //if equipment - item source_combat_item; //if combat item - skill source_combat_skill; //if combat skill - familiar source_familiar; //familiar or bjorn familiar -}; - -PassiveDamageSource PassiveDamageSourceMake(int damage_type, int source_type) -{ - PassiveDamageSource pds; - pds.damage_type = damage_type; - pds.source_type = source_type; - pds.chance_of_acting = 1.0; - - return pds; -} - -void PassiveDamageSourceAddDamage(PassiveDamageSource pds, float min_damage, float max_damage, element e) -{ - Vec2f range; - range.x = min_damage; - range.y = max_damage; - if (pds.damage_range contains e) - { - range.x += pds.damage_range[e].x; - range.y += pds.damage_range[e].y; - } - pds.damage_range[e] = range; -} - -void PassiveDamageSourceAddDamage(PassiveDamageSource pds, float amount, element e) -{ - PassiveDamageSourceAddDamage(pds, amount, amount, e); -} - -void PassiveDamageSourceAddDamage(PassiveDamageSource pds, float physical_only) -{ - PassiveDamageSourceAddDamage(pds, physical_only, $element[none]); -} - -void listAppend(PassiveDamageSource [int] list, PassiveDamageSource entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -PassiveDamageSource listExactLastObject(PassiveDamageSource [int] list) //WARNING only works for linear arrays -{ - if (list.count() == 0) - return PassiveDamageSourceMake(0, 0); - return list[list.count() - 1]; -} - -static -{ - PassiveDamageSource [int] __known_sources; - void PDSInitialiseDoNotCallThis() - { - if (__known_sources.count() > 0) - return; - //Create every source: - //FIXME add - __known_sources.listAppend(PassiveDamageSourceMake(PDS_DAMAGE_TYPE_ACTIVE, PDS_SOURCE_TYPE_EQUIPMENT)); - __known_sources.listExactLastObject().PassiveDamageSourceAddDamage(1, 11, $element[none]); //FIXME WRONG - __known_sources.listExactLastObject().source_equipment = $item[hand in glove]; - - //FIXME wrong, but a good preliminary: - foreach it in $items[MagiMechTech NanoMechaMech,bottle opener belt buckle,old school calculator watch,ant hoe,ant pick,ant pitchfork,ant rake,ant sickle,fishy wand,moveable feast,oversized fish scaler,plastic pumpkin bucket,replica plastic pumpkin bucket,tiny bowler,cup of infinite pencils,double-ice box,smirking shrunken head,mr. haggis,stapler bear,dubious loincloth,muddy skirt,bottle of Goldschnöckered,acid-squirting flower,ironic oversized sunglasses,hippy protest button,cannonball charrrm bracelet,groovy prism necklace,spiky turtle shoulderpads,double-ice cap,parasitic headgnawer,eelskin hat,balloon shield,hot plate,Ol' Scratch's stove door,Oscus's garbage can lid,eelskin shield,eelskin pants,buddy bjorn,shocked shell,crown of thrones] - { - __known_sources.listAppend(PassiveDamageSourceMake(PDS_DAMAGE_TYPE_ACTIVE, PDS_SOURCE_TYPE_EQUIPMENT)); - __known_sources.listExactLastObject().PassiveDamageSourceAddDamage(1); - __known_sources.listExactLastObject().source_equipment = it; - } - foreach e in $effects[Skeletal Warrior,Skeletal Cleric,Skeletal Wizard,Bone Homie,Burning\, Man,Biologically Shocked,EVISCERATE!,Fangs and Pangs,Permanent Halloween,Curse of the Black Pearl Onion,Long Live GORF,Apoplectic with Rage,Dizzy with Rage,Quivering with Rage,Jabañero Saucesphere,Psalm of Pointiness,Drenched With Filth,Stuck-Up Hair,It's Electric!,Smokin',Jalapeño Saucesphere,Scarysauce,spiky shell,Boner Battalion] - { - __known_sources.listAppend(PassiveDamageSourceMake(PDS_DAMAGE_TYPE_ACTIVE, PDS_SOURCE_TYPE_EFFECT)); - __known_sources.listExactLastObject().PassiveDamageSourceAddDamage(1); - __known_sources.listExactLastObject().source_effect = e; - } - - foreach f in $familiars[] - { - if (!(f.physical_damage || f.elemental_damage) && !($familiars[Doppelshifter,Comma Chameleon,Mad Hatrack,Robot Reindeer,Fancypants Scarecrow,Mini-Adventurer] contains f)) - continue; - __known_sources.listAppend(PassiveDamageSourceMake(PDS_DAMAGE_TYPE_ACTIVE, PDS_SOURCE_TYPE_FAMILIAR)); - __known_sources.listExactLastObject().chance_of_acting = 0.333; //most - __known_sources.listExactLastObject().PassiveDamageSourceAddDamage(1); - __known_sources.listExactLastObject().source_familiar = f; - } - } - - PDSInitialiseDoNotCallThis(); -} - - -PassiveDamageSource [int] PDSGetActiveDamageSources() -{ - PassiveDamageSource [int] result; - - foreach key, pds in __known_sources - { - boolean should_add = false; - if (pds.source_type == PDS_SOURCE_TYPE_EFFECT) - { - if (pds.source_effect.have_effect() > 0) - should_add = true; - } - else if (pds.source_type == PDS_SOURCE_TYPE_COMBAT_ITEM) - { - //Nothing - } - else if (pds.source_type == PDS_SOURCE_TYPE_EQUIPMENT) - { - if (pds.source_equipment.equipped_amount() > 0) - should_add = true; - } - else if (pds.source_type == PDS_SOURCE_TYPE_COMBAT_SKILL) - { - //Nothing - } - else if (pds.source_type == PDS_SOURCE_TYPE_FAMILIAR) - { - if (my_familiar() == pds.source_familiar) - should_add = true; - } - else if (pds.source_type == PDS_SOURCE_TYPE_BJORN_FAMILIAR) - { - if (my_bjorned_familiar() == pds.source_familiar && $item[buddy bjorn].equipped_amount() > 0) - should_add = true; - if (my_enthroned_familiar() == pds.source_familiar && $item[crown of thrones].equipped_amount() > 0) - should_add = true; - } - if (should_add) - result.listAppend(pds); - } - - return result; -} - -//Does not return sources already in effect -PassiveDamageSource [int] PDSGetPotentialDamageSources() -{ - PassiveDamageSource [int] result; - - foreach key, pds in __known_sources - { - boolean should_add = false; - if (pds.source_type == PDS_SOURCE_TYPE_EFFECT) - { - if (pds.source_effect.have_effect() == 0) - { - if (pds.source_effect_potion.available_amount() > 0) - should_add = true; - if (pds.source_effect_skill.have_skill() && pds.source_effect_skill.is_unrestricted()) - should_add = true; - } - } - else if (pds.source_type == PDS_SOURCE_TYPE_COMBAT_ITEM) - { - if (pds.source_combat_item.available_amount() > 0) - should_add = true; - } - else if (pds.source_type == PDS_SOURCE_TYPE_EQUIPMENT) - { - if (pds.source_equipment.equipped_amount() == 0 && pds.source_equipment.can_equip() && pds.source_equipment.available_amount() > 0) - should_add = true; - } - else if (pds.source_type == PDS_SOURCE_TYPE_COMBAT_SKILL) - { - //FIXME is this correct? - if (pds.source_combat_skill.have_skill() && pds.source_combat_skill.is_unrestricted()) - should_add = true; - } - else if (pds.source_type == PDS_SOURCE_TYPE_FAMILIAR) - { - if (pds.source_familiar.familiar_is_usable() && my_familiar() != pds.source_familiar) - should_add = true; - } - else if (pds.source_type == PDS_SOURCE_TYPE_BJORN_FAMILIAR) - { - //FIXME add - } - if (should_add) - result.listAppend(pds); - } - - return result; -} - - -string [int] PDSGenerateDescriptionToUneffectPassives() -{ - string [int] effect_types; - string [int] equipment_types; - string [int] familiar_types; //you know, because we often bring two or more familiars... with us... avatar of susie? - string [int] bjorn_familiar_types; - foreach key, pds in PDSGetActiveDamageSources() - { - if (pds.source_type == PDS_SOURCE_TYPE_EFFECT) - { - effect_types.listAppend(pds.source_effect); - } - else if (pds.source_type == PDS_SOURCE_TYPE_EQUIPMENT) - { - equipment_types.listAppend(pds.source_equipment); - } - else if (pds.source_type == PDS_SOURCE_TYPE_FAMILIAR) - { - familiar_types.listAppend(pds.source_familiar); - } - else if (pds.source_type == PDS_SOURCE_TYPE_BJORN_FAMILIAR) - { - bjorn_familiar_types.listAppend(pds.source_familiar); - } - } - string [int] result; - if (effect_types.count() > 0) - result.listAppend("Uneffect " + effect_types.listJoinComponents(", ", "and") + "."); - if (equipment_types.count() > 0) - result.listAppend("Unequip " + equipment_types.listJoinComponents(", ", "and") + "."); - if (familiar_types.count() > 0) - result.listAppend("Change familiar from " + familiar_types.listJoinComponents(", ", "and") + "."); - if (bjorn_familiar_types.count() > 0) - result.listAppend("Change bjorn/crown familiar from " + bjorn_familiar_types.listJoinComponents(", ", "and") + "."); - if (get_property("_horsery") == "pale horse") //FIXME make generic - result.listAppend("Change to a different horse."); - - return result; -} - -boolean PDSFamiliarCouldPossiblyAttack(familiar f) -{ - if (f.combat) return true; - foreach key, pds in __known_sources - { - if (pds.source_type == PDS_SOURCE_TYPE_FAMILIAR) - { - if (f == pds.source_familiar) - return true; - } - } - return false; -} diff --git a/Source/relay/TourGuide/Support/Spell Damage.ash b/Source/relay/TourGuide/Support/Spell Damage.ash deleted file mode 100644 index 1640bfc6..00000000 --- a/Source/relay/TourGuide/Support/Spell Damage.ash +++ /dev/null @@ -1,192 +0,0 @@ -import "relay/TourGuide/Support/Math.ash"; - -effect [element] __flavour_lookup; -__flavour_lookup[$element[hot]] = $effect[Spirit of Cayenne]; -__flavour_lookup[$element[cold]] = $effect[Spirit of Peppermint]; -__flavour_lookup[$element[stench]] = $effect[Spirit of Garlic]; -__flavour_lookup[$element[spooky]] = $effect[Spirit of Wormwood]; -__flavour_lookup[$element[sleaze]] = $effect[Spirit of Bacon Grease]; - -float damageForElementAgainstElement(float base_damage, element attacking_element, element defence_element) -{ - if (defence_element == $element[none] || attacking_element == $element[none]) - return base_damage; - if (attacking_element == defence_element) - return MIN(base_damage, 1); - if (base_damage < 1) - return 0.0; - - boolean [element] relevant_elements = $elements[sleaze,stench,hot,spooky,cold]; - float [element,element] attack_versus_element; - foreach e1 in relevant_elements - { - foreach e2 in relevant_elements - { - if (e1 == e2) - attack_versus_element[e1][e2] = 0.0; - else - attack_versus_element[e1][e2] = 1.0; - } - } - attack_versus_element[$element[sleaze]][$element[stench]] = 2.0; - attack_versus_element[$element[sleaze]][$element[hot]] = 2.0; - - attack_versus_element[$element[stench]][$element[hot]] = 2.0; - attack_versus_element[$element[stench]][$element[spooky]] = 2.0; - - attack_versus_element[$element[hot]][$element[spooky]] = 2.0; - attack_versus_element[$element[hot]][$element[cold]] = 2.0; - - attack_versus_element[$element[spooky]][$element[cold]] = 2.0; - attack_versus_element[$element[spooky]][$element[sleaze]] = 2.0; - - attack_versus_element[$element[cold]][$element[sleaze]] = 2.0; - attack_versus_element[$element[cold]][$element[stench]] = 2.0; - - - float final = MAX(1, base_damage * attack_versus_element[attacking_element][defence_element]); - return final; -} - -element currentFlavourElement() -{ - foreach s, d in __flavour_lookup - { - if (d.have_effect() != 0) - return s; - } - return $element[none]; -} - -//Does not take into account spell criticals, as they're random by nature. -//FIXME support 100% criticals, I suppose - -Vec2f spellFormulaDamageRange(float multiplier, float damage_cap, Vec2f base_damage_range, float buffed_myst_percentage, element e) -{ - Vec2f range = Vec2fMake(0.0, 0.0); - range.x = base_damage_range.x + floor(my_buffedstat($stat[mysticality]) * buffed_myst_percentage) + numeric_modifier("spell damage"); - range.y = base_damage_range.y + floor(my_buffedstat($stat[mysticality]) * buffed_myst_percentage) + numeric_modifier("spell damage"); - - if (e != $element[none]) - { - float element_spell_damage = numeric_modifier(e + " spell damage"); - range.x += element_spell_damage; - range.y += element_spell_damage; - } - if (damage_cap > 0.0) - { - range.x = MIN(damage_cap, range.x); - range.y = MIN(damage_cap, range.y); - } - range.x *= multiplier; - range.y *= multiplier; - - range.x *= 1.0 + numeric_modifier("spell damage percent") / 100.0; - range.y *= 1.0 + numeric_modifier("spell damage percent") / 100.0; - - range.x = ceil(range.x); - range.y = ceil(range.y); - return range; -} - -Record SEDRDamageSource -{ - element element_type; - Vec2f damage_range; -}; - -SEDRDamageSource SEDRDamageSourceMake(element e, Vec2f damage_range) -{ - SEDRDamageSource result; - result.element_type = e; - result.damage_range = damage_range; - return result; -} - -void listAppend(SEDRDamageSource [int] list, SEDRDamageSource entry) -{ - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; -} - -float MLDamageMultiplier() -{ - float ml_damage_multiplier = 1.0; - ml_damage_multiplier = MIN(1.0, 1.0 - MIN(monster_level_adjustment() * 0.4 / 100.0, 0.5)); //FIXME investigate negative ML - return ml_damage_multiplier; -} - -Vec2f skillExpectedDamageRangeAlternate(monster m, skill s) -{ - //FIXME spade how on earth to properly calculate this - //for instance, how does elemental spell damage work? - float ml_damage_multiplier = MLDamageMultiplier(); - - element flavour_element = currentFlavourElement(); - - int monster_group_size = 1; - //FIXME add a bunch of these, or feature request to mafia: - if (m == $monster[wall of bones]) - monster_group_size = 100; //FIXME spade - - element [int] active_lanterns; - - if ($item[Rain-Doh green lantern].equipped_amount() > 0) - active_lanterns.listAppend($element[stench]); - else if ($item[snow mobile].equipped_amount() > 0) - active_lanterns.listAppend($element[cold]); - - element [int] pastamancer_active_lanterns = active_lanterns.listCopy(); - if ($item[porcelain porkpie].equipped_amount() > 0) //ONLY for pastamancer spells - pastamancer_active_lanterns.listAppend($element[sleaze]); - - - SEDRDamageSource [int] damage_sources; - - if (s == $skill[saucegeyser]) - { - float multiplier = MIN(3.0, monster_group_size); - element saucegeyser_element = $element[hot]; - if (m.defense_element == $element[hot] || m.defense_element == $element[sleaze] || m.defense_element == $element[stench]) - saucegeyser_element = $element[cold]; - else if (m.defense_element == $element[cold] || m.defense_element == $element[spooky]) - saucegeyser_element = $element[hot]; - else - { - //complicated - //we pick the one with more spell damage - //FIXME the exact calculation in-game is probably "whichever element does more damage" - //we should be doing that now, but we aren't handling hotform/coldform/etc - //or double-ice - //but spading suggests if hot spell damage is greater than cold spell damage, it'll always be hot against non-elementals. if they're equal, it's random. if it's less than, it's always cold. - if (numeric_modifier("hot spell damage") > numeric_modifier("cold spell damage")) - saucegeyser_element = $element[hot]; - else - saucegeyser_element = $element[cold]; - } - Vec2f saucegeyser_base = spellFormulaDamageRange(multiplier, 0.0, Vec2fMake(60.0, 70.0), 0.4, saucegeyser_element); - //FIXME is the group damage multiplier before or after bonus spell damage? - damage_sources.listAppend(SEDRDamageSourceMake(saucegeyser_element, saucegeyser_base)); - foreach key, e in active_lanterns - damage_sources.listAppend(SEDRDamageSourceMake(e, saucegeyser_base)); - } - else - return Vec2fMake(-1.0, -1.0); - Vec2f expected_damage_range = Vec2fMake(0.0, 0.0); - - foreach key, damage_source in damage_sources - { - expected_damage_range.x += ml_damage_multiplier * damageForElementAgainstElement(damage_source.damage_range.x, damage_source.element_type, m.defense_element); - expected_damage_range.y += ml_damage_multiplier * damageForElementAgainstElement(damage_source.damage_range.y, damage_source.element_type, m.defense_element); - } - - return expected_damage_range; -} - -float skillExpectedDamageAlternate(monster m, skill s) -{ - Vec2f range = skillExpectedDamageRangeAlternate(m, s); - return (range.x + range.y) * 0.5; -} diff --git a/Source/relay/TourGuide/Support/Statics 2.ash b/Source/relay/TourGuide/Support/Statics 2.ash deleted file mode 100644 index f6648851..00000000 --- a/Source/relay/TourGuide/Support/Statics 2.ash +++ /dev/null @@ -1,17 +0,0 @@ -import "relay/TourGuide/Support/Library.ash"; - -static -{ - //mr. fusion: - boolean [item] __pvpable_food_and_drinks; - void initialisePVPFoodAndDrinks() - { - foreach it in $items[] - { - if (it.fullness == 0 && it.inebriety == 0) continue; - if (!it.item_is_pvp_stealable()) continue; - __pvpable_food_and_drinks[it] = true; - } - } - initialisePVPFoodAndDrinks(); -} diff --git a/Source/relay/TourGuide/Support/Statics.ash b/Source/relay/TourGuide/Support/Statics.ash deleted file mode 100644 index 3a3a9e4e..00000000 --- a/Source/relay/TourGuide/Support/Statics.ash +++ /dev/null @@ -1,403 +0,0 @@ -import "relay/TourGuide/Support/List.ash"; -import "relay/TourGuide/Support/Ingredients.ash" - -static { - int PATH_UNKNOWN = -1; - int PATH_NONE = 0; - int PATH_BOOZETAFARIAN = 1; - int PATH_TEETOTALER = 2; - int PATH_OXYGENARIAN = 3; - - int PATH_BEES_HATE_YOU = 4; - int PATH_WAY_OF_THE_SURPRISING_FIST = 6; - int PATH_TRENDY = 7; - int PATH_AVATAR_OF_BORIS = 8; - int PATH_BUGBEAR_INVASION = 9; - int PATH_ZOMBIE_SLAYER = 10; - int PATH_CLASS_ACT = 11; - int PATH_AVATAR_OF_JARLSBERG = 12; - int PATH_BIG = 14; - int PATH_KOLHS = 15; - int PATH_CLASS_ACT_2 = 16; - int PATH_AVATAR_OF_SNEAKY_PETE = 17; - int PATH_SLOW_AND_STEADY = 18; - int PATH_HEAVY_RAINS = 19; - int PATH_PICKY = 21; - int PATH_STANDARD = 22; - int PATH_ACTUALLY_ED_THE_UNDYING = 23; - int PATH_ONE_CRAZY_RANDOM_SUMMER = 24; - int PATH_COMMUNITY_SERVICE = 25; - int PATH_AVATAR_OF_WEST_OF_LOATHING = 26; - int PATH_THE_SOURCE = 27; - int PATH_NUCLEAR_AUTUMN = 28; - int PATH_GELATINOUS_NOOB = 29; - int PATH_LICENSE_TO_ADVENTURE = 30; - int PATH_LIVE_ASCEND_REPEAT = 31; - int PATH_POCKET_FAMILIARS = 32; - int PATH_G_LOVER = 33; - int PATH_DISGUISES_DELIMIT = 34; - int PATH_DEMIGUISE = 34; - int PATH_DARK_GYFFTE = 35; - int PATH_DARK_GIFT = 35; - int PATH_VAMPIRE = 35; - int PATH_2CRS = 36; - int PATH_KINGDOM_OF_EXPLOATHING = 37; - int PATH_EXPLOSION = 37; - int PATH_EXPLOSIONS = 37; - int PATH_EXPLODING = 37; - int PATH_EXPLODED = 37; - int PATH_OF_THE_PLUMBER = 38; - int PATH_LOW_KEY_SUMMER = 39; - int PATH_GREY_GOO = 40; - int PATH_YOU_ROBOT = 41; - int PATH_QUANTUM_TERRARIUM = 42; - int PATH_WILDFIRE = 43; - int PATH_GREY_YOU = 44; - int PATH_JOURNEYMAN = 45; - int PATH_FALL_OF_THE_DINOSAURS = 46; - int PATH_AVATAR_OF_SHADOWS_OVER_LOATHING = 47; - int PATH_LEGACY_OF_LOATHING = 48; - int PATH_SMOL = 49; // easier to type - int PATH_A_SHRUNKEN_ADVENTURER_AM_I = 49; - int PATH_WEREPROFESSOR = 50; - int PATH_SEA = 55; -} - -float numeric_modifier_replacement(item it, string modifier_string) { - string modifier_lowercase = modifier_string.to_lower_case(); - float additional = 0; - if (my_path().id == PATH_G_LOVER && !it.contains_text("g") && !it.contains_text("G")) - return 0.0; - if (it == $item[your cowboy boots]) - { - if (modifier_lowercase == "monster level" && $slot[bootskin].equipped_item() == $item[diamondback skin]) - { - return 20.0; - } - if (modifier_lowercase == "initiative" && $slot[bootspur].equipped_item() == $item[quicksilver spurs]) - return 30; - if (modifier_lowercase == "item drop" && $slot[bootspur].equipped_item() == $item[nicksilver spurs]) - return 30; - if (modifier_lowercase == "muscle percent" && $slot[bootskin].equipped_item() == $item[grizzled bearskin]) - return 50.0; - if (modifier_lowercase == "mysticality percent" && $slot[bootskin].equipped_item() == $item[frontwinder skin]) - return 50.0; - if (modifier_lowercase == "moxie percent" && $slot[bootskin].equipped_item() == $item[mountain lion skin]) - return 50.0; - //FIXME deal with rest (resistance, etc) - } - //so, when we don't have the smithsness items equipped, they have a numeric modifier of zero. - //but, they always have an inherent value of five. so give them that. - //FIXME do other smithsness items - if (it == $item[a light that never goes out] && modifier_lowercase == "item drop") - { - if (it.equipped_amount() == 0) - additional += 5; - } - return numeric_modifier(it, modifier_string) + additional; -} - - -static { - skill [class][int] __skills_by_class; - - void initialiseSkillsByClass() { - if (__skills_by_class.count() > 0) return; - foreach s in $skills[] { - if (s.class != $class[none]) { - if (!(__skills_by_class contains s.class)) { - skill [int] blank; - __skills_by_class[s.class] = blank; - } - __skills_by_class[s.class].listAppend(s); - } - } - } - initialiseSkillsByClass(); -} - - -static { - boolean [skill] __libram_skills; - - void initialiseLibramSkills() { - foreach s in $skills[] { - if (s.libram) - __libram_skills[s] = true; - } - } - initialiseLibramSkills(); -} - - -static { - boolean [item] __items_that_craft_food; - boolean [item] __minus_combat_equipment; - boolean [item] __equipment; - boolean [item] __items_in_outfits; - boolean [string][item] __equipment_by_numeric_modifier; - void initialiseItems() { - foreach it in $items[] { - //Crafting: - string craft_type = it.craft_type(); - if (craft_type.contains_text("Cooking")) { - foreach ingredient in it.get_ingredients_fast() { - __items_that_craft_food[ingredient] = true; - } - } - - //Equipment: - if ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3,familiar] contains it.to_slot()) { - __equipment[it] = true; - if (it.numeric_modifier("combat rate") < 0) { - __minus_combat_equipment[it] = true; - } - } - } - foreach key, outfit_name in all_normal_outfits() { - foreach key, it in outfit_pieces(outfit_name) - __items_in_outfits[it] = true; - } - } - initialiseItems(); -} - -boolean [item] equipmentWithNumericModifier(string modifier_string) -{ - modifier_string = modifier_string.to_lower_case(); - boolean [item] dynamic_items; - dynamic_items[to_item("kremlin's greatest briefcase")] = true; - dynamic_items[$item[your cowboy boots]] = true; - dynamic_items[$item[a light that never goes out]] = true; //FIXME all smithsness items - if (!(__equipment_by_numeric_modifier contains modifier_string)) - { - //Build it: - boolean [item] blank; - __equipment_by_numeric_modifier[modifier_string] = blank; - foreach it in __equipment - { - if (dynamic_items contains it) continue; - if (it.numeric_modifier(modifier_string) != 0.0) - __equipment_by_numeric_modifier[modifier_string][it] = true; - } - } - //Certain equipment is dynamic. Inspect them dynamically: - boolean [item] extra_results; - foreach it in dynamic_items - { - if (it.numeric_modifier_replacement(modifier_string) != 0.0) - { - extra_results[it] = true; - } - } - //damage + spell damage is basically the same for most things - string secondary_modifier = ""; - foreach e in $elements[hot,cold,spooky,stench,sleaze] - { - if (modifier_string == e + " damage") - secondary_modifier = e + " spell damage"; - } - if (secondary_modifier != "") - { - foreach it in equipmentWithNumericModifier(secondary_modifier) - extra_results[it] = true; - } - - if (extra_results.count() == 0) - return __equipment_by_numeric_modifier[modifier_string]; - else - { - //Add extras: - foreach it in __equipment_by_numeric_modifier[modifier_string] - { - extra_results[it] = true; - } - return extra_results; - } -} - -static -{ - boolean [item] __beancannon_source_items = $items[Heimz Fortified Kidney Beans,Hellfire Spicy Beans,Mixed Garbanzos and Chickpeas,Pork 'n' Pork 'n' Pork 'n' Beans,Shrub's Premium Baked Beans,Tesla's Electroplated Beans,Frigid Northern Beans,Trader Olaf's Exotic Stinkbeans,World's Blackest-Eyed Peas]; -} - -static -{ - //This would be a good mafia proxy value. Feature request? - boolean [skill] __combat_skills_that_are_spells; - void initialiseCombatSkillsThatAreSpells() - { - //Saucecicle,Surge of Icing are guesses - foreach s in $skills[Awesome Balls of Fire,Bake,Blend,Blinding Flash,Boil,Candyblast,Cannelloni Cannon,Carbohydrate Cudgel,Chop,CLEESH,Conjure Relaxing Campfire,Creepy Lullaby,Curdle,Doubt Shackles,Eggsplosion,Fear Vapor,Fearful Fettucini,Freeze,Fry,Grease Lightning,Grill,Haggis Kick,Inappropriate Backrub,Käsesoßesturm,Mudbath,Noodles of Fire,Rage Flame,Raise Backup Dancer,Ravioli Shurikens,Salsaball,Saucegeyser,Saucemageddon,Saucestorm,Saucy Salve,Shrap,Slice,Snowclone,Spaghetti Spear,Stream of Sauce,Stringozzi Serpent,Stuffed Mortar Shell,Tear Wave,Toynado,Volcanometeor Showeruption,Wassail,Wave of Sauce,Weapon of the Pastalord,Saucecicle,Surge of Icing] - { - __combat_skills_that_are_spells[s] = true; - } - foreach s in $skills[Lavafava,Pungent Mung,Beanstorm] //FIXME cowcall? snakewhip? - __combat_skills_that_are_spells[s] = true; - } - initialiseCombatSkillsThatAreSpells(); -} - -static -{ - location [item] __shen_items_to_locations = { - $item[Murphy's Rancid Black Flag]:$location[The Castle in the Clouds in the Sky (Top Floor)], - $item[The Stankara Stone]:$location[The Batrat and Ratbat Burrow], - $item[The First Pizza]:$location[Lair of the Ninja Snowmen], - $item[The Eye of the Stars]:$location[The Hole in the Sky], - $item[The Lacrosse Stick of Lacoronado]:$location[The Smut Orc Logging Camp], - $item[The Shield of Brook]:$location[The VERY Unquiet Garves]}; - - item [int] [int] __shen_start_day_to_assignments = { - //Shen's demands are seeded based on what day you're at when first meeting him. - 1:{1:$item[The Stankara Stone], 2:$item[The First Pizza], 3:$item[Murphy's Rancid Black Flag]}, - 2:{1:$item[The Lacrosse Stick of Lacoronado], 2:$item[The Shield of Brook], 3:$item[The Eye of the Stars]}, - 3:{1:$item[The First Pizza], 2:$item[The Stankara Stone], 3:$item[The Shield of Brook]}, - 4:{1:$item[The Lacrosse Stick of Lacoronado], 2:$item[The Stankara Stone], 3:$item[The Shield of Brook]}, - 5:{1:$item[Murphy's Rancid Black Flag], 2:$item[The Lacrosse Stick of Lacoronado], 3:$item[The Eye of the Stars]}, - 6:{1:$item[Murphy's Rancid Black Flag], 2:$item[The Stankara Stone], 3:$item[The Eye of the Stars]}, - 7:{1:$item[The Lacrosse Stick of Lacoronado], 2:$item[The Shield of Brook], 3:$item[The Eye of the Stars]}, - 8:{1:$item[The Shield of Brook], 2:$item[Murphy's Rancid Black Flag], 3:$item[The Lacrosse Stick of Lacoronado]}, - 9:{1:$item[The Shield of Brook], 2:$item[The Lacrosse Stick of Lacoronado], 3:$item[The Eye of the Stars]}, - 10:{1:$item[The Eye of the Stars], 2:$item[The Stankara Stone], 3:$item[Murphy's Rancid Black Flag]}, - 11:{1:$item[The First Pizza], 2:$item[The Stankara Stone], 3:$item[Murphy's Rancid Black Flag]}}; - - item [int] __shen_exploathing_assignments = {1:$item[The Eye of the Stars], 2:$item[The Lacrosse Stick of Lacoronado], 3:$item[The First Pizza]}; - //tried to develop in case there's more paths with fixed assignments in the future, but gave up. Not worth it without knowing if it'll really happen and how they'll work. -} -location [int] shenAssignmentsJoinLocationsStartingAfter(item [int] assignments, int index) { //messy/ugly, but saves a lot of time - location [int] destinations; - - //ignores the first elements - foreach position, assignment in assignments { - if (position > index) - destinations.listAppend(__shen_items_to_locations[assignment]); - } - return destinations; -} -location [int] shenAssignmentsJoinLocations(item [int] assignments) { - return shenAssignmentsJoinLocationsStartingAfter(assignments, 0); -} -location [int] getFutureShenAssignments(int [string] level_11_state_ints) { //QuestState's haven't been set yet, so instead, pass the whole __quest_state["Level 11 Shen"].state_int to the function (this is sooooo stupid, I know, but still simpler than passing the two values every single call) - item [int] assignments; - if (my_path().id == PATH_KINGDOM_OF_EXPLOATHING) - assignments = __shen_exploathing_assignments; - else - assignments = __shen_start_day_to_assignments[level_11_state_ints["Shen initiation day"]]; - - //Will, by nature, only return something if you've talked to Shen at least once (unless in Exploathing) - return assignments.shenAssignmentsJoinLocationsStartingAfter(level_11_state_ints["Shen meetings"]); -} - -static -{ - boolean [monster] __snakes; - void initialiseSnakes() - { - __snakes = $monsters[aggressive grass snake,Bacon snake,Batsnake,Black adder,Burning Snake of Fire,Coal snake,Diamondback rattler,Frontwinder,Frozen Solid Snake,King snake,Licorice snake,Mutant rattlesnake,Prince snake,Sewer snake with a sewer snake in it,Snakeleton,The Snake With Like Ten Heads,Tomb asp,Trouser Snake,Whitesnake]; - } - initialiseSnakes(); -} - -item lookupAWOLOilForMonster(monster m) -{ - if (__snakes contains m) - return $item[snake oil]; - else if ($phylums[beast,dude,hippy,humanoid,orc,pirate] contains m.phylum) - return $item[skin oil]; - else if ($phylums[bug,construct,constellation,demon,elemental,elf,fish,goblin,hobo,horror,mer-kin,penguin,plant,slime,weird] contains m.phylum) - return $item[unusual oil]; - else if ($phylums[undead] contains m.phylum) - return $item[eldritch oil]; - return $item[none]; -} - -static -{ - boolean [item] __ns_tower_door_base_keys = $items[Boris\'s key,Jarlsberg\'s key,Sneaky Pete\'s key,Richard\'s star key,skeleton key,digital key]; -} - -static -{ - record Key { - item it; - location zone; - string enchantment; - string condition_for_unlock; - string pre_unlock_url; - boolean was_used; - }; - - Key [int] LKS_keys; - if (my_path().id == PATH_LOW_KEY_SUMMER) { - Key KeyMake(string name, location zone, string enchantment, string condition_for_unlock, string pre_unlock_url) { - Key result; - result.it = name.to_item(); - result.zone = zone; - result.enchantment = enchantment; - result.condition_for_unlock = condition_for_unlock; - result.pre_unlock_url = pre_unlock_url; - return result; - } - Key KeyMake(string name, location zone, string enchantment, string condition_for_unlock) { - return KeyMake(name, zone, enchantment, condition_for_unlock, ""); - } - Key KeyMake(string name, location zone, string enchantment) { - return KeyMake(name, zone, enchantment, "", ""); - } - void listAppend(Key [int] list, Key entry) { - int position = list.count(); - while (list contains position) - position += 1; - list[position] = entry; - } - - LKS_keys.listAppend(KeyMake("actual skeleton key", $location[The Skeleton Store], "+100 Damage Absorption, +10 Damage Reduction", "accepting the meathsmith\'s quest", "shop.php?whichshop=meatsmith")); - LKS_keys.listAppend(KeyMake("anchovy can key", $location[The Haunted Pantry], "+100% Food Drops")); - LKS_keys.listAppend(KeyMake("aquí", $location[South of the Border], "+3 Hot Res, +15 Hot Damage, +30 Hot Spell Damage", "getting access to the desert beach")); - LKS_keys.listAppend(KeyMake("batting cage key", $location[The Bat Hole Entrance], "+3 Stench Res, +15 Stench Damage, +30 Stench Spell Damage", "starting the boss bat quest")); - LKS_keys.listAppend(KeyMake("black rose key", $location[The Haunted Conservatory], "+5 Familiar Weight, +2 Familiar Exp")); - LKS_keys.listAppend(KeyMake("cactus key", $location[The Arid, Extra-Dry Desert], "Regen HP, Max HP +20", "reading the diary in the McGuffin quest")); - LKS_keys.listAppend(KeyMake("clown car key", $location[The \"Fun\" House], "+10 Prismatic Damage, +10 ML", "doing the nemesis quest")); - LKS_keys.listAppend(KeyMake("deep-fried key", $location[Madness Bakery], "+3 Sleaze Res, +15 Sleaze Damage, +30 Sleaze Spell Damage", "accepting the Armorer and Leggerer\'s quest", "shop.php?whichshop=armory")); - LKS_keys.listAppend(KeyMake("demonic key", $location[Pandamonium Slums], "+20% Myst Gains, Myst +5, -1 MP Skills", "finishing the Friars quest")); - LKS_keys.listAppend(KeyMake("discarded bike lock key", $location[The Overgrown Lot], "Max MP + 10, Regen MP", "accepting Doc Galaktik\'s quest", "shop.php?whichshop=doc")); - LKS_keys.listAppend(KeyMake("f'c'le sh'c'le k'y", $location[The F\'c\'le], "+20 ML", "doing the pirate\'s quest")); - LKS_keys.listAppend(KeyMake("ice key", $location[The Icy Peak], "+3 Cold Res, +15 Cold Damage, +30 Cold Spell Damage", "doing the trapper quest")); - LKS_keys.listAppend(KeyMake("kekekey", $location[The Valley of Rof L\'m Fao], "+50% Meat", "finishing the chasm quest")); - LKS_keys.listAppend(KeyMake("key sausage", $location[Cobb\'s Knob Kitchens], "-10% Combat", "doing the Cobb\'s Knob quest")); - LKS_keys.listAppend(KeyMake("knob labinet key", $location[Cobb\'s Knob Laboratory], "+20% Muscle Gains, Muscle +5, -1 MP Skills", "finding the Cobb's Knob lab key during the Cobb\'s Knob quest")); - LKS_keys.listAppend(KeyMake("knob shaft skate key", $location[The Knob Shaft], "Regen HP/MP, +3 Adventures", "finding the Cobb's Knob lab key during the Cobb\'s Knob quest")); - LKS_keys.listAppend(KeyMake("knob treasury key", $location[Cobb\'s Knob Treasury], "+50% Meat, +20% Pickpocket", "doing the Cobb\'s Knob quest")); - LKS_keys.listAppend(KeyMake("music Box Key", $location[The Haunted Nursery], "+10% Combat", "doing the Spookyraven quest")); - LKS_keys.listAppend(KeyMake("peg key", $location[The Obligatory Pirate\'s Cove], "+5 Stats", "doing the pirate\'s quest")); - LKS_keys.listAppend(KeyMake("rabbit\'s foot key", $location[The Dire Warren], "All Attributes +10")); - LKS_keys.listAppend(KeyMake("scrap metal key", $location[The Old Landfill], "+20% Moxie Gains, Moxie +5, -1MP Skills", "starting the Old Landfill quest")); - LKS_keys.listAppend(KeyMake("treasure chest key", $location[Belowdecks], "+30% Item, +30% Meat", "doing the pirate\'s quest")); - LKS_keys.listAppend(KeyMake("weremoose key", $location[Cobb\'s Knob Menagerie, Level 2], "+3 Spooky Res, +15 Spooky Damage, +30 Spooky Spell Damage", "finding the Cobb\'s Knob Menagerie key in the Cobb\'s Knob lab" + ($item[Cobb's Knob Menagerie key].available_amount() == 0 ? ", accessed by doing the Cobb\'s Knob quest" : ""))); - } -} - -static -{ - monster [location] __protonic_monster_for_location {$location[Cobb\'s Knob Treasury]:$monster[The ghost of Ebenoozer Screege], $location[The Haunted Conservatory]:$monster[The ghost of Lord Montague Spookyraven], $location[The Haunted Gallery]:$monster[The ghost of Waldo the Carpathian], $location[The Haunted Kitchen]:$monster[The Icewoman], $location[The Haunted Wine Cellar]:$monster[The ghost of Jim Unfortunato], $location[The Icy Peak]:$monster[The ghost of Sam McGee], $location[Inside the Palindome]:$monster[Emily Koops, a spooky lime], $location[Madness Bakery]:$monster[the ghost of Monsieur Baguelle], $location[The Old Landfill]:$monster[The ghost of Vanillica "Trashblossom" Gorton], $location[The Overgrown Lot]:$monster[the ghost of Oily McBindle], $location[The Skeleton Store]:$monster[boneless blobghost], $location[The Smut Orc Logging Camp]:$monster[The ghost of Richard Cockingham], $location[The Spooky Forest]:$monster[The Headless Horseman]}; -} - - -static -{ - boolean [monster][location] __monsters_natural_habitats; -} -boolean [location] getPossibleLocationsMonsterCanAppearInNaturally(monster m) -{ - if (__monsters_natural_habitats.count() == 0) - { - //initialise: - foreach l in $locations[] - { - foreach key, m in l.get_monsters() - __monsters_natural_habitats[m][l] = true; - } - } - return __monsters_natural_habitats[m]; -} diff --git a/Source/relay/TourGuide/Support/Strings.ash b/Source/relay/TourGuide/Support/Strings.ash deleted file mode 100644 index 5b6c335f..00000000 --- a/Source/relay/TourGuide/Support/Strings.ash +++ /dev/null @@ -1,367 +0,0 @@ -import "relay/TourGuide/Support/Math.ash" -import "relay/TourGuide/Support/List.ash" - -// buffer to_buffer(string str) -// { -// buffer result; -// result.append(str); -// return result; -// } - -buffer copyBuffer(buffer buf) -{ - buffer result; - result.append(buf); - return result; -} - -//split_string returns an immutable array, which will error on certain edits -//Use this function - it converts to an editable map. -string [int] split_string_mutable(string source, string delimiter) -{ - string [int] result; - string [int] immutable_array = split_string(source, delimiter); - foreach key in immutable_array - result[key] = immutable_array[key]; - return result; -} - -//This returns [] for empty strings. This isn't standard for split(), but is more useful for passing around lists. Hacky, I suppose. -string [int] split_string_alternate(string source, string delimiter) -{ - if (source.length() == 0) - return listMakeBlankString(); - return split_string_mutable(source, delimiter); -} - -string slot_to_string(slot s) -{ - if (s == $slot[acc1] || s == $slot[acc2] || s == $slot[acc3]) - return "accessory"; - else if (s == $slot[sticker1] || s == $slot[sticker2] || s == $slot[sticker3]) - return "sticker"; - else if (s == $slot[folder1] || s == $slot[folder2] || s == $slot[folder3] || s == $slot[folder4] || s == $slot[folder5]) - return "folder"; - else if (s == $slot[fakehand]) - return "fake hand"; - else if (s == $slot[crown-of-thrones]) - return "crown of thrones"; - else if (s == $slot[buddy-bjorn]) - return "buddy bjorn"; - return s; -} - -string slot_to_plural_string(slot s) -{ - if (s == $slot[acc1] || s == $slot[acc2] || s == $slot[acc3]) - return "accessories"; - else if (s == $slot[hat]) - return "hats"; - else if (s == $slot[weapon]) - return "weapons"; - else if (s == $slot[off-hand]) - return "off-hands"; - else if (s == $slot[shirt]) - return "shirts"; - else if (s == $slot[back]) - return "back items"; - - return s.slot_to_string(); -} - - -string format_today_to_string(string desired_format) -{ - return format_date_time("yyyyMMdd", today_to_string(), desired_format); -} - - -boolean stringHasPrefix(string s, string prefix) -{ - if (s.length() < prefix.length()) - return false; - else if (s.length() == prefix.length()) - return (s == prefix); - else if (substring(s, 0, prefix.length()) == prefix) - return true; - return false; -} - -boolean stringHasSuffix(string s, string suffix) -{ - if (s.length() < suffix.length()) - return false; - else if (s.length() == suffix.length()) - return (s == suffix); - else if (substring(s, s.length() - suffix.length()) == suffix) - return true; - return false; -} - - -static string [int] __uniwords_to_cardinal_map; -static string [int] __tens_to_cardinal_map; -string tens_to_cardinal(int value, boolean is_following_digits_of_larger_number) -{ - // Takes [0-99] and turns it into ["zero"-"ninety-nine"] (no negatives) - if (__uniwords_to_cardinal_map.count() == 0) - __uniwords_to_cardinal_map = split_string("zero,one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen,fifteen,sixteen,seventeen,eighteen,nineteen", ","); - - string result; - if (is_following_digits_of_larger_number) - result = "and "; - - int v = value % 100; - - if (v < 20) - return result + __uniwords_to_cardinal_map[v]; - - if (__tens_to_cardinal_map.count() == 0) - __tens_to_cardinal_map = {2:"twenty", 3:"thirty", 4:"forty", 5:"fifty", 6:"sixty", 7:"seventy", 8:"eighty", 9:"ninety"}; - - int tens = v / 10; - result += __tens_to_cardinal_map[tens]; - - int units = v % 10; - if (units != 0) - return result + "-" + __uniwords_to_cardinal_map[units]; - return result; -} -string tens_to_cardinal(int value) -{ - return tens_to_cardinal(value, false); -} - -string hundreds_to_cardinal(int value, boolean is_following_digits_of_larger_number) -{ - // Takes [0-999] and turns it into ["zero"-"nine hundred ninety-nine"] (no negatives) - int v = value % 1000; - - int hundreds = v / 100; - if (hundreds == 0) - return tens_to_cardinal(v, is_following_digits_of_larger_number); /* five million "and three" */ - - string result = tens_to_cardinal(hundreds, false) + " hundred"; - - int rest = v % 100; - if (rest > 0) - return result + " " + tens_to_cardinal(rest, is_following_digits_of_larger_number); - return result; -} -string hundreds_to_cardinal(int value) -{ - return hundreds_to_cardinal(value, false); -} - -static string [int] __short_scale_thousands_to_cardinal_map; -string int_to_cardinal(int v) -{ - string result; - if (v < 0) { - v = 0 - v; - result += "minus"; - } - - if (v == 0) return "zero"; - - if (__short_scale_thousands_to_cardinal_map.count() == 0) - __short_scale_thousands_to_cardinal_map = {0:"",3:" thousand",6:" million",9:" billion"}; - - int magnitude = v.length() - 1; - int order_of_magnitude = magnitude - magnitude % 3; - int rest = v; - boolean start = true; - - while (order_of_magnitude >= 0) { - int current_magnitude = 10**order_of_magnitude; - - int v_in_current_magnitude = rest / current_magnitude; - - if (v_in_current_magnitude > 0) - result += " " + hundreds_to_cardinal(v_in_current_magnitude, !start) + __short_scale_thousands_to_cardinal_map[order_of_magnitude]; - - order_of_magnitude -= 3; - start = false; - } - return result; -} -string int_to_wordy(int v) -{ - return int_to_cardinal(v); -} - -string int_to_position(int v) -{ - if (v == 0) - return "-"; - - string result = v; - if (v < 0) - v = 0 - v; - - if (v / 10 % 10 == 1) - return result + "th"; - - switch (v % 10) { - case 1: - return result + "st"; - case 2: - return result + "nd"; - case 3: - return result + "rd"; - } - return result + "th"; -} - -string int_to_ordinal(int v) -{ - string cardinal = int_to_cardinal(v); - if (cardinal.stringHasSuffix("y")) - return cardinal.substring(0, cardinal.length() - 1) + "ieth"; - if (cardinal.stringHasSuffix("one")) - return cardinal.substring(0, cardinal.length() - 3) + "first"; - if (cardinal.stringHasSuffix("two")) - return cardinal.substring(0, cardinal.length() - 3) + "second"; - if (cardinal.stringHasSuffix("three")) - return cardinal.substring(0, cardinal.length() - 3) + "ird"; - if (cardinal.stringHasSuffix("five")) - return cardinal.substring(0, cardinal.length() - 2) + "fth"; - if (cardinal.stringHasSuffix("eight")) - return cardinal + "h"; - if (cardinal.stringHasSuffix("nine")) - return cardinal.substring(0, cardinal.length() - 1) + "th"; - if (cardinal.stringHasSuffix("twelve")) - return cardinal.substring(0, cardinal.length() - 2) + "fth"; - return cardinal + "th"; -} -string int_to_position_wordy(int v) -{ - return int_to_ordinal(v); -} - - -string capitaliseFirstLetter(string v) -{ - buffer buf = v.to_buffer(); - if (v.length() <= 0) - return v; - buf.replace(0, 1, buf.char_at(0).to_upper_case()); - return buf.to_string(); -} - -//shadowing; this may override ints -string pluralise(float value, string non_plural, string plural) -{ - string value_out = ""; - if (value.to_int() == value) - value_out = value.to_int(); - else - value_out = value; - if (value == 1.0) - return value_out + " " + non_plural; - else - return value_out + " " + plural; -} - -string pluralise(int value, string non_plural, string plural) -{ - if (value == 1) - return value + " " + non_plural; - else - return value + " " + plural; -} - -string pluralise(int value, item i) -{ - return pluralise(value, i.to_string(), i.plural); -} - -string pluralise(item i) //whatever we have around -{ - return pluralise(i.available_amount(), i); -} - -string pluralise(effect e) -{ - return pluralise(e.have_effect(), "turn", "turns") + " of " + e; -} - -string pluraliseWordy(int value, string non_plural, string plural) -{ - if (value == 1) - { - if (non_plural == "more time") //we're gonna celebrate - return "One More Time"; - else if (non_plural == "more turn") - return "One More Turn"; - return value.int_to_wordy() + " " + non_plural; - } - else - return value.int_to_wordy() + " " + plural; -} - -string pluraliseWordy(int value, item i) -{ - return pluraliseWordy(value, i.to_string(), i.plural); -} - -string pluraliseWordy(item i) //whatever we have around -{ - return pluraliseWordy(i.available_amount(), i); -} - -string invSearch(string it) -{ - string url = "inventory.php?ftext="; - url += it.entity_encode().replace_string(" ", "+"); - return url; -} - -string invSearch(item it) -{ - return invSearch(it.name); -} - - -//Additions to standard API: -//Auto-conversion property functions: -boolean get_property_boolean(string property) -{ - return get_property(property).to_boolean(); -} - -int get_property_int(string property) -{ - return get_property(property).to_int_silent(); -} - -location get_property_location(string property) -{ - return get_property(property).to_location(); -} - -float get_property_float(string property) -{ - return get_property(property).to_float(); -} - -monster get_property_monster(string property) -{ - return get_property(property).to_monster(); -} - -//Returns true if the propery is equal to my_ascensions(). Commonly used in mafia properties. -boolean get_property_ascension(string property) -{ - return get_property_int(property) == my_ascensions(); -} - -element get_property_element(string property) -{ - return get_property(property).to_element(); -} - -item get_property_item(string property) -{ - return get_property(property).to_item(); -} diff --git a/Source/relay/TourGuide/Tasks.ash b/Source/relay/TourGuide/Tasks.ash deleted file mode 100644 index 6cd483e8..00000000 --- a/Source/relay/TourGuide/Tasks.ash +++ /dev/null @@ -1,21 +0,0 @@ -import "relay/TourGuide/Support/Checklist.ash" -import "relay/TourGuide/Support/Library.ash" -import "relay/TourGuide/Plants.ash" -import "relay/TourGuide/Support/HTML.ash" -import "relay/TourGuide/Sets.ash" - -void generateTasks(Checklist [int] checklists) -{ - ChecklistEntry [int] task_entries; - - ChecklistEntry [int] optional_task_entries; - - ChecklistEntry [int] future_task_entries; - - QuestsGenerateTasks(task_entries, optional_task_entries, future_task_entries); - SetsGenerateTasks(task_entries, optional_task_entries, future_task_entries); - - checklists.listAppend(ChecklistMake("Tasks", task_entries)); - checklists.listAppend(ChecklistMake("Optional Tasks", optional_task_entries)); - checklists.listAppend(ChecklistMake("Future Tasks", future_task_entries)); -} \ No newline at end of file diff --git a/Source/relay/relay_TourGuide.ash b/Source/relay/relay_TourGuide.ash deleted file mode 100644 index b46c13bf..00000000 --- a/Source/relay/relay_TourGuide.ash +++ /dev/null @@ -1,9 +0,0 @@ -//This script and its support scripts are in the public domain. - -since r28562; // fix: names for base hippy camp, frat house, video game dungeons -import "relay/TourGuide/Main.ash" - -void main() -{ - runMain(__FILE__); -} diff --git a/documentation/develop.md b/documentation/develop.md deleted file mode 100644 index 8664c507..00000000 --- a/documentation/develop.md +++ /dev/null @@ -1,7 +0,0 @@ -tourguide logo - -# TourGuide Development - -This file will go over the basics of developing for TourGuide. - -This file will also be updated at a later date, because Scotch is tired. \ No newline at end of file diff --git a/documentation/history.md b/documentation/history.md deleted file mode 100644 index 1ef9f417..00000000 --- a/documentation/history.md +++ /dev/null @@ -1,25 +0,0 @@ -tourguide logo - -# TourGuide History -TourGuide is based on a script by [Ezandora](https://github.com/Ezandora/Guide), a long-time KoL speedrunner who built Guide in 2014 as a way to help advise the KoL community on the best ascension tips and tricks from her Gold Star runs and from her /hardcore friends. Guide was quite actively updated and maintained by Ezandora alone from January 2014 to August 2019. - -In September 2019, the world of KoL changed. The creator of the game, Zack Johnson, was [credibly accused of physical and emotional abuse](https://www.gamesindustry.biz/games-professor-accuses-kingdom-of-loathing-designer-of-abuse) by his ex-wife, A.M. Darke. Many, many people left KoL (or drastically reduced their time investment in the game) around this time; while Ezandora did not leave, she did dramatically reduce her investment, and her scripts (largely) became unsupported and unmaintained. She was not alone -- many other KoL scripters backed out similarly around that time as well (Stary, Veracity, Soolar, Cheesecookie, etc). Around this time, players who remained active in the game realized that they would need to fork, support, and update their favorite tools if they wished to continue using them as the game continued to receive monthly and yearly content in IOTMs and Challenge Paths. - -**Loathing Associates Scripting Society** was formed by members of the Ascension Speed Show discord by many such players, who began forking old scripts and building new scripts to rebuild and refactor them into the new KoL scripting world. One member of LASS reached out to Ezandora to request her blessing in forking and using Guide; when no response was received, the LASS member defaulted to Ezandora's [public domain licensing](https://github.com/Ezandora/Guide/blob/master/LICENSE) on Guide and forked it. He began developing it by adding recent IOTMs and bringing the team along on the development of the tool. Several months after this began and TourGuide's first beta was released, Ezandora expressed discontent with the idea of TourGuide, messaged a few members of LASS noting that she did not approve of the fork, and began pushing a handful of updates to Guide. Ezandora has (sporadically) supported Guide since; it does not cover every IOTM since September 2019, but it covers a handful of them now, and is consistently kept abreast of breaking changes. - -There was a significant internal debate among TourGuide developers at how to respond to Ezandora's discontent with our fork. We ended up landing at this: while TourGuide owes a massive debt in intellectual property to Ezandora, the actual script is very, very different than the current vintage of Guide. Despite being built on the same exact scaffolding, with extra years of development and a different team overseeing the proceedings, TourGuide and Guide are **very** different scripts. The team that oversees TourGuide has a deep and substantial appreciation to the incredible work Ezandora has done on Guide, both prior to and after we began work on TourGuide. But we feel TourGuide -- with additional IOTM resource advice, slightly different quest requests, and increased usage of the script's alert mechanisms -- has an important place in the KoL ecosystem for bleeding edge speedrunners. - -We share this here for three reasons. One, we wanted to make sure users are aware of how important Ezandora is to the underlying code that built TourGuide and stands at the script's scaffolding. Two, we wanted to make sure any member of the public who would potentially rather keep using Guide if they knew this history would have that knowledge. And finally, we wanted to make sure to express that while we respect and appreciate Ezandora's work, it is our view that TourGuide is distinct enough and content-rich enough to deserve continued support even with Ezan's Guide updates over the recent years. - -Thank you for reading! - -# Developer Credits - -In addition to [Ezandora](https://github.com/Ezandora) (noted above), here are a handful of developers we would like to explicitly credit for their substantial work on TourGuide over the years: - -- [fredg1](https://github.com/fredg1) -- [JamesDowney](https://github.com/JamesDowney) (aka Beldur) -- [uthuluc](https://github.com/uthuluc) (aka The Erosionseeker) -- [docrostov](https://github.com/docrostov) (aka Captain Scotch) -- [ajcoppa](https://github.com/ajcoppa) (aka zincaito) -- [cdrock](https://github.com/cdrock) diff --git a/documentation/scope.md b/documentation/scope.md deleted file mode 100644 index 27410caa..00000000 --- a/documentation/scope.md +++ /dev/null @@ -1,33 +0,0 @@ -tourguide logo - -# TourGuide Scope - -In this page, we're going to outline exactly what TourGuide is meant to do. This is an evolving document that will (ideally) be updated over time, although given the age of TourGuide (and its predecessor, Guide), it seems unlikely that there will be massive scope changes without a large number of new developers coming in. - -At its core, TourGuide is an advice script. Here are some things that are out of scope and in scope for TourGuide changes. - -## Out-of-Scope - -- **TourGuide will not run turns.** - - TourGuide should never run turns by itself. This is an advice script, not an automation script. -- **TourGuide links will never directly run a turn.** - - This is slightly different from the above bullet, but it is important -- TourGuide has a ton of links to container zones, skillcasting pages, the terrarium, IOTM interfaces, etc. However, we take great pains to ensure that a user idly clicking TourGuide will not accidentally spend a turn. All TourGuide links must go to (at most) a location where a link can be clicked to spend a turn, not the link that spends the turn itself. This is a really important part of the ethos for how TourGuide tiles are designed and how we are advising our users. -- **TourGuide will not require massive preference changes.** - - TourGuide should work out of the box. There should not be a ton of preferences that require user management to make TourGuide work properly. This design ethos is part of why the tile minimization code does not involve anything in core KoLMafia preferences, instead preferring to use a user's LocalStorage. This is an active design choice. -- **TourGuide will not always be updated for quest changes in all challenge paths.** - - TourGuide has a ton of support for old paths and old quests. However, at writing, there are over 40 challenge paths in KoL. TourGuide is not meant to support every small change and every tiny quest diversion in every single challenge path. We do our best! But we can't guarantee we have -every- change tracked. If there are areas where obvious changes can improve TourGuide support for a path, we encourage users to visit our **issues** page and post it as an issue -- if it's a good change, we'll try to put some work on it. But this is not the default, and as a user, please do not enter with the expectation that TourGuide will *always* and immediately account for path-by-path quest differences. We try, but we're a very limited dev team! -- **TourGuide will not account for every IOTM synergy.** - - In many cases, TourGuide will account for important synergies. But it won't get everything, and it isn't meant to. While TourGuide will lightly poke the user and note that you should maximize your familiar weight before using free runs or running Professor Lectures, it will not string the Vintner tile and the Grey Goose tile together and tell you that you should run the Vintner for familiar experience wine to make your Grey Goose gain weight quicker. The tiles are (largely) meant to be somewhat laser focused on the resource or task in question, with only occasional notes encouraging synergistic use. - -## In-Scope - -- **TourGuide will expose as much information from mafia preferences as possible to the user.** - - It is very important that TourGuide exposes the user to all the incredible data KoLMafia stores to make ascending easier. The entire point of TourGuide as an exercise is to take all that data and turn it into something that's powerful and helpful for a burgeoning speed ascender. -- **TourGuide will be responsive.** - - Users should not need to reload TourGuide -- it reloads itself constantly, making sure it stays up to date as you use resources in your KoL day. -- **TourGuide will make it easier to navigate the map by linking to container zones that make it easier to complete quests.** - - While we will never link to a zone where you spend a turn, we will absolutely make the user's navigation tasks easier by linking to containers and areas that they need to be if they want to advance a particular quest. -- **TourGuide will help alert the user when they may be missing an important resource.** - - This ties into the "alert" framework we discussed in our "Usage" documentation. This is a mild difference from prior iterations of TourGuide -- the current developers are much more focused on alerting the user when they have a resource pending they may want to use. If you do not want the alerts, we highly recommend using our minimization functions to ignore them -- they're a part of TourGuide now. -- **TourGuide will tell bad jokes.** - - Lots of them. Lots of bad jokes, all over the place. \ No newline at end of file diff --git a/documentation/usage.md b/documentation/usage.md deleted file mode 100644 index 65f0b0b0..00000000 --- a/documentation/usage.md +++ /dev/null @@ -1,73 +0,0 @@ -tourguide logo - -# Using TourGuide - -This file is meant to be a more detailed introduction to what TourGuide is and what kind of features TourGuide has. - -## Walking Through TourGuide -The easiest way to explain what TourGuide does is to show screenshots. To start, this is a view of what TourGuide looks like on initial run, for a user who is midway through a run. - -![image](https://user-images.githubusercontent.com/8014761/192012161-1a120f69-e811-47ac-9915-28c91ceb4cb2.png) - -At the top, TourGuide will tell you how many turns you've played in your ascension -- this helps speedrunners tell how they're doing on broader turncount relative to their overarching turncount goal. Underneath, it will start out by telling you your **Tasks**, which is the language TourGuide uses to represent things the user needs to do, most prominently main game quests -- as seen in the screenshot, things like the Boss Bat Quest, Knob Goblin Quest, Highland Lord Quest, etc. - -Each quest is associated with a tile. The tile changes as the user proceeds on the quest, giving different advice for different stages in the respective quest. Note that the Boss Bat Tile here describes a state where the user is 1 turn of delay away from the Boss Bat being eligible for inclusion in the monster pool in the Boss Bat Chamber. If the user had not yet unlocked the Boss Bat Chamber, the tile would instead show information advising the user to get Sonar-in-a-Biscuit items or adventure to find Screambats. If you were to click on the task tile, TourGuide will try to send you to the container zone where the quest is set -- for instance, if we were to click on Castle quest, we'd get this in our main window: - -![image](https://user-images.githubusercontent.com/8014761/192012232-e6805ffc-44ff-4ad7-86fa-a219e0a43472.png) - -Directly below tasks, TourGuide reports **Optional Tasks** -- these are tasks that are (surprise!) very optional. Tracked tasks like your nemesis quest will live here, tasks that are not required at the present time and in many cases not required for ascension at all. Sometimes, tasks that will eventually be required but are not yet required (like burning delay in Spookyraven's Haunted Ballroom) will also appear here. - -Below tasks & optional tasks, there are **Resources**, tracking the myriad resources users have at their disposal during an ascension. Things like free kills, banishes, buffs, et cetera. - -![image](https://user-images.githubusercontent.com/8014761/192012329-84f29dc2-3564-4910-809f-3e011cfaa44d.png) - -These can get very, very large in unrestricted paths, as seen in the banish tile (headlined by Snokebombs and the Middle Finger Ring). There are often significant resources that go either unused or virtually unable-to-be-used in unrestricted. But in Standard paths, this tends to be a great end-of-day reminder zone -- if you're getting close to the end of your day, it's a good idea to scroll down to resources and ensure that you've used everything that's available in some way or another. - -When relevant, Resource tiles will link to the relevant container zone (for example, the cloud-talk buff tile will link to your Getaway Campsite). More often, they will link to either the skills page (if the Resource is a skill), your equipment page (if you need to equip something to make that resource work), or your terrarium (if the resource is a familiar that needs to be equipped). - -One thing that's important to call out is the alert system. TourGuide is coded such that it tries to explicitly alert you when there are time-dependent tasks that are imminently available. Alerts will float at the top of the sidebar, ensuring they don't go away even if you are scrolled down and examining a tile lower in the sidebar. Alerts will look like this: - -![image](https://user-images.githubusercontent.com/8014761/192012398-d9f0efef-2aa2-4414-a359-08017c63e30a.png) - -Things that TourGuide tries to alert the user of are too varied to fully account. Here are some examples: - -- If a digitized monster will show up in your next adventure -- If you have a Cold Medicine Cabinet consultation available -- If you have an Asdon Martin banish available right now (as seen above) -- If you have a Cleaver NC ready to go on your next adventure - -Finally, there's the bottom bar of TourGuide. This includes links that will take you to the top item in each of the previously described tile zones (Tasks, Optional Tasks, and Resources). It also includes something even more useful -- a zone summary. - -![image](https://user-images.githubusercontent.com/8014761/192012470-2266aa41-c49e-4d17-bef9-4cfe535b0730.png) - -When you aren't hovering over the summary, it will show you the bottom part of that screenshot: the name of the zone, the environment of the zone (Underground, Indoors, Outdoors, etc) and the number of turns you've spent in the zone (including freeruns and delay you've burned there). This is useful for delay burn tracking and complaining about how long a task is taking during your ascension, one of the most important parts of KOL. When you hover over the summary, it will show you the monsters within the zone, the phylum of the given monsters, their respective item drop tables, and the projected probability that you will encounter any given monster in the zone on your incoming turn, based on KoLMafia's calculation of rejection probability and the current banishes. It will also show you which monsters in the zone are banished, ultra rares that exist within the zone, and the drop rate of items on monsters in the zone in their drop tables. Here, when it says "100%" for the GOTO item, that means that my item drop % is high enough that I can cap a 30% drop; I will get it every time I fight a BASIC Elemental. - -## Tile Minimization - -There are a lot of tiles in TourGuide. Like, a LOT of tiles. On fully-decked-out accounts, you can get all the way to 200-300 tiles, which is an absolutely absurd amount of information. To try and help manage this, TourGuide has a tile minimization feature. To minimize the tiles, click the arrow in the top right hand corner of any given tile. - -That will turn this: - -![image](https://user-images.githubusercontent.com/8014761/192012531-d2359940-3037-4684-9222-c1abfd541245.png) - -Into this: - -![image](https://user-images.githubusercontent.com/8014761/192012589-ac94aab8-8e0e-461e-82cb-fe9403af6f3c.png) - -You can do this with, again, -every- tile. You can even set default values for it! If you right-click the arrow, you will get the following menu: - -![image](https://user-images.githubusercontent.com/8014761/192012624-868558b4-ffaf-4b83-be1e-c22722a9d1bf.png) - -Here, if there are certain tiles you want to permanently hide, you can set "Auto-Expansion" to "no" on the tile in question; TourGuide will store this in your LocalStorage, keeping the tile minimized over rollover and ascension if you choose to do so. You can also make the minimized tiles even smaller -- if you select "Don't Display" for tile image and "Replace all with tile ID" for content to show, the tile will minimize even further; instead of the default minimization above, it could look like this: - -![image](https://user-images.githubusercontent.com/8014761/192012683-b6a3733c-0f79-48eb-a124-6d4c810665ae.png) - -## Other Features - -Many people like using the KoL Chat while ascending. TourGuide supports generating two sidebars, so you can access in-game chat while you're using TourGuide. To access this, click the left-facing arrow at the top of TourGuide (which has the alt-text "Show Chat Pane".) - -![image](https://user-images.githubusercontent.com/8014761/192012791-f6ba72f0-2278-4930-9106-85aa501ca7e4.png) - -Alternatively, you can also pop TourGuide out into its own window, using the double-square box next to the described arrow. - -tourguide windowed diff --git a/Source/relay/TourGuide/TourGuide.js b/relay/TourGuide/TourGuide.js similarity index 100% rename from Source/relay/TourGuide/TourGuide.js rename to relay/TourGuide/TourGuide.js diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash new file mode 100644 index 00000000..0c0ae1c3 --- /dev/null +++ b/relay/relay_TourGuide.ash @@ -0,0 +1,61399 @@ +//This script and its support scripts are in the public domain. + +since r28562; // fix: names for base hippy camp, frat house, video game dungeons +//These settings are for development. Don't worry about editing them. +string __version = "2.2.2"; // pushed to 2.2.1 on jill/leaves tiles + +//Path and name of the .js file. In case you change either. +string __javascript = "TourGuide/TourGuide.js"; + +//Debugging: +boolean __setting_debug_mode = false; +boolean __setting_debug_enable_example_mode_in_aftercore = false; //for testing. Will give false information, so don't enable +boolean __setting_debug_show_all_internal_states = false; //displays usable images/__misc_state/__misc_state_string/__misc_state_int/__quest_state + +//Display settings: +boolean __setting_entire_area_clickable = false; +boolean __setting_side_negative_space_is_dark = true; +boolean __setting_fill_vertical = true; +int __setting_image_width_large = 100; +int __setting_image_width_medium = 70; +int __setting_image_width_small = 30; + +boolean __show_importance_bar = true; +boolean __setting_show_navbar = true; +boolean __setting_navbar_has_proportional_widths = false; //doesn't look very good, remove? +boolean __setting_gray_navbar = true; +boolean __setting_use_kol_css = false; //images/styles.css +boolean __setting_show_location_bar = true; +boolean __setting_enable_location_popup_box = true; +boolean __setting_location_bar_uses_last_location = false; //nextAdventure otherwise +boolean __setting_location_bar_fixed_layout = true; +boolean __setting_location_bar_limit_max_width = true; +float __setting_location_bar_max_width_per_entry = 0.35; +boolean __setting_enable_outputting_all_numberology_options = true; + +string __setting_unavailable_colour = "#7F7F7F"; +string __setting_line_colour = "#B2B2B2"; +string __setting_dark_colour = "#C0C0C0"; +string __setting_modifier_colour = "#404040"; +string __setting_navbar_background_colour = "#FFFFFF"; +string __setting_page_background_colour = "#F7F7F7"; + +string __setting_media_query_large_size = "@media (min-width: 500px)"; +string __setting_media_query_medium_size = "@media (min-width: 350px) and (max-width: 500px)"; +string __setting_media_query_small_size = "@media (max-width: 350px) and (min-width: 225px)"; +string __setting_media_query_tiny_size = "@media (max-width: 225px)"; + +float __setting_navbar_height_in_em = 2.3; +string __setting_navbar_height = __setting_navbar_height_in_em + "em"; +int __setting_horizontal_width = 600; +boolean __setting_ios_appearance = false; //no don't + + +//Allows error checking. The intention behind this design is Errors are passed in to a method. The method then sets the error if anything went wrong. +record Error +{ + boolean was_error; + string explanation; +}; + +Error ErrorMake(boolean was_error, string explanation) +{ + Error err; + err.was_error = was_error; + err.explanation = explanation; + return err; +} + +Error ErrorMake() +{ + return ErrorMake(false, ""); +} + +void ErrorSet(Error err, string explanation) +{ + err.was_error = true; + err.explanation = explanation; +} + +void ErrorSet(Error err) +{ + ErrorSet(err, "Unknown"); +} + +//Coordinate system is upper-left origin. + +int INT32_MAX = 2147483647; + + + +float clampf(float v, float min_value, float max_value) +{ + if (v > max_value) + return max_value; + if (v < min_value) + return min_value; + return v; +} + +float clampNormalf(float v) +{ + return clampf(v, 0.0, 1.0); +} + +int clampi(int v, int min_value, int max_value) +{ + if (v > max_value) + return max_value; + if (v < min_value) + return min_value; + return v; +} + +float clampNormali(int v) +{ + return clampi(v, 0, 1); +} + +//random() will halt the script if range is <= 1, which can happen when picking a random object out of a variable-sized list. +//There's also a hidden bug where values above 2147483647 will be treated as zero. +int random_safe(int range) +{ + if (range < 2 || range > 2147483647) + return 0; + return random(range); +} + +float randomf() +{ + return random_safe(2147483647).to_float() / 2147483647.0; +} + +//to_int will print a warning, but not halt, if you give it a non-int value. +//This function prevents the warning message. +//err is set if value is not an integer. +int to_int_silent(string value, Error err) +{ + //to_int() supports floating-point values. is_integer() will return false. + //So manually strip out everything past the dot. + //We probably should just ask for to_int() to be silent in the first place. + int dot_position = value.index_of("."); + if (dot_position != -1 && dot_position > 0) //two separate concepts - is it valid, and is it past the first position. I like testing against both, for safety against future changes. + { + value = value.substring(0, dot_position); + } + + if (is_integer(value)) + return to_int(value); + ErrorSet(err, "Unknown integer \"" + value + "\"."); + return 0; +} + +int to_int_silent(string value) +{ + return to_int_silent(value, ErrorMake()); +} + +//Silly conversions in case we chose the wrong function, removing the need for a int -> string -> int hit. +int to_int_silent(int value) +{ + return value; +} + +int to_int_silent(float value) +{ + return value; +} + + +float sqrt(float v, Error err) +{ + if (v < 0.0) + { + ErrorSet(err, "Cannot take square root of value " + v + " less than 0.0"); + return -1.0; //mathematically incorrect, but prevents halting. should return NaN + } + return square_root(v); +} + +float sqrt(float v) +{ + return sqrt(v, ErrorMake()); +} + +float fabs(float v) +{ + if (v < 0.0) + return -v; + return v; +} + +int abs(int v) +{ + if (v < 0) + return -v; + return v; +} + +int ceiling(float v) +{ + return ceil(v); +} + +int pow2i(int v) +{ + return v * v; +} + +float pow2f(float v) +{ + return v * v; +} + +//x^p +float powf(float x, float p) +{ + return x ** p; +} + +//x^p +int powi(int x, int p) +{ + return x ** p; +} + +record Vec2i +{ + int x; //or width + int y; //or height +}; + +Vec2i Vec2iMake(int x, int y) +{ + Vec2i result; + result.x = x; + result.y = y; + + return result; +} + +Vec2i Vec2iCopy(Vec2i v) +{ + return Vec2iMake(v.x, v.y); +} + +Vec2i Vec2iZero() +{ + return Vec2iMake(0,0); +} + +boolean Vec2iValueInInterval(Vec2i v, int value) +{ + if (value >= v.x && value <= v.y) + return true; + return false; +} + +boolean Vec2iValueInRange(Vec2i v, int value) +{ + return Vec2iValueInInterval(v, value); +} + +boolean Vec2iEquals(Vec2i a, Vec2i b) +{ + if (a.x != b.x) return false; + if (a.y != b.y) return false; + return true; +} + +string Vec2iDescription(Vec2i v) +{ + buffer out; + out.append("["); + out.append(v.x); + out.append(", "); + out.append(v.y); + out.append("]"); + return out.to_string(); +} + +Vec2i Vec2iIntersection(Vec2i a, Vec2i b) +{ + Vec2i result; + result.x = max(a.x, b.x); + result.y = min(a.y, b.y); + return result; +} + +boolean Vec2iIntersectsWithVec2i(Vec2i a, Vec2i b) +{ + //Assumed [min, max]: + if (a.y < b.x) return false; + if (a.x > b.y) return false; + return true; +} + +record Vec2f +{ + float x; //or width + float y; //or height +}; + +Vec2f Vec2fMake(float x, float y) +{ + Vec2f result; + result.x = x; + result.y = y; + + return result; +} + +Vec2f Vec2fCopy(Vec2f v) +{ + return Vec2fMake(v.x, v.y); +} + +Vec2f Vec2fZero() +{ + return Vec2fMake(0.0, 0.0); +} + +boolean Vec2fValueInRange(Vec2f v, float value) +{ + if (value >= v.x && value <= v.y) + return true; + return false; +} + +Vec2f Vec2fMultiply(Vec2f v, float c) +{ + return Vec2fMake(v.x * c, v.y * c); +} +Vec2f Vec2fAdd(Vec2f v, float c) +{ + return Vec2fMake(v.x + c, v.y + c); +} +float Vec2fAverage(Vec2f v) +{ + return (v.x + v.y) * 0.5; +} + + + +string Vec2fDescription(Vec2f v) +{ + buffer out; + out.append("["); + out.append(v.x); + out.append(", "); + out.append(v.y); + out.append("]"); + return out.to_string(); +} + + +record Rect +{ + Vec2i min_coordinate; + Vec2i max_coordinate; +}; + +Rect RectMake(Vec2i min_coordinate, Vec2i max_coordinate) +{ + Rect result; + result.min_coordinate = Vec2iCopy(min_coordinate); + result.max_coordinate = Vec2iCopy(max_coordinate); + return result; +} + +Rect RectCopy(Rect r) +{ + return RectMake(r.min_coordinate, r.max_coordinate); +} + +Rect RectMake(int min_x, int min_y, int max_x, int max_y) +{ + return RectMake(Vec2iMake(min_x, min_y), Vec2iMake(max_x, max_y)); +} + +Rect RectZero() +{ + return RectMake(Vec2iZero(), Vec2iZero()); +} + + +void listAppend(Rect [int] list, Rect entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +//Allows for fractional digits, not just whole numbers. Useful for preventing "+233.333333333333333% item"-type output. +//Outputs 3.0, 3.1, 3.14, etc. +float round(float v, int additional_fractional_digits) +{ + if (additional_fractional_digits < 1) + return v.round().to_float(); + float multiplier = powf(10.0, additional_fractional_digits); + return to_float(round(v * multiplier)) / multiplier; +} + +//Similar to round() addition above, but also converts whole float numbers into integers for output +string roundForOutput(float v, int additional_fractional_digits) +{ + v = round(v, additional_fractional_digits); + int vi = v.to_int(); + if (vi.to_float() == v) + return vi.to_string(); + else + return v.to_string(); +} + + +float floor(float v, int additional_fractional_digits) +{ + if (additional_fractional_digits < 1) + return v.floor().to_float(); + float multiplier = powf(10.0, additional_fractional_digits); + return to_float(floor(v * multiplier)) / multiplier; +} + +string floorForOutput(float v, int additional_fractional_digits) +{ + v = floor(v, additional_fractional_digits); + int vi = v.to_int(); + if (vi.to_float() == v) + return vi.to_string(); + else + return v.to_string(); +} + + +float TriangularDistributionCalculateCDF(float x, float min, float max, float centre) +{ + //piecewise function: + if (x < min) return 0.0; + else if (x > max) return 1.0; + else if (x >= min && x <= centre) + { + float divisor = (max - min) * (centre - min); + if (divisor == 0.0) + return 0.0; + + return pow2f(x - min) / divisor; + } + else if (x <= max && x > centre) + { + float divisor = (max - min) * (max - centre); + if (divisor == 0.0) + return 0.0; + + + return 1.0 - pow2f(max - x) / divisor; + } + else //probably only happens with weird floating point values, assume chance of zero: + return 0.0; +} + +//assume a centre equidistant from min and max +float TriangularDistributionCalculateCDF(float x, float min, float max) +{ + return TriangularDistributionCalculateCDF(x, min, max, (min + max) * 0.5); +} + +float averagef(float a, float b) +{ + return (a + b) * 0.5; +} + +boolean numberIsInRangeInclusive(int v, int min, int max) +{ + if (v < min) return false; + if (v > max) return false; + return true; +} + +//WARNING: All listAppend functions are flawed. +//Specifically, there's a possibility of a hole that causes order to be incorrect. +//But, the only way to fix that is to traverse the list to determine the maximum key. +//That would take forever... + +string listLastObject(string [int] list) +{ + if (list.count() == 0) + return ""; + return list[list.count() - 1]; +} + +void listAppend(string [int] list, string entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppendList(string [int] list, string [int] entries) +{ + foreach key in entries + list.listAppend(entries[key]); +} + +string [int] listUnion(string [int] list, string [int] list2) +{ + string [int] result; + foreach key, s in list + result.listAppend(s); + foreach key, s in list2 + result.listAppend(s); + return result; +} + +void listAppendList(boolean [item] destination, boolean [item] source) +{ + foreach it, value in source + destination[it] = value; +} + +void listAppendList(boolean [string] destination, boolean [string] source) +{ + foreach key, value in source + destination[key] = value; +} + +void listAppendList(boolean [skill] destination, boolean [skill] source) +{ + foreach key, value in source + destination[key] = value; +} + +void listAppend(item [int] list, item entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppendList(item [int] list, item [int] entries) +{ + foreach key in entries + list.listAppend(entries[key]); +} + + + +void listAppend(int [int] list, int entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(float [int] list, float entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(location [int] list, location entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(element [int] list, element entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppendList(location [int] list, location [int] entries) +{ + foreach key in entries + list.listAppend(entries[key]); +} + +void listAppend(effect [int] list, effect entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(skill [int] list, skill entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(familiar [int] list, familiar entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(monster [int] list, monster entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(phylum [int] list, phylum entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(buffer [int] list, buffer entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(slot [int] list, slot entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(thrall [int] list, thrall entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + + + + + +void listAppend(string [int][int] list, string [int] entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(skill [int][int] list, skill [int] entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(familiar [int][int] list, familiar [int] entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(int [int][int] list, int [int] entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(item [int][int] list, item [int] entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(skill [int] list, boolean [skill] entry) +{ + foreach v in entry + list.listAppend(v); +} + +void listAppend(item [int] list, boolean [item] entry) +{ + foreach v in entry + list.listAppend(v); +} + +void listPrepend(string [int] list, string entry) +{ + int position = 0; + while (list contains position) + position -= 1; + list[position] = entry; +} + +void listPrepend(skill [int] list, skill entry) +{ + int position = 0; + while (list contains position) + position -= 1; + list[position] = entry; +} + +void listAppendList(skill [int] list, skill [int] entries) +{ + foreach key in entries + list.listAppend(entries[key]); +} + +void listPrepend(location [int] list, location entry) +{ + int position = 0; + while (list contains position) + position -= 1; + list[position] = entry; +} + +void listPrepend(item [int] list, item entry) +{ + int position = 0; + while (list contains position) + position -= 1; + list[position] = entry; +} + + +void listClear(string [int] list) +{ + foreach i in list + { + remove list[i]; + } +} + +void listClear(int [int] list) +{ + foreach i in list + { + remove list[i]; + } +} + +void listClear(item [int] list) +{ + foreach i in list + { + remove list[i]; + } +} + +void listClear(location [int] list) +{ + foreach i in list + { + remove list[i]; + } +} + +void listClear(monster [int] list) +{ + foreach i in list + { + remove list[i]; + } +} + +void listClear(skill [int] list) +{ + foreach i in list + { + remove list[i]; + } +} + + +void listClear(boolean [string] list) +{ + foreach i in list + { + remove list[i]; + } +} + + +string [int] listMakeBlankString() +{ + string [int] result; + return result; +} + +item [int] listMakeBlankItem() +{ + item [int] result; + return result; +} + +skill [int] listMakeBlankSkill() +{ + skill [int] result; + return result; +} + +location [int] listMakeBlankLocation() +{ + location [int] result; + return result; +} + +monster [int] listMakeBlankMonster() +{ + monster [int] result; + return result; +} + +familiar [int] listMakeBlankFamiliar() +{ + familiar [int] result; + return result; +} + +int [int] listMakeBlankInt() +{ + int [int] result; + return result; +} + +string [int] listMake(string ... entries) +{ + string [int] result; + foreach _, e in entries + { + result.listAppend(e); + } + return result; +} + +int [int] listMake(int ... entries) +{ + int [int] result; + foreach _, e in entries + { + result.listAppend(e); + } + return result; +} + +item [int] listMake(item ... entries) +{ + item [int] result; + foreach _, e in entries + { + result.listAppend(e); + } + return result; +} + +skill [int] listMake(skill ... entries) +{ + skill [int] result; + foreach _, e in entries + { + result.listAppend(e); + } + return result; +} + +monster [int] listMake(monster ... entries) +{ + monster [int] result; + foreach _, e in entries + { + result.listAppend(e); + } + return result; +} + +string listJoinComponents(string [int] list, string joining_string, string and_string) +{ + buffer result; + boolean first = true; + int number_seen = 0; + foreach i, value in list + { + if (first) + { + result.append(value); + first = false; + } + else + { + if (!(list.count() == 2 && and_string != "")) + result.append(joining_string); + if (and_string != "" && number_seen == list.count() - 1) + { + result.append(" "); + result.append(and_string); + result.append(" "); + } + result.append(value); + } + number_seen = number_seen + 1; + } + return result.to_string(); +} + +string listJoinComponents(string [int] list, string joining_string) +{ + return listJoinComponents(list, joining_string, ""); +} + +string listJoinComponents(item [int] list, string joining_string, string and_string) +{ + //lazy: + //convert items to strings, join that + string [int] list_string; + foreach key in list + list_string.listAppend(list[key].to_string()); + return listJoinComponents(list_string, joining_string, and_string); +} + +string listJoinComponents(item [int] list, string joining_string) +{ + return listJoinComponents(list, joining_string, ""); +} + +string listJoinComponents(monster [int] list, string joining_string, string and_string) +{ + string [int] list_string; + foreach key in list + list_string.listAppend(list[key].to_string()); + return listJoinComponents(list_string, joining_string, and_string); +} +string listJoinComponents(monster [int] list, string joining_string) +{ + return listJoinComponents(list, joining_string, ""); +} + +string listJoinComponents(effect [int] list, string joining_string, string and_string) +{ + string [int] list_string; + foreach key in list + list_string.listAppend(list[key].to_string()); + return listJoinComponents(list_string, joining_string, and_string); +} + +string listJoinComponents(effect [int] list, string joining_string) +{ + return listJoinComponents(list, joining_string, ""); +} + + +string listJoinComponents(familiar [int] list, string joining_string, string and_string) +{ + string [int] list_string; + foreach key in list + list_string.listAppend(list[key].to_string()); + return listJoinComponents(list_string, joining_string, and_string); +} + +string listJoinComponents(familiar [int] list, string joining_string) +{ + return listJoinComponents(list, joining_string, ""); +} + + + +string listJoinComponents(location [int] list, string joining_string, string and_string) +{ + //lazy: + //convert locations to strings, join that + string [int] list_string; + foreach key in list + list_string.listAppend(list[key].to_string()); + return listJoinComponents(list_string, joining_string, and_string); +} + +string listJoinComponents(location [int] list, string joining_string) +{ + return listJoinComponents(list, joining_string, ""); +} + +string listJoinComponents(phylum [int] list, string joining_string, string and_string) +{ + string [int] list_string; + foreach key in list + list_string.listAppend(list[key].to_string()); + return listJoinComponents(list_string, joining_string, and_string); +} + +string listJoinComponents(phylum [int] list, string joining_string) +{ + return listJoinComponents(list, joining_string, ""); +} + + + +string listJoinComponents(skill [int] list, string joining_string, string and_string) +{ + string [int] list_string; + foreach key in list + list_string.listAppend(list[key].to_string()); + return listJoinComponents(list_string, joining_string, and_string); +} + +string listJoinComponents(skill [int] list, string joining_string) +{ + return listJoinComponents(list, joining_string, ""); +} + +string listJoinComponents(int [int] list, string joining_string, string and_string) +{ + //lazy: + //convert ints to strings, join that + string [int] list_string; + foreach key in list + list_string.listAppend(list[key].to_string()); + return listJoinComponents(list_string, joining_string, and_string); +} + +string listJoinComponents(int [int] list, string joining_string) +{ + return listJoinComponents(list, joining_string, ""); +} + + +void listRemoveKeys(string [int] list, int [int] keys_to_remove) +{ + foreach i in keys_to_remove + { + int key = keys_to_remove[i]; + if (!(list contains key)) + continue; + remove list[key]; + } +} + +int listSum(int [int] list) +{ + int v = 0; + foreach key in list + { + v += list[key]; + } + return v; +} + + +string [int] listCopy(string [int] l) +{ + string [int] result; + foreach key in l + result[key] = l[key]; + return result; +} + +int [int] listCopy(int [int] l) +{ + int [int] result; + foreach key in l + result[key] = l[key]; + return result; +} + +monster [int] listCopy(monster [int] l) +{ + monster [int] result; + foreach key in l + result[key] = l[key]; + return result; +} + +element [int] listCopy(element [int] l) +{ + element [int] result; + foreach key in l + result[key] = l[key]; + return result; +} + +skill [int] listCopy(skill [int] l) +{ + skill [int] result; + foreach key in l + result[key] = l[key]; + return result; +} + +boolean [monster] listCopy(boolean [monster] l) +{ + boolean [monster] result; + foreach key in l + result[key] = l[key]; + return result; +} + +//Strict, in this case, means the keys start at 0, and go up by one per entry. This allows easy consistent access +boolean listKeysMeetStrictRequirements(string [int] list) +{ + int expected_value = 0; + foreach key in list + { + if (key != expected_value) + return false; + expected_value += 1; + } + return true; +} +string [int] listCopyStrictRequirements(string [int] list) +{ + string [int] result; + foreach key in list + result.listAppend(list[key]); + return result; +} + +string [string] mapMake() +{ + string [string] result; + return result; +} + +string [string] mapMake(string key1, string value1) +{ + string [string] result; + result[key1] = value1; + return result; +} + +string [string] mapMake(string key1, string value1, string key2, string value2) +{ + string [string] result; + result[key1] = value1; + result[key2] = value2; + return result; +} + +string [string] mapMake(string key1, string value1, string key2, string value2, string key3, string value3) +{ + string [string] result; + result[key1] = value1; + result[key2] = value2; + result[key3] = value3; + return result; +} + +string [string] mapMake(string key1, string value1, string key2, string value2, string key3, string value3, string key4, string value4) +{ + string [string] result; + result[key1] = value1; + result[key2] = value2; + result[key3] = value3; + result[key4] = value4; + return result; +} + +string [string] mapMake(string key1, string value1, string key2, string value2, string key3, string value3, string key4, string value4, string key5, string value5) +{ + string [string] result; + result[key1] = value1; + result[key2] = value2; + result[key3] = value3; + result[key4] = value4; + result[key5] = value5; + return result; +} + + +string [string] mapMake(string key1, string value1, string key2, string value2, string key3, string value3, string key4, string value4, string key5, string value5, string key6, string value6) +{ + string [string] result; + result[key1] = value1; + result[key2] = value2; + result[key3] = value3; + result[key4] = value4; + result[key5] = value5; + result[key6] = value6; + return result; +} + +string [string] mapCopy(string [string] map) +{ + string [string] result; + foreach key in map + result[key] = map[key]; + return result; +} + +boolean mapsAreEqual(string [string] map1, string [string] map2) +{ + if (map1.count() != map2.count()) + { + //print_html("map1.c = " + map1.count() + " which is not " + map2.count()); + return false; + } + foreach key1, v in map1 + { + if (!(map2 contains key1)) + { + //print_html("map2 lacks " + key1); + return false; + } + if (map2[key1] != v) + { + //print_html("map2 v(" + map2[key1] + " does not equal " + key1 + " (" + v + ")"); + return false; + } + } + return true; +} + +boolean [string] listInvert(string [int] list) +{ + boolean [string] result; + foreach key in list + { + result[list[key]] = true; + } + return result; +} + + +boolean [int] listInvert(int [int] list) +{ + boolean [int] result; + foreach key in list + { + result[list[key]] = true; + } + return result; +} + +boolean [location] listInvert(location [int] list) +{ + boolean [location] result; + foreach key in list + { + result[list[key]] = true; + } + return result; +} + +boolean [item] listInvert(item [int] list) +{ + boolean [item] result; + foreach key in list + { + result[list[key]] = true; + } + return result; +} + +boolean [monster] listInvert(monster [int] list) +{ + boolean [monster] result; + foreach key in list + { + result[list[key]] = true; + } + return result; +} + +boolean [familiar] listInvert(familiar [int] list) +{ + boolean [familiar] result; + foreach key in list + { + result[list[key]] = true; + } + return result; +} + +int [int] listConvertToInt(string [int] list) +{ + int [int] result; + foreach key in list + result[key] = list[key].to_int(); + return result; +} + +item [int] listConvertToItem(string [int] list) +{ + item [int] result; + foreach key in list + result[key] = list[key].to_item(); + return result; +} + +string listFirstObject(string [int] list) +{ + foreach key in list + return list[key]; + return ""; +} + +//(I'm assuming maps have a consistent enumeration order, which may not be the case) +int listKeyForIndex(string [int] list, int index) +{ + int i = 0; + foreach key in list + { + if (i == index) + return key; + i += 1; + } + return -1; +} + +int listKeyForIndex(location [int] list, int index) +{ + int i = 0; + foreach key in list + { + if (i == index) + return key; + i += 1; + } + return -1; +} + +int listKeyForIndex(familiar [int] list, int index) +{ + int i = 0; + foreach key in list + { + if (i == index) + return key; + i += 1; + } + return -1; +} + +int listKeyForIndex(item [int] list, int index) +{ + int i = 0; + foreach key in list + { + if (i == index) + return key; + i += 1; + } + return -1; +} + +int listKeyForIndex(monster [int] list, int index) +{ + int i = 0; + foreach key in list + { + if (i == index) + return key; + i += 1; + } + return -1; +} + +int listKeyForIndex(int [int] list, int index) +{ + int i = 0; + foreach key in list + { + if (i == index) + return key; + i += 1; + } + return -1; +} + +int llistKeyForIndex(string [int][int] list, int index) +{ + int i = 0; + foreach key in list + { + if (i == index) + return key; + i += 1; + } + return -1; +} + +string listGetRandomObject(string [int] list) +{ + if (list.count() == 0) + return ""; + if (list.count() == 1) + return list[listKeyForIndex(list, 0)]; + return list[listKeyForIndex(list, random(list.count()))]; +} + +item listGetRandomObject(item [int] list) +{ + if (list.count() == 0) + return $item[none]; + if (list.count() == 1) + return list[listKeyForIndex(list, 0)]; + return list[listKeyForIndex(list, random(list.count()))]; +} + +location listGetRandomObject(location [int] list) +{ + if (list.count() == 0) + return $location[none]; + if (list.count() == 1) + return list[listKeyForIndex(list, 0)]; + return list[listKeyForIndex(list, random(list.count()))]; +} + +familiar listGetRandomObject(familiar [int] list) +{ + if (list.count() == 0) + return $familiar[none]; + if (list.count() == 1) + return list[listKeyForIndex(list, 0)]; + return list[listKeyForIndex(list, random(list.count()))]; +} + +monster listGetRandomObject(monster [int] list) +{ + if (list.count() == 0) + return $monster[none]; + if (list.count() == 1) + return list[listKeyForIndex(list, 0)]; + return list[listKeyForIndex(list, random(list.count()))]; +} + +int listGetRandomObject(int [int] list) +{ + if (list.count() == 0) + return -1; + if (list.count() == 1) + return list[listKeyForIndex(list, 0)]; + return list[listKeyForIndex(list, random(list.count()))]; +} + + +boolean listContainsValue(monster [int] list, monster vo) +{ + foreach key, v2 in list + { + if (v2 == vo) + return true; + } + return false; +} + +boolean listContainsValue(string [int] list, string vo) +{ + foreach key, v2 in list + { + if (v2 == vo) + return true; + } + return false; +} + +string [int] listInvert(boolean [string] list) +{ + string [int] out; + foreach m, value in list + { + if (value) + out.listAppend(m); + } + return out; +} + +int [int] listInvert(boolean [int] list) +{ + int [int] out; + foreach m, value in list + { + if (value) + out.listAppend(m); + } + return out; +} + +skill [int] listInvert(boolean [skill] list) +{ + skill [int] out; + foreach m, value in list + { + if (value) + out.listAppend(m); + } + return out; +} + +monster [int] listInvert(boolean [monster] monsters) +{ + monster [int] out; + foreach m, value in monsters + { + if (value) + out.listAppend(m); + } + return out; +} + +location [int] listInvert(boolean [location] list) +{ + location [int] out; + foreach k, value in list + { + if (value) + out.listAppend(k); + } + return out; +} + +familiar [int] listInvert(boolean [familiar] list) +{ + familiar [int] out; + foreach k, value in list + { + if (value) + out.listAppend(k); + } + return out; +} + +item [int] listInvert(boolean [item] list) +{ + item [int] out; + foreach k, value in list + { + if (value) + out.listAppend(k); + } + return out; +} + +skill [int] listConvertStringsToSkills(string [int] list) +{ + skill [int] out; + foreach key, s in list + { + out.listAppend(s.to_skill()); + } + return out; +} + +monster [int] listConvertStringsToMonsters(string [int] list) +{ + monster [int] out; + foreach key, s in list + { + out.listAppend(s.to_monster()); + } + return out; +} + +int [int] stringToIntIntList(string input, string delimiter) +{ + int [int] out; + if (input == "") + return out; + foreach key, v in input.split_string(delimiter) + { + if (v == "") continue; + out.listAppend(v.to_int()); + } + return out; +} + +int [int] stringToIntIntList(string input) +{ + return stringToIntIntList(input, ","); +} + + +// buffer to_buffer(string str) +// { +// buffer result; +// result.append(str); +// return result; +// } + +buffer copyBuffer(buffer buf) +{ + buffer result; + result.append(buf); + return result; +} + +//split_string returns an immutable array, which will error on certain edits +//Use this function - it converts to an editable map. +string [int] split_string_mutable(string source, string delimiter) +{ + string [int] result; + string [int] immutable_array = split_string(source, delimiter); + foreach key in immutable_array + result[key] = immutable_array[key]; + return result; +} + +//This returns [] for empty strings. This isn't standard for split(), but is more useful for passing around lists. Hacky, I suppose. +string [int] split_string_alternate(string source, string delimiter) +{ + if (source.length() == 0) + return listMakeBlankString(); + return split_string_mutable(source, delimiter); +} + +string slot_to_string(slot s) +{ + if (s == $slot[acc1] || s == $slot[acc2] || s == $slot[acc3]) + return "accessory"; + else if (s == $slot[sticker1] || s == $slot[sticker2] || s == $slot[sticker3]) + return "sticker"; + else if (s == $slot[folder1] || s == $slot[folder2] || s == $slot[folder3] || s == $slot[folder4] || s == $slot[folder5]) + return "folder"; + else if (s == $slot[fakehand]) + return "fake hand"; + else if (s == $slot[crown-of-thrones]) + return "crown of thrones"; + else if (s == $slot[buddy-bjorn]) + return "buddy bjorn"; + return s; +} + +string slot_to_plural_string(slot s) +{ + if (s == $slot[acc1] || s == $slot[acc2] || s == $slot[acc3]) + return "accessories"; + else if (s == $slot[hat]) + return "hats"; + else if (s == $slot[weapon]) + return "weapons"; + else if (s == $slot[off-hand]) + return "off-hands"; + else if (s == $slot[shirt]) + return "shirts"; + else if (s == $slot[back]) + return "back items"; + + return s.slot_to_string(); +} + + +string format_today_to_string(string desired_format) +{ + return format_date_time("yyyyMMdd", today_to_string(), desired_format); +} + + +boolean stringHasPrefix(string s, string prefix) +{ + if (s.length() < prefix.length()) + return false; + else if (s.length() == prefix.length()) + return (s == prefix); + else if (substring(s, 0, prefix.length()) == prefix) + return true; + return false; +} + +boolean stringHasSuffix(string s, string suffix) +{ + if (s.length() < suffix.length()) + return false; + else if (s.length() == suffix.length()) + return (s == suffix); + else if (substring(s, s.length() - suffix.length()) == suffix) + return true; + return false; +} + + +static string [int] __uniwords_to_cardinal_map; +static string [int] __tens_to_cardinal_map; +string tens_to_cardinal(int value, boolean is_following_digits_of_larger_number) +{ + // Takes [0-99] and turns it into ["zero"-"ninety-nine"] (no negatives) + if (__uniwords_to_cardinal_map.count() == 0) + __uniwords_to_cardinal_map = split_string("zero,one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen,fifteen,sixteen,seventeen,eighteen,nineteen", ","); + + string result; + if (is_following_digits_of_larger_number) + result = "and "; + + int v = value % 100; + + if (v < 20) + return result + __uniwords_to_cardinal_map[v]; + + if (__tens_to_cardinal_map.count() == 0) + __tens_to_cardinal_map = {2:"twenty", 3:"thirty", 4:"forty", 5:"fifty", 6:"sixty", 7:"seventy", 8:"eighty", 9:"ninety"}; + + int tens = v / 10; + result += __tens_to_cardinal_map[tens]; + + int units = v % 10; + if (units != 0) + return result + "-" + __uniwords_to_cardinal_map[units]; + return result; +} +string tens_to_cardinal(int value) +{ + return tens_to_cardinal(value, false); +} + +string hundreds_to_cardinal(int value, boolean is_following_digits_of_larger_number) +{ + // Takes [0-999] and turns it into ["zero"-"nine hundred ninety-nine"] (no negatives) + int v = value % 1000; + + int hundreds = v / 100; + if (hundreds == 0) + return tens_to_cardinal(v, is_following_digits_of_larger_number); /* five million "and three" */ + + string result = tens_to_cardinal(hundreds, false) + " hundred"; + + int rest = v % 100; + if (rest > 0) + return result + " " + tens_to_cardinal(rest, is_following_digits_of_larger_number); + return result; +} +string hundreds_to_cardinal(int value) +{ + return hundreds_to_cardinal(value, false); +} + +static string [int] __short_scale_thousands_to_cardinal_map; +string int_to_cardinal(int v) +{ + string result; + if (v < 0) { + v = 0 - v; + result += "minus"; + } + + if (v == 0) return "zero"; + + if (__short_scale_thousands_to_cardinal_map.count() == 0) + __short_scale_thousands_to_cardinal_map = {0:"",3:" thousand",6:" million",9:" billion"}; + + int magnitude = v.length() - 1; + int order_of_magnitude = magnitude - magnitude % 3; + int rest = v; + boolean start = true; + + while (order_of_magnitude >= 0) { + int current_magnitude = 10**order_of_magnitude; + + int v_in_current_magnitude = rest / current_magnitude; + + if (v_in_current_magnitude > 0) + result += " " + hundreds_to_cardinal(v_in_current_magnitude, !start) + __short_scale_thousands_to_cardinal_map[order_of_magnitude]; + + order_of_magnitude -= 3; + start = false; + } + return result; +} +string int_to_wordy(int v) +{ + return int_to_cardinal(v); +} + +string int_to_position(int v) +{ + if (v == 0) + return "-"; + + string result = v; + if (v < 0) + v = 0 - v; + + if (v / 10 % 10 == 1) + return result + "th"; + + switch (v % 10) { + case 1: + return result + "st"; + case 2: + return result + "nd"; + case 3: + return result + "rd"; + } + return result + "th"; +} + +string int_to_ordinal(int v) +{ + string cardinal = int_to_cardinal(v); + if (cardinal.stringHasSuffix("y")) + return cardinal.substring(0, cardinal.length() - 1) + "ieth"; + if (cardinal.stringHasSuffix("one")) + return cardinal.substring(0, cardinal.length() - 3) + "first"; + if (cardinal.stringHasSuffix("two")) + return cardinal.substring(0, cardinal.length() - 3) + "second"; + if (cardinal.stringHasSuffix("three")) + return cardinal.substring(0, cardinal.length() - 3) + "ird"; + if (cardinal.stringHasSuffix("five")) + return cardinal.substring(0, cardinal.length() - 2) + "fth"; + if (cardinal.stringHasSuffix("eight")) + return cardinal + "h"; + if (cardinal.stringHasSuffix("nine")) + return cardinal.substring(0, cardinal.length() - 1) + "th"; + if (cardinal.stringHasSuffix("twelve")) + return cardinal.substring(0, cardinal.length() - 2) + "fth"; + return cardinal + "th"; +} +string int_to_position_wordy(int v) +{ + return int_to_ordinal(v); +} + + +string capitaliseFirstLetter(string v) +{ + buffer buf = v.to_buffer(); + if (v.length() <= 0) + return v; + buf.replace(0, 1, buf.char_at(0).to_upper_case()); + return buf.to_string(); +} + +//shadowing; this may override ints +string pluralise(float value, string non_plural, string plural) +{ + string value_out = ""; + if (value.to_int() == value) + value_out = value.to_int(); + else + value_out = value; + if (value == 1.0) + return value_out + " " + non_plural; + else + return value_out + " " + plural; +} + +string pluralise(int value, string non_plural, string plural) +{ + if (value == 1) + return value + " " + non_plural; + else + return value + " " + plural; +} + +string pluralise(int value, item i) +{ + return pluralise(value, i.to_string(), i.plural); +} + +string pluralise(item i) //whatever we have around +{ + return pluralise(i.available_amount(), i); +} + +string pluralise(effect e) +{ + return pluralise(e.have_effect(), "turn", "turns") + " of " + e; +} + +string pluraliseWordy(int value, string non_plural, string plural) +{ + if (value == 1) + { + if (non_plural == "more time") //we're gonna celebrate + return "One More Time"; + else if (non_plural == "more turn") + return "One More Turn"; + return value.int_to_wordy() + " " + non_plural; + } + else + return value.int_to_wordy() + " " + plural; +} + +string pluraliseWordy(int value, item i) +{ + return pluraliseWordy(value, i.to_string(), i.plural); +} + +string pluraliseWordy(item i) //whatever we have around +{ + return pluraliseWordy(i.available_amount(), i); +} + +string invSearch(string it) +{ + string url = "inventory.php?ftext="; + url += it.entity_encode().replace_string(" ", "+"); + return url; +} + +string invSearch(item it) +{ + return invSearch(it.name); +} + + +//Additions to standard API: +//Auto-conversion property functions: +boolean get_property_boolean(string property) +{ + return get_property(property).to_boolean(); +} + +int get_property_int(string property) +{ + return get_property(property).to_int_silent(); +} + +location get_property_location(string property) +{ + return get_property(property).to_location(); +} + +float get_property_float(string property) +{ + return get_property(property).to_float(); +} + +monster get_property_monster(string property) +{ + return get_property(property).to_monster(); +} + +//Returns true if the propery is equal to my_ascensions(). Commonly used in mafia properties. +boolean get_property_ascension(string property) +{ + return get_property_int(property) == my_ascensions(); +} + +element get_property_element(string property) +{ + return get_property(property).to_element(); +} + +item get_property_item(string property) +{ + return get_property(property).to_item(); +} + + +/* +Discovery - get_ingredients() takes up to 5.8ms per call, scaling to inventory size. Fixing the code in mafia might be possible, but it's old and looks complicated. +This implementation is not 1:1 compatible, as it doesn't take into account your current status, but we don't generally need that information(?). +*/ + +//Relevant prototype: +//int [item] get_ingredients_fast(item it) + + +static +{ + int [item][item] __item_ingredients; + boolean [item] __item_is_purchasable_from_a_store; +} + + + +boolean parseDatafileItem(int [item] out, string item_name) +{ + if (item_name == "") return false; + + item it = item_name.to_item(); + if (it != $item[none]) + { + out[it] += 1; + } + else if (item_name.contains_text("(")) + { + //Do complicated parsing. + //NOTE: "CRIMBCO Employee Handbook (chapter 1)" and "snow berries (7)" are both valid entries that mean different things. + string [int][int] matches = item_name.group_string("(.*?) \\(([0-9]*)\\)"); + if (matches[0].count() == 3) + { + it = matches[0][1].to_item(); + int amount = matches[0][2].to_int(); + if (it != $item[none] && amount > 0) + { + out[it] += amount; + } + } + } + return true; +} + + +Record ConcoctionMapEntry +{ + //Only way I know how to parse this file with file_to_map. string [int] won't work, string [string] won't... + string craft_type; + string mixing_item_1; + string mixing_item_2; + string mixing_item_3; + string mixing_item_4; + string mixing_item_5; + string mixing_item_6; + string mixing_item_7; + string mixing_item_8; + string mixing_item_9; + string mixing_item_10; + string mixing_item_11; + string mixing_item_12; + string mixing_item_13; + string mixing_item_14; + string mixing_item_15; + string mixing_item_16; + string mixing_item_17; + string mixing_item_18; +}; + +void parseConcoction(int [item] ingredients, ConcoctionMapEntry c) +{ + //If this ever shows up somewhere, please understand, it's not my fault file_to_map works this way. + if (!parseDatafileItem(ingredients, c.mixing_item_1)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_2)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_3)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_4)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_5)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_6)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_7)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_8)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_9)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_10)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_11)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_12)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_13)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_14)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_15)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_16)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_17)) + return; + if (!parseDatafileItem(ingredients, c.mixing_item_18)) + return; +} + +void initialiseItemIngredients() +{ + if (__item_ingredients.count() > 0) return; + + //Parse concoctions: + //Highest observed so far: 17. + if (true) + { + string [string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string, string] concoctions_map_2; + file_to_map("data/concoctions.txt", concoctions_map_2); + foreach crafting_thing, crafting_type, mixing_item_1, mixing_item_2, mixing_item_3, mixing_item_4, mixing_item_5, mixing_item_6, mixing_item_7, mixing_item_8, mixing_item_9, mixing_item_10, mixing_item_11, mixing_item_12, mixing_item_13, mixing_item_14, mixing_item_15, mixing_item_16, mixing_item_17, mixing_item_18 in concoctions_map_2 + { + if (crafting_type == "SUSHI" || crafting_type == "VYKEA") continue; //not really items + if (crafting_type == "CLIPART") continue; //bucket of wine is not made of three turtle totems + item it = crafting_thing.to_item(); + if (it == $item[none]) + { + int [item] item_results; + parseDatafileItem(item_results, crafting_thing); + if (item_results.count() == 0) + { + //print_html("Unknown crafting_thing " + crafting_thing); + continue; + } + foreach it2 in item_results + it = it2; + } + if (crafting_type.contains_text("ROW")) + __item_is_purchasable_from_a_store[it] = true; + if (__item_ingredients contains it) continue; //mafia uses first defined entry + + int [item] ingredients; + //Create map entry: + ConcoctionMapEntry c; + c.craft_type = crafting_type; + c.mixing_item_1 = mixing_item_1; + c.mixing_item_2 = mixing_item_2; + c.mixing_item_3 = mixing_item_3; + c.mixing_item_4 = mixing_item_4; + c.mixing_item_5 = mixing_item_5; + c.mixing_item_6 = mixing_item_6; + c.mixing_item_7 = mixing_item_7; + c.mixing_item_8 = mixing_item_8; + c.mixing_item_9 = mixing_item_9; + c.mixing_item_10 = mixing_item_10; + c.mixing_item_11 = mixing_item_11; + c.mixing_item_12 = mixing_item_12; + c.mixing_item_13 = mixing_item_13; + c.mixing_item_14 = mixing_item_14; + c.mixing_item_15 = mixing_item_15; + c.mixing_item_16 = mixing_item_16; + c.mixing_item_17 = mixing_item_17; + c.mixing_item_18 = mixing_item_18; + + parseConcoction(ingredients, c); + + if (ingredients.count() > 0) + __item_ingredients[it] = ingredients; + } + } + else + { + //Not compatible. + //Concoction manager seems to read the first entry, not the second. file_to_map reads the second. Example: spooky wad. + //Or maybe it's just random which the concoction manager uses? Example: bloody beer vs. spooky wad. Or it picks the one we can make...? + ConcoctionMapEntry [string] concoctions_map; + file_to_map("data/concoctions.txt", concoctions_map); + foreach crafting_thing in concoctions_map + { + ConcoctionMapEntry c = concoctions_map[crafting_thing]; + item it = crafting_thing.to_item(); + if (it == $item[none]) + continue; + + int [item] ingredients; + + parseConcoction(ingredients, c); + + if (__item_ingredients contains it) continue; //mafia uses first defined entry + if (ingredients.count() > 0) + __item_ingredients[it] = ingredients; + } + } + //Parse coinmasters: + + /*Record CoinmastersMapEntry + { + string buy_or_sell_type; + int amount; + item it; + string row_id; + }; + CoinmastersMapEntry [string] coinmasters_map;*/ + string [string,string,int,string] coinmasters_map; + file_to_map("data/coinmasters.txt", coinmasters_map); + //print_html("coinmasters_map = " + coinmasters_map.to_json()); + foreach master_name, type, amount, item_string in coinmasters_map + { + //FIXME track if coinmaster is accessible? + //print_html(master_name + ", " + type + ", " + amount + ", " + item_string); + if (type != "buy") continue; + coinmaster c = master_name.to_coinmaster(); + if (c == $coinmaster[none]) + { + //Hmm.... + //print_html(master_name + " is not a coinmaster"); + continue; + } + if (c.item == $item[none]) //bat-fabricator + continue; + item it = item_string.to_item(); + if (it == $item[none]) + { + //peppermint tailings (10) at the moment + //FIXME write this + continue; + } + + if (it == $item[none]) + continue; + + __item_is_purchasable_from_a_store[it] = true; + if (__item_ingredients contains it) continue; + + int [item] ingredients; + ingredients[c.item] = amount; + __item_ingredients[it] = ingredients; + } + +} + + +int [item] get_ingredients_fast(item it) +{ + //return it.get_ingredients(); + if (__item_ingredients.count() == 0) + initialiseItemIngredients(); + if (!(__item_ingredients contains it)) + { + //This is six milliseconds per call, but only if the item has an ingredient(?), so be wary: + int [item] ground_truth = it.get_ingredients(); + if (ground_truth.count() > 0) //We could cache it if it's empty, except sometimes that changes. + __item_ingredients[it] = ground_truth; + } + return __item_ingredients[it]; +} + +boolean item_is_purchasable_from_a_store(item it) +{ + return __item_is_purchasable_from_a_store[it]; +} + +boolean item_cannot_be_asdon_martined_because_it_was_purchased_from_a_store(item it) +{ + if ($items[wasabi pocky,tobiko pocky,natto pocky,wasabi-infused sake,tobiko-infused sake,natto-infused sake] contains it) return false; + return it.item_is_purchasable_from_a_store(); +} + +void testItemIngredients() +{ + initialiseItemIngredients(); + print_html(__item_ingredients.count() + " ingredients known."); + foreach it in $items[] + { + int [item] ground_truth_ingredients = it.get_ingredients(); + int [item] our_ingredients = get_ingredients_fast(it); + if (ground_truth_ingredients.count() == 0 && our_ingredients.count() == 0) continue; + + boolean passes = true; + if (ground_truth_ingredients.count() != our_ingredients.count()) + { + passes = false; + if (ground_truth_ingredients.count() == 0 && our_ingredients.count() > 0) //probably just a coinmaster + continue; + } + else + { + foreach it2, amount in ground_truth_ingredients + { + if (our_ingredients[it2] != amount) + { + passes = false; + break; + } + } + } + if (!passes) + { + print_html(it + ": " + ground_truth_ingredients.to_json() + " vs " + our_ingredients.to_json()); + } + } +} + +/*void main() +{ + testItemIngredients(); +}*/ + + +static { + int PATH_UNKNOWN = -1; + int PATH_NONE = 0; + int PATH_BOOZETAFARIAN = 1; + int PATH_TEETOTALER = 2; + int PATH_OXYGENARIAN = 3; + + int PATH_BEES_HATE_YOU = 4; + int PATH_WAY_OF_THE_SURPRISING_FIST = 6; + int PATH_TRENDY = 7; + int PATH_AVATAR_OF_BORIS = 8; + int PATH_BUGBEAR_INVASION = 9; + int PATH_ZOMBIE_SLAYER = 10; + int PATH_CLASS_ACT = 11; + int PATH_AVATAR_OF_JARLSBERG = 12; + int PATH_BIG = 14; + int PATH_KOLHS = 15; + int PATH_CLASS_ACT_2 = 16; + int PATH_AVATAR_OF_SNEAKY_PETE = 17; + int PATH_SLOW_AND_STEADY = 18; + int PATH_HEAVY_RAINS = 19; + int PATH_PICKY = 21; + int PATH_STANDARD = 22; + int PATH_ACTUALLY_ED_THE_UNDYING = 23; + int PATH_ONE_CRAZY_RANDOM_SUMMER = 24; + int PATH_COMMUNITY_SERVICE = 25; + int PATH_AVATAR_OF_WEST_OF_LOATHING = 26; + int PATH_THE_SOURCE = 27; + int PATH_NUCLEAR_AUTUMN = 28; + int PATH_GELATINOUS_NOOB = 29; + int PATH_LICENSE_TO_ADVENTURE = 30; + int PATH_LIVE_ASCEND_REPEAT = 31; + int PATH_POCKET_FAMILIARS = 32; + int PATH_G_LOVER = 33; + int PATH_DISGUISES_DELIMIT = 34; + int PATH_DEMIGUISE = 34; + int PATH_DARK_GYFFTE = 35; + int PATH_DARK_GIFT = 35; + int PATH_VAMPIRE = 35; + int PATH_2CRS = 36; + int PATH_KINGDOM_OF_EXPLOATHING = 37; + int PATH_EXPLOSION = 37; + int PATH_EXPLOSIONS = 37; + int PATH_EXPLODING = 37; + int PATH_EXPLODED = 37; + int PATH_OF_THE_PLUMBER = 38; + int PATH_LOW_KEY_SUMMER = 39; + int PATH_GREY_GOO = 40; + int PATH_YOU_ROBOT = 41; + int PATH_QUANTUM_TERRARIUM = 42; + int PATH_WILDFIRE = 43; + int PATH_GREY_YOU = 44; + int PATH_JOURNEYMAN = 45; + int PATH_FALL_OF_THE_DINOSAURS = 46; + int PATH_AVATAR_OF_SHADOWS_OVER_LOATHING = 47; + int PATH_LEGACY_OF_LOATHING = 48; + int PATH_SMOL = 49; // easier to type + int PATH_A_SHRUNKEN_ADVENTURER_AM_I = 49; + int PATH_WEREPROFESSOR = 50; + int PATH_SEA = 55; +} + +float numeric_modifier_replacement(item it, string modifier_string) { + string modifier_lowercase = modifier_string.to_lower_case(); + float additional = 0; + if (my_path().id == PATH_G_LOVER && !it.contains_text("g") && !it.contains_text("G")) + return 0.0; + if (it == $item[your cowboy boots]) + { + if (modifier_lowercase == "monster level" && $slot[bootskin].equipped_item() == $item[diamondback skin]) + { + return 20.0; + } + if (modifier_lowercase == "initiative" && $slot[bootspur].equipped_item() == $item[quicksilver spurs]) + return 30; + if (modifier_lowercase == "item drop" && $slot[bootspur].equipped_item() == $item[nicksilver spurs]) + return 30; + if (modifier_lowercase == "muscle percent" && $slot[bootskin].equipped_item() == $item[grizzled bearskin]) + return 50.0; + if (modifier_lowercase == "mysticality percent" && $slot[bootskin].equipped_item() == $item[frontwinder skin]) + return 50.0; + if (modifier_lowercase == "moxie percent" && $slot[bootskin].equipped_item() == $item[mountain lion skin]) + return 50.0; + //FIXME deal with rest (resistance, etc) + } + //so, when we don't have the smithsness items equipped, they have a numeric modifier of zero. + //but, they always have an inherent value of five. so give them that. + //FIXME do other smithsness items + if (it == $item[a light that never goes out] && modifier_lowercase == "item drop") + { + if (it.equipped_amount() == 0) + additional += 5; + } + return numeric_modifier(it, modifier_string) + additional; +} + + +static { + skill [class][int] __skills_by_class; + + void initialiseSkillsByClass() { + if (__skills_by_class.count() > 0) return; + foreach s in $skills[] { + if (s.class != $class[none]) { + if (!(__skills_by_class contains s.class)) { + skill [int] blank; + __skills_by_class[s.class] = blank; + } + __skills_by_class[s.class].listAppend(s); + } + } + } + initialiseSkillsByClass(); +} + + +static { + boolean [skill] __libram_skills; + + void initialiseLibramSkills() { + foreach s in $skills[] { + if (s.libram) + __libram_skills[s] = true; + } + } + initialiseLibramSkills(); +} + + +static { + boolean [item] __items_that_craft_food; + boolean [item] __minus_combat_equipment; + boolean [item] __equipment; + boolean [item] __items_in_outfits; + boolean [string][item] __equipment_by_numeric_modifier; + void initialiseItems() { + foreach it in $items[] { + //Crafting: + string craft_type = it.craft_type(); + if (craft_type.contains_text("Cooking")) { + foreach ingredient in it.get_ingredients_fast() { + __items_that_craft_food[ingredient] = true; + } + } + + //Equipment: + if ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3,familiar] contains it.to_slot()) { + __equipment[it] = true; + if (it.numeric_modifier("combat rate") < 0) { + __minus_combat_equipment[it] = true; + } + } + } + foreach key, outfit_name in all_normal_outfits() { + foreach key, it in outfit_pieces(outfit_name) + __items_in_outfits[it] = true; + } + } + initialiseItems(); +} + +boolean [item] equipmentWithNumericModifier(string modifier_string) +{ + modifier_string = modifier_string.to_lower_case(); + boolean [item] dynamic_items; + dynamic_items[to_item("kremlin's greatest briefcase")] = true; + dynamic_items[$item[your cowboy boots]] = true; + dynamic_items[$item[a light that never goes out]] = true; //FIXME all smithsness items + if (!(__equipment_by_numeric_modifier contains modifier_string)) + { + //Build it: + boolean [item] blank; + __equipment_by_numeric_modifier[modifier_string] = blank; + foreach it in __equipment + { + if (dynamic_items contains it) continue; + if (it.numeric_modifier(modifier_string) != 0.0) + __equipment_by_numeric_modifier[modifier_string][it] = true; + } + } + //Certain equipment is dynamic. Inspect them dynamically: + boolean [item] extra_results; + foreach it in dynamic_items + { + if (it.numeric_modifier_replacement(modifier_string) != 0.0) + { + extra_results[it] = true; + } + } + //damage + spell damage is basically the same for most things + string secondary_modifier = ""; + foreach e in $elements[hot,cold,spooky,stench,sleaze] + { + if (modifier_string == e + " damage") + secondary_modifier = e + " spell damage"; + } + if (secondary_modifier != "") + { + foreach it in equipmentWithNumericModifier(secondary_modifier) + extra_results[it] = true; + } + + if (extra_results.count() == 0) + return __equipment_by_numeric_modifier[modifier_string]; + else + { + //Add extras: + foreach it in __equipment_by_numeric_modifier[modifier_string] + { + extra_results[it] = true; + } + return extra_results; + } +} + +static +{ + boolean [item] __beancannon_source_items = $items[Heimz Fortified Kidney Beans,Hellfire Spicy Beans,Mixed Garbanzos and Chickpeas,Pork 'n' Pork 'n' Pork 'n' Beans,Shrub's Premium Baked Beans,Tesla's Electroplated Beans,Frigid Northern Beans,Trader Olaf's Exotic Stinkbeans,World's Blackest-Eyed Peas]; +} + +static +{ + //This would be a good mafia proxy value. Feature request? + boolean [skill] __combat_skills_that_are_spells; + void initialiseCombatSkillsThatAreSpells() + { + //Saucecicle,Surge of Icing are guesses + foreach s in $skills[Awesome Balls of Fire,Bake,Blend,Blinding Flash,Boil,Candyblast,Cannelloni Cannon,Carbohydrate Cudgel,Chop,CLEESH,Conjure Relaxing Campfire,Creepy Lullaby,Curdle,Doubt Shackles,Eggsplosion,Fear Vapor,Fearful Fettucini,Freeze,Fry,Grease Lightning,Grill,Haggis Kick,Inappropriate Backrub,Käsesoßesturm,Mudbath,Noodles of Fire,Rage Flame,Raise Backup Dancer,Ravioli Shurikens,Salsaball,Saucegeyser,Saucemageddon,Saucestorm,Saucy Salve,Shrap,Slice,Snowclone,Spaghetti Spear,Stream of Sauce,Stringozzi Serpent,Stuffed Mortar Shell,Tear Wave,Toynado,Volcanometeor Showeruption,Wassail,Wave of Sauce,Weapon of the Pastalord,Saucecicle,Surge of Icing] + { + __combat_skills_that_are_spells[s] = true; + } + foreach s in $skills[Lavafava,Pungent Mung,Beanstorm] //FIXME cowcall? snakewhip? + __combat_skills_that_are_spells[s] = true; + } + initialiseCombatSkillsThatAreSpells(); +} + +static +{ + location [item] __shen_items_to_locations = { + $item[Murphy's Rancid Black Flag]:$location[The Castle in the Clouds in the Sky (Top Floor)], + $item[The Stankara Stone]:$location[The Batrat and Ratbat Burrow], + $item[The First Pizza]:$location[Lair of the Ninja Snowmen], + $item[The Eye of the Stars]:$location[The Hole in the Sky], + $item[The Lacrosse Stick of Lacoronado]:$location[The Smut Orc Logging Camp], + $item[The Shield of Brook]:$location[The VERY Unquiet Garves]}; + + item [int] [int] __shen_start_day_to_assignments = { + //Shen's demands are seeded based on what day you're at when first meeting him. + 1:{1:$item[The Stankara Stone], 2:$item[The First Pizza], 3:$item[Murphy's Rancid Black Flag]}, + 2:{1:$item[The Lacrosse Stick of Lacoronado], 2:$item[The Shield of Brook], 3:$item[The Eye of the Stars]}, + 3:{1:$item[The First Pizza], 2:$item[The Stankara Stone], 3:$item[The Shield of Brook]}, + 4:{1:$item[The Lacrosse Stick of Lacoronado], 2:$item[The Stankara Stone], 3:$item[The Shield of Brook]}, + 5:{1:$item[Murphy's Rancid Black Flag], 2:$item[The Lacrosse Stick of Lacoronado], 3:$item[The Eye of the Stars]}, + 6:{1:$item[Murphy's Rancid Black Flag], 2:$item[The Stankara Stone], 3:$item[The Eye of the Stars]}, + 7:{1:$item[The Lacrosse Stick of Lacoronado], 2:$item[The Shield of Brook], 3:$item[The Eye of the Stars]}, + 8:{1:$item[The Shield of Brook], 2:$item[Murphy's Rancid Black Flag], 3:$item[The Lacrosse Stick of Lacoronado]}, + 9:{1:$item[The Shield of Brook], 2:$item[The Lacrosse Stick of Lacoronado], 3:$item[The Eye of the Stars]}, + 10:{1:$item[The Eye of the Stars], 2:$item[The Stankara Stone], 3:$item[Murphy's Rancid Black Flag]}, + 11:{1:$item[The First Pizza], 2:$item[The Stankara Stone], 3:$item[Murphy's Rancid Black Flag]}}; + + item [int] __shen_exploathing_assignments = {1:$item[The Eye of the Stars], 2:$item[The Lacrosse Stick of Lacoronado], 3:$item[The First Pizza]}; + //tried to develop in case there's more paths with fixed assignments in the future, but gave up. Not worth it without knowing if it'll really happen and how they'll work. +} +location [int] shenAssignmentsJoinLocationsStartingAfter(item [int] assignments, int index) { //messy/ugly, but saves a lot of time + location [int] destinations; + + //ignores the first elements + foreach position, assignment in assignments { + if (position > index) + destinations.listAppend(__shen_items_to_locations[assignment]); + } + return destinations; +} +location [int] shenAssignmentsJoinLocations(item [int] assignments) { + return shenAssignmentsJoinLocationsStartingAfter(assignments, 0); +} +location [int] getFutureShenAssignments(int [string] level_11_state_ints) { //QuestState's haven't been set yet, so instead, pass the whole __quest_state["Level 11 Shen"].state_int to the function (this is sooooo stupid, I know, but still simpler than passing the two values every single call) + item [int] assignments; + if (my_path().id == PATH_KINGDOM_OF_EXPLOATHING) + assignments = __shen_exploathing_assignments; + else + assignments = __shen_start_day_to_assignments[level_11_state_ints["Shen initiation day"]]; + + //Will, by nature, only return something if you've talked to Shen at least once (unless in Exploathing) + return assignments.shenAssignmentsJoinLocationsStartingAfter(level_11_state_ints["Shen meetings"]); +} + +static +{ + boolean [monster] __snakes; + void initialiseSnakes() + { + __snakes = $monsters[aggressive grass snake,Bacon snake,Batsnake,Black adder,Burning Snake of Fire,Coal snake,Diamondback rattler,Frontwinder,Frozen Solid Snake,King snake,Licorice snake,Mutant rattlesnake,Prince snake,Sewer snake with a sewer snake in it,Snakeleton,The Snake With Like Ten Heads,Tomb asp,Trouser Snake,Whitesnake]; + } + initialiseSnakes(); +} + +item lookupAWOLOilForMonster(monster m) +{ + if (__snakes contains m) + return $item[snake oil]; + else if ($phylums[beast,dude,hippy,humanoid,orc,pirate] contains m.phylum) + return $item[skin oil]; + else if ($phylums[bug,construct,constellation,demon,elemental,elf,fish,goblin,hobo,horror,mer-kin,penguin,plant,slime,weird] contains m.phylum) + return $item[unusual oil]; + else if ($phylums[undead] contains m.phylum) + return $item[eldritch oil]; + return $item[none]; +} + +static +{ + boolean [item] __ns_tower_door_base_keys = $items[Boris\'s key,Jarlsberg\'s key,Sneaky Pete\'s key,Richard\'s star key,skeleton key,digital key]; +} + +static +{ + record Key { + item it; + location zone; + string enchantment; + string condition_for_unlock; + string pre_unlock_url; + boolean was_used; + }; + + Key [int] LKS_keys; + if (my_path().id == PATH_LOW_KEY_SUMMER) { + Key KeyMake(string name, location zone, string enchantment, string condition_for_unlock, string pre_unlock_url) { + Key result; + result.it = name.to_item(); + result.zone = zone; + result.enchantment = enchantment; + result.condition_for_unlock = condition_for_unlock; + result.pre_unlock_url = pre_unlock_url; + return result; + } + Key KeyMake(string name, location zone, string enchantment, string condition_for_unlock) { + return KeyMake(name, zone, enchantment, condition_for_unlock, ""); + } + Key KeyMake(string name, location zone, string enchantment) { + return KeyMake(name, zone, enchantment, "", ""); + } + void listAppend(Key [int] list, Key entry) { + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; + } + + LKS_keys.listAppend(KeyMake("actual skeleton key", $location[The Skeleton Store], "+100 Damage Absorption, +10 Damage Reduction", "accepting the meathsmith\'s quest", "shop.php?whichshop=meatsmith")); + LKS_keys.listAppend(KeyMake("anchovy can key", $location[The Haunted Pantry], "+100% Food Drops")); + LKS_keys.listAppend(KeyMake("aquí", $location[South of the Border], "+3 Hot Res, +15 Hot Damage, +30 Hot Spell Damage", "getting access to the desert beach")); + LKS_keys.listAppend(KeyMake("batting cage key", $location[The Bat Hole Entrance], "+3 Stench Res, +15 Stench Damage, +30 Stench Spell Damage", "starting the boss bat quest")); + LKS_keys.listAppend(KeyMake("black rose key", $location[The Haunted Conservatory], "+5 Familiar Weight, +2 Familiar Exp")); + LKS_keys.listAppend(KeyMake("cactus key", $location[The Arid, Extra-Dry Desert], "Regen HP, Max HP +20", "reading the diary in the McGuffin quest")); + LKS_keys.listAppend(KeyMake("clown car key", $location[The \"Fun\" House], "+10 Prismatic Damage, +10 ML", "doing the nemesis quest")); + LKS_keys.listAppend(KeyMake("deep-fried key", $location[Madness Bakery], "+3 Sleaze Res, +15 Sleaze Damage, +30 Sleaze Spell Damage", "accepting the Armorer and Leggerer\'s quest", "shop.php?whichshop=armory")); + LKS_keys.listAppend(KeyMake("demonic key", $location[Pandamonium Slums], "+20% Myst Gains, Myst +5, -1 MP Skills", "finishing the Friars quest")); + LKS_keys.listAppend(KeyMake("discarded bike lock key", $location[The Overgrown Lot], "Max MP + 10, Regen MP", "accepting Doc Galaktik\'s quest", "shop.php?whichshop=doc")); + LKS_keys.listAppend(KeyMake("f'c'le sh'c'le k'y", $location[The F\'c\'le], "+20 ML", "doing the pirate\'s quest")); + LKS_keys.listAppend(KeyMake("ice key", $location[The Icy Peak], "+3 Cold Res, +15 Cold Damage, +30 Cold Spell Damage", "doing the trapper quest")); + LKS_keys.listAppend(KeyMake("kekekey", $location[The Valley of Rof L\'m Fao], "+50% Meat", "finishing the chasm quest")); + LKS_keys.listAppend(KeyMake("key sausage", $location[Cobb\'s Knob Kitchens], "-10% Combat", "doing the Cobb\'s Knob quest")); + LKS_keys.listAppend(KeyMake("knob labinet key", $location[Cobb\'s Knob Laboratory], "+20% Muscle Gains, Muscle +5, -1 MP Skills", "finding the Cobb's Knob lab key during the Cobb\'s Knob quest")); + LKS_keys.listAppend(KeyMake("knob shaft skate key", $location[The Knob Shaft], "Regen HP/MP, +3 Adventures", "finding the Cobb's Knob lab key during the Cobb\'s Knob quest")); + LKS_keys.listAppend(KeyMake("knob treasury key", $location[Cobb\'s Knob Treasury], "+50% Meat, +20% Pickpocket", "doing the Cobb\'s Knob quest")); + LKS_keys.listAppend(KeyMake("music Box Key", $location[The Haunted Nursery], "+10% Combat", "doing the Spookyraven quest")); + LKS_keys.listAppend(KeyMake("peg key", $location[The Obligatory Pirate\'s Cove], "+5 Stats", "doing the pirate\'s quest")); + LKS_keys.listAppend(KeyMake("rabbit\'s foot key", $location[The Dire Warren], "All Attributes +10")); + LKS_keys.listAppend(KeyMake("scrap metal key", $location[The Old Landfill], "+20% Moxie Gains, Moxie +5, -1MP Skills", "starting the Old Landfill quest")); + LKS_keys.listAppend(KeyMake("treasure chest key", $location[Belowdecks], "+30% Item, +30% Meat", "doing the pirate\'s quest")); + LKS_keys.listAppend(KeyMake("weremoose key", $location[Cobb\'s Knob Menagerie, Level 2], "+3 Spooky Res, +15 Spooky Damage, +30 Spooky Spell Damage", "finding the Cobb\'s Knob Menagerie key in the Cobb\'s Knob lab" + ($item[Cobb's Knob Menagerie key].available_amount() == 0 ? ", accessed by doing the Cobb\'s Knob quest" : ""))); + } +} + +static +{ + monster [location] __protonic_monster_for_location {$location[Cobb\'s Knob Treasury]:$monster[The ghost of Ebenoozer Screege], $location[The Haunted Conservatory]:$monster[The ghost of Lord Montague Spookyraven], $location[The Haunted Gallery]:$monster[The ghost of Waldo the Carpathian], $location[The Haunted Kitchen]:$monster[The Icewoman], $location[The Haunted Wine Cellar]:$monster[The ghost of Jim Unfortunato], $location[The Icy Peak]:$monster[The ghost of Sam McGee], $location[Inside the Palindome]:$monster[Emily Koops, a spooky lime], $location[Madness Bakery]:$monster[the ghost of Monsieur Baguelle], $location[The Old Landfill]:$monster[The ghost of Vanillica "Trashblossom" Gorton], $location[The Overgrown Lot]:$monster[the ghost of Oily McBindle], $location[The Skeleton Store]:$monster[boneless blobghost], $location[The Smut Orc Logging Camp]:$monster[The ghost of Richard Cockingham], $location[The Spooky Forest]:$monster[The Headless Horseman]}; +} + + +static +{ + boolean [monster][location] __monsters_natural_habitats; +} +boolean [location] getPossibleLocationsMonsterCanAppearInNaturally(monster m) +{ + if (__monsters_natural_habitats.count() == 0) + { + //initialise: + foreach l in $locations[] + { + foreach key, m in l.get_monsters() + __monsters_natural_habitats[m][l] = true; + } + } + return __monsters_natural_habitats[m]; +} + + +boolean mafiaIsPastRevision(int revision_number) +{ + if (get_revision() <= 0) //get_revision reports zero in certain cases; assume they're on a recent version + return true; + return (get_revision() >= revision_number); +} + + +boolean have_familiar_replacement(familiar f) +{ + //have_familiar bugs in avatar of sneaky pete for now, so: + if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) + return false; + return f.have_familiar(); +} + +//Similar to have_familiar, except it also checks trendy (not sure if have_familiar supports trendy) and 100% familiar runs +boolean familiar_is_usable(familiar f) +{ + //r13998 has most of these + if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING || my_path().id == PATH_LICENSE_TO_ADVENTURE || my_path().id == PATH_POCKET_FAMILIARS || my_path().id == PATH_VAMPIRE) + return false; + if (my_path().id == PATH_ZOMBIE_SLAYER && !f.attributes.contains_text("undead")) + return false; + if (!is_unrestricted(f)) + return false; + if (my_path().id == PATH_G_LOVER && !f.contains_text("g") && !f.contains_text("G")) + return false; + //On second thought, this is terrible: + /*int single_familiar_run = get_property_int("singleFamiliarRun"); + if (single_familiar_run != -1 && my_turncount() >= 30) //after 30 turns, they're probably sure + { + if (f == single_familiar_run.to_familiar()) + return true; + return false; + }*/ + if (my_path().id == PATH_TRENDY) + { + if (!is_trendy(f)) + return false; + } + else if (my_path().id == PATH_BEES_HATE_YOU) + { + if (f.to_string().contains_text("b") || f.to_string().contains_text("B")) //bzzzz! + return false; //so not green + } + return have_familiar(f); +} + +//inigo's used to show up as have_skill while under restrictions, possibly others +boolean skill_is_usable(skill s) +{ + if (!s.have_skill()) + return false; + if (!s.is_unrestricted()) + return false; + if (my_path().id == PATH_G_LOVER && (!s.passive || s == $skill[meteor lore]) && !s.contains_text("g") && !s.contains_text("G")) + return false; + if ($skills[rapid prototyping] contains s) + return $item[hand turkey outline].is_unrestricted(); + return true; +} + +boolean a_skill_is_usable(boolean [skill] skills) +{ + foreach s in skills + { + if (s.skill_is_usable()) return true; + } + return false; +} + +boolean skill_is_currently_castable(skill s) +{ + //FIXME accordion thief songs, MP, a lot of things + if (s == $skill[Utensil Twist] && $slot[weapon].equipped_item().item_type() != "utensil") + { + return false; + } + return true; +} + +boolean item_is_usable(item it) +{ + if (!it.is_unrestricted()) + return false; + if (my_path().id == PATH_G_LOVER && !it.contains_text("g") && !it.contains_text("G")) + return false; + if (my_path().id == PATH_BEES_HATE_YOU && (it.contains_text("b") || it.contains_text("B"))) + return false; + return true; +} + +//available_amount() except it tests against item_is_usable() +int usable_amount(item it) +{ + if (!it.item_is_usable()) return 0; + return it.available_amount(); +} + +boolean effect_is_usable(effect e) +{ + if (my_path().id == PATH_G_LOVER && !e.contains_text("g") && !e.contains_text("G")) + return false; + return true; +} + +boolean in_ronin() +{ + return !can_interact(); +} + + +boolean [item] makeConstantItemArrayMutable(boolean [item] array) +{ + boolean [item] result; + foreach k in array + result[k] = array[k]; + + return result; +} + +boolean [location] makeConstantLocationArrayMutable(boolean [location] locations) +{ + boolean [location] result; + foreach k in locations + result[k] = locations[k]; + + return result; +} + +boolean [skill] makeConstantSkillArrayMutable(boolean [skill] array) +{ + boolean [skill] result; + foreach k in array + result[k] = array[k]; + + return result; +} + +boolean [effect] makeConstantEffectArrayMutable(boolean [effect] array) +{ + boolean [effect] result; + foreach k in array + result[k] = array[k]; + + return result; +} + +//Same as my_primestat(), except refers to substat +stat my_primesubstat() +{ + if (my_primestat() == $stat[muscle]) + return $stat[submuscle]; + else if (my_primestat() == $stat[mysticality]) + return $stat[submysticality]; + else if (my_primestat() == $stat[moxie]) + return $stat[submoxie]; + return $stat[none]; +} + +item [int] items_missing(boolean [item] items) +{ + item [int] result; + foreach it in items + { + if (it.available_amount() == 0) + result.listAppend(it); + } + return result; +} + +skill [int] skills_missing(boolean [skill] skills) +{ + skill [int] result; + foreach s in skills + { + if (!s.have_skill()) + result.listAppend(s); + } + return result; +} + +int storage_amount(boolean [item] items) +{ + int count = 0; + foreach it in items + { + count += it.storage_amount(); + } + return count; +} + +int closet_amount(boolean [item] items) +{ + int count = 0; + foreach it in items + { + count += it.closet_amount(); + } + return count; +} + +int display_amount(boolean [item] items) +{ + int count = 0; + foreach it in items + { + count += it.display_amount(); + } + return count; +} + +int stash_amount(boolean [item] items) +{ + int count = 0; + foreach it in items + { + count += it.stash_amount(); + } + return count; +} + +int available_amount(boolean [item] items) +{ + //Usage: + //$items[disco ball, corrupted stardust].available_amount() + //Returns the total number of all items. + int count = 0; + foreach it in items + { + count += it.available_amount(); + } + return count; +} + +int creatable_amount(boolean [item] items) +{ + //Usage: + //$items[disco ball, corrupted stardust].available_amount() + //Returns the total number of all items. + int count = 0; + foreach it in items + { + count += it.creatable_amount(); + } + return count; +} + +int item_amount(boolean [item] items) +{ + int count = 0; + foreach it in items + { + count += it.item_amount(); + } + return count; +} + +int have_effect(boolean [effect] effects) +{ + int count = 0; + foreach e in effects + count += e.have_effect(); + return count; +} + +int available_amount(item [int] items) +{ + int count = 0; + foreach key in items + { + count += items[key].available_amount(); + } + return count; +} + +int available_amount_ignoring_storage(item it) +{ + if (!in_ronin()) + return it.available_amount() - it.storage_amount(); + else + return it.available_amount(); +} + +int available_amount_ignoring_closet(item it) +{ + if (get_property_boolean("autoSatisfyWithCloset")) + return it.available_amount() - it.closet_amount(); + else + return it.available_amount(); +} + +int available_amount_including_closet(item it) +{ + if (get_property_boolean("autoSatisfyWithCloset")) + return it.available_amount(); + else + return it.available_amount() + it.closet_amount(); +} + +//Display case, etc +//WARNING: Does not take into account your shop. Conceptually, the shop is things you're getting rid of... and they might be gone already. +int item_amount_almost_everywhere(item it) +{ + return it.closet_amount() + it.display_amount() + it.equipped_amount() + it.item_amount() + it.storage_amount(); +} + +//Similar to item_amount_almost_everywhere, but won't trigger a display case load unless it has to: +boolean haveAtLeastXOfItemEverywhere(item it, int amount) +{ + int total = 0; + total += it.item_amount(); + if (total >= amount) return true; + total += it.equipped_amount(); + if (total >= amount) return true; + total += it.closet_amount(); + if (total >= amount) return true; + total += it.storage_amount(); + if (total >= amount) return true; + total += it.display_amount(); + if (total >= amount) return true; + + return false; +} + +int equipped_amount(boolean [item] items) +{ + int count = 0; + foreach it in items + { + count += it.equipped_amount(); + } + return count; +} + +int [item] creatable_items(boolean [item] items) +{ + int [item] creatable_items; + foreach it in items + { + if (it.creatable_amount() == 0) + continue; + creatable_items[it] = it.creatable_amount(); + } + return creatable_items; +} + + +item [slot] equipped_items() +{ + item [slot] result; + foreach s in $slots[] + { + item it = s.equipped_item(); + if (it == $item[none]) + continue; + result[s] = it; + } + return result; +} + +//Have at least one of these familiars: +boolean have_familiar_replacement(boolean [familiar] familiars) +{ + foreach f in familiars + { + if (f.have_familiar()) + return true; + } + return false; +} + +item [int] missing_outfit_components(string outfit_name) +{ + item [int] outfit_pieces = outfit_pieces(outfit_name); + item [int] missing_components; + foreach key in outfit_pieces + { + item it = outfit_pieces[key]; + if (it.available_amount() == 0) + missing_components.listAppend(it); + } + return missing_components; +} + + +//have_outfit() will tell you if you have an outfit, but only if you pass stat checks. This does not stat check: +boolean have_outfit_components(string outfit_name) +{ + return (outfit_name.missing_outfit_components().count() == 0); +} + +//Non-API-related functions: + +boolean playerIsLoggedIn() +{ + return !(my_hash().length() == 0 || my_id() == 0) || __setting_debug_mode; +} + +int substatsForLevel(int level) +{ + if (level == 1) + return 0; + return pow2i(pow2i(level - 1) + 4); +} + +int availableFullness() +{ + int limit = fullness_limit(); + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING && limit == 0 && $skill[Replacement Stomach].have_skill()) + { + limit += 5; + } + return limit - my_fullness(); +} + +int availableDrunkenness() +{ + int limit = inebriety_limit(); + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING && limit == 0 && $skill[Replacement Liver].have_skill()) + { + limit += 5; + } + if (limit == 0) return 0; //certain edge cases + return limit - my_inebriety(); +} + +int availableSpleen() +{ + int limit = spleen_limit(); + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING && limit == 0) + { + limit += 5; //always true + //mafia resets the limits to zero in the underworld because it does, so anti-mafia: + foreach s in $skills[Extra Spleen,Another Extra Spleen,Yet Another Extra Spleen,Still Another Extra Spleen,Just One More Extra Spleen,Okay Seriously\, This is the Last Spleen] + { + if (s.have_skill()) + limit += 5; + } + } + return limit - my_spleen_use(); +} + +item [int] missingComponentsToMakeItemPrivateImplementation(item it, int it_amounted_needed, int recursion_limit_remaining) +{ + item [int] result; + if (recursion_limit_remaining <= 0) //possible loop + return result; + if ($items[dense meat stack,meat stack] contains it) return listMake(it); //meat from yesterday + fairy gravy boat? hmm... no + if (it.available_amount() >= it_amounted_needed) + return result; + int [item] ingredients = get_ingredients_fast(it); + if (ingredients.count() == 0) + { + for i from 1 to (it_amounted_needed - it.available_amount()) + result.listAppend(it); + } + foreach ingredient in ingredients + { + int ingredient_amounted_needed = ingredients[ingredient]; + if (ingredient.available_amount() >= ingredient_amounted_needed) //have enough + continue; + //split: + item [int] r = missingComponentsToMakeItemPrivateImplementation(ingredient, ingredient_amounted_needed, recursion_limit_remaining - 1); + if (r.count() > 0) + { + result.listAppendList(r); + } + } + return result; +} + +item [int] missingComponentsToMakeItem(item it, int it_amounted_needed) +{ + return missingComponentsToMakeItemPrivateImplementation(it, it_amounted_needed, 30); +} + + +item [int] missingComponentsToMakeItem(item it) +{ + return missingComponentsToMakeItem(it, 1); +} + +string [int] missingComponentsToMakeItemInHumanReadableFormat(item it) +{ + item [int] parts = missingComponentsToMakeItem(it); + + int [item] parts_inverted; + foreach key, it2 in parts + { + parts_inverted[it2] += 1; + } + string [int] result; + foreach it2, amount in parts_inverted + { + string line = amount; + line += " more "; + if (amount > 1) + line += it2.plural; + else + line += it2.to_string(); + result.listAppend(line); + } + return result; +} + +//For tracking time deltas. Won't accurately compare across day boundaries and isn't monotonic (be wary of negative deltas), but still useful for temporal rate limiting. +int getMillisecondsOfToday() +{ + //To replicate value in GCLI: + //ash (now_to_string("H").to_int() * 60 * 60 * 1000 + now_to_string("m").to_int() * 60 * 1000 + now_to_string("s").to_int() * 1000 + now_to_string("S").to_int()) + return now_to_string("H").to_int_silent() * 60 * 60 * 1000 + now_to_string("m").to_int_silent() * 60 * 1000 + now_to_string("s").to_int_silent() * 1000 + now_to_string("S").to_int_silent(); +} + +//WARNING: Only accurate for up to five turns. +//It also will not work properly in certain areas, and possibly across day boundaries. Actually, it's kind of a hack. +//But now we have turns_spent so no need to worry. +int combatTurnsAttemptedInLocation(location place) +{ + int count = 0; + if (place.combat_queue != "") + count += place.combat_queue.split_string_alternate("; ").count(); + return count; +} + +int noncombatTurnsAttemptedInLocation(location place) +{ + int count = 0; + if (place.noncombat_queue != "") + count += place.noncombat_queue.split_string_alternate("; ").count(); + return count; +} + +int turnsAttemptedInLocation(location place) +{ + return place.turns_spent; +} + +int turnsAttemptedInLocation(boolean [location] places) +{ + int count = 0; + foreach place in places + count += place.turnsAttemptedInLocation(); + return count; +} + +string [int] locationSeenNoncombats(location place) +{ + return place.noncombat_queue.split_string_alternate("; "); +} + +string [int] locationSeenCombats(location place) +{ + return place.combat_queue.split_string_alternate("; "); +} + +string lastNoncombatInLocation(location place) +{ + if (place.noncombat_queue != "") + return place.locationSeenNoncombats().listLastObject(); + return ""; +} + +string lastCombatInLocation(location place) +{ + if (place.noncombat_queue != "") + return place.locationSeenCombats().listLastObject(); + return ""; +} + +static +{ + int [location] __place_delays; + __place_delays[$location[the spooky forest]] = 5; + __place_delays[$location[the haunted bedroom]] = 6; //a guess from spading + __place_delays[$location[the boss bat's lair]] = 4; + __place_delays[$location[the oasis]] = 5; + __place_delays[$location[the hidden park]] = 6; //6? does turkey blaster give four turns sometimes...? + __place_delays[$location[the haunted gallery]] = 5; //FIXME this is a guess, spade + __place_delays[$location[the haunted bathroom]] = 5; + __place_delays[$location[the haunted ballroom]] = 5; //FIXME rumored + __place_delays[$location[the penultimate fantasy airship]] = 25; + __place_delays[$location[the "fun" house]] = 10; + __place_delays[$location[The Castle in the Clouds in the Sky (Ground Floor)]] = 10; + __place_delays[$location[the outskirts of cobb's knob]] = 10; + __place_delays[$location[the hidden apartment building]] = 8; + __place_delays[$location[the hidden office building]] = 10; + __place_delays[$location[the copperhead club]] = 14; + __place_delays[$location[the upper chamber]] = 5; +} + +int totalDelayForLocation(location place) +{ + //the haunted billiards room does not contain delay + //also failure at 16 skill + + if (__place_delays contains place) + return __place_delays[place]; + return -1; +} + +int delayRemainingInLocation(location place) +{ + int delay_for_place = place.totalDelayForLocation(); + + if (delay_for_place == -1) + return -1; + + int turns_attempted = place.turns_spent; + + return MAX(0, delay_for_place - turns_attempted); +} + +int turnsCompletedInLocation(location place) +{ + return place.turnsAttemptedInLocation(); //FIXME make this correct +} + +//Backwards compatibility: +//We want to be able to support new content with daily builds. But, we don't want to ask users to run a daily build. +//So these act as replacements for new content. Unknown lookups are given as $type[none] The goal is to have compatibility with the last major release. +//We use this instead of to_item() conversion functions, so we can easily identify them in the source. +item lookupItem(string name) +{ + return name.to_item(); +} + +boolean [item] lookupItems(string names) //CSV input +{ + boolean [item] result; + string [int] item_names = split_string_alternate(names, ","); + foreach key in item_names + { + item it = item_names[key].to_item(); + if (it == $item[none]) + continue; + result[it] = true; + } + return result; +} + +boolean [item] lookupItemsArray(boolean [string] names) +{ + boolean [item] result; + + foreach item_name in names + { + item it = item_name.to_item(); + if (it == $item[none]) + continue; + result[it] = true; + } + return result; +} + +skill lookupSkill(string name) +{ + return name.to_skill(); +} + +boolean [skill] lookupSkills(string names) //CSV input +{ + boolean [skill] result; + string [int] skill_names = split_string_alternate(names, ","); + foreach key in skill_names + { + skill s = skill_names[key].to_skill(); + if (s == $skill[none]) + continue; + result[s] = true; + } + return result; +} + + +//lookupSkills(string) will be called instead if we keep the same name, so use a different name: +boolean [skill] lookupSkillsInt(boolean [int] skill_ids) +{ + boolean [skill] result; + foreach skill_id in skill_ids + { + skill s = skill_id.to_skill(); + if (s == $skill[none]) + continue; + result[s] = true; + } + return result; +} + +effect lookupEffect(string name) +{ + return name.to_effect(); +} + +familiar lookupFamiliar(string name) +{ + return name.to_familiar(); +} + +location lookupLocation(string name) +{ + return name.to_location(); + /*l = name.to_location(); + if (__setting_debug_mode && l == $location[none]) + print_html("Unable to find location \"" + name + "\""); + return l;*/ +} + +boolean [location] lookupLocations(string names_string) +{ + boolean [location] result; + + string [int] names = names_string.split_string(","); + foreach key, name in names + { + if (name.length() == 0) + continue; + location l = name.to_location(); + if (l != $location[none]) + result[l] = true; + } + + return result; +} + +monster lookupMonster(string name) +{ + return name.to_monster(); +} + +boolean [monster] lookupMonsters(string names_string) +{ + boolean [monster] result; + + string [int] names = names_string.split_string(","); + foreach key, name in names + { + if (name.length() == 0) + continue; + monster m = name.to_monster(); + if (m != $monster[none]) + result[m] = true; + } + + return result; +} + +class lookupClass(string name) +{ + return name.to_class(); +} + +boolean monsterDropsItem(monster m, item it) +{ + //record [int] drops = m.item_drops_array(); + foreach key in m.item_drops_array() + { + if (m.item_drops_array()[key].drop == it) + return true; + } + return false; +} + + +Record StringHandle +{ + string s; +}; + +Record FloatHandle +{ + float f; +}; + + +buffer generateTurnsToSeeNoncombat(int combat_rate, int noncombats_in_zone, string task, int max_turns_between_nc, int extra_starting_turns) +{ + float turn_estimation = -1.0; + float combat_rate_modifier = combat_rate_modifier(); + float noncombat_rate = 1.0 - (combat_rate + combat_rate_modifier).to_float() / 100.0; + + + if (noncombats_in_zone > 0) + { + float minimum_nc_rate = 0.0; + if (max_turns_between_nc != 0) + minimum_nc_rate = 1.0 / max_turns_between_nc.to_float(); + if (noncombat_rate < minimum_nc_rate) + noncombat_rate = minimum_nc_rate; + + if (noncombat_rate > 0.0) + turn_estimation = noncombats_in_zone.to_float() / noncombat_rate; + } + else + turn_estimation = 0.0; + + turn_estimation += extra_starting_turns; + + + buffer result; + + if (turn_estimation == -1.0) + { + result.append("Impossible"); + } + else + { + result.append("~"); + result.append(turn_estimation.roundForOutput(1)); + if (turn_estimation == 1.0) + result.append(" turn"); + else + result.append(" turns"); + } + + if (task != "") + { + result.append(" to "); + result.append(task); + } + else + { + if (turn_estimation == -1.0) + { + } + else if (turn_estimation == 1.0) + result.append(" remains"); + else + result.append(" remain"); + } + if (noncombats_in_zone > 0) + { + result.append(" at "); + result.append(combat_rate_modifier.floor()); + result.append("% combat rate"); + } + result.append("."); + + return result; +} + +buffer generateTurnsToSeeNoncombat(int combat_rate, int noncombats_in_zone, string task, int max_turns_between_nc) +{ + return generateTurnsToSeeNoncombat(combat_rate, noncombats_in_zone, task, max_turns_between_nc, 0); +} + +buffer generateTurnsToSeeNoncombat(int combat_rate, int noncombats_in_zone, string task) +{ + return generateTurnsToSeeNoncombat(combat_rate, noncombats_in_zone, task, 0); +} + + +int damageTakenByElement(int base_damage, float elemental_resistance) +{ + if (base_damage < 0) + return 1; + + float effective_base_damage = MAX(30, base_damage).to_float(); + + return MAX(1, ceil(base_damage.to_float() - effective_base_damage * elemental_resistance)); +} + +int damageTakenByElement(int base_damage, element e) +{ + float elemental_resistance = e.elemental_resistance() / 100.0; + + //mafia might already do this for us already, but I haven't checked: + + if (e == $element[cold] && $effect[coldform].have_effect() > 0) + elemental_resistance = 1.0; + else if (e == $element[hot] && $effect[hotform].have_effect() > 0) + elemental_resistance = 1.0; + else if (e == $element[sleaze] && $effect[sleazeform].have_effect() > 0) + elemental_resistance = 1.0; + else if (e == $element[spooky] && $effect[spookyform].have_effect() > 0) + elemental_resistance = 1.0; + else if (e == $element[stench] && $effect[stenchform].have_effect() > 0) + elemental_resistance = 1.0; + + + return damageTakenByElement(base_damage, elemental_resistance); +} + +boolean locationHasPlant(location l, string plant_name) +{ + string [int] plants_in_place = get_florist_plants()[l]; + foreach key in plants_in_place + { + if (plants_in_place[key] == plant_name) + return true; + } + return false; +} + +float initiative_modifier_ignoring_plants() +{ + //FIXME strange bug here, investigate + //seen in cyrpt + float init = initiative_modifier(); + + location my_location = my_location(); + if (my_location != $location[none] && (my_location.locationHasPlant("Impatiens") || my_location.locationHasPlant("Shuffle Truffle"))) + init -= 25.0; + + return init; +} + +float item_drop_modifier_ignoring_plants() +{ + float item_modifier = item_drop_modifier(); + + location my_location = my_location(); + if (my_location != $location[none]) + { + if (my_location.locationHasPlant("Rutabeggar") || my_location.locationHasPlant("Stealing Magnolia")) + item_modifier -= 25.0; + if (my_location.locationHasPlant("Kelptomaniac")) + item_modifier -= 40.0; + } + return item_modifier; +} + +int monster_level_adjustment_ignoring_plants() //this is unsafe to use in heavy rains +{ + //FIXME strange bug possibly here, investigate + int ml = monster_level_adjustment(); + + location my_location = my_location(); + + if (my_location != $location[none]) + { + string [3] location_plants = get_florist_plants()[my_location]; + foreach key in location_plants + { + string plant = location_plants[key]; + if (plant == "Rabid Dogwood" || plant == "War Lily" || plant == "Blustery Puffball") + { + ml -= 30; + break; + } + } + + } + return ml; +} + +int water_level_of_location(location l) +{ + int water_level = 1; + if (l.recommended_stat >= 40) //FIXME is this threshold spaded? + water_level += 1; + if (l.environment == "indoor") + water_level += 2; + if (l.environment == "underground" || l == $location[the lower chambers]) //per-location fix + water_level += 4; + water_level += numeric_modifier("water level"); + + water_level = clampi(water_level, 1, 6); + if (l.environment == "underwater") //or does the water get the rain instead? nobody knows, rain man + water_level = 0; //the aquaman hates rain man, they have a fight, aquaman wins + return water_level; +} + +float washaway_rate_of_location(location l) +{ + //Calculate washaway chance: + int current_water_level = l.water_level_of_location(); + + int washaway_chance = current_water_level * 5; + if ($item[fishbone catcher's mitt].equipped_amount() > 0) + washaway_chance -= 15; //GUESS + + if ($effect[Fishy Whiskers].have_effect() > 0) + { + //washaway_chance -= ?; //needs spading + } + return clampNormalf(washaway_chance / 100.0); +} + +int monster_level_adjustment_for_location(location l) +{ + int ml = monster_level_adjustment_ignoring_plants(); + + if (l.locationHasPlant("Rabid Dogwood") || l.locationHasPlant("War Lily") || l.locationHasPlant("Blustery Puffball")) + { + ml += 30; + } + + if (my_path().id == PATH_HEAVY_RAINS) + { + //complicated: + //First, cancel out the my_location() rain: + int my_location_water_level_ml = monster_level_adjustment() - numeric_modifier("Monster Level"); + ml -= my_location_water_level_ml; + + //Now, calculate the water level for the location: + int water_level = water_level_of_location(l); + + //Add that as ML: + if (!($locations[oil peak,the typical tavern cellar] contains l)) //kind of hacky to put this here, sorry + { + ml += water_level * 10; + } + } + + return ml; +} + +float initiative_modifier_for_location(location l) +{ + float base = initiative_modifier_ignoring_plants(); + + if (l.locationHasPlant("Impatiens") || l.locationHasPlant("Shuffle Truffle")) + base += 25.0; + return base; +} + +float item_drop_modifier_for_location(location l) +{ + int base = item_drop_modifier_ignoring_plants(); + if (l.locationHasPlant("Rutabeggar") || l.locationHasPlant("Stealing Magnolia")) + base += 25.0; + if (l.locationHasPlant("Kelptomaniac")) + base += 40.0; + return base; +} + +int monsterExtraInitForML(int ml) +{ + if (ml < 21) + return 0.0; + else if (ml < 41) + return 0.0 + 1.0 * (ml - 20.0); + else if (ml < 61) + return 20.0 + 2.0 * (ml - 40.0); + else if (ml < 81) + return 60.0 + 3.0 * (ml - 60.0); + else if (ml < 101) + return 120.0 + 4.0 * (ml - 80.0); + else + return 200.0 + 5.0 * (ml - 100.0); +} + +int stringCountSubstringMatches(string str, string substring) +{ + int count = 0; + int position = 0; + int breakout = 100; + int str_length = str.length(); //uncertain whether this is a constant time operation + while (breakout > 0 && position + 1 < str_length) + { + position = str.index_of(substring, position + 1); + if (position != -1) + count += 1; + else + break; + breakout -= 1; + } + return count; +} + +effect to_effect(item it) +{ + return it.effect_modifier("effect"); +} + + + +boolean weapon_is_club(item it) +{ + if (it.to_slot() != $slot[weapon]) return false; + if (it.item_type() == "club") + return true; + if (it.item_type() == "sword" && $effect[Iron Palms].have_effect() > 0) + return true; + return false; +} + +buffer prepend(buffer in_buffer, buffer value) +{ + buffer result; + result.append(value); + result.append(in_buffer); + in_buffer.set_length(0); + in_buffer.append(result); + return result; +} + +buffer prepend(buffer in_buffer, string value) +{ + return prepend(in_buffer, value.to_buffer()); +} + +float pressurePenaltyForLocation(location l, Error could_get_value) +{ + float pressure_penalty = 0.0; + + if (my_location() != l) + { + ErrorSet(could_get_value); + return -1.0; + } + + pressure_penalty = MAX(0, -numeric_modifier("item drop penalty")); + return pressure_penalty; +} + +int XiblaxianHoloWristPuterTurnsUntilNextItem() +{ + int drops = get_property_int("_holoWristDrops"); + int progress = get_property_int("_holoWristProgress"); + + //_holoWristProgress resets when drop happens + if (!mafiaIsPastRevision(15148)) + return -1; + int next_turn_hit = 5 * (drops + 1) + 6; + if (!mafiaIsPastRevision(15493)) //old behaviour + { + if (drops != 0) + next_turn_hit += 1; + } + return MAX(0, next_turn_hit - progress); +} + +int ka_dropped(monster m) +{ + if (m.phylum == $phylum[dude] || m.phylum == $phylum[hobo] || m.phylum == $phylum[hippy] || m.phylum == $phylum[pirate]) + return 2; + if (m.phylum == $phylum[goblin] || m.phylum == $phylum[humanoid] || m.phylum == $phylum[beast] || m.phylum == $phylum[bug] || m.phylum == $phylum[orc] || m.phylum == $phylum[elemental] || m.phylum == $phylum[elf] || m.phylum == $phylum[penguin]) + return 1; + return 0; +} + + +boolean is_underwater_familiar(familiar f) +{ + return $familiars[Barrrnacle,Emo Squid,Cuddlefish,Imitation Crab,Magic Dragonfish,Midget Clownfish,Rock Lobster,Urchin Urchin,Grouper Groupie,Squamous Gibberer,Dancing Frog,Adorable Space Buddy] contains f; +} + +float calculateCurrentNinjaAssassinMaxDamage() +{ + + //float assassin_ml = 155.0 + monster_level_adjustment(); + float assassin_ml = $monster[ninja snowman assassin].base_attack + 5.0; + float damage_absorption = raw_damage_absorption(); + float damage_reduction = damage_reduction(); + float moxie = my_buffedstat($stat[moxie]); + float cold_resistance = numeric_modifier("cold resistance"); + float v = 0.0; + + //spaded by yojimboS_LAW + //also by soirana + + float myst_class_extra_cold_resistance = 0.0; + if (my_class() == $class[pastamancer] || my_class() == $class[sauceror] || my_class() == $class[avatar of jarlsberg]) + myst_class_extra_cold_resistance = 0.05; + //Direct from the spreadsheet: + if (cold_resistance < 9) + v = ((((MAX((assassin_ml - moxie), 0.0) - damage_reduction) + 120.0) * MAX(0.1, MIN((1.1 - sqrt((damage_absorption/1000.0))), 1.0))) * ((1.0 - myst_class_extra_cold_resistance) - ((0.1) * MAX((cold_resistance - 5.0), 0.0)))); + else + v = ((((MAX((assassin_ml - moxie), 0.0) - damage_reduction) + 120.0) * MAX(0.1, MIN((1.1 - sqrt((damage_absorption/1000.0))), 1.0))) * (0.1 - myst_class_extra_cold_resistance + (0.5 * (powf((5.0/6.0), (cold_resistance - 9.0)))))); + + + + return v; +} + +float calculateCurrentNinjaAssassinMaxEnvironmentalDamage() +{ + float v = 0.0; + int ml_level = monster_level_adjustment_ignoring_plants(); + if (ml_level >= 25) + { + float expected_assassin_damage = 0.0; + + expected_assassin_damage = ((150 + ml_level) * (ml_level - 25)).to_float() / 500.0; + + expected_assassin_damage = expected_assassin_damage + ceiling(expected_assassin_damage / 11.0); //upper limit + + //FIXME add in resists later + //Resists don't work properly. They have an effect, but it's different. I don't know how much exactly, so for now, ignore this: + //I think they're probably just -5 like above + //expected_assassin_damage = damageTakenByElement(expected_assassin_damage, $element[cold]); + + expected_assassin_damage = ceil(expected_assassin_damage); + + v += expected_assassin_damage; + } + return v; +} + +//mafia describes "merkin" for the "mer-kin" phylum, which "to_phylum()" does not interpret +//hmm... maybe file a request for to_phylum() to parse that +phylum getDNASyringePhylum() +{ + string phylum_text = get_property("dnaSyringe"); + if (phylum_text == "merkin") + return $phylum[mer-kin]; + else + return phylum_text.to_phylum(); +} + +int nextLibramSummonMPCost() +{ + int libram_summoned = get_property_int("libramSummons"); + int next_libram_summoned = libram_summoned + 1; + int libram_mp_cost = MAX(1 + (next_libram_summoned * (next_libram_summoned - 1)/2) + mana_cost_modifier(), 1); + return libram_mp_cost; +} + +int equippable_amount(item it) +{ + if (!it.can_equip()) return it.equipped_amount(); + if (it.available_amount() == 0) return 0; + if ($slots[acc1, acc2, acc3] contains it.to_slot() && it.available_amount() > 1 && !it.boolean_modifier("Single equip")) + return MIN(3, it.available_amount()); + if (it.to_slot() == $slot[weapon] && it.weapon_hands() == 1) + { + int weapon_maximum = 1; + if ($skill[double-fisted skull smashing].skill_is_usable()) + weapon_maximum += 1; + if (my_familiar() == $familiar[disembodied hand]) + weapon_maximum += 1; + return MIN(weapon_maximum, it.available_amount()); + } + return 1; +} + +boolean haveSeenBadMoonEncounter(int encounter_id) +{ + if (!get_property_ascension("lastBadMoonReset")) //badMoonEncounter values are not reset when you ascend + return false; + string zero = ""; //Encounters under 10 are listed as "01", "02", "03"... + if (encounter_id < 10) + zero = "0"; + return get_property_boolean("badMoonEncounter" + zero + encounter_id); +} + +//FIXME make this use static etc. Probably extend Item Filter.ash to support equipment. +item [int] generateEquipmentForExtraExperienceOnStat(stat desired_stat, boolean require_can_equip_currently) +{ + //boolean [item] experience_percent_modifiers; + /*string numeric_modifier_string; + if (desired_stat == $stat[muscle]) + { + //experience_percent_modifiers = $items[trench lighter,fake washboard]; + numeric_modifier_string = "Muscle"; + } + else if (desired_stat == $stat[mysticality]) + { + //experience_percent_modifiers = lookupItems("trench lighter,basaltamander buckler"); + numeric_modifier_string = "Mysticality"; + } + else if (desired_stat == $stat[moxie]) + { + //experience_percent_modifiers = $items[trench lighter,backwoods banjo]; + numeric_modifier_string = "Moxie"; + } + else + return listMakeBlankItem(); + if (numeric_modifier_string != "") + numeric_modifier_string += " Experience Percent";*/ + + item [slot] item_slots; + string numeric_modifier_string = desired_stat + " Experience Percent"; + + //foreach it in experience_percent_modifiers + foreach it in equipmentWithNumericModifier(numeric_modifier_string) + { + slot s = it.to_slot(); + if (s == $slot[shirt] && !($skill[12].have_skill() || $skill[Best Dressed].have_skill())) // Torso Aware(g)ness + continue; + if (it.available_amount() > 0 && (!require_can_equip_currently || it.can_equip()) && item_slots[it.to_slot()].numeric_modifier(numeric_modifier_string) < it.numeric_modifier(numeric_modifier_string)) + { + item_slots[it.to_slot()] = it; + } + } + + item [int] items_could_equip; + foreach s, it in item_slots + items_could_equip.listAppend(it); + return items_could_equip; +} + + +item [int] generateEquipmentToEquipForExtraExperienceOnStat(stat desired_stat) +{ + item [int] items_could_equip = generateEquipmentForExtraExperienceOnStat(desired_stat, true); + item [int] items_equipping; + foreach key, it in items_could_equip + { + if (it.equipped_amount() == 0) + { + items_equipping.listAppend(it); + } + } + return items_equipping; +} + + + +float averageAdventuresForConsumable(item it, boolean assume_monday) +{ + float adventures = 0.0; + string [int] adventures_string = it.adventures.split_string("-"); + foreach key, v in adventures_string + { + float a = v.to_float(); + if (a < 0) + continue; + adventures += a * (1.0 / to_float(adventures_string.count())); + } + if (it == lookupItem("affirmation cookie")) + adventures += 3; + if (it == $item[White Citadel burger]) + { + if (in_bad_moon()) + adventures = 2; //worst case scenario + else + adventures = 9; //saved across lifetimes + } + + if ($skill[saucemaven].have_skill() && ($items[hot hi mein,cold hi mein,sleazy hi mein,spooky hi mein,stinky hi mein,Hell ramen,fettucini Inconnu,gnocchetti di Nietzsche,spaghetti with Skullheads,spaghetti con calaveras,Fleetwood mac 'n' cheese,haunted hell ramen] contains it)) + { + if ($classes[sauceror,pastamancer] contains my_class()) + adventures += 5; + else + adventures += 3; + } + + + if ($skill[pizza lover].have_skill() && it.to_lower_case().contains_text("pizza")) + { + adventures += it.fullness; + } + if (it.to_lower_case().contains_text("lasagna") && !assume_monday) + adventures += 5; + //FIXME lasagna properly + return adventures; +} + +float averageAdventuresForConsumable(item it) +{ + return averageAdventuresForConsumable(it, false); +} + +boolean [string] getInstalledSourceTerminalSingleChips() +{ + string [int] chips = get_property("sourceTerminalChips").split_string_alternate(","); + boolean [string] result; + foreach key, s in chips + result[s] = true; + return result; +} + +boolean [skill] getActiveSourceTerminalSkills() +{ + string skill_1_name = get_property("sourceTerminalEducate1"); + string skill_2_name = get_property("sourceTerminalEducate2"); + + boolean [skill] skills_have; + if (skill_1_name != "") + skills_have[skill_1_name.replace_string(".edu", "").to_skill()] = true; + if (skill_2_name != "") + skills_have[skill_2_name.replace_string(".edu", "").to_skill()] = true; + return skills_have; +} + +boolean monsterIsGhost(monster m) +{ + if (m.attributes.contains_text("GHOST")) + return true; + /*if ($monsters[Ancient ghost,Ancient protector spirit,Banshee librarian,Battlie Knight Ghost,Bettie Barulio,Chalkdust wraith,Claybender Sorcerer Ghost,Cold ghost,Contemplative ghost,Dusken Raider Ghost,Ghost,Ghost miner,Hot ghost,Lovesick ghost,Marcus Macurgeon,Marvin J. Sunny,Mayor Ghost,Mayor Ghost (Hard Mode),Model skeleton,Mortimer Strauss,Plaid ghost,Protector Spectre,Sexy sorority ghost,Sheet ghost,Sleaze ghost,Space Tourist Explorer Ghost,Spirit of New Wave (Inner Sanctum),Spooky ghost,Stench ghost,The ghost of Phil Bunion,Whatsian Commando Ghost,Wonderful Winifred Wongle] contains m) + return true; + if ($monsters[boneless blobghost,the ghost of Vanillica \"Trashblossom\" Gorton,restless ghost,The Icewoman,the ghost of Monsieur Baguelle,The ghost of Lord Montague Spookyraven,The Headless Horseman,The ghost of Ebenoozer Screege,The ghost of Sam McGee,The ghost of Richard Cockingham,The ghost of Jim Unfortunato,The ghost of Waldo the Carpathian,the ghost of Oily McBindle] contains m) + return true; + if (lookupMonster("Emily Koops, a spooky lime") == m) + return true;*/ + return false; +} + +boolean item_is_pvp_stealable(item it) +{ + if (it == $item[amulet of yendor]) + return true; + if (!it.tradeable) + return false; + if (!it.discardable) + return false; + if (it.quest) + return false; + if (it.gift) + return false; + return true; +} + +int effective_familiar_weight(familiar f) +{ + if (f == $familiar[none]) return 0; + int weight = f.familiar_weight(); + + boolean is_moved = false; + string [int] familiars_used_on = get_property("_feastedFamiliars").split_string_alternate(";"); + foreach key, f_name in familiars_used_on + { + if (f_name.to_familiar() == f) + { + is_moved = true; + break; + } + } + if (is_moved) + weight += 10; + return weight; +} + +boolean year_is_leap_year(int year) +{ + if (year % 4 != 0) return false; + if (year % 100 != 0) return true; + if (year % 400 != 0) return false; + return true; +} + +boolean today_is_pvp_season_end() +{ + string today = format_today_to_string("MMdd"); + if (today == "0228") + { + int year = format_today_to_string("yyyy").to_int(); + boolean is_leap_year = year_is_leap_year(year); + if (!is_leap_year) + return true; + } + else if (today == "0229") //will always be true, but won't always be there + return true; + else if (today == "0430") + return true; + else if (today == "0630") + return true; + else if (today == "0831") + return true; + else if (today == "1031") + return true; + else if (today == "1231") + return true; + return false; +} + +boolean monster_has_zero_turn_cost(monster m) +{ + if (m.attributes.contains_text("FREE")) + return true; + if (m == lookupMonster("sausage goblin") && m != $monster[none]) return true; + if (lookupMonsters("LOV Engineer,LOV Enforcer,LOV Equivocator") contains m) return true; + + if ($monsters[lynyrd] contains m) return true; //not marked as FREE in attributes + //if ($monsters[Black Crayon Beast,Black Crayon Beetle,Black Crayon Constellation,Black Crayon Golem,Black Crayon Demon,Black Crayon Man,Black Crayon Elemental,Black Crayon Crimbo Elf,Black Crayon Fish,Black Crayon Goblin,Black Crayon Hippy,Black Crayon Hobo,Black Crayon Shambling Monstrosity,Black Crayon Manloid,Black Crayon Mer-kin,Black Crayon Frat Orc,Black Crayon Penguin,Black Crayon Pirate,Black Crayon Flower,Black Crayon Slime,Black Crayon Undead Thing,Black Crayon Spiraling Shape,broodling seal,Centurion of Sparky,heat seal,hermetic seal,navy seal,Servant of Grodstank,shadow of Black Bubbles,Spawn of Wally,watertight seal,wet seal,lynyrd,BRICKO airship,BRICKO bat,BRICKO cathedral,BRICKO elephant,BRICKO gargantuchicken,BRICKO octopus,BRICKO ooze,BRICKO oyster,BRICKO python,BRICKO turtle,BRICKO vacuum cleaner,Witchess Bishop,Witchess King,Witchess Knight,Witchess Ox,Witchess Pawn,Witchess Queen,Witchess Rook,Witchess Witch,The ghost of Ebenoozer Screege,The ghost of Lord Montague Spookyraven,The ghost of Waldo the Carpathian,The Icewoman,The ghost of Jim Unfortunato,the ghost of Sam McGee,the ghost of Monsieur Baguelle,the ghost of Vanillica "Trashblossom" Gorton,the ghost of Oily McBindle,boneless blobghost,The ghost of Richard Cockingham,The Headless Horseman,Emily Koops\, a spooky lime,time-spinner prank,random scenester,angry bassist,blue-haired girl,evil ex-girlfriend,peeved roommate] contains m) + //return true; + if (m == $monster[X-32-F Combat Training Snowman] && get_property_int("_snojoFreeFights") < 10) + return true; + if (my_familiar() == $familiar[machine elf] && my_location() == $location[the deep machine tunnels] && get_property_int("_machineTunnelsAdv") < 5) + return true; + if (lookupMonsters("terrible mutant,slime blob,government bureaucrat,angry ghost,annoyed snake") contains m && get_property_int("_voteFreeFights") < 3) + return true; + return false; +} + +static +{ + int [location] __location_combat_rates; +} +void initialiseLocationCombatRates() +{ + if (__location_combat_rates.count() > 0) + return; + int [location] rates; + file_to_map("data/combats.txt", __location_combat_rates); + //needs spading: + foreach l in $locations[the spooky forest] + __location_combat_rates[l] = 85; + __location_combat_rates[$location[the black forest]] = 95; //can't remember if this is correct + __location_combat_rates[$location[inside the palindome]] = 80; //this is not accurate, there's probably a turn cap or something + __location_combat_rates[$location[The Haunted Billiards Room]] = 85; //completely and absolutely wrong and unspaded; just here to make another script work + foreach l in $locations[the haunted gallery, the haunted bathroom, the haunted ballroom] + __location_combat_rates[l] = 90; //or 95? can't remember + __location_combat_rates[$location[Twin Peak]] = 90; //FIXME assumption + //print_html("__location_combat_rates = " + __location_combat_rates.to_json()); +} +//initialiseLocationCombatRates(); +int combatRateOfLocation(location l) +{ + initialiseLocationCombatRates(); + //Some revamps changed the combat rate; here we have some not-quite-true-but-close assumptions: + if (l == $location[the haunted ballroom]) + return 95; + if (__location_combat_rates contains l) + { + int rate = __location_combat_rates[l]; + if (rate < 0) + rate = 100; + return rate; + } + return 100; //Unknown + + /*float base_rate = l.appearance_rates()[$monster[none]]; + if (base_rate == 0.0) + return 0; + return base_rate + combat_rate_modifier();*/ +} + +//Specifically checks whether you can eat this item right now - fullness/drunkenness, meat, etc. +boolean CafeItemEdible(item it) +{ + //Mafia does not seem to support accessing its cafe data via ASH. + //So, do the same thing. There's four mafia supports - Chez Snootee, Crimbo Cafe, Hell's Kitchen, and MicroBrewery. + if (it.fullness > availableFullness()) + return false; + if (it.inebriety > availableDrunkenness()) + return false; + //FIXME rest + if (it == $item[Jumbo Dr. Lucifer] && in_bad_moon() && my_meat() >= 150) + return true; + return false; +} + +static +{ + int [string] __lta_social_capital_purchases; + void initialiseLTASocialCapitalPurchases() + { + __lta_social_capital_purchases["bondAdv"] = 1; + __lta_social_capital_purchases["bondBeach"] = 1; + __lta_social_capital_purchases["bondBeat"] = 1; + __lta_social_capital_purchases["bondBooze"] = 2; + __lta_social_capital_purchases["bondBridge"] = 3; + __lta_social_capital_purchases["bondDR"] = 1; + __lta_social_capital_purchases["bondDesert"] = 5; + __lta_social_capital_purchases["bondDrunk1"] = 2; + __lta_social_capital_purchases["bondDrunk2"] = 3; + __lta_social_capital_purchases["bondHP"] = 1; + __lta_social_capital_purchases["bondHoney"] = 5; + __lta_social_capital_purchases["bondInit"] = 1; + __lta_social_capital_purchases["bondItem1"] = 1; + __lta_social_capital_purchases["bondItem2"] = 2; + __lta_social_capital_purchases["bondItem3"] = 4; + __lta_social_capital_purchases["bondJetpack"] = 3; + __lta_social_capital_purchases["bondMPregen"] = 3; + __lta_social_capital_purchases["bondMartiniDelivery"] = 1; + __lta_social_capital_purchases["bondMartiniPlus"] = 3; + __lta_social_capital_purchases["bondMartiniTurn"] = 1; + __lta_social_capital_purchases["bondMeat"] = 1; + __lta_social_capital_purchases["bondMox1"] = 1; + __lta_social_capital_purchases["bondMox2"] = 3; + __lta_social_capital_purchases["bondMus1"] = 1; + __lta_social_capital_purchases["bondMus2"] = 3; + __lta_social_capital_purchases["bondMys1"] = 1; + __lta_social_capital_purchases["bondMys2"] = 3; + __lta_social_capital_purchases["bondSpleen"] = 4; + __lta_social_capital_purchases["bondStat"] = 2; + __lta_social_capital_purchases["bondStat2"] = 4; + __lta_social_capital_purchases["bondStealth"] = 3; + __lta_social_capital_purchases["bondStealth2"] = 4; + __lta_social_capital_purchases["bondSymbols"] = 3; + __lta_social_capital_purchases["bondWar"] = 3; + __lta_social_capital_purchases["bondWeapon2"] = 3; + __lta_social_capital_purchases["bondWpn"] = 1; + } + initialiseLTASocialCapitalPurchases(); +} + +int licenseToAdventureSocialCapitalAvailable() +{ + int total_social_capital = 0; + total_social_capital += 1 + MIN(23, get_property_int("bondPoints")); + foreach level in $ints[3,6,9,12,15] + { + if (my_level() >= level) + total_social_capital += 1; + } + total_social_capital += 2 * get_property_int("bondVillainsDefeated"); + + + + int social_capital_used = 0; + foreach property_name, value in __lta_social_capital_purchases + { + if (get_property_boolean(property_name)) + social_capital_used += value; + } + //print_html("total_social_capital = " + total_social_capital + ", social_capital_used = " + social_capital_used); + + return total_social_capital - social_capital_used; +} + + + +monster convertEncounterToMonster(string encounter) +{ + boolean [string] intergnat_strings; + intergnat_strings[" WITH SCIENCE!"] = true; + intergnat_strings["ELDRITCH HORROR "] = true; + intergnat_strings[" WITH BACON!!!"] = true; + intergnat_strings[" NAMED NEIL"] = true; + intergnat_strings[" AND TESLA!"] = true; + foreach s in intergnat_strings + { + if (encounter.contains_text(s)) + encounter = encounter.replace_string(s, ""); + } + if (encounter == "The Junk") //not a junksprite + return $monster[Junk]; + if ((encounter.stringHasPrefix("the ") || encounter.stringHasPrefix("The")) && encounter.to_monster() == $monster[none]) + { + encounter = encounter.substring(4); + //print_html("now \"" + encounter + "\""); + } + //if (encounter == "the X-32-F Combat Training Snowman") + //return $monster[X-32-F Combat Training Snowman]; + if (encounter == "clingy pirate") + return $monster[clingy pirate (male)]; //always accurate for my personal data + return encounter.to_monster(); +} + +//Returns [0, 100] +float resistanceLevelToResistancePercent(float level) +{ + float m = 0; + if (my_primestat() == $stat[mysticality]) + m = 5; + if (level <= 3) return 10 * level + m; + return 90 - 50 * powf(5.0 / 6.0, level - 4) + m; +} + + +//Mafia's text output doesn't handle very long strings with no spaces in them - they go horizontally past the text box. This is common for to_json()-types. +//So, add spaces every so often if we need them: +buffer processStringForPrinting(string str) +{ + buffer out; + int limit = 50; + int comma_limit = 25; + int characters_since_space = 0; + for i from 0 to str.length() - 1 + { + if (str.length() == 0) break; + string c = str.char_at(i); + out.append(c); + + if (c == " ") + characters_since_space = 0; + else + { + characters_since_space++; + if (characters_since_space >= limit || (c == "," && characters_since_space >= comma_limit)) //prefer adding spaces after a comma + { + characters_since_space = 0; + out.append(" "); + } + } + } + return out; +} +void printSilent(string line, string font_colour) +{ + print_html("" + line.processStringForPrinting() + ""); +} + +void printSilent(string line) +{ + print_html(line.processStringForPrinting()); +} + +//have_equipped() exists +boolean equipped(item it) +{ + return it.equipped_amount() > 0; +} + +boolean have(item it) +{ + return it.available_amount() > 0; +} + +boolean canAccessMall() +{ + if (!can_interact()) return false; + if (!get_property_boolean("autoSatisfyWithMall")) return false; + if (my_ascensions() == 0 && !get_property_ascension("lastDesertUnlock")) return false; + return true; +} + + +// In Mafia r26631, the locations list was refactored and some locations were renamed. These are +// helper functions to get the right zone on either old or new versions. + +location fratHouseInDisguise() { + location house = to_location("Frat House In Disguise"); + if (house == $location[none]) { + house = to_location("Frat House (Frat Disguise)"); + } + return house; +} + +location hippyCampInDisguise() { + location camp = to_location("Hippy Camp In Disguise"); + if (camp == $location[none]) { + camp = to_location("Hippy Camp (Hippy Disguise)"); + } + return camp; +} + +boolean isAprilFools() { + return (now_to_string("MMdd") == "0401"); +} + + +//Quest status stores all/most of our quest information in an internal format that's easier to understand. +record QuestState +{ + string quest_name; + string image_name; + + boolean startable; //can be started, but hasn't yet + boolean started; + boolean in_progress; + boolean finished; + + int mafia_internal_step; //0 for not started. INT32_MAX for finished. This is +1 versus mafia's "step1/step2/stepX" system. "step1" is represented as 2, "step2" as 3, etc. + + boolean [string] state_boolean; + string [string] state_string; + int [string] state_int; + float [string] state_float; + + boolean council_quest; +}; + +QuestState [string] __quest_state; +boolean [string] __misc_state; +string [string] __misc_state_string; +int [string] __misc_state_int; +float [string] __misc_state_float; + +int QuestStateConvertQuestPropertyValueToNumber(string property_value) +{ + int result = 0; + if (property_value == "") + return -1; + if (property_value == "started") + { + result = 1; + } + else if (property_value == "finished") + { + result = INT32_MAX; + } + else if (property_value.contains_text("step")) + { + //lazy: + string theoretical_int = property_value.replace_string(" ", "").replace_string("step", ""); //one revision had a bug that set questL11Worship to "step 4", so remove spaces + int step_value = theoretical_int.to_int_silent(); + + result = step_value + 1; + + if (result < 0) + result = 0; + } + else + { + //unknown + } + return result; +} + +boolean questPropertyPastInternalStepNumber(string quest_property, int number) +{ + return QuestStateConvertQuestPropertyValueToNumber(get_property(quest_property)) >= number; +} + +void QuestStateParseMafiaQuestPropertyValue(QuestState state, string property_value) +{ + state.started = false; + state.finished = false; + state.in_progress = false; + state.mafia_internal_step = QuestStateConvertQuestPropertyValueToNumber(property_value); + + if (state.mafia_internal_step > 0) + state.started = true; + if (state.mafia_internal_step == INT32_MAX) + state.finished = true; + if (state.started && !state.finished) + state.in_progress = true; + + // Adding a new state check that finishes our quests if the user is in CS or GG. + if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) + state.finished = true; +} + +boolean QuestStateEquals(QuestState q1, QuestState q2) +{ + //not sure how to do record equality otherwise + if (q1.quest_name != q2.quest_name) + return false; + if (q1.image_name != q2.image_name) + return false; + if (q1.startable != q2.startable) + return false; + if (q1.started != q2.started) + return false; + if (q1.in_progress != q2.in_progress) + return false; + if (q1.finished != q2.finished) + return false; + if (q1.mafia_internal_step != q2.mafia_internal_step) + return false; + + if (q1.state_boolean != q2.state_boolean) + return false; + if (q1.state_string != q2.state_string) + return false; + if (q1.state_int != q2.state_int) + return false; + return true; +} + +void QuestStateParseMafiaQuestProperty(QuestState state, string property_name, boolean allow_quest_log_load) +{ + state.QuestStateParseMafiaQuestPropertyValue(get_property(property_name)); +} + +void QuestStateParseMafiaQuestProperty(QuestState state, string property_name) +{ + QuestStateParseMafiaQuestProperty(state, property_name, true); +} + +QuestState QuestState(string property_name) +{ + QuestState state; + QuestStateParseMafiaQuestProperty(state, property_name); + return state; +} + +QuestState QuestStateFromManualStep(string manual_value) +{ + QuestState state; + state.QuestStateParseMafiaQuestPropertyValue(manual_value); + return state; +} + + + +float __setting_indention_width_in_em = 1.45; +string __setting_indention_width = __setting_indention_width_in_em + "em"; + +string __html_right_arrow_character = "►"; + +buffer HTMLGenerateTagPrefix(string tag, string [string] attributes) +{ + buffer result; + result.append("<"); + result.append(tag); + foreach attribute_name, attribute_value in attributes + { + //string attribute_value = attributes[attribute_name]; + result.append(" "); + result.append(attribute_name); + if (attribute_value != "") + { + boolean is_integer = attribute_value.is_integer(); //don't put quotes around integer attributes (i.e. width, height) + + result.append("="); + if (!is_integer) + result.append("\""); + result.append(attribute_value); + if (!is_integer) + result.append("\""); + } + } + result.append(">"); + return result; +} + +buffer HTMLGenerateTagPrefix(string tag) +{ + buffer result; + result.append("<"); + result.append(tag); + result.append(">"); + return result; +} + +buffer HTMLGenerateTagSuffix(string tag) +{ + buffer result; + result.append(""); + return result; +} + +buffer HTMLGenerateTagWrap(string tag, string source, string [string] attributes) +{ + buffer result; + result.append(HTMLGenerateTagPrefix(tag, attributes)); + result.append(source); + result.append(HTMLGenerateTagSuffix(tag)); + return result; +} + +buffer HTMLGenerateTagWrap(string tag, string source) +{ + buffer result; + result.append(HTMLGenerateTagPrefix(tag)); + result.append(source); + result.append(HTMLGenerateTagSuffix(tag)); + return result; +} + +buffer HTMLGenerateDivOfClass(string source, string class_name) +{ + if (class_name == "") + return HTMLGenerateTagWrap("div", source); + else + return HTMLGenerateTagWrap("div", source, mapMake("class", class_name)); +} + +buffer HTMLGenerateDivOfClass(string source, string class_name, string extra_style) +{ + return HTMLGenerateTagWrap("div", source, mapMake("class", class_name, "style", extra_style)); +} + +buffer HTMLGenerateDivOfStyle(string source, string style) +{ + if (style == "") + return HTMLGenerateTagWrap("div", source); + + return HTMLGenerateTagWrap("div", source, mapMake("style", style)); +} + +buffer HTMLGenerateDiv(string source) +{ + return HTMLGenerateTagWrap("div", source); +} + +buffer HTMLGenerateSpan(string source) +{ + return HTMLGenerateTagWrap("span", source); +} + +buffer HTMLGenerateSpanOfClass(string source, string class_name) +{ + if (class_name == "") + return HTMLGenerateTagWrap("span", source); + else + return HTMLGenerateTagWrap("span", source, mapMake("class", class_name)); +} + +buffer HTMLGenerateSpanOfStyle(string source, string style) +{ + if (style == "") + { + buffer out; + out.append(source); + return out; + } + return HTMLGenerateTagWrap("span", source, mapMake("style", style)); +} + +buffer HTMLGenerateSpanFont(string source, string font_colour, string font_size) +{ + if (font_colour == "" && font_size == "") + { + buffer out; + out.append(source); + return out; + } + + buffer style; + + if (font_colour != "") + { + //style += "color:" + font_colour + ";"; + style.append("color:"); + style.append(font_colour); + style.append(";"); + } + if (font_size != "") + { + //style += "font-size:" + font_size + ";"; + style.append("font-size:"); + style.append(font_size); + style.append(";"); + } + return HTMLGenerateSpanOfStyle(source, style.to_string()); +} + +buffer HTMLGenerateSpanFont(string source, string font_colour) +{ + return HTMLGenerateSpanFont(source, font_colour, ""); +} + +string HTMLConvertStringToAnchorID(string id) +{ + if (id.length() == 0) + return id; + + id = to_string(replace_string(id, " ", "_")); + //ID and NAME must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".") + + //FIXME do that + return id; +} + +string HTMLEscapeString(string line) +{ + return entity_encode(line); +} + +string HTMLStripTags(string html) +{ + matcher pattern = create_matcher("<[^>]*>", html); + return pattern.replace_all(""); +} + + +string [string] generateMainLinkMap(string url) +{ + return mapMake("class", "r_a_undecorated", "href", url, "target", "mainpane"); +} + + + +string HTMLGreyOutTextUnlessTrue(string text, boolean conditional) +{ + if (conditional) + return text; + return HTMLGenerateSpanFont(text, "gray"); +} + +record RestingBonus +{ + string header; + effect given_effect; + int duration; + int limit; + + //Special cases that have particularities not worth mentioning other than setting a quick boolean + boolean tasteful; //needs 1 or 0 adv. left of its given effect, and breaks after 3-5 uses +}; + + +RestingBonus RestingBonusMake(string header, effect given_effect, int duration, int limit) +{ + RestingBonus result; + result.header = header; + result.given_effect = given_effect; + result.duration = duration; + result.limit = limit; + + return result; +} + +RestingBonus RestingBonusMake(string header, effect given_effect, int duration) +{ + return RestingBonusMake(header, given_effect, duration, 0); +} + +RestingBonus RestingBonusMake(string header, int duration) +{ + return RestingBonusMake(header, $effect[none], duration); +} + +RestingBonus RestingBonusMake(string header) +{ + return RestingBonusMake(header, 0); +} + +RestingBonus RestingBonusMake() +{ + return RestingBonusMake(""); +} + +RestingBonus RestingBonusIsTasteful(RestingBonus RB) +{ + RB.tasteful = true; + return RB; +} + +RestingBonus [item] __resting_bonuses; +int [item] __campground = get_campground(); + +void RestingBonusInit() +{ + int holiday_bliss_givers = 0; + int [int] holiday_bliss = {1:5, 2:10, 3:20, 4:50}; + foreach furniture in __campground { + switch (furniture) { + /* + //want to be sure I have EVERYTHING + //The "useless to this situation" + case $item[big rock]: case $item[Newbiesport™ tent]: case $item[Barskin tent]: case $item[Cottage]: case $item[Frobozz Real-Estate Company Instant House (TM)]: case $item[Sandcastle]: case $item[House of twigs and spit]: + case $item[Beanbag chair]: case $item[bed of coals]: case $item[comfy coffin]: case $item[filth-encrusted futon]: case $item[frigid air mattress]: case $item[stained mattress]: case $item[gauze hammock]: case $item[sleeping stocking]: case $item[saltwaterbed]: + case $item[Meat Maid]: case $item[Clockwork Maid]: + case $item[Meat golem]: + case $item[Spooky scarecrow]: + case $item[Certificate of Participation]: + case $item[Feng Shui for Big Dumb Idiots]: + case $item[pagoda plans]: + case $item[Bonsai tree]: + case $item[Cuckoo clock]: + case $item[Tin roof (rusted)]: + case $item[Meat globe]: + case $item[Picture of you]: + case $item[E-Z Cook™ oven]: case $item[Dramatic™ range]: + case $item[My First Shaker™]: case $item[Queue Du Coq cocktailcrafting kit]: + case $item[Sushi-rolling mat]: + case $item[chef-in-the-box]: case $item[Clockwork Chef-in-the-box]: + case $item[Bartender-in-the-box]: case $item[Clockwork Bartender-in-the-box]: + case $item[Discount Telescope Warehouse gift certificate]: + case $item[Haunted doghouse]: + case $item[Potted tea tree]: + case $item[Source terminal]: + case $item[Witchess Set]: + case $item[Asdon Martin keyfob]: case $item[Portable Mayo Clinic]: case $item[Little Geneticist DNA-Splicing Lab]: case $item[Diabolic pizza cube]: case $item[Warbear LP-ROM burner]: case $item[Warbear jackhammer drill press]: case $item[Warbear induction oven]: case $item[Warbear high-efficiency still]: case $item[Warbear chemistry lab]: case $item[Warbear auto-anvil]: case $item[Spinning wheel]: case $item[Snow machine]: + case $item[jar of psychoses (The Crackpot Mystic)]: case $item[jar of psychoses (The Captain of the Gourd)]: case $item[jar of psychoses (The Meatsmith)]: case $item[jar of psychoses (The Pretentious Artist)]: case $item[jar of psychoses (The Suspicious-Looking Guy)]: case $item[jar of psychoses (The Old Man)]: case $item[jar of psychoses (Jick)]: + case $item[El Vibrato trapezoid]: + case $item[packet of pumpkin seeds]: case $item[Peppermint Pip Packet]: case $item[packet of dragon's teeth]: case $item[packet of beer seeds]: case $item[packet of winter seeds]: case $item[packet of thanksgarden seeds]: case $item[packet of tall grass seeds]: case $item[packet of mushroom spores]: + break; + default: + __resting_bonuses[furniture] = RestingBonusMake(); //they are in a mafia version where mafia recognizes the campground furniture, but we didn't add it to this list yet + break; + */ //Bad idea. get_campground() also lists what you'd get out of your campground at any given point, as items, and that looks too boring to list. Was already getting a lot anyway. Not deleted just in case + case $item[Giant pilgrim hat]: + __resting_bonuses[$item[Giant pilgrim hat]] = RestingBonusMake("a random effect", 15); + break; + case $item[BRICKO pyramid]: + __resting_bonuses[$item[BRICKO pyramid]] = RestingBonusMake("+100% weapon/spell dmg", $effect[Pyramid Power], 20, 3); + break; + case $item[Ginormous pumpkin]: + __resting_bonuses[$item[Ginormous pumpkin]] = RestingBonusMake("+20% Item, +10 Spooky Dmg, +10 ML", $effect[Juiced and Jacked], 10, 1); + break; + case $item[Giant Faraday cage]: + __resting_bonuses[$item[Giant Faraday cage]] = RestingBonusMake("+50 MP, 5-8 MP regen", $effect[Uncaged Power], 30, 1); + break; + case $item[Snow fort]: + __resting_bonuses[$item[Snow fort]] = RestingBonusMake("+25% Item, +50% Meat, +100 HP, +50 MP", $effect[Snow Fortified], 10, 1); + break; + case $item[Elevent]: + __resting_bonuses[$item[Elevent]] = RestingBonusMake("+11% stats, +11% init, +11% item, +11% meat, +11 weapon/spell dmg, +11 HP/MP, +11 DR", $effect[It's Ridiculous], 11, 1); + break; + case $item[Gingerbread house]: + case $item[Crimbo wreath]: + case $item[string of Crimbo lights]: + case $item[plastic Crimbo reindeer]: + __resting_bonuses[$item[Gingerbread house]] = RestingBonusMake("+20% Item, +20% Meat", $effect[Holiday Bliss], holiday_bliss [++holiday_bliss_givers], 1); + break; + case $item[Hobo fortress blueprints]: + __resting_bonuses[$item[Hobo fortress blueprints]] = RestingBonusMake("+5 hobo power", $effect[Hobonic], 10); + break; + case $item[Xiblaxian residence-cube]: + __resting_bonuses[$item[Xiblaxian residence-cube]] = RestingBonusMake("+100 MP, 10-20 MP regen", $effect[Hypercubed], 50, 1); + break; + case $item[House-sized mushroom]: + __resting_bonuses[$item[House-sized mushroom]] = RestingBonusMake("+25% stats, +25% init, +1 all res", $effect[Mushed], 20, 1); + break; + case $item[Lazybones™ recliner]: + __resting_bonuses[$item[Lazybones™ recliner]] = RestingBonusMake("+25% stats, +25 spooky dmg", $effect[Bonelording], 20, 1); + break; + case $item[Spirit bed]: + __resting_bonuses[$item[Spirit bed]] = RestingBonusMake("+20% MP", $effect[Spirit Schooled], 20, 1); + break; + case $item[Lucky cat statue]: + __resting_bonuses[$item[Lucky cat statue]] = RestingBonusMake("+5% Item", $effect[Lucky Cat Is Lucky], 5, 1); //SETS the remaining duration of that effect to 5 adv + break; + case $item[Confusing LED clock]: + __resting_bonuses[$item[Confusing LED clock]] = RestingBonusMake(HTMLGenerateSpanFont("+5 PVP fights, -5 adventures", "red"), $effect[none], 0, 1); + break; + case $item[Black-and-blue light]: + __resting_bonuses[$item[Black-and-blue light]] = RestingBonusMake("2-5 HP regen", $effect[Less Vincible], 5).RestingBonusIsTasteful(); + break; + case $item[Blue plasma ball]: + __resting_bonuses[$item[Blue plasma ball]] = RestingBonusMake("1-5 phys. react. passive dmg", $effect[Stuck-Up Hair], 5).RestingBonusIsTasteful(); + break; + case $item[Loudmouth Larry Lamprey]: + __resting_bonuses[$item[Loudmouth Larry Lamprey]] = RestingBonusMake("3-5 MP regen", $effect[In Tuna], 5).RestingBonusIsTasteful(); + break; + } + } +} + +RestingBonusInit(); + + +boolean [item] __iotms_usable; + +void replicaCheck(string iotmName) { + // helper function for checking ownership of either the item or the + // legacy of loathing replica of said item + + int amountItem = lookupItem(iotmName).available_amount(); + int amountReplica = lookupItem("replica "+iotmName).available_amount(); + + if ((amountItem + amountReplica) > 0) { + __iotms_usable[lookupItem(iotmName)] = true; + } + else { + __iotms_usable[lookupItem(iotmName)] = false; + } +} + +void initialiseIOTMsUsable() +{ + foreach key in __iotms_usable + remove __iotms_usable[key]; + + if (in_bad_moon()) + return; + + // ... for futureproofing, we should probably just make a thing in the library that explicitly denotes no-campground paths + // and incorporate them here. Not really sure why ezan didn't, it's possible mafia tracking is just uniquely wrong in ed? + + if (my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) + { + //Campground items: + foreach it in $items[source terminal, haunted doghouse, Witchess Set, potted tea tree, portable mayo clinic, Little Geneticist DNA-Splicing Lab, cornucopia, A Guide to Burning Leaves] + { + if (__campground[it] > 0) + __iotms_usable[it] = true; + } + // Workshed + if (__campground[lookupItem("Asdon Martin keyfob")] > 0) + __iotms_usable[lookupItem("Asdon Martin keyfob")] = true; + if (__campground[lookupItem("diabolic pizza cube")] > 0) + __iotms_usable[lookupItem("diabolic pizza cube")] = true; + if (__campground[lookupItem("cold medicine cabinet")] > 0) + __iotms_usable[lookupItem("cold medicine cabinet")] = true; + if (__campground[lookupItem("model train set")] > 0) + __iotms_usable[lookupItem("model train set")] = true; + + // This didn't appear in my LoL test run; I am making this more explicit and hopefully this works. + if (__campground[lookupItem("Little Geneticist DNA-Splicing Lab")] > 0) + __iotms_usable[lookupItem("Little Geneticist DNA-Splicing Lab")] = true; + if (__campground[lookupItem("Replica Little Geneticist DNA-Splicing Lab")] > 0) + __iotms_usable[lookupItem("Little Geneticist DNA-Splicing Lab")] = true; + + // __iotms_usable for gardens tracks whether the user has the garden installed. + // Gardens start returning 0 instead of 1 when the items are picked, so checking + // presence of the key is more useful than checking the value. + foreach garden in $items[packet of mushroom spores, packet of rock seeds] + { + if (__campground contains garden) + __iotms_usable[garden] = true; + } + } + if (florist_available() && $item[hand turkey outline].is_unrestricted()) //May 2013 + //Order of the Green Thumb Order Form is not marked as out of standard. + __iotms_usable[$item[Order of the Green Thumb Order Form]] = true; + if (get_property_boolean("sleazeAirportAlways") || get_property_boolean("_sleazeAirportToday")) //May 2014 + __iotms_usable[$item[airplane charter: Spring Break Beach]] = true; + if (get_property_boolean("spookyAirportAlways") || get_property_boolean("_spookyAirportToday")) //Oct 2014 + __iotms_usable[$item[airplane charter: Conspiracy Island]] = true; + if (get_property_boolean("chateauAvailable")) //Jan 2015 + __iotms_usable[$item[Chateau Mantegna room key]] = true; + if (get_property_boolean("lovebugsUnlocked") && $item[hand turkey outline].is_unrestricted()) //Feb 2015 + __iotms_usable[$item[bottle of lovebug pheromones]] = true; + if (get_property_boolean("stenchAirportAlways") || get_property_boolean("_stenchAirportToday")) //Apr 2015 + __iotms_usable[$item[airplane charter: Dinseylandfill]] = true; + // if (lookupItem("Deck of Every Card").available_amount() > 0) //Jul 2015 + // __iotms_usable[$item[Deck of Every Card]] = true; + if (get_property_boolean("hotAirportAlways") || get_property_boolean("_hotAirportToday")) //Aug 2015 + __iotms_usable[$item[Airplane charter: That 70s Volcano]] = true; + if (get_property_boolean("barrelShrineUnlocked")) //Sep 2015 + __iotms_usable[$item[shrine to the Barrel god]] = true; + if (get_property_boolean("coldAirportAlways") || get_property_boolean("_coldAirportToday")) //Nov 2015 + __iotms_usable[$item[Airplane charter: The Glaciest]] = true; + if (get_property_boolean("snojoAvailable")) //Jan 2016 + __iotms_usable[$item[X-32-F snowman crate]] = true; + if (get_property_boolean("telegraphOfficeAvailable")) //Feb 2016 + __iotms_usable[$item[LT&T telegraph office deed]] = true; + if (get_property_boolean("hasDetectiveSchool")) //Jul 2016 + __iotms_usable[$item[detective school application]] = true; + if (lookupItem("protonic accelerator pack").available_amount() > 0) //Aug 2016 + __iotms_usable[lookupItem("protonic accelerator pack")] = true; + if (lookupItem("Time-Spinner").available_amount() > 0) //Sep 2016 + __iotms_usable[lookupItem("Time-Spinner")] = true; + if (get_property_boolean("gingerbreadCityAvailable") || get_property_boolean("_gingerbreadCityToday")) //Dec 2016 + __iotms_usable[$item[Build-a-City Gingerbread kit]] = true; + if (get_property_boolean("loveTunnelAvailable")) //Feb 2017 + __iotms_usable[lookupItem("heart-shaped crate")] = true; + if (get_property_boolean("spacegateAlways") || get_property_boolean("_spacegateToday")) //Apr 2017 + __iotms_usable[lookupItem("Spacegate access badge")] = true; + if (lookupItem("kremlin's greatest briefcase").available_amount() > 0) //Jun 2017 + __iotms_usable[lookupItem("kremlin's greatest briefcase")] = true; + if (get_property_boolean("horseryAvailable")) //Aug 2017-18 + __iotms_usable[lookupItem("Horsery contract")] = true; + // if (lookupItem("genie bottle").available_amount() > 0) //Sep 2017 + // __iotms_usable[lookupItem("genie bottle")] = true; + if (lookupItem("portable pantogram").available_amount() > 0) //Nov 2017 + __iotms_usable[lookupItem("portable pantogram")] = true; + // if (lookupItem("January's Garbage Tote").available_amount() > 0) //Jan 2018 + // __iotms_usable[lookupItem("January's Garbage Tote")] = true; + if (get_property_boolean("_frToday") || get_property_boolean("frAlways")) //Apr 2018 + __iotms_usable[lookupItem("FantasyRealm membership packet")] = true; + if (get_property_boolean("_neverendingPartyToday") || get_property_boolean("neverendingPartyAlways")) //Sep 2018 + __iotms_usable[lookupItem("Neverending Party invitation envelope")] = true; + if (lookupItem("latte lovers member's mug").available_amount() > 0) //Oct 2018 + __iotms_usable[lookupItem("latte lovers member's mug")] = true; + if (get_property_boolean("_voteToday") || get_property_boolean("voteAlways") || lookupItem(""I Voted!" sticker").available_amount() > 0) //Nov 2018 + __iotms_usable[lookupItem("voter registration form")] = true; + if (get_property_boolean("daycareOpen")) //Dec 2018 + __iotms_usable[lookupItem("Boxing Day care package")] = true; + if (lookupItem("vampyric cloake").available_amount() > 0) //Mar 2019 + __iotms_usable[lookupItem("vampyric cloake")] = true; + // if (lookupItem("Fourth of May Cosplay Saber").available_amount() > 0) //May 2019 + // __iotms_usable[lookupItem("Fourth of May Cosplay Saber")] = true; + // if (lookupItem("hewn moon-rune spoon").available_amount() > 0) //Jun 2019 + // __iotms_usable[lookupItem("hewn moon-rune spoon")] = true; + if (get_property_boolean("getawayCampsiteUnlocked")) //Aug 2019 + __iotms_usable[lookupItem("Distant Woods Getaway Brochure")] = true; + if (lookupItem("Eight Days a Week Pill Keeper").available_amount() > 0) //Oct 2019 + __iotms_usable[lookupItem("Eight Days a Week Pill Keeper")] = true; + if (lookupItem("Bird-a-Day calendar").available_amount() > 0) //Jan 2020 + __iotms_usable[lookupItem("Bird-a-Day calendar")] = true; + if (lookupItem("unwrapped knock-off retro superhero cape").available_amount() > 0) //Nov 2020 + __iotms_usable[lookupItem("unwrapped knock-off retro superhero cape")] = true; + if (lookupItem("Potted power plant").available_amount() > 0) //Mar 2021 + __iotms_usable[lookupItem("Potted power plant")] = true; + if (lookupItem("cosmic bowling ball").available_amount() > 0 || get_property_int("_cosmicBowlingSkillsUsed") > 0) //Jan 2022 + // change to use tracking property if/when mafia adds one from coolitems.php + __iotms_usable[lookupItem("cosmic bowling ball")] = true; + + if (lookupItem("unbreakable umbrella").available_amount() > 0) //Mar 2022 + __iotms_usable[lookupItem("unbreakable umbrella")] = true; + + if (available_amount($item[jurassic parka]) > 0) // adding because of a strange issue w/ Sneaks.ash... + __iotms_usable[$item[jurassic parka]] = true; + + if ($item[Clan VIP Lounge key].item_amount() > 0) + { + //FIXME all + __iotms_usable[lookupItem("Clan Carnival Game")] = true; + __iotms_usable[$item[clan floundry]] = true; + } + + if (lookupItem("candy cane sword cane").available_amount() > 0) //Dec 2023 + __iotms_usable[lookupItem("candy cane sword cane")] = true; + + if (lookupItem("spring shoes").available_amount() > 0) //Feb 2024 + __iotms_usable[lookupItem("spring shoes")] = true; + + if (lookupItem("everfull dart holster").available_amount() > 0) //Mar 2024 + __iotms_usable[lookupItem("everfull dart holster")] = true; + + if (lookupItem("apriling band helmet").available_amount() > 0) //Apr 2024 + __iotms_usable[lookupItem("apriling band helmet")] = true; + + if (lookupItem("mayam calendar").available_amount() > 0) //May 2024 + __iotms_usable[lookupItem("mayam calendar")] = true; + + if (lookupItem("roman candelabra").available_amount() > 0) //Jun 2024 + __iotms_usable[lookupItem("roman candelabra")] = true; + + if (lookupItem("tearaway pants").available_amount() > 0) //Aug 2024 + __iotms_usable[lookupItem("tearaway pants")] = true; + + //Can't use many things in G-Lover + if (my_path().id == PATH_G_LOVER) //Path 33 + { + __iotms_usable[lookupItem("Bird-a-Day calendar")] = false; + __iotms_usable[lookupItem("Deck of Every Card")] = false; + __iotms_usable[lookupItem("Fourth of May Cosplay Saber")] = false; + __iotms_usable[lookupItem("hewn moon-rune spoon")] = false; + __iotms_usable[lookupItem("Potted power plant")] = false; + __iotms_usable[lookupItem("protonic accelerator pack")] = false; + __iotms_usable[lookupItem("Time-Spinner")] = false; + __iotms_usable[lookupItem("unbreakable umbrella")] = false; + __iotms_usable[lookupItem("Underground Fireworks Shop")] = false; //can't use any items here + __iotms_usable[lookupItem("unwrapped knock-off retro superhero cape")] = false; + __iotms_usable[lookupItem("vampyric cloake")] = false; + } + if (my_path().id == PATH_EXPLOSIONS) //Path 37 + { + __iotms_usable[lookupItem("Spacegate access badge")] = false; + } + + // Remove non-standard. Do this prior to replicaChecks, since replicas allow + // usage of non-standard IOTMs. + foreach it in __iotms_usable + { + if (!it.is_unrestricted() || it == $item[none]) + remove __iotms_usable[it]; + } + + // Legacy of Loathing introduced a whole host of replica IOTMs. In order + // to properly support LoL, it was decided that the easiest way to work + // this is to reinstitute __iotms_usable for the last few years of IOTMs + // and make it so that ownership of the replica flags as ownership of the + // real deal. Alternative would've been to make every item check a boolean + // that checks ownership of either/or, and this feels... less bad, to me. + + // One note -- familiars are the same as the real deal, so they don't need + // checks (I don't think?). This only applies for items explicitly formatted + // as "replica [itemname]". Another note -- we did not add a path check here, + // mostly owing to the fact that the replicaCheck function also works for + // the real iotms, which means it'll properly populate __iotms_usable... + // even outside of LoL. + + // One last note -- I have noted where each is used in TourGuide. This is + // mostly a check for me personally, to make sure I have looked at each. + // We could delete the "no tile" entries at any time. I just didn't want to! + + // 2005 + replicaCheck("miniature gravy-covered maypole"); # no tile + replicaCheck("wax lips"); # no tile + + // 2006 + + // This won't show up for the natural tome, because you never have the tome item in your inventory. Just pings for replica. + replicaCheck("Tome of Snowcone Summoning"); # handled in tomes.ash + replicaCheck("jewel-eyed wizard hat"); # no tile + replicaCheck("plastic pumpkin bucket"); # no tile; fixed in passive damage engines + + // 2007 + replicaCheck("V for Vivala mask"); # handled in Misc Items.ash + replicaCheck("navel ring of navel gazing"); # handled in Misc Items.ash + replicaCheck("bottle-rocket crossbow"); # no tile + + // 2008 + replicaCheck("little box of fireworks"); # no tile + replicaCheck("haiku katana"); # no tile + + // 2009 + replicaCheck("Elvish Sunglasses"); # no tile + + // 2010 + replicaCheck("Juju Mojo Mask"); # no tile + replicaCheck("Greatest American Pants"); # handled in Misc Items.ash + + // 2011 + replicaCheck("Operation Patriot Shield"); # no tile + replicaCheck("plastic vampire fangs"); # handled in own tile + + // 2012 + replicaCheck("Libram of Resolutions"); # handled in tomes.ash + replicaCheck("Camp Scout backpack"); # no tile + + // 2013 + replicaCheck("over-the-shoulder Folder Holder"); # no tile + replicaCheck("Smith's Tome"); # handled in tomes.ash + + // 2014 + // replicaCheck(""); # handled in DNA.ash; already used __iotms_usable! + // 2015 + if (lookupItem("replica Little Geneticist DNA-Splicing Lab").available_amount() > 0) + __iotms_usable[$item[Little Geneticist DNA-Splicing Lab]] = true; + + // 2015 + if (get_property_boolean("replicaChateauAvailable")) + __iotms_usable[$item[Chateau Mantegna room key]] = true; # handled in daily + state + replicaCheck("Deck of Every Card"); # handled in tile & lvl8 + + // 2016 + if (get_property_boolean("replicaWitchessSetAvailable")) + __iotms_usable[$item[Witchess Set]] = true; # handled in own tile + replicaCheck("Source terminal"); # handled in own tile + + // 2017 + replicaCheck("genie bottle"); # handled in own tile + + // 2018 + replicaCheck("January's Garbage Tote"); # handled in own tile + if (get_property_boolean("replicaNeverendingPartyAlways")) + __iotms_usable[$item[Neverending Party invitation envelope]] = true; # handled in own tile + + // 2019 + replicaCheck("Kramco Sausage-o-Matic™"); # handled in own tile + replicaCheck("Fourth of May Cosplay Saber"); # handled in own tile & lvl 12 + replicaCheck("hewn moon-rune spoon"); # handled in own tile + + // 2020 + replicaCheck("Powerful Glove"); # handled in own tile + replicaCheck("Cargo Cultist Shorts"); # handled in own tile + + // 2021 + replicaCheck("miniature crystal ball"); # handled in own tile + replicaCheck("emotion chip"); # handled in own (annoying) tile + replicaCheck("industrial fire extinguisher"); # handled in own tile & lvl 11 + + // 2022 + replicaCheck("designer sweatpants"); # handled in own tile + replicaCheck("Jurassic Parka"); # handled in own tile + + // 2023 + replicaCheck("Cincho de Mayo"); # handled in own tile & sneaks.ash + replicaCheck("2002 Mr. Store Catalog"); # handled in own tile + replicaCheck("August Scepter"); # handled in own tile + + // Swap parka to false if you aren't torso aware. You cannot use the __misc_state + // shortcuts here, because this comes before it in execution. That's a sad + // disadvantage of all our bundling, did not remotely realize state wasn't + // instantiated before this. That means the parka stuff hasn't shown up since + // Legacy of Loathing lmao. + if (!$skill[12].have_skill()) + { + __iotms_usable[lookupItem("Jurassic Parka")] = false; + } + +} + +initialiseIOTMsUsable(); + +string [string] __user_preferences_private; +boolean __read_user_preferences_initially = false; + + + +//File implementation: +//Preferred, but not chosen in case this somehow triggers an HD read too often: +/*string __user_preferences_file_name = "data/relay_ezandora_guide_preferences_" + my_id() + ".txt"; +void readUserPreferences() +{ + __read_user_preferences_initially = true; + file_to_map(__user_preferences_file_name, __user_preferences_private); +} + +void writeUserPreferences() +{ + map_to_file(__user_preferences_private, __user_preferences_file_name); +}*/ + + +string __user_preferences_property_name = "ezandora_guide_preferences"; +void readUserPreferences() +{ + string [string] blank; + __user_preferences_private = blank; + string guide_value = get_property(__user_preferences_property_name); + foreach key, pair in guide_value.split_string_alternate(";") + { + string [int] split = pair.split_string_alternate("="); + if (split.count() != 2) + continue; + __user_preferences_private[split[0]] = split[1]; + } + __read_user_preferences_initially = true; +} + +void writeUserPreferences() +{ + if (!__read_user_preferences_initially) + readUserPreferences(); + buffer output_value; + boolean first = true; + foreach key, value in __user_preferences_private + { + if (!first) + output_value.append(";"); + else + first = false; + output_value.append(key); + output_value.append("="); + output_value.append(value); + } + set_property(__user_preferences_property_name, output_value); +} + + +string PreferenceGet(string name) +{ + if (!__read_user_preferences_initially) + readUserPreferences(); + + return __user_preferences_private[name]; +} + +boolean PreferenceGetBoolean(string name) +{ + return PreferenceGet(name).to_boolean(); +} + +void PreferenceSet(string name, string value) +{ + if (!__read_user_preferences_initially) + readUserPreferences(); + __user_preferences_private[name] = value; + writeUserPreferences(); +} + + +void processSetUserPreferences(string [string] form_fields) +{ + foreach key, value in form_fields + { + if (key == "set user preferences") + continue; + PreferenceSet(key, value); + } +} + +static +{ + //mr. fusion: + boolean [item] __pvpable_food_and_drinks; + void initialisePVPFoodAndDrinks() + { + foreach it in $items[] + { + if (it.fullness == 0 && it.inebriety == 0) continue; + if (!it.item_is_pvp_stealable()) continue; + __pvpable_food_and_drinks[it] = true; + } + } + initialisePVPFoodAndDrinks(); +} + +//Runtime variables: +location __last_adventure_location; + + +//Runtime call functions: + +//Init functions happen after state and quest initialisation, so they can be referred to safely. +string [int] __init_functions; + +void RegisterInitFunction(string function_name) +{ + __init_functions.listAppend(function_name); +} + +string [int] __checklist_generation_function_names; + +//Call function registration: +void RegisterChecklistGenerationFunction(string function_name) +{ + __checklist_generation_function_names.listAppend(function_name); +} + +string [string][int] __specific_checklist_1_generation_function_names; +void RegisterSpecificChecklistGenerationFunction1(string function_name, string checklist_name_1) +{ + if (!(__specific_checklist_1_generation_function_names contains checklist_name_1)) { + __specific_checklist_1_generation_function_names[checklist_name_1] = listMakeBlankString(); + } + __specific_checklist_1_generation_function_names[checklist_name_1].listAppend(function_name); +} + +Record ChecklistGenerationFunctionRequest +{ + string function_name; + string [int] checklist_names; +}; + +void listAppend(ChecklistGenerationFunctionRequest [int] list, ChecklistGenerationFunctionRequest entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +ChecklistGenerationFunctionRequest [int] __specific_checklist_generation_requests; + +void RegisterSpecificChecklistGenerationFunction3(string function_name, string checklist_name_1, string checklist_name_2, string checklist_name_3) +{ + ChecklistGenerationFunctionRequest request; + request.function_name = function_name; + //Hardcoded to match call structure: + request.checklist_names[0] = checklist_name_1; + request.checklist_names[1] = checklist_name_2; + request.checklist_names[2] = checklist_name_3; + __specific_checklist_generation_requests.listAppend(request); +} + +void RegisterTaskGenerationFunction(string function_name) { + RegisterSpecificChecklistGenerationFunction3(function_name, "Tasks", "Optional Tasks", "Future Tasks"); +} + +void RegisterResourceGenerationFunction(string function_name) { + RegisterSpecificChecklistGenerationFunction1(function_name, "Resources"); +} + +void RegisterLowKeyGenerationFunction(string function_name) { + RegisterSpecificChecklistGenerationFunction1(function_name, "Keys"); +} +string __close_image_data = "data:image/gif;base64,R0lGODlhgACAANUiAODg4IqKitra2o2NjYGBgdXV1YCAgOPj49vb24eHh4iIiIODg+fn5+Tk5NnZ2YmJidbW1ouLi9zc3M/Pz4WFhdTU1MDAwMfHx8HBwcrKysbGxtjY2Lu7u8XFxfj4+IKCgsTExH9/f/f39wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACIALAAAAACAAIAAAAb/QJFwmBEMj8ikcslsOp/QaBOgcSIMBKN0y+16v0fAIlRgCgKhUOAAbrvfXcYgnagoL4Z0OuCA+/+AAHN6IRZIV4RpBn2AjY5bYolpZUJnkmkPbI+bnEhylyF1Ihl5oCEPG52qj4KmaSASBK4hi6u2cJGuBmUIEbOZt8Fen64JlCINvq4PjMLOTq3FAEgCsrrNz9lhY7oQSpbLmtraxKYKx0kHaMvY48HR5tNN1bO17u/cpgbeT+CmwPdWlQN1Toq6X+0CNoJHUJ4UetcUssoHap8Xf6AASvQz8FLBLwfZbcQ1KJ4biPoSjoRE8ZLFNxgvaVy5paOkj3BC/lNJkwlD/48O/aCsqKUntJaSXjaKKWmm0SQ2E+F0pDMjT6M/bwZ9NNRl0adCcunjp4ppIqc9oxKaqqqqzKsKs0rduqpr0q8jxVYkK8wsIbQB1ephK8xtU7jP5K6l68xuIgN4x+l1yXecXz2AnQlOQ3ic4bOIVSkezNidY0KQtU1OWlniZUzigm0O0VniZ0J8hI3mXHojAmumstxa/bh1z9dqYm+aXbtng3WmcnPaTbu30d+zhE+sZxxsJeig1jhijs57kuezpPuhrsC6eRHYXWl/Qxx19/dHkIt3Qx4/FPSuqOcFe+75N0R8wUUWRX16KGVgP+Bdsl9NJRFU3oNOABhdaGFUCP8UhlwgCMp8R3EHYhf6KadEfyd2oWF4cBHY4hciXkLiNibO+EWKUHl404U6bvGihF/JGGQbNUqiHYOK3HfkQxFKsgZ7QD7pYpRSAdeQlX4kOUtxXP6BnDlVhvnFkF9WZ2YjXo61piNjclbmm200oMCXFBRI54AffJnanoH4GJ6CgA6IlHyEFirFbBKqqOiCgqYZQKKPLsHklzdWysRsFJQSnaOadjhLAgDoR2mll+4iRJt6ZBrqbMbkhyVuoCpKHannzarHpKGGdShqVbKahqt7wjonArruUauZtxaIZiK8FprqnEcIGwKxVhq7BbLpLatjs1emd+qJ09KopY3jPqj/LRjcBuitgeC68Sxu6ZpXLhzWYovful0mm1yL8QIy7671rnSvI/kWLBG/j7T7qX8BczLwHgpL9muD1P6RsHcMr+JweO9KFqkeuDozsRoVD3exIhlvsvFIHTvzcaMbRazNydHec/A9L48TszszSxnyJjYrhHPKuKxMS8vZ9HzLz775O+EqRdN0tC07g+X0I1BfJ/XQA45Mh54rXe1I1v5t/UbX7wUNLdhPVP2g2W6gfaLaXLCNodu0giH3jMmIa2g9TGMYS3YV661jL91K8beVgQeYrt1rHo6oE4pzybi7PokdCtlcRh6dgpQXanmCnngea68HKvNwWKqDTqfog4pQT3qlHohw+ogCXDBq4YpuboohBdx5ScmsM0E7IRRMMAQELgGv6e56OH8EBomsnvwTwqfBgRLFj729FJE3zwT0qo4vxeHWM9GB9OojgEESQQAAOw=="; +string __new_window_image_data = "data:image/gif;base64,R0lGODlhgACAANU7AImJiZiYmKCgoKenp/Dw8MjIyKGhoYyMjKioqLW1tZmZmYiIiISEhICAgIWFhfPz8+7u7ry8vIeHh6Ojo4aGhunp6dTU1JeXl+Tk5JycnLGxsaSkpI6Ojpubm4qKisXFxYKCgvb29u/v75+fn7S0tK6urqWlpb29vaKiotbW1q2trdPT08fHx9DQ0K+vr+3t7Y2NjZGRkaamptHR0bq6ure3t8bGxtfX16mpqbKysn9/f/f39wAAAAAAAAAAAAAAACH5BAEAADsALAAAAACAAIAAAAb/wJ1wSCwaj8ikcslsOp/QqHRKrVqv2Kx2y+16v+CweExGYjSZS2DNbrvf8Lh8Tq+/L5kcZrxq6P6AgYKDhIWGh4iJiQ0WYS8AipGSk5SUABBgNJWbnJ2TEWATnqOkpRtgI6Wqq5MCYAKssbKEBq+zt7O1X7C4vaq6XryDFALFxsfIycrLzM3OzQ6FwF3Cggpl2DsB0raE19lk27Tdg9/gYuKD01zVgebnYOmC61vtgO/wXvKB9Fr2f/jycdkHqF+WfzoCCtRC8I9BLAgVLsTSUMfDKxEn6uO2q5BEjVUqXrSSEeQWkeSsmTzJMZjHlQxbUnsJk6JMdjRrWkHZ0ZvO/ys8Xfr8GfJmvZxEpQSdOTSpUqP+kDp9shRn06lUoR6UipUJzwoRTEwYQLas2bNoz3ootCCt27dw45KVgQIHiwc2x1nw46tvJQ4VgEqrIMGvYUodBNNScbixpBs7pcFwTBlRjci0olXePKgEZnVrOYv+Q+LzvAOjRycwzQ91as6ri9JyPQgEgNu4c+verZsBgwW8gwsfTvw230GxqYikLQhBVyiQCCWfsryQ8+dOoiNnXZB5oOvYmWgXNP3pbOvhm4wPVD5KdULg0ydZD6g9lPeD4ss/Qv+P/aznwbefEv3p8J8T+DU34HyFHNhEgt8tiESBDnoljXeA6CehEBRy5/8Qhn9ouGGHsqkDog4iSkiicheit2ERK1LXooAvEhGjeSa6WCOHDXpo0YkpLnijezPmt+MQQ95XpIJH7pAkgDnSeOSTCC4ZYZNUPmhlhk062WOJp+m4Y5YWBmgkll+yaCaTU6Yp45pXtimdjwYA2SWZS0DIJZpzgtmamDXiqYSeId7pJo5hSjnmoUTCuaec2/nZHaAvCpoEoSga2qeaUZ4JqSAxyAVXYY4WyqdhdVI6YmOpKlrjAqza2aRmhgkg65EMNLbBrTvCetgJvAZ6GAUEBFvpYR/sYOyqhDBQ3LML/DZBCkIsqyKjWlgrJLZZaDugpVJ4ux+4UYgrH7lQmJvJHrpPqBseu064ix28Tcj7HL1M2NsVvkvoixW/Svg7FcBJCOwUwUgYnBTCRyhMFMNGOPwTxEVIrBPFRFhcE8ZDaAwTx9Wqeu2mXXi8EsjKirwtyVycGEABMMcs88w012zzzTjnjDOt5IFx4mt+VVjFz0D7IjQVRBeNy9FTkKp0YxqAQcHTjrkARgdUN5bsFy1kbdgCmIAxgNd92SDGAxFwQLYsDSgwAzYPiEDA3HTXbffdeOet99589303BCF0KfjghBdu+OGIgxMEADs="; +string __left_arrow_image_data = "data:image/gif;base64,R0lGODlhgACAAOZyAH5+fnt7e/b29vr6+nx8fPn5+fv7+/f394ODg3l5eXp6evj4+H19ffz8/Hh4eImJiYKCgvHx8bGxsbW1te7u7o6OjoyMjJOTk5ubm8TExM3NzeXl5dzc3N/f34eHh8nJyb6+vtnZ2fDw8Kqqquzs7Jqamubm5uLi4paWloCAgIuLi/Pz86WlpZKSkq6urrq6urOzs+Tk5N7e3szMzLCwsIiIiNbW1tPT0+Dg4Ly8vKKiotvb24SEhOrq6tfX19HR0ZeXl/T09M/Pz4+Pj52dnXd3d9LS0ujo6IGBgZ6enrS0tKurq+np6ZCQkO3t7a+vr+/v7/Ly8srKysbGxpGRkaSkpJycnKGhocDAwOHh4efn57m5uaOjo/39/Z+fn729vYaGhuvr66ioqIqKipSUlMLCwqenp8vLy9XV1bu7u5mZmdra2oWFhb+/v8PDw6CgoMjIyH9/f/X19QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAHIALAAAAACAAIAAAAf/gHKCg4SFhoeIiYqLhAU2PBAIkpOUlQgML4yam5ydnp9yAkQBAKWmp6gADk1MoK6vsLEDHwwAcbe4uboADFINscDBwoYLJC0Kusm6ARgCAsPQ0a4GIAq2ysoAEDsL0t7fiwUbDwTY2A4wA8/g7O1yCy4J5soKQ0cF7vneCzIQ1/O4eGX4pa+gMAEHdCADmCtAklAGI8ZqoIEXw4AAbOCTyPHTAhEl5F28lYDGgXUdU2oqkCHAyFsBLGwYoLLmogNMVJQbCSBAGYI2gxpqMMHlywBqIqAUytRAhxo7L5YKsZEpUwELlhR5GSfBiJNWrQ7wEecfwwAPYtAMK/QZBqNS/wOAMMCW6YAzUS8GQBHhQN2gByi0gCv1RtW/KhvksPYygZgFSxFzLGDCwkK9HnCslZxyAQ2RcXMA5TyZAw+zAAOQgeKXdMcFOkBfZPBjs+uIXTTEYdDYjLPbEhdQCPmSAJgOtoHrMzDFwUtVEwxEVt5OQBgVvEcSuOCkG/WCDWAQZkhgBt3v+gZk8ZAXoAIWENG7QzjCuXYEHM7Lb2cATQrU5gCQgBLq7FddFBhcdlYFPRxmoDcGfDAeQAR8kNyD0RxAwgXtzROAF/Fh6M0ALzB2EQH4XSiiMAPEMMaE5jggQQHTrQgMQhLIlloFJjhoYzAF4PDfURno9+MwB7wBI/82zIR4ZDAN3IBEdgwxAAFVTw6zQARW6DiPjDRmKYwBZ5AyUkwb+CgmKIE10aE5AWCh4pqfGJCGgu4BsUKNdHZCGTk8xeHDnH1uIsAA8TT2BFiFThPClGc+cAKhjS4iQBCxvaTAXJW6UsAPb2JDAAoi8NmpIgdEwCFPBNxg5KmbUGPmRQksgRCsnQygRQV4wikppbgWgpUSXpqjwBavBqsIPwgAKCoVSim7SQEsLJlMKUKoKa0hBhiRApUAOQBfa9smssAKRNh3Vg3IlbvIAHDMetYEo7lryAFQoGCtLgRUQAG59nL7xb65AECABskGLMgBPVgQajIJVLECwAoPUoD/BL2K6sEOCVcsQpfabdyxwt1+O1ICXExc8SEHVJFxNgEgvLIhQfqjnb8Ur4zVBFudSe/Mheg6xMvJBMAusO520Ya84Y4L9CACqPrwLgBk+7TFPxCcCwHQmmrvpVcUi82xIwdsQAgQgOvhr1eHgqi6DHl169UFnACoVAQYUba9dhKdzKiltq3hqiNture7BsxAgLPKoDWp4EFwIbYyCSzqtbsDrMGG2gEKinS5Azzhty4K6Hl5uQscgd1RcrYtxwBuJMB40TJpG3ABTgAxei5gnr6tAUKYPNuVtn8thxda49Kk79IWIENZRB6+LY6TF81j8Zi7mPwtvbdNoonkpSj4/4ZTL/MQ88pGuP0tFX4urQBRlLC78gxiX25/SMy+y4AFPk0f3BTCj/SkpR72aAo+6AtWeNYXh/IMUFnWWZ12uOOdpw2gOc9xQHQSCCvhEEc7x3Gfsiiym978xn8FyNRLaCPCYBXANPpbxmpyVjHPVG8XARBN2yhjmaNkpoW4Ugz44vYYDp4qMIPhCgAM4z3FcWUvfbmaM97ynAB8oV4rGwv0IqUWKWalZyf7ihE75RSoPAcAWLoaURiIlGg9jWE6qeJPdtiSJ8oEiKf6yAdPZpIxVooiFuFJRuz3PgFcYX7KO9/V+GEznjBgIG2Dxw1JZw9CKkscdxsJOvoHNGoMESwg2uDGIo2BSJg0w4+NmkUtntMLLFZMFKRIhSxLsYpW0O0RkbCELiWBCXcEAgA7"; +string __right_arrow_image_data = "data:image/gif;base64,R0lGODlhgACAAOZyAH5+fnt7e/b29vr6+nx8fPn5+fv7+/f394ODg3l5eXp6evj4+H19ffz8/Hh4eImJiYKCgvHx8bGxsbW1te7u7o6OjoyMjJOTk5ubm8TExM3NzeXl5dzc3N/f34eHh8nJyb6+vtnZ2fDw8Kqqquzs7Jqamubm5uLi4paWloCAgIuLi/Pz86WlpZKSkq6urrq6urOzs+Tk5N7e3szMzLCwsIiIiNbW1tPT0+Dg4Ly8vKKiotvb24SEhOrq6tfX19HR0ZeXl/T09M/Pz4+Pj52dnXd3d9LS0ujo6IGBgZ6enrS0tKurq+np6ZCQkO3t7a+vr+/v7/Ly8srKysbGxpGRkaSkpJycnKGhocDAwOHh4efn57m5uaOjo/39/Z+fn729vYaGhuvr66ioqIqKipSUlMLCwqenp8vLy9XV1bu7u5mZmdra2oWFhb+/v8PDw6CgoMjIyH9/f/X19QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAHIALAAAAACAAIAAAAf/gHKCg4SFhoeHLwwIjI2OjwgQPDYFiJaXmJmam5ybTE0OAKKjpKUAAUQCnausra6dDVIMAHG1tre4AAwfA6++v8CcAgIYAbjHuAotJAvBzs/PCzsQtMjIAAogBtDc3awCAzAO1tYEDxuV3urriAVHQwrkyAkuzez3+A0Zs/K5EDL28AnspiqJsX63FOg4oGqgw2cFbIhCaGuWhgYPMwITcIBGAoq2EpQQEVCjyVUDNlg4CDJAhnQnY3JqUCZANYoEVDA5ILNnJgER1LCkGGACRp9I24WYCJJAjQ7bkkodxHHER5BxiixZ0HCq1AExHgztR8tHL69TDYCwiTUABjld/9H6PBABxdh+BM6clYu0wI2bRFtQ4MnXp4AFYq5SxJbjaOGeA3B4uEtOgQUTMB/HbJCDLcgENEpqNnkAChnK1gDw4JB5tMYBPxhgjZNAh2jXD4eZUYxQtoYuuE8O6ACGAFaRFG4HxyfAwIRQWB1Mibr84QInF4yDZKAiTNzqAg3M0N4ShmPwAlWxiNfUQ5a96PEZ4ICAPEIHIxjGTz9ASQLA8gCQAhrU7cdOAT1UgBoyCmAQxXcGejPAB/YhFMAHBUbojSpeLHgMAReQQJiG6gxAX4XkYPMCfCRyI0ABEozT0hgxsNgiRCYoeJwE+t3YjQEZeJhLCji05mMwqhTT1v8bIx4JUQgQyEYRA0jccJ6TG8EoI0UJWBGBcli6UoBKQtpyyhkZhunLAFiUaQsBTQymJpIrAMEeRQqkkeacrQzgQxwAkmMOZnz+wtETvPVDzwAQFtrJACeItR0SIezpKCdq3YlQbUE0eqkmAoiAAoqC/mDkp5sYcAMBgZZzQQRNoroJQ0skmmIA2sjKCqSS4lmBFjbqiokBW2iqqBJcCStMBFSQeg0CACnLSQFCMGUhC6dKewhPLGzZDwMpGGGptoUMV4ObcThAxApgkktIAxOgewocwbpLyAEUVODsMQGgAEWs9hZigAastvTFuAEfsEIVtpZjQQ8ABzyIATt4sG//MhJkKzHFFn9mhQgSb7sCFw0jA664IRsysGcIKVBFxBLjqy9IAEBQZMqFwItuVhMki7Mg5qKrwBDA/iwIt94GGEAbwBktB7XW4vWqp/YC1WxbpjotB7HGypPAFZ06zSu6DEBQqdMMWRWdC4w6bYARBeP0wAkauxvqqFjlibC7mWIFoohiRyovATPsre2hJc/DRRAw2+snoNuxsUa9VdfZdWVPUO54m1hxd0S77o65Es0JuKE5uS/GmDcQTtRNbgFQStlbCkIYLm2SOwfgBVxuB4kVLTK4rm0BOe6cAI9Uo65lWzSerq2J9dGswIpOF7Tz3427O+HF/GLoNII6gqRA/wkPGg2Of61egwSBbp8YXX7JHy7Hen6757y04nGPSwDmOX1ddp3rTvxu5xzogEQ691PWcIpznBIkx3wC2E3n4nARscVmNrUpwACVVZrT/G41wpMWZ1i2qdCITTI7swyhfnaYxPxOAY353l9mEwDBZE9bdLHLbAiXQGE14Ask7IdbhmE0sPRqMXEwi/kOoDasaMVnOINd1PDyFNsJCyhCoaFRnEaTIMojJxArIplo+JIlegSDIwHd8CSSPpMBoIIslINBZqOAKxDxZ/rgB83+oUZpuQMeGKyH+cKRNLycI4TCkgY1XpgrFhJjZ3FQBjOMFgs9LmYXPdTVJ0Jhik6KAg8VG5SWIiBBykZIghIRCgQAOw=="; +string __refresh_image_data = "data:image/gif;base64,R0lGODlhgACAAPeIAG1tbW5ubvPz8/T09G9vb/Ly8vHx8XBwcPDw8HNzc+zs7HFxcbq6unR0dIKCgs3Nze7u7urq6nJycoCAgIGBgXV1dd3d3dfX1+/v74SEhJmZmXd3d+np6ePj44yMjJWVldXV1dDQ0ODg4Ovr635+fnl5edHR0aWlpdTU1OXl5ebm5t7e3qysrNjY2IqKisHBwXp6eri4uNvb276+vsnJye3t7eTk5LGxscTExOHh4ZCQkJycnJGRkaamppOTk6Kiont7e6ioqIODg4uLi6+vr3x8fN/f35+fn6CgoMXFxZ2dnc/Pz7W1tefn5+Li4n9/f87Ozq2trdzc3JKSkoWFhZubm9PT04eHh4mJiaenp4+Pj8fHx7S0tKurq5qamqOjo9ra2nh4eJ6ensLCwpaWlszMzLOzs9nZ2cPDw4iIiI6Ojqmpqb+/v42Njb29vcvLy9bW1nZ2dry8vH19fbKysujo6JeXl5iYmMDAwIaGhqqqqq6urre3t7m5udLS0sbGxrCwsJSUlMjIyMrKyru7u6GhoaSkpGxsbPX19QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAIgALAAAAACAAIAAAAj/ABEJHEiwoMGDCBMqXMiwocOHECNKnEixosWLGDNq3Mixo8ePIEOKHEmypMmTKFOqXOlQBQ1CRzQ4mElz5o4eci6w3AkxApQbdzIsOES0qNGjRA+Q+KBnSxOeUAUisOCmDdKrWLG6wCNCQFSVTA4AyEq2bNEAG2Z8LblFx1CzcOFu+ABmrccRM4TE3cuXRwivdi8aePGWr+G4VGQMCEwxBIWxhyPDPaBjBGOIK3ZI3ry3ARMMlxcaoNGA8yEAFYpMyMC6tYMiFQJwTiMiNEIEHzhT0LNEAQIDBQQIHy7AAAIIKNaUkHwAje2CF/QaBqAmBgoOFFOY6LLhcBUEzwds/ykcNw0gFRxpaCi9l4qT0ANi8D3goUNIBEjIm5XBeMAPAnEF0IN9JKlABGRmJUCDXQb0gGBZO6yQkgg7AGhWBUksBtUAUcQ1gRU7PQAEXAE8EBUdD2a1RgFQQeADXASUMREg72GEg35XlQCFXTMccKFOD1mhlw4sWrSCBGapUQdjIBRh1gYpNGSAIUYhoeFEGCRglhLPUZAgeAt5aVQAf1R0hFksGPBcBLmVJQZDLiB1ABwTjVEWAXwU+dwIPJjFwEIc4ChEDREpsFxWAPzwXEEFXFFWBdgpdMJVWlzZ0Itk6QHYogNB4EBZG4CJEAfdHQVAFw+FUBYPCnBqkBTsZf/1p0J2XvVGQwJ4QFYRhLpqUAgWYnWAEQohUOpRCxCo0AxkAVCbrwdlUZYXC3XgI1JXMEQFWTdAi1CuZAUAwkIaYOWFmgihQBYWonpbkAVaZkUBugiNgCRSAIxh6UAFjIgVAPxFNMBTgTHQ7LgKMYEVASYcZESwSO2wL0MpaJBADoFlSRYMeh5kKFYkREpQEFnBAMFDAvjxQbyKBnbGtVjtqJAJsl2VxqaIYAAzUlk4hAANQyAF5FoDWJXVBwsJkEdWJxA0CFmgLTQAGykW5QNjMpSlLEJG3HsVDgP9oCKgJ8BAFgEgBmYHWS0rJC1WFbQgkJhX0YnQBT/sjBUVDQf/9gZZEzDEgddIzWtDVmEcZEALWMAlQRS2TUCWhAslQZYLdMha0AAvkFBzWUOkMPFaW5ClBUMQzIForEclEMFATdzwRFxh4NHxZXXEexUArS5kgd5wTVDAAEYEoXtZB2hwsqtB/3tGQ3ccVogKbVSdlQTPQ/sAWXw01MHxcCXwuVkLmNG7t/5e5YFDCpuWlQ5DuzsFWb0upADh7hNVgXPuEpR5Vn1jCAjG5z4liKx/AvEDWbjgkAI0z31PuBUCC4IAiB0FCQ8RAY4MU4EeTBAhjcPK6R7yNslQwAYfRMiksFIEiKigApGJwxhul8KByCErC4gIDqyHKA2gsIYIKQNZ/87XEGPtpQTxA6JB1JUVuUFEBATEyg2IqESDWIAsSZCIF8qihiRW0SArIMusIGID/BUlDDH4IkMiIMaJyAcprFLjGtsoEQXEYAr3ooCJ5DhHzVUEAUvgQv34qBA2+pGQJDEkVsaISJF0gI6NFEkYDxlJkICBLE6sJEisQBYLaDIkgiDLJ0PSIawAISMCKIBxMEDDRpZLKxTJwQtYoAQPUOEJMGgAAFgwSkTAECtkoMgKr4K0Tz4yK6iaCA6yUoJRvoAs/JMIE7EihU+eKSvPkogKyNI0TS7NlBZRHVaEV0kIRLEo3aQIF3D4ukjugSwhsEgTLGgUJkQSA2b71w8pgv8AcV6lAVEjpBToWZQStBIigSCLzAj5BbK8ACMgIIsGENmBcxJlAziriHSuEgAvKpEIZOGBRm5AFmrJ0QAkwKJGRHA2KgKRBYDjSBXWNboJIiAMZOkDR2RAUKIAYAlf7MHZorQRAWRgV/RKYQvKQgSP2KCnRNmDEh94lThYxiNry0oCEPZBM5QFch/53cYG6S4ngO8oJBAJSMlyNQQqgHVXeWhIImDGozDQXQWIHlnIcNCNwAF4RiEA2LwF03DVaCRZvR7GfOWGsgCAkSLBwKfIsgCuPgcHUCVKW01iBcAapQFAfQ4bzDIBgp1kBjwsSgOgUFOoNLYsAUCBSgZABrP/BECngRGAGFJLlBKxpADz21K7eMKBPpklChlFyQioKi+PomQAKJCcWY4QlRScdZFJRYkBusDbokz0K3VIKVyEEM+UOCYuHljeV5wQJxJpoC4lkUEVLIqUNzFGAVfobpUskFyNDCAH14wLBkNjAB3wJQBPKC9HcuCCzB4lADNo7VfeyJcJiEFGF5FBEDJA36ts4AESXosJ0seXOCjhBSBQQX8NogAp0IAF0jWMC4jlLR3otyxX6IEZHsDjHieBBVOAq2EC8IUVP6cAf9hg/tznAPhOMAJfcPCSO3MD9aZwBVfo8JTLsoAPXLWKAsjBUbdsmCmIjpACWMIOtEzmQwQhV5ORtMAXxNvms+SBCFYepQW0IJYtByABQchzLwcyghbEQFecaYAP2GCBgA5aITUwgRyCUAUPkOBQSIHBEzxQBSLgQQrZfbSoR03qUpv61KhOtapXfZKAAAA7"; + +string __bad_moon_small_image_data = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAACyUlEQVR4AZ2WzUsbXRSHVUQhgi0iSgmYtFS7aJG2WdQgiCGlqyKKC1+yaHFRhQpFsCAKIqgLRZOFLgItqYK4SCRI03FTtFCC1Fr84P0PJItQQjbNR5vU5NdzBicMYT4u88CDMPfMfSA4M7dGEAf5gvSTETJ2/TdAviSdAGrMNMNLfiRR7draGmZmZuD1elFfX8/XJPKZldhNMkxCy+npaahJJpNYWVlBW1sbr0fJVtHYA/KnXqixsRHFYhF6jI+P81yafGgWu08WSOg5Pz8PM0KhEM9ekY/0Yjbyl1GotrYWmUwG1ZTLZQwPD6OhoQHZbBbM5uYm3/ObvKEVk0gYOTAwgGqOjo7Q3t4ur3s8HuRyOSiMjY3x9cPqmJuEmTs7O1AzOztbWdva2oIWLS0tvO5Rx76KxPi/jrm4uIDT6ZSv9ff3w4hgMMhzJ0rMLhLq7OyEwsbGhnxtfX0dTCKRQD6fhxalUgk2m43n73DslUhsaGgIapR//8nJSXm9o6MDqVQKWgwODvLMG44FRWK8qRZ1dXWVmdPTU2jBDzytv+fYJ5HY4uIitIhGo+ju7sbExIT8k2kRDochv/aIQ5HY6uoqrCJJEu/xmWP7IrHl5WVYZXd3F/IvSLwTifEzZRW/3897hDj2WiQ2OjoKq4yMjPAeUxxzisR6e3thlebmZt7jHilzYhZramrC8fExzs/PcXZ2VvHy8hJGbG9v8/3/q19XT0lYNZ1OQw+73c4zz9UxJm62qdvtlh/QpaUl2YWFBX736X5M+dhA9/3Q+sS0kldGsZ6eHogSi8WU+25pxZgnJIw8ODiAGXt7e8p8n9kZpI/8oxdzuVwwYm5ujuf+kh7R09Vt8oteMB6PQ02hUJA/Ow6HA9ffxrtWzo3/kd+qY11dXYhEIggEAvD5fMqx4DvpMz83muMi35IfyH3ykJTIEDlFPhY5Ef8DCuHZP51PEtAAAAAASUVORK5CYII="; + +string __matrix_glyphs = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAACvCAIAAAD1+0KvAAA++ElEQVR4AcRbi3dO55r/Pa8JQgSRtkRL6hI+xCDSOi7pEXXXOFRLi6Ip6kJQF22IICEuVZc0otJjnHbWzFFdRw+nnc4cR3UZPZQxf9J0/9Z693523v3u70vHmvmtZ2V92fvd7+Xdz/15N34lBgLvCzYI1gv6IETwuxQYD0wVuOiG4JFvDJ5FF1ACHOJYNRwrRwwD1gp2Co4KcsFrgiOkN/zthwsmCioErwqWCbYLzgi+MuiGBOQjWGYx9yoDzBCsFDQLrhn8A54yBNgrOCg4LBiKJLwi2G2wUbBW0QZuUKNBg3GWCnxuAuowyEOEV0Vdd3ii3oB3cdzgOXjRHfjYBAy0QDBJsMT2eYZbmSP+kU+REthipmCToC8iLLXt3xH4sJZtXCpDAiaycSJlPEMkrm6KYLWl8D2sECwXVAnGCgYjWEiL7XwEO88jh0XYKPhv46W/qBfMn5hk2/9soDEK0VOliKFacF/1+YMJRCERLyB5Gn83uG5wxeD3/DEKEcqAcwZTRPGT6mQ0Ynhd8ITXfzT4iFK7SnDaNm6SgPkGw85fYbVnl3YKXJTBs58c1MV8wW2Ddx0ttc0O+lht9XX/y/qJG/WEEhJhmY/dSK2q67kSCOJ22/6iwUgJaJRgCif3mX1qrLOMoRTNsNtLJnjrLobwbX2ejQYqnjtkL2416A/MEvxOcNlefE0CpukH9ABGqRk2G6sekmirOO9MsFuwmertbcFCwTQJJKZnoopWSq6VY+0yASdVczIxUAQv2HH3G2gsUFsdojmH/akRWNBaNAn5mvTLj4MS7Ms8vrYRiLAhVdZLgK/t7yUCF88B/xx/pFnQCxqBQBynddgluMk2lDbcMPjW4J6lAUoiw95WC+75pse7N+zvuyYQ07X+5Zx15r9Z8MjgzyZgnVOCBsEewft0RGoFLsqBxYKFpNk0Ny9QebpotNP4L4OMR23cNzGTuk7wJd/UV2TlH+2071Dj3jR4y51SRtCipHYgEvBmqqwXIxLuRYIEcIXvxjs5ZGLveGfSEKcMtnFV7whW82+ZFd8TSubqUqf3kmC44DR/TxKATtA0CV7DQdvmtMEeUo1AY6xSCS6dM0Dc2axLbEnmaDHBPMfZ/gcopbLO2bR5dkWfmCSHgNeP0kHhv8Fy0tALgey2GQzy+7SzKGGhxu8gXTZoExQBDfbWvtSRlgj+rsSlTjX+A69kpXl8pEqJ4ASJGPkkJSxUSF9yqpV8pAiBwA0D1ggOCY7y7+/tg3sFiagU/M03GUqMRkf2+UeBxmY1T9cHfs/evWUiX+xDCWTd56lskdwcdaEqOJTk8f5GIn9Yox+w0t5aLUjHQiVtmwUaxaHtIZ2gBF8kJ4UXy/lIrZ6JEoWRgv6IGg+hrHPZyCP76640HTOYLNDQszpim/0y0FzBcKCC6neeKB9CjdtmsEOwVQID3MynQsPc2zGoe0zMhL/EPpfbBTbau2/YK1oFntJX6CQZpMIAZy1T/JthRKGwwLLVbRPpmSM0UVfsU/WSFgjtDk0+6U3pNDr7sdQiaGKQt4NR0/P0cnuRBe/YNrvZw2P7LzUw/mT/3aL63y/ZxIt6Lx8JKADalKey3t1HuzmkuBdJDhtBlzbcnBLlbL9tLxbRU7nGrk8J75K/wVU/jKIb/uCeNziLWivIgjLgkuWIZZIUZZITCxCgB2jblJC96ZeDA3F2WykwfuF26WMKKAcNhKND2dQ226ZCsz/NnoBvSEl5PQ3tSEaT251R6gTuCmqFjytaL539pklq8lMF6ahUjeldoxDcSdJzDHC1RiyFiiOU7/2pUgPWNtvAuhcpEZ9bdvjKQGOo4rvQL1geZ6L3BC6mCe6qNg+4xa5p2CP4STX7mS21xN8xUXAyjMqDTgO+iY8+Qc3zN8INVZMcRIfjKh3+j+z1rzkcfwcWSuN5T2h7ld5liCJEPdxldJ6CLXbcR8xwUcqjLbqmRnldOofXMwRL7eN6maFWy4ThXTvZuZYKcIFgPmOkLYIOFTJ2QosKZydaeWpVrD1doCHUXdoRPUGeTURPYJVgG81bsTJLmxS/Dxe42GobHKbPvFIJ3A4uYURcvEJ+b1TqJBylRlCIyN8ss9fbeatZO/kqsaM1BwkfGrwqGJokSEuSvJm3JMH37m9f/3kltQsEe3VLBv2tnVJsM3OwSfsFcSjeoWwd4Js4qi6+LLEkXLMehdmofvBiBKK48Fs2vmTwRShbpGFIwBpnLQ1xN7snkgPlz0w0onbUq/n43wz+iRFwKOUgF55WnT9UPN0duOjZyduOdR9KvmwRhBikDC0pdved1Pel1V4fm+3MkhPZRn3oemFbRLltBr10V45ftljd2sJMdQomZJ2SIBH9uLO6ZYn1JDqslqt2Oj/MW51tsIFhHOGOvl2iTVgrkUXvjhhP/07sZBQtFuSCKqrPULgL47pwmbpLDwNLQl3luk1DyPi76Km2Ci5RXNoYINYKMvAiD6gnN50WdLOJqjrBfpo0DZ1WbWHjdEwCzgq+s/Kk6XsTqNAe8OJlwR8N/pNO5seCXlQe5wWj445uKI5XaSmGK4f8Fh1aY7WlVhuU5tieGASj3KQKdTGAftkfAhPLxzlWjhgn2ChYIShAAsYKjlmHZrUAXMI+QQdV91KB4CmhTBTnZmfMrhXL8uh1v0hPqpQeZtfhHbE3jaIe6wW+Etfp68/tGykoZTM36ivOYSElfCtPHX3ZeddQAFxgonU5XYP/d7zCwLFFAlnJEQupgT6lQvL5caxIYqoEUd8Yvt2BpGHOlhWwMckyGf21hZbyPZmiVs6hnX5oV9EPWCSooRCP9z++hrNaLBiT+xDPq2CrU9eFVMKsHGM1OaCG21QtgYNeyZhyGHX1APxKdKNMaExTYXcP5ITZEvmf3Tz7kmLjC9F51W51Wdvy3irKr2RdISMokyiRMINVyCIKXAHZK4+UgmI16AJBiP7kRWP3KvSZFwpyxXzlpxU7pX5ez04PdBWZzHhOcIvW8Z7BTb6tep6gGIfYaxuMwPR+Z3CF1v0gjY325zcJ6sm2iThj8ImgTT2ywbKjzuE88c48uGXiRfgBatWhVl+khnC2LieqFqSg0Ek26CHuMbg4o4ar4Lu33KytD43caEGeUzI65T3LkZ3OmGik/emNGaU0Wz9laG5D7BAkosnT/ojpnG9qizui2xgWH2WmLEQD88lno5ZBm110pPcpCV7IdHSl6DgiO2U1yZeTpHOeZNtMCs8a9QgZgfWWTyV4u/9qmeKEJESo5wXXyeadoq4vKZcP7JU/2206LblKPLkP45FDe06VwDkGqR10/k/568F/cpg1A/y7klot4ulnJ3x0UTCD4colS+Eu/YUb8j3Luo9DmROkIyy4rVct1wt7yEZbRTl45GWHUnXIAEZj7arxcon8l0H0rkGfpSPkLG7iNLL5bB6KqDc6M2ydXjqcoygQr9DA10gUc3cwlJxFI6dzapouk+WbVJpplVAI6F5MZ89jBC+SX7XEr3MCMN7NlTYJ4ohW10LdsE34UrlFA/k3HZ84xzP0Fm1TNatGqsyLJhL6ueEjk4VRWhLdYbws8GI08FfV3s27LlPi+64kV6CrGYLvEccI8QVk6LL1UcmdmQKN7/Sc1fGlHbrklXquSlHQ2zFmBdYLBnOB5cB0pVSqBHPIdvskdsyqmccQNAySRa0uKf2+gt3GEdWLdkiCC3bflW+iN+/md+KIoTwTuVVsXULR+wKTmlbsUPbJ8dfU6UPpwpnIBgqrPjLR6klj/ZYO/BTBVO7R63w3nao6A50jTtlJZUPzoVbB6VVJrH9kO1h5wGC/0mSFegNtPtk95HTcPvK2c2ud6rzB4Lg99vWaZItfuvMQ70meGdBeXAquGlUSceJR5c3mGPV6XFyVLh4CL57lKa3pgmIldm9JNJ9LZJ0bKrvkI32s5aFzMnK2OomRiANq7UskVsgqh4VSge3O/tz0FNcnp27RwxxDplJ1uvGkQQp2uhGhRV9lh9pZtc2Kj/RZBcprnfDglaJa8ab3OqwP30MdltglcJFHKW+MJ4onMKZ/g7WsnnqNzpnFSokkEvCXthy6GN+l91Q//T0SrB1AfYrU+iV2k1WJ7xmVWPDvtWI640nWzAmztfTDJaUT0mXuY6l/3NANPiOdKxB/ZCr4EJ3VRAhwyz6+WOzQdPIL/aXJWz5PmxB70PokM9hfM7iYyNJqKDGJOCzJ6mepY2KikySCbor/7nuqeflAjVDwBBm7kwXxQtNKUTbgND3AxXRxx/OQczn9iAvu0WiiQrBGsF14zlnRRoGLHkC9J1w7awLJ6ISjqt45W1BCr6GAWzyFUVxZPBO+gU51Oc9mTBacVZVdXZWqkpjsPkvPw9CvblGikFjaamCMUMXNGUmil+DNFrhlulO0o3O5nE4w8XPO9ZzqFG5veHGO40Y10dyWCXor2zo9HpoT+mCin1rEX3ZV4jvEn9a/4BnF/RZofbb5ZJBT5mgzU8Q/q4NLIYYg+ZF7qk3uyalz/gPCN+O+fQfdWPfTrKnI4naMhPcLEqoQfs3gObWZPfnS6NiGyfYRzXelSIMAGdqbc3Fr1DNpX2pTp6QrzTPFm0ejM4k6dQyDO6tONjmWbJbARVXqZNoMhsOLQUCzo+TEI+6tniGWSJfr5Rt04PMSM1n/IvghzgV36dfVJBX4ygGyJL4xaBRUogsQYDTj4w/4GYgPk1hn/dFRElcol9qAtQlukosf8e8NE/RcpE6e3KCTotlioiOU1w2mIxmVPNr4heCvKgn1mMmpI6yspCOfZdpHNlvXP9X/3y+4raz1VbGWxZHgI3QInjhZ9GtU3Wm7n0/Ky3aotpB//w9QwBx6EUeUX1WbkiTHahgwBhgHvNj1MrOgyyhkTWxmbk/2AvqkvwJld58BhpBKgHxPizSemk+/ppbG/OmiiAWZVZLre6oU/zEu6uoa0oj4p1Bz+CHaOob/TxcV/Iyj0f8J8igEQ+8VVKiEUl90AT34CjLAy9lOVUziZM7/Qsb5FIX2CS0MOvcYfEDazfJLueiPA/63qBT8ltHFRh5J7LD+eZ4nDXSEnudkQZ4yhO30SI+RNM/tSfo4Rxe2M06kMZMuTxPTQIdpt6ZwrBxRoaaUiA91JtkyXAdTTmvj4ZAgux9ekuSsFKgTPDYPH19CJrV0Mw7RBzlzUuyl4AyrbytSk5rfekZxXRtdg3pAd+k/Eh6kNbGFz7AArPPyAtxN+HgiGPEHz2S+Z3E+cY21rCtX2DVWq0zWYL48bnfCV9df8ETHM9TSocnX5b+f6DpcsTWoz9jgA8FAJBePM8AhCSrrbfTJ240qmZN7FnGqvRm/B8LapFMhikbSFeJvzBdf3lg/61G5nrLPCX5R/z/tnfl7ldXV/tlPIMRAAkFClEEGRBCQQURQrHXAAeNLwVoVxLaiYFsHNBAGEdCUAYSCMhhIUmul1sG++FXq8NbWalWUIuRf+ub95Nqn92Y9e58nGK+XH1jXunrVkyeH55w8a69h3fdal7mc4LNN+LJXhSDCDslZx9M03Zb54ByWykJGLCwHXtLkeF2qlVeneIIYgeHoPeTObi1Pd5SZVAV3UQfP1n6lpRxdeSXXm5BYqleeNujJdmOhOYVA6NgHIaBr4PQbW+rJUEyvRQfgoTe4OC+dUOVrtQDB4Ft5WaM+U9DRCK5dLtviuqNl32nmYR9HfMQ5GT+BOFFW+wsO+D7dZ9IrUzbGeqEjn+J7SOPGoR2o8nAT7xAJW9XPnmxwSf35iP/pZv7zKXc2ynpb9BsgLbzS/P0Pk54e9gMf7nQly7DxrT7F+g7R5GGEEPQORnKGRXpL8l3M9HasPNorpP1l9TYKy4romG26WyXTv9XJJ5Ke1ZPia5/NFOrsleO02Vfa18pJU6r0/TaTyhRHTuk8rwWvOZv6623ozUQDo3i3Eluze1BEjW/e7wazcS3VulkEN9pfWu66TiyC6vlJC5jlSnWcsKSOKbwmV+7JfP8V/TQcsXBZ8DeWR75AGUuxV+tKbk/qKo5z6E/++g0c0XfzTY0S+/uE+28WDpJyeUvVuh/LTIwa7fb4nt0g3uRMpO+kNbKfULL2RQUNd2xxMDX5pXRgdMsykuNbzQcZWGp5aZ1yKGM37hc7WEcU3URfuutLnOxKjZ2gf7xKmQG0bjJ5eLEY8kt4rt3XNBI6TgtLrMNAQDaB16lVXoJthfIZDkvnJzdkhTmv3VYtp1MjE0iXztd5mYZKJjjFiVzTpgNsvEzSkhw+NZMP202BdDx82w39ydt3Ppq6nirQJs9wmSsESZWJ/vWtmelf8UcMRRoXi2g5DDVFn2PZf6LzfVrwErR+Ax5OurACa6J5MEV89hfwl/zF5K/ewr7iLm2lV33SK/q6UIF/S/thvk94bugjKE/p8LyR+Q/YJ0SkyFvdEnKO5wDH7PqwTsp5Jd0N3GeRMbif2aqZhAi2hHLU//RJJ5VwOFoqN7j/hP3LaBSN5PiRir2Y402G8d6Bn5vKc6oM86qwM3pE80tlFQMzyHjQdETGPvHTEylfeJOFq4kR78cKSwS9/SGw+RHDeK+md9aaB6PE4wYWvFjyxfoS90RAVRV4ZU2dWzV698Y0xSluGaV4UDK4Vzylv9UkDj9ycjgZmSQnSqPTf1QKUHnN5nbild1nxRAzZfCM1U1O+IDERMe08plLpeLr/s4/QVtkxARcWJSkq/vZ+rO0QhGcN6PnLPU9E/PqyHCZQoe1ulOQD3/n+ln6iXyrY5W49tfl0w3lwPw8Mgpjhpqmd/9T0pBQaJhLNTEBP1MfGbD1MFeWcofub+A30oC3eiTAXZOMB08BDOInhOXeJjjkTMNmMrOYjHXcjVjDvS5o7AwBfbGZoSe5naWakrvFDpbiOJ6Wu/2pywcJU/L1YCXaSuqrnMIhMLJbnaTyomszMW5/hz+XQUR364wRTK2BZraeGY8p8NR/llckyC+VB17iyHkhtHisWdyqdM/0I1wvU4Ie9V38DnAvHPFK4qNn+aHMqimVn1pcdwjHf5IYlJXxIcE+L2MT2INBEm10cVgWUTSlVmxU+jz/wruX/PQbinjyTteSFv9u3n8GF+8PadB7pduzXH40mR55lxxUxjCO+d8+sf7G/BMj+CfsCaRRwnfi4zmc+aRSUfiGBOwDyZ6fAvoyo1SS3UZHc2teQWeavL7YcT1GubgYOzGjztWEfVRx+FhDWeFtYjM2qlIVgTW1Q5jX0HEq6YS9rOtvuVpSQ+lnSwxM9DeEw6Ar4j1AxaMUis/m5l8097AnC0oIY6V6LOmvQKbB1uwu2bGUHm300AGIjO6IfytBRjzCVzqNBM/+4hRHRhOU3X10voEH4SRGcJiYqHtMx9c8gAtdqYLfY+FRxd/I8XCCiBckepyFTKb+quf2f4kNBXw4oWF1HeN/JNo8zmWzuWw7MK5vDSq9lm/qDUy/yaX6OfPoYq1z8DYoHm2lSiw+2E9e4vobGenYDL/5JPn3Go/fq+SnC/h17RmM5cm4HUzPvNAldz1bf8YBl7q8Q30n8Z5w4MkXGN55IXUQI4iNi0tvt5/l+608V9pxrVe+8f8DqQDQPkmJy8VlGI/tc7Q8083USh7ATRTxyzxDgLMOoYn2lHI33iNx/JUrgvPlndGhnsc2Jf5kaEV9OefeC/GW8yBOmke4RmfaFgUL4ERaUPxLSq5jfM6NFMKuIuG+PDa4m0ilWxuKzLXbTOzXQoRcJXOybG15AP51IUUopTbNKXf3hxTmmBYpXN8txee5nGM6ZceOmKuRaTf7BaOUK2PlF2MzHKc4M6TOD93cbcJDR8J9F/9oJfUfB4W8CJH3RgnpNcPWTvmd8CrGE9aUrhnCodJ1b3V8Fd2l7Pj8N9zwfwshxz71sR5LVJRKJE7dShXluhdlWlaLt601Lgfs358m4H3yESp5/V2hSeZCMtaAcdec+2mQYi95cpv+E6WbacaPXi5J/ENhE7pUPzhMDkMU7WuFnhv9AX1u4/LFrYoelPdfW4ytuUXvf7KLdkYTM0xbwhyxiUDmRho42iZ60P1vereKdsdDgh2c66LzTndG8IsLICAFo27wDi/nlbEeljLQ7EgPP9EVnh7ONXrCGJbqeDv6Ct3EiITUHAEi0EcpEqwm835IqgW/gO3e5CR6kguSGo4y3Od8gYaH8UlTK1E2sf5LHXzR1xGa9xMQsqLLFGyguiBCNsTEo/qm/z9/zjivyhGZSlm7dcbXxk1Bk/LpQraI6fRSiVju5z0Qvhi6IFZFG3xNW0mRc+Wu6iP0nIf5w28ChCUD9yBJ0/neJc+E9ESF4ztDYA/qAtOyKazRINEZzrNdfLYGN7pATFAraDoaTkdPP0sBdlOmxaMUo2kIjuCXPNDbSyVf/t1pktjsliyzQ2gTW8Ki1Qg/nTw2cHtpaaIWn93J8eDPS4JzCVMa84K+Gq5ninxAGVnBZ+Ew+N/XM3F4xqpMIckGsZMh4L5MyNrC0MDLxFjXu2CS22wyvEUwaL+L+3U9S54Hj62JZqOeK9hEl5RKr3/Kgqh+lqXBC6SmSuZsXMOdr/hP04zIkVvVkngnTYJ2GV/rbzW8Ad7zWwNOHif9um59SgaCK3X4dTMd7K/K0tbrk1qr8bA2fJRi3JHDMBc/YcooB6SIHZP2JF14dQjk0HEWQ7FXLT/1kdD0EF5zkJ9zo+HlYnbKHPEd1gaKR89TtjVkAqUgiMMDGqaDsl+S3KHdeOJ6X0Eqfcs/k5J7afJeg/8+8e5JFS9Zw+SQndxAR/z6AZqwn4nwgD80Fiw7EuJK+J0rg+Xp+z1YzGYXRFs7nXexHDInpaH0BnsU3lAekUAbVT/kj+cv85NylLbrO6mfRD8CYFimb2opu1Ib3ug/KafrCIPBnMa7SQFGm9B3retSf6LQF3k7+U1qpdqceQK75Ih+GNzPEFtE2i4UI5Vm9cHWp9LSn060soRQVn2SrfvcARsxzaWZ57R+y3uKlXRwZUhZlpGZ8otNCmWKgDvvwWlt525bw0nRi3319EHpzvbzfcyzDGtBCNy8WsIIZ9hE7QJgnRGOrOWnODvKxn7sNueWIW9W0MXPHSGyxe7bWB0mgn0lY5mEasbWIZPgXZi8Lmez12uuT4dMM3F8KVFbERvlTUi+cxX20SaLMGHu06sQmf5NX2gF1pM/m0BOhfvDQEGDW10jpJiNGjyaxvmPOIiT3jErSvJjnRQmyO3S+VENd94kF4ID4ePM8/f2lu94Njo4zXH9FB+sdbjAG+3E6V6JsVv239LQyKZSyBxCPWgeme6kgIkrOF7TuJ0k7dWmrBTchvAlGWF+Jb+yz6fdMZnYR/s8EQvmDOieDlYTNqMGhsXe7XoyYbK2c6VwsAXibuuDOMtfSV+5zndUjxAl7BWsywzM44AUADx2M5WV3EgYG01SbolMX9pmLGCUzG+yageqvihLgXbJA/sakeS/dE+RnOcLqWS1ixP6rvAs3l8Jsb8y/lOrOtte8wWbB3eYWPdNn5ncri1kjOk92kEn7Iw7LPtKw0LuxK9vcRbmLVtaOK5+J9e8RQs5NUZvmjw1KJFehJZzJGKXHWYOCzArBnIKxkM0WZrmruwY5LQ0C6Ijt330XJzTMDm/jSEtYZKFKr6EfYIrHSKuitQ5paPi4zN1vSNDBFAyzwr//nspsI8nUG+N7HGqivRMqE95H9Ya/zZHcVa8Kd7uFL3YA/orcjzMETry+2bGHXigqCzx2XOTuPZ4Hdv7e5LpXKmmOnhMqksngG9OT77t3Rwqn4K9Kp004/BNzvS/N9P5PmNiiLeSlI4n+KTHvV0NoF/yDNXyypBKOV7oy0cFp32SwvWV5Zuv3OWwH4wyO5xoczY+tarA9eMpiBaXodT8Jrry/Mw6EhvX251pJVLXoQX5zfDYeiyV/oP0ftd8i29z5j+Y8tCNKvilFMMCJK4ZBg7kKbC0Ews8mtupif43AVRxuQ7bWuuiY1GHYN+DIyiDsnI54UIT/0SuTIK6MoEHgtWbpWM4HDVbgz0NTWnqb9MqbLgIRZ/kleJRERb5z/nDHEzqKzps08iP7LAZQz5+gkHbC2gtr5ORcRMYXTPTtAujZXOgzlacjA/r8Iyvbm0r1gufJNG4lWpZr2T1JhdJ9Yrs5qvDPq7xeqoUBmf+RZ6s0d4c3wy7xelj3243Lb4dVM+rf0qJOLcP1vP3V5EyNXGyFRLZqNrmTQNFlUeZ0RdM3cVzW9lSrBUmhLu46lafAZqkxlVbyA3hs7aX7DMmNxWeJZmwYIagpihAja5n798XFu8KTuNH+BvUalztGQxac72C1FYpINtJ5RkIKzV/ZFiYv2wj49ch291H2qIQLaQY7A6aaVupYRzC0gILPkMz8mSwYIxXiI1Py/DnCYUnvjeGoxQ+UEgwJdkBkZk0n8uxMZzn4yr6d91DyBpwKKOoPUWFn3bGp9xewjG+kJLF48TG26WP2+YYRS9MC5AhqKCv/2Bs6A53diB5LJjbFfPBQsyUVLhVXtR1bur79stPZUJicinJwTxIQF8Jbdok2VodarM8U3PN3aw2o6xulrJo7kTzlVSaXpQubHF5VjyrykzYtIP9v0UMgWuUvnImrpSea1Kxub1CbNROXXM4/iCLhB1yGOTntew7NQEpvkBwLAUi8K8E1JMrpe7H23k3ay1Y7+Z9Syng0R4ZPnDqtt8VpsI6Vy4Cp2/zL+pfxyPFtT95EznK/ybX8gu+gut/gcXbT1Gbl6fdSwy8Xqd9USSpiccEH2ZYggtvzAcu/c0OjGN8P1/qsL74NJW4BZu7ibu35OLNuP/uYKLyiNK3I277JTR9S/XkCYl4otHpVCFRYSKtt78iAKs9Mr0mA5ojXjO0LXLCwylz55Pmlak7fNN6dlgrvCvsIz1d7kTRsVc9tuB5LmAWqVRTOkcFtSPyjnDlsCTpv3J8qds+RkNmJJmYtyFjslByvyRs0cE2qnrYjKaW257J/GepjT8te8k/Zrvic7l0ZGXoem329z+tAEzsW1muBrSW+5EtqRAn8/cBL3NBaexNaJIfmtPocyjX52LByjHULaNF5HndmQJ+rMmPO26IVGd0mWeHqeJuDFFgC2WZ5xKFlZn37y+9XkWJLADmsdNjWu+VN3R5ZidKEMTdar98gl8UvlRb5rSGMt+dq5QPIq4tf+/hM8LtH+wJYD8lvF8r/OB13Tc8l58tLGnpEeYifV3rGLeGrY8mF9lAHLfgQ+FO9DQW/JqQJtuQh+E6wjv82ikXksZRfJ/xw8LG/3spJgB7dalUMxRF1VeqRXNMQrHWBRlqp6n4V3eze4kq6j3m/jTWv9kJi9AENDom5VWhI1f7Vel6Vm2hoD1BVtUWVZVl7uyQeCHFyKwnFlxc1EHux+dd5M9JdVTrJPzuPgNeloZPCVwxn1udS17bxC9eK+8zIcxndus/zftsx9aVXfg4qOmLTRbQzJCv7kJ0A6b2M+anTHNnY9AOSjRQEp2C8nveCgrMfxrkv5aBAgdkV87I4jB50bMP6ufzfneHK27BRQXfKbEo+gfAVlWy+0h1swsH86Bjw37wGaiCx4Etai98qpk2ezLPYV8dLhMv9aoHGdyW6hkFFMjtKUXfWvA1gDidH3N3Om9wwO9zzypWSDOiMq5ruGBTll94OqRQEILAhLxQ2IKtjJHQeq9kJlfmhawzXalkr71khVkZldEi9p/eYEBkU+R9Lo7fqqpAyey8IlQ4A1Vy52PCo3FevB9/mOpQb0o9xwCzc8oHXO8rZrHnMhjaz2nDipgMWLzbzv4WjqWsoDT2OkCtCZ7l9y6lqE6zGPhZl5oGO5Lgo5ETfrgiN/Li1YH4+KNC7P+OWHdDXnngXoBdB0OC7zCxYEsSGEPL+Z9h8euPjDbrZVH6V1mp8YRaPaZ6KsPinj7LvzcjMty3Dh1wTsTiWq99y5VfzuFrz7grNNUbHUSUOgKL74FcTmSLym/2ttSSxSpWQZfNrEBLh+2d/hWy/l6WieC9N4LTTks1kelmrFM7telhzk+RiUxLPwrIWDglWyAij0kiTFY4NLlduFBXp3+ExroGyO7DlOx/Th61FID0UjiAaRkOxrbVJ2PRNrMU3la6/M1no4gkFsSUB+Ke9GMq04Zi86u10btVQt8i+eFCIQz2K8BG13g+bt+2+xu/4wF596TBs+0HnCk3DSohm8Naz7/zwK0nzTzLFqedWrtcLak+DhpIHfRio3fKm9CVCw6zDyn5vuMZfJ/m94jkcWGuyDrGuc2BvqWDc6xoZDpcXO880+9xtuwfsZBMiUbdg2SeJZ9jUWcwulRFByUmdKmhXilj+CcuYP3+QrYJPeZD93ap3K5GfyfVaTpXnBMFtsYoGXdesea3ds/SEMlWaAQFd57t9CvTLhMg2FQykVavh8Musn+RpiffJL1hrYTzilF6aFL6Segpwr/3woVFb4WL/H5FnWw9bqxFyan8Ab4Kk7OLSF6/palez2kxQhPlAqrG3Rg2fDqM/p4pH3XmZEqojuR5Kf0rWHZ1ZOdgQk97zLa2zhLa4uyAzPRd+QICX0EhbYisE9DlVvYwb5dlggo4Go7v3Ke7BQvDRbT+rHei3S0rasFpbZfmrr7/3RjfWCxJQcvNYVVyKuWqB2E17o2fE3H+tFGx4AIX6yxPHc5GBfxhNuO+nvfYVoegxmNxJ6rBsL65lpdDthKEWmK3Oxj1XCoG7aD21qXtArO6g0Ek44wPHl5gi9FQv6Tnr1J9I9sJauzf+MbOAKH26vq0MVpcw0mP8oMDtBuoQ+VXwTp8h0Nxvzt7AsIuR0Ag5eVX/SvcMzE8/y6cMfn2/Dja0RREL+WC0YpfOSwr9kaYJ72Wq0swIrXCDnleKiNL7faLWVzldIyzV3zq5PD9d5iJ78udRUv12IJV1gin0na7mylAWjqWpvvjwubbRTIu4RW84ErnWRTEEGoetYbQQLwW/HOH4lF3bZ4pPxnQSiJP2QlGIamvikhIuddpovE3/0agPC+7bq+Zn8YdFXRj8Sh6eI/+wFKUbpDyxX7fy1Mb+LcQdkeES+A+Fw5jQ9xHdmJkh0i17wM2JOVorUILzjVO1VGev5amD4LMihNjCPNcaMFWlCar2qzppqRhzYo5otBYQf1lcZyxslJQwRf5+GgVuriXLHim0xUnZSD194UbF2q0KqmnWjG6vhal/0u3Sng/clhShppI1VZr7IdD73uxreRlbJ8oTZZYHLfg/mYz7lchu/5WM6p0sIkVP6ZeMT2O8dcj5HcJSpJaMAXn+4wuoQ4zPg9Q8Em4HKJvsoD1Tujw5sYqoFSt51AaY0CAVYWI+PFezAR1eUuX37RoCD0qiEhuCGeAfMWBX19ihu3Fsd1H3ec2wpz14jjPXrUY4oG7l6m/aHoy12Cm+m3+2uXnkRvhrteZr2lngGOKriUrmAdfHR+VpW3XGfFDpc58zKY4AcLe2yTqBzdS/Vgt5ZSpLhgnMo/5/LWmD31DeGN1YsGzHAmRaWGRRuraaFFBPUbJtaeEgjGsj5BTZZ66scv8nUJf50UHM73nU1Z8XdyC06p82TQmeWvkSoU6q/4pXrB8RpjKfePdgqAs6N3iZDVKygbTItM5bpFBtIf9i9udtISjD74ZB5T5mRgdpofVj7ZXm896a+K8kltkyJSWl62MF6PpIDfNJYHpGuPmPH1BonQrdwt6a4ukA7Eqv643PpJ85ybdWROX38gb6rSyy31M3mY+e0Of/MPJkWpuI3BByH9Wk5+1uj5vuT7vUbR6BwiBDv5WH3wUeHCuTKHIlSh9aJOgi/61g6Hyy1yq47SF0veLkWvu6II6dyWXaP33WCX6gc6sSwuQx//h+ieS/YDPdF57coXuC7zhl3h3jZzHUhezY6mmmOlmvTl6+aLkW2Ro786CHsxR9oNKBU3DIqJDlPune8aUHaZTMzhnqeJ97IvjvRYaaSw+CWBzElVTQes+OSy7d2Q0bhvtmXUOABaIUl0xFpO4w/7lmueVBZ7IORCUJ51Tq38azOPDLFj/3t9kvBPydBwXvdIBZkaF+erJu7icXhEFO5LnFJVB4qL0BCs4sFWJVYMorC6Rltf9IJx/QwE1IzYeYOLtfRIAN9Neu40+0kQStnH6DHkG9lB0SBh7X5N3/LKyLx+4vohAvc4OOnnMP+9/kWGp3a/8gv+NrhcsMDX6IAHwR7kKPOqqPuVZFLFryhZ6rIPf6IpSI2e7cNAc1n9CctkroDGeIZae4o83tjrGlY9cJbDwvyVnBgaFFwGzdipAE5nax/9Ix4UOE/BwTLdm6vaLtzIU/ZvSceK0MjtnXa9JI61sqdaSaHwLHFJvqLzYLhasgzwbfTtEU9vlsqGtv3yltzJYPNZL/rkzNUSjsf1UP9YbcDnlP1Qc04T8KeOoWLNKycq/pN3dgM7g3BjuWxkqR5JvrtZ5B2CP0141QTwjr8NdPncL7tuTASAfhmPXD8sutyqsWZHYiXrTBnbbd6/BuDp0Qzq/s8Xrx1JvmB7ZRvV4uLnzpBQMshDoFUy6W8VTX9LbHYsF7UMkON7rYNu9EklVr5V3s3onPqPwuIHI5Aqxnp+QCOZa8HisakdZlebPcqmKD5I9Fg/gU8+ymEpOnQleZ4Rf1ATRqb4wl0kFquRWpwEl6xB+sK7o3SMFPlMPkExaZabMrzsNjCZLhpH/EBbbFl33pcyAnos2UlKqFixH0V7D7FML1mWqRRAXiOCf6V1eCrL6bR76Uiv3O6xZTbYoTEyraXyoCb7P9inbn9RtTy6B2uT1Wf5FrXvPyYmNzertFsKKqp5AI14CJ/Z9Iug6GnBTuzM8/o8y9bpfnMjr08KaCaTQGPBDHoKCJ4QsxFaC025txlEPmE779lGnJeJiKuSMejkY9FNsFtZyk+AIJpT+FS4orQa7gmLis2cV7fvS98DTiEoHdwcHqc2m2w1dh25dr4o4uT2RtG1qntX+NWLBlR5VWYuqP1vtcR2DuUCmAcmaQtxQv5TvZ3ECAfYh9BsZztv9yiueeKIjtDa4HE7zdAyslVKuM0R7f2VyHs1V6q6S2h7OaL/ebCFZxdPd67Jeqr72AbJjNJrh/aWjaD23WsUUEi5JW1tPUa8uKM/IwmOXrMzsC2dWVyTLfONkdn5HvJUSuk/OgTfkCVJ0oA6hXBDBRX/iYy4F0B8jLU7ru8qqi8+0estOwxDP+j5A2iJRtEqb3L+dbqExynea6OMsi4ha/8pyK7E6hcj0UDln1xQa/ercfnaVfzZXeftYHe6lnwp1/CAoe13xLq6R/xR9lv5GRfGoWFNtFRmuqmDE8S4/JugXz4MLFsvaALTECJLXh26+jVEY4wpEFa06PUOdXWTCkK5dmposGK82bfgJufGz0vGO5M3o6Gd+5aTschhpJkl1cmgUj4pJtVOP9hl9c5AbaSluwZkJJk4ASokF+coV5tiIdkG0lBEO6CAoi09y7DTfzMzYwS6Efx1CnxK14KjAk18pnr8fFdo2k4eN5Y4fKqCLyx1f7QLBrCxei9ZKULxbt1lXPiTORiqL22QIfcG48v5wFvSgcs2GvWFw0zfZsHrUFbl5Y8E7XY9HCE+iNfsZ3eZel5tgIX8ahxIk1pGUlSpqvJ2km7UFLt7AoRINbSKwvZPU4yYXSxd3O0CcyfvRN/8WQFz5b/5KP1BUY+bi4shDfrjFw2MLN5hrvPYv/P4jqUMVlHP4mINBgRWXccUbyXw5I9IM7vlUDc9Bav3yz+I1rAZ+5S5m/PSmgBL5FUpv4LwSMmy0pjfeDYpDAakAZHTI1DaLicbJqb9Wg9/JspFaQWItxDjGaCxM6mL+NzXIh5ykVyQDRAz1OaL8dF5P1iEvz+t/PAqedQrFjb40bG4AgjnJmNMCQG1KrY6LLkZBZ2iDosBBVCsJYkfk32tNxs9PhDOz/tmTqHsIec5M0eOC8dfXr3Up3MgB3jB3A/imnuzr1YPELk541Vws1VYpL9NmLv3nkuBi+ZHpu6f8rl3ROQFobkuB+tQ66beYMp7s5DR6iL0Z+gF+2cO8eWLh63dlUdel+9g2ksGrNPV8X+8YUq920iFlDzfHM5Sr5F8ZTJVbz8XE5ubRBSOjt6X7OJW/2WnhzQ1Lb6eXZ5xWuYgMLz9DdWwzx86syNnQoEuKmF+3Fd3m+uwU3UVXVYfgxVS5CFaG5C1aawkLv49oKQ34aaCUl1sFQFMdvmcnk6V/SYDyWsyCBXB+wlc0E4jMJSHto5Bo57JDfSSPmwQFsulBmiH53H55gKb7cYeD+f+LADy0YMSXmB082ipRe6qmLKwyjlr6Viq9KGUjdL9/pYULmjPLRhF4tpkKKaG1TqMsFD+uchHWdXy/xVqpA55l7jste0hBOArMTstrltaQZ5HKav2jp2C8K+Xo3BD9LlAKH+XZ1iqDrT8a+jbnvdQHeEqbRy7inL+C331HDLG7g/azvAioShsyPGc/kglyneEE3/8nTehhhfGgqx0jMK3iCFRqJI4pTe5ZnVwF/rDTw6lArpwZ/7cxXnC5Qq58wJ1NNhxjqy25C7qEOFthjOBg+LyPkgJ4m3lmt0oF7XmJVNdHdn9XahUXK68yuxyOwGuVBSvC4i0sGd/VvbCE2+IWfIPlH2t6QmM+3eBqIvpJZUrbnN1gGXXgfxQWW60PK3RcupUDToqxvoO9EFDLMCmK6WfW7s134e5sF+KNtB2kFtwi+Ck9mdv0Y4qPyHQihwcO09hXW0wf1Kn619GIBb8hAdBAKad3Sq89r03CBdKoHhB7ylZEAsWX8tDIyoZTksVmgT1kedvtWsjbxvswNaOpPpmdxiMiU4TtEMp7XDRE7+DIUQtWBOQon/htDMP4ywxpY5s363626SRO+hyAK83WgjV+5tlVeVaBp/qjcF6RZhZj0mM0OiGrKxziFPisigiWYC2DG6dzhD6WjKX7+iLGvcxweyvT6QDRuve18hRLfCuHv0Sbf+YrVwtukF9fTz/xg/CjXefyK0T/yGv3hqxoEBARXs+syPi+t4wFV5YcPHqTs8MRUtM9M4Vioaf5pPVnVSp2htDfSwxSejPzNvlRoaRwO6HTZT6EntC99TwJkcwdDfCkk3vgL5SAhhEWqQWz0F3+iVpNapOjU2sjfZuNocV00MkYblKv7kBhG26oq72zEm2S0PpBpyYYPfmqNXYROqdKpuREr4f5JzLNBD6kjuOkXnjMoDXqmblYFDXoXbhTIr3RE+TZB7WOnUeh+Edk/sZ2WaZLfCsW7KM/RRHPdRxUekj2RGo1mJChBmoxhCNJlXbqGqk3LMq7pVXCY9jsIiEUafSp8HC6wRZ0KkxuUyLC7vWNz1/6x/AA31Ez60g6IqjECqnb6cO1Flc6nRlBCRnlw+OORKpHmLrZcwWsBWe80iQ+bL0GpT0XB2vhFUEsDzUnfPp428RxpVDtfWT8LtIE2kEwVHaX4kjx2fPNxalFjx+AddLhzPupLml8OBY+3d2MJ10DYHhPFkxK+Brm/M1xQEysx7WJolX55qDJWfc5n2Wa9v73l0s4PM4oQV588FTwPY1wulbQ2vq1g/1FSbwiD0QwOlFI5o9XRBx9iL09DQBzr+7Xw3fo//2Yuz3aTHwZyon9w8pQPtoFiZX06PMALqiLdE+7oQc3UbLvS/xyKUdIP7NUeZJXfQSnAKOfZlYuVzO24Y6I3kVS8H8uixn/eT9xw/d6jKrxrEsSytjFBglcFxTQhuIjqS0W0EzDu9YFiMOayO6/A1n+HBrlVumPiozkmUeokdZNgNTtWVJvlzHzOFYbTxQd3GFq0dXMLdma1F2laTX9JTlL6zQFEhfQstiUxnLc36vCUVA/letrI3xfbRldHJuojEEXH8mjm8ZU06tH73E5y9V0i4oy7k8ySnorg0J/7LcTHY90k2oL0Z/EwDQ9Tei4wmRfNcqCM6TGRfCLmgLq9QMijH1t+io0ep4p7q9iCfhyo08wekFvXgrRRuNJ6prkb010Ogw+R1slN1nJX6uvQGWL3E+dbSKdpHWjut8amcAu3zPX75TrZ7rCRMLIxZMCC5brzbSstQUtWArdM41eLWvN5zLZI7RgYJT8iGtEMbtLTf6qlJGTXk/xPtdIoaNgUaHTg5AqiNInYQDD0a9l/PxofjRFw5RSsttmOhITXNyCtVagvk0tWNzGgCSYSy/W0EmHZkyX64eYBrhOdE1b8F09RGjcJt9PTFwywhhhcooKyak0pe5KqF6wK4Rlol1GmFkX6kGpkPsXCUttwfNqM+kvYcEb8xbRW6PMoO3a1b/zQwvWp2G62V7Q6AJq7xQzOMZzIZMWLOMJimOs1Ad/ZZUxfXuTu0nnujTgKaxFY3w7hTF83E86GFvEAYsOU0NRo9Qi0a4MFUZQjyy4gtY05ESpRpk5kROF+PSMn6g/VC2Ykm9s9kyjNJT65pEbNGjSaHwbPUGrTSRLxX2wJXBeas6PmNRK5Z8RCcFW1Q0ZsTDos4qiDti44eNSw0yxqXpuwVoK/jIk/9/owqiSj/qav40RITuhEcRPZwQEcq+81ZXytO3w8y5udEF14pQMck2nmKlZnqIv5SFGOpP8XZVbpbP7JSuTv4nsr6kBdfoRHe7jXs/ItIXj/OgjFrnV5z7UO8TDGemxBWfhEvtWUtJMV7eULJjD+ZAQ2i82RvCiTB9QuaKHsKmHwnEW6d9YID6YPWSB1nq1srsnIJDbHRg05jo0mLMnLQejPEpx9crw/yxOr1MLPkrzWPXJPLc62Li9d+ic6Grem514Uxm6epYT3So/vTbk7X8Rdqkry5UYdd3Cbi2lxdFPp7Pyw/3GENMsREuLGv/G/QdKiepSg4nob5YWS/YVla+L8CjH+nBOEY1zdEbH98iDa8SppCpHOJvt9gJvwRpItyjH0MTGuznVx8Tr2DNCsu9BGlwNMQuWy6weokV2t5PAophOdNEipWb8tn7wOM9HIxXDRfJBsOC4zHI816E+5qIWnFKT2laSGn5XoAw0Lm//7j3+wH9PXnwmnMO/3y7rTUaw/6X3E/HuasExVQ7jLYUulsjDiuDCPs2SIw+M3uUKtEeaQ6asiwOLWnDDqo+US20bqHsHRwX4xSvMrKtNeo2HmqgRP2omFlTIwOo0V0rThB0hcKVf0oLjigXDEdlQZB8z4fHYyO3tlkBEJXU/1OFri/cU34MpWxdZVvIS+jNn+z8MkkGvTOILb2b5yB9JIiOr95jTjec7oqcx+wxejjdYxjJGivS00FCYSrhun1AqmhSJyLrz3S+IgHK1njirV6SOU+q0CaE1vVzF+tNd/g+xHRbBedABQyZIx7sgZ7dfAVxAZl7RpzMaFv3wUn9OE4X7Up8Y3psMWAHIzQcrOSF5Z9Wct6wQQ3mQBxW478lEibez9bZ/geunEU0spF04vngPVG6sfyRxiJljQ5K/O5qjZRm3NCGelYzA39X5e1DF4gs/5ZEjsKbAN2BtH4ckuiPS9YvQ+lJItox608uGXfgAf+aC1+P4kyR8JUYkAUoLXeHWkAQoa+zOf4sGLDZPr67gAUbqODQcvLKOml1bXNshnQayNB6bgfFUidD6JCgwktog9GpeOek5l5gimSL71pi0m/Cn8MhoiepVLolPdf5Mpk4Wn4jZkIZAERw87TGXbwtOb0/6zZXjpNgDDT7bUP3P4UUsOE44nxJe3G4aJmflVOO5XrNPAksdBBc90lfHx7er/LqHFqwI7Z0gcPV0ecB9Lwuup+Op73GxMEW0Qlc8ql/iIoMSW6HHDFTkhowP1zu4nVXu+ru/0styOQFAFwbx/sfi2fbNBId/gcX0kafrbA5H3llxlmGl49sjsx6PhrHxMPqsg0znoFPKcFV+bnMHvYr5pkLSQMLWGOoBuaU2aYpM9WeD9CRkzix6UHqOM6VE/xOXF0OgAblBi0ej7TL55OyO21x5C74DaP8a3meuL1lssWlufP155tfso/mTke7RklM5C94mTvQhRl60UDS+Ni8BU47TnUAD7qGWNB/mXEGsZ6tU2QZKxn9E7iQTeoTfmHR22bif1ByfCSd73wJR9lanH5lfOCMkvizv9TNxduKyAhZso5VX1Mi0v6tCWeMzqANfy8Vf5FHitKH0B8arpy3Y1uzUXCojiBFazmGxDCN25VDDf5JfCRGASoYGZSAd5RORViMDpVN6yIX9SKUTqmjJqfZcLdgCOV6O0+nT4Wg7xTUbf06VAtaL3OoSl7LgLLn33H6Q5a7ALvIkeUAr/Laa1hHZoxaLtOfE7kdZivouukNQRXGBdd/bgjNFL6An4s9EIhx9NyQuj5DuaSftv5kQ3XSKz83hMJQ6uqqdfg/qjYwq2uGUbpTiFR6kDPd2SDJOpPIfxfmDNqT/Nj70Vg/dT8OA+WEQgyvQx5zZOtwqdLkqoXhEFyT03IKdjlREnyNVSMtAqruXA3PUJu4LWdTKi28freiGL0la0ibfg8p9xv3b/aiD4i0cmWUQo4lAKxJ9vFzp8Qb9NsqOd3xVOxIK+NPd9YUsuCguYnuyZTueatEqas53ulIoawFHUStPQ52HAYpbRgpwh2zQOS2eNQbhftLlus/oYrZWp4tXUkPw/py31/QRDqSaPIM5JO/8cRqIPt8FTYk7+VoPpItBxS0YQzxkms3NXjfAMVfRrtQeyhrjzRiCup5bsPowDTuuYwfK0/Lib7Pw/mUl9wHa5CO1FsbYWRcZ99tm7iEm/c0hp7rY5bz5NkNWviSSigir3+gHnNtpC06Djx4sHvUhUySAz9Xj8oX2RRNerRHYQmVYy43Nv4lBI5qSHyGCExLcGXpJITonFGejc+Sf0AT9fQOfDqtAcumuvAdnZzlP2eh0SFZ6H2JUn3b2YDCBrtjQ5eWRcv76yJyGrnfQI0r1cfWU8hg9Hrl+Zbx3uTBMzQuKI/JYwaD96AhBsWP9ejcnJgoP5GzsOvc/R1/n5NSmROx4b/FqOeqlStkef43qVipWh3C3uetUXoCdfNrn6H8BxVGktnCf/CvXu2hPYg3IqTM+waXkEv1rOdCJ7eQap0nHD8B8TMhP5TZw3oVFmmnLCIzL0kQ+poWPNfaSjLIl8gtynstAfMBCuPpXFaCl1oIBuwudQ7B3Qc5TuQhsymHjgGe46J92pVmd1IZDqj3fPtsF6a9JmInKbC23nx3SKvoefv6CnEeikXAbSeoLIe6iNladQZ8ll+0wMOYLcr6Imu8sGSFQevEhF819n3MGgwHj4YKcR7JLhlg5O1KW+pzKNPnRFshSIxTJjOe+IOeN6N4yoB6OmGtPuN9LpcI0dFUBLV+Q80nuNRioI+UWHjQoaEh0G3NdL8j5JTWmpGnX8arMknXhVk8xGe+CnF9SA2vokBQ/FXe4Lotu/VjqcV/LQurfBTkfZRzMg0vpvfzY5QOeq8O+7FDBlWn2fEHOI5ne3V33ndorYDkoFHlMWAHXAtYjNEdHar+WA+CCnEcyRXC/qnYzj6J2E7rjfPPBF2RB2H/VKlV1znZeKXUZ3Qzu94KcdzIbDNTnNDu/BfL/gIs2BPsB2uoy7uNc/C2R9h46UedND/GC/H/Z+dV1BMjijgAAAABJRU5ErkJggg=="; + +string __red_pill_image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAIsUlEQVR4Ae3d/29ddR3H8Xv6ZVvazs4C2Ro1G0EX2RzGkQgJigP9QTSUqb8sWVKjCQqaKCGpASWZzi1CMAG3KBolJfEHg4jBCNHhUMMUMTPYL260a0tpu663a9fvu12/3B6fP5xPcnPb7dPz5d7POZ/z/uHxB8Dr+WnOOffu3IzruikmbP8PFBKAkACEBCAkACEBCAlASABCAhASgJAAhAQgAVQ45VSBD+AefAOP4/v4Lr6Mu1EPB5mgVjx5LHuWCixiwXMF856c5zLmMIsZzzSmMIkJzyWMYwwXMYosRjwXMIzzGMIgBvAu+vGOp89xMr3owTlPl+dtnPWc8fzP01Gg3dPmU6kHb8AX8TT+gjEsw72GRfThFTyG21CVnAAkgG14EG9iCW4ERvAM7oATzwAkgL1oxRW4JdSFh7EpHgFIALvwEpbhltEUWrDBTAASwPX4hTrxBp3DveUNQAK4D8NwY+QEdkkApQ2gEkeQhxtDSzjG+A3RByABbMbLcONsBRhHCwHUSADRBFCJV5MxPpAHehn/znABSADV+DXcuCscX2H8PFoZvtF/ABKAg6eSND4KxwfA8DN4BBslgPUH8DW4CT79avxCvQSwXwLQB3AX5iw5/QAWPYx/Eh+RANYefyuGLTv9BeMDjL+EVsbfDgmgwCtw7T39KgCA8XM4zPi1SH0An0vX+EAOGMJBAnDSGkAF2lIbAC4DJwlgexoDaErz+CqAOWCWAL7H+JvSEoCDf1hz4acJYF5Za3zMehj/HTQTQKXtAdwmf/oLAsCMZxpoJ4C7bA7gWctOv358/elneGAKk8CLjH+jbQHUYgLuanL6pzyTmADmcZQA6mwJYL9c+BWMf/XTz/jAJWCYAJoJwEl6AM/Yf+GnP/2zutNfFMC4hwDeJIDbkxzAWT9DyOkvGB8XgTwBtBLADUkLYBvyabnty/k6/QXjawIY9RDAOON/E1VJCeA+ufALe/oLAsAI0EkAn0lCAIfltg/rHB9qfFxlfFzAMPASAdwU4wD0X/SU2z796c961PgqgPPAFQJ4nAA2xzGA/9g6vvnTz/gY8hDACAF8hQAq4hTAgPW3fdrxw5/+kauefjU+MAACOEMATXEJIBt6LLnw059+NT76PYz/KnabDmAs3Rd+KMmffhSPXxwA+vhaGgEcJ4AGUwF0asaQ0x/gwk9/+oE+MD6cUQL4kokA/iqnvzQXfvrTD4fxPT1g/D/iQ+UM4HiaTv9sOW771PjrPf3oUQEAC4z/UzSWI4AHNaPI8/7oTr9+fHSjC5ghgEcZf2MpA/hgup/3h7/tG9affv2f/uLx8baH8fvwhVIF4OCinP4At30BLvx0p79rzQAAxn8Ne0rxcfBvrDr95m/7wPiRnH41PsDwy/gZrosygK+m7nm/ods+/ekvHr84AKDTcSYY/luojiKAm4yNb+DTPpO3fb3hTj+ATnQA57AvXADAafN/+hP7aR/jQ3vhF9HpR0cBhp/Do6gKE8DD8iXPwvFLf9sX9PR3rA5A+TOjvjdoAPWYScOnfZPBT3+5bvv0f/qLx0cb0I2b/QcAHINbQJ73a05/1Ld9Z32c/vbVAShZ3BokgPcjF+fn/Yjn837zp7/YOD7mLwDgCbjhyfP+0Ld9wcdXRnGj3wDqMShf84rXhV+gAIDTqFl/AMA9ibvtM/A1r6AXftCMj2jGV1r9BBDgn4vJp339Jm770LZ++/0GsAGvJ+WlDuZPv/kLP40stq0/AKARg2n9kueFuN/2+dfqLwBgD0bhBpem5/3mT7/GLf4CAHYjm/J/3aMCMH/bF84L/gMAdqJbnvfH/rZPJ48d/gMAbsAJS17qkNzn/eE9GSwAwMEPkLP9a16RXfgZuO3TyIYJQNmHQSte6oCR9Jx+5dPhAgA24RHMJPNrXijLhR+CXPiVNoAjUQSgNOI55OW2L/anX/lXlAEoH8cbBk6/uU/7HMO3fcEtY0uU4ysOwx/EkHzaZ/7CT+OT0QeAFaCW8X+IXPjbPnneXyIPlS4A5IEdjP8clix5qUP8nvcH95PSB4BlYA/Dn7TjpQ4WnH7ghfIFgCWgmfEnjX3JM2W3fRp/L38AYPytDP8s8qU9/XLbp/FfMwFgAbiV8U/JlzwNjA+0mQ0AjO8w/AEMWPJSh2ScfuAt8wFgHqhh+BaMx/6lDjaMD7wWnwCQAxoY/xjjL1nyUgcUjR+fAH4fxwDUL3fuZvwT5l/qYOnpB56IcwDqlzub0GPBSx3iNT7w9fgHAGwggBbGnzbxvD+q098RvwA+lZQA1C93vo/xf2vJSx1Mj7+ILUkLQP1y5z60W/JSB1MB/BuZZAYAVDL+A4w/Jl/yDORI0gNQv9y5hfGfYvjFRL7UwYwV7LUlAPXLnR9m/D9BnvfrtSNjVwAYBT5PAN3yvP+aHrI3ABBANQE8wPjD8rx/lUu4zvYA1C931jH+Ucafj9VLHcw6ikxaAlC/3LmT8d+IzUsdzJlHY/oCAONXMP79GE3lbR/wI2TSGoD65c56xv8xwy+U+7avzaxBbJYA8C4YfydeTsnpn8VHkVEkAA8B3EkA/7T8tu/byKxFAgABOIx/kOGHLDz9z8O5dgASgPrlzlocZvycJeOfRt263xQqAQAEsJ3hn8dKgm/7erA1yLuCJQB0AZ9l+KEEnv4R7EBGAggTABj/PTjE+NMG/nVPEOdxCzKRBCABAIy/leF/hXyMT//r2IZM1AFIADgD7GX4UzEbfxlPYiMypQxAAgDjOzjA6AMxCKAdn1CDSgBlCQBg9BocwmUD4/ejGVXISABmAlCuZ/jHkC1DAB24H5vUiBKA6QDQDlTyP/VevIjZCEefxC9xNyrVeHELQAJAGzw1aMJxvIWcjy9sDuJvOIQ7UI2MkowAJIBidbgd38HP8Qec8ob+HZ7GAewKcsqDB+C66SUkAMtJAEICEBKAkACEBCAkACEBCAlASABCAhASgPg/csK8SMv+MG0AAAAASUVORK5CYII="; + +string __blue_pill_image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAJMElEQVR4AezStw3CABRF0Q+9gwdgGTqmoGcEKiowOWOgJuecmc0861uip6CAV5wBrnTF9/0/Rr8dSByAOABxAOIAxAGIAxAHIA5AHIA4AHEAEqf//KYoxCABKXAhA2lIQhwsiIB8rPd4695DN3E8ZXtXsTuBi2qfVesUOordPKjGXqxAfadqW1XdiFVZw0qVl2KWFqo4V4UZTMXMT5Q7FjM3EiOQHcJAjFd79/9b1V3Hcfxc2kLT3q7ItkCjCSxToiAzssQtmU6m/uCXjKH+QkJCosl0i4kuSzBbnMNBiSNz2dZGUaGU0iWsTth0NI4vc2bonMHM4aKRfdFQJBTBfSmzbLR3x+e56Ttt8jHXcz89537O55z3D49/gNfz05zPvZd7t0QGg47u3cDmAWDTrqAcuacfO4Py9yJ9wMbIjqB89/Zp3/2plbQHX4Av4UEcwllMIqzhIl7FMO7CNWj2JwANYBFuxXOYQJiA09iG61DSALIZwEr0422EKfobbkerBpCNAJbhcfnT3kBvYAPmagBuArgMP5ET79BLuLGxAWgAN+EUwgw5gGXpBqABNKEbFYQZNIEehl+gASQfQAf2I8wyRo+cwwa0aQDJBNCEg56MP9MrjH+9BjC7AFowiNC/AA6FjF9BPwF0aQD1B1DCA16OD4aHODjG+HdgXvwANICvIfT49Mv4wLaqVwhgjQbw/wO4AW/5Pz5kfDB+FQEcZvwPQwP4HxbiVG5Ovzk+noxMoJ/xF0MDgBj2e/x4AQjGH8cmxm9H4QP4vLfjw2J8AIx/EusIoFTUAObghYKdfhkfYvgw4y8uYgCrizi+EUDvMPafx3cIoLUoAZTw25xd+4wAYowvAYTzeyJP/J0A1jN+U94DuEZPvzF+2Bl5KPLLY7ghzwH0+RtAon/6ZwYg41cxfGQvrshbAO14raAPfrVPv4wvAYDxL2ALAZTzEsCaAlz74p9+Gd88/RIAHgsJ4BTjr0fJ9wC2FeDBL6nTX8X4U/aFnffve44ArvU5gL/WOYaefhkfjB9ecv/eCuP343LfAliESjGufRann9Frn34QAMOLc4z/DTT7EsBNCPXBr/bpZ/gap386AIYXLxLAZ3wIYBNC6LWvzj/9xumHBMD4GIo8zvhXZjkA84Oeeu2zP/0yvgSwNfLI27iXADqyGMAfcze+xenvtDj95vjG6Y/GB+6N7DlNAF8hgDlZCuBE4a59vbO99tV1+mX8KgIICeAvBLA6KwGM6uv99g9+sU+/jA/Gn/LwQQJY7jqAs4V/8EPtP/0i9oOfnH5zfEgAjB+ZIIBexl/gKoAXode+hB/8Ypx+xp/SPYjdZ/BlFwH82tnQevoxKAGEHZsjA0/gA40MoFevfTEe/KxO/564p39mAJF3COCHBNDViABu1df7U7r2Gac/xvhg/CoCGCOAOwlgXpoBvL/wr/dbnP4Yf/qBGH/6YY4Pxp+y81UC+GJaAZTwL6vB9PV+iwe/GKffDCAkAPQ9hRVJBxDZ48ODnxlAhh/80JHM6Zfxqxh/Ej8igEuTDOCrFqPp6/3Jn35zfDMA7AjLd+94jeG/iZYkArjS/fjZfLdPxhd2D36YOT5i/+k3x5cAsD3yElbNJgBxNO2x9fQP1nH6ZXwzABlfMORbuBPNswngdr321RgfyV/7bE//diEBiCfxHtsAOjFWgHf7YnzMy/W1zxy/xukX4jg+ZBNApCfRgfXdPovTvzP+6TfHF6O42iaA92HcblR9vR9xX+9P/vSbzuGj9QQgtuqDXwqv9yf/4BfHGVxRbwCdGPH/wQ8evN5vce2LG4A4ira4AYjP6bt98T/mFf/aNyBqjZ/A6Tf01xOA2OZgfH/f7WN4B9e+eqypN4C5eMaLd/vcf8jTDCDla5+FUSyKG4DowkhRr30M78u1L67+egIQK3CmwP+7x/5jXg4e/GK4qp4AxHKMItRrHxxe+xLwqE0AkaU4HmNwfb0/m6dfVLDEJoDI5Tjg8Zc62L/eD/ev9yfmPpsARAn3YDwT174e+9Pv/7XP2qhFAIZVGPH8Sx18fLcvKZ+2CMDQijswpv+7x/ba52B8oDuJAEQXdqFSgGuf76df/D7JAMTH8GzO3u1z9TGvtE1ifpLjixKjr8NJ/7/Uwf3HvFL2ieQDAMNH2rGZAMbtr336en/KbksxAHFoCePvwkQir/ejoB/zSsNDjQhAfr51BcMfdvkxL33wMzzauADA+JH1jP+6Xvucji9+0/gAwPgLGb+P0Sv+f6mDl6df/MlVAPLLnVfjiP9f6uD+2mfpBdcBREoMvxYnYr3bpx/yTNLz7gMAw0faGH0Dzjn6UocCXPsMT2UnADB8ZAF6GH8iJ1/qAGP8rASwL3MBCAJYTgAHPPhSBx9Pv9ia5QDklztXM/7L+jGvVHzdhwACApjL8BvwZuO+1OFh8/R79np/DJ/0IwAwfuS9DP+znHypg2sXMd+vAMD4kVWMf8zphzz9P/1/QOBnACCAJgK4hQDO+v+lDk50+x4AHgsIYD4BPMD4F/Xdvtjexcq8BCC/3PlBhv+VvtsXyzEEeQtAfrnzCwx/XF/vr+m2/AYAxm/BLYx/Sl/vN/wbl+Y9gCoCKDP+Fk7/BQ+/1CEtWxAUJQAMBQSwlACedf+/e5y7gK4iBoBH5jD+zThTnHf7DN9HUNQA5Jc7Oxn/Bwz/TkGufWIEHRrA9C93LsV+F1/q4MB5fATBNA2givGvx+9qnn7/r33fMsfXACSASIkA1jH+yRye/iGUNIBaAYAAsLudADYx/nhOHvyOohz/m0I1gIAAMLCY8YfwrsfXvpexEEH9AWgA8sudn2X4kx6e/tNYgmA2AWgAYPxLsJEA3vTkwe+fuApBMgFoAFWMv5Dhd6CS4dP/DBYhSD4ADQB9kZWMfyRj40/iPsxDoAGkGQAIoEQAaxn9RAYCOIaPy6AaQGMCkF/ubMNG/MfB8P/AejQj0ADcBCAu4x/zLowiTNmfcTNaZUQNwH0A8g/ahBuxF+cTHP11bMen0CTjZS8ADWCmNqxGL57HeB0f2BzB09iI69CCQHgRgAZgKONafBs/xi9wBE/j53gQa7FMTnkjBGEYFpfKeQBKA1AagNIAlAagNAClASgNQGkASgNQGoDSANR/AWJ2EQGXgXEIAAAAAElFTkSuQmCC"; +//This file isn't used in guide at all, currently, but I'd thought I'd release it anyways. +//Classifies locations on whether they are adventure.php. Useful for scripts that need that information. Relevant for arrowing monsters, KOLHS, wandering monsters, semi-rare, etc. + + +static +{ + int [location] __adventure_php_locations; + void initialiseAdventurePHPLocations() + { + //Two methods: + //Look up every snarfblat, and assign ones that have locations. (this is faster) + //Load adventures.txt, find every adventure= entry, save those. (slower, but more accurate if they ever go past 1000 snarfblat) + //Using the first method, because our parsing of adventures.txt isn't perfect, and it'll take a few years before we go over snarfblat=1000 + if (true) + { + //0.985093583 total, 0.663535898 net, 1000 invocations + for i from 1 to 1000 //FIXME update this in a few years, we're nearing 500 or so right now + { + location l = i.to_location(); + if (l != $location[none]) + __adventure_php_locations[l] = i; + } + } + else + { + //2.571006588 total, 0.791600414 net, 1000 invocations + //Read from adventures.txt: + //This doesn't accurately read the file. No idea how to use file_to_map here. + string [string,string] adventures_txt; + file_to_map("data/adventures.txt", adventures_txt); + //print_html("adventures_txt = " + adventures_txt.to_json()); + foreach key in adventures_txt + { + foreach key2 in adventures_txt[key] + { + if (key2.contains_text("adventure=")) + { + int snarfblat = key2.replace_string("adventure=", "").to_int_silent(); + + location l = snarfblat.to_location(); + if (l != $location[none]) + __adventure_php_locations[l] = snarfblat; + } + //print_html("found (" + key + ")(" + key2 + ") \"" + adventures_txt[key][key2] + "\""); + } + } + } + } + initialiseAdventurePHPLocations(); +} + +boolean locationVisitsAdventurePHP(location l) +{ + if (l.to_url().contains_text("adventure.php")) + return true; + if (__adventure_php_locations contains l) + return true; + return false; +} + +boolean locationAllowsWanderingMonsters(location l) +{ + if ($locations[The Shore\, Inc. Travel Agency,Noob Cave,The Dire Warren] contains l) + return false; + if ($locations[The Daily Dungeon,An Overgrown Shrine (Northwest),An Overgrown Shrine (Southwest),An Overgrown Shrine (Northeast),An Overgrown Shrine (Southeast),A Massive Ziggurat] contains l) //warning: I have not personally verified these + return false; + if (l == $location[The X-32-F Combat Training Snowman]) + return false; + if ($locations[Gingerbread Industrial Zone,Gingerbread Train Station,Gingerbread Sewers,Gingerbread Upscale Retail District] contains l && l != $location[none]) + return false; + return l.locationVisitsAdventurePHP(); +} + +int snarfblatForLocation(location l) +{ + if (__adventure_php_locations contains l) + return __adventure_php_locations[l]; + return -1; +} + + +Record Counter +{ + string name; + string location_id; //number or * + string mafia_informed_type; //"wander" seen + string [int] mafia_gifs; + int [int] exact_turns; //sorted order + int range_start_turn; + int range_end_turn; + boolean found_start_turn_range; + boolean found_end_turn_range; + + boolean initialised; + boolean waiting_for_adventure_php; +}; + +Counter CounterMake() +{ + Counter c; + c.range_start_turn = -1; + c.range_end_turn = -1; + c.initialised = true; + + return c; +} + +//If false, use exact_turns. If true, range_start_turn/range_end_turn. (this isn't ideal, sorry) +boolean CounterIsRange(Counter c) +{ + if (!c.initialised) + return false; + //if (c.range_start_turn < 0 && c.range_end_turn < 0) //seems to be an errornous test when we go past our window + //return false; + if (c.exact_turns.count() == 0 && (c.found_start_turn_range || c.found_end_turn_range)) + return true; + return false; +} + +int CounterGetNextExactTurn(Counter c) +{ + if (!c.initialised) + return -1; + if (c.CounterIsRange()) + return -1; + if (c.exact_turns.count() == 0) + return -1; + return c.exact_turns[0]; +} + +boolean CounterIsExact(Counter c) +{ + return c.CounterGetNextExactTurn() > 0; +} + +boolean CounterMayHitNextTurn(Counter c) +{ + //FIXME use CounterMayHitInXTurns to implement this once we're sure it works + if (!c.initialised) + return false; + if (c.exact_turns.count() > 0) + { + foreach key, turn in c.exact_turns + { + if (turn == 0) + return true; + } + return false; + } + else if (!c.found_start_turn_range && !c.found_end_turn_range) + { + return false; + } + //turn range: + else if (c.found_start_turn_range) + { + if (c.range_start_turn <= 0) + return true; + else + return false; + } + else if (c.found_end_turn_range) + return true; //maaaybe? + return false; +} + +boolean CounterMayHitInXTurns(Counter c, int turns_limit) +{ + if (!c.initialised) + return false; + if (c.exact_turns.count() > 0) + { + foreach key, turn in c.exact_turns + { + if (turn <= turns_limit) + return true; + } + return false; + } + else if (!c.found_start_turn_range && !c.found_end_turn_range) + { + return false; + } + //turn range: + else if (c.found_start_turn_range) + { + if (c.range_start_turn <= turns_limit && c.range_end_turn >= 0) + return true; + else + return false; + } + else if (c.found_end_turn_range && c.range_end_turn >= 0) + { + return true; //maaaybe? + } + return false; +} + +Vec2i CounterGetWindowRange(Counter c) //x is min, y is max +{ + if (!c.CounterIsRange()) + return Vec2iMake(-1, -1); + return Vec2iMake(c.range_start_turn, c.range_end_turn); +} + +//DOES NOT HANDLE COUNTER RANGES: +boolean CounterWillHitExactlyInTurnRange(Counter c, int start_turn_range, int end_turn_range) +{ + if (!c.initialised) + return false; + + Vec2i turn_range = Vec2iMake(start_turn_range, end_turn_range); + + foreach key in c.exact_turns + { + int turn = c.exact_turns[key]; + if (turn_range.Vec2iValueInRange(turn)) + return true; + } + return false; +} + +boolean CounterWillHitNextTurn(Counter c) +{ + if (c.name == "Holiday Monster") //mafia's tracking of these breaks, so, don't rely on it. thinking of El Dia de Los Muertos Borrachos specifically + return false; + if (c.CounterIsRange()) + { + Vec2i range = c.CounterGetWindowRange(); + if (c.name == "Semi-rare" && range.y <= 0) + return false; //there's probably a lot of other ones where being negative means it won't happen + if (range.y <= 0) + return true; + } + if (c.CounterWillHitExactlyInTurnRange(0, 0)) + return true; + return false; +} + + +boolean CounterExists(Counter c) +{ + if (!c.initialised) + return false; + if (c.CounterIsRange()) + return true; + if (c.exact_turns.count() > 0) + return true; + return false; +} + +buffer CounterDescription(Counter c) +{ + if (!c.initialised) + { + return "Uninitialised".to_buffer(); + } + buffer description; + description.append(c.name); + if (!c.CounterExists()) + description.append(" (invalid)"); + if (c.location_id != "") + { + description.append(" (location "); + description.append(c.location_id); + description.append(")"); + } + if (c.mafia_gifs.count() > 0) + { + description.append(" (gif "); + description.append(c.mafia_gifs.listJoinComponents(", ", "and")); + description.append(")"); + } + description.append(" in "); + if (c.CounterIsRange()) + { + description.append("["); + description.append(c.range_start_turn); + description.append(", "); + description.append(c.range_end_turn); + description.append("]"); + } + else + { + description.append(c.exact_turns.listJoinComponents(", ", "or")); + } + description.append(" turns"); + return description; +} + + +void CountersParseProperty(string property_name, Counter [string] counters, boolean are_temp_counters) +{ + foreach key in counters + { + remove counters[key]; + } + + string counter_string = get_property(property_name); + /*_tempRelayCounters uses | as a separator, relayCounters does not: +> get _tempRelayCounters + +15:Romantic Monster window begin loc=*:lparen.gif|25:Romantic Monster window end loc=* type=wander:rparen.gif|7:Digitize Monster loc=* type=wander:watch.gif|7:Digitize Monster loc=* type=wander:watch.gif|7:Digitize Monster loc=* type=wander:watch.gif| + +> get relayCounters + +70:Semirare window begin:lparen.gif:80:Semirare window end loc=*:rparen.gif + */ + string [int] counter_split = split_string(counter_string.replace_string("|", ":"), ":"); //FIXME | properly + //print_html("counter_split = " + counter_split.to_json()); + //Parse counters: + for i from 0 to (counter_split.count() - 1) by 3 + { + if (i + 3 > counter_split.count()) + break; + if (counter_split[i].length() == 0) + continue; + int turn_number = to_int_silent(counter_split[i]); + if (are_temp_counters) + turn_number += my_turncount(); + int turns_until_counter = turn_number - my_turncount(); + string counter_name_raw = counter_split[i + 1]; + string counter_gif = counter_split[i + 2]; + string location_id; + string type; + string intermediate_name = counter_name_raw; + //print_html("intermediate_name = " + intermediate_name + ", turn_number = " + turn_number + ", turns_until_counter = " + turns_until_counter); + + //Parse loc, remove it from intermediate name: + //loc=* type=wander + + string [string] set_properties; + + string [int][int] properties_found = intermediate_name.group_string(" ([^= ]*)=([^ ]*)"); + //print_html("intermediate_name = " + intermediate_name + " properties_found = " + properties_found.to_json()); + + foreach key in properties_found + { + string entire_match = properties_found[key][0]; + set_properties[properties_found[key][1]] = properties_found[key][2]; + intermediate_name = intermediate_name.replace_string(entire_match, ""); + } + if (set_properties contains "loc") + location_id = set_properties["loc"]; + if (set_properties contains "type") + type = set_properties["type"]; + + /*string [int][int] location_match = group_string(intermediate_name, " loc=([0-9*]*)"); + if (location_match.count() > 0) + { + location_id = location_match[0][1]; + string end_string = " loc=" + location_id; + if (intermediate_name.stringHasSuffix(end_string)) + { + int clip_pos = intermediate_name.length() - end_string.length(); + if (clip_pos > 0) + intermediate_name = intermediate_name.substring(0, clip_pos); + else + intermediate_name = ""; + } + }*/ + + boolean is_window_start = false; + boolean is_window_end = false; + //Convert intermediate name to our internal representation: + if (intermediate_name.contains_text("window begin")) + { + //generic window + intermediate_name = intermediate_name.substring(0, intermediate_name.index_of(" window begin")); + is_window_start = true; + } + else if (intermediate_name.contains_text("window end")) + { + //generic window + intermediate_name = intermediate_name.substring(0, intermediate_name.index_of(" window end")); + is_window_end = true; + } + + + string final_name = intermediate_name; + final_name = final_name.entity_encode(); + + //Now create and edit our counter: + + Counter c = CounterMake(); + if (counters contains final_name) + c = counters[final_name]; + if (are_temp_counters) + c.waiting_for_adventure_php = true; + + c.name = final_name; + boolean should_add_gif = true; + if (c.mafia_gifs.count() > 0) + { + foreach key in c.mafia_gifs + { + if (c.mafia_gifs[key] == counter_gif) + should_add_gif = false; + } + } + if (should_add_gif) + c.mafia_gifs.listAppend(counter_gif); + c.location_id = location_id; + c.mafia_informed_type = type; + + if (is_window_start) + { + c.range_start_turn = turns_until_counter; + if (!c.found_end_turn_range) //haven't found an end turn range - implicitly set it to the start + c.range_end_turn = turns_until_counter; + c.found_start_turn_range = true; + } + else if (is_window_end) + { + c.range_end_turn = turns_until_counter; + c.found_end_turn_range = true; + } + else + { + if (c.name == "Dance Card" && turns_until_counter < 0) //bug: dance card is still in relayCounters after being met + { + continue; + } + //if (turns_until_counter >= 0) + if (true) + { + if (turns_until_counter >= 0 || c.name != "Semi-rare") + c.exact_turns.listAppend(MAX(0, turns_until_counter)); + sort c.exact_turns by value; + } + } + + counters[final_name] = c; + } + + /*if (my_path().id == PATH_LIVE_ASCEND_REPEAT && !(counters contains "Semi-rare")) + { + //We already have this information: + //(won't always be accurate) + Counter c = CounterMake(); + c.name = "Semi-rare"; + int next_turn = 75; + while (next_turn < my_turncount()) + { + next_turn += 110; + } + next_turn -= my_turncount(); + c.exact_turns.listAppend(next_turn); + counters["Semi-rare"] = c; + }*/ +} + +Counter [string] __active_counters; //Try to avoid referencing directly +Counter [string] __active_temp_counters; + +boolean __counters_inited = false; +int __counters_turn_inited = -1; +string __counters_inited_property_value; +void CountersInit() +{ + if (__counters_inited && __counters_turn_inited == my_turncount() && __counters_inited_property_value == get_property("relayCounters")) + return; + __counters_inited = true; + __counters_turn_inited = my_turncount(); + __counters_inited_property_value = get_property("relayCounters"); + + //parse counters: + //Examples: + //relayCounters(user, now '1378:Fortune Cookie:fortune.gif', default ) + //relayCounters(user, now '1539:Semirare window begin loc=*:lparen.gif:1579:Semirare window end loc=*:rparen.gif', default ) + //relayCounters(user, now '70:Semirare window begin:lparen.gif:80:Semirare window end loc=*:rparen.gif', default ) + //relayCounters(user, now '1750:Romantic Monster window begin loc=*:lparen.gif:1760:Romantic Monster window end loc=*:rparen.gif', default ) + //relayCounters(user, now '7604:Fortune Cookie:fortune.gif:7584:Fortune Cookie:fortune.gif', default ) + //relayCounters(user, now '450:Fortune Cookie:fortune.gif:458:Fortune Cookie:fortune.gif:401:Dance Card loc=109:guildapp.gif', default ) + //relayCounters(user, now '1271:Nemesis Assassin window begin loc=*:lparen.gif:1286:Nemesis Assassin window end loc=*:rparen.gif:1331:Fortune Cookie:fortune.gif', default ) + //relayCounters(user, now '695:Nemesis Assassin window begin loc=*:lparen.gif:710:Nemesis Assassin window end loc=*:rparen.gif:780:Fortune Cookie:fortune.gif:685:Dance Card loc=109:guildapp.gif', default ) + //70:Semirare window begin:lparen.gif:80:Semirare window end loc=*:rparen.gif:57:Digitize Monster:watch.gif:57:Romantic Monster window begin loc=*:lparen.gif:67:Romantic Monster window end loc=*:rparen.gif + + foreach key in __active_counters + { + remove __active_counters[key]; + } + foreach key in __active_temp_counters + { + remove __active_temp_counters[key]; + } + CountersParseProperty("relayCounters", __active_counters, false); + CountersParseProperty("_tempRelayCounters", __active_temp_counters, true); + + //print_html("__active_counters = " + __active_counters.to_json()); + +} + +Counter CounterLookup(string counter_name, Error found, boolean allow_temp_counters) +{ + CountersInit(); + if (__active_counters contains counter_name) + { + return __active_counters[counter_name]; + } + else if (allow_temp_counters && __active_temp_counters contains counter_name) + { + return __active_temp_counters[counter_name]; + } + else + { + found.ErrorSet(); + return CounterMake(); + } +} + + +Counter CounterLookup(string counter_name, Error found) +{ + return CounterLookup(counter_name, found, false); +} + +Counter CounterLookup(string counter_name, boolean allow_temp_counters) +{ + return CounterLookup(counter_name, ErrorMake(), allow_temp_counters); +} + +Counter CounterLookup(string counter_name) +{ + return CounterLookup(counter_name, ErrorMake()); +} + +string [int] CounterGetAllNames(boolean allow_temp_counters) +{ + string [int] names; + foreach name in __active_counters + names.listAppend(name); + if (allow_temp_counters) + { + foreach name in __active_temp_counters + names.listAppend(name); + } + return names; +} + +string [int] CounterGetAllNames() +{ + return CounterGetAllNames(false); +} + +void CountersReparse() +{ + __counters_inited = false; + CountersInit(); +} + + + +//Bee is wrong, mafia does not track properly. +boolean [string] __wandering_monster_counter_names = $strings[Romantic Monster,Rain Monster,Holiday Monster,Nemesis Assassin,WoL Monster,Digitize Monster,Enamorang Monster,portscan.edu]; +string [string] __wandering_monster_property_lookups {"Romantic Monster":"romanticTarget", "Digitize Monster": "_sourceTerminalDigitizeMonster", "Enamorang Monster":"enamorangMonster"}; + +//This is for ascension automation scripts. Call this immediately before adventuring in an adventure.php zone. +//This will enable tracking of zero-adventure encounters that mean a wandering monster will not appear next turn. Affects CounterWanderingMonsterMayHitNextTurn() only. +int __last_turn_definitely_visited_adventure_php = -1; +void CounterAdviseAboutToVisitAdventurePHP() +{ + __last_turn_definitely_visited_adventure_php = my_turncount(); +} + +void CounterAdviseLastTurnAttemptedAdventurePHP(int turn) +{ + __last_turn_definitely_visited_adventure_php = turn; +} + +boolean CounterWanderingMonsterMayHitNextTurn() +{ + monster last_monster = get_property_monster("lastEncounter"); + + if (my_path().id == PATH_THE_SOURCE) + { + int interval = get_property_int("sourceInterval"); + if (interval == 200 || interval == 400) + return true; + } + if (get_property("questG04Nemesis") == "step17") //first wanderer in nemesis quest + return true; + + if (__last_turn_definitely_visited_adventure_php == -1 && $monsters[Black Crayon Beast,Black Crayon Beetle,Black Crayon Constellation,Black Crayon Golem,Black Crayon Demon,Black Crayon Man,Black Crayon Elemental,Black Crayon Crimbo Elf,Black Crayon Fish,Black Crayon Goblin,Black Crayon Hippy,Black Crayon Hobo,Black Crayon Shambling Monstrosity,Black Crayon Manloid,Black Crayon Mer-kin,Black Crayon Frat Orc,Black Crayon Penguin,Black Crayon Pirate,Black Crayon Flower,Black Crayon Slime,Black Crayon Undead Thing,Black Crayon Spiraling Shape,angry bassist,blue-haired girl,evil ex-girlfriend,peeved roommate,random scenester] contains last_monster) //bit of a hack - if they just fought a hipster monster (hopefully not faxing it), then the wandering monster isn't up this turn. though... __last_turn_definitely_visited_adventure_php should handle that... + { + return false; + } + if (my_turncount() == __last_turn_definitely_visited_adventure_php && __last_turn_definitely_visited_adventure_php != -1) //that adventure didn't advance the counter; no wandering monsters. also, does lights out override wanderers? but, what if there are TWO wandering monsters? the plot thickens + { + string last_encounter = get_property("lastEncounter"); + location last_location = get_property_location("lastAdventure"); + if (!($strings[Lights Out,Wooof! Wooooooof!,Playing Fetch*,Your Dog Found Something Again,Gunbowwowder,Seeing-Eyes Dog] contains last_encounter) && !(last_location != $location[none] && !last_location.locationAllowsWanderingMonsters())) + return false; + } + //FIXME use CounterWanderingMonsterMayHitInXTurns to implement this once we're sure it works + foreach s in __wandering_monster_counter_names + { + if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug + if (s == "Romantic Monster" && get_property_int("_romanticFightsLeft") == 0) //If mafia's tracking doesn't recognise the monster, then we can override by decrementing the romantic fights left. Added because of the machine elf tunnels. + continue; + Counter c = CounterLookup(s); + if (c.CounterExists() && c.CounterMayHitNextTurn()) + { + return true; + } + } + if (get_property_int("_romanticFightsLeft") > 0 && !CounterLookup("Romantic Monster").CounterExists() && my_path().id != PATH_ONE_CRAZY_RANDOM_SUMMER) //mafia will clear the romantic monster window if it goes out of bounds + return true; + + //Disabled for now, because this is hard to predict: + /*boolean [string] holidays = getHolidaysToday(); + foreach s in $strings[Feast of Boris,El Dia de Los Muertos Borrachos] + { + if (!holidays[s]) continue; + if (!CounterLookup("Holiday Monster").CounterExists()) + { + return true; + } + }*/ + return false; +} + +//only_detect_by_counter_names or in other words "not source agents", which we use in exactly one place for an obscure situation. +boolean CounterWanderingMonsterMayHitInXTurns(int turns, boolean only_detect_by_counter_names) +{ + if (CounterWanderingMonsterMayHitNextTurn() && !only_detect_by_counter_names) + return true; + foreach s in __wandering_monster_counter_names + { + if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug + if (CounterLookup(s).CounterExists() && CounterLookup(s).CounterMayHitInXTurns(turns)) + return true; + } + //if (get_property_int("_romanticFightsLeft") > 0 && !CounterLookup("Romantic Monster").CounterExists() && my_path().id != PATH_ONE_CRAZY_RANDOM_SUMMER) //mafia will clear the romantic monster window if it goes out of bounds + //return true; + return false; +} +boolean CounterWanderingMonsterMayHitInXTurns(int turns) +{ + return CounterWanderingMonsterMayHitInXTurns(turns, false); +} + +boolean CounterWanderingMonsterWillHitInXTurns(int turns) +{ + //CounterWillHitExactlyInTurnRange + foreach s in __wandering_monster_counter_names + { + if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug + if (CounterLookup(s).CounterExists() && CounterLookup(s).CounterWillHitExactlyInTurnRange(0, turns)) + return true; + } + return false; +} + +Counter [int] CounterWanderingMonsterWindowsActiveInXTurns(int turns) +{ + Counter [int] result; + foreach s in __wandering_monster_counter_names + { + if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug + Counter c = CounterLookup(s); + if (c.CounterExists() && c.CounterMayHitInXTurns(turns)) + result[result.count()] = c; + } + return result; +} + +Counter [int] CounterWanderingMonsterWindowsActiveNextTurn() +{ + Counter [int] result; + if (!CounterWanderingMonsterMayHitNextTurn()) + return result; + foreach s in __wandering_monster_counter_names + { + if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug + Counter c = CounterLookup(s); + if (c.CounterExists() && c.CounterMayHitNextTurn()) + result[result.count()] = c; + } + return result; +} + +boolean [monster] CounterWanderingMonstersActiveNextTurn() +{ + boolean [monster] result; + foreach key, c in CounterWanderingMonsterWindowsActiveNextTurn() + { + if (__wandering_monster_property_lookups contains c.name) + result[get_property_monster(__wandering_monster_property_lookups[c.name])] = true; + //result + } + //FIXME determine Rain Monster,Holiday Monster,Nemesis Assassin,Bee,WoL Monster + return result; +} + +boolean [monster] CounterWanderingMonstersActiveInXTurns(int turns) +{ + boolean [monster] result; + foreach key, c in CounterWanderingMonsterWindowsActiveInXTurns(turns) + { + if (__wandering_monster_property_lookups contains c.name) + result[get_property_monster(__wandering_monster_property_lookups[c.name])] = true; + //result + } + //FIXME determine Rain Monster,Holiday Monster,Nemesis Assassin,Bee,WoL Monster + return result; +} + +boolean CounterWanderingMonsterCountersHaveRange() +{ + foreach s in __wandering_monster_counter_names + { + if (s == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) continue; //mafia bug + Counter c = CounterLookup(s); + if (!c.CounterExists()) + continue; + if (c.CounterIsRange()) + return true; + } + return false; +} + + +boolean CounterWanderingMonsterWillHitNextTurn() +{ + if (!CounterWanderingMonsterMayHitNextTurn()) + return false; + foreach key, c in CounterWanderingMonsterWindowsActiveNextTurn() + { + if (c.CounterWillHitNextTurn()) + { + return true; + } + } + return false; +} + +boolean CounterWanderingMonstersCurrentlyActiveNextTurnAreFree() +{ + boolean [monster] monsters = CounterWanderingMonstersActiveNextTurn(); + if (monsters.count() == 0) + return false; + foreach m in monsters + { + if (!m.monster_has_zero_turn_cost()) + return false; + } + return true; +} + + +boolean CounterWanderingMonstersCurrentlyAroundAreFree() +{ + boolean [monster] monsters = CounterWanderingMonstersActiveInXTurns(10000); //FIXME better + if (monsters.count() == 0) + return false; + foreach m in monsters + { + if (!m.monster_has_zero_turn_cost()) + return false; + } + return true; +} + +boolean CounterWanderingMonstersCurrentlyAroundAreExact() //not exclusively, but at least one is +{ + foreach key, c in CounterWanderingMonsterWindowsActiveInXTurns(10000) //FIXME better + { + if (c.CounterExists() && !c.CounterIsRange()) + return true; + } + return false; +} + +CountersInit(); + +//Library for checking if any given location is unlocked. +//Similar to canadv.ash, except there's no code for using items and no URLs are (currently) visited. This limits our accuracy. +//Currently, most locations are missing, sorry. + + +boolean [location] __la_location_is_available; +boolean [string] __la_zone_is_unlocked; + +boolean __la_commons_were_inited = false; +int __la_turncount_initialised_on = -1; + + +float [monster] appearance_rates_adjusted(location l, boolean account_for_queue) +{ + float [monster] source = l.appearance_rates(account_for_queue); + + boolean lawyers_relocated = get_property_ascension("relocatePygmyLawyer"); + boolean janitors_relocated = get_property_ascension("relocatePygmyJanitor"); + if (l == $location[the hidden park]) + { + if (!janitors_relocated && source contains $monster[pygmy janitor]) + remove source[$monster[pygmy janitor]]; + if (!lawyers_relocated && source contains $monster[pygmy witch lawyer]) + remove source[$monster[pygmy witch lawyer]]; + } + if (($locations[The Hidden Apartment Building,The Hidden Bowling Alley,The Hidden Hospital,The Hidden Office Building] contains l)) + { + if (janitors_relocated && (source contains $monster[pygmy janitor])) + remove source[$monster[pygmy janitor]]; + if (lawyers_relocated && (source contains $monster[pygmy witch lawyer])) + remove source[$monster[pygmy witch lawyer]]; + } + if ($locations[domed city of grimacia,domed city of ronaldus] contains l) + { + //appearance_rates() currently doesn't handle the relation between aliens and moonlight + boolean [monster] aliens; + boolean [monster] survivors; + float actual_percent_aliens = 0.0; + + + if (l == $location[domed city of grimacia]) + { + aliens = $monsters[cat-alien,dog-alien,alielf]; + survivors = $monsters[unhinged survivor,grizzled survivor,whiny survivor]; + int grimace_phase = moon_phase() / 2; + int grimace_darkness = abs(grimace_phase - 4); + int grimace_light = 4 - grimace_darkness; + if (grimace_light < 2) + actual_percent_aliens = 0.0; + else + actual_percent_aliens = 8.0 * grimace_light; + } + else + { + aliens = $monsters[dogcat,hamsterpus,ferrelf]; + survivors = $monsters[unlikely survivor,overarmed survivor,primitive survivor]; + int ronald_phase = moon_phase() % 8; + int ronald_darkness = abs(ronald_phase - 4); + int ronald_light = 4 - ronald_darkness; + if (ronald_light < 2) + actual_percent_aliens = 0.0; + else + actual_percent_aliens = 8.0 * ronald_light; + } + //Readjust: + if (actual_percent_aliens == 0.0) + { + foreach m, rate in source + { + if (aliens contains m) + remove source[m]; + } + } + else + { + float source_percent_aliens = 0.0; + float source_percent_survivors = 0.0; + foreach m, rate in source + { + if (aliens contains m) + source_percent_aliens += rate; + if (survivors contains m) + source_percent_survivors += rate; + } + foreach m, rate in source + { + if (aliens contains m && source_percent_aliens != 0.0) + source[m] = rate / source_percent_aliens * actual_percent_aliens; + if (survivors contains m && source_percent_survivors != 0.0) + source[m] = rate / source_percent_survivors * (100.0 - actual_percent_aliens); + } + } + + } + if (l == $location[The Nemesis' Lair]) + { + boolean [monster] all_monsters_to_remove = $monsters[hellseal guardian,Gorgolok\, the Infernal Seal (Inner Sanctum),warehouse worker,Stella\, the Turtle Poacher (Inner Sanctum),evil spaghetti cult zealot,Spaghetti Elemental (Inner Sanctum),security slime,Lumpy\, the Sinister Sauceblob (Inner Sanctum),daft punk,Spirit of New Wave (Inner Sanctum),mariachi bruiser,Somerset Lopez\, Dread Mariachi (Inner Sanctum)]; + + boolean [monster] monsters_not_to_remove; + if (my_class() == $class[seal clubber]) + monsters_not_to_remove = $monsters[hellseal guardian,Gorgolok\, the Infernal Seal (Inner Sanctum)]; + else if (my_class() == $class[turtle tamer]) + monsters_not_to_remove = $monsters[warehouse worker,Stella\, the Turtle Poacher (Inner Sanctum)]; + else if (my_class() == $class[pastamancer]) + monsters_not_to_remove = $monsters[evil spaghetti cult zealot,Spaghetti Elemental (Inner Sanctum)]; + else if (my_class() == $class[sauceror]) + monsters_not_to_remove = $monsters[security slime,Lumpy\, the Sinister Sauceblob (Inner Sanctum)]; + else if (my_class() == $class[disco bandit]) + monsters_not_to_remove = $monsters[daft punk,Spirit of New Wave (Inner Sanctum)]; + else if (my_class() == $class[accordion thief]) + monsters_not_to_remove = $monsters[mariachi bruiser,Somerset Lopez\, Dread Mariachi (Inner Sanctum)]; + foreach m in all_monsters_to_remove + { + if (monsters_not_to_remove contains m) + continue; + remove source[m]; + } + } + + + //change the NC rate manually when we suspect mafia got it wrong + float original_combat_rate = 100.0 - source[$monster[none]]; + float new_combat_rate = -1.0; + + if (l == $location[the sleazy back alley]) //FIXME is mafia's data files incorrect, or the wiki's? + new_combat_rate = clampf(80.0 + combat_rate_modifier(), 0, 100); + + // @todo Update this once mafia is fixed. + if ($locations[The Dark Elbow of the Woods,The Dark Heart of the Woods,The Dark Neck of the Woods] contains l) + new_combat_rate = clampf(95.0 + combat_rate_modifier(), 0, 100); + + if (l == $location[Inside the Palindome]) + if (!questPropertyPastInternalStepNumber("questL11Palindome", 3)) + new_combat_rate = 100.0; + + //Readjust: + if (new_combat_rate == 0.0) + { + foreach m, rate in source + if (rate > 0.0) + source[m] = 0.0; + source[$monster[none]] = 100.0; + } + else if (original_combat_rate != new_combat_rate && new_combat_rate > 0.0 && original_combat_rate > 0.0) + { + source[$monster[none]] = 100.0 - new_combat_rate; + + float ratio = new_combat_rate / original_combat_rate; + foreach m, rate in source + { + if (m == $monster[none]) + continue; + if (rate > 0.0) + source[m] = rate * ratio; + } + } + + //for monsters which always appear every X adventures, which mafia returns as 0 when not about to get them. + //Currently doesn't support cases when mafia is not aware that the encounter is periodically scheduled. Currently "peanut" from the calaginous abyss + void averagePediodicSuperlikely(monster superlikely_monster, int frequency) + { + float combat_rate = clampf(100.0 - source[$monster[none]], 0.0, 100.0); + if (combat_rate == 0.0) return; + if (source[superlikely_monster] != 0) return; + + float superlikely_average_occurence = 1.0 / frequency; + source[superlikely_monster] = superlikely_average_occurence * combat_rate; + //If, let's say, we have 4 monsters (25% occurence), with a superlikely occuring every 2 turns (1 / 2 = 50%) + //the 4 monsters' 25% (obviously giving 100%) + the SL's 50% give 150% combat chance: 3/2 the combat rate. + //if we divide the 4 monsters' rate by 3/2, we get 16.6. Not quite. + //To get them to 12.5% (which, when *4, gives 50%, which, when added the SL's rate, equals the combat rate), + //we say that the ratio is 1 + (1 / (x-1)) + //here this gives 1 + (1 / (2-1)) = 200% = 2/1 the combat rate + //25% (the 4 monsters' appearance rate) / (2/1) = 12.5% + float excess_ratio = 1.0 + 1.0 / (frequency - 1); + + foreach m, v in source + { + if (m == $monster[none] || m == superlikely_monster) + continue; + if (v > 0.0) + source[m] = v / excess_ratio * combat_rate / 100.0; + } + } + + if ($locations[Guano Junction,the Batrat and Ratbat Burrow,the Beanbat Chamber] contains l) + $monster[screambat].averagePediodicSuperlikely(8); + + if (l == $location[kokomo resort]) + $monster[Brick Mulligan, the Bartender].averagePediodicSuperlikely(25); + + if (l == $location[The Post-Mall]) + $monster[sentient ATM].averagePediodicSuperlikely(11); + + + return source; +} + +float [monster] appearance_rates_adjusted(location l) +{ + return appearance_rates_adjusted(l, false); +} + + +float [monster] appearance_rates_cancel_nc(float [monster] base_rates) +{ + if (base_rates[$monster[none]] == 100.0) return base_rates; + + float combat_rate_sum = 0.0; + foreach m, rate in base_rates + { + if (m == $monster[none]) + continue; + if (rate > 0.0) + combat_rate_sum += rate; + } + if (combat_rate_sum != 100.0 && combat_rate_sum != 0.0) + { + float divisor = combat_rate_sum / 100.0; + + foreach m, rate in base_rates + { + if (m == $monster[none]) + continue; + if (rate > 0.0) + base_rates[m] /= divisor; + } + } + + return base_rates; +} + +float [monster] appearance_rates_adjusted_cancel_nc(location l) +{ + float [monster] base_rates = appearance_rates_adjusted(l); + return base_rates.appearance_rates_cancel_nc(); +} + +//Do not call - internal implementation detail. +boolean locationAvailablePrivateCheck(location loc, Error able_to_find) +{ + string zone = loc.zone; + + if (zone == "KOL High School") + { + if (my_path().id == PATH_KOLHS) + return true; + return false; + } + if (zone == "Mothership") + { + if (my_path().id == PATH_BUGBEAR_INVASION) + return true; + return false; + } + if (zone == "BadMoon") + { + if (in_bad_moon()) + return true; + return false; + } + if ($strings[Crimbo05,Crimbo14,Crimbo15,Crimbo16] contains zone) + return false; + if (zone == "Woods" && !__la_zone_is_unlocked["Woods"]) + return false; + if (loc.parentdesc == "Batfellow Area") + return limit_mode() == "batman"; + if (zone == "Spelunky Area") + return limit_mode() == "spelunky"; + if (zone == "Twitch") + return get_property_boolean("timeTowerAvailable"); + if (zone == "The Prince's Ball") + return get_property("grimstoneMaskPath").to_lower_case() == "stepmother" && get_property_int("cinderellaMinutesToMidnight") > 0; + + if (loc == $location[The Hippy Camp]) + { + //FIXME we don't know who won the war, do we? so only give information if the war hasn't started + if (get_property_ascension("lastIslandUnlock")) + { + if (!QuestState("questL12War").started) return true; + } + else + return false; + } + + switch (loc) + { + case $location[The Castle in the Clouds in the Sky (Ground floor)]: + return get_property_ascension("lastCastleGroundUnlock"); + case $location[The Castle in the Clouds in the Sky (Top floor)]: + return get_property_ascension("lastCastleTopUnlock"); + case $location[The Haunted Kitchen]: + case $location[The Haunted Conservatory]: + return questPropertyPastInternalStepNumber("questM20Necklace", 1); + case $location[The Haunted Billiards Room]: + if ($item[7301].available_amount() > 0) + return true; + else + return false; + //return get_property_ascension("lastManorUnlock"); + case $location[The Haunted Bedroom]: + case $location[The Haunted Bathroom]: + case $location[the haunted gallery]: + return get_property_ascension("lastSecondFloorUnlock") && QuestState("questM21Dance").started; + case $location[the haunted ballroom]: + return questPropertyPastInternalStepNumber("questM21Dance", 4); + case $location[The Haunted Laboratory]: + case $location[The Haunted Nursery]: + case $location[The Haunted Storage Room]: + return questPropertyPastInternalStepNumber("questM17Babies", 1); + case $location[The Haunted Boiler Room]: + case $location[The Haunted Laundry Room]: + case $location[The Haunted Wine Cellar]: + return questPropertyPastInternalStepNumber("questL11Manor", 2); + case $location[summoning chamber]: + return get_property("questL11Manor") == "finished"; + case $location[the batrat and ratbat burrow]: + return questPropertyPastInternalStepNumber("questL04Bat", 2); + case $location[the beanbat chamber]: + return questPropertyPastInternalStepNumber("questL04Bat", 3); + case $location[The Unquiet Garves]: + return true; + case $location[The VERY Unquiet Garves]: + return get_property("questL07Cyrptic") == "finished"; + case $location[The Wreck of the Edgar Fitzsimmons]: + return questPropertyPastInternalStepNumber("questS02Monkees", 2); + case $location[the boss bat\'s lair]: + if (get_property("questL04Bat") == "finished") return false; //area closes + if ($location[the boss bat\'s lair].combatTurnsAttemptedInLocation() > 0) + return true; + return questPropertyPastInternalStepNumber("questL04Bat", 4); + case $location[cobb\'s knob barracks]: + case $location[cobb\'s knob kitchens]: + case $location[cobb\'s knob harem]: + case $location[cobb\'s knob treasury]: + string quest_value = get_property("questL05Goblin"); + if (quest_value == "finished") + return true; + else if (questPropertyPastInternalStepNumber("questL05Goblin", 1)) + { + //Inference - quest is started. If map is missing, area must be unlocked + if ($item[cobb\'s knob map].available_amount() > 0) + return false; + else //no map, must be available + return true; + } + //unstarted, impossible + return false; + case $location[Vanya\'s Castle Chapel]: + if ($item[map to Vanya\'s Castle].available_amount() > 0) + return true; + return false; + case $location[lair of the ninja snowmen]: + case $location[the extreme slope]: + return questPropertyPastInternalStepNumber("questL08Trapper", 3); + case $location[the hidden park]: + return questPropertyPastInternalStepNumber("questL11Worship", 4); + case $location[the hidden temple]: + return get_property_ascension("lastTempleUnlock"); + case $location[the spooky forest]: + return __la_zone_is_unlocked["Woods"]; + case $location[The Smut Orc Logging Camp]: + return questPropertyPastInternalStepNumber("questL09Topping", 1); + case $location[the black forest]: + return questPropertyPastInternalStepNumber("questL11MacGuffin", 1); + case $location[guano junction]: + case $location[the bat hole entrance]: + return questPropertyPastInternalStepNumber("questL04Bat", 1); + case $location[itznotyerzitz mine]: + return questPropertyPastInternalStepNumber("questL08Trapper", 2); + case $location[the arid, extra-dry desert]: + return (questPropertyPastInternalStepNumber("questL11MacGuffin", 3) || $item[your father\'s MacGuffin diary].available_amount() > 0); + case $location[the oasis]: + return (get_property_int("desertExploration") > 0) && (questPropertyPastInternalStepNumber("questL11MacGuffin", 3) || $item[your father\'s MacGuffin diary].available_amount() > 0); + case $location[the defiled alcove]: + return questPropertyPastInternalStepNumber("questL07Cyrptic", 1) && get_property_int("cyrptAlcoveEvilness") > 0; + case $location[the defiled cranny]: + return questPropertyPastInternalStepNumber("questL07Cyrptic", 1) && get_property_int("cyrptCrannyEvilness") > 0; + case $location[the defiled niche]: + return questPropertyPastInternalStepNumber("questL07Cyrptic", 1) && get_property_int("cyrptNicheEvilness") > 0; + case $location[the defiled nook]: + return questPropertyPastInternalStepNumber("questL07Cyrptic", 1) && get_property_int("cyrptNookEvilness") > 0; + case $location[south of the border]: + case $location[The Shore\, Inc. Travel Agency]: + return get_property_ascension("lastDesertUnlock"); + case $location[Portal to Terrible Parents]: + case $location[Rumpelstiltskin\'s Workshop]: + case $location[Ye Olde Medievale Villagee]: + return (get_property("grimstoneMaskPath") == "gnome"); + case $location[the mansion of dr. weirdeaux]: + case $location[the secret government laboratory]: + case $location[the deep dark jungle]: + return $item[airplane charter: Conspiracy Island].is_unrestricted() && (get_property_boolean("_spookyAirportToday") || get_property_boolean("spookyAirportAlways")); + case $location[the fun-guy mansion]: + case $location[sloppy seconds diner]: + case $location[the sunken party yacht]: + return $item[airplane charter: Spring Break Beach].is_unrestricted() && (get_property_boolean("_sleazeAirportToday") || get_property_boolean("sleazeAirportAlways")); + case $location[Pirates of the Garbage Barges]: + case $location[Barf Mountain]: + case $location[The Toxic Teacups]: + case $location[Uncle Gator\'s Country Fun-Time Liquid Waste Sluice]: + return $item[airplane charter: Dinseylandfill].is_unrestricted() && (get_property_boolean("_stenchAirportToday") || get_property_boolean("stenchAirportAlways")); + case $location[The SMOOCH Army HQ]: + case $location[The Velvet / Gold Mine]: + case $location[LavaCo™ Lamp Factory]: + case $location[The Bubblin\' Caldera]: + return $item[airplane charter: That 70s Volcano].is_unrestricted() && (get_property_boolean("_hotAirportToday") || get_property_boolean("hotAirportAlways")); + case $location[The Ice Hotel]: + case $location[VYKEA]: + case $location[The Ice Hole]: + return $item[airplane charter: The Glaciest].is_unrestricted() && (get_property_boolean("_coldAirportToday") || get_property_boolean("coldAirportAlways")); + case $location[Kokomo Resort]: + return $effect[Tropical Contact High].have_effect() > 0; + case $location[Dreadsylvanian Woods]: + case $location[Dreadsylvanian Village]: + case $location[Dreadsylvanian Castle]: + //FIXME not correct - does not take account whether the dungeon is open and the areas are unlocked + return get_clan_id() > 0 && my_level() >= 15; + case $location[A Barroom Brawl]: + return questPropertyPastInternalStepNumber("questL03Rat", 1); + case $location[The Laugh Floor]: + case $location[Pandamonium Slums]: + case $location[Infernal Rackets Backstage]: + return get_property("questL06Friar") == "finished"; + case $location[The Degrassi Knoll Restroom]: + case $location[The Degrassi Knoll Bakery]: + case $location[The Degrassi Knoll Gym]: + case $location[The Degrassi Knoll Garage]: + return !knoll_available(); + case $location[Thugnderdome]: + return gnomads_available() && my_basestat(my_primestat()) >= 25; + case $location[outskirts of camp logging camp]: + case $location[camp logging camp]: + return canadia_available(); + ///FIXME test grimstone masks against their progress? + case $location[Sweet-Ade Lake]: + case $location[Eager Rice Burrows]: + case $location[Gumdrop Forest]: + return get_property("grimstoneMaskPath") == "witch"; + case $location[The Inner Wolf Gym]: + case $location[Unleash Your Inner Wolf]: + return get_property("grimstoneMaskPath") == "wolf"; + case $location[A Deserted Stretch of I-911]: + return get_property("grimstoneMaskPath") == "hare"; + case $location[A-Boo Peak]: + case $location[Twin Peak]: + case $location[Oil Peak]: + return questPropertyPastInternalStepNumber("questL09Topping", 2); + case $location[The Icy Peak]: + return get_property("questL08Trapper") == "finished"; //FIXME is it finished, or after defeating groar? + case $location[the bugbear pen]: + return knoll_available() && questPropertyPastInternalStepNumber("questM03Bugbear", 1) && get_property("questM03Bugbear") != "finished"; + case $location[post-quest bugbear pens]: + return knoll_available() && get_property("questM03Bugbear") == "finished"; + case $location[the thinknerd warehouse]: + return questPropertyPastInternalStepNumber("questM22Shirt", 1); + case $location[The Overgrown Lot]: + return questPropertyPastInternalStepNumber("questM24Doc", 1); + case $location[The Skeleton Store]: + if (questPropertyPastInternalStepNumber("questM23Meatsmith", 1)) + return true; + //otherwise, don't know + break; + case $location[the old landfill]: + return questPropertyPastInternalStepNumber("questM19Hippy", 1); + case $location[The Hidden Apartment Building]: + return get_property_int("hiddenApartmentProgress") >= 1; + case $location[The Hidden Bowling Alley]: + return get_property_int("hiddenBowlingAlleyProgress") >= 1; + case $location[The Hidden Hospital]: + return get_property_int("hiddenHospitalProgress") >= 1; + case $location[The Hidden Office Building]: + return get_property_int("hiddenOfficeProgress") >= 1; + case $location[The Enormous Greater-Than Sign]: + return my_basestat(my_primestat()) >= 45 && !get_property_ascension("lastPlusSignUnlock"); + case $location[The dungeons of doom]: + return my_basestat(my_primestat()) >= 45 && get_property_ascension("lastPlusSignUnlock"); + case $location[The "Fun" House]: + return questPropertyPastInternalStepNumber("questG04Nemesis", 6); //FIXME 6 is wrong, but I don't know the right value + case $location[The Dark Neck of the Woods]: + case $location[The Dark Heart of the Woods]: + case $location[The Dark Elbow of the Woods]: + return QuestState("questL06Friar").in_progress; + case $location[The Goatlet]: + return questPropertyPastInternalStepNumber("questL08Trapper", 1); + case $location[The Penultimate Fantasy Airship]: + return questPropertyPastInternalStepNumber("questL10Garbage", 2); + case $location[anger man\'s level]: + case $location[fear man\'s level]: + case $location[doubt man\'s level]: + case $location[regret man\'s level]: + return __campground[$item[jar of psychoses (The Crackpot Mystic)]] > 0; + case $location[the gourd!]: + return __campground[$item[jar of psychoses (The Captain of the Gourd)]] > 0; + case $location[The Nightmare Meatrealm]: + return __campground[$item[jar of psychoses (The Meatsmith)]] > 0; + case $location[A Kitchen Drawer]: + case $location[A Grocery Bag]: + return __campground[$item[jar of psychoses (The Pretentious Artist)]] > 0; + case $location[Chinatown Shops]: //needs tracking for the quest? maybe use the items? + return __campground[$item[jar of psychoses (The Suspicious-Looking Guy)]] > 0 && $item[strange goggles].available_amount() == 0; + case $location[Triad Factory]: + return $item[zaibatsu lobby card].available_amount() > 0 && $item[strange goggles].available_amount() == 0 && __campground[$item[jar of psychoses (The Suspicious-Looking Guy)]] > 0; + //case $location[1st Floor, Shiawase-Mitsuhama Building]: + //case $location[2nd Floor, Shiawase-Mitsuhama Building]: + //case $location[3rd Floor, Shiawase-Mitsuhama Building]: + case $location[Chinatown Tenement]: + return $item[test site key].available_amount() > 0 && __campground[$item[jar of psychoses (The Suspicious-Looking Guy)]] > 0; + case $location[whitey\'s grove]: + return questPropertyPastInternalStepNumber("questG02Whitecastle", 1) || questPropertyPastInternalStepNumber("questL11Palindome", 4); //FIXME what step for questL11Palindome? + case $location[The Road to the White Citadel]: + return questPropertyPastInternalStepNumber("questG02Whitecastle", 2) && !questPropertyPastInternalStepNumber("questG02Whitecastle", 11); // the road closes when the White Citadel is found + case $location[the Obligatory pirate\'s cove]: + return get_property_ascension("lastIslandUnlock") && !(QuestState("questL12War").mafia_internal_step >= 2 && !QuestState("questL12War").finished); + case $location[Inside the Palindome]: + return $item[talisman o\' namsilat].equipped_amount() > 0; //technically + case $location[The Valley of Rof L\'m Fao]: + return QuestState("questL09Topping").finished; + case $location[Swamp Beaver Territory]: + return get_property_boolean("maraisBeaverUnlock"); + case $location[The Corpse Bog]: + return get_property_boolean("maraisCorpseUnlock"); + case $location[The Dark and Spooky Swamp]: + return get_property_boolean("maraisDarkUnlock"); + case $location[The Weird Swamp Village]: + return get_property_boolean("maraisVillageUnlock"); + case $location[The Wildlife Sanctuarrrrrgh]: + return get_property_boolean("maraisWildlifeUnlock"); + case $location[The Ruined Wizard Tower]: + return get_property_boolean("maraisWizardUnlock"); + case $location[The Edge of the Swamp]: + return QuestState("questM18Swamp").started; + case $location[madness bakery]: + return QuestState("questM25Armorer").started; + case $location[sonofa beach]: + return QuestState("questL12War").mafia_internal_step >= 2; + case $location[the spooky gravy burrow]: + return QuestState("questM03Bugbear").mafia_internal_step >= 3; + case $location[The Copperhead Club]: + return QuestState("questL11MacGuffin").mafia_internal_step >= 3; //FIXME no idea, diary? + case $location[A mob of zeppelin protesters]: + return QuestState("questL11MacGuffin").mafia_internal_step >= 3; //FIXME no idea, diary? + case $location[The Red Zeppelin]: + return QuestState("questL11MacGuffin").mafia_internal_step >= 3 && get_property_int("zeppelinProtestors") >= 80; //FIXME not quite right, diary?; also NC needs to be visited first + case $location[The F\'c\'le]: + return QuestState("questM12Pirate").mafia_internal_step >= 6; + case $location[Belowdecks]: + return QuestState("questM12Pirate").finished; + default: + break; + } + + ErrorSet(able_to_find, ""); + return false; +} + +void locationAvailablePrivateInit() +{ + if (__la_commons_were_inited && __la_turncount_initialised_on == my_turncount()) + return; + + if (__la_location_is_available.count() > 0) + { + foreach key in __la_location_is_available + { + remove __la_location_is_available[key]; + } + } + if (__la_zone_is_unlocked.count() > 0) + { + foreach key in __la_zone_is_unlocked + { + remove __la_zone_is_unlocked[key]; + } + } + + boolean [location] locations_always_available = $locations[the haunted pantry,the sleazy back alley,the outskirts of cobb's knob,the limerick dungeon,The Haiku Dungeon,The Daily Dungeon,noob cave,the dire warren]; + foreach loc in locations_always_available + { + if (loc == $location[none]) + continue; + __la_location_is_available[loc] = true; + } + + if (questPropertyPastInternalStepNumber("questL02Larva", 1) || questPropertyPastInternalStepNumber("questG02Whitecastle", 1)) + __la_zone_is_unlocked["Woods"] = true; + + string zones_never_accessible_string = "Gyms,Crimbo06,Crimbo07,Crimbo08,Crimbo09,Crimbo10,The Candy Diorama,Crimbo12,WhiteWed"; + + item [location] locations_unlocked_by_item; + effect [location] locations_unlocked_by_effect; + + item [string] zones_unlocked_by_item; + effect [string] zones_unlocked_by_effect; + + locations_unlocked_by_item[$location[Cobb\'s Knob Laboratory]] = $item[Cobb\'s Knob lab key]; + locations_unlocked_by_item[$location[The Knob Shaft]] = $item[Cobb\'s Knob lab key]; + locations_unlocked_by_item[$location[Cobb\'s Knob Menagerie\, Level 1]] = $item[Cobb\'s Knob Menagerie key]; + locations_unlocked_by_item[$location[Cobb\'s Knob Menagerie\, Level 2]] = $item[Cobb\'s Knob Menagerie key]; + locations_unlocked_by_item[$location[Cobb\'s Knob Menagerie\, Level 3]] = $item[Cobb\'s Knob Menagerie key]; + + locations_unlocked_by_item[$location[The Haunted Library]] = $item[7302]; //library key + locations_unlocked_by_item[$location[The Castle in the Clouds in the Sky (Basement)]] = $item[S.O.C.K.]; + locations_unlocked_by_item[$location[the hole in the sky]] = $item[steam-powered model rocketship]; + if (my_path().id == PATH_EXPLOSION) + { + locations_unlocked_by_item[$location[The Castle in the Clouds in the Sky (Basement)]] = $item[none]; + locations_unlocked_by_item[$location[the hole in the sky]] = $item[none]; + } + + locations_unlocked_by_item[$location[Vanya\'s Castle Foyer]] = $item[map to Vanya\'s Castle]; + + zones_unlocked_by_item["Magic Commune"] = $item[map to the Magic Commune]; + zones_unlocked_by_item["Landscaper"] = $item[Map to The Landscaper\'s Lair]; + zones_unlocked_by_item["Kegger"] = $item[map to the Kegger in the Woods]; + zones_unlocked_by_item["Ellsbury's Claim"] = $item[Map to Ellsbury\'s Claim]; + zones_unlocked_by_item["Memories"] = $item[empty agua de vida bottle]; + zones_unlocked_by_item["Casino"] = $item[casino pass]; + + zones_unlocked_by_effect["Astral"] = $effect[Half-Astral]; + zones_unlocked_by_effect["Spaaace"] = $effect[Transpondent]; + zones_unlocked_by_effect["RabbitHole"] = $effect[Down the Rabbit Hole]; + zones_unlocked_by_effect["Wormwood"] = $effect[Absinthe-Minded]; + zones_unlocked_by_effect["Suburbs"] = $effect[Dis Abled]; + + string [int] zones_never_accessible = split_string_alternate(zones_never_accessible_string, ","); + + boolean [string] zone_accessibility_status = zones_never_accessible.listInvert(); + foreach s in zone_accessibility_status //invert + { + zone_accessibility_status[s] = false; + } + + + foreach loc in $locations[Shivering Timbers,A Skeleton Invasion!,The Cannon Museum,A Swarm of Yeti-Mounted Skeletons,The Bonewall,A Massive Flying Battleship,A Supply Train,The Bone Star,Grim Grimacite Site,A Pile of Old Servers,The Haunted Sorority House,Fightin' Fire,Super-Intense Mega-Grassfire,Fierce Flying Flames,Lord Flameface's Castle Entryway,Lord Flameface's Castle Belfry,Lord Flameface's Throne Room,A Stinking Abyssal Portal,A Scorching Abyssal Portal,A Terrifying Abyssal Portal,A Freezing Abyssal Portal,An Unsettling Abyssal Portal,A Yawning Abyssal Portal,The Space Odyssey Discotheque,The Spirit World,The Crimbonium Mining Camp,WarBear Fortress (First Level),WarBear Fortress (Second Level),WarBear Fortress (Third Level)] + { + __la_location_is_available[loc] = false; + } + + foreach loc in locations_unlocked_by_item + { + if (locations_unlocked_by_item[loc].available_amount() > 0 || locations_unlocked_by_item[loc] == $item[none]) + __la_location_is_available[loc] = true; + else + __la_location_is_available[loc] = false; + } + foreach loc in locations_unlocked_by_effect + { + if (locations_unlocked_by_effect[loc].have_effect() > 0) + __la_location_is_available[loc] = true; + else + __la_location_is_available[loc] = false; + } + + foreach zone in zones_unlocked_by_item + { + if (zones_unlocked_by_item[zone].available_amount() > 0) + zone_accessibility_status[zone] = true; + else + zone_accessibility_status[zone] = false; + } + foreach zone in zones_unlocked_by_effect + { + if (zones_unlocked_by_effect[zone].have_effect() > 0) + zone_accessibility_status[zone] = true; + else + zone_accessibility_status[zone] = false; + } + + + + + foreach loc in $locations[] + { + if (zone_accessibility_status contains (loc.zone)) + __la_location_is_available[loc] = zone_accessibility_status[loc.zone]; + } + + + __la_commons_were_inited = true; + __la_turncount_initialised_on = my_turncount(); +} + +boolean locationAvailable(location loc, Error able_to_find) +{ + locationAvailablePrivateInit(); + if ((__la_location_is_available contains loc)) + return __la_location_is_available[loc]; + + boolean [int] could_find; + boolean is_available = locationAvailablePrivateCheck(loc, able_to_find); + if (able_to_find.was_error) + return false; + __la_location_is_available[loc] = is_available; + + return is_available; +} + +boolean locationAvailable(location loc) +{ + return locationAvailable(loc, ErrorMake()); +} + +void locationAvailableResetCache() +{ + __la_commons_were_inited = false; +} + + + +string [location] LAConvertLocationLookupToLocations(string [string] lookup_map) +{ + string [location] result; + foreach location_name in lookup_map + { + location l = location_name.to_location(); + if (l == $location[none]) + { + if (__setting_debug_mode) + print_html("Location \"" + location_name + "\" does not appear to exist anymore."); + continue; + } + result[l] = lookup_map[location_name]; + } + + return result; +} +static +{ + string [location] __constant_clickable_urls; + void initialiseConstantClickableURLs() + { + string [string] lookup_map; + + lookup_map["Pump Up Muscle"] = "place.php?whichplace=knoll_friendly&action=dk_gym"; + lookup_map["Richard's Hobo Mysticality"] = "clan_hobopolis.php?place=3"; + lookup_map["Richard's Hobo Moxie"] = "clan_hobopolis.php?place=3"; + lookup_map["Richard's Hobo Muscle"] = "clan_hobopolis.php?place=3"; + lookup_map["South of the Border"] = "place.php?whichplace=desertbeach"; + lookup_map["The Oasis"] = "place.php?whichplace=desertbeach"; + lookup_map["The Arid, Extra-Dry Desert"] = "place.php?whichplace=desertbeach"; + lookup_map["The Shore, Inc. Travel Agency"] = "place.php?whichplace=desertbeach"; + lookup_map["The Upper Chamber"] = "pyramid.php"; + lookup_map["The Middle Chamber"] = "pyramid.php"; + lookup_map["The Lower Chambers"] = "pyramid.php"; + lookup_map["Goat Party"] = "casino.php"; + lookup_map["Pirate Party"] = "casino.php"; + lookup_map["Lemon Party"] = "casino.php"; + lookup_map["The Roulette Tables"] = "casino.php"; + lookup_map["The Poker Room"] = "casino.php"; + lookup_map["The Haiku Dungeon"] = "da.php"; + lookup_map["The Limerick Dungeon"] = "da.php"; + lookup_map["The Enormous Greater-Than Sign"] = "da.php"; + lookup_map["The Dungeons of Doom"] = "da.php"; + lookup_map["The Daily Dungeon"] = "da.php"; + lookup_map["[DungeonFAQ - Level 1]"] = "place.php?whichplace=faqdungeon"; + lookup_map["[DungeonFAQ - Level 2]"] = "place.php?whichplace=faqdungeon"; + lookup_map["[DungeonFAQ - Level 3]"] = "place.php?whichplace=faqdungeon"; + lookup_map["A Maze of Sewer Tunnels"] = "clan_hobopolis.php"; + lookup_map["Hobopolis Town Square"] = "clan_hobopolis.php?place=2"; + lookup_map["Burnbarrel Blvd."] = "clan_hobopolis.php?place=4"; + lookup_map["Exposure Esplanade"] = "clan_hobopolis.php?place=5"; + lookup_map["The Heap"] = "clan_hobopolis.php?place=6"; + lookup_map["The Ancient Hobo Burial Ground"] = "clan_hobopolis.php?place=7"; + lookup_map["The Purple Light District"] = "clan_hobopolis.php?place=8"; + lookup_map["The Slime Tube"] = "clan_slimetube.php"; + lookup_map["Dreadsylvanian Woods"] = "clan_dreadsylvania.php"; + lookup_map["Dreadsylvanian Village"] = "clan_dreadsylvania.php"; + lookup_map["Dreadsylvanian Castle"] = "clan_dreadsylvania.php"; + lookup_map["The Briny Deeps"] = "place.php?whichplace=thesea"; + lookup_map["The Brinier Deepers"] = "place.php?whichplace=thesea"; + lookup_map["The Briniest Deepests"] = "place.php?whichplace=thesea"; + lookup_map["An Octopus's Garden"] = "seafloor.php"; + lookup_map["The Wreck of the Edgar Fitzsimmons"] = "seafloor.php"; + lookup_map["Madness Reef"] = "seafloor.php"; + lookup_map["The Mer-Kin Outpost"] = "seafloor.php"; + lookup_map["The Skate Park"] = "seafloor.php"; + lookup_map["The Marinara Trench"] = "seafloor.php"; + lookup_map["Anemone Mine"] = "seafloor.php"; + lookup_map["The Dive Bar"] = "seafloor.php"; + lookup_map["The Coral Corral"] = "seafloor.php"; + lookup_map["Mer-kin Elementary School"] = "sea_merkin.php?seahorse=1"; + lookup_map["Mer-kin Library"] = "sea_merkin.php?seahorse=1"; + lookup_map["Mer-kin Gymnasium"] = "sea_merkin.php?seahorse=1"; + lookup_map["Mer-kin Colosseum"] = "sea_merkin.php?seahorse=1"; + lookup_map["The Caliginous Abyss"] = "seafloor.php"; + lookup_map["Anemone Mine (Mining)"] = "seafloor.php"; + lookup_map["The Sleazy Back Alley"] = "place.php?whichplace=town_wrong"; + lookup_map["The Copperhead Club"] = "place.php?whichplace=town_wrong"; + lookup_map["The Haunted Kitchen"] = "place.php?whichplace=manor1"; + lookup_map["The Haunted Conservatory"] = "place.php?whichplace=manor1"; + lookup_map["The Haunted Library"] = "place.php?whichplace=manor1"; + lookup_map["The Haunted Billiards Room"] = "place.php?whichplace=manor1"; + lookup_map["The Haunted Pantry"] = "place.php?whichplace=manor1"; + lookup_map["The Haunted Gallery"] = "place.php?whichplace=manor2"; + lookup_map["The Haunted Bathroom"] = "place.php?whichplace=manor2"; + lookup_map["The Haunted Bedroom"] = "place.php?whichplace=manor2"; + lookup_map["The Haunted Ballroom"] = "place.php?whichplace=manor2"; + lookup_map["The Haunted Boiler Room"] = "place.php?whichplace=manor4"; + lookup_map["The Haunted Laundry Room"] = "place.php?whichplace=manor4"; + lookup_map["The Haunted Wine Cellar"] = "place.php?whichplace=manor4"; + lookup_map["The Haunted Laboratory"] = "place.php?whichplace=manor3"; + lookup_map["The Haunted Nursery"] = "place.php?whichplace=manor3"; + lookup_map["The Haunted Storage Room"] = "place.php?whichplace=manor3"; + lookup_map["Summoning Chamber"] = "place.php?whichplace=manor4"; + lookup_map["The Hidden Apartment Building"] = "place.php?whichplace=hiddencity"; + lookup_map["The Hidden Hospital"] = "place.php?whichplace=hiddencity"; + lookup_map["The Hidden Office Building"] = "place.php?whichplace=hiddencity"; + lookup_map["The Hidden Bowling Alley"] = "place.php?whichplace=hiddencity"; + lookup_map["The Hidden Park"] = "place.php?whichplace=hiddencity"; + lookup_map["An Overgrown Shrine (Northwest)"] = "place.php?whichplace=hiddencity"; + lookup_map["An Overgrown Shrine (Southwest)"] = "place.php?whichplace=hiddencity"; + lookup_map["An Overgrown Shrine (Northeast)"] = "place.php?whichplace=hiddencity"; + lookup_map["An Overgrown Shrine (Southeast)"] = "place.php?whichplace=hiddencity"; + lookup_map["A Massive Ziggurat"] = "place.php?whichplace=hiddencity"; + lookup_map["The Typical Tavern Cellar"] = "cellar.php"; + lookup_map["The Spooky Forest"] = "place.php?whichplace=woods"; + lookup_map["The Hidden Temple"] = "place.php?whichplace=woods"; + lookup_map["A Barroom Brawl"] = "tavern.php"; + lookup_map["8-Bit Realm"] = "place.php?whichplace=woods"; + lookup_map["Whitey's Grove"] = "place.php?whichplace=woods"; + lookup_map["The Road to the White Citadel"] = "place.php?whichplace=woods"; + lookup_map["The Black Forest"] = "place.php?whichplace=woods"; + lookup_map["The Old Landfill"] = "place.php?whichplace=woods"; + lookup_map["The Bat Hole Entrance"] = "place.php?whichplace=bathole"; + lookup_map["Guano Junction"] = "place.php?whichplace=bathole"; + lookup_map["The Batrat and Ratbat Burrow"] = "place.php?whichplace=bathole"; + lookup_map["The Beanbat Chamber"] = "place.php?whichplace=bathole"; + lookup_map["The Boss Bat's Lair"] = "place.php?whichplace=bathole"; + lookup_map["The Red Queen's Garden"] = "place.php?whichplace=rabbithole"; + lookup_map["The Clumsiness Grove"] = "suburbandis.php"; + lookup_map["The Maelstrom of Lovers"] = "suburbandis.php"; + lookup_map["The Glacier of Jerks"] = "suburbandis.php"; + lookup_map["The Degrassi Knoll Restroom"] = "place.php?whichplace=knoll_hostile"; + lookup_map["The Degrassi Knoll Bakery"] = "place.php?whichplace=knoll_hostile"; + lookup_map["The Degrassi Knoll Gym"] = "place.php?whichplace=knoll_hostile"; + lookup_map["The Degrassi Knoll Garage"] = "place.php?whichplace=knoll_hostile"; + lookup_map["The \"Fun\" House"] = "place.php?whichplace=plains"; + lookup_map["The Unquiet Garves"] = "place.php?whichplace=cemetery"; + lookup_map["The VERY Unquiet Garves"] = "place.php?whichplace=cemetery"; + lookup_map["Tower Ruins"] = "fernruin.php"; + lookup_map["Fernswarthy's Basement"] = "basement.php"; + lookup_map["Cobb's Knob Barracks"] = "cobbsknob.php"; + lookup_map["Cobb's Knob Kitchens"] = "cobbsknob.php"; + lookup_map["Cobb's Knob Harem"] = "cobbsknob.php"; + lookup_map["Cobb's Knob Treasury"] = "cobbsknob.php"; + lookup_map["Throne Room"] = "cobbsknob.php"; + lookup_map["Cobb's Knob Laboratory"] = "cobbsknob.php?action=tolabs"; + lookup_map["The Knob Shaft"] = "cobbsknob.php?action=tolabs"; + lookup_map["The Knob Shaft (Mining)"] = "cobbsknob.php?action=tolabs"; + lookup_map["Cobb's Knob Menagerie, Level 1"] = "cobbsknob.php?action=tomenagerie"; + lookup_map["Cobb's Knob Menagerie, Level 2"] = "cobbsknob.php?action=tomenagerie"; + lookup_map["Cobb's Knob Menagerie, Level 3"] = "cobbsknob.php?action=tomenagerie"; + lookup_map["The Dark Neck of the Woods"] = "friars.php"; + lookup_map["The Dark Heart of the Woods"] = "friars.php"; + lookup_map["The Dark Elbow of the Woods"] = "friars.php"; + lookup_map["Friar Ceremony Location"] = "friars.php"; + lookup_map["Pandamonium Slums"] = "pandamonium.php"; + lookup_map["The Laugh Floor"] = "pandamonium.php?action=beli"; + lookup_map["Infernal Rackets Backstage"] = "pandamonium.php?action=infe"; + lookup_map["The Defiled Nook"] = "crypt.php"; + lookup_map["The Defiled Cranny"] = "crypt.php"; + lookup_map["The Defiled Alcove"] = "crypt.php"; + lookup_map["The Defiled Niche"] = "crypt.php"; + lookup_map["Haert of the Cyrpt"] = "crypt.php"; + lookup_map["The Orcish Frat House"] = "island.php"; + lookup_map["Frat House In Disguise"] = "island.php"; + lookup_map["Frat House (frat disguise)"] = "island.php"; + lookup_map["The Frat House (Bombed Back to the Stone Age)"] = "island.php"; + lookup_map["The Hippy Camp"] = "island.php"; + lookup_map["Hippy Camp In Disguise"] = "island.php"; + lookup_map["Hippy Camp (hippy disguise)"] = "island.php"; + lookup_map["The Hippy Camp (Bombed Back to the Stone Age)"] = "island.php"; + lookup_map["The Obligatory Pirate's Cove"] = "island.php"; + lookup_map["Barrrney's Barrr"] = "place.php?whichplace=cove"; + lookup_map["The F'c'le"] = "place.php?whichplace=cove"; + lookup_map["The Poop Deck"] = "place.php?whichplace=cove"; + lookup_map["Belowdecks"] = "place.php?whichplace=cove"; + lookup_map["Post-War Junkyard"] = "island.php"; + lookup_map["McMillicancuddy's Farm"] = "island.php"; + lookup_map["The Battlefield (Frat Uniform)"] = "bigisland.php"; + lookup_map["The Battlefield (Hippy Uniform)"] = "bigisland.php"; + lookup_map["Wartime Frat House"] = "island.php"; + lookup_map["Wartime Frat House (Hippy Disguise)"] = "island.php"; + lookup_map["Wartime Hippy Camp"] = "island.php"; + lookup_map["Wartime Hippy Camp (Frat Disguise)"] = "island.php"; + lookup_map["Next to that Barrel with Something Burning in it"] = "bigisland.php?place=junkyard"; + lookup_map["Near an Abandoned Refrigerator"] = "bigisland.php?place=junkyard"; + lookup_map["Over Where the Old Tires Are"] = "bigisland.php?place=junkyard"; + lookup_map["Out by that Rusted-Out Car"] = "bigisland.php?place=junkyard"; + lookup_map["Sonofa Beach"] = "bigisland.php?place=lighthouse"; + lookup_map["The Themthar Hills"] = "bigisland.php?place=nunnery"; + lookup_map["McMillicancuddy's Barn"] = "bigisland.php?place=farm"; + lookup_map["McMillicancuddy's Pond"] = "bigisland.php?place=farm"; + lookup_map["McMillicancuddy's Back 40"] = "bigisland.php?place=farm"; + lookup_map["McMillicancuddy's Other Back 40"] = "bigisland.php?place=farm"; + lookup_map["McMillicancuddy's Granary"] = "bigisland.php?place=farm"; + lookup_map["McMillicancuddy's Bog"] = "bigisland.php?place=farm"; + lookup_map["McMillicancuddy's Family Plot"] = "bigisland.php?place=farm"; + lookup_map["McMillicancuddy's Shady Thicket"] = "bigisland.php?place=farm"; + lookup_map["The Hatching Chamber"] = "bigisland.php?place=orchard"; + lookup_map["The Feeding Chamber"] = "bigisland.php?place=orchard"; + lookup_map["The Royal Guard Chamber"] = "bigisland.php?place=orchard"; + lookup_map["The Filthworm Queen's Chamber"] = "bigisland.php?place=orchard"; + lookup_map["Noob Cave"] = "tutorial.php"; + lookup_map["The Dire Warren"] = "tutorial.php"; + lookup_map["The Valley of Rof L'm Fao"] = "place.php?whichplace=mountains"; + lookup_map["Mt. Molehill"] = "place.php?whichplace=mountains"; + lookup_map["The Barrel Full of Barrels"] = "barrel.php"; + lookup_map["The Smut Orc Logging Camp"] = "place.php?whichplace=orc_chasm"; + lookup_map["The Thinknerd Warehouse"] = "place.php?whichplace=mountains"; + lookup_map["A Mob of Zeppelin Protesters"] = "place.php?whichplace=zeppelin"; + lookup_map["The Red Zeppelin"] = "place.php?whichplace=zeppelin"; + lookup_map["A-Boo Peak"] = "place.php?whichplace=highlands"; + lookup_map["Twin Peak"] = "place.php?whichplace=highlands"; + lookup_map["Oil Peak"] = "place.php?whichplace=highlands"; + lookup_map["Itznotyerzitz Mine"] = "place.php?whichplace=mclargehuge"; + lookup_map["The Goatlet"] = "place.php?whichplace=mclargehuge"; + lookup_map["Lair of the Ninja Snowmen"] = "place.php?whichplace=mclargehuge"; + lookup_map["The eXtreme Slope"] = "place.php?whichplace=mclargehuge"; + lookup_map["Mist-Shrouded Peak"] = "place.php?whichplace=mclargehuge"; + lookup_map["The Icy Peak"] = "place.php?whichplace=mclargehuge"; + lookup_map["Itznotyerzitz Mine (in Disguise)"] = "place.php?whichplace=mclargehuge"; + lookup_map["The Penultimate Fantasy Airship"] = "place.php?whichplace=beanstalk"; + lookup_map["The Castle in the Clouds in the Sky (Basement)"] = "place.php?whichplace=giantcastle"; + lookup_map["The Castle in the Clouds in the Sky (Ground Floor)"] = "place.php?whichplace=giantcastle"; + lookup_map["The Castle in the Clouds in the Sky (Top Floor)"] = "place.php?whichplace=giantcastle"; + lookup_map["The Hole in the Sky"] = "place.php?whichplace=beanstalk"; + lookup_map["The Broodling Grounds"] = "volcanoisland.php"; + lookup_map["The Outer Compound"] = "volcanoisland.php"; + lookup_map["The Temple Portico"] = "volcanoisland.php"; + lookup_map["Convention Hall Lobby"] = "volcanoisland.php"; + lookup_map["Outside the Club"] = "volcanoisland.php"; + lookup_map["The Island Barracks"] = "volcanoisland.php"; + lookup_map["The Nemesis' Lair"] = "volcanoisland.php"; + lookup_map["The Bugbear Pen"] = "place.php?whichplace=knoll_friendly"; + lookup_map["The Spooky Gravy Burrow"] = "place.php?whichplace=knoll_friendly"; + lookup_map["The Stately Pleasure Dome"] = "place.php?whichplace=wormwood"; + lookup_map["The Mouldering Mansion"] = "place.php?whichplace=wormwood"; + lookup_map["The Rogue Windmill"] = "place.php?whichplace=wormwood"; + lookup_map["The Primordial Soup"] = "place.php?whichplace=memories"; + lookup_map["The Jungles of Ancient Loathing"] = "place.php?whichplace=memories"; + lookup_map["Seaside Megalopolis"] = "place.php?whichplace=memories"; + lookup_map["Domed City of Ronaldus"] = "place.php?whichplace=spaaace"; + lookup_map["Domed City of Grimacia"] = "place.php?whichplace=spaaace"; + lookup_map["Hamburglaris Shield Generator"] = "place.php?whichplace=spaaace"; + lookup_map["The Arrrboretum"] = "place.php?whichplace=woods"; + lookup_map["Spectral Pickle Factory"] = "place.php?whichplace=plains"; + lookup_map["Lollipop Forest"] = ""; + lookup_map["Fudge Mountain"] = ""; + lookup_map["WarBear Fortress (First Level)"] = ""; + lookup_map["WarBear Fortress (Second Level)"] = ""; + lookup_map["WarBear Fortress (Third Level)"] = ""; + lookup_map["Elf Alley"] = ""; + lookup_map["CRIMBCO cubicles"] = ""; + lookup_map["CRIMBCO WC"] = ""; + lookup_map["Crimbo Town Toy Factory (2005)"] = ""; + lookup_map["The Don's Crimbo Compound"] = ""; + lookup_map["Atomic Crimbo Toy Factory"] = ""; + lookup_map["Crimbo Town Toy Factory (2007)"] = ""; + lookup_map["Sinister Dodecahedron"] = ""; + lookup_map["Crimbo Town Toy Factory (2009)"] = ""; + lookup_map["Simple Tool-Making Cave"] = ""; + lookup_map["Spooky Fright Factory"] = ""; + lookup_map["Crimborg Collective Factory"] = ""; + lookup_map["Crimbo Town Toy Factory (2012)"] = ""; + lookup_map["Market Square, 28 Days Later"] = ""; + lookup_map["The Mall of Loathing, 28 Days Later"] = ""; + lookup_map["Wrong Side of the Tracks, 28 Days Later"] = ""; + lookup_map["The Icy Peak in The Recent Past"] = ""; + lookup_map["Shivering Timbers"] = ""; + lookup_map["A Skeleton Invasion!"] = ""; + lookup_map["The Cannon Museum"] = ""; + lookup_map["A Swarm of Yeti-Mounted Skeletons"] = ""; + lookup_map["The Bonewall"] = ""; + lookup_map["A Massive Flying Battleship"] = ""; + lookup_map["A Supply Train"] = ""; + lookup_map["The Bone Star"] = ""; + lookup_map["Grim Grimacite Site"] = ""; + lookup_map["A Pile of Old Servers"] = ""; + lookup_map["The Haunted Sorority House"] = ""; + lookup_map["Fightin' Fire"] = ""; + lookup_map["Super-Intense Mega-Grassfire"] = ""; + lookup_map["Fierce Flying Flames"] = ""; + lookup_map["Lord Flameface's Castle Entryway"] = ""; + lookup_map["Lord Flameface's Castle Belfry"] = ""; + lookup_map["Lord Flameface's Throne Room"] = ""; + lookup_map["A Stinking Abyssal Portal"] = ""; + lookup_map["A Scorching Abyssal Portal"] = ""; + lookup_map["A Terrifying Abyssal Portal"] = ""; + lookup_map["A Freezing Abyssal Portal"] = ""; + lookup_map["An Unsettling Abyssal Portal"] = ""; + lookup_map["A Yawning Abyssal Portal"] = ""; + lookup_map["The Space Odyssey Discotheque"] = ""; + lookup_map["The Spirit World"] = ""; + lookup_map["Some Scattered Smoking Debris"] = "place.php?whichplace=crashsite"; + lookup_map["Anger Man's Level"] = "place.php?whichplace=junggate_3"; + lookup_map["Fear Man's Level"] = "place.php?whichplace=junggate_3"; + lookup_map["Doubt Man's Level"] = "place.php?whichplace=junggate_3"; + lookup_map["Regret Man's Level"] = "place.php?whichplace=junggate_3"; + lookup_map["The Nightmare Meatrealm"] = "place.php?whichplace=junggate_6"; + lookup_map["A Kitchen Drawer"] = "place.php?whichplace=junggate_5"; + lookup_map["A Grocery Bag"] = "place.php?whichplace=junggate_5"; + lookup_map["Chinatown Shops"] = "place.php?whichplace=junggate_1"; + lookup_map["Triad Factory"] = "place.php?whichplace=junggate_1"; + lookup_map["1st Floor, Shiawase-Mitsuhama Building"] = "place.php?whichplace=junggate_1"; + lookup_map["2nd Floor, Shiawase-Mitsuhama Building"] = "place.php?whichplace=junggate_1"; + lookup_map["3rd Floor, Shiawase-Mitsuhama Building"] = "place.php?whichplace=junggate_1"; + lookup_map["Chinatown Tenement"] = "place.php?whichplace=junggate_1"; + lookup_map["The Gourd!"] = "place.php?whichplace=junggate_2"; + lookup_map["A Deserted Stretch of I-911"] = "place.php?whichplace=ioty2014_hare"; + lookup_map["The Prince's Restroom"] = "place.php?whichplace=ioty2014_cindy"; + lookup_map["The Prince's Dance Floor"] = "place.php?whichplace=ioty2014_cindy"; + lookup_map["The Prince's Kitchen"] = "place.php?whichplace=ioty2014_cindy"; + lookup_map["The Prince's Balcony"] = "place.php?whichplace=ioty2014_cindy"; + lookup_map["The Prince's Lounge"] = "place.php?whichplace=ioty2014_cindy"; + lookup_map["The Prince's Canapes table"] = "place.php?whichplace=ioty2014_cindy"; + lookup_map["The Inner Wolf Gym"] = "place.php?whichplace=ioty2014_wolf"; + lookup_map["Unleash Your Inner Wolf"] = "place.php?whichplace=ioty2014_wolf"; + lookup_map["The Crimbonium Mining Camp"] = "place.php?whichplace=desertbeach"; + lookup_map["Kokomo Resort"] = "place.php?whichplace=desertbeach"; + lookup_map["The Crimbonium Mine"] = "mining.php?mine=5"; + lookup_map["The Secret Council Warehouse"] = "tutorial.php"; + lookup_map["The Skeleton Store"] = "place.php?whichplace=town_market"; + lookup_map["Madness Bakery"] = "place.php?whichplace=town_right"; + lookup_map["Investigating a Plaintive Telegram"] = "place.php?whichplace=town_right"; + lookup_map["The Fungal Nethers"] = "place.php?whichplace=nemesiscave"; + lookup_map["Thugnderdome"] = "gnomes.php"; + lookup_map["The Overgrown Lot"] = "place.php?whichplace=town_wrong"; + lookup_map["The Canadian Wildlife Preserve"] = "place.php?whichplace=mountains"; + foreach s in $strings[The Hallowed Halls,Shop Class,Chemistry Class,Art Class] + lookup_map[s] = "place.php?whichplace=KOLHS"; + foreach s in $strings[The Edge of the Swamp,The Dark and Spooky Swamp,The Corpse Bog,The Ruined Wizard Tower,The Wildlife Sanctuarrrrrgh,Swamp Beaver Territory,The Weird Swamp Village] + lookup_map[s] = "place.php?whichplace=marais"; + foreach s in $strings[Ye Olde Medievale Villagee,Portal to Terrible Parents,Rumpelstiltskin's Workshop] + lookup_map[s] = "place.php?whichplace=ioty2014_rumple"; + + foreach s in $strings[The Cave Before Time,An Illicit Bohemian Party,Moonshiners' Woods,The Roman Forum,The Post-Mall,The Rowdy Saloon,The Spooky Old Abandoned Mine,Globe Theatre Main Stage,Globe Theatre Backstage,12 West Main,KoL Con Clan Party House] + lookup_map[s] = "place.php?whichplace=twitch"; + foreach s in $strings[The Fun-Guy Mansion,Sloppy Seconds Diner,The Sunken Party Yacht] + lookup_map[s] = "place.php?whichplace=airport_sleaze"; + foreach s in $strings[The Mansion of Dr. Weirdeaux,The Deep Dark Jungle,The Secret Government Laboratory] + lookup_map[s] = "place.php?whichplace=airport_spooky"; + foreach s in $strings[Pirates of the Garbage Barges,Barf Mountain,The Toxic Teacups,Uncle Gator's Country Fun-Time Liquid Waste Sluice] + lookup_map[s] = "place.php?whichplace=airport_stench"; + foreach s in $strings[The SMOOCH Army HQ,The Velvet / Gold Mine,LavaCo™ Lamp Factory,The Bubblin' Caldera] + lookup_map[s] = "place.php?whichplace=airport_hot"; + foreach s in $strings[The Ice Hotel,VYKEA,The Ice Hole] + lookup_map[s] = "place.php?whichplace=airport_cold"; + lookup_map["The Velvet / Gold Mine (Mining)"] = "mining.php?mine=6"; + foreach s in $strings[The Mines,The Jungle,The Ice Caves,The Temple Ruins,Hell,The Snake Pit,The Spider Hole,The Ancient Burial Ground,The Beehive,the crashed u. f. o.,The City of Goooold,LOLmec's Lair,Yomama's Throne] + lookup_map[s] = "place.php?whichplace=spelunky"; + + foreach s in $strings[Medbay,Waste Processing,Sonar,Science Lab,Morgue,Special Ops,Engineering,Navigation,Galley] + lookup_map[s] = "place.php?whichplace=bugbearship"; + foreach s in $strings[Sweet-Ade Lake,Eager Rice Burrows,Gumdrop Forest] + lookup_map[s] = "place.php?whichplace=ioty2014_candy"; + foreach s in $strings[Gingerbread Industrial Zone,Gingerbread Train Station,Gingerbread Sewers,Gingerbread Upscale Retail District] + lookup_map[s] = "place.php?whichplace=gingerbreadcity"; + + foreach s in $strings[Fastest Adventurer Contest,Strongest Adventurer Contest,Smartest Adventurer Contest,Smoothest Adventurer Contest,A Crowd of (Stat) Adventurers,Hottest Adventurer Contest,Coldest Adventurer Contest,Spookiest Adventurer Contest,Stinkiest Adventurer Contest,Sleaziest Adventurer Contest,A Crowd of (Element) Adventurers,The Hedge Maze,Tower Level 1,Tower Level 2,Tower Level 3,Tower Level 4,Tower Level 5,The Naughty Sorceress' Chamber] + lookup_map[s] = "place.php?whichplace=nstower"; + + lookup_map["Trick-or-treating"] = "place.php?whichplace=town&action=town_trickortreat"; + lookup_map["The Deep Machine Tunnels"] = "place.php?whichplace=dmt"; + + lookup_map["The Ruins of the Fully Automated Crimbo Factory"] = "place.php?whichplace=crimbo2015"; + lookup_map["The X-32-F Combat Training Snowman"] = "place.php?whichplace=snojo"; + foreach s in $strings[Your Bung Chakra,Your Guts Chakra,Your Liver Chakra,Your Nipple Chakra,Your Nose Chakra,Your Hat Chakra] + lookup_map[s] = "place.php?whichplace=crimbo2016m"; + foreach s in $strings[Crimbo's Sack,Crimbo's Boots,Crimbo's Jelly,Crimbo's Reindeer,Crimbo's Beard,Crimbo's Hat] + lookup_map[s] = "place.php?whichplace=crimbo2016c"; + foreach s in $strings[The Cheerless Spire (Level 1), The Cheerless Spire (Level 2), The Cheerless Spire (Level 3), The Cheerless Spire (Level 4), The Cheerless Spire (Level 5)] + lookup_map[s] = "place.php?whichplace=crimbo17_silentnight"; + foreach s in $strings[The Bandit Crossroads,The Putrid Swamp,Near the Witch's House,The Troll Fortress,The Sprawling Cemetery,The Cursed Village,The Foreboding Cave,The Faerie Cyrkle,The Evil Cathedral,The Towering Mountains,The Mystic Wood,The Druidic Campsite,The Old Rubee Mine] + lookup_map[s] = "place.php?whichplace=realm_fantasy"; + foreach s in $strings[PirateRealm Island,Sailing the PirateRealm Seas] + lookup_map[s] = "place.php?whichplace=realm_pirate"; + lookup_map["An Eldritch Horror"] = "place.php?whichplace=town"; + lookup_map["The Neverending Party"] = "place.php?whichplace=town_wrong"; + lookup_map["Through the Spacegate"] = "place.php?whichplace=spacegate"; + lookup_map["The Exploaded Battlefield"] = "place.php?whichplace=exploathing"; + __constant_clickable_urls = LAConvertLocationLookupToLocations(lookup_map); + } + initialiseConstantClickableURLs(); +} + +string [location] __variable_clickable_urls; +string getClickableURLForLocation(location l, Error unable_to_find_url) +{ + if (l == $location[none]) + return ""; + if (__constant_clickable_urls contains l) + return __constant_clickable_urls[l]; + + if (__variable_clickable_urls.count() == 0) + { + //Initialize: + //We use to_location() lookups here because $location[] will halt the script if the location name changes. + //Probably could move this to an external data file. + string [string] lookup_map; + + //Conditionals only: + if ($location[cobb\'s knob barracks].locationAvailable()) + lookup_map["The Outskirts of Cobb's Knob"] = "cobbsknob.php"; + else + lookup_map["The Outskirts of Cobb's Knob"] = "place.php?whichplace=plains"; + + if (knoll_available()) + lookup_map["Post-Quest Bugbear Pens"] = "place.php?whichplace=knoll_friendly"; + else + lookup_map["Post-Quest Bugbear Pens"] = "place.php?whichplace=knoll_hostile"; + + if ($item[talisman o\' namsilat].equipped_amount() > 0) + lookup_map["Inside the Palindome"] = "place.php?whichplace=palindome"; + else + lookup_map["Inside the Palindome"] = "inventory.php?ftext=talisman+o\'+namsilat"; + //antique maps are weird: + lookup_map["The Electric Lemonade Acid Parade"] = "inv_use.php?pwd=" + my_hash() + "&whichitem=4613"; + foreach s in $strings[Professor Jacking's Small-O-Fier,Professor Jacking's Huge-A-Ma-tron] + lookup_map[s] = "inv_use.php?pwd=" + my_hash() + "&whichitem=4560"; + + //Parse into locations: + __variable_clickable_urls = LAConvertLocationLookupToLocations(lookup_map); + } + if (__variable_clickable_urls contains l) + return __variable_clickable_urls[l]; + + ErrorSet(unable_to_find_url); + return ""; +} + +string getClickableURLForLocation(location l) +{ + return l.getClickableURLForLocation(ErrorMake()); +} + +string getClickableURLForLocationIfAvailable(location l) +{ + Error able_to_find; + boolean found = l.locationAvailable(able_to_find); + if (able_to_find.was_error) //assume it's available, since we don't know + found = true; + if (found) + return l.getClickableURLForLocation(); + else + return ""; +} + + + +void locationAvailableRunDiagnostics() +{ + location [string][int] unknown_locations_by_zone; + + foreach loc in $locations[] + { + Error able_to_find; + locationAvailable(loc, able_to_find); + if (!able_to_find.was_error) + continue; + if (!(unknown_locations_by_zone contains (loc.zone))) + unknown_locations_by_zone[loc.zone] = listMakeBlankLocation(); + unknown_locations_by_zone[loc.zone].listAppend(loc); + } + if (unknown_locations_by_zone.count() > 0) + { + print_html("Unknown locations in location availability tester:"); + foreach zone in unknown_locations_by_zone + { + print(zone + ":"); + foreach key in unknown_locations_by_zone[zone] + { + location loc = unknown_locations_by_zone[zone][key]; + print_html("      " + loc); + } + } + } + /*print_html("Missing URLs:"); + foreach loc in $locations[] + { + if (loc.parent == "Removed") continue; + if (loc.getClickableURLForLocation() == "") + print_html(loc.parent + ": " + loc.zone + ": " + loc); + }*/ +} + +/*void main() +{ + locationAvailableRunDiagnostics(); +}*/ + + +Record EquipmentStatRequirement +{ + stat requirement_stat; + int requirement_amount; +}; +static +{ + EquipmentStatRequirement [item] __equipment_stat_requirements; +} + +void initialiseEquipmentRequirements() +{ + if (__equipment_stat_requirements.count() > 0) + return; + Record equipment_txt_entry + { + int power; + string requirement; + string weapon_description; + }; + equipment_txt_entry [item] entries; + file_to_map("data/equipment.txt", entries); + + foreach it, entry in entries + { + if (entry.requirement == "" || entry.requirement == "none") + continue; + int requirement_integer = entry.requirement.split_string(" ")[1].to_int_silent(); + if (requirement_integer <= 0) + continue; + stat known_stat = $stat[none]; + if (entry.requirement.contains_text("Mus: ")) + { + known_stat = $stat[muscle]; + } + else if (entry.requirement.contains_text("Mys: ")) + { + known_stat = $stat[mysticality]; + } + else if (entry.requirement.contains_text("Mox: ")) + { + known_stat = $stat[moxie]; + } + if (known_stat != $stat[none]) + { + EquipmentStatRequirement requirement; + requirement.requirement_stat = known_stat; + requirement.requirement_amount = requirement_integer; + + __equipment_stat_requirements[it] = requirement; + //__equipment_stat_requirements[it][known_stat] = requirement_integer; + } + } +} +EquipmentStatRequirement StatRequirementForEquipment(item it) +{ + initialiseEquipmentRequirements(); + return __equipment_stat_requirements[it]; +} + + + +string HTMLGenerateFutureTextByLocationAvailability(string base_text, location place) +{ + if (!place.locationAvailable() && place != $location[none]) + { + base_text = HTMLGenerateSpanOfClass(base_text, "r_future_option"); + } + return base_text; +} + +string HTMLGenerateFutureTextByLocationAvailability(location place) +{ + return HTMLGenerateFutureTextByLocationAvailability(place.to_string(), place); +} + +//Alternate name, since last time I tried making this function then discovered the "generate future text" options which I cleverly named in such a way that I would never find it +string HTMLGreyOutIfLocationUnavailable(string source, location l) +{ + return HTMLGenerateFutureTextByLocationAvailability(source, l); +} +string HTMLBoldIfTrue(string base_text, boolean conditional) +{ + if (conditional) + return HTMLGenerateSpanOfClass(base_text, "r_bold"); + return base_text; +} + + +boolean can_equip_replacement(item it) +{ + if (it.equipped_amount() > 0) + return true; + if (it.item_type() == "chefstaff" && !($skill[Spirit of Rigatoni].have_skill() || my_class() == $class[Avatar of Jarlsberg] || (my_class() == $class[sauceror] && $item[special sauce glove].equipped_amount() > 0))) + return false; + boolean can_equip = it.can_equip(); + if (can_equip) + return true; + if (my_class() == $class[pastamancer]) + { + //Bind Undead Elbow Macaroni -> equalises muscle + //Bind Penne Dreadful -> equalises moxie + EquipmentStatRequirement requirement = it.StatRequirementForEquipment(); + + if (requirement.requirement_stat == $stat[none]) + return true; + if (my_basestat(requirement.requirement_stat) >= requirement.requirement_amount) + return true; + if (requirement.requirement_stat == $stat[mysticality]) + return false; + + if (requirement.requirement_stat == $stat[muscle]) + { + if ($skill[bind undead elbow macaroni].have_skill() && my_basestat($stat[mysticality]) >= requirement.requirement_amount) + return true; + } + else if (requirement.requirement_stat == $stat[moxie]) + { + if ($skill[Bind Penne Dreadful].have_skill() && my_basestat($stat[mysticality]) >= requirement.requirement_amount) + return true; + } + } + return can_equip; +} + +boolean can_equip_outfit(string outfit_name) +{ + if (!have_outfit_components(outfit_name)) + return false; + item [int] outfit_pieces = outfit_pieces(outfit_name); + foreach key, it in outfit_pieces + { + if (!it.can_equip_replacement()) + return false; + } + return true; +} + + +//Probably not a good place for it: +boolean asdonMartinFailsFuelableTestsPrivate(item craft, boolean [item] ingredients_blacklisted, boolean [item] crafts_seen) +{ + //if ($items[wad of dough,flat dough] contains craft) return false; + if (craft.craft_type().contains_text("(fancy)")) + return true; + crafts_seen[craft] = true; + boolean all_npc = true; + foreach it, amount in craft.get_ingredients_fast() + { + //print_html(craft + ": " + it); + if (ingredients_blacklisted[it]) return true; + if (!it.is_npc_item()) + all_npc = false; + + if (it.item_amount() >= amount) continue; + if (crafts_seen[it]) //wad of dough, flat dough, jolly roger charrrm + { + continue; + } + if (it.asdonMartinFailsFuelableTestsPrivate(ingredients_blacklisted, crafts_seen)) + return true; + } + if (craft.get_ingredients_fast().count() == 0) + all_npc = false; + if (all_npc && crafts_seen.count() == 0) //hmm... what if it's a second level all-NPC? + { + return true; + } + return false; +} + +boolean asdonMartinFailsFuelableTests(item craft, boolean [item] ingredients_blacklisted) +{ + boolean [item] crafts_seen; //slower than a "last item" test, but necessary (spooky wads) + return asdonMartinFailsFuelableTestsPrivate(craft, ingredients_blacklisted, crafts_seen); +} + +item [int] asdonMartinGenerateListOfFuelables() +{ + item [int] fuelables; + boolean [item] blacklist; + if (!QuestState("questL11Black").finished) //FIXME no + blacklist[$item[blackberry]] = true; //FIXME test properly? + blacklist[$item[stunt nuts]] = true; + blacklist[$item[wet stew]] = true; //FIXME I guess maybe not after + blacklist[$item[goat cheese]] = true; + blacklist[$item[turkey blaster]] = true; + blacklist[$item[hot wing]] = true; + blacklist[$item[glass of goat's milk]] = true; + blacklist[$item[soft green echo eyedrop antidote martini]] = true; //if it's not created, FIXME + blacklist[$item[warm gravy]] = true; //don't steal my boat + foreach it in $items[Falcon™ Maltese Liquor, hardboiled egg] + blacklist[it] = true; //don't steal my -combat + blacklist[$item[loaf of soda bread]] = true; //elsewhere + foreach it in $items[hot buttered roll,ketchup,catsup] + blacklist[it] = true; //hermit + + //These aren't directly feedable, but indirectly make things: + blacklist[$item[source essence]] = true; //that's silly + blacklist[$item[white pixel]] = true; //no! + blacklist[$item[cashew]] = true; + + if (my_path().id != PATH_LICENSE_TO_ADVENTURE && inebriety_limit() > 0) //FIXME the test for can drink just about + { + foreach it in $items[bottle of gin,bottle of rum,bottle of vodka,bottle of whiskey,bottle of tequila] //too useful for crafting? + blacklist[it] = true; + } + foreach it in $items[bottle of Calcutta Emerald,bottle of Lieutenant Freeman,bottle of Jorge Sinsonte,bottle of Definit,bottle of Domesticated Turkey,boxed champagne,bottle of Ooze-O,bottle of Pete's Sake,tangerine,kiwi,cocktail onion,kumquat,tonic water,raspberry] //nash crosby's still's results isn't feedable + blacklist[it] = true; + foreach it in __pvpable_food_and_drinks + { + if (blacklist[it]) continue; + if (it.is_npc_item()) continue; + if (it.historical_price() >= 20000) continue; + if (it.item_amount() == 0) + { + if (it.creatable_amount() == 0) + continue; + if (it.asdonMartinFailsFuelableTests(blacklist)) + { + continue; + } + } + if (my_path().id == PATH_LICENSE_TO_ADVENTURE && false) + { + if (it.inebriety > 0 && it.image == "martini.gif") + continue; + } + if (it.item_cannot_be_asdon_martined_because_it_was_purchased_from_a_store()) //the asdon martin wishes it was an AE86, so those work + { + //print_html("Rejecting " + it); + continue; + } + /*int [item] ingredients = it.get_ingredients_fast(); + if (ingredients.count() > 0) + { + boolean reject = false; + //Various things count as being from a "store": + foreach it in lookupItems("yellow pixel,handful of barley,spacegate research") + { + if (ingredients[it] > 0) + { + reject = true; + break; + } + } + if (reject) + continue; + }*/ + float average_adventures = it.averageAdventuresForConsumable(); + if (average_adventures == 0.0) + continue; + + float soda_bread_efficiency = to_float($item[wad of dough].npc_price() + $item[soda water].npc_price()) / 6.0; + if (soda_bread_efficiency < 1.0) soda_bread_efficiency = 100000.0; + if (it.autosell_price() > 0 && it.autosell_price().to_float() / average_adventures > soda_bread_efficiency) + { + continue; + } + fuelables.listAppend(it); + } + sort fuelables by -value.averageAdventuresForConsumable() * ((value.asdonMartinFailsFuelableTests(blacklist) ? 0 : value.creatable_amount()) + value.item_amount()); + return fuelables; +} + + + + +boolean craftableUsingOnlyActiveNPCStoresPrivate(item it, boolean [item] crafts_seen) +{ + if (it.npc_price() > 0) + return true; + + int [item] ingredients = it.get_ingredients_fast(); + if (ingredients.count() == 0) return false; + + if (crafts_seen[it]) + return true; + + crafts_seen[it] = true; + + foreach ingredient in ingredients + { + if (!craftableUsingOnlyActiveNPCStoresPrivate(ingredient, crafts_seen)) + { + return false; + } + } + return true; +} + +boolean craftableUsingOnlyActiveNPCStores(item it) +{ + boolean [item] crafts_seen; + return craftableUsingOnlyActiveNPCStoresPrivate(it, crafts_seen); +} + + +int CatBurglarChargesLeftToday() +{ + //FIXME this is totally wrong I think, fix this mafia + int charge = get_property_int("_catBurglarCharge"); + + int heists_gained_today = 0; + int limit = 10; + int c = charge; + while (c >= limit) + { + heists_gained_today += 1; + c -= limit; + limit *= 2; + } + int heists_complete = get_property_int("_catBurglarHeistsComplete"); + //print_html("heists_gained_today = " + heists_gained_today + ", heists_complete = " + heists_complete); + return get_property_int("catBurglarBankHeists") + heists_gained_today - heists_complete; +} + + +int PathCommunityServiceEstimateTurnsTakenForTask(string service_name) +{ + int turns = 60; + if (service_name == "Donate Blood") + { + turns = 60 - (my_maxhp() - (my_buffedstat($stat[muscle]) + 3)) / 30; + } + else if (service_name == "Coil Wire") + { + turns = 60; + } + else if (service_name == "Make Margaritas") + { + float item_drop = numeric_modifier("Item Drop"); + //Mafia adds item drop modifiers depending on our location. + //set_location() is slow, we want to avoid it. + //Manually correct: + if ($skill[Speluck].have_skill() && my_location().environment == "underground") + { + item_drop -= 5.0; + if ($effect[Steely-Eyed Squint].have_effect() > 0) + item_drop -= 5.0; + } + turns = 60 - (floor(item_drop / 30) + floor(numeric_modifier("Booze Drop") / 15)); + } + else if (service_name == "Feed The Children (But Not Too Much)" || service_name == "Build Playground Mazes" || service_name == "Feed Conspirators") + { + stat using_stat; + if (service_name == "Feed The Children (But Not Too Much)") + { + using_stat = $stat[muscle]; + } + else if (service_name == "Build Playground Mazes") + { + using_stat = $stat[mysticality]; + } + else if (service_name == "Feed Conspirators") + { + using_stat = $stat[moxie]; + } + int basestat = my_basestat(using_stat); + boolean relevant_thrall_active = false; + if (my_thrall() == $thrall[Elbow Macaroni] && using_stat == $stat[muscle]) + { + basestat = my_basestat($stat[mysticality]); + relevant_thrall_active = true; + } + if (my_thrall() == $thrall[Penne Dreadful] && using_stat == $stat[moxie]) + { + basestat = my_basestat($stat[mysticality]); + relevant_thrall_active = true; + } + + turns = 60 - (my_buffedstat(using_stat) - basestat) / 30; + } + else if (service_name == "Reduce Gazelle Population") + { + float modifier_1 = numeric_modifier("Weapon Damage"); + float modifier_2 = numeric_modifier("Weapon Damage Percent"); + + foreach s in $slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3,familiar] + { + item it = s.equipped_item(); + if (it.to_slot() != $slot[weapon]) continue; + int power = it.get_power(); + float addition = to_float(power) * 0.15; + + modifier_1 -= addition; + } + if ($effect[bow-legged swagger].have_effect() > 0) + { + modifier_1 *= 2; + modifier_2 *= 2; + } + turns = 60 - (floor(modifier_1 / 50 + 0.001) + floor(modifier_2 / 50 + 0.001)); + } + else if (service_name == "Make Sausage") + { + turns = 60 - (floor(numeric_modifier("Spell Damage") / 50 + 0.001) + floor(numeric_modifier("Spell Damage Percent") / 50 + 0.001)); + } + else if (service_name == "Clean Steam Tunnels") + { + turns = 60 - round(numeric_modifier("Hot Resistance")); + } + else if (service_name == "Breed More Collies") + { + int current_familiar_weight = my_familiar().effective_familiar_weight() + round(numeric_modifier("familiar weight")); + turns = 60 - floor(current_familiar_weight / 5); + } + else if (service_name == "Be a Living Statue") + { + int combat_rate_raw = round(numeric_modifier("Combat Rate")); + int combat_rate_inverse = 0; + if (combat_rate_raw < 0) combat_rate_inverse = -combat_rate_raw; + if (combat_rate_inverse > 25) combat_rate_inverse = (combat_rate_inverse - 25) * 5 + 25; + turns = 60 - (combat_rate_inverse / 5) * 3; + } + + turns = clampi(turns, 1, 60); + + return turns; +} + + + +Record KramcoSausageFightInformation +{ + boolean goblin_will_appear; + int turns_to_next_guaranteed_fight; + float probability_of_sausage_fight; +}; + +KramcoSausageFightInformation KramcoCalculateSausageFightInformation() { + KramcoSausageFightInformation information; + int goblinsFought = get_property_int("_sausageFights"); + int turnsSinceLastGoblin = total_turns_played() - get_property_int("_lastSausageMonsterTurn"); + + int nextGuaranteedGoblin = 4 + goblinsFought * 3 + MAX(0, goblinsFought - 5) * MAX(0, goblinsFought - 5) * MAX(0, goblinsFought - 5); + int turnsToNextGuaranteedFight = MAX(0, nextGuaranteedGoblin - turnsSinceLastGoblin); + + if (goblinsFought == 0) { + turnsToNextGuaranteedFight = 0; + } + + int goblinMultiplier = MAX(0, goblinsFought - 5); + float probabilityOfFight = to_float(turnsSinceLastGoblin + 1) / (5.0 + to_float(goblinsFought) * 3.0 + to_float(goblinMultiplier) * to_float(goblinMultiplier) * to_float(goblinMultiplier)); + + information.turns_to_next_guaranteed_fight = MAX(0, nextGuaranteedGoblin - turnsSinceLastGoblin); + information.probability_of_sausage_fight = clampf(probabilityOfFight, 0.0, 1.0); + information.goblin_will_appear = (turnsToNextGuaranteedFight == 0); + + return information; +} + + +record CSSEntry +{ + string tag; + string class_name; + string definition; + int importance; +}; + +CSSEntry CSSEntryMake(string tag, string class_name, string definition, int importance) +{ + CSSEntry entry; + entry.tag = tag; + entry.class_name = class_name; + entry.definition = definition; + entry.importance = importance; + return entry; +} + +record CSSBlock +{ + CSSEntry [int] defined_css_classes; + string identifier; +}; + +CSSBlock CSSBlockMake(string identifier) +{ + CSSBlock result; + result.identifier = identifier; + return result; +} + +buffer CSSBlockGenerate(CSSBlock block) +{ + buffer result; + + if (block.defined_css_classes.count() > 0) + { + boolean output_identifier = (block.identifier != ""); + if (output_identifier) + { + result.append("\t\t\t"); + result.append(block.identifier); + result.append(" {\n"); + } + sort block.defined_css_classes by value.importance; + + foreach key in block.defined_css_classes + { + CSSEntry entry = block.defined_css_classes[key]; + result.append("\t\t\t"); + if (output_identifier) + result.append("\t"); + + if (entry.class_name == "") + result.append(entry.tag + " { " + entry.definition + " }"); + else + { + result.append(entry.tag + ( entry.class_name.char_at(0) != "#" && entry.class_name.char_at(0) != "." ? "." : "") + entry.class_name + " { " + entry.definition + " }"); + } + result.append("\n"); + } + if (output_identifier) + result.append("\n\t\t\t}\n"); + } + return result; +} + +void listAppend(CSSEntry [int] list, CSSEntry entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +record Page +{ + string title; + buffer head_contents; + buffer body_contents; + string [string] body_attributes; //[attribute_name] -> attribute_value + + CSSBlock [string] defined_css_blocks; //There is always an implicit "" block. +}; + + +Page __global_page; + + + +Page Page() +{ + return __global_page; +} + +buffer PageGenerateBodyContents(Page page_in) +{ + return page_in.body_contents; +} + +buffer PageGenerateBodyContents() +{ + return Page().PageGenerateBodyContents(); +} + +buffer PageGenerateStyle(Page page_in) +{ + buffer result; + + if (page_in.defined_css_blocks.count() > 0) + { + if (true) + { + result.append("\t\t"); + result.append(HTMLGenerateTagPrefix("style", mapMake("type", "text/css"))); + result.append("\n"); + } + result.append(page_in.defined_css_blocks[""].CSSBlockGenerate()); //write first + foreach identifier in page_in.defined_css_blocks + { + CSSBlock block = page_in.defined_css_blocks[identifier]; + if (identifier == "") //skip, already written + continue; + result.append(block.CSSBlockGenerate()); + } + if (true) + { + result.append("\t\t\n"); + } + } + return result; +} + +buffer PageGenerateStyle() +{ + return Page().PageGenerateStyle(); +} + +buffer PageGenerate(Page page_in) +{ + buffer result; + + result.append("\n"); //HTML 5 target + result.append("\n"); + + //Head: + result.append("\t\n"); + result.append("\t\t"); + result.append(page_in.title); + result.append("\n"); + if (page_in.head_contents.length() != 0) + { + result.append("\t\t"); + result.append(page_in.head_contents); + result.append("\n"); + } + //Write CSS styles: + result.append(PageGenerateStyle(page_in)); + result.append("\t\n"); + + //Body: + result.append("\t"); + result.append(HTMLGenerateTagPrefix("body", page_in.body_attributes)); + result.append("\n\t\t"); + result.append(page_in.body_contents); + result.append("\n"); + + result.append("\t\n"); + + + result.append(""); + + return result; +} + +void PageGenerateAndWriteOut(Page page_in) +{ + write(PageGenerate(page_in)); +} + +void PageSetTitle(Page page_in, string title) +{ + page_in.title = title; +} + +void PageAddCSSClass(Page page_in, string tag, string class_name, string definition, int importance, string block_identifier) +{ + //print_html("Adding block_identifier \"" + block_identifier + "\""); + if (!(page_in.defined_css_blocks contains block_identifier)) + page_in.defined_css_blocks[block_identifier] = CSSBlockMake(block_identifier); + page_in.defined_css_blocks[block_identifier].defined_css_classes.listAppend(CSSEntryMake(tag, class_name, definition, importance)); +} + +void PageAddCSSClass(Page page_in, string tag, string class_name, string definition, int importance) +{ + PageAddCSSClass(page_in, tag, class_name, definition, importance, ""); +} + +void PageAddCSSClass(Page page_in, string tag, string class_name, string definition) +{ + PageAddCSSClass(page_in, tag, class_name, definition, 0); +} + + +void PageWriteHead(Page page_in, string contents) +{ + page_in.head_contents.append(contents); +} + +void PageWriteHead(Page page_in, buffer contents) +{ + page_in.head_contents.append(contents); +} + + +void PageWrite(Page page_in, string contents) +{ + page_in.body_contents.append(contents); +} + +void PageWrite(Page page_in, buffer contents) +{ + page_in.body_contents.append(contents); +} + +void PageSetBodyAttribute(Page page_in, string attribute, string value) +{ + page_in.body_attributes[attribute] = value; +} + + +//Global: + +buffer PageGenerate() +{ + return PageGenerate(Page()); +} + +void PageGenerateAndWriteOut() +{ + write(PageGenerate()); +} + +void PageSetTitle(string title) +{ + PageSetTitle(Page(), title); +} + +void PageAddCSSClass(string tag, string class_name, string definition) +{ + PageAddCSSClass(Page(), tag, class_name, definition); +} + +void PageAddCSSClass(string tag, string class_name, string definition, int importance) +{ + PageAddCSSClass(Page(), tag, class_name, definition, importance); +} + +void PageAddCSSClass(string tag, string class_name, string definition, int importance, string block_identifier) +{ + PageAddCSSClass(Page(), tag, class_name, definition, importance, block_identifier); +} + +void PageWriteHead(string contents) +{ + PageWriteHead(Page(), contents); +} + +void PageWriteHead(buffer contents) +{ + PageWriteHead(Page(), contents); +} + +//Writes to body: + +void PageWrite(string contents) +{ + PageWrite(Page(), contents); +} + +void PageWrite(buffer contents) +{ + PageWrite(Page(), contents); +} + +void PageSetBodyAttribute(string attribute, string value) +{ + PageSetBodyAttribute(Page(), attribute, value); +} + + +void PageInit() +{ + PageAddCSSClass("a", "r_a_undecorated", "text-decoration:none;color:inherit;"); + PageAddCSSClass("", "r_centre", "margin-left:auto; margin-right:auto;text-align:center;"); + PageAddCSSClass("", "r_bold", "font-weight:bold;"); + PageAddCSSClass("", "r_end_floating_elements", "clear:both;"); + + PageAddCSSClass("", "r_element_important", "color: red;"); + + PageAddCSSClass("", "r_element_good", "color: rgb(0, 128, 0);"); + PageAddCSSClass("", "r_element_awesome", "color: rgb(0, 0, 255);"); + PageAddCSSClass("", "r_element_epic", "color: rgb(138, 43, 226);"); + + PageAddCSSClass("", "r_element_stench", "color:green;"); + PageAddCSSClass("", "r_element_hot", "color:red;"); + PageAddCSSClass("", "r_element_cold", "color:blue;"); + PageAddCSSClass("", "r_element_sleaze", "color:purple;"); + PageAddCSSClass("", "r_element_spooky", "color:gray;"); + + //50% desaturated versions of above: + PageAddCSSClass("", "r_element_stench_desaturated", "color:#427F40;"); + PageAddCSSClass("", "r_element_hot_desaturated", "color:#FF7F81;"); + PageAddCSSClass("", "r_element_cold_desaturated", "color:#6B64FF;"); + PageAddCSSClass("", "r_element_sleaze_desaturated", "color:#7F407F;"); + PageAddCSSClass("", "r_element_spooky_desaturated", "color:gray;"); + + PageAddCSSClass("", "r_indention", "margin-left:" + __setting_indention_width + ";"); + + //Simple table lines: + PageAddCSSClass("div", "r_stl_container", "display:table;"); + PageAddCSSClass("div", "r_stl_container_row", "display:table-row;"); + PageAddCSSClass("div", "r_stl_entry", "padding:0px;margin:0px;display:table-cell;"); + PageAddCSSClass("div", "r_stl_spacer", "width:1em;"); +} + + + +string HTMLGenerateIndentedText(string text, string width) +{ + return HTMLGenerateDivOfClass(text, "r_indention"); +} + +string HTMLGenerateIndentedText(string [int] text) +{ + + buffer building_text; + foreach key in text + { + string line = text[key]; + building_text.append(HTMLGenerateDiv(line)); + } + + return HTMLGenerateIndentedText(to_string(building_text), __setting_indention_width); +} + +string HTMLGenerateIndentedText(string text) +{ + return HTMLGenerateIndentedText(text, __setting_indention_width); +} + + +string HTMLGenerateSimpleTableLines(string [int][int] lines, boolean dividers_are_visible) +{ + buffer result; + + int max_columns = 0; + foreach i in lines + { + max_columns = max(max_columns, lines[i].count()); + } + + //div-based layout: + int intra_i = 0; + int last_cell_count = 0; + result.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_stl_container"))); + foreach i in lines + { + if (intra_i > 0) + { + result.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_stl_container_row"))); + for i from 1 to last_cell_count //no colspan with display:table, generate extra (zero-padding, zero-margin) cells: + { + string separator = ""; + if (dividers_are_visible) + separator = "
"; + else + separator = "
"; //laziness - generate an invisible HR, so there's still spacing + result.append(HTMLGenerateDivOfClass(separator, "r_stl_entry")); + } + result.append(""); + last_cell_count = 0; + } + result.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_stl_container_row"))); + int intra_j = 0; + foreach j in lines[i] + { + string entry = lines[i][j]; + if (intra_j > 0) + { + result.append(HTMLGenerateDivOfClass("", "r_stl_entry r_stl_spacer")); + last_cell_count += 1; + } + result.append(HTMLGenerateDivOfClass(entry, "r_stl_entry")); + last_cell_count += 1; + + intra_j += 1; + } + + result.append(""); + intra_i += 1; + } + result.append(""); + return result.to_string(); +} + +string HTMLGenerateSimpleTableLines(string [int][int] lines) +{ + return HTMLGenerateSimpleTableLines(lines, true); +} + +string HTMLGenerateElementSpan(element e, string additional_text, boolean desaturated) +{ + string line = e; + if (additional_text != "") + line += " " + additional_text; + return HTMLGenerateSpanOfClass(line, "r_element_" + e + (desaturated ? "_desaturated" : "")); +} + +string HTMLGenerateElementSpan(element e, string additional_text) +{ + return HTMLGenerateElementSpan(e, additional_text, false); +} +string HTMLGenerateElementSpanDesaturated(element e, string additional_text) +{ + return HTMLGenerateElementSpan(e, additional_text, true); +} +string HTMLGenerateElementSpanDesaturated(element e) +{ + return HTMLGenerateElementSpanDesaturated(e, ""); +} + + +boolean __setting_show_alignment_guides = false; +//Library for displaying KOL images +//Each image is referred to by a string via KOLImageLookup, or KOLImageGenerateImageHTML +//There's a list of pre-set images in KOLImagesInit. Otherwise, it tries to look up the string as an item, then as a familiar, and then as an effect. If any matches are found, that image is output. (uses KoLmafia's internal database) +//Also "__item item name", "__familiar familiar name", and "__effect effect name" explicitly request those images. +//"__half lookup name" will reduce the image to half-size. +//NOTE: To use KOLImageGenerateImageHTML with should_centre set to true, the page must have the class "r_centre" set as "margin-left:auto; margin-right:auto;text-align:center;" + +Record ServerImageStats +{ + int width; + int height; + int minimum_y_coordinate; + int maximum_y_coordinate; +}; + +ServerImageStats ServerImageStatsMake(int width, int height, int minimum_y_coordinate, int maximum_y_coordinate) +{ + ServerImageStats result; + result.width = width; + result.height = height; + result.minimum_y_coordinate = minimum_y_coordinate; + result.maximum_y_coordinate = maximum_y_coordinate; + return result; +} + +ServerImageStats ServerImageStatsMake() +{ + return ServerImageStatsMake(-1,-1,-1,-1); +} + +record KOLImage +{ + string url; + + Vec2i base_image_size; + Rect crop; + + Rect [int] erase_zones; //rectangular zones which are generated as white divs on the output. Erases specific sections of the image. Can be offset by one pixel depending on the browser, sorry. +}; + + +KOLImage KOLImageMake(string url, Vec2i base_image_size, Rect crop) +{ + KOLImage result; + result.url = url; + result.base_image_size = base_image_size; + result.crop = crop; + return result; +} + +KOLImage KOLImageMake(string url, Vec2i base_image_size) +{ + return KOLImageMake(url, base_image_size, RectZero()); +} + +KOLImage KOLImageMake(string url) +{ + return KOLImageMake(url, Vec2iZero(), RectZero()); +} + +KOLImage KOLImageMake() +{ + return KOLImageMake("", Vec2iZero(), RectZero()); +} + + +static +{ + KOLImage [string] __kol_images; + + void initialiseConstantKOLImages() + { + // One note. In order to figure out RectMake here, you open up the respective images in an image editing program + // and figure out X/Y coordinates. I believe it's Xmin, Ymin, Xmax, Ymax. This is generally better than most + // other possible bespoke solutions. Thanks once again go to Ezandora, the queen of human civilization. + + KOLimage [string] building_images; + building_images["typical tavern"] = KOLImageMake("images/otherimages/woods/tavern0.gif", Vec2iMake(100,100), RectMake(0,39,99,97)); + building_images["boss bat"] = KOLImageMake("images/adventureimages/bossbat.gif", Vec2iMake(100,100), RectMake(0,27,99,74)); + building_images["bugbear"] = KOLImageMake("images/adventureimages/fallsfromsky.gif", Vec2iMake(100,150)); + + building_images["twin peak"] = KOLImageMake("images/otherimages/orcchasm/highlands_main.gif", Vec2iMake(500, 250), RectMake(153,128,237,214)); + building_images["a-boo peak"] = KOLImageMake("images/otherimages/orcchasm/highlands_main.gif", Vec2iMake(500, 250), RectMake(40,134,127,218)); + building_images["oil peak"] = KOLImageMake("images/otherimages/orcchasm/highlands_main.gif", Vec2iMake(500, 250), RectMake(261,117,345,213)); + building_images["highland lord"] = KOLImageMake("images/otherimages/orcchasm/highlands_main.gif", Vec2iMake(500, 250), RectMake(375,73,457,144)); + building_images["orc chasm"] = KOLImageMake("images/otherimages/mountains/chasm.gif", Vec2iMake(100, 100), RectMake(0, 41, 99, 95)); + + building_images["spooky forest"] = KOLImageMake("images/otherimages/woods/forest.gif", Vec2iMake(100, 100), RectMake(12,39,91,93)); + building_images["council"] = KOLImageMake("images/otherimages/council.gif", Vec2iMake(100, 100), RectMake(0,26,99,73)); + + + building_images["daily dungeon"] = KOLImageMake("images/otherimages/town/dd1.gif", Vec2iMake(100,100), RectMake(28,44,71,86)); + building_images["clover"] = KOLImageMake("images/itemimages/clover.gif", Vec2iMake(30,30)); + + building_images["mayfly bait"] = KOLImageMake("images/itemimages/mayflynecklace.gif", Vec2iMake(30,30)); + building_images["spooky putty"] = KOLImageMake("images/itemimages/sputtysheet.gif", Vec2iMake(30,30)); + + building_images["fax machine"] = KOLImageMake("images/otherimages/clanhall/faxmachine.gif", Vec2iMake(100,100), RectMake(34,28,62,54)); + + building_images["unknown"] = KOLImageMake("images/itemimages/confused.gif", Vec2iMake(30,30)); + + building_images["goth kid"] = KOLImageMake("images/itemimages/crayongoth.gif", Vec2iMake(30,30)); + building_images["hipster"] = KOLImageMake("images/itemimages/minihipster.gif", Vec2iMake(30,30)); + + + building_images[""] = KOLImageMake("images/itemimages/blank.gif", Vec2iMake(30,30)); + building_images["blank"] = KOLImageMake("images/itemimages/blank.gif", Vec2iMake(30,30)); + building_images["demon summon"] = KOLImageMake("images/otherimages/manor/chamber.gif", Vec2iMake(100,100), RectMake(14, 12, 88, 66)); + + building_images["cobb's knob"] = KOLImageMake("images/otherimages/plains/knob2.gif", Vec2iMake(100,100), RectMake(12,43,86,78)); + + building_images["generic dwelling"] = KOLImageMake("images/otherimages/campground/rest4.gif", Vec2iMake(100,100), RectMake(0,26,95,99)); + + + building_images["forest friars"] = KOLImageMake("images/otherimages/woods/stones0.gif", Vec2iMake(100,100), RectMake(0, 24, 99, 99)); + building_images["cyrpt"] = KOLImageMake("images/otherimages/plains/cyrpt.gif", Vec2iMake(100,100), RectMake(0, 33, 99, 99)); + building_images["trapper"] = KOLImageMake("images/otherimages/thetrapper.gif", Vec2iMake(60,100), RectMake(0,11,59,96)); + + building_images["castle"] = KOLImageMake("images/otherimages/stalktop/beanstalk.gif", Vec2iMake(500,400), RectMake(234,158,362,290)); //experimental - half sized castle + building_images["penultimate fantasy airship"] = KOLImageMake("images/otherimages/stalktop/beanstalk.gif", Vec2iMake(500,400), RectMake(75, 231, 190, 367)); + building_images["lift, bro"] = KOLImageMake("images/adventureimages/fitposter.gif", Vec2iMake(100,100)); + //building_images["castle stairs up"] = KOLImageMake("images/adventureimages/giantstairsup.gif", Vec2iMake(100,100), RectMake(0, 8, 99, 85)); + building_images["castle stairs up"] = KOLImageMake("images/adventureimages/giantstairsup.gif", Vec2iMake(100,100), RectMake(20, 10, 74, 83)); + building_images["castle stairs up"].erase_zones.listAppend(RectMake(70, 78, 76, 84)); + + + building_images["goggles? yes!"] = KOLImageMake("images/adventureimages/steamposter.gif", Vec2iMake(100,100)); + //building_images["hole in the sky"] = KOLImageMake("images/otherimages/stalktop/beanstalk.gif", Vec2iMake(500,400), RectMake(403, 4, 487, 92)); + building_images["hole in the sky"] = KOLImageMake("images/otherimages/stalktop/beanstalk.gif", Vec2iMake(250,200), RectMake(201, 2, 243, 46)); + + building_images["macguffin"] = KOLImageMake("images/itemimages/macguffin.gif", Vec2iMake(30,30)); + building_images["island war"] = KOLImageMake("images/otherimages/sigils/warhiptat.gif", Vec2iMake(50,50), RectMake(0,12,49,35)); + building_images["naughty sorceress"] = KOLImageMake("images/adventureimages/sorcform1.gif", Vec2iMake(100,100)); + building_images["naughty sorceress lair"] = KOLImageMake("images/otherimages/main/map6.gif", Vec2iMake(100,100), RectMake(6,0,50,43)); + + building_images["king imprismed"] = KOLImageMake("images/otherimages/lair/kingprism1.gif", Vec2iMake(100,100)); + building_images["astral gash"] = KOLImageMake("images/otherimages/gash.gif", Vec2iMake(100,100)); + building_images["campsite"] = KOLImageMake("images/otherimages/plains/plains1.gif", Vec2iMake(100,100)); + building_images["trophy"] = KOLImageMake("images/otherimages/trophy/not_wearing_any_pants.gif", Vec2iMake(100,100)); + building_images["hidden temple"] = KOLImageMake("images/otherimages/woods/temple.gif", Vec2iMake(100,100), RectMake(16, 40, 89, 96)); + building_images["florist friar"] = KOLImageMake("images/adventureimages/floristfriar.gif", Vec2iMake(100,100), RectMake(31, 7, 77, 92)); + + + building_images["plant rutabeggar"] = KOLImageMake("images/otherimages/friarplants/plant2.gif", Vec2iMake(50,100), RectMake(1, 24, 47, 96)); + + building_images["plant stealing magnolia"] = KOLImageMake("images/otherimages/friarplants/plant12.gif", Vec2iMake(49,100), RectMake(3, 15, 43, 94)); + + building_images["plant shuffle truffle"] = KOLImageMake("images/otherimages/friarplants/plant24.gif", Vec2iMake(66,100), RectMake(4, 35, 63, 88)); + building_images["plant horn of plenty"] = KOLImageMake("images/otherimages/friarplants/plant22.gif", Vec2iMake(62,100), RectMake(4, 14, 58, 86)); + + building_images["plant rabid dogwood"] = KOLImageMake("images/otherimages/friarplants/plant1.gif", Vec2iMake(57,100), RectMake(3, 16, 55, 98)); + building_images["plant rad-ish radish"] = KOLImageMake("images/otherimages/friarplants/plant3.gif", Vec2iMake(48,100), RectMake(4, 14, 42, 96)); + building_images["plant war lily"] = KOLImageMake("images/otherimages/friarplants/plant11.gif", Vec2iMake(49,100), RectMake(5, 5, 45, 98)); + + building_images["plant canned spinach"] = KOLImageMake("images/otherimages/friarplants/plant13.gif", Vec2iMake(48,100), RectMake(3, 24, 46, 94)); + building_images["plant blustery puffball"] = KOLImageMake("images/otherimages/friarplants/plant21.gif", Vec2iMake(54,100), RectMake(3, 38, 50, 90)); + building_images["plant wizard's wig"] = KOLImageMake("images/otherimages/friarplants/plant23.gif", Vec2iMake(53,100), RectMake(2, 15, 48, 90)); + + building_images["plant up sea daisy"] = KOLImageMake("images/otherimages/friarplants/plant40.gif", Vec2iMake(64,100), RectMake(3, 6, 60, 92)); + building_images["sunflower face"] = KOLImageMake("images/otherimages/friarplants/plant40.gif", Vec2iMake(64,100), RectMake(6, 6, 58, 52)); + + building_images["ringing phone"] = KOLImageMake("images/otherimages/spookyraven/srphonering.gif", Vec2iMake(30, 51), RectMake(0, 16, 30, 46)); + + building_images["basic hot dog"] = KOLImageMake("images/itemimages/jarl_regdog.gif", Vec2iMake(30,30)); + building_images["Island War Arena"] = KOLImageMake("images/otherimages/bigisland/6.gif", Vec2iMake(100,100), RectMake(17, 28, 89, 76)); + building_images["Island War Lighthouse"] = KOLImageMake("images/otherimages/bigisland/17.gif", Vec2iMake(100,100), RectMake(30, 34, 68, 97)); + building_images["Island War Nuns"] = KOLImageMake("images/otherimages/bigisland/19.gif", Vec2iMake(100,100), RectMake(20, 43, 78, 87)); + building_images["Island War Farm"] = KOLImageMake("images/otherimages/bigisland/15.gif", Vec2iMake(100,100), RectMake(8, 50, 93, 88)); + building_images["Island War Orchard"] = KOLImageMake("images/otherimages/bigisland/3.gif", Vec2iMake(100,100), RectMake(20, 36, 99, 87)); + + building_images["Island War Junkyard"] = KOLImageMake("images/otherimages/bigisland/25.gif", Vec2iMake(100,100), RectMake(0, 4, 99, 89)); + building_images["Island War Junkyard"].erase_zones.listAppend(RectMake(0, 2, 20, 6)); + building_images["Island War Junkyard"].erase_zones.listAppend(RectMake(9, 41, 95, 52)); + + + building_images["spookyraven manor"] = KOLImageMake("images/otherimages/town/manor.gif", Vec2iMake(100,100), RectMake(0, 22, 99, 99)); + + building_images["spookyraven manor"].erase_zones.listAppend(RectMake(23, 18, 53, 28)); + + + building_images["spookyraven manor locked"] = KOLImageMake("images/otherimages/town/pantry.gif", Vec2iMake(80,80), RectMake(0, 26, 79, 79)); + + building_images["haunted billiards room"] = KOLImageMake("images/otherimages/manor/sm4.gif", Vec2iMake(100,100), RectMake(12, 10, 93, 63)); + + building_images["haunted library"] = KOLImageMake("images/otherimages/manor/sm7.gif", Vec2iMake(100,100), RectMake(14, 5, 92, 55)); + + building_images["haunted bedroom"] = KOLImageMake("images/otherimages/manor/sm2_1b.gif", Vec2iMake(100,100), RectMake(18, 28, 91, 86)); + building_images["Haunted Ballroom"] = KOLImageMake("images/otherimages/manor/sm2_5.gif", Vec2iMake(100,200), RectMake(19, 11, 74, 76)); + + building_images["Palindome"] = KOLImageMake("images/otherimages/plains/the_palindome.gif", Vec2iMake(96,86), RectMake(0, 17, 96, 83)); + + + building_images["high school"] = KOLImageMake("images/otherimages/town/kolhs.gif", Vec2iMake(100,100), RectMake(0, 26, 99, 92)); + //building_images["Toot Oriole"] = KOLImageMake("images/otherimages/oriole.gif", Vec2iMake(60,100), RectMake(0, 12, 59, 85)); + building_images["Toot Oriole"] = KOLImageMake("images/otherimages/mountains/noobsingtop.gif", Vec2iMake(200,100), RectMake(52, 18, 131, 49)); //I love this GIF + + building_images["bookshelf"] = KOLImageMake("images/otherimages/campground/bookshelf.gif", Vec2iMake(100,100), RectMake(0, 26, 99, 99)); + building_images["pirate quest"] = KOLImageMake("images/otherimages/trophy/party_on_the_big_boat.gif", Vec2iMake(100,100), RectMake(18, 3, 87, 64)); + building_images["ship wheel"] = KOLImageMake("images/adventureimages/shipwheel.gif", Vec2iMake(100,100)); + building_images["meat"] = KOLImageMake("images/itemimages/meat.gif", Vec2iMake(30,30)); + building_images["monk"] = KOLImageMake("images/itemimages/monkhead.gif", Vec2iMake(30,30)); + + + building_images["Pyramid"] = KOLImageMake("images/otherimages/desertbeach/pyramid.gif", Vec2iMake(60,70), RectMake(12, 11, 47, 38)); + building_images["Pyramid"].erase_zones.listAppend(RectMake(14, 19, 19, 22)); + building_images["Pyramid"].erase_zones.listAppend(RectMake(41, 12, 45, 16)); + + + //building_images["hidden city"] = KOLImageMake("images/otherimages/hiddencity//hiddencitybg.gif", Vec2iMake(600,400), RectMake(114, 38, 213, 159)); //building, don't like + //building_images["hidden city"] = KOLImageMake("images/otherimages/hiddencity//hiddencitybg.gif", Vec2iMake(600,400), RectMake(7, 240, 77, 294)); //shrine, too close to hidden temple + building_images["hidden city"] = KOLImageMake("images/otherimages/hiddencity//hiddencitybg.gif", Vec2iMake(600,400), RectMake(426, 13, 504, 61)); //hidden tavern, small, better + building_images["Dispensary"] = KOLImageMake("images/adventureimages/knobwindow.gif", Vec2iMake(100,100)); + + + building_images["Wine Racks"] = KOLImageMake("images/otherimages/manor/cellar4.gif", Vec2iMake(100,100), RectMake(17, 11, 96, 65)); + building_images["Wine Racks"].erase_zones.listAppend(RectMake(17, 11, 33, 12)); + building_images["Wine Racks"].erase_zones.listAppend(RectMake(39, 61, 42, 66)); + building_images["Wine Racks"].erase_zones.listAppend(RectMake(70, 61, 74, 66)); + building_images["Wine Racks"].erase_zones.listAppend(RectMake(94, 45, 97, 54)); + building_images["Wine Racks"].erase_zones.listAppend(RectMake(17, 49, 18, 53)); + + + building_images["black forest"] = KOLImageMake("images/otherimages/woods/bforest.gif", Vec2iMake(100,100), RectMake(0, 19, 99, 99)); + + building_images["possessed wine rack"] = KOLImageMake("images/adventureimages/winerack.gif", Vec2iMake(100,100), RectMake(0, 0, 99, 99)); + building_images["cabinet of Dr. Limpieza"] = KOLImageMake("images/adventureimages/laundrycabinet.gif", Vec2iMake(100,100), RectMake(0, 0, 99, 99)); + building_images["monstrous boiler"] = KOLImageMake("images/adventureimages/boiler.gif", Vec2iMake(100,100), RectMake(0, 0, 99, 99)); + + + + building_images["Dad Sea Monkee"] = KOLImageMake("images/adventureimages/dad_machine.gif", Vec2iMake(400,300), RectMake(150,212,245,260)); + building_images["Shub-Jigguwatt"] = KOLImageMake("images/adventureimages/shub-jigguwatt.gif", Vec2iMake(300,300), RectMake(19, 17, 267, 288)); + building_images["Yog-Urt"] = KOLImageMake("images/adventureimages/yog-urt.gif", Vec2iMake(300,300), RectMake(36, 88, 248, 299)); + building_images["Sea"] = KOLImageMake("images/adventureimages/wizardfish.gif", Vec2iMake(100,100), RectMake(18, 23, 61, 72)); + building_images["Sea"].erase_zones.listAppend(RectMake(18, 23, 27, 28)); + building_images["Sea"].erase_zones.listAppend(RectMake(48, 23, 62, 35)); + building_images["Sea Monkey Castle"] = KOLImageMake("images/otherimages/ocean/monkeycastle.gif", Vec2iMake(100,100), RectMake(29, 36, 66, 82)); + building_images["Sea Monkey Castle"].erase_zones.listAppend(RectMake(29, 36, 39, 39)); + building_images["Sea Monkey Castle"].erase_zones.listAppend(RectMake(60, 36, 66, 42)); + building_images["Mom Monkey Castle Window"] = KOLImageMake("images/adventureimages/momwindow.gif", Vec2iMake(100,100), RectMake(15, 16, 81, 78)); + building_images["Mom Monkey Castle Window"].erase_zones.listAppend(RectMake(71, 16, 81, 21)); + building_images["Mom Monkey Castle Window"].erase_zones.listAppend(RectMake(81, 16, 81, 43)); + building_images["Mom Monkey Castle Window"].erase_zones.listAppend(RectMake(15, 16, 25, 24)); + building_images["Mom Monkey Castle Window"].erase_zones.listAppend(RectMake(15, 16, 21, 28)); + building_images["Skate Park"] = KOLImageMake("images/otherimages/ocean/rumble_a.gif", Vec2iMake(100,100), RectMake(20, 37, 79, 94)); + building_images["Skate Park"].erase_zones.listAppend(RectMake(20, 37, 40, 71)); + building_images["Skate Park"].erase_zones.listAppend(RectMake(20, 37, 45, 53)); + building_images["Skate Park"].erase_zones.listAppend(RectMake(57, 44, 79, 52)); + building_images["Skate Park"].erase_zones.listAppend(RectMake(64, 37, 79, 69)); + building_images["Skate Park"].erase_zones.listAppend(RectMake(20, 77, 22, 94)); + building_images["Skate Park"].erase_zones.listAppend(RectMake(20, 85, 27, 94)); + building_images["Skate Park"].erase_zones.listAppend(RectMake(57, 93, 79, 94)); + building_images["Spooky little girl"] = KOLImageMake("images/adventureimages/axelgirl.gif", Vec2iMake(100,100), RectMake(37, 25, 63, 74)); + + //hermit.gif and oldman.gif are almost identical. twins? + + building_images["astral spirit"] = KOLImageMake("images/otherimages/spirit.gif", Vec2iMake(60,100)); + building_images["Disco Bandit"] = KOLImageMake("images/otherimages/discobandit_f.gif", Vec2iMake(60,100), RectMake(0,6,59,87)); + building_images["Seal Clubber"] = KOLImageMake("images/otherimages/sealclubber_f.gif", Vec2iMake(60,100), RectMake(0,9,59,92)); + building_images["Turtle Tamer"] = KOLImageMake("images/otherimages/turtletamer_f.gif", Vec2iMake(60,100), RectMake(0,5,59,93)); + building_images["Pastamancer"] = KOLImageMake("images/otherimages/pastamancer_f.gif", Vec2iMake(60,100), RectMake(0,0,59,91)); + building_images["Sauceror"] = KOLImageMake("images/otherimages/sauceror_f.gif", Vec2iMake(60,100), RectMake(0,5,59,90)); + building_images["Accordion Thief"] = KOLImageMake("images/otherimages/accordionthief_f.gif", Vec2iMake(60,100), RectMake(0,2,59,99)); + building_images["Avatar of Sneaky Pete"] = KOLImageMake("images/otherimages/peteavatar_f.gif", Vec2iMake(60,100), RectMake(1,7,59,96)); + building_images["Avatar of Jarlsberg"] = KOLImageMake("images/otherimages/jarlsberg_avatar_f.gif", Vec2iMake(60,100), RectMake(0,6,59,96)); + building_images["Avatar of Boris"] = KOLImageMake("images/otherimages/boris_avatar_f.gif", Vec2iMake(60,100), RectMake(0,4,59,93)); + building_images["Zombie Master"] = KOLImageMake("images/otherimages/zombavatar_f.gif", Vec2iMake(60,100), RectMake(10,3,55,99)); + building_images["WereProfessor"] = KOLImageMake("images/otherimages/wereprofavatar_f.gif", Vec2iMake(60,100), RectMake(9,7,50,98)); + building_images["Hourglass"] = KOLImageMake("images/itemimages/hourglass.gif", Vec2iMake(30,30)); + + building_images["Nemesis Disco Bandit"] = KOLImageMake("images/adventureimages/newwave.gif", Vec2iMake(100,100)); + building_images["Nemesis Seal Clubber"] = KOLImageMake("images/adventureimages/1_1.gif", Vec2iMake(100,100)); + building_images["Nemesis Turtle Tamer"] = KOLImageMake("images/adventureimages/2_1.gif", Vec2iMake(100,100)); + building_images["Nemesis Pastamancer"] = KOLImageMake("images/adventureimages/3_1.gif", Vec2iMake(100,100)); + building_images["Nemesis Sauceror"] = KOLImageMake("images/adventureimages/4_1.gif", Vec2iMake(100,100)); + building_images["Nemesis Accordion Thief"] = KOLImageMake("images/adventureimages/6_1.gif", Vec2iMake(100,100)); + building_images["Nemesis Actually Ed the Undying"] = KOLImageMake("images/itemimages/blackcheck.gif", Vec2iMake(30,30)); //being old, his true enemy is his ever-decreasing pension + + building_images["sword guy"] = KOLImageMake("images/otherimages/leftswordguy.gif", Vec2iMake(80,100)); + building_images["Jick"] = KOLImageMake("images/otherimages/customavatars/1.gif", Vec2iMake(60,100)); + building_images["Superhuman Cocktailcrafting"] = KOLImageMake("images/itemimages/fruitym.gif", Vec2iMake(30,30)); + + // Big thanks to Beldur for looking up the right dimensions. A true king of kings. + building_images["Vanya's Castle"] = KOLImageMake("images/otherimages/8bitrealm.gif", Vec2iMake(400,400), RectMake(285,115,400,207)); + building_images["Megalo-City"] = KOLImageMake("images/otherimages/8bitrealm.gif", Vec2iMake(400,400), RectMake(227,0,310,99)); + building_images["The Fungus Plains"] = KOLImageMake("images/otherimages/8bitrealm.gif", Vec2iMake(400,400), RectMake(290,250,386,315)); + building_images["Hero's Field"] = KOLImageMake("images/otherimages/8bitrealm.gif", Vec2iMake(400,400), RectMake(64,17,178,117)); + + building_images["inexplicable door"] = KOLImageMake("images/otherimages/woods/8bitdoor.gif", Vec2iMake(100,100), RectMake(15, 43, 85, 99)); + building_images["Dungeons of Doom"] = KOLImageMake("images/otherimages/town/ddoom.gif", Vec2iMake(100,100), RectMake(31, 33, 68, 99)); + + building_images["chinatown"] = KOLImageMake("images/otherimages/jung/jung_chinaback.gif", Vec2iMake(450,500), RectMake(188, 202, 229, 270)); + building_images["chinatown"].erase_zones.listAppend(RectMake(227, 247, 231, 256)); + + + building_images["barrel god"] = KOLImageMake("images/otherimages/bgshrine.gif", Vec2iMake(100,100), RectMake(29, 39, 69, 81)); + + building_images["__skill Easy Riding"] = KOLImageMake("images/itemimages/motorbike.gif", Vec2iMake(30,30)); + building_images["__skill jump shark"] = KOLImageMake("images/itemimages/sharkfin.gif", Vec2iMake(30,30)); + building_images["__skill Natural Dancer"] = KOLImageMake("images/itemimages/dance3.gif", Vec2iMake(30,30)); + building_images["__skill Check Mirror"] = KOLImageMake("images/itemimages/bikemirror.gif", Vec2iMake(30,30)); + building_images["__skill Ball Lightning"] = KOLImageMake("images/itemimages/balllightning.gif", Vec2iMake(30,30)); + building_images["__skill rain man"] = KOLImageMake("images/itemimages/rainman.gif", Vec2iMake(30,30)); + building_images["__skill Wisdom of Thoth"] = KOLImageMake("images/itemimages/thoth.gif", Vec2iMake(30,30)); + + building_images["lair registration desk"] = KOLImageMake("images/otherimages/nstower/nstower_regdesk.gif", Vec2iMake(100,61), RectMake(30, 3, 68, 41)); + + + building_images["mini-adventurer blank female"] = KOLImageMake("images/itemimages/miniadv0f.gif", Vec2iMake(30,30)); + building_images["mini-adventurer seal clubber female"] = KOLImageMake("images/itemimages/miniadv1f.gif", Vec2iMake(30,30)); + building_images["mini-adventurer turtle tamer female"] = KOLImageMake("images/itemimages/miniadv2f.gif", Vec2iMake(30,30)); + building_images["mini-adventurer pastamancer female"] = KOLImageMake("images/itemimages/miniadv3f.gif", Vec2iMake(30,30)); + building_images["mini-adventurer sauceror female"] = KOLImageMake("images/itemimages/miniadv4f.gif", Vec2iMake(30,30)); + building_images["mini-adventurer disco bandit female"] = KOLImageMake("images/itemimages/miniadv5f.gif", Vec2iMake(30,30)); + building_images["mini-adventurer accordion thief female"] = KOLImageMake("images/itemimages/miniadv6f.gif", Vec2iMake(30,30)); + + building_images["Lady Spookyraven"] = KOLImageMake("images/otherimages/spookyraven/sr_ladys.gif", Vec2iMake(65,65), RectMake(0, 0, 64, 37)); + building_images["Yeti"] = KOLImageMake("images/adventureimages/yeti.gif", Vec2iMake(100,100), RectMake(12, 0, 80, 98)); + building_images["Lights Out"] = KOLImageMake("images/adventureimages/lightning.gif", Vec2iMake(100,100), RectMake(0, 10, 99, 96)); + building_images["stench airport kiosk"] = KOLImageMake("images/otherimages/dinseylandfill_bg.gif", Vec2iMake(500,500), RectMake(163, 438, 225, 494)); + + foreach key in building_images + { + __kol_images[key.to_lower_case()] = building_images[key]; + } + + } + initialiseConstantKOLImages(); +} + +boolean __kol_images_has_inited = false; +//Does not need to be called directly. +void KOLImagesInit() +{ + if (__kol_images_has_inited) + return; + + PageAddCSSClass("div", "r_image_container", "overflow:hidden;position:relative;top:0px;left:0px;"); + __kol_images_has_inited = true; + KOLimage [string] building_images; + + string class_name = my_class().to_string().to_lower_case(); + string class_nemesis_name = "nemesis " + class_name; + + if (__kol_images contains class_name) + building_images["player character"] = __kol_images[class_name]; + else + building_images["player character"] = __kol_images["disco bandit"]; + + if (__kol_images contains class_nemesis_name) + building_images["nemesis"] = __kol_images[class_nemesis_name]; + else + building_images["nemesis"] = __kol_images["jick"]; + + + + foreach key in building_images + { + __kol_images[key.to_lower_case()] = building_images[key]; + } +} + + + +KOLImage KOLImageLookup(string lookup_name) +{ + KOLImagesInit(); + if (!(__kol_images contains lookup_name)) + { + //Automatically look up items, familiars, and effects by name: + item it = lookup_name.to_item(); + familiar f = lookup_name.to_familiar(); + effect e = lookup_name.to_effect(); + monster m = $monster[none]; + skill s = $skill[none]; + string secondary_lookup_name = lookup_name; + if (lookup_name.stringHasPrefix("__item ")) + { + secondary_lookup_name = lookup_name.substring(7); + f = $familiar[none]; + e = $effect[none]; + it = secondary_lookup_name.to_item(); + } + else if (lookup_name.stringHasPrefix("__familiar ")) + { + secondary_lookup_name = lookup_name.substring(11); + it = $item[none]; + e = $effect[none]; + f = secondary_lookup_name.to_familiar(); + } + else if (lookup_name.stringHasPrefix("__effect ")) + { + secondary_lookup_name = lookup_name.substring(9); + f = $familiar[none]; + it = $item[none]; + e = secondary_lookup_name.to_effect(); + } + else if (lookup_name.stringHasPrefix("__monster ")) + { + secondary_lookup_name = lookup_name.substring(10); + f = $familiar[none]; + it = $item[none]; + e = $effect[none]; + m = secondary_lookup_name.to_monster(); + } + else if (lookup_name.stringHasPrefix("__skill ")) + { + secondary_lookup_name = lookup_name.substring(8); + f = $familiar[none]; + it = $item[none]; + e = $effect[none]; + s = secondary_lookup_name.to_skill(); + } + //Disabled for now - skill images are a new feature. + /*if (lookup_name.stringHasPrefix("__skill ")) + { + secondary_lookup_name = lookup_name.substring(8); + skill s = secondary_lookup_name.to_skill(); + + __kol_images[lookup_name] = KOLImageMake("images/itemimages/" + s.image, Vec2iMake(30,30)); + return __kol_images[lookup_name]; + }*/ + secondary_lookup_name = secondary_lookup_name.to_lower_case(); + if (it != $item[none] && it.smallimage != "" && it.to_string().to_lower_case() == secondary_lookup_name) + { + __kol_images[lookup_name] = KOLImageMake("images/itemimages/" + it.smallimage, Vec2iMake(30,30)); + } + else if (f != $familiar[none] && f.image != "" && f.to_string().to_lower_case() == secondary_lookup_name) + { + __kol_images[lookup_name] = KOLImageMake("images/itemimages/" + f.image, Vec2iMake(30,30)); + } + else if (e != $effect[none] && e.image != "" && e.to_string().to_lower_case() == secondary_lookup_name) + { + __kol_images[lookup_name] = KOLImageMake("images/itemimages/" + e.image, Vec2iMake(30,30)); + } + else if (m != $monster[none] && m.image != "" && m.to_string().to_lower_case() == secondary_lookup_name) + { + __kol_images[lookup_name] = KOLImageMake("images/adventureimages/" + m.image, Vec2iMake(100, 100)); + } + else if (s != $skill[none] && s.image != "" && s.to_string().to_lower_case() == secondary_lookup_name) + { + __kol_images[lookup_name] = KOLImageMake("images/itemimages/" + s.image, Vec2iMake(30,30)); + } + else + { + if (__setting_debug_mode) + print("Unknown image \"" + lookup_name + "\""); + return KOLImageMake(); + } + } + return __kol_images[lookup_name]; +} + +Vec2i __kol_image_generate_image_html_return_final_size; +buffer KOLImageGenerateImageHTML(string lookup_name, boolean should_centre, Vec2i max_image_dimensions, string container_additional_class) +{ + KOLImagesInit(); + lookup_name = to_lower_case(lookup_name); + + boolean half_sized_output = false; + boolean item_sized_output = false; + lookup_name = lookup_name.to_lower_case(); + if (lookup_name.stringHasPrefix("__half ")) + { + lookup_name = lookup_name.substring(7); + half_sized_output = true; + } + if (lookup_name.stringHasPrefix("__itemsize ")) + { + lookup_name = lookup_name.substring(11); + item_sized_output = true; + } + + __kol_image_generate_image_html_return_final_size = Vec2iZero(); + + KOLImage kol_image = KOLImageLookup(lookup_name); + buffer result; + if (kol_image.url == "") + return "".to_buffer(); + + Vec2i image_size = Vec2iCopy(kol_image.base_image_size); + Rect image_crop = RectCopy(kol_image.crop); + + + + boolean have_size = true; + boolean have_crop = true; + if (image_size.x == 0 || image_size.y == 0) + have_size = false; + if (image_crop.max_coordinate.x == 0 || image_crop.max_coordinate.y == 0) + have_crop = false; + + + float scale_ratio = 1.0; + if (have_size || have_crop) + { + Vec2i effective_image_size = image_size; + + if (half_sized_output) + { + effective_image_size.x = round(effective_image_size.x.to_float() * 0.5); + effective_image_size.y = round(effective_image_size.y.to_float() * 0.5); + } + if (item_sized_output) + { + //FIXME this will result in incorrect proportions for nonsquare images + //also crop? what crop? + effective_image_size.x = MIN(effective_image_size.x, 30.0); + effective_image_size.y = MIN(effective_image_size.y, 30.0); + } + if (have_crop) + effective_image_size = Vec2iMake(image_crop.max_coordinate.x - image_crop.min_coordinate.x + 1, image_crop.max_coordinate.y - image_crop.min_coordinate.y + 1); + + if (half_sized_output && have_crop) + { + image_crop.min_coordinate.x = round(image_crop.min_coordinate.x.to_float() * 0.5); + image_crop.min_coordinate.y = round(image_crop.min_coordinate.y.to_float() * 0.5); + image_crop.max_coordinate.x = round(image_crop.max_coordinate.x.to_float() * 0.5); + image_crop.max_coordinate.y = round(image_crop.max_coordinate.y.to_float() * 0.5); + } + + if (effective_image_size.x > max_image_dimensions.x || effective_image_size.y > max_image_dimensions.y) + { + //Scale down, to match limitations: + float image_ratio = 1.0; + if (effective_image_size.x != 0.0 && effective_image_size.y != 0.0) + { + image_ratio = effective_image_size.y.to_float() / effective_image_size.x.to_float(); + //Try width-major: + Vec2i new_image_size = Vec2iMake(max_image_dimensions.x.to_float(), max_image_dimensions.x.to_float() * image_ratio); + if (new_image_size.x > max_image_dimensions.x || new_image_size.y > max_image_dimensions.y) //too big, try vertical-major: + { + new_image_size = Vec2iMake(max_image_dimensions.y.to_float() / image_ratio, max_image_dimensions.y); + } + //Find ratio: + if (new_image_size.x != 0.0) + { + scale_ratio = new_image_size.x.to_float() / effective_image_size.x.to_float(); + } + } + } + } + if (scale_ratio > 1.0) scale_ratio = 1.0; + if (scale_ratio < 1.0) + { + image_size.x = round(image_size.x.to_float() * scale_ratio); + image_size.y = round(image_size.y.to_float() * scale_ratio); + image_crop.min_coordinate.x = ceil(image_crop.min_coordinate.x.to_float() * scale_ratio); + image_crop.min_coordinate.y = ceil(image_crop.min_coordinate.y.to_float() * scale_ratio); + image_crop.max_coordinate.x = floor(image_crop.max_coordinate.x.to_float() * scale_ratio); + image_crop.max_coordinate.y = floor(image_crop.max_coordinate.y.to_float() * scale_ratio); + } + + boolean outputting_div = false; + boolean outputting_erase_zones = false; + Vec2i div_dimensions; + + if (container_additional_class != "") + outputting_div = true; + if (have_size) + { + div_dimensions = image_size; + if (have_crop) + { + outputting_div = true; + div_dimensions = Vec2iMake(image_crop.max_coordinate.x - image_crop.min_coordinate.x + 1, + image_crop.max_coordinate.y - image_crop.min_coordinate.y + 1); + } + else if (image_size.x > 100) + { + //Automatically crop to 100 pixels wide: + outputting_div = true; + div_dimensions = image_size; + div_dimensions.x = min(100, div_dimensions.x); + } + if (kol_image.erase_zones.count() > 0) + { + outputting_div = true; + outputting_erase_zones = true; + } + } + + if (outputting_div) + { + string style = ""; + + if (have_size) + style = "width:" + div_dimensions.x + "px; height:" + div_dimensions.y + "px;"; + if (__setting_show_alignment_guides) + style += "background:purple;"; + + string [int] classes; + classes.listAppend("r_image_container"); + + if (should_centre) + classes.listAppend("r_centre"); + if (container_additional_class != "") + classes.listAppend(container_additional_class); + result.append(HTMLGenerateTagPrefix("div", mapMake("class", classes.listJoinComponents(" "), "style", style))); + } + + string [string] img_tag_attributes; + img_tag_attributes["src"] = kol_image.url; + if (have_size) + { + img_tag_attributes["width"] = image_size.x; + img_tag_attributes["height"] = image_size.y; + + __kol_image_generate_image_html_return_final_size = image_size; + + } + + //Needs to be optimized to use buffers first. + /*string unadorned_name = lookup_name; + int breakout = 50; + while (unadorned_name != "" && unadorned_name.stringHasPrefix("__") && breakout > 0) + { + int space_index = unadorned_name.index_of(" ") + 1; + if (space_index < 0 || space_index > unadorned_name.length()) + space_index = unadorned_name.length(); + unadorned_name = unadorned_name.substring(space_index); + breakout -= 1; + }*/ + + img_tag_attributes["alt"] = lookup_name.HTMLEscapeString(); + //img_tag_attributes["title"] = unadorned_name.HTMLEscapeString(); + + if (have_crop && outputting_div) + { + //cordinates are upper-left + //format is clip:rect(top-edge,right-edge,bottom-edge,left-edge); + + int top_edge = image_crop.min_coordinate.y; + int bottom_edge = image_crop.max_coordinate.y; + int left_edge = image_crop.min_coordinate.x; + int right_edge = image_crop.max_coordinate.x; + + int margin_top = -(image_crop.min_coordinate.y); + int margin_bottom = -(image_size.y - image_crop.max_coordinate.y); + int margin_left = -(image_crop.min_coordinate.x); + int margin_right = -(image_size.x - image_crop.max_coordinate.x); + img_tag_attributes["style"] = "margin: " + margin_top + "px " + margin_right + "px " + margin_bottom + "px " + margin_left + "px;"; + + + + __kol_image_generate_image_html_return_final_size = Vec2iMake(right_edge - left_edge, bottom_edge - top_edge); + } + + if (__setting_show_alignment_guides) + img_tag_attributes["style"] += "opacity: 0.5;"; + + result.append(HTMLGenerateTagPrefix("img", img_tag_attributes)); + + if (outputting_erase_zones) + { + foreach i in kol_image.erase_zones + { + Rect zone = RectCopy(kol_image.erase_zones[i]); + Vec2i dimensions = Vec2iMake(zone.max_coordinate.x - zone.min_coordinate.x + 1, zone.max_coordinate.y - zone.min_coordinate.y + 1); + //print_html("zone = " + zone.to_json()); + if (scale_ratio < 1.0) + { + dimensions.x = round(dimensions.x.to_float() * scale_ratio); + dimensions.y = round(dimensions.y.to_float() * scale_ratio); + zone.min_coordinate.x = round(zone.min_coordinate.x.to_float() * scale_ratio); + zone.min_coordinate.y = round(zone.min_coordinate.y.to_float() * scale_ratio); + zone.max_coordinate.x = round(zone.max_coordinate.x.to_float() * scale_ratio); + zone.max_coordinate.y = round(zone.max_coordinate.y.to_float() * scale_ratio); + } + + int top = 0; + int left = 0; + + top = -image_crop.min_coordinate.y; + left = -image_crop.min_coordinate.x; + + top += zone.min_coordinate.y; + left += zone.min_coordinate.x; + //Output a white div over this area: + buffer style; + style.append("width:"); + style.append(dimensions.x); + style.append("px;height:"); + style.append(dimensions.y); + style.append("px;"); + if (__setting_show_alignment_guides) + style.append("background:pink;"); + else + style.append("background:#FFFFFF;"); + + style.append("z-index:2;position:absolute;top:"); + style.append(top); + style.append("px;left:"); + style.append(left); + style.append("px;"); + + result.append(HTMLGenerateDivOfStyle("", style)); + } + } + + if (outputting_div) + result.append(""); + return result; +} + +buffer KOLImageGenerateImageHTML(string lookup_name, boolean should_centre, Vec2i max_image_dimensions) +{ + return KOLImageGenerateImageHTML(lookup_name, should_centre, max_image_dimensions, ""); +} + +buffer KOLImageGenerateImageHTML(string lookup_name, boolean should_centre) +{ + return KOLImageGenerateImageHTML(lookup_name, should_centre, Vec2iMake(65535, 65535)); +} + +static +{ + //Rect [string] __minimum_bounding_box_of_image_url; + int [string] __minimum_y_of_image_url; + ServerImageStats [string] __server_image_stats; + + void initialiseMinimumBoundingBoxOfImageURL() + { + //Rect rm(int min_x, int min_y, int max_x, int max_y) { return RectMake(min_x, min_y, max_x, max_y); } + //Vec2i vm(int x, int y) { return Vec2iMake(x, y); } + //Rect test = rm(0,0,0,0); + ServerImageStats im(int width, int height, int min_y, int max_y) { return ServerImageStatsMake(width, height, min_y, max_y); } + ServerImageStats im(int min_y, int max_y) { return ServerImageStatsMake(100, 100, min_y, max_y); } + + ServerImageStats [string] ism; + int [string] ysm; + +ism["borgelf1.gif"] = im(11, 74);ism["borgelf4.gif"] = im(19, 82);ism["borgelf2.gif"] = im(25, 87);ism["borgelf3.gif"] = im(14, 78);ism["handymanjay.gif"] = im(5, 92);ism["1335.gif"] = im(7, 93);ism["miner.gif"] = im(1, 95);ism["foreman.gif"] = im(2, 94);ism["gremlinamc.gif"] = im(12, 78);ism["abcrusher.gif"] = im(12, 89);ism["adv_smart1.gif"] = im(0, 97);ism["lower_b.gif"] = im(16, 74);ism["electriceel.gif"] = im(1, 98);ism["1boy2cups.gif"] = im(2, 91);ism["advecho.gif"] = im(0, 99);ism["whitebat.gif"] = im(33, 70);ism["mar_alert.gif"] = im(0, 99);ism["alielf.gif"] = im(4, 95);ism["spelunkalien.gif"] = im(17, 81);ism["muthamster.gif"] = im(5, 95);ism["spelunkalienq.gif"] = im(150, 150, 17, 141);ism["spelunkufo.gif"] = im(21, 78);ism["steve.gif"] = im(0, 98);ism["catfish.gif"] = im(41, 91);ism["giant_alphabet.gif"] = im(1, 97);ism["elf_amateur.gif"] = im(10, 83);ism["ninja.gif"] = im(13, 85);ism["pirate2.gif"] = im(6, 93);ism["crimbominer3.gif"] = im(2, 97);ism["amokputty.gif"] = im(5, 84);ism["srpainting2.gif"] = im(20, 82);ism["regret3.gif"] = im(27, 79);ism["oldguardstatue.gif"] = im(0, 97);ism["pebbleman.gif"] = im(2, 89);ism["mariner.gif"] = im(5, 93);ism["protspirit.gif"] = im(7, 86);ism["guardstatue.gif"] = im(0, 98);ism["bb_horror.gif"] = im(125, 100, 5, 89);ism["anemone.gif"] = im(0, 97);ism["bb_doctor.gif"] = im(7, 83);ism["angel.gif"] = im(6, 87);ism["angerman.gif"] = im(200, 250, 15, 242);ism["anglerbush.gif"] = im(0, 97);ism["mh_bassist.gif"] = im(2, 97);ism["angbugbear.gif"] = im(6, 91);ism["bb_caveman.gif"] = im(4, 92);ism["mush_angry.gif"] = im(8, 89);ism["pinata.gif"] = im(0, 97);ism["madpoet.gif"] = im(7, 93);ism["raccoon.gif"] = im(6, 93);ism["hunter7.gif"] = im(0, 98);ism["stenchtourist.gif"] = im(0, 93);ism["nightstand2.gif"] = im(13, 91);ism["darkstand.gif"] = im(1, 98);ism["nightstand.gif"] = im(2, 96);ism["nightstand4.gif"] = im(1, 99);ism["fear2.gif"] = im(1, 95);ism["nightstand3.gif"] = im(7, 95);ism["spittoon.gif"] = im(3, 99);ism["smiley.gif"] = im(30, 67);ism["annoyfairy.gif"] = im(15, 76);ism["spiderserver.gif"] = im(7, 94);ism["lizardman.gif"] = im(4, 94);ism["aquabat.gif"] = im(150, 100, 15, 79);ism["aquaconda.gif"] = im(5, 91);ism["aquagoblin.gif"] = im(0, 99);ism["2headseal.gif"] = im(9, 81);ism["mush_armor.gif"] = im(7, 91);ism["adv_spooky4.gif"] = im(4, 96);ism["adv_stench3.gif"] = im(5, 95);ism["astronomer.gif"] = im(6, 93);ism["aquadargon.gif"] = im(200, 200, 6, 190);ism["elf_auteur.gif"] = im(15, 78);ism["disco_awkward.gif"] = im(4, 95);ism["axehandle.gif"] = im(9, 89);ism["axewound.gif"] = im(9, 87);ism["saucezombie.gif"] = im(0, 97);ism["stone_serpent.gif"] = im(0, 98);ism["stone_sheep.gif"] = im(21, 81);ism["baconsnake.gif"] = im(4, 96);ism["badascii.gif"] = im(35, 61);ism["pa_potatoes.gif"] = im(8, 95);ism["baglady.gif"] = im(0, 99);ism["warhipmo.gif"] = im(44, 98);ism["baiowulf.gif"] = im(8, 94);ism["spelunkbanana.gif"] = im(150, 150, 0, 149);ism["bangyomama.gif"] = im(2, 89);ism["banjowizard.gif"] = im(0, 99);ism["banshee.gif"] = im(6, 98);ism["bar.gif"] = im(13, 88);ism["ratsworth.gif"] = im(0, 96);ism["basaltamander.gif"] = im(0, 99);ism["ballbat.gif"] = im(7, 60);ism["reindeer.gif"] = im(0, 99);ism["basicgolem.gif"] = im(6, 89);ism["spelunkbat.gif"] = im(15, 77);ism["bb_bat.gif"] = im(27, 81);ism["adv_spooky3.gif"] = im(1, 93);ism["batrat.gif"] = im(25, 75);ism["snakeboss5.gif"] = im(150, 150, 13, 141);ism["bb_mech.gif"] = im(1, 98);ism["aboo_wars.gif"] = im(3, 98);ism["gremlinbat.gif"] = im(11, 83);ism["bazookafish.gif"] = im(25, 68);ism["beanbat.gif"] = im(28, 63);ism["topi2.gif"] = im(9, 93);ism["earbeast.gif"] = im(14, 80);ism["eyebeast.gif"] = im(17, 99);ism["beaver.gif"] = im(13, 77);ism["spelunkbee.gif"] = im(3, 86);ism["beeswarm.gif"] = im(3, 97);ism["beethoven.gif"] = im(5, 94);ism["beebeegunner.gif"] = im(16, 70);ism["beebeeking.gif"] = im(16, 79);ism["beebeequeue.gif"] = im(4, 97);ism["beefybat.gif"] = im(18, 58);ism["beelephant.gif"] = im(0, 89);ism["batter.gif"] = im(0, 99);ism["warfratbg.gif"] = im(0, 95);ism["straw_stench.gif"] = im(15, 93);ism["bellhop.gif"] = im(17, 89);ism["carpet.gif"] = im(33, 75);ism["novelist.gif"] = im(2, 92);ism["wraith2.gif"] = im(15, 89);ism["biclops.gif"] = im(4, 92);ism["spider1.gif"] = im(15, 78);ism["bigmeat.gif"] = im(0, 94);ism["whelps2.gif"] = im(1, 98);ism["twins_bigwheel.gif"] = im(200, 100, 5, 95);ism["aquaniewski.gif"] = im(0, 97);ism["bigface.gif"] = im(14, 92);ism["vib2.gif"] = im(3, 97);ism["blimp.gif"] = im(8, 94);ism["blackadder.gif"] = im(12, 79);ism["blackcat.gif"] = im(4, 90);ism["cray_beast.gif"] = im(200, 200, 41, 171);ism["cray_bug.gif"] = im(200, 200, 43, 152);ism["cray_const.gif"] = im(200, 200, 15, 193);ism["cray_elf.gif"] = im(200, 200, 22, 181);ism["cray_demon.gif"] = im(200, 200, 32, 178);ism["cray_elemental.gif"] = im(200, 200, 8, 191);ism["cray_fish.gif"] = im(200, 200, 30, 145);ism["cray_plant.gif"] = im(200, 200, 9, 184);ism["cray_orc.gif"] = im(200, 200, 32, 169);ism["cray_goblin.gif"] = im(200, 200, 32, 167);ism["cray_construct.gif"] = im(200, 200, 23, 183);ism["cray_hippy.gif"] = im(200, 200, 19, 163);ism["cray_hobo.gif"] = im(200, 200, 1, 198);ism["cray_dude.gif"] = im(200, 200, 7, 182);ism["cray_humanoid.gif"] = im(200, 200, 12, 188);ism["cray_merkin.gif"] = im(200, 200, 17, 172);ism["cray_penguin.gif"] = im(200, 200, 31, 185);ism["cray_pirate.gif"] = im(200, 200, 18, 179);ism["cray_horror.gif"] = im(200, 200, 1, 197);ism["cray_slime.gif"] = im(200, 200, 61, 166);ism["cray_weird.gif"] = im(200, 200, 27, 186);ism["cray_undead.gif"] = im(200, 200, 22, 162);ism["blackfriar.gif"] = im(5, 97);ism["blknight.gif"] = im(4, 90);ism["witchywoman.gif"] = im(1, 99);ism["bb_ninja.gif"] = im(5, 91);ism["panther.gif"] = im(11, 93);ism["blpudding.gif"] = im(47, 98);ism["blackwidow.gif"] = im(0, 99);ism["pengblackop.gif"] = im(3, 98);ism["blackbush.gif"] = im(15, 98);ism["sawblade.gif"] = im(0, 98);ism["firebat.gif"] = im(1, 97);ism["squid.gif"] = im(3, 95);ism["bluecultist.gif"] = im(0, 99);ism["mh_bluehair.gif"] = im(1, 98);ism["blur.gif"] = im(4, 97);ism["boaraffe.gif"] = im(0, 99);ism["naskar2.gif"] = im(5, 95);ism["bogleech.gif"] = im(10, 91);ism["bogskeleton.gif"] = im(1, 95);ism["bogart.gif"] = im(11, 91);ism["elf_boltcutters.gif"] = im(5, 78);ism["foss_wyrm.gif"] = im(200, 200, 0, 196);ism["bookbat.gif"] = im(22, 65);ism["boothslime.gif"] = im(2, 97);ism["bootycrab.gif"] = im(20, 85);ism["boozegiant.gif"] = im(5, 92);ism["borgabeeping.gif"] = im(0, 96);ism["bossbat.gif"] = im(26, 73);ism["deadbossbat.gif"] = im(7, 94);ism["crimonster3.gif"] = im(4, 96);ism["cricket.gif"] = im(5, 97);ism["box.gif"] = im(9, 87);ism["pa_muffin.gif"] = im(13, 87);ism["mystwander5.gif"] = im(5, 99);ism["broombrain.gif"] = im(6, 95);ism["bram.gif"] = im(8, 92);ism["breadgolem.gif"] = im(6, 90);ism["breakdancer.gif"] = im(0, 97);ism["brick_sleaze.gif"] = im(24, 96);ism["brick_cold.gif"] = im(1, 95);ism["brick_hot.gif"] = im(0, 99); +ism["brick_spooky.gif"] = im(4, 95);ism["kok_tender.gif"] = im(21, 97);ism["brick_stench.gif"] = im(4, 94);ism["brickoairship.gif"] = im(300, 300, 6, 295);ism["brickobat.gif"] = im(3, 68);ism["brickocathedral.gif"] = im(500, 450, 17, 443);ism["brickoelephant.gif"] = im(150, 150, 34, 132);ism["brickogchicken.gif"] = im(600, 450, 15, 444);ism["brickoctopus.gif"] = im(150, 150, 9, 143);ism["brickoblob.gif"] = im(57, 94);ism["brickooyster.gif"] = im(16, 91);ism["brickopython.gif"] = im(450, 100, 11, 87);ism["brickoturtle.gif"] = im(22, 77);ism["brickovacuum.gif"] = im(200, 200, 17, 182);ism["casebat.gif"] = im(40, 63);ism["bath_bubble.gif"] = im(17, 76);ism["iceguy5.gif"] = im(0, 97);ism["broctopus.gif"] = im(0, 99);ism["bronzechef.gif"] = im(0, 99);ism["babyseal.gif"] = im(6, 84);ism["togafrat.gif"] = im(2, 96);ism["twins_bubble.gif"] = im(13, 94);ism["bb_ghost.gif"] = im(5, 89);ism["bb_captain.gif"] = im(150, 150, 3, 143);ism["bb_drone.gif"] = im(2, 97);ism["bb_mortician.gif"] = im(9, 91);ism["robosurgeon.gif"] = im(14, 88);ism["bb_science.gif"] = im(6, 88);ism["binbox.gif"] = im(4, 91);ism["bugbugbear.gif"] = im(6, 91);ism["bulletbill.gif"] = im(15, 83);ism["bullseal.gif"] = im(9, 95);ism["ratbunch.gif"] = im(1, 92);ism["pa_meat.gif"] = im(5, 96);ism["bunsen.gif"] = im(9, 87);ism["sidekick.gif"] = im(5, 97);ism["adv_hot3.gif"] = im(18, 95);ism["snakeboss4.gif"] = im(150, 150, 19, 133);ism["bishop.gif"] = im(54, 94);ism["bush.gif"] = im(8, 93);ism["bushippy.gif"] = im(8, 94);ism["hedgerow.gif"] = im(25, 79);ism["pa_knife.gif"] = im(1, 87);ism["buzzerker.gif"] = im(11, 84);ism["buzzy.gif"] = im(0, 97);ism["chum1.gif"] = im(7, 91);ism["chumchief.gif"] = im(7, 94);ism["carnivore.gif"] = im(6, 96);ism["animbear.gif"] = im(0, 99);ism["laundrycabinet.gif"] = im(1, 98);ism["cactuary.gif"] = im(0, 97);ism["cakelord.gif"] = im(0, 98);ism["cameltoe.gif"] = im(5, 97);ism["cancan.gif"] = im(4, 97);ism["pecantree.gif"] = im(1, 98);ism["yamgolem.gif"] = im(0, 97);ism["gourd_cangoblin.gif"] = im(9, 88);ism["carbuncletop.gif"] = im(1, 92);ism["cargocrab.gif"] = im(7, 94);ism["dillplant.gif"] = im(2, 99);ism["carniv.gif"] = im(5, 94);ism["pa_eggs.gif"] = im(22, 86);ism["thecastle.gif"] = im(21, 78);ism["catalien.gif"] = im(21, 89);ism["spelunkcaveman.gif"] = im(7, 91);ism["cavedan.gif"] = im(0, 97);ism["cavefrat.gif"] = im(2, 95);ism["cavehippy.gif"] = im(0, 97);ism["cavesorority.gif"] = im(0, 95);ism["cavewomyn.gif"] = im(0, 94);ism["butt.gif"] = im(16, 81);ism["pengcement.gif"] = im(2, 97);ism["centurion.gif"] = im(7, 80);ism["adv_hot2.gif"] = im(2, 96);ism["chimp.gif"] = im(6, 90);ism["chalkdust.gif"] = im(6, 98);ism["hunter10.gif"] = im(1, 97);ism["c10chatty.gif"] = im(0, 96);ism["strix.gif"] = im(4, 93);ism["adv_stench2.gif"] = im(1, 97);ism["adv_fast1.gif"] = im(4, 93);ism["chefboy.gif"] = im(0, 98);ism["chester.gif"] = im(1, 97);ism["robotceo.gif"] = im(5, 92);ism["chocohare.gif"] = im(23, 93);ism["ccprairie.gif"] = im(1, 97);ism["soupgolem.gif"] = im(3, 93);ism["ciggirl.gif"] = im(0, 99);ism["animelf3.gif"] = im(19, 80);ism["cavebars.gif"] = im(0, 98);ism["clancy.gif"] = im(9, 94);ism["bathtub.gif"] = im(50, 97);ism["claygolem.gif"] = im(1, 98);ism["aboo_wiz.gif"] = im(3, 96);ism["cleanroomdemon.gif"] = im(5, 95);ism["cleanpirate.gif"] = im(3, 94);ism["girlpirate.gif"] = im(7, 91);ism["colaoff1.gif"] = im(4, 94);ism["colasol1.gif"] = im(6, 96);ism["rock_hopper.gif"] = im(0, 99);ism["whiskers.gif"] = im(8, 84);ism["clubfish.gif"] = im(1, 90);ism["prim_bact.gif"] = im(0, 98);ism["coaltergeist.gif"] = im(5, 91);ism["kg_oven.gif"] = im(8, 97);ism["spelunkcobra.gif"] = im(14, 77);ism["cocktailshrimp.gif"] = im(0, 99);ism["dvcoldbear1.gif"] = im(3, 97);ism["coldcutter.gif"] = im(2, 94);ism["dvcoldghost1.gif"] = im(0, 96);ism["coldhobo1.gif"] = im(5, 89);ism["wood_cold.gif"] = im(13, 96);ism["dvcoldskel1.gif"] = im(1, 95);ism["dvcoldvamp1.gif"] = im(3, 94);ism["dvcoldwolf1.gif"] = im(1, 98);ism["dvcoldzom1.gif"] = im(5, 98);ism["minegolem.gif"] = im(4, 89);ism["spider2.gif"] = im(20, 83);ism["pianist.gif"] = im(0, 98);ism["lilgoth.gif"] = im(19, 96);ism["2zombies.gif"] = im(6, 92);ism["conhippy.gif"] = im(2, 94);ism["regret1.gif"] = im(2, 90);ism["pa_cutter.gif"] = im(21, 76);ism["crimonster2.gif"] = im(0, 99);ism["coolerwino.gif"] = im(0, 97);ism["coppertender.gif"] = im(6, 91);ism["fatzombie.gif"] = im(9, 93);ism["prim_alga.gif"] = im(0, 98);ism["makeupwraith.gif"] = im(11, 81);ism["bakula.gif"] = im(7, 90);ism["drunkula.gif"] = im(100, 175, 5, 166);ism["drunkula_hm.gif"] = im(300, 175, 2, 159);ism["courtesan.gif"] = im(5, 95);ism["cowskeleton.gif"] = im(1, 97);ism["creep.gif"] = im(13, 91);ism["craggybart.gif"] = im(3, 91);ism["crate.gif"] = im(10, 89);ism["stone_raven.gif"] = im(21, 85);ism["bastard.gif"] = im(3, 94);ism["adv_smooth2.gif"] = im(3, 94);ism["clown.gif"] = im(3, 97);ism["creepydoll.gif"] = im(4, 96);ism["dianoga.gif"] = im(11, 87);ism["twins_ginger.gif"] = im(1, 98);ism["creepygirl.gif"] = im(32, 97);ism["pa_torch.gif"] = im(3, 92);ism["crimbomega.gif"] = im(400, 550, 7, 545);ism["spelunkcroc.gif"] = im(6, 89);ism["croqueteer.gif"] = im(1, 90);ism["dustmote.gif"] = im(20, 86);ism["hippy3.gif"] = im(8, 94);ism["crustpirate.gif"] = im(1, 95);ism["crys_rock.gif"] = im(200, 150, 2, 137);ism["cubistbull.gif"] = im(0, 99);ism["spelunkhawk.gif"] = im(3, 95);ism["curmpirate.gif"] = im(6, 93);ism["cybercop.gif"] = im(2, 97);ism["prim_cyru.gif"] = im(0, 98);ism["dad_machine.gif"] = im(400, 300, 6, 294);ism["daftpunk.gif"] = im(3, 97);ism["biggoat.gif"] = im(2, 98);ism["ooze.gif"] = im(45, 93);ism["dirtyape.gif"] = im(0, 99);ism["mush_dancing.gif"] = im(11, 91);ism["chad.gif"] = im(3, 93);ism["rorshach.gif"] = im(8, 79);ism["bath_showerhead.gif"] = im(2, 97);ism["venomtrout.gif"] = im(47, 99);ism["vice.gif"] = im(20, 85);ism["shiv_dead.gif"] = im(3, 94);ism["deathray.gif"] = im(4, 98);ism["lumberjack.gif"] = im(5, 92);ism["whiteshark.gif"] = im(15, 71);ism["5_4a.gif"] = im(200, 200, 0, 197);ism["demfridge.gif"] = im(1, 99);ism["jigsaw.gif"] = im(12, 83);ism["demoninja.gif"] = im(17, 89);ism["liana.gif"] = im(13, 90);ism["wanderacc1.gif"] = im(1, 97);ism["hunter8.gif"] = im(0, 97);ism["goldfarmer.gif"] = im(9, 91);ism["smoochboss4.gif"] = im(100, 200, 11, 191);ism["spelunkdevil.gif"] = im(0, 99);ism["digitalug.gif"] = im(17, 87);ism["dinnertroll.gif"] = im(13, 87);ism["direpigeon.gif"] = im(0, 98);ism["hippy2.gif"] = im(8, 93);ism["dirtyoldlihc.gif"] = im(6, 99);ism["bandit.gif"] = im(1, 95);ism["dinbox.gif"] = im(16, 91);ism["c10files.gif"] = im(7, 98);ism["divingbelle.gif"] = im(0, 99);ism["js_oh.gif"] = im(5, 91);ism["pede.gif"] = im(20, 81);ism["dogalien.gif"] = im(3, 92);ism["catdog.gif"] = im(17, 85);ism["iceguy2.gif"] = im(8, 97);ism["doncrimbo.gif"] = im(0, 99);ism["donerbagon.gif"] = im(200, 200, 1, 189);ism["dwarf_dopey.gif"] = im(0, 99);ism["doubtman.gif"] = im(200, 200, 2, 193);ism["doughbat.gif"] = im(41, 63);ism["aquard.gif"] = im(0, 99);ism["drawkward.gif"] = im(4, 95);ism["braddarb.gif"] = im(5, 96);ism["droll.gif"] = im(18, 87);ism["dropbase.gif"] = im(12, 80);ism["drownedsailor.gif"] = im(1, 97);ism["drownedbeat.gif"] = im(0, 95);ism["ducknicedrunk.gif"] = im(1, 94);ism["drunkgoat.gif"] = im(2, 98);ism["pyg_drunk.gif"] = im(9, 99);ism["drunkminer.gif"] = im(0, 98);ism["hobo.gif"] = im(5, 91);ism["rat.gif"] = im(33, 67);ism["ratking.gif"] = im(200, 200, 7, 185);ism["kok_drunk.gif"] = im(0, 93);ism["zomhobo.gif"] = im(5, 91);ism["aboo_dipshit.gif"] = im(1, 97);ism["straw_spooky.gif"] = im(39, 91);ism["dwarfgnome.gif"] = im(17, 84);ism["dweebie.gif"] = im(5, 94);ism["colaoff2.gif"] = im(4, 94);ism["colasol2.gif"] = im(6, 96);ism["eve.gif"] = im(0, 93);ism["eagle.gif"] = im(0, 98);ism["ed.gif"] = im(1, 98);ism["ed2.gif"] = im(1, 98);ism["ed3.gif"] = im(1, 98);ism["ed4.gif"] = im(1, 98);ism["ed5.gif"] = im(1, 98);ism["ed6.gif"] = im(22, 98);ism["ed7.gif"] = im(46, 98);ism["edwing.gif"] = im(24, 83);ism["eldiablo.gif"] = im(0, 99);ism["elders.gif"] = im(11, 85);ism["submarine.gif"] = im(8, 86);ism["nightstand5.gif"] = im(22, 82);ism["topi3.gif"] = im(7, 90);ism["elfhobo1.gif"] = im(28, 97);ism["warfratbg2.gif"] = im(0, 95);ism["elp_and_cros.gif"] = im(300, 150, 5, 146);ism["skinyeti.gif"] = im(4, 90);ism["armor.gif"] = im(0, 98);ism["inflatiger.gif"] = im(7, 98);ism["c10confcall.gif"] = im(2, 94);ism["grayblob3.gif"] = im(150, 200, 21, 178);ism["cow.gif"] = im(0, 99);ism["adv_strong3.gif"] = im(9, 91);ism["gremlinglasses.gif"] = im(7, 94);ism["stairmaster.gif"] = im(12, 94);ism["mc_respect3.gif"] = im(4, 94);ism["mc_soy3.gif"] = im(0, 97);ism["mc_tofu3.gif"] = im(1, 98);ism["cultist.gif"] = im(3, 98);ism["mh_evilex.gif"] = im(0, 99);ism["oliveevil.gif"] = im(13, 85);ism["spagcult2.gif"] = im(1, 95);ism["spagcult3.gif"] = im(0, 99);ism["spagcult1.gif"] = im(0, 98);ism["spagcult2k.gif"] = im(1, 95);ism["spagcult4.gif"] = im(0, 99);ism["spagcult1k.gif"] = im(0, 98);ism["trumpetmariachi.gif"] = im(2, 97);ism["vihuelamariachi.gif"] = im(2, 96);ism["crimbominer1.gif"] = im(0, 99);ism["skihippy.gif"] = im(3, 94);ism["fratboard.gif"] = im(3, 91);ism["wcorcs.gif"] = im(0, 97); +ism["witchy2.gif"] = im(0, 99);ism["darkeye.gif"] = im(5, 91);ism["guai.gif"] = im(11, 85);ism["facworker4.gif"] = im(3, 95);ism["facworker3.gif"] = im(1, 97);ism["facworker1.gif"] = im(3, 97);ism["facworker2.gif"] = im(1, 93);ism["badskel1.gif"] = im(20, 84);ism["archfiend.gif"] = im(10, 84);ism["fallsfromsky.gif"] = im(100, 150, 2, 143);ism["fallsfromsky_hm.gif"] = im(200, 300, 7, 285);ism["jewels.gif"] = im(8, 82);ism["kobolds.gif"] = im(0, 97);ism["fandancer.gif"] = im(6, 91);ism["fanslime.gif"] = im(2, 94);ism["bathslug.gif"] = im(1, 98);ism["hunter5.gif"] = im(1, 98);ism["hunter9.gif"] = im(1, 93);ism["fearman.gif"] = im(200, 200, 12, 185);ism["bath_octopus.gif"] = im(0, 98);ism["wacken.gif"] = im(200, 200, 23, 186);ism["manyeyes.gif"] = im(4, 81);ism["felonia.gif"] = im(0, 98);ism["haiku2.gif"] = im(6, 91);ism["bath_pelican.gif"] = im(1, 97);ism["ferrelf.gif"] = im(5, 90);ism["finger.gif"] = im(2, 96);ism["asparagus.gif"] = im(9, 89);ism["mush_flaming.gif"] = im(0, 99);ism["duckskate.gif"] = im(2, 98);ism["filthworm2.gif"] = im(24, 75);ism["filthworm3.gif"] = im(19, 70);ism["hippy1.gif"] = im(8, 89);ism["stinkpirate1.gif"] = im(3, 97);ism["adv_hot1.gif"] = im(1, 97);ism["firetruck.gif"] = im(300, 150, 7, 145);ism["duckfirebreath.gif"] = im(7, 91);ism["fisherfish.gif"] = im(3, 97);ism["stinkpirate3.gif"] = im(1, 93);ism["giant_fitness.gif"] = im(9, 97);ism["bigskeleton5.gif"] = im(250, 100, 0, 99);ism["meatblob.gif"] = im(10, 79);ism["samurai.gif"] = im(0, 99);ism["flametroll.gif"] = im(1, 96);ism["flange.gif"] = im(12, 78);ism["flashypirate.gif"] = im(4, 94);ism["cvfleaman.gif"] = im(5, 90);ism["woodsman.gif"] = im(9, 96);ism["disco_flexible.gif"] = im(3, 97);ism["caveelf3.gif"] = im(25, 85);ism["horstray.gif"] = im(19, 89);ism["seagulls.gif"] = im(3, 91);ism["stabbats.gif"] = im(0, 97);ism["bunny.gif"] = im(49, 94);ism["gourd_fnord.gif"] = im(200, 200, 23, 171);ism["giant_foodie.gif"] = im(4, 97);ism["forspirit.gif"] = im(21, 74);ism["bigskeleton4.gif"] = im(200, 100, 0, 99);ism["mime.gif"] = im(0, 97);ism["artteacher.gif"] = im(4, 95);ism["accboss.gif"] = im(0, 98);ism["warfrata.gif"] = im(1, 96);ism["mush_freaked.gif"] = im(9, 91);ism["frenchturtle.gif"] = im(19, 72);ism["bonefish.gif"] = im(40, 97);ism["frog.gif"] = im(53, 99);ism["frosty.gif"] = im(0, 99);ism["straw_cold.gif"] = im(12, 91);ism["mystwander3.gif"] = im(8, 94);ism["duckfrozen.gif"] = im(2, 96);ism["snakeboss1.gif"] = im(150, 150, 21, 133);ism["fruitgolem.gif"] = im(8, 97);ism["anger3.gif"] = im(0, 99);ism["fudgemonkey2.gif"] = im(0, 99);ism["fudgeoyster.gif"] = im(0, 99);ism["fudgepoodle.gif"] = im(2, 96);ism["fudgevulture.gif"] = im(0, 99);ism["fudgeweasel.gif"] = im(11, 86);ism["bigmirror.gif"] = im(0, 99);ism["fun-gal1.gif"] = im(0, 99);ism["funkparticle.gif"] = im(8, 94);ism["solebrother.gif"] = im(19, 76);ism["stinkpirate2.gif"] = im(3, 96);ism["shiv_fur.gif"] = im(1, 94);ism["giant_furry.gif"] = im(0, 98);ism["gimp.gif"] = im(15, 90);ism["gamblinman.gif"] = im(1, 95);ism["muggers.gif"] = im(2, 98);ism["ganger.gif"] = im(16, 88);ism["garbagetourist.gif"] = im(3, 94);ism["gargantulihc.gif"] = im(1, 93);ism["ghuol_skinny.gif"] = im(16, 90);ism["gelcube.gif"] = im(12, 97);ism["generalseal.gif"] = im(150, 100, 2, 97);ism["duckgeneric.gif"] = im(4, 94);ism["merkinballer2.gif"] = im(1, 99);ism["smoochboss1.gif"] = im(100, 200, 8, 189);ism["phantom.gif"] = im(1, 95);ism["cvghost.gif"] = im(4, 92);ism["spelunkghost.gif"] = im(11, 91);ism["ghostminer.gif"] = im(1, 98);ism["elizabeth.gif"] = im(10, 86);ism["fernghost.gif"] = im(1, 92);ism["worker.gif"] = im(2, 94);ism["adv_spooky1.gif"] = im(8, 91);ism["ghuol_reg.gif"] = im(11, 85);ism["giantbee.gif"] = im(2, 84);ism["pterodactyl.gif"] = im(6, 91);ism["globe.gif"] = im(0, 95);ism["friedegg.gif"] = im(2, 82);ism["centipede.gif"] = im(21, 81);ism["moth.gif"] = im(5, 95);ism["isopod.gif"] = im(35, 95);ism["python.gif"] = im(4, 93);ism["bath_whale.gif"] = im(14, 82);ism["manyspiders.gif"] = im(1, 94);ism["watertentacle.gif"] = im(6, 93);ism["tweezers.gif"] = im(6, 93);ism["headpumpkin.gif"] = im(5, 96);ism["rubberspider.gif"] = im(15, 84);ism["sandworm.gif"] = im(2, 99);ism["giantskel.gif"] = im(0, 99);ism["tarantula.gif"] = im(1, 97);ism["giantsquid.gif"] = im(0, 98);ism["whelps3.gif"] = im(0, 99);ism["tardigrade.gif"] = im(4, 91);ism["zomfish.gif"] = im(2, 86);ism["crimonster5.gif"] = im(0, 92);ism["gingerbreadman.gif"] = im(0, 99);ism["gladiator.gif"] = im(1, 96);ism["juiceglass.gif"] = im(12, 87);ism["wood_hot.gif"] = im(3, 95);ism["ghuol_fat.gif"] = im(13, 87);ism["gnarlgnome.gif"] = im(9, 79);ism["gnasgnome.gif"] = im(6, 77);ism["gnefgnome.gif"] = im(12, 83);ism["dk_builder.gif"] = im(9, 97);ism["dk_cross.gif"] = im(3, 94);ism["dk_swatter.gif"] = im(3, 95);ism["dk_gearhead.gif"] = im(1, 97);ism["dk_piechef.gif"] = im(0, 99);ism["dk_plunger.gif"] = im(3, 93);ism["gnollmage.gif"] = im(3, 95);ism["dk_juggler.gif"] = im(1, 97);ism["dk_warchef.gif"] = im(0, 98);ism["gnomester.gif"] = im(5, 91);ism["gnugnome.gif"] = im(10, 84);ism["gourd_goblin.gif"] = im(7, 92);ism["goldenring.gif"] = im(17, 86);ism["goomba.gif"] = im(9, 89);ism["goosealaying.gif"] = im(0, 99);ism["1_4a.gif"] = im(200, 200, 2, 198);ism["1_1.gif"] = im(18, 93);ism["1_2.gif"] = im(10, 92);ism["1_3.gif"] = im(10, 93);ism["giant_goth.gif"] = im(3, 96);ism["gourami.gif"] = im(51, 93);ism["gov_agent.gif"] = im(11, 94);ism["scientist.gif"] = im(3, 95);ism["adv_stench1.gif"] = im(6, 97);ism["grasselemental.gif"] = im(0, 99);ism["grasspirate.gif"] = im(0, 95);ism["rober.gif"] = im(8, 91);ism["zomshovel.gif"] = im(4, 94);ism["adv_sleaze1.gif"] = im(3, 90);ism["duckgreasy.gif"] = im(0, 91);ism["wolfoftheair.gif"] = im(200, 150, 8, 136);ism["wolfoftheair_hm.gif"] = im(200, 150, 7, 135);ism["warhipgr.gif"] = im(5, 93);ism["porkbun.gif"] = im(14, 79);ism["gritpirate.gif"] = im(1, 97);ism["surv_grizzled.gif"] = im(3, 91);ism["wingedyeti.gif"] = im(200, 100, 0, 99);ism["groast.gif"] = im(5, 94);ism["grouchewie.gif"] = im(7, 90);ism["cultistgroup.gif"] = im(4, 96);ism["groupie.gif"] = im(16, 85);ism["dwarf_grumpy.gif"] = im(0, 99);ism["grungypirate.gif"] = im(11, 95);ism["guardturtle1.gif"] = im(29, 89);ism["plesio.gif"] = im(1, 98);ism["gurgle.gif"] = im(150, 100, 0, 99);ism["animturtle.gif"] = im(100, 120, 4, 118);ism["beeguy.gif"] = im(0, 96);ism["gothic.gif"] = im(4, 96);ism["adv_sleaze2.gif"] = im(6, 89);ism["drunkyam.gif"] = im(0, 99);ism["hamsterpus.gif"] = im(2, 88);ism["mariachi1.gif"] = im(2, 97);ism["shiv_hangman.gif"] = im(3, 93);ism["hunter12.gif"] = im(3, 97);ism["skullabra.gif"] = im(1, 91);ism["tureen.gif"] = im(6, 87);ism["crystalgolem.gif"] = im(1, 92);ism["heatseal.gif"] = im(0, 99);ism["warfratar2.gif"] = im(10, 88);ism["nachogolem.gif"] = im(0, 98);ism["hellion.gif"] = im(3, 95);ism["sealguard.gif"] = im(13, 95);ism["sealpup.gif"] = im(29, 81);ism["hepcat.gif"] = im(1, 98);ism["hunter6.gif"] = im(3, 96);ism["hermeticseal.gif"] = im(5, 88);ism["c10slideshow.gif"] = im(10, 89);ism["highpriest.gif"] = im(0, 99);ism["warbear31.gif"] = im(0, 99);ism["snakes.gif"] = im(2, 83);ism["hockeyelem.gif"] = im(6, 90);ism["hodgman.gif"] = im(1, 96);ism["holoarmy.gif"] = im(2, 92);ism["honeypot.gif"] = im(5, 92);ism["hooded.gif"] = im(4, 96);ism["stenchfamily.gif"] = im(4, 96);ism["prim_amoe.gif"] = im(0, 98);ism["dvhotbear1.gif"] = im(5, 94);ism["dvhotghost1.gif"] = im(4, 93);ism["hothobo1.gif"] = im(3, 92);ism["dvhotskel1.gif"] = im(13, 99);ism["dvhotvamp1.gif"] = im(0, 98);ism["dvhotwolf1.gif"] = im(12, 98);ism["dvhotzom1.gif"] = im(1, 98);ism["mimic4.gif"] = im(1, 97);ism["ghuol_huge.gif"] = im(5, 95);ism["giantmosquito.gif"] = im(0, 98);ism["iceguy1.gif"] = im(1, 98);ism["bridgetroll.gif"] = im(2, 97);ism["vib6.gif"] = im(7, 98);ism["caveelf2.gif"] = im(18, 73);ism["huntingseal.gif"] = im(9, 85);ism["poolghost.gif"] = im(0, 99);ism["hypnotist.gif"] = im(0, 97);ism["medicus.gif"] = im(3, 92);ism["bb_vamp.gif"] = im(3, 93);ism["adv_cold2.gif"] = im(0, 98);ism["icecreamtruck.gif"] = im(400, 150, 9, 142);ism["icecube.gif"] = im(12, 94);ism["iceskate.gif"] = im(4, 96);ism["adv_cold3.gif"] = im(8, 93);ism["mummycat.gif"] = im(1, 96);ism["illegal_alien.gif"] = im(24, 96);ism["vib3.gif"] = im(0, 99);ism["drunktofurkey.gif"] = im(0, 99);ism["seal_larva.gif"] = im(63, 93);ism["seal_baby.gif"] = im(47, 93);ism["meatbug.gif"] = im(7, 89);ism["inkubus.gif"] = im(7, 97);ism["mariachi2.gif"] = im(2, 91);ism["adv_strong2.gif"] = im(5, 92);ism["encount.gif"] = im(3, 93);ism["jacobsadder.gif"] = im(0, 99);ism["orquette1.gif"] = im(13, 86);ism["jamfish.gif"] = im(0, 98);ism["pilot.gif"] = im(3, 97);ism["jetski.gif"] = im(15, 94);ism["jockohomo.gif"] = im(0, 98);ism["merkindragger2.gif"] = im(1, 99);ism["doubt3.gif"] = im(0, 99);ism["orangutan.gif"] = im(8, 97);ism["scabie_jungle.gif"] = im(2, 92);ism["thejunk.gif"] = im(19, 86);ism["js_bender.gif"] = im(5, 91);ism["js_melter.gif"] = im(11, 95);ism["js_sharpener.gif"] = im(7, 90);ism["orquette2.gif"] = im(13, 86);ism["keese.gif"] = im(25, 66);ism["tooold.gif"] = im(1, 97);ism["clownfish.gif"] = im(22, 82);ism["killingbird.gif"] = im(0, 98);ism["adv_smart3.gif"] = im(15, 94);ism["snaknight.gif"] = im(0, 97);ism["wolfknight.gif"] = im(3, 97);ism["knight.gif"] = im(7, 91);ism["kg_accountant.gif"] = im(12, 98);ism["kg_alchemist.gif"] = im(15, 94);ism["kg_asstchef.gif"] = im(0, 99);ism["kg_bbqteam.gif"] = im(1, 99);ism["kg_beancounter.gif"] = im(12, 97);ism["kg_guard.gif"] = im(10, 94);ism["kg_guardcaptain.gif"] = im(10, 94);ism["zomelite.gif"] = im(6, 90); +ism["kg_embezzler.gif"] = im(12, 97);ism["kg_haremgirl.gif"] = im(15, 89);ism["kg_haremguard.gif"] = im(14, 94);ism["kg_king.gif"] = im(0, 98);ism["kg_madsci.gif"] = im(11, 91);ism["kg_madam.gif"] = im(16, 97);ism["kg_masterchef.gif"] = im(0, 99);ism["kg_mba.gif"] = im(16, 98);ism["kg_mutant.gif"] = im(13, 97);ism["kg_poseur.gif"] = im(28, 94);ism["kg_souschef.gif"] = im(0, 98);ism["kg_verymadsci.gif"] = im(15, 92);ism["slanding.gif"] = im(5, 91);ism["yeti.gif"] = im(1, 95);ism["koopa.gif"] = im(5, 93);ism["kublakhan.gif"] = im(5, 92);ism["adv_fast3.gif"] = im(4, 92);ism["limp.gif"] = im(8, 94);ism["labmonkey.gif"] = im(16, 91);ism["n00b.gif"] = im(6, 91);ism["lower_k.gif"] = im(7, 81);ism["headwolf.gif"] = im(0, 98);ism["grayblob2.gif"] = im(9, 93);ism["larrysignfield.gif"] = im(9, 95);ism["filthworm1.gif"] = im(49, 83);ism["laser.gif"] = im(9, 97);ism["lavagolem.gif"] = im(5, 89);ism["lavalamprey.gif"] = im(3, 95);ism["lavalos.gif"] = im(200, 300, 7, 290);ism["lavatory.gif"] = im(0, 98);ism["statbike.gif"] = im(2, 96);ism["linbox.gif"] = im(17, 91);ism["lemonfish.gif"] = im(17, 74);ism["adv_sleaze4.gif"] = im(3, 97);ism["lfruitgol.gif"] = im(33, 84);ism["licosnake.gif"] = im(5, 94);ism["lich.gif"] = im(3, 98);ism["bb_liquidmetal.gif"] = im(7, 92);ism["liquidmetal.gif"] = im(1, 97);ism["grayblob1.gif"] = im(40, 88);ism["canoeman.gif"] = im(13, 66);ism["wanderacc2.gif"] = im(1, 98);ism["pa_bread.gif"] = im(7, 95);ism["lobsterman.gif"] = im(1, 98);ism["lollicat.gif"] = im(12, 91);ism["lolligator.gif"] = im(18, 85);ism["lollipede.gif"] = im(11, 77);ism["lolliphaunt.gif"] = im(12, 91);ism["spelunklolm.gif"] = im(250, 300, 3, 269);ism["lollirus2.gif"] = im(9, 91);ism["vib5.gif"] = im(1, 97);ism["coalition.gif"] = im(2, 89);ism["soggyraven.gif"] = im(0, 99);ism["lordspooky.gif"] = im(7, 97);ism["lotswife.gif"] = im(1, 97);ism["lizardfish.gif"] = im(31, 61);ism["regret2.gif"] = im(1, 95);ism["kok_lovers.gif"] = im(5, 97);ism["lower_h.gif"] = im(13, 87);ism["catstatue.gif"] = im(15, 84);ism["lumbersup.gif"] = im(5, 92);ism["lumberjill.gif"] = im(5, 92);ism["lumberjuan.gif"] = im(0, 92);ism["4_4a.gif"] = im(200, 200, 13, 168);ism["4_1.gif"] = im(21, 70);ism["4_2.gif"] = im(19, 92);ism["4_3.gif"] = im(3, 97);ism["lynyrd.gif"] = im(9, 91);ism["skinner.gif"] = im(2, 96);ism["adv_strong1.gif"] = im(5, 94);ism["madbugbear.gif"] = im(6, 95);ism["prim_flag.gif"] = im(0, 98);ism["madwino.gif"] = im(6, 94);ism["madiator.gif"] = im(2, 96);ism["dragonfish.gif"] = im(0, 99);ism["mech.gif"] = im(1, 98);ism["spelunkmagma.gif"] = im(7, 84);ism["cropcircle.gif"] = im(2, 93);ism["hairclog.gif"] = im(0, 94);ism["magfield.gif"] = im(1, 93);ism["tofurkey.gif"] = im(2, 92);ism["maltliquorgolem.gif"] = im(0, 99);ism["mammon.gif"] = im(200, 200, 11, 193);ism["redbuttons.gif"] = im(1, 93);ism["audrey.gif"] = im(0, 98);ism["wraith5.gif"] = im(10, 90);ism["bandolero.gif"] = im(0, 99);ism["mar_bruiser.gif"] = im(4, 93);ism["mariachi3.gif"] = im(1, 96);ism["wraith3.gif"] = im(9, 88);ism["promoter.gif"] = im(2, 93);ism["wasp.gif"] = im(13, 96);ism["mayorghost.gif"] = im(200, 150, 3, 146);ism["mayorghost_hm.gif"] = im(200, 150, 5, 147);ism["beggar.gif"] = im(0, 98);ism["duckmeandrunk.gif"] = im(3, 96);ism["med_dung.gif"] = im(5, 94);ism["med_mugman.gif"] = im(3, 92);ism["med_muggirl.gif"] = im(5, 89);ism["med_potter.gif"] = im(3, 91);ism["med_strawman.gif"] = im(0, 97);ism["med_stucco.gif"] = im(12, 96);ism["mimic3.gif"] = im(11, 89);ism["cvmedusa.gif"] = im(4, 91);ism["megafrog.gif"] = im(15, 89);ism["vib1.gif"] = im(0, 98);ism["lawngnome1.gif"] = im(14, 80);ism["nemesisthug.gif"] = im(7, 90);ism["merkinalphabet.gif"] = im(6, 93);ism["merkinballer.gif"] = im(4, 98);ism["merkinswitcher.gif"] = im(4, 98);ism["merkinburglar.gif"] = im(1, 95);ism["merkindiver.gif"] = im(1, 95);ism["merkindrifter.gif"] = im(4, 98);ism["merkinhealer.gif"] = im(3, 95);ism["merkinjuicer.gif"] = im(4, 98);ism["merkinminer.gif"] = im(1, 95);ism["merkinmonitor.gif"] = im(6, 93);ism["merkindragger.gif"] = im(4, 98);ism["merkinposeur.gif"] = im(1, 95);ism["merkinpunisher.gif"] = im(1, 95);ism["merkinraider.gif"] = im(3, 95);ism["merkinresearcher.gif"] = im(6, 93);ism["merkinspear.gif"] = im(1, 95);ism["merkinscav.gif"] = im(1, 95);ism["merkinghost.gif"] = im(13, 85);ism["merkinteacher.gif"] = im(2, 99);ism["merkintippler.gif"] = im(1, 99);ism["merkintrainer.gif"] = im(4, 98);ism["mercenary.gif"] = im(6, 95);ism["pengmesmer.gif"] = im(3, 99);ism["adv_smart2.gif"] = im(6, 98);ism["adv_fast2.gif"] = im(1, 96);ism["lowerm.gif"] = im(9, 90);ism["minecrab.gif"] = im(0, 99);ism["mineboss2.gif"] = im(1, 96);ism["mineboss1.gif"] = im(2, 97);ism["mineworker1.gif"] = im(3, 92);ism["mineworker2.gif"] = im(3, 92);ism["twins_mism.gif"] = im(100, 200, 17, 198);ism["badportrait.gif"] = im(0, 98);ism["pengarson.gif"] = im(2, 97);ism["mobcapo.gif"] = im(8, 95);ism["pengcapo.gif"] = im(3, 98);ism["pengdemo.gif"] = im(2, 98);ism["pengthug.gif"] = im(2, 98);ism["peng_ent.gif"] = im(3, 98);ism["pengbook.gif"] = im(2, 98);ism["penggoon.gif"] = im(2, 98);ism["penggun.gif"] = im(3, 98);ism["pengchef.gif"] = im(3, 98);ism["pengpsycho.gif"] = im(3, 98);ism["pengracket.gif"] = im(3, 99);ism["pengsmasher.gif"] = im(0, 98);ism["hazmatpeng.gif"] = im(0, 98);ism["pengprano.gif"] = im(0, 99);ism["pengphone.gif"] = im(0, 98);ism["warhipar2.gif"] = im(6, 89);ism["modelskeleton.gif"] = im(1, 99);ism["modernzombie.gif"] = im(8, 91);ism["moyster.gif"] = im(7, 93);ism["moneybee.gif"] = im(11, 75);ism["elf_wrench.gif"] = im(17, 87);ism["monsterhearse.gif"] = im(250, 200, 22, 186);ism["boiler.gif"] = im(4, 95);ism["monty.gif"] = im(4, 95);ism["moonshriner.gif"] = im(0, 99);ism["fear1.gif"] = im(0, 99);ism["wraith1.gif"] = im(8, 83);ism["motherseal.gif"] = im(9, 91);ism["otherimages/slimetube/stboss.gif"] = im(30, 30, 29, 30);ism["motorhead.gif"] = im(2, 95);ism["mountainman.gif"] = im(3, 97);ism["lawngnome3.gif"] = im(1, 99);ism["lawngnome2.gif"] = im(26, 98);ism["mrcheeng.gif"] = im(0, 97);ism["mrchoch.gif"] = im(0, 98);ism["adv_strong4.gif"] = im(17, 91);ism["adv_cold4.gif"] = im(0, 99);ism["chemteacher.gif"] = im(0, 98);ism["swampturtle.gif"] = im(0, 99);ism["muff.gif"] = im(10, 78);ism["mumblebee.gif"] = im(27, 74);ism["spelunkmumm.gif"] = im(3, 92);ism["mush_beefy.gif"] = im(6, 89);ism["antlerelf.gif"] = im(12, 97);ism["elfblob.gif"] = im(5, 98);ism["elflimbs.gif"] = im(17, 97);ism["elfclaw.gif"] = im(25, 96);ism["mutantgila.gif"] = im(3, 96);ism["mutantsnake.gif"] = im(19, 95);ism["mutantcactus.gif"] = im(0, 96);ism["elfhulk.gif"] = im(3, 97);ism["alielephant.gif"] = im(10, 97);ism["mutantalielf.gif"] = im(1, 97);ism["bb_vassist.gif"] = im(3, 95);ism["nastybear.gif"] = im(1, 97);ism["fear3.gif"] = im(1, 99);ism["sorcform1.gif"] = im(0, 99);ism["sorcblob.gif"] = im(200, 200, 28, 197);ism["bigsaus.gif"] = im(39, 59);ism["warfratmd2.gif"] = im(2, 96);ism["navyseal.gif"] = im(0, 98);ism["giant_neckbeard.gif"] = im(3, 95);ism["neil.gif"] = im(6, 95);ism["flytrap.gif"] = im(0, 96);ism["mc_respect2.gif"] = im(0, 97);ism["mc_respect1.gif"] = im(0, 97);ism["snakenest.gif"] = im(8, 88);ism["newt.gif"] = im(43, 97);ism["emofrat.gif"] = im(0, 97);ism["ninjawaiter.gif"] = im(5, 95);ism["ninjarice.gif"] = im(7, 95);ism["snowman.gif"] = im(7, 95);ism["ninja_ass.gif"] = im(3, 91);ism["ninjamop.gif"] = im(10, 98);ism["ninjacloud.gif"] = im(3, 97);ism["nhobo1.gif"] = im(7, 94);ism["hunter2.gif"] = im(0, 99);ism["tropicalskel.gif"] = im(0, 98);ism["novia.gif"] = im(5, 99);ism["novio.gif"] = im(11, 97);ism["nurseshark.gif"] = im(15, 71);ism["whirlwind.gif"] = im(8, 91);ism["tourist.gif"] = im(9, 92);ism["octopus.gif"] = im(0, 96);ism["octorok.gif"] = im(10, 93);ism["headghost.gif"] = im(4, 94);ism["adv_stench4.gif"] = im(0, 97);ism["kg_offdutyguard.gif"] = im(13, 95);ism["officialseal.gif"] = im(17, 91);ism["oilbaron.gif"] = im(0, 99);ism["oilcartel2.gif"] = im(200, 100, 5, 97);ism["oilslick.gif"] = im(29, 61);ism["oiltycoon.gif"] = im(1, 99);ism["straw_sleaze.gif"] = im(37, 93);ism["olscratch.gif"] = im(2, 97);ism["noart.gif"] = im(7, 91);ism["dk_oneeye.gif"] = im(2, 95);ism["oneeyed.gif"] = im(4, 91);ism["fratboy.gif"] = im(2, 91);ism["fratskirt.gif"] = im(2, 91);ism["fratbong.gif"] = im(2, 91);ism["lilfratboy.gif"] = im(7, 86);ism["oscus.gif"] = im(5, 97);ism["bandsaw.gif"] = im(11, 87);ism["tableoutlaw.gif"] = im(8, 93);ism["outlawboss.gif"] = im(0, 97);ism["surv_overarmed.gif"] = im(0, 98);ism["pimp.gif"] = im(17, 90);ism["elpriest.gif"] = im(1, 97);ism["stonebros.gif"] = im(2, 96);ism["warfratpr.gif"] = im(19, 85);ism["ptowels.gif"] = im(0, 99);ism["hunter3.gif"] = im(1, 99); +ism["peanut.gif"] = im(0, 98);ism["mh_roommate.gif"] = im(2, 97);ism["pencil.gif"] = im(5, 93);ism["smoochboss3.gif"] = im(100, 200, 17, 191);ism["defense_sphere.gif"] = im(3, 97);ism["pestopuddle.gif"] = im(46, 91);ism["perpbat.gif"] = im(5, 88);ism["bystander.gif"] = im(1, 96);ism["somepig.gif"] = im(3, 88);ism["pinebat.gif"] = im(33, 69);ism["piranhadon.gif"] = im(29, 97);ism["wood_stench.gif"] = im(3, 90);ism["adv_spooky2.gif"] = im(4, 95);ism["plaidghost.gif"] = im(7, 95);ism["plaque.gif"] = im(0, 99);ism["drunkcrancan.gif"] = im(1, 99);ism["drunkfrat.gif"] = im(1, 96);ism["animelf2.gif"] = im(20, 81);ism["poolter.gif"] = im(1, 97);ism["poolter2.gif"] = im(2, 98);ism["popnlocker.gif"] = im(0, 98);ism["porkbutterfly.gif"] = im(9, 88);ism["porksword.gif"] = im(17, 87);ism["adv_sleaze3.gif"] = im(8, 90);ism["abom.gif"] = im(6, 95);ism["crancan.gif"] = im(21, 95);ism["mystwander2.gif"] = im(9, 95);ism["mystwander1.gif"] = im(8, 95);ism["tomatosoup.gif"] = im(6, 89);ism["eyewash.gif"] = im(11, 91);ism["mystwander4.gif"] = im(1, 97);ism["mangler.gif"] = im(5, 95);ism["organ.gif"] = im(1, 99);ism["silverware.gif"] = im(0, 99);ism["toybox.gif"] = im(7, 89);ism["winerack.gif"] = im(4, 98);ism["question.gif"] = im(0, 86);ism["pouooze.gif"] = im(33, 88);ism["primp.gif"] = im(7, 90);ism["fly.gif"] = im(4, 92);ism["surv_primitive.gif"] = im(2, 91);ism["chalmers.gif"] = im(1, 98);ism["bigskeleton.gif"] = im(0, 98);ism["giant_procrast.gif"] = im(5, 98);ism["profjacking.gif"] = im(2, 96);ism["elf_propaganda.gif"] = im(11, 84);ism["protag.gif"] = im(6, 95);ism["protspect.gif"] = im(0, 99);ism["spurt.gif"] = im(0, 99);ism["elf_provocateur.gif"] = im(10, 83);ism["pterodact.gif"] = im(250, 150, 14, 136);ism["pufferfish.gif"] = im(0, 98);ism["pumpedbass.gif"] = im(17, 69);ism["shiv_pumpkin.gif"] = im(6, 97);ism["giant_punk.gif"] = im(0, 98);ism["pyg_squad.gif"] = im(0, 99);ism["pyg_blowgunner.gif"] = im(31, 99);ism["pyg_bowler.gif"] = im(29, 98);ism["pyg_headhunter.gif"] = im(28, 99);ism["pyg_janitor.gif"] = im(41, 99);ism["pyg_orderlies.gif"] = im(18, 98);ism["pyg_shaman.gif"] = im(24, 97);ism["pyg_acct.gif"] = im(33, 99);ism["pyg_lawyer.gif"] = im(27, 98);ism["pyg_nurse.gif"] = im(20, 98);ism["pyg_surgeon.gif"] = im(21, 99);ism["wood_spooky.gif"] = im(28, 90);ism["animelf4.gif"] = im(19, 78);ism["upper_q.gif"] = im(8, 88);ism["beequeen.gif"] = im(13, 87);ism["spelunkbeeq.gif"] = im(200, 150, 5, 149);ism["filthworm4.gif"] = im(0, 97);ism["qbasicele.gif"] = im(0, 97);ism["healer.gif"] = im(9, 93);ism["wanderacc3.gif"] = im(0, 99);ism["mmoaddict.gif"] = im(12, 94);ism["naskar1.gif"] = im(5, 95);ism["weightrack.gif"] = im(27, 95);ism["elf_raconteur.gif"] = im(7, 80);ism["radiator.gif"] = im(0, 99);ism["hunter13.gif"] = im(7, 93);ism["anger1.gif"] = im(0, 99);ism["ragingbull.gif"] = im(2, 94);ism["adding.gif"] = im(2, 89);ism["mh_scenester.gif"] = im(1, 96);ism["ratbat.gif"] = im(19, 67);ism["duckrattle.gif"] = im(2, 96);ism["smoochboss2.gif"] = im(100, 200, 13, 191);ism["raven.gif"] = im(18, 93);ism["giant_raver.gif"] = im(0, 99);ism["wallpaper.gif"] = im(17, 83);ism["foss_baboon.gif"] = im(1, 97);ism["foss_bat.gif"] = im(38, 69);ism["foss_demon.gif"] = im(150, 150, 2, 130);ism["foss_spider.gif"] = im(150, 150, 32, 130);ism["foss_serpent.gif"] = im(1, 96);ism["redbutler.gif"] = im(4, 95);ism["redfox.gif"] = im(5, 94);ism["redherring.gif"] = im(7, 94);ism["redskeleton.gif"] = im(5, 97);ism["redsnapper.gif"] = im(6, 90);ism["regretman.gif"] = im(200, 200, 9, 180);ism["regbat.gif"] = im(35, 66);ism["headlessskel.gif"] = im(15, 89);ism["mistress.gif"] = im(2, 99);ism["giant_renfair.gif"] = im(1, 97);ism["reneccorman.gif"] = im(1, 97);ism["doubt2.gif"] = im(6, 92);ism["kok_waiter.gif"] = im(2, 95);ism["revbugbear.gif"] = im(1, 98);ism["merkinswitcher2.gif"] = im(1, 99);ism["duckgolem.gif"] = im(2, 92);ism["rock_guy.gif"] = im(31, 96);ism["popweasel.gif"] = im(0, 99);ism["scorpion.gif"] = im(8, 91);ism["rock_snake.gif"] = im(1, 97);ism["caveelf1.gif"] = im(21, 78);ism["rock_fish.gif"] = im(24, 77);ism["rollerskate.gif"] = im(2, 92);ism["muse.gif"] = im(2, 96);ism["rollingstone.gif"] = im(4, 90);ism["roncopper.gif"] = im(3, 96);ism["realdolphin.gif"] = im(14, 92);ism["duckfat.gif"] = im(0, 99);ism["rudolfus.gif"] = im(3, 97);ism["rulergolem.gif"] = im(0, 99);ism["runningman.gif"] = im(2, 94);ism["bum.gif"] = im(8, 95);ism["elf_saboteur.gif"] = im(22, 79);ism["ferret.gif"] = im(2, 90);ism["toothgoat.gif"] = im(0, 95);ism["stkiwi.gif"] = im(8, 85);ism["lime.gif"] = im(15, 77);ism["sadiator.gif"] = im(3, 92);ism["safarijack.gif"] = im(1, 97);ism["salamander.gif"] = im(51, 97);ism["salaminder.gif"] = im(26, 88);ism["salaryninja.gif"] = im(4, 96);ism["pirate1.gif"] = im(6, 93);ism["adv_smooth1.gif"] = im(5, 92);ism["zompirate.gif"] = im(7, 93);ism["bb_scav.gif"] = im(7, 93);ism["gummifish.gif"] = im(0, 99);ism["schoolofmany.gif"] = im(3, 94);ism["wizardfish.gif"] = im(1, 99);ism["scimitarfish.gif"] = im(16, 73);ism["duckscorch.gif"] = im(0, 98);ism["spelunkscorp.gif"] = im(3, 89);ism["hunter4.gif"] = im(2, 92);ism["scoutseal.gif"] = im(12, 86);ism["screambat.gif"] = im(24, 79);ism["screwgolem.gif"] = im(3, 98);ism["seacow.gif"] = im(17, 73);ism["seacowboy.gif"] = im(0, 98);ism["adv_smooth4.gif"] = im(2, 95);ism["secrobot.gif"] = im(11, 87);ism["securityslime.gif"] = im(4, 96);ism["crimbominer2.gif"] = im(9, 81);ism["sadpoet.gif"] = im(5, 93);ism["atm.gif"] = im(7, 94);ism["serialbus.gif"] = im(1, 94);ism["grodseal.gif"] = im(3, 93);ism["fireservant1.gif"] = im(0, 99);ism["sewergator.gif"] = im(11, 78);ism["sewersnake.gif"] = im(5, 91);ism["sewertruck.gif"] = im(400, 150, 6, 143);ism["sororghost1.gif"] = im(1, 97);ism["sororeton1.gif"] = im(3, 89);ism["sororpire1.gif"] = im(7, 97);ism["sororwolf1.gif"] = im(6, 97);ism["sororbie1.gif"] = im(5, 95);ism["shadowseal.gif"] = im(8, 91);ism["sheetghost.gif"] = im(5, 95);ism["shopkeep.gif"] = im(7, 91);ism["shub-jigguwatt.gif"] = im(300, 300, 20, 283);ism["tacoelf_sign.gif"] = im(27, 94);ism["caveelf4.gif"] = im(14, 77);ism["sk8gnome.gif"] = im(23, 77);ism["boardskate.gif"] = im(3, 91);ism["animrat.gif"] = im(1, 93);ism["catskel.gif"] = im(20, 84);ism["hamskel.gif"] = im(73, 95);ism["monkeyskel.gif"] = im(17, 77);ism["crimonster6.gif"] = im(3, 95);ism["steward.gif"] = im(3, 97);ism["spelunkskel.gif"] = im(10, 91);ism["mopskeleton.gif"] = im(6, 96);ism["buttleton.gif"] = im(3, 97);ism["sketchyvan.gif"] = im(200, 100, 0, 99);ism["skinflute.gif"] = im(27, 76);ism["skeleton.gif"] = im(6, 93);ism["skullbat.gif"] = im(31, 66);ism["skulldozer.gif"] = im(450, 300, 12, 278);ism["skullery.gif"] = im(0, 97);ism["dvsleazebear1.gif"] = im(5, 89);ism["dvsleazeghost1.gif"] = im(11, 88);ism["slhobo1.gif"] = im(1, 97);ism["dvsleazeskel1.gif"] = im(9, 92);ism["dvsleazevamp1.gif"] = im(3, 96);ism["dvsleazewolf1.gif"] = im(2, 97);ism["dvsleazezom1.gif"] = im(4, 93);ism["kg_sleepingguard.gif"] = im(0, 98);ism["dwarf_sleepy.gif"] = im(37, 95);ism["mar_sleepy.gif"] = im(0, 99);ism["slime1_1.gif"] = im(0, 98);ism["slime2_1.gif"] = im(0, 96);ism["slime3_1.gif"] = im(2, 97);ism["slime4_1.gif"] = im(3, 95);ism["slime5_1.gif"] = im(0, 98);ism["wood_sleaze.gif"] = im(16, 79);ism["holglob.gif"] = im(34, 89);ism["slithering.gif"] = im(15, 81);ism["ssd_burger.gif"] = im(0, 99);ism["ssd_cocktail.gif"] = im(0, 98);ism["ssd_sundae.gif"] = im(1, 98);ism["eliot.gif"] = im(5, 97);ism["mimic2.gif"] = im(23, 87);ism["smartskel.gif"] = im(4, 94);ism["smellothewisp.gif"] = im(4, 98);ism["smokemonster.gif"] = im(5, 96);ism["smoochman3.gif"] = im(100, 150, 16, 127);ism["smoochman1.gif"] = im(7, 93);ism["smoochman2.gif"] = im(1, 97);ism["adv_smooth3.gif"] = im(3, 97);ism["scabie_jazz.gif"] = im(2, 89);ism["smutorc_jacker.gif"] = im(6, 95);ism["smutorc_nailer.gif"] = im(8, 96);ism["smutorc_pervert.gif"] = im(7, 93);ism["smutorc_layer.gif"] = im(5, 97);ism["smutorc_screwer.gif"] = im(9, 97);ism["spelunksnake.gif"] = im(20, 83);ism["firesnake.gif"] = im(0, 99);ism["snakeboss6.gif"] = im(150, 150, 26, 131);ism["snapdragon.gif"] = im(1, 98);ism["snowqueen.gif"] = im(0, 98);ism["adv_cold1.gif"] = im(9, 93);ism["sodium.gif"] = im(3, 92);ism["6_4a.gif"] = im(200, 200, 11, 189);ism["6_1.gif"] = im(10, 91);ism["6_2.gif"] = im(3, 96);ism["6_3.gif"] = im(2, 98);ism["sonofsailor.gif"] = im(1, 99);ism["warfratmd.gif"] = im(4, 96);ism["warfratcm.gif"] = im(1, 96);ism["tree_hickory.gif"] = im(0, 98);ism["drunkstuffing.gif"] = im(0, 99);ism["spacebeast1.gif"] = im(8, 83);ism["spacebeast3.gif"] = im(14, 91);ism["spacemarine.gif"] = im(1, 95);ism["aboo_trek.gif"] = im(1, 97);ism["3_4a.gif"] = im(200, 200, 3, 193);ism["3_1.gif"] = im(2, 95);ism["3_2.gif"] = im(4, 97);ism["3_3.gif"] = im(0, 93);ism["spamwitch.gif"] = im(3, 95);ism["pa_spatula.gif"] = im(7, 98);ism["wretchedseal.gif"] = im(54, 94);ism["hunter11.gif"] = im(3, 95);ism["jellyfish.gif"] = im(6, 96);ism["spelastronaut.gif"] = im(2, 96);ism["spelunkspider.gif"] = im(21, 88);ism["topi1.gif"] = im(3, 93);ism["gourd_spider.gif"] = im(10, 83);ism["gremlinspider.gif"] = im(7, 88);ism["spelunkspiderq.gif"] = im(150, 100, 1, 96);ism["gourd_spidergob.gif"] = im(1, 97);ism["spiderhut.gif"] = im(200, 150, 9, 140);ism["bb_spider.gif"] = im(125, 100, 3, 86);ism["spikeskel.gif"] = im(7, 92);ism["spiritalclock.gif"] = im(0, 99);ism["spiritbug.gif"] = im(10, 92);ism["spiritfaucet.gif"] = im(5, 93);ism["5_1.gif"] = im(3, 99);ism["5_2.gif"] = im(0, 99);ism["5_3.gif"] = im(0, 99);ism["spiritpea.gif"] = im(18, 78);ism["sponge.gif"] = im(0, 98);ism["dvspookybear1.gif"] = im(1, 95);ism["dvspookyghost1.gif"] = im(4, 94);ism["sgguard.gif"] = im(16, 77);ism["sgninja.gif"] = im(22, 80);ism["sgwarlock.gif"] = im(8, 83);ism["spookyhobo1.gif"] = im(3, 89);ism["mummy.gif"] = im(6, 89);ism["musicbox.gif"] = im(2, 90);ism["dvspookyskel1.gif"] = im(13, 97);ism["vampire.gif"] = im(10, 91);ism["dvspookyvamp1.gif"] = im(35, 65);ism["dvspookywolf1.gif"] = im(8, 94);ism["dvspookyzom1.gif"] = im(39, 93);ism["manor.gif"] = im(12, 89);ism["sporto.gif"] = im(1, 99);ism["princess.gif"] = im(8, 95);ism["steamelemental.gif"] = im(3, 94);ism["straw_hot.gif"] = im(5, 91);ism["giant_steampunk.gif"] = im(0, 99);ism["2_4a.gif"] = im(200, 200, 11, 189);ism["2_1.gif"] = im(10, 90);ism["2_2.gif"] = im(12, 96);ism["2_3.gif"] = im(16, 93);ism["dvstenchbear1.gif"] = im(1, 99);ism["dvstenchghost1.gif"] = im(0, 97);ism["stenchhobo1.gif"] = im(12, 97);ism["dvstenchskel1.gif"] = im(2, 99);ism["dvstenchvamp1.gif"] = im(0, 98);ism["dvstenchwolf1.gif"] = im(1, 99);ism["dvstenchzom1.gif"] = im(0, 98);ism["steven.gif"] = im(5, 91); +ism["stickymummy.gif"] = im(3, 94);ism["disco_stiff.gif"] = im(2, 91);ism["crimonster4.gif"] = im(3, 94);ism["stomper.gif"] = im(0, 99);ism["stone_pirate.gif"] = im(3, 93);ism["stormcow.gif"] = im(0, 99);ism["strangler.gif"] = im(1, 98);ism["algae.gif"] = im(1, 97);ism["crimboelf.gif"] = im(27, 96);ism["moosehead.gif"] = im(7, 93);ism["stuffgolem.gif"] = im(3, 91);ism["paulblart.gif"] = im(2, 99);ism["suckubus.gif"] = im(6, 92);ism["tree_juniper.gif"] = im(0, 99);ism["colasoldier.gif"] = im(1, 95);ism["supervirus.gif"] = im(9, 95);ism["witchy1.gif"] = im(0, 99);ism["mar_surprised.gif"] = im(0, 99);ism["mc_soy2.gif"] = im(0, 94);ism["mc_soy1.gif"] = im(0, 98);ism["beav_jack.gif"] = im(9, 92);ism["beav_shaman.gif"] = im(0, 97);ism["beav_warrior.gif"] = im(7, 90);ism["duckstinky.gif"] = im(0, 98);ism["swampentity.gif"] = im(5, 95);ism["swampgator.gif"] = im(19, 81);ism["swamphag.gif"] = im(0, 97);ism["swampowl.gif"] = im(0, 99);ism["swampskunk.gif"] = im(3, 95);ism["swarmers.gif"] = im(1, 95);ism["ralphbat.gif"] = im(2, 84);ism["ants.gif"] = im(1, 97);ism["fudgewasps.gif"] = im(0, 98);ism["whelps1.gif"] = im(10, 85);ism["aswarm.gif"] = im(7, 93);ism["kg_lice.gif"] = im(3, 93);ism["mutantants.gif"] = im(9, 87);ism["beatles.gif"] = im(5, 94);ism["skullswarm.gif"] = im(50, 93);ism["swisshen.gif"] = im(0, 98);ism["t9000.gif"] = im(3, 99);ism["cacotap.gif"] = im(21, 80);ism["tacofish.gif"] = im(17, 82);ism["tacoelf_taco.gif"] = im(12, 86);ism["tacoelf_cart.gif"] = im(9, 82);ism["kasemhead.gif"] = im(2, 96);ism["biggnat.gif"] = im(21, 70);ism["hatskel.gif"] = im(0, 99);ism["adv_fast4.gif"] = im(11, 86);ism["c10spreadsheet.gif"] = im(8, 98);ism["tektite.gif"] = im(21, 77);ism["skel10.gif"] = im(300, 100, 0, 98);ism["terrorbot.gif"] = im(5, 88);ism["tetched.gif"] = im(1, 98);ism["madpirate.gif"] = im(6, 93);ism["fudgeman.gif"] = im(200, 200, 19, 186);ism["theaquaman.gif"] = im(0, 99);ism["boris.gif"] = im(6, 89);ism["aojarls.gif"] = im(6, 93);ism["sneakypete.gif"] = im(13, 90);ism["batinspats.gif"] = im(200, 100, 6, 96);ism["beefhemoth.gif"] = im(200, 100, 0, 98);ism["c10bge.gif"] = im(11, 86);ism["thisdude.gif"] = im(0, 93);ism["c10faces.gif"] = im(0, 99);ism["beelzebozo.gif"] = im(0, 98);ism["colollilossus.gif"] = im(270, 270, 3, 264);ism["bath_craykin.gif"] = im(0, 99);ism["darkness.gif"] = im(0, 98);ism["theemperor.gif"] = im(5, 93);ism["skelmanager.gif"] = im(5, 97);ism["snakeboss2.gif"] = im(5, 94);ism["hunter15.gif"] = im(0, 92);ism["fudgewizard.gif"] = im(0, 99);ism["bunionghost.gif"] = im(4, 92);ism["thegunk.gif"] = im(3, 95);ism["hermit.gif"] = im(30, 30, 29, 30);ism["landscaper.gif"] = im(0, 99);ism["snitch.gif"] = im(150, 300, 13, 275);ism["adv_hot4.gif"] = im(10, 97);ism["theluter.gif"] = im(11, 93);ism["theman.gif"] = im(0, 94);ism["darkmariachi.gif"] = im(2, 97);ism["masterat.gif"] = im(40, 97);ism["adv_smart4.gif"] = im(13, 97);ism["thenuge.gif"] = im(4, 94);ism["rainking.gif"] = im(250, 300, 10, 287);ism["sagittarian.gif"] = im(3, 95);ism["theserver.gif"] = im(0, 97);ism["sierpinski.gif"] = im(0, 89);ism["snakeboss3.gif"] = im(150, 150, 5, 136);ism["timebandit.gif"] = im(9, 88);ism["thepinch.gif"] = im(100, 150, 4, 147);ism["thething.gif"] = im(250, 200, 3, 195);ism["thethorax.gif"] = im(200, 100, 4, 92);ism["c10tropes.gif"] = im(0, 99);ism["ukskeleton.gif"] = im(200, 200, 15, 187);ism["ukskeleton_hm.gif"] = im(200, 200, 2, 195);ism["unknownghost.gif"] = im(0, 99);ism["c10cooler.gif"] = im(0, 98);ism["wholekingdom.gif"] = im(200, 200, 2, 195);ism["they.gif"] = im(0, 99);ism["tnbot1.gif"] = im(1, 95);ism["bigskeleton3.gif"] = im(150, 100, 0, 99);ism["thug1thug2.gif"] = im(200, 100, 1, 93);ism["anger2.gif"] = im(0, 99);ism["tigerlily.gif"] = im(1, 96);ism["spelunktiki.gif"] = im(1, 93);ism["mc_tofu2.gif"] = im(2, 97);ism["mc_tofu1.gif"] = im(2, 95);ism["gourd_can.gif"] = im(14, 90);ism["gourd_canspider.gif"] = im(150, 100, 9, 87);ism["mimic1.gif"] = im(17, 83);ism["animelf1.gif"] = im(19, 79);ism["tipsypirate.gif"] = im(0, 98);ism["tpgeist.gif"] = im(0, 97);ism["shiv_tp.gif"] = im(6, 94);ism["tombasp.gif"] = im(0, 99);ism["mummybat.gif"] = im(34, 60);ism["tombrat.gif"] = im(33, 78);ism["tombratking.gif"] = im(200, 200, 17, 176);ism["tombguy.gif"] = im(0, 98);ism["mastiff.gif"] = im(34, 95);ism["toothpirate.gif"] = im(2, 96);ism["toothskel.gif"] = im(5, 90);ism["topiarychi.gif"] = im(2, 95);ism["topiaryduck.gif"] = im(10, 89);ism["topiary.gif"] = im(0, 98);ism["topiarygopher.gif"] = im(7, 93);ism["topiarykiwi.gif"] = im(17, 92);ism["tree_baobab.gif"] = im(3, 96);ism["c10tmz.gif"] = im(0, 99);ism["orquette3.gif"] = im(6, 92);ism["vib4.gif"] = im(2, 96);ism["toxbeast1.gif"] = im(2, 98);ism["animelf5.gif"] = im(18, 76);ism["crimonster1.gif"] = im(1, 98);ism["travoltron.gif"] = im(200, 200, 4, 197);ism["treadmill.gif"] = im(9, 91);ism["bb_chef.gif"] = im(5, 92);ism["triadwizard.gif"] = im(1, 96);ism["tribalgoblin.gif"] = im(11, 89);ism["trixiepixie.gif"] = im(6, 99);ism["triffid.gif"] = im(2, 96);ism["tarkinhead.gif"] = im(0, 98);ism["monahead.gif"] = im(0, 99);ism["twins_troll.gif"] = im(0, 98);ism["trollipop.gif"] = im(100, 150, 5, 145);ism["trophyfish.gif"] = im(0, 98);ism["tsnake.gif"] = im(5, 94);ism["tumbleweed.gif"] = im(4, 93);ism["turtlemech.gif"] = im(14, 89);ism["turtletrapper.gif"] = im(1, 95);ism["twigberry.gif"] = im(3, 89);ism["bigskeleton2.gif"] = im(0, 99);ism["tex.gif"] = im(0, 98);ism["unclehobo.gif"] = im(10, 92);ism["macaroni.gif"] = im(4, 84);ism["pengundercover.gif"] = im(2, 98);ism["shiv_underworld.gif"] = im(200, 200, 17, 170);ism["ellsburyboss.gif"] = im(150, 150, 15, 124);ism["lensgoblin.gif"] = im(3, 94);ism["surv_unhinged.gif"] = im(6, 95);ism["unholydiver.gif"] = im(0, 99);ism["surv_unlikely.gif"] = im(7, 89);ism["c10database.gif"] = im(2, 95);ism["unstill.gif"] = im(8, 92);ism["ram.gif"] = im(13, 85);ism["urchin.gif"] = im(10, 90);ism["eyesdown.gif"] = im(45, 62);ism["usher.gif"] = im(11, 88);ism["spelunkvampire.gif"] = im(13, 85);ism["vampclam.gif"] = im(11, 91);ism["duckvampire.gif"] = im(3, 95);ism["vandalkid.gif"] = im(9, 91);ism["cvcreature.gif"] = im(100, 200, 4, 196);ism["gremlinveg.gif"] = im(5, 93);ism["velvetug.gif"] = im(19, 91);ism["vendorslime.gif"] = im(0, 95);ism["turtleghost.gif"] = im(23, 84);ism["mantrap.gif"] = im(4, 97);ism["easel.gif"] = im(5, 95);ism["gnauga.gif"] = im(14, 92);ism["victor.gif"] = im(15, 88);ism["qmark.gif"] = im(4, 93);ism["gar.gif"] = im(6, 93);ism["prim_fung.gif"] = im(0, 98);ism["music.gif"] = im(2, 95);ism["iceguy4.gif"] = im(7, 98);ism["smallartist.gif"] = im(40, 97);ism["wimp.gif"] = im(15, 90);ism["wackypirate.gif"] = im(1, 97);ism["iceguy3.gif"] = im(1, 98);ism["mush_shrieking.gif"] = im(1, 93);ism["waiterninja.gif"] = im(5, 95);ism["wallofbones.gif"] = im(250, 150, 3, 138);ism["wallofskin.gif"] = im(250, 125, 1, 115);ism["warfratc.gif"] = im(1, 95);ism["warfrata2.gif"] = im(1, 96);ism["warfratb.gif"] = im(0, 95);ism["warfratc2.gif"] = im(1, 95);ism["warfratb2.gif"] = im(0, 95);ism["warfratsp2.gif"] = im(0, 97);ism["warfratgr.gif"] = im(5, 96);ism["warfratar.gif"] = im(5, 89);ism["warfratmo.gif"] = im(24, 89);ism["warfratgr2.gif"] = im(2, 91);ism["streaker.gif"] = im(3, 95);ism["warfratsp.gif"] = im(3, 98);ism["warhipb.gif"] = im(6, 96);ism["warhipac2.gif"] = im(1, 96);ism["warhipar.gif"] = im(0, 99);ism["warhipds.gif"] = im(8, 93);ism["warhipsh2.gif"] = im(0, 98);ism["warhipfs2.gif"] = im(3, 95);ism["warhipc2.gif"] = im(5, 94);ism["warhipa2.gif"] = im(0, 98);ism["warhipfs.gif"] = im(2, 94);ism["warhipb2.gif"] = im(6, 96);ism["warhipmd.gif"] = im(0, 90);ism["warhipa.gif"] = im(0, 98);ism["warhipmd2.gif"] = im(0, 91);ism["warhipc.gif"] = im(5, 92);ism["warhipsh.gif"] = im(1, 97);ism["warhipac.gif"] = im(5, 96);ism["hippyspy.gif"] = im(8, 89);ism["warhipcm.gif"] = im(2, 94);ism["warbear11.gif"] = im(2, 97);ism["warbear21.gif"] = im(0, 99);ism["nightstand1.gif"] = im(4, 96);ism["warehouseclerk.gif"] = im(2, 95);ism["warehouseguard.gif"] = im(0, 98);ism["warehousejanitor.gif"] = im(3, 92);ism["warehouseguy.gif"] = im(3, 94);ism["wartdinsey.gif"] = im(150, 150, 0, 148);ism["wartpirate.gif"] = im(2, 92);ism["werewolf.gif"] = im(4, 98);ism["wigwasp.gif"] = im(8, 93);ism["wastoid.gif"] = im(8, 93);ism["waterspider.gif"] = im(23, 80);ism["waterseal.gif"] = im(0, 99);ism["richpirate.gif"] = im(3, 93);ism["weatherug.gif"] = im(3, 91);ism["weremoose.gif"] = im(2, 90);ism["weretaco.gif"] = im(29, 82);ism["hunter14.gif"] = im(4, 95);ism["wetseal.gif"] = im(6, 80); +ism["aboo_who.gif"] = im(2, 97);ism["tree_willow.gif"] = im(2, 95);ism["surv_whiny.gif"] = im(3, 91);ism["pa_whisk.gif"] = im(4, 91);ism["whitebonedemon.gif"] = im(200, 100, 12, 98);ism["chocgolem.gif"] = im(9, 92);ism["whiteelephant.gif"] = im(11, 88);ism["lion.gif"] = im(6, 93);ism["zombie2.gif"] = im(5, 94);ism["whitesnake.gif"] = im(10, 87);ism["wildgirl.gif"] = im(0, 97);ism["seahorse.gif"] = im(4, 96);ism["wiresculpture.gif"] = im(0, 97);ism["elf_wires.gif"] = im(12, 89);ism["mush_wizard.gif"] = im(0, 99);ism["tree_magnolia.gif"] = im(1, 99);ism["wraith4.gif"] = im(14, 81);ism["doubt1.gif"] = im(0, 98);ism["ravendesk.gif"] = im(0, 94);ism["susguy.gif"] = im(1, 96);ism["wumpus.gif"] = im(0, 99);ism["beergolem.gif"] = im(4, 97);ism["stonegolem.gif"] = im(3, 97);ism["dimhorror.gif"] = im(2, 96);ism["shopteacher.gif"] = im(1, 98);ism["hydra.gif"] = im(6, 99);ism["polprisoner.gif"] = im(9, 89);ism["pr0n.gif"] = im(11, 87);ism["yakisoba.gif"] = im(0, 97);ism["yakcourier.gif"] = im(3, 96);ism["yakguard.gif"] = im(3, 96);ism["yeastbeast.gif"] = im(4, 93);ism["spelunkyeti.gif"] = im(1, 97);ism["yog-urt.gif"] = im(300, 300, 107, 290);ism["yomama.gif"] = im(300, 300, 3, 289);ism["c10inbox.gif"] = im(9, 94);ism["otherimages/shadows/20.gif"] = im(30, 30, 29, 30);ism["zrex.gif"] = im(150, 100, 0, 99);ism["zimmerman.gif"] = im(4, 98);ism["zombie.gif"] = im(3, 84);ism["zol.gif"] = im(11, 90);ism["zomlizard.gif"] = im(4, 94);ism["zmobaby.gif"] = im(2, 86);ism["zombiechef.gif"] = im(1, 97);ism["zomclown.gif"] = im(3, 97);ism["duckzombie.gif"] = im(1, 96);ism["zomsnow.gif"] = im(7, 91);ism["zomfrat.gif"] = im(12, 84);ism["zomknoll.gif"] = im(10, 87);ism["zomgoth.gif"] = im(0, 94);ism["zomhippy.gif"] = im(4, 92);ism["zombiehoa.gif"] = im(150, 150, 1, 148);ism["zombiehoa_hm.gif"] = im(200, 200, 0, 199);ism["zomchef.gif"] = im(1, 92);ism["zomnoob.gif"] = im(4, 93);ism["zomhealer.gif"] = im(1, 93);ism["zomwaltz.gif"] = im(0, 97);ism["zomyeast.gif"] = im(9, 98);ism["hunter1.gif"] = im(3, 96);ism["zombo.gif"] = im(0, 98); + + + + foreach s, v in ysm + { + __minimum_y_of_image_url["images/adventureimages/" + s] = v; + } + foreach s, v in ism + { + __server_image_stats["images/adventureimages/" + s] = v; + } + } + initialiseMinimumBoundingBoxOfImageURL(); +} + +ServerImageStats ServerImageStatsOfImageURL(string url) +{ + if (__server_image_stats contains url) + { + return __server_image_stats[url]; + } + return ServerImageStatsMake(); +} + +int KOLImageMinimumYOfImageURL(string url) +{ + if (__server_image_stats contains url) + { + return __server_image_stats[url].minimum_y_coordinate; + } + return 0; +} + + + +record ChecklistSubentry +{ + string header; + string [int] modifiers; + string [int] entries; +}; + + +ChecklistSubentry ChecklistSubentryMake(string header, string [int] modifiers, string [int] entries) +{ + boolean all_subentries_are_empty = true; + foreach key in entries + { + if (entries[key] != "") + all_subentries_are_empty = false; + } + ChecklistSubentry result; + result.header = header; + result.modifiers = modifiers; + if (!all_subentries_are_empty) + result.entries = entries; + return result; +} + +ChecklistSubentry ChecklistSubentryMake(string header, string modifiers, string [int] entries) +{ + if (modifiers == "") + return ChecklistSubentryMake(header, listMakeBlankString(), entries); + else + return ChecklistSubentryMake(header, listMake(modifiers), entries); +} + + +ChecklistSubentry ChecklistSubentryMake(string header, string [int] entries) +{ + return ChecklistSubentryMake(header, listMakeBlankString(), entries); +} + +ChecklistSubentry ChecklistSubentryMake(string header, string [int] modifiers, string e1) +{ + return ChecklistSubentryMake(header, modifiers, listMake(e1)); +} + +ChecklistSubentry ChecklistSubentryMake(string header, string [int] modifiers, string e1, string e2) +{ + return ChecklistSubentryMake(header, modifiers, listMake(e1, e2)); +} + + +ChecklistSubentry ChecklistSubentryMake(string header, string modifiers, string e1) +{ + if (modifiers == "") + return ChecklistSubentryMake(header, listMakeBlankString(), listMake(e1)); + else + return ChecklistSubentryMake(header, listMake(modifiers), listMake(e1)); +} + +ChecklistSubentry ChecklistSubentryMake(string header) +{ + return ChecklistSubentryMake(header, "", ""); +} + +void listAppend(ChecklistSubentry [int] list, ChecklistSubentry entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listPrepend(ChecklistSubentry [int] list, ChecklistSubentry entry) +{ + int position = 0; + while (list contains position) + position -= 1; + list[position] = entry; +} + +ChecklistSubentry [int] listMake(ChecklistSubentry e1) +{ + ChecklistSubentry [int] result; + result.listAppend(e1); + return result; +} + + +record TagGroup +{ + string id; //For the "minimize" feature to keep track of the entries. Uses 'combination' instead if present. Uses the first entry's header if empty. + string combination; //Entries with identical combination tags will be combined into one, with the "first" taking precedence. +}; + +int CHECKLIST_DEFAULT_IMPORTANCE = 0; +record ChecklistEntry +{ + string image_lookup_name; + string url; + string [string] container_div_attributes; + ChecklistSubentry [int] subentries; + TagGroup tags; //meta-informations about the entry + boolean should_indent_after_first_subentry; + + boolean should_highlight; + + int importance_level; //Entries will be resorted by importance level before output, ascending order. Default importance is 0. Convention is to vary it from [-11, 11] for reasons that are clear and well supported in the narrative. + boolean only_show_as_extra_important_pop_up; //only valid if -11 importance or lower - only shows up as a pop-up, meant to inform the user they can scroll up to see something else (semi-rares) + ChecklistSubentry [int] subentries_on_mouse_over; //replaces subentries +}; + + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string url, ChecklistSubentry [int] subentries, TagGroup tags, int importance, boolean should_highlight) +{ + ChecklistEntry result; + result.image_lookup_name = image_lookup_name; + result.url = url; + result.subentries = subentries; + result.tags = tags; + result.importance_level = importance; + result.should_highlight = should_highlight; + return result; +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, TagGroup tags, int importance) +{ + return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, importance, false); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, TagGroup tags, int importance, boolean [location] highlight_if_last_adventured) +{ + boolean should_highlight = false; + + if (highlight_if_last_adventured contains __last_adventure_location) + should_highlight = true; + return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, importance, should_highlight); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, TagGroup tags) +{ + return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, CHECKLIST_DEFAULT_IMPORTANCE); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, TagGroup tags, boolean [location] highlight_if_last_adventured) +{ + return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, CHECKLIST_DEFAULT_IMPORTANCE, highlight_if_last_adventured); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, TagGroup tags, int importance) +{ + ChecklistSubentry [int] subentries; + subentries[subentries.count()] = subentry; + return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, importance); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, TagGroup tags, int importance, boolean [location] highlight_if_last_adventured) +{ + ChecklistSubentry [int] subentries; + subentries[subentries.count()] = subentry; + return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, importance, highlight_if_last_adventured); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, TagGroup tags) +{ + return ChecklistEntryMake(image_lookup_name, target_location, subentry, tags, CHECKLIST_DEFAULT_IMPORTANCE); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, TagGroup tags, boolean [location] highlight_if_last_adventured) +{ + ChecklistSubentry [int] subentries; + subentries[subentries.count()] = subentry; + return ChecklistEntryMake(image_lookup_name, target_location, subentries, tags, CHECKLIST_DEFAULT_IMPORTANCE, highlight_if_last_adventured); +} + + +//should we remove these? Players may have build their own ChecklistEntries, so if we do, we'd put a warning here during a release, and officially remove them on the next. +// Considering YOUR speed (yes, you, you know who you are), they'll have, what... a year..? <_< +// ... to change their custom ChecklistEntry / make the right edit(s) +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string url, ChecklistSubentry [int] subentries, int importance, boolean should_highlight) +{ + TagGroup tags; + return ChecklistEntryMake(image_lookup_name, url, subentries, tags, importance, should_highlight); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, int importance) +{ + return ChecklistEntryMake(image_lookup_name, target_location, subentries, importance, false); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, int importance, boolean [location] highlight_if_last_adventured) +{ + boolean should_highlight = false; + + if (highlight_if_last_adventured contains __last_adventure_location) + should_highlight = true; + return ChecklistEntryMake(image_lookup_name, target_location, subentries, importance, should_highlight); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries) +{ + return ChecklistEntryMake(image_lookup_name, target_location, subentries, CHECKLIST_DEFAULT_IMPORTANCE); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry [int] subentries, boolean [location] highlight_if_last_adventured) +{ + return ChecklistEntryMake(image_lookup_name, target_location, subentries, CHECKLIST_DEFAULT_IMPORTANCE, highlight_if_last_adventured); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, int importance) +{ + ChecklistSubentry [int] subentries; + subentries[subentries.count()] = subentry; + return ChecklistEntryMake(image_lookup_name, target_location, subentries, importance); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, int importance, boolean [location] highlight_if_last_adventured) +{ + ChecklistSubentry [int] subentries; + subentries[subentries.count()] = subentry; + return ChecklistEntryMake(image_lookup_name, target_location, subentries, importance, highlight_if_last_adventured); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry) +{ + return ChecklistEntryMake(image_lookup_name, target_location, subentry, CHECKLIST_DEFAULT_IMPORTANCE); +} + +ChecklistEntry ChecklistEntryMake(string image_lookup_name, string target_location, ChecklistSubentry subentry, boolean [location] highlight_if_last_adventured) +{ + ChecklistSubentry [int] subentries; + subentries[subentries.count()] = subentry; + return ChecklistEntryMake(image_lookup_name, target_location, subentries, CHECKLIST_DEFAULT_IMPORTANCE, highlight_if_last_adventured); +} + +//Secondary level of making checklist entries; setting properties and returning them. +ChecklistEntry ChecklistEntrySetIDTag(ChecklistEntry e, string id) +{ + e.tags.id = id; + return e; +} + +ChecklistEntry ChecklistEntrySetCombinationTag(ChecklistEntry e, string tag) +{ + e.tags.combination = tag; + return e; +} + + +void listAppend(ChecklistEntry [int] list, ChecklistEntry entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppendList(ChecklistEntry [int] list, ChecklistEntry [int] entries) +{ + foreach key in entries + list.listAppend(entries[key]); +} + +void listClear(ChecklistEntry [int] list) +{ + foreach i in list + { + remove list[i]; + } +} + + +record Checklist +{ + string title; + ChecklistEntry [int] entries; + + boolean disable_generating_id; //disable generating checklist anchor and title-based div identifier +}; + + +Checklist ChecklistMake(string title, ChecklistEntry [int] entries) +{ + Checklist cl; + cl.title = title; + cl.entries = entries; + return cl; +} + +Checklist ChecklistMake() +{ + Checklist cl; + return cl; +} + +void listAppend(Checklist [int] list, Checklist entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listRemoveKeys(Checklist [int] list, int [int] keys_to_remove) +{ + foreach i in keys_to_remove + { + int key = keys_to_remove[i]; + if (!(list contains key)) + continue; + remove list[key]; + } +} + + +string ChecklistGenerateModifierSpan(string [int] modifiers) +{ + if (modifiers.count() == 0) + return ""; + return HTMLGenerateSpanOfClass(modifiers.listJoinComponents(", "), "r_cl_modifier"); +} + +string ChecklistGenerateModifierSpan(string checklist_modifier) //no longer span, but I'm sure as hell not gonna change every instance of it :V +{ + return HTMLGenerateDivOfClass(checklist_modifier, "r_cl_modifier"); +} + + +void ChecklistInit() +{ + PageAddCSSClass("a", "r_cl_internal_anchor", ""); + PageAddCSSClass("", "r_cl_modifier_inline", "font-size:0.85em; color:" + __setting_modifier_colour + ";"); + PageAddCSSClass("", "r_cl_modifier", "font-size:0.85em; color:" + __setting_modifier_colour + "; display:block;"); + + PageAddCSSClass("", "r_cl_header", "text-align:center; font-size:1.15em; font-weight:bold;"); + PageAddCSSClass("", "r_cl_subheader", "font-size:1.07em; font-weight:bold;"); + PageAddCSSClass("", "r_cl_entry_id", "font-size:1.07em; font-weight:bold; display:none;"); + PageAddCSSClass("div", "r_cl_entry_first_subheader", "display:flex;flex-direction:row;align-items:flex-start;width:100%;"); + PageAddCSSClass("div", "r_cl_entry_container", "display:flex; flex-direction:row; align-items:flex-start; padding-top: var(--cl_entry_container_padding); padding-bottom: var(--cl_entry_container_padding);"); + + string gradient = "background: #ffffff;background: -moz-linear-gradient(left, #ffffff 50%, #F0F0F0 75%, #F0F0F0 100%);background: -webkit-gradient(linear, left top, right top, color-stop(50%,#ffffff), color-stop(75%,#F0F0F0), color-stop(100%,#F0F0F0));background: -webkit-linear-gradient(left, #ffffff 50%,#F0F0F0 75%,#F0F0F0 100%);background: -o-linear-gradient(left, #ffffff 50%,#F0F0F0 75%,#F0F0F0 100%);background: -ms-linear-gradient(left, #ffffff 50%,#F0F0F0 75%,#F0F0F0 100%);background: linear-gradient(to right, #ffffff 50%,#F0F0F0 75%,#F0F0F0 100%);filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#F0F0F0',GradientType=1 );"; //help + PageAddCSSClass("", "container_highlighted", gradient + "margin-right: calc(0px - var(--cl_container_padding)); padding-right: var(--cl_container_padding);"); //counter the checklist_container's padding, so that the gradient won't stop mid-way + PageAddCSSClass("", "close_highlight", "margin-right: calc(0px - var(--cl_container_padding)); padding-right: var(--cl_container_padding);"); + + PageAddCSSClass("div", "r_cl_entry_image", "width: var(--image-width); flex:none;"); + PageAddCSSClass("div", "r_cl_entry_content_container", "flex-grow:1;display:flex;flex-direction:column;text-align:left;align-items:flex-start;"); + PageAddCSSClass("", "hr_like", "border: 0px; border-top: 1px; border-style:solid; border-color: " + __setting_line_colour + ";"); + + //subentries-on-mouseover + PageAddCSSClass("", "r_cl_entry_content_container.entry_hoverable", ""); + PageAddCSSClass("", "r_cl_entry_content_container.entry_hovered", "display:none;"); + PageAddCSSClass("", "r_cl_entry_container:hover .r_cl_entry_content_container.entry_hoverable", "display:none;"); + PageAddCSSClass("", "r_cl_entry_container:hover .r_cl_entry_content_container.entry_hovered", "display:flex;"); + + //collapsing feature + PageAddCSSClass("button", "r_cl_minimize_button", "background-color:antiquewhite;padding:0px;font-size:11px;height:18px;width:18px;flex-shrink:0;position:relative;z-index:2;color:#7F7F7F;cursor:pointer;"); + PageAddCSSClass("button", "r_cl_minimize_button:hover", "background-color:black;"); + + if (true) + { + PageAddCSSClass("", "#Guide_body.opacity_full .r_cl_entry_container.r_cl_collapsed .r_cl_entry_image" + + ", #Guide_body.opacity_full .r_cl_entry_container.r_cl_collapsed .r_cl_subheader" + + ", #Guide_body.opacity_full .r_cl_entry_container.r_cl_collapsed .r_cl_modifier", "opacity:1;"); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_full .r_cl_entry_image" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_full .r_cl_subheader" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_full .r_cl_modifier", "opacity:1;", 1); + + PageAddCSSClass("", "#Guide_body.opacity_half .r_cl_entry_container.r_cl_collapsed .r_cl_entry_image" + + ", #Guide_body.opacity_half .r_cl_entry_container.r_cl_collapsed .r_cl_subheader" + + ", #Guide_body.opacity_half .r_cl_entry_container.r_cl_collapsed .r_cl_modifier", "opacity:0.5;"); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_half .r_cl_entry_image" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_half .r_cl_subheader" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.opacity_half .r_cl_modifier", "opacity:0.5;", 1); + + + //.image_auto on #Guide_body is already the normal behaviour, so don't do anything here (THANKFULLY). + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_large", "display:block;", 1, __setting_media_query_large_size); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_medium" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_small", "display:none;", 1, __setting_media_query_large_size); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_medium", "display:block;", 1, __setting_media_query_medium_size); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_large" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_small", "display:none;", 1, __setting_media_query_medium_size); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_small", "display:block;", 1, __setting_media_query_small_size); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_large" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_auto .r_cl_image_container_medium", "display:none;" , 1, __setting_media_query_small_size); + + PageAddCSSClass("", "#Guide_body.image_none .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_large" + + ", #Guide_body.image_none .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_medium" + + ", #Guide_body.image_none .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_small", "display:none;"); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_none .r_cl_image_container_large" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_none .r_cl_image_container_medium" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_none .r_cl_image_container_small", "display:none;", 1); + + PageAddCSSClass("", "#Guide_body.image_small .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_large" + + ", #Guide_body.image_small .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_medium", "display:none;"); + PageAddCSSClass("", "#Guide_body.image_small .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_small", "display:block;"); + PageAddCSSClass("", "#Guide_body.image_small .r_cl_entry_container.r_cl_collapsed .r_cl_image_container_small", "display:none;", 0, __setting_media_query_tiny_size); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_small .r_cl_image_container_large" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.image_small .r_cl_image_container_medium", "display:none;", 1); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_small .r_cl_image_container_small", "display:block;", 1); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.image_small .r_cl_image_container_small", "display:none;", 1, __setting_media_query_tiny_size); + + + PageAddCSSClass("", "#Guide_body.collapsing_entries .r_cl_entry_container.r_cl_collapsed .r_cl_subheader" + + ", #Guide_body.collapsing_entries .r_cl_entry_container.r_cl_collapsed .r_cl_modifier", "display:block;"); + PageAddCSSClass("", "#Guide_body.collapsing_entries .r_cl_entry_container.r_cl_collapsed .r_cl_entry_id", "display:none;"); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_entries .r_cl_subheader" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_entries .r_cl_modifier", "display:block;", 1); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_entries .r_cl_entry_id", "display:none;", 1); + + PageAddCSSClass("", "#Guide_body.collapsing_modifiers .r_cl_entry_container.r_cl_collapsed .r_cl_subheader", "display:block;"); + PageAddCSSClass("", "#Guide_body.collapsing_modifiers .r_cl_entry_container.r_cl_collapsed .r_cl_modifier" + + ", #Guide_body.collapsing_modifiers .r_cl_entry_container.r_cl_collapsed .r_cl_entry_id", "display:none;"); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_modifiers .r_cl_subheader", "display:block;", 1); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_modifiers .r_cl_modifier" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_modifiers .r_cl_entry_id", "display:none;", 1); + + PageAddCSSClass("", "#Guide_body.collapsing_replace .r_cl_entry_container.r_cl_collapsed .r_cl_subheader" + + ", #Guide_body.collapsing_replace .r_cl_entry_container.r_cl_collapsed .r_cl_modifier", "display:none;"); + PageAddCSSClass("", "#Guide_body.collapsing_replace .r_cl_entry_container.r_cl_collapsed .r_cl_entry_id", "display:block;"); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_replace .r_cl_subheader" + + ", #Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_replace .r_cl_modifier", "display:none;", 1); + PageAddCSSClass("", "#Guide_body .r_cl_entry_container.r_cl_collapsed.collapsing_replace .r_cl_entry_id", "display:block;", 1); + + PageAddCSSClass("", "r_cl_entry_container.r_cl_collapsed .r_cl_collapsable", "display:none;"); + } + + + PageAddCSSClass("", "r_cl_image_container_large", "display:block;"); + PageAddCSSClass("", "r_cl_image_container_medium", "display:none;"); + PageAddCSSClass("", "r_cl_image_container_small", "display:none;"); + + PageAddCSSClass("div", "r_cl_checklist_container", "margin:0px; padding-left: var(--cl_container_padding); padding-right: var(--cl_container_padding); border:1px; border-style: solid; border-color:" + __setting_line_colour + ";border-left:0px; border-right:0px;background-color:#FFFFFF; padding-top:5px;"); + + //media queries: + if (true) + { + PageAddCSSClass("", "r_cl_image_container_large", "display:none", 0, __setting_media_query_medium_size); + PageAddCSSClass("", "r_cl_image_container_medium", "display:block;", 0, __setting_media_query_medium_size); + PageAddCSSClass("", "r_cl_image_container_small", "display:none;", 0, __setting_media_query_medium_size); + + PageAddCSSClass("", "r_cl_image_container_large", "display:none", 0, __setting_media_query_small_size); + PageAddCSSClass("", "r_cl_image_container_medium", "display:none;", 0, __setting_media_query_small_size); + PageAddCSSClass("", "r_cl_image_container_small", "display:block;", 0, __setting_media_query_small_size); + + PageAddCSSClass("", "r_cl_image_container_large", "display:none", 0, __setting_media_query_tiny_size); + PageAddCSSClass("", "r_cl_image_container_medium", "display:none;", 0, __setting_media_query_tiny_size); + PageAddCSSClass("", "r_cl_image_container_small", "display:none;", 0, __setting_media_query_tiny_size); + + + PageAddCSSClass("", "r_indention", "margin-left:" + (__setting_indention_width_in_em / 2.0) + "em;", 0, __setting_media_query_small_size); + PageAddCSSClass("", "r_indention", "margin-left:" + (__setting_indention_width_in_em / 2.0) + "em;", 0, __setting_media_query_tiny_size); + } +} + +//Creates if not found: +Checklist lookupChecklist(Checklist [int] checklists, string title) +{ + foreach key in checklists + { + Checklist cl = checklists[key]; + if (cl.title == title) + return cl; + } + //Not found, create one. + Checklist cl = ChecklistMake(); + cl.title = title; + checklists.listAppend(cl); + return cl; +} + +void ChecklistFormatSubentry(ChecklistSubentry subentry) { + foreach i in subentry.entries { + string [int] line_split = split_string_alternate(subentry.entries[i], "\\|"); + foreach l in line_split { + if (stringHasPrefix(line_split[l], "*")) { + // Indent + line_split[l] = HTMLGenerateIndentedText(substring(line_split[l], 1)); + } + } + + // Recombine + buffer building_line; + boolean first = true; + boolean last_was_indention = false; + foreach key in line_split { + string line = line_split[key]; + if (!contains_text(line, "class=\"r_indention\"") && !first && !last_was_indention) { + building_line.append("
"); + } + last_was_indention = contains_text(line, "class=\"r_indention\""); + building_line.append(line); + first = false; + } + subentry.entries[i] = to_string(building_line); + } +} + +buffer ChecklistEntryGenerateContentHTML(ChecklistEntry entry, ChecklistSubentry [int] subentries, string [string] anchor_attributes) { + buffer entry_content; + + string entry_id = entry.tags.id; + + boolean first = true; + boolean indented_after_first_subentry = false; + boolean entry_is_just_a_title = true; + foreach j, subentry in subentries { + if (subentry.header == "") + continue; + + if (first) + { + string subheader = HTMLGenerateSpanOfClass(subentry.header, "r_cl_subheader"); + subheader += HTMLGenerateSpanOfClass(entry_id, "r_cl_entry_id"); + + buffer first_subheader; + if (anchor_attributes.count() > 0 && !__setting_entire_area_clickable) + subheader = HTMLGenerateTagWrap("a", subheader, anchor_attributes); + first_subheader.append(subheader); + + //minimize button + boolean entry_has_content_to_minimize = false; + int indented_entries; + foreach j, subentry in subentries { + if (subentry.header == "") + continue; + + if (entry.should_indent_after_first_subentry) + indented_entries++; + if (subentry.entries.count() > 0 || indented_entries >= 2) { + entry_has_content_to_minimize = true; + break; + } + } + + first_subheader.append(HTMLGenerateTagWrap("div", "", string [string] {"style":"flex-grow:1;"})); //fill empty space to ensure the button(s) are on the right end + + if (entry_has_content_to_minimize) { + first_subheader.append(HTMLGenerateTagWrap("button", "▼", string [string] {"class":"r_cl_minimize_button toggle_" + entry_id,"alt":"Minimize","title":"Minimize","id":"toggle_" + entry_id,"onclick":"alterSubentryMinimization(event)", "oncontextmenu":"callSettingsContextualMenu(event)"})); + } + + entry_content.append(HTMLGenerateTagWrap("div", first_subheader, string [string] {"class":"r_cl_entry_first_subheader"})); + } + else if (entry.should_indent_after_first_subentry && !indented_after_first_subentry) + { + entry_content.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_indention r_cl_collapsable"))); // + entry_id + indented_after_first_subentry = true; + } + + if (anchor_attributes.count() > 0 && !__setting_entire_area_clickable) { + if (subentry.modifiers.count() + subentry.entries.count() > 0 && entry_is_just_a_title) { + entry_is_just_a_title = false; + entry_content.append(HTMLGenerateTagPrefix("a", anchor_attributes)); + } + } + + if (!first) + entry_content.append(HTMLGenerateDivOfClass(subentry.header, "r_cl_subheader")); + + if (subentry.modifiers.count() > 0) + entry_content.append(subentry.modifiers.listJoinComponents(", ").HTMLGenerateDivOfClass("r_indention r_cl_modifier")); + + if (subentry.entries.count() > 0) + { + buffer subentry_text; + for intra_k from 0 to subentry.entries.count() - 1 + { + if (intra_k > 0) + subentry_text.append("
"); + string line = subentry.entries[listKeyForIndex(subentry.entries, intra_k)]; + + subentry_text.append(line); + } + entry_content.append(HTMLGenerateTagWrap("div", subentry_text, mapMake("class", "r_indention" + (indented_after_first_subentry ? "" : " r_cl_collapsable") ))); // + entry_id + } + + first = false; + } + if (indented_after_first_subentry) + entry_content.append(""); + if (anchor_attributes.count() > 0 && !__setting_entire_area_clickable && !entry_is_just_a_title) + entry_content.append(""); + return entry_content; +} + +/** +Generates HTML for a checklist and appends it to the DOM +@param cl The checklist being appended to the DOM +@param output_borders Whether or not to add borders +*/ +buffer ChecklistGenerate(Checklist cl, boolean output_borders) { + ChecklistEntry [int] entries = cl.entries; + + //Combine entries with identical combination tags: + ChecklistEntry [string] combination_tag_entries; + foreach key, entry in entries { + if (entry.tags.combination == "") continue; + if (entry.only_show_as_extra_important_pop_up) continue; //do not support this feature with this + if (entry.should_indent_after_first_subentry) continue; + if (entry.subentries_on_mouse_over.count() > 0) continue; + if (entry.container_div_attributes.count() > 0) continue; + + entry.importance_level -= 1; //combined entries gain a hack; a level above everything else + + if (!(combination_tag_entries contains entry.tags.combination)) { + entry.tags.id = cl.title + "_" + entry.tags.combination; + combination_tag_entries[entry.tags.combination] = entry; + continue; + } + + ChecklistEntry master_entry = combination_tag_entries[entry.tags.combination]; + + if (entry.should_highlight) { + master_entry.should_highlight = true; + } + + if (master_entry.url == "" && entry.url != "") { + master_entry.url = entry.url; + } + + if (entry.importance_level < master_entry.importance_level) + { + master_entry.importance_level = entry.importance_level; + master_entry.image_lookup_name = entry.image_lookup_name; + if (entry.url != "") + master_entry.url = entry.url; + + //Put that entry's subentries at the start + ChecklistSubentry [int] new_master_subentries = entry.subentries; + foreach key, subentry in master_entry.subentries { + new_master_subentries.listAppend(subentry); + } + master_entry.subentries = new_master_subentries; + } + else + { + foreach key, subentry in entry.subentries { + master_entry.subentries.listAppend(subentry); + } + } + + remove entries[key]; + } + + //Sort by importance: + sort entries by value.importance_level; + + //Format subentries: + foreach index in entries { + ChecklistEntry entry = entries[index]; + foreach subentryIndex in entry.subentries { + ChecklistFormatSubentry(entry.subentries[subentryIndex]); + } + foreach subentryIndex in entry.subentries_on_mouse_over { + ChecklistFormatSubentry(entry.subentries_on_mouse_over[subentryIndex]); + } + } + + boolean skip_first_entry = false; + string special_subheader = ""; + if (entries.count() > 0) { + if (entries[0].image_lookup_name == "special subheader") { + if (entries[0].subentries.count() > 0) { + special_subheader = entries[0].subentries[0].header; + skip_first_entry = true; + } + } + } + + buffer result; + string [string] main_container_map; + main_container_map["class"] = "r_cl_checklist_container"; + if (!cl.disable_generating_id) + main_container_map["id"] = HTMLConvertStringToAnchorID(cl.title + " checklist container"); + if (output_borders) + main_container_map["style"] = "margin-top:12px;margin-bottom:24px;"; //spacing + else + main_container_map["style"] = "border:0px;"; + result.append(HTMLGenerateTagPrefix("div", main_container_map)); + + + string anchor = cl.title; + if (!cl.disable_generating_id) + anchor = HTMLGenerateTagWrap("a", "", mapMake("id", HTMLConvertStringToAnchorID(cl.title), "class", "r_cl_internal_anchor")) + cl.title; + + result.append(HTMLGenerateDivOfClass(anchor, "r_cl_header")); + + if (special_subheader != "") + result.append(ChecklistGenerateModifierSpan(special_subheader)); + + int starting_intra_i = 1; + if (skip_first_entry) + starting_intra_i++; + int intra_i = 0; + int entries_output = 0; + boolean last_was_highlighted = false; + foreach i, entry in entries + { + if (++intra_i < starting_intra_i) + continue; + entries_output++; + string [string] anchor_attributes; + if (entry.url != "") + anchor_attributes = {"target":"mainpane", "href":entry.url, "class":"r_a_undecorated"}; + + buffer entry_content; + string container_class = "r_cl_entry_container"; + if (entry.should_highlight) + container_class += " container_highlighted"; + if (intra_i > starting_intra_i) + { + container_class += " hr_like"; + if (last_was_highlighted && !entry.should_highlight) + container_class += " close_highlight"; + } + last_was_highlighted = entry.should_highlight; + + if (true) //"Correct" the entry ID + { + string entry_id; + if (entry.tags.combination != "") //not supposed to happen, but still can + entry_id = entry.tags.combination; + else if (entry.tags.id != "") + entry_id = entry.tags.id; + else + entry_id = "unIDed_" + entry.subentries[0].header; + entry_id = create_matcher("[ \\-.,#]", entry_id).replace_all("_"); + entry.tags.id = entity_encode(entry_id); + } + + buffer image_container; + + if (true) //image + { + image_container.append(KOLImageGenerateImageHTML(entry.image_lookup_name, true, Vec2iMake(__setting_image_width_large, 75), "r_cl_image_container_large")); + image_container.append(KOLImageGenerateImageHTML(entry.image_lookup_name, true, Vec2iMake(__setting_image_width_medium, 50), "r_cl_image_container_medium")); + image_container.append(KOLImageGenerateImageHTML(entry.image_lookup_name, true, Vec2iMake(__setting_image_width_small, 50), "r_cl_image_container_small")); + if (anchor_attributes.count() > 0 && !__setting_entire_area_clickable) + image_container = HTMLGenerateTagWrap("a", image_container, anchor_attributes); + image_container = HTMLGenerateTagWrap("div", image_container, mapMake("class", "r_cl_entry_image")); + } + + buffer content; + + if (true) //content (text) + { + string base_content = entry.ChecklistEntryGenerateContentHTML(entry.subentries, anchor_attributes); + if (entry.subentries_on_mouse_over.count() == 0) + base_content = HTMLGenerateTagWrap("div", base_content, mapMake("class", "r_cl_entry_content_container")); + else + { + base_content = HTMLGenerateTagWrap("div", base_content, mapMake("class", "r_cl_entry_content_container entry_hoverable")); + + string hover_content = entry.ChecklistEntryGenerateContentHTML(entry.subentries_on_mouse_over, anchor_attributes); + hover_content = HTMLGenerateTagWrap("div", hover_content, mapMake("class", "r_cl_entry_content_container entry_hovered")); + content.append(hover_content); + } + content.append(base_content); + } + + buffer generated_subentry_html; + generated_subentry_html.append(image_container); + generated_subentry_html.append(content); + + if (entry.container_div_attributes contains "class") + { + if (!entry.container_div_attributes["class"].contains_text(container_class)) //can happen with entries being pinned in the importance bar, passing here twice + entry.container_div_attributes["class"] += " " + container_class; + } + else + entry.container_div_attributes["class"] = container_class; + entry.container_div_attributes["class"] += " " + entry.tags.id; + entry_content.append(HTMLGenerateTagWrap("div", generated_subentry_html, entry.container_div_attributes)); + + + if (anchor_attributes.count() > 0 && __setting_entire_area_clickable) + entry_content = HTMLGenerateTagWrap("a", entry_content, anchor_attributes); + + result.append(entry_content); + } + result.append(""); + + return result; +} + +/** +Attaches checklist to DOM. +@param checklist The checklist being appended. +*/ +buffer ChecklistGenerate(Checklist checklist) { + return ChecklistGenerate(checklist, true); +} + + +Record ChecklistCollection +{ + Checklist [string] checklists; +}; + +//NOTE: WILL DESTRUCTIVELY EDIT CHECKLISTS GIVEN TO IT +//mostly because there's no easy way to copy an object in ASH +//without manually writing a copy function and insuring it is synched +Checklist [int] ChecklistCollectionMergeWithLinearList(ChecklistCollection collection, Checklist [int] other_checklists) +{ + Checklist [int] result; + + boolean [string] seen_titles; + foreach key, checklist in other_checklists + { + seen_titles[checklist.title] = true; + result.listAppend(checklist); + } + foreach key, checklist in collection.checklists + { + if (seen_titles contains checklist.title) + { + foreach key, checklist2 in result + { + if (checklist2.title == checklist.title) + { + checklist2.entries.listAppendList(checklist.entries); + break; + } + } + } + else + { + result.listAppend(checklist); + } + } + + return result; +} + +Checklist lookup(ChecklistCollection collection, string name) +{ + if (collection.checklists contains name) + return collection.checklists[name]; + + Checklist c = ChecklistMake(); + c.title = name; + collection.checklists[c.title] = c; + return c; +} + + +void QLevel2Init() +{ + //questL02Larva + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questL02Larva"); + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + // Finish this quest if you are in 11,037 Leagues Under the Sea, so the tiles never generate. + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Spooky Forest Quest"; + state.image_name = "Spooky Forest"; + state.council_quest = true; + + if (my_level() >= 2 || my_path().id == PATH_EXPLOSIONS) + state.startable = true; + + if (state.in_progress) + { + if ($item[mosquito larva].available_amount() > 0) + { + state.state_boolean["have mosquito"] = true; + } + } + else if (state.finished) + { + state.state_boolean["have mosquito"] = true; + } + + __quest_state["Level 2"] = state; + __quest_state["Spooky Forest"] = state; +} + + +void QLevel2GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Level 2"]; + if (!base_quest_state.in_progress) + return; + + if (my_path().id == PATH_COMMUNITY_SERVICE || __misc_state["in aftercore"]) + return; + + ChecklistSubentry subentry; + string url = "place.php?whichplace=woods"; + + subentry.header = base_quest_state.quest_name; + + + if (base_quest_state.state_boolean["have mosquito"]) + { + subentry.entries.listAppend("Finished, go chat with the council."); + url = "place.php?whichplace=town"; + } + else + { + string [int] modifiers; + modifiers.listAppend("-combat"); + + if (delayRemainingInLocation($location[the spooky forest]) > 0) + { + string hipster_text = ""; + if (__misc_state["have hipster"]) + { + hipster_text = " (use " + __misc_state_string["hipster name"] + ")"; + modifiers.listAppend(__misc_state_string["hipster name"]); + } + string line = "Delay for " + pluralise(delayRemainingInLocation($location[the spooky forest]), "turn", "turns") + hipster_text + "."; + subentry.entries.listAppend(line); + subentry.entries.listAppend("Run -combat after that."); + } + else + subentry.entries.listAppend("Run -combat"); + subentry.entries.listAppend("Explore the stream" + __html_right_arrow_character + "March to the marsh"); + + + if (!__quest_state["Manor Unlock"].state_boolean["ballroom song effectively set"]) + subentry.entries.listAppend("Possibly wait until -combat ballroom song set. (marginal)"); + + if (__misc_state["free runs available"]) + { + subentry.entries.listAppend("Free run from monsters (low stats)"); + modifiers.listAppend("free runs"); + } + + + subentry.modifiers = modifiers; + } + + task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the spooky forest]).ChecklistEntrySetIDTag("Council L2 mosquito quest")); +} + + +void QLevel3Init() +{ + //questL03Rat + //lastTavernSquare + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL03Rat"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Typical Tavern Quest"; + state.image_name = "Typical Tavern"; + state.council_quest = true; + + if ((my_path().id == PATH_EXPLOSIONS || my_level() >= 3) && __quest_state["Level 2"].finished) + state.startable = true; + + __quest_state["Level 3"] = state; + __quest_state["Typical Tavern"] = state; +} + + +void QLevel3GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 3"].in_progress) + return; + QuestState base_quest_state = __quest_state["Level 3"]; + boolean wait_until_level_eleven = false; + if ($skill[ur-kel's aria of annoyance].skill_is_usable() && my_level() < 11) + wait_until_level_eleven = true; + + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + + if (base_quest_state.mafia_internal_step == 1) + subentry.entries.listAppend("Speak to the bartender."); + + boolean can_skip_cold = numeric_modifier("Cold Damage") >= 20.0; + boolean can_skip_hot = numeric_modifier("Hot Damage") >= 20.0; + boolean can_skip_spooky = numeric_modifier("Spooky Damage") >= 20.0; + boolean can_skip_stench = numeric_modifier("Stench Damage") >= 20.0; + + + + float combat_rate = clampNormalf((0.85 + combat_rate_modifier() / 100.0)); //15%? I can't remember... + + boolean need_to_complete_pyramid = true; + + //FIXME test properly + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + need_to_complete_pyramid = false; + if (__quest_state["Level 11"].finished) + need_to_complete_pyramid = false; + if (need_to_complete_pyramid && $item[tangle of rat tails].available_amount() < 6) + { + float rat_king_chance = clampNormalf(monster_level_adjustment_for_location($location[the typical tavern cellar]) / 300.0); + float average_tangles_found = (clampNormalf(rat_king_chance * combat_rate) * 8.5); + + if (wait_until_level_eleven) + subentry.entries.listAppend("May want to wait until level 11 for most +ML from aria."); + string line = "Run +ML for tangles (" + roundForOutput(rat_king_chance * 100.0, 0) + "% rat king chance, " + average_tangles_found.roundForOutput(1) + " tangles on average"; + line += ")"; + + subentry.entries.listAppend(line); + } + + string [int] elemental_sources_available; + if ($item[piddles].available_amount() > 0 && $effect[Belch the Rainbow™].have_effect() == 0) + elemental_sources_available.listAppend("+" + MIN(11, my_level()) + " piddles"); + + + if ($skill[Benetton's Medley of Diversity].skill_is_usable() && my_level() >= 15 && get_property_int("_benettonsCasts") < 10) + elemental_sources_available.listAppend("+15 Benetton's Medley of Diversity"); + + string elemental_sources_available_string; + if (elemental_sources_available.count() > 0) + elemental_sources_available_string = " (" + listJoinComponents(elemental_sources_available, ", ") + " available)"; + + if (true) + { + int ncs_skippable = 0; + string [int] additionals; + if (!can_skip_cold) + additionals.listAppend(HTMLGenerateSpanOfClass("cold", "r_element_cold")); + else + ncs_skippable += 1; + if (!can_skip_hot) + additionals.listAppend(HTMLGenerateSpanOfClass("hot", "r_element_hot")); + else + ncs_skippable += 1; + if (!can_skip_spooky) + additionals.listAppend(HTMLGenerateSpanOfClass("spooky", "r_element_spooky")); + else + ncs_skippable += 1; + if (!can_skip_stench) + additionals.listAppend(HTMLGenerateSpanOfClass("stench", "r_element_stench")); + else + ncs_skippable += 1; + + //drunken rat kings seem to happen after the combat/non-combat check, so recommend +combat if they need tangles: + + string combat_type_to_run = "-combat/maybe +combat"; + if (ncs_skippable > 0)// && ($item[tangle of rat tails].available_amount() * 3 + $item[tomb ratchet].available_amount() >= 11 || !need_to_complete_pyramid)) //technically should check if we're done with the pyramid moving, not level 11 finished, but that's harder to test. on second thought, just -combat if we can skip at least one? + combat_type_to_run = "-combat"; + string line; + if (additionals.count() > 0) + line += "Run " + combat_type_to_run + " with +20 " + additionals.listJoinComponents("/") + " damage."; + else + line += "Run " + combat_type_to_run + "."; + if (ncs_skippable < 4) + line += elemental_sources_available_string; + if (ncs_skippable > 0) + { + float rate = ncs_skippable.to_float() / 4.0; + if (ncs_skippable == 4) + line += "|Can skip every non-combat."; + else + line += "|Can skip " + (rate * 100.0).round() + "% of non-combats."; + } + subentry.modifiers.listAppend(combat_type_to_run); + subentry.entries.listAppend(line); + + if ($item[tangle of rat tails].available_amount() > 0 && need_to_complete_pyramid) + { + subentry.entries.listAppend(pluralise($item[tangle of rat tails]) + " found."); + } + } + if (need_to_complete_pyramid) + subentry.modifiers.listAppend("+300 ML"); + + string url = "tavern.php"; + + if (get_property_ascension("lastCellarReset") && base_quest_state.mafia_internal_step > 1) + url = "cellar.php"; + + ChecklistEntry entry = ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the typical tavern cellar]); + entry.tags.id = "Council L3 quest cellar"; + + if (wait_until_level_eleven && false) //Ehhh... no? It's like, a 5% difference? + optional_task_entries.listAppend(entry); + else + task_entries.listAppend(entry); +} + + +void QLevel4Init() +{ + //questL04Bat + //be sure to set state_int["areas unlocked"] + + //started -> no areas unlocked + //step1 -> 1 area unlocked + //step2 -> 2 areas unlocked + //step3 -> 3 areas unlocked + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL04Bat"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Boss Bat Quest"; + state.image_name = "Boss Bat"; + state.council_quest = true; + + if (state.in_progress) + { + //Zones opened? + if ($location[the batrat and ratbat burrow].locationAvailable()) + state.state_int["areas unlocked"] = 1; + if ($location[the beanbat chamber].locationAvailable()) + state.state_int["areas unlocked"] = 2; + if ($location[the boss bat\'s lair].locationAvailable()) + state.state_int["areas unlocked"] = 3; + + } + else if (state.finished) + { + state.state_int["areas unlocked"] = 3; + } + + if (my_level() >= 4 || my_path().id == PATH_EXPLOSIONS) + state.startable = true; + + __quest_state["Level 4"] = state; + __quest_state["Boss Bat"] = state; +} + + +void QLevel4GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 4"].in_progress) + return; + + QuestState base_quest_state = __quest_state["Level 4"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + string url = "place.php?whichplace=bathole"; + + if (base_quest_state.mafia_internal_step >= 5) + { + subentry.entries.listAppend("Quest finished, speak to the council of loathing."); + url = "place.php?whichplace=town"; + } + else if ($location[the boss bat\'s lair].locationAvailable()) + { + subentry.entries.listAppend("Possibly run +meat in the boss bat's lair. (250 meat drop)"); + subentry.modifiers.listAppend("+meat"); + if (delayRemainingInLocation($location[the boss bat\'s lair]) > 0) + { + string line = "Delay for " + pluralise(delayRemainingInLocation($location[the boss bat\'s lair]), "turn", "turns") + " before boss bat shows up."; + subentry.entries.listAppend(line); + } + } + else + { + int areas_unlocked = base_quest_state.state_int["areas unlocked"]; + int areas_locked = 3 - areas_unlocked; + int sonars_needed = MAX(areas_locked - $item[sonar-in-a-biscuit].available_amount(), 0); + + + if (true) + { + string line = pluraliseWordy(areas_locked, "area", "areas").capitaliseFirstLetter() + " to unlock"; + /*if ($item[sonar-in-a-biscuit].available_amount() > 0) + line += ", " + pluralise($item[sonar-in-a-biscuit]);*/ + line += "."; + subentry.entries.listAppend(line); + } + + if ($item[sonar-in-a-biscuit].available_amount() > 0 && areas_locked > 0 && $item[sonar-in-a-biscuit].item_is_usable()) + { + int amount = MIN(areas_locked, $item[sonar-in-a-biscuit].available_amount()); + subentry.entries.listAppend("Use " + pluralise(amount, $item[sonar-in-a-biscuit])); + url = "inventory.php?ftext=sonar-in-a-biscuit"; + } + + boolean have_stench_resistance = (numeric_modifier("stench resistance") > 0.0); + if (!have_stench_resistance) + { + string line = "Need " + HTMLGenerateSpanOfClass("stench resistance", "r_element_stench") + " to adventure in Guano Junction."; + string [int] possibilities; + //This could be more... unified: + if ($item[ghost of a necklace].available_amount() > 0) + { + if ($item[ghost of a necklace].equipped_amount() == 0) + line += "|*Equip your ghost of a necklace."; + } + else if ($item[bum cheek].available_amount() > 0) + { + if ($item[bum cheek].equipped_amount() == 0) + line += "|*Equip your bum cheek."; + } + else if ($item[knob goblin harem veil].available_amount() == 0) + { + possibilities.listAppend("acquire a knob goblin harem veil"); + possibilities.listAppend("finish the first floor of spookyraven manor"); + } + else + { + if ($item[knob goblin harem veil].equipped_amount() == 0) + { + possibilities.listAppend("equip your knob goblin harem veil"); + } + } + if ($skill[elemental saucesphere].have_skill()) + { + possibilities.listAppend("cast elemental saucesphere"); + } + else if (my_class() == $class[sauceror]) + possibilities.listAppend("learn elemental saucesphere at guild trainer"); + if (possibilities.count() > 0) + line += "|*Possibly " + possibilities.listJoinComponents(", ", "or") + "."; + + subentry.entries.listAppend(line); + } + + + if ($item[enchanted bean].available_amount() == 0 && !__quest_state["Level 10"].state_boolean["beanstalk grown"]) + { + if ($location[the beanbat chamber].locationAvailable()) + subentry.entries.listAppend("Run +100% item in the beanbat chamber for a single turn for enchanted bean. (50% drop)"); + else + subentry.entries.listAppend("When beanbat chamber is unlocked, run +100% item for a single turn there for enchanted bean (50% drop)"); + } + + int total_turns = $location[Guano Junction].turns_spent + $location[The Batrat and Ratbat Burrow].turns_spent + $location[The Beanbat Chamber].turns_spent; + int turns_until_next_screambat = 8 - (total_turns % 8); + if (turns_until_next_screambat == 8 && total_turns != 0) turns_until_next_screambat = 0; + boolean screambat_up_now = false; + + if (turns_until_next_screambat == 0) + { + screambat_up_now = true; + subentry.entries.listAppend("Screambat next turn."); + } + else + subentry.entries.listAppend("Screambat after " + pluraliseWordy(turns_until_next_screambat, "turn", "turns") + "."); + + if (!screambat_up_now && $item[sonar-in-a-biscuit].item_is_usable()) + { + if (__misc_state["yellow ray available"] && sonars_needed > 0) + subentry.entries.listAppend("Potentially yellow ray for sonar-in-a-biscuit."); + if (sonars_needed > 0) + subentry.entries.listAppend("Run +item in the batrat and ratbat burrow for biscuits. (15% drop)"); + subentry.modifiers.listAppend("+566% item"); + + //Low chance that they started copperhead without having done this, but who knows; just in case + if (__quest_state["Level 11 Shen"].state_int.getFutureShenAssignments().listInvert() contains $location[The Batrat and Ratbat Burrow]) + subentry.entries.listAppend("Could wait before going there? Shen will send you to the Burrow later."); + } + //subentry.entries.listAppend("Run +meat in the boss bat's lair, if you wish. (250 meat drop)"); + } + + task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the bat hole entrance, guano junction, the batrat and ratbat burrow, the beanbat chamber,the boss bat's lair]).ChecklistEntrySetIDTag("Council L4 bat quest")); +} + + +void QLevel5Init() +{ + //questL05Goblin + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL05Goblin"); + + state.quest_name = "Knob Goblin Quest"; + state.image_name = "cobb's knob"; + state.council_quest = true; + + + if (my_level() >= 5 || my_path().id == PATH_EXPLOSIONS) + state.startable = true; + + if (get_property("questL05Goblin") == "unstarted" && $item[knob goblin encryption key].available_amount() == 0 && my_path().id != PATH_COMMUNITY_SERVICE) + { + //start the quest anyways, because they need to acquire the encryption key: + //there's also an edge case here in BIG!, where you want to avoid visiting the council for a while to yellow ray an outfit + QuestStateParseMafiaQuestPropertyValue(state, "started"); + } + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + __quest_state["Level 5"] = state; + __quest_state["Knob Goblin King"] = state; +} + + +void QLevel5GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 5"].in_progress) + return; + if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO || my_path().id == PATH_SEA || __misc_state["in aftercore"]) + return; + string url = "place.php?whichplace=plains"; + //if the quest isn't started and we have unlocked the barracks, wait until it's started: + if (get_property("questL05Goblin") == "unstarted" && $item[knob goblin encryption key].available_amount() > 0) //have key already, waiting for quest to start, nothing more to do here + return; + + QuestState base_quest_state = __quest_state["Level 5"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + + boolean should_output = true; + + if (!$location[cobb's knob barracks].locationAvailable()) + { + if ($item[knob goblin encryption key].available_amount() == 0) + { + //Need key: + //Unlocking: + if (__misc_state["have hipster"]) + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + if (__misc_state["free runs available"]) + subentry.modifiers.listAppend("free runs"); + + int turns_spent = $location[the outskirts of cobb's knob].turns_spent; + if (turns_spent != -1) + { + int delay_turns_remaining = 10 - turns_spent; + if (delay_turns_remaining == 0) + subentry.entries.listAppend("Map appears next turn in cobb's knob."); + else + subentry.entries.listAppend("Delay for " + pluraliseWordy(delay_turns_remaining, "more turn", "more turns") + " in cobb's knob to unlock area."); + } + else + subentry.entries.listAppend("Delay for ten turns in cobb's knob to unlock area."); + if ($classes[seal clubber, turtle tamer] contains my_class() && !__misc_state["guild open"] && !QuestState("questG09Muscle").started && my_path().id != PATH_NUCLEAR_AUTUMN) + { + url = "guild.php"; + subentry.entries.listAppend("Start your guild quest first."); + } + } + else if ($item[cobb's knob map].available_amount() > 0 && $item[knob goblin encryption key].available_amount() > 0) + { + url = "inventory.php?ftext=cobb's+knob+map"; + subentry.entries.listAppend("Use cobb's knob map to unlock area."); + } + else if ($item[cobb's knob map].available_amount() == 0 && $item[knob goblin encryption key].available_amount() > 0) + should_output = false; + } + else + { + url = "cobbsknob.php"; + //Cobb's knob unlocked. Now to set up for king: + + boolean can_use_harem_route = true; + boolean can_use_kge_route = true; + + boolean have_knob_cake_or_ingredients = false; + have_knob_cake_or_ingredients = ($item[knob cake].available_amount() > 0 || creatable_amount($item[knob cake]) > 0); + + if (can_use_kge_route && have_outfit_components("Knob Goblin Elite Guard Uniform") && have_knob_cake_or_ingredients) + can_use_harem_route = false; + else if (can_use_harem_route && have_outfit_components("Knob Goblin Harem Girl Disguise") && have_outfit_components("Knob Goblin Elite Guard Uniform")) //only stop guarding after KGE is acquired, for dispensary + can_use_kge_route = false; + + if (!__misc_state["can equip just about any weapon"]) + can_use_kge_route = false; + string fight_king_string = "fight king"; + if (53 + monster_level_adjustment() > my_buffedstat($stat[moxie])) + fight_king_string += " (" + (53 + monster_level_adjustment()) + " attack)"; + if (can_use_harem_route) + { + string [int] harem_modifiers; + string [int] harem_lines; + if (!have_outfit_components("Knob Goblin Harem Girl Disguise")) + { + harem_lines.listAppend("Need disguise.|*20% drop from harem girls (olfact)|*Or adventure in zone for eleven (or more) turns."); + harem_modifiers.listAppend("+400% item"); + harem_modifiers.listAppend("olfact harem girls"); + if ($familiar[slimeling].familiar_is_usable()) + harem_modifiers.listAppend("slimeling?"); + } + else + { + string [int] things_to_do_before_fighting_king; + if (!is_wearing_outfit("Knob Goblin Harem Girl Disguise")) + things_to_do_before_fighting_king.listAppend("wear harem girl disguise"); + if ($effect[Knob Goblin Perfume].have_effect() > 0) + { + } + else + { + if ($item[knob goblin perfume].available_amount() > 0) + { + things_to_do_before_fighting_king.listAppend("use knob goblin perfume"); + } + else + { + things_to_do_before_fighting_king.listAppend("adventure in harem for perfume"); + } + } + things_to_do_before_fighting_king.listAppend(fight_king_string); + harem_lines.listAppend(things_to_do_before_fighting_king.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + } + subentry.entries.listAppend("Harem route:|*" + ChecklistGenerateModifierSpan(harem_modifiers) + harem_lines.listJoinComponents("|*")); + } + if (can_use_kge_route) + { + string [int] kge_modifiers; + string [int] kge_lines; + + if (!have_outfit_components("Knob Goblin Elite Guard Uniform")) + { + int outfit_pieces_needed = 0; + if ($item[Knob Goblin elite polearm].available_amount() == 0) + outfit_pieces_needed += 1; + if ($item[Knob Goblin elite pants].available_amount() == 0) + outfit_pieces_needed += 1; + if ($item[Knob Goblin elite helm].available_amount() == 0) + outfit_pieces_needed += 1; + //take into account combats? + //with banishes and slimeling and +item and? + //too complicated. Possibly remove? + kge_modifiers.listAppend("-combat"); + if ($familiar[slimeling].familiar_is_usable()) + kge_modifiers.listAppend("slimeling?"); + string line = "Need knob goblin elite guard uniform.|*Lucky adventure in barracks.|*Or run -combat in barracks"; + if (familiar_is_usable($familiar[slimeling])) + line += " with slimeling"; + + line += "."; + + line += "|*" + generateTurnsToSeeNoncombat(85, outfit_pieces_needed, "acquire outfit via only non-combats"); + kge_lines.listAppend(line); + } + else + { + string cook_cake_line = "cook a knob cake"; + + if (!__misc_state["can cook for free"]) + { + cook_cake_line += " (1 adventure"; + if (skill_is_usable($skill[inigo's incantation of inspiration])) + cook_cake_line += ", can use inigo's"; + cook_cake_line += ")"; + } + string [int] things_to_do_before_fighting_king; + if (!is_wearing_outfit("Knob Goblin Elite Guard Uniform")) + things_to_do_before_fighting_king.listAppend("wear knob goblin elite guard uniform"); + + + boolean have_first_step = ($item[knob cake pan].available_amount() > 0 || $item[unfrosted Knob cake].available_amount() > 0); + boolean have_second_step = ($item[knob batter].available_amount() > 0 || $item[unfrosted Knob cake].available_amount() > 0); + boolean have_third_step = ($item[knob frosting].available_amount() > 0); + have_third_step = have_third_step && have_second_step && have_first_step; + have_second_step = have_second_step && have_first_step; + + if ($item[knob cake].available_amount() > 0) + { + } + else if (have_first_step && have_second_step && have_third_step) + { + things_to_do_before_fighting_king.listAppend(cook_cake_line); + } + else + { + + string times_remaining = "three times"; + if (have_first_step) + times_remaining = "two times"; + if (have_second_step) + times_remaining = "One More Time"; + if (have_third_step) + times_remaining = "zero times?"; + string line = "adventure in kitchens " + times_remaining + " for knob cake components"; + things_to_do_before_fighting_king.listAppend(line); + things_to_do_before_fighting_king.listAppend(cook_cake_line); + } + things_to_do_before_fighting_king.listAppend(fight_king_string); + kge_lines.listAppend(things_to_do_before_fighting_king.listJoinComponents(", then ", "").capitaliseFirstLetter() + "."); + } + subentry.entries.listAppend("Guard route:|*" + ChecklistGenerateModifierSpan(kge_modifiers) + kge_lines.listJoinComponents("|*")); + } + if (!__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "") + { + stat stat_race_type = __quest_state["Level 13"].state_string["Stat race type"].to_stat(); + + int change_mcd_to = -1; + if (stat_race_type == $stat[muscle] && (current_mcd() == 3 || current_mcd() == 7) && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) + change_mcd_to = -2; + else if (stat_race_type == $stat[mysticality]) + change_mcd_to = 3; + else if (stat_race_type == $stat[moxie]) + change_mcd_to = 7; + + if (change_mcd_to != -1 && change_mcd_to != current_mcd()) + { + string mcd_change_text = change_mcd_to; + if (change_mcd_to == -2) + mcd_change_text = "anything besides 3 or 7"; + subentry.entries.listAppend("For the king fight, change MCD to " + mcd_change_text + " for the tower stat test. (+" + stat_race_type.to_lower_case() + ")"); + } + } + } + + + if (should_output) + task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[cobb's knob barracks, cobb's knob kitchens, cobb's knob harem, the outskirts of cobb's knob]).ChecklistEntrySetIDTag("Council L5 knob quest")); +} + + +void QLevel6Init() +{ + //questL06Friar + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL06Friar"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Deep Fat Friars' Quest"; + state.image_name = "forest friars"; + state.council_quest = true; + + if (my_level() >= 6 || my_path().id == PATH_EXPLOSIONS) + state.startable = true; + + state.state_int["dark neck turns on last nc"] = 0; + state.state_int["dark heart turns on last nc"] = 0; + state.state_int["dark elbow turns on last nc"] = 0; + + __quest_state["Level 6"] = state; + __quest_state["Friars"] = state; +} + +float QLevel6TurnsToCompleteArea(location place) +{ + QuestState base_quest_state = __quest_state["Level 6"]; + //FIXME not sure how accurate these calculations are. + int ncs_found = noncombatTurnsAttemptedInLocation(place); + + + // get_property("lastFriarsXNC").to_int() will return 0 until the first NC is hit, then it will return the turns spent in the zone prior to hitting the NC, + // so we need to add 1 to account for the last NC itself + // For example, if you spend 3 turns in the neck, hit an NC, then hit another NC after 2 turns the pref will manifest as: + // TURN 1: lastFriarsNeckNC = 0 + // TURN 2: lastFriarsNeckNC = 0 + // TURN 3: lastFriarsNeckNC = 0 + // TURN 4: lastFriarsNeckNC = 3 <= hits NC + // TURN 5: lastFriarsNeckNC = 3 + // TURN 6: lastFriarsNeckNC = 3 + // TURN 7: lastFriarsNeckNC = 6 <= hits NC + base_quest_state.state_int["dark neck turns on last nc"] = get_property("lastFriarsNeckNC").to_int() > 0 ? get_property("lastFriarsNeckNC").to_int() + 1 : 0; + base_quest_state.state_int["dark heart turns on last nc"] = get_property("lastFriarsHeartNC").to_int() > 0 ? get_property("lastFriarsHeartNC").to_int() + 1 : 0; + base_quest_state.state_int["dark elbow turns on last nc"] = get_property("lastFriarsElbowNC").to_int() > 0 ? get_property("lastFriarsElbowNC").to_int() + 1 : 0; + + boolean [string] area_known_ncs; + if (place == $location[The Dark Neck of the Woods]) + area_known_ncs = $strings[How Do We Do It? Quaint and Curious Volume!,Strike One!,Olive My Love To You\, Oh.,Dodecahedrariffic!]; + if (place == $location[The Dark Heart of the Woods]) + area_known_ncs = $strings[Moon Over the Dark Heart,Running the Lode,I\, Martin,Imp Be Nimble\, Imp Be Quick]; + if (place == $location[The Dark Elbow of the Woods]) + area_known_ncs = $strings[Deep Imp Act,Imp Art\, Some Wisdom,A Secret\, But Not the Secret You're Looking For,Butter Knife? I'll Take the Knife]; + + if (area_known_ncs.count() > 0) + { + ncs_found = 0; + string [int] location_ncs = place.locationSeenNoncombats(); + foreach key, s in location_ncs + { + if (area_known_ncs contains s) + { + ncs_found += 1; + } + } + } + + if (ncs_found == 4) + { + return 0.0; + } + + float turns_remaining = 0.0; + int ncs_remaining = MAX(0, 4 - ncs_found); + + float combat_rate = 0.95 + combat_rate_modifier() / 100.0; + float noncombat_rate = 1.0 - combat_rate; + + if (noncombat_rate != 0.0) + turns_remaining = ncs_remaining / noncombat_rate; + else + turns_remaining = 10000.0; //how do you refer to infinity in this language? + + int max_turns_remaining = ncs_remaining * 5; + if (place == $location[The Dark Neck of the Woods]) + max_turns_remaining -= $location[The Dark Neck of the Woods].turns_spent - base_quest_state.state_int["dark neck turns on last nc"]; + if (place == $location[The Dark Heart of the Woods]) + max_turns_remaining -= $location[The Dark Heart of the Woods].turns_spent - base_quest_state.state_int["dark heart turns on last nc"]; + if (place == $location[The Dark Elbow of the Woods]) + max_turns_remaining -= $location[The Dark Elbow of the Woods].turns_spent - base_quest_state.state_int["dark elbow turns on last nc"]; + return MIN(turns_remaining, max_turns_remaining); +} + + +void QLevel6GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 6"].in_progress) + return; + boolean want_hell_ramen = false; + if ($skill[pastamastery].skill_is_usable() && $skill[Advanced Saucecrafting].skill_is_usable()) + want_hell_ramen = true; + if (my_path().id == PATH_SLOW_AND_STEADY) + want_hell_ramen = false; + want_hell_ramen = false; //this needs rethinking + + boolean hot_wings_relevant = __quest_state["Pirate Quest"].state_boolean["hot wings relevant"] && __quest_state["Pirate Quest"].state_boolean["valid"]; + boolean need_more_hot_wings = __quest_state["Pirate Quest"].state_boolean["need more hot wings"] && __quest_state["Pirate Quest"].state_boolean["valid"]; + + QuestState base_quest_state = __quest_state["Level 6"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + if (want_hell_ramen && __misc_state["have olfaction equivalent"]) + subentry.modifiers.listAppend("olfact hellions"); + + string [int] sources_need_234; + if (want_hell_ramen) + sources_need_234.listAppend("hell ramen"); + if (need_more_hot_wings) + sources_need_234.listAppend("hot wings"); + if (sources_need_234.count() > 0) + subentry.modifiers.listAppend("+234% item"); + + boolean hipster_fights_needed = false; + boolean need_minus_combat = false; + if ($item[dodecagram].available_amount() == 0) { + hipster_fights_needed = true; + subentry.entries.listAppend("Adventure in " + HTMLGenerateSpanOfClass("Dark Neck of the Woods", "r_bold") + ", acquire dodecagram.|~" + roundForOutput(QLevel6TurnsToCompleteArea($location[The Dark Neck of the Woods]), 1) + " turns remain at " + combat_rate_modifier().floor() + "% combat."); + if ($location[The Dark Neck of the Woods].turns_spent - base_quest_state.state_int["dark neck turns on last nc"] >= 5) + subentry.entries.listAppend(HTMLGenerateSpanOfClass("Your next adventure in the Neck will be an NC", "r_bold")); + need_minus_combat = true; + } + if ($item[box of birthday candles].available_amount() == 0) { + hipster_fights_needed = true; + subentry.entries.listAppend("Adventure in " + HTMLGenerateSpanOfClass("Dark Heart of the Woods", "r_bold") + ", acquire box of birthday candles.|~" + roundForOutput(QLevel6TurnsToCompleteArea($location[The Dark Heart of the Woods]), 1) + " turns remain at " + combat_rate_modifier().floor() + "% combat."); + if ($location[The Dark Heart of the Woods].turns_spent - base_quest_state.state_int["dark heart turns on last nc"] >= 5) + subentry.entries.listAppend(HTMLGenerateSpanOfClass("Your next adventure in the Heart will be an NC", "r_bold")); + need_minus_combat = true; + } + if ($item[Eldritch butterknife].available_amount() == 0) { + hipster_fights_needed = true; + subentry.entries.listAppend("Adventure in " + HTMLGenerateSpanOfClass("Dark Elbow of the Woods", "r_bold") + ", acquire Eldritch butterknife.|~" + roundForOutput(QLevel6TurnsToCompleteArea($location[The Dark Elbow of the Woods]), 1) + " turns remain at " + combat_rate_modifier().floor() + "% combat."); + if ($location[The Dark Elbow of the Woods].turns_spent - base_quest_state.state_int["dark elbow turns on last nc"] >= 5) + subentry.entries.listAppend(HTMLGenerateSpanOfClass("Your next adventure in the Elbow will be an NC", "r_bold")); + need_minus_combat = true; + } + + //hipster fights advance the superlikelies. in slow paths, is this relevant? + //FIXME suggest in HCO/S&S? + //if (hipster_fights_needed && __misc_state["have hipster"]) + //subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + + string [int] needed_modifiers; + if (need_minus_combat) { + subentry.modifiers.listAppend("-combat"); + needed_modifiers.listAppend("-combat"); + } + if (sources_need_234.count() > 0) + needed_modifiers.listAppend("+234% item for " + listJoinComponents(sources_need_234, "/")); + if (needed_modifiers.count() > 0) + subentry.entries.listAppend("Run " + needed_modifiers.listJoinComponents(", ", "and") + "."); + + if ($item[dodecagram].available_amount() + $item[box of birthday candles].available_amount() + $item[Eldritch butterknife].available_amount() == 3) { + if (!(hot_wings_relevant && $item[hot wing].available_amount() <3)) { + subentry.entries.listAppend("Go to the cairn stones!"); + } else { + subentry.entries.listAppend("Visit The Dark Heart of the Woods for hot wings."); + } + } + if (!get_property_ascension("lastTempleUnlock") && QuestState("questM16Temple").in_progress && $item[heavy-duty bendy straw].available_amount() == 0) + subentry.entries.listAppend("Potentially find a heavy-duty bendy straw, first.|From fallen archfiends in The Dark Heart of the Woods."); + if (__misc_state_int["ruby w needed"] > 0) + subentry.entries.listAppend("Potentially find ruby W, if not clovering (w imp, dark neck, 30% drop)"); + if (hot_wings_relevant) { + if ($item[hot wing].available_amount() <3 ) + subentry.entries.listAppend((MIN(3, $item[hot wing].available_amount())) + "/3 hot wings for pirate quest. (optional, 30% drop)"); + else + subentry.entries.listAppend((MIN(3, $item[hot wing].available_amount())) + "/3 hot wings for pirate quest."); + } + boolean should_delay = false; + if (!__quest_state["Manor Unlock"].state_boolean["ballroom song effectively set"] && need_minus_combat) { + subentry.entries.listAppend(HTMLGenerateSpanOfClass("Wait until -combat ballroom song set.", "r_bold")); + should_delay = true; + } + + ChecklistEntry entry = ChecklistEntryMake(base_quest_state.image_name, "friars.php", subentry, $locations[The Dark Neck of the Woods, The Dark Heart of the Woods, The Dark Elbow of the Woods]); + entry.tags.id = "Council L6 friars quest"; + + if (should_delay) + future_task_entries.listAppend(entry); + else + task_entries.listAppend(entry); +} + +void QLevel7Init() +{ + int CYRPT_BOSS_EVILNESS = 13; + //questL07Cyrptic + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL07Cyrptic"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Cyrpt Quest"; + state.image_name = "cyrpt"; + state.council_quest = true; + + if (my_level() >= 7 || my_path().id == PATH_EXPLOSIONS) + state.startable = true; + + if (state.started) + { + state.state_int["alcove evilness"] = get_property_int("cyrptAlcoveEvilness"); + state.state_int["cranny evilness"] = get_property_int("cyrptCrannyEvilness"); + state.state_int["niche evilness"] = get_property_int("cyrptNicheEvilness"); + state.state_int["nook evilness"] = get_property_int("cyrptNookEvilness"); + } + else + { + //mafia won't track these properly until quest is started, I think? + state.state_int["alcove evilness"] = 50; + state.state_int["cranny evilness"] = 50; + state.state_int["niche evilness"] = 50; + state.state_int["nook evilness"] = 50; + } + + if (state.finished) + { + //just in case: + state.state_int["alcove evilness"] = 0; + state.state_int["cranny evilness"] = 0; + state.state_int["niche evilness"] = 0; + state.state_int["nook evilness"] = 0; + } + + foreach l in $strings[alcove,cranny,niche,nook] + { + boolean need_speeding_up = false; + int evilness = state.state_int[l + " evilness"]; + + if (l == "alcove" && get_property_monster("romanticTarget") == $monster[modern zmobie]) + evilness -= 5 * get_property_int("_romanticFightsLeft"); + + if (evilness <= CYRPT_BOSS_EVILNESS + 1) + need_speeding_up = false; + else + need_speeding_up = true; + state.state_boolean[l + " needs speed tricks"] = need_speeding_up; + + } + + if (state.state_int["alcove evilness"] <= 0) + state.state_boolean["alcove finished"] = true; + if (state.state_int["cranny evilness"] <= 0) + state.state_boolean["cranny finished"] = true; + if (state.state_int["niche evilness"] <= 0) + state.state_boolean["niche finished"] = true; + if (state.state_int["nook evilness"] <= 0) + state.state_boolean["nook finished"] = true; + + + __quest_state["Level 7"] = state; + __quest_state["Cyrpt"] = state; +} + + +void QLevel7GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + int CYRPT_BOSS_EVILNESS = 13; + if (!__quest_state["Level 7"].in_progress) + return; + QuestState base_quest_state = __quest_state["Level 7"]; + + ChecklistEntry entry; + entry.url = "crypt.php"; + entry.image_lookup_name = base_quest_state.image_name; + entry.tags.id = "Council L7 crypt cyrpt quest"; + entry.should_indent_after_first_subentry = true; + entry.subentries.listAppend(ChecklistSubentryMake(base_quest_state.quest_name)); + entry.should_highlight = $locations[the defiled nook, the defiled cranny, the defiled alcove, the defiled niche, haert of the cyrpt] contains __last_adventure_location; + + string [int] evilness_properties = split_string_alternate("cyrptAlcoveEvilness,cyrptCrannyEvilness,cyrptNicheEvilness,cyrptNookEvilness", ","); + string [string] evilness_text; + + foreach key in evilness_properties + { + string property = evilness_properties[key]; + int evilness = get_property_int(property); + string text; + if (evilness == 0) + text = "Finished"; + else if (evilness <= CYRPT_BOSS_EVILNESS) + text = HTMLGenerateSpanFont("At boss", "red"); + else + text = (evilness - CYRPT_BOSS_EVILNESS) + " evilness to boss."; + evilness_text[property] = text; + } + + // speed up cyrpt using Slay the Dead + if ($item[unwrapped knock-off retro superhero cape].available_amount() > 0 && __iotms_usable[lookupItem("unwrapped knock-off retro superhero cape")] && __misc_state["can equip just about any weapon"]) { + string cape_hero = get_property("retroCapeSuperhero"); + string cape_tag = get_property("retroCapeWashingInstructions"); + + string [int] problems; + if ($item[unwrapped knock-off retro superhero cape].equipped_amount() == 0) { + problems.listAppend("Equip the superhero cape"); + } + if (cape_hero != "vampire" || cape_tag != "kill") { + problems.listAppend("Set retro superhero cape to \"Vampire Slicer\"+\"Kill Me\""); + } + if ($slot[weapon].equipped_item().item_type() != "sword") { + problems.listAppend("Equip a sword in your main-hand"); + } + + if (problems.count() > 0) { + entry.subentries[0].entries.listAppend(problems.listJoinComponents(", ", "and") + " to Slay the Dead in combat."); + } + else { + entry.subentries[0].entries.listAppend("Cast Slay the Dead in combat for +1 evil reduction/fight."); + } + } + + if (!base_quest_state.state_boolean["nook finished"]) + { + int evilness = base_quest_state.state_int["nook evilness"]; + ChecklistSubentry subentry; + subentry.header = "Defiled Nook"; + + subentry.entries.listAppend(evilness_text["cyrptNookEvilness"]); + + if (evilness > CYRPT_BOSS_EVILNESS + 1 && my_path().id != PATH_G_LOVER) + { + subentry.modifiers.listAppend("+400% item"); + subentry.modifiers.listAppend("banish party skelteon"); + + float [monster] appearance_rates = $location[the defiled nook].appearance_rates_adjusted_cancel_nc(); + float chance_of_monster_with_eye = 0.0; + chance_of_monster_with_eye += 1.0 * appearance_rates[$monster[spiny skelelton]] / 100.0; + chance_of_monster_with_eye += 1.0 * appearance_rates[$monster[toothy sklelton]] / 100.0; + + float item_drop = (100.0 + chance_of_monster_with_eye * $location[the defiled nook].item_drop_modifier_for_location()) / 100.0; + + float eyes_per_adventure = MIN(1.0, (item_drop) * 0.2); + float eyes_value = 3.0; + if (evilness < CYRPT_BOSS_EVILNESS + 4) + eyes_value = clampi(evilness - CYRPT_BOSS_EVILNESS - 1, 0, 3); + float evilness_per_adventure = 1.0; + if ($item[gravy boat].equipped_amount() > 0) + evilness_per_adventure += 1.0; + evilness_per_adventure = MAX(evilness_per_adventure, evilness_per_adventure + eyes_per_adventure * eyes_value); + + if ($item[evil eye].available_amount() > 0) + { + if ($item[evil eye].available_amount() == 1) + subentry.entries.listAppend("Use your evil eye."); + else + subentry.entries.listAppend("Use your evil eyes."); + } + if (__iotms_usable[$item[haunted doghouse]] && !$location[the defiled nook].noncombat_queue.contains_text("Seeing-Eyes Dog") && $location[the defiled nook].turns_spent >= 5) + { + //haunted doghouse adventures are a percentage chance, and the NC is skippable. more NCs, more chances, less turns spent + subentry.modifiers.listAppend("-combat"); + } + if (my_path().id == PATH_EXPLOSIONS) + subentry.entries.listAppend("Ignore this area until the end of the run; wandering astronauts drop evil eyes. Lure them to delay-burning areas; keep signal jammer equipped otherwise."); + + float evilness_remaining = evilness - CYRPT_BOSS_EVILNESS; + evilness_remaining -= $item[evil eye].available_amount() * 3; + if (evilness_remaining > 0) + { + float average_turns_remaining = (evilness_remaining / evilness_per_adventure); + int theoretical_best_turns_remaining = ceil(evilness_remaining / 4.0); + if (average_turns_remaining < theoretical_best_turns_remaining) //not sure about this. +344.91% item, 38 evilness, 4 optimal, 3.something not-optimal, what does it mean? + average_turns_remaining = theoretical_best_turns_remaining; + + subentry.entries.listAppend(roundForOutput(eyes_per_adventure * 100.0, 0) + "% chance of evil eyes."); + subentry.entries.listAppend("~" + roundForOutput(average_turns_remaining, 1) + " turns remain to boss. (theoretical best: " + theoretical_best_turns_remaining + ")"); + } + } + + entry.subentries.listAppend(subentry); + } + if (!base_quest_state.state_boolean["niche finished"]) + { + int evilness = base_quest_state.state_int["niche evilness"]; + ChecklistSubentry subentry; + subentry.header = "Defiled Niche"; + + subentry.entries.listAppend(evilness_text["cyrptNicheEvilness"]); + + float [monster] appearance_rates = $location[the defiled niche].appearance_rates_adjusted_cancel_nc(); + float evilness_removed_per_adventure = 0.0; + evilness_removed_per_adventure += 1.0 * appearance_rates[$monster[basic lihc]] / 100.0; + evilness_removed_per_adventure += 1.0 * appearance_rates[$monster[slick lihc]] / 100.0; + evilness_removed_per_adventure += 1.0 * appearance_rates[$monster[senile lihc]] / 100.0; + evilness_removed_per_adventure += 3.0 * appearance_rates[$monster[dirty old lihc]] / 100.0; + + float evilness_remaining = MAX(0, evilness - CYRPT_BOSS_EVILNESS); + int turns_remaining = evilness_remaining; + + if (evilness_removed_per_adventure != 0.0) + turns_remaining = MAX(1, ceiling(evilness_remaining / evilness_removed_per_adventure)); + + // TODO: This doesn't work if the user is using a non-olfaction copy source, like nosy nose or monkey point. Need to add logic for that + boolean sniffedDOL = false; + if (get_property_monster("olfactedMonster") == $monster[dirty old lihc]) sniffedDOL = true; + + // evilness_removed_per_adventure will = 0 if all appearance rates are 0, i.e., everyone is banished. + // This allows the tile to note that if DOL is olfacted and everything else is banished via phylum + // silliness, you can assume the rest of the turns are DOL. Otherwise, everything is unbanished, so + // you get 1.5 per turn (average of all 4 monsters). + if (evilness_removed_per_adventure == 0.0) + { + if (sniffedDOL) turns_remaining = MAX(1, ceiling(evilness_remaining / 3.0)); + if (!sniffedDOL) turns_remaining = MAX(1, ceiling(evilness_remaining / 1.5)); + + } + + if (evilness > CYRPT_BOSS_EVILNESS + 1 && (appearance_rates[$monster[slick lihc]] > 0.0 || appearance_rates[$monster[senile lihc]] > 0.0)) + { + subentry.modifiers.listAppend("olfact dirty old lihc"); + subentry.modifiers.listAppend("banish"); + } + if (evilness > CYRPT_BOSS_EVILNESS) + subentry.entries.listAppend("~" + turns_remaining.roundForOutput(1) + " turns remaining to boss."); + + entry.subentries.listAppend(subentry); + } + if (!base_quest_state.state_boolean["cranny finished"]) + { + ChecklistSubentry subentry; + subentry.header = "Defiled Cranny"; + subentry.entries.listAppend(evilness_text["cyrptCrannyEvilness"]); + + if (base_quest_state.state_int["cranny evilness"] > CYRPT_BOSS_EVILNESS + 1) + { + subentry.modifiers.listAppend("-combat"); + subentry.modifiers.listAppend("+ML"); + float monster_level = monster_level_adjustment_for_location($location[the defiled cranny]); + + monster_level = MAX(monster_level, 0); + + float cranny_beep_beep_beep = MAX(3.0,sqrt(monster_level)); + int beep_boop_lookup = floor(cranny_beep_beep_beep) - 3; + + float area_combat_rate = clampNormalf(0.85 + combat_rate_modifier() / 100.0); + float area_nc_rate = 1.0 - area_combat_rate; + + float average_beeps_per_turn = cranny_beep_beep_beep * area_nc_rate + 1.0 * area_combat_rate; + float average_turns_remaining = ((base_quest_state.state_int["cranny evilness"] - CYRPT_BOSS_EVILNESS) / average_beeps_per_turn); + + average_turns_remaining = MAX(1, average_turns_remaining); + + subentry.entries.listAppend("~" + cranny_beep_beep_beep.roundForOutput(1) + " beeps per ghuol swarm. ~" + average_turns_remaining.roundForOutput(1) + " turns remain to boss."); + } + else if (base_quest_state.state_int["cranny evilness"] <= CYRPT_BOSS_EVILNESS) + subentry.modifiers.listAppend("+meat"); + + entry.subentries.listAppend(subentry); + } + if (!base_quest_state.state_boolean["alcove finished"]) + { + ChecklistSubentry subentry; + int evilness = base_quest_state.state_int["alcove evilness"]; + subentry.header = "Defiled Alcove"; + subentry.entries.listAppend(evilness_text["cyrptAlcoveEvilness"]); + + + int evilness_after_arrow = evilness; + if (get_property_monster("romanticTarget") == $monster[modern zmobie]) + evilness_after_arrow -= 5 * get_property_int("_romanticFightsLeft"); + + if (evilness_after_arrow <= CYRPT_BOSS_EVILNESS && evilness > CYRPT_BOSS_EVILNESS) + { + subentry.entries.listAppend("Wait for modern zmobie arrows."); + } + else if (evilness > CYRPT_BOSS_EVILNESS + 1) + { + subentry.modifiers.listAppend("+850% init"); + subentry.modifiers.listAppend("-combat"); + int zmobies_needed = ceil((evilness.to_float() - CYRPT_BOSS_EVILNESS.to_float()) / 5.0); // used to be a +1 there; hope this is OK? + float zmobie_chance = min(100.0, 15.0 + initiative_modifier_for_location($location[the defiled alcove]) / 10.0); + + subentry.entries.listAppend(pluralise(zmobies_needed, "modern zmobie", "modern zmobies") + " needed (" + roundForOutput(zmobie_chance, 0) + "% chance of appearing)"); + + //float combat_rate = clampNormalf(0.85 + combat_rate_modifier() / 100.0); + //float nc_rate = 1.0 - combat_rate; + + if ($familiar[oily woim].familiar_is_usable() && !(($familiars[oily woim,happy medium] contains my_familiar()))) + { + if (!(my_familiar() == $familiar[Xiblaxian Holo-Companion] && my_familiar() != $familiar[none])) + subentry.entries.listAppend("Run " + $familiar[oily woim] + ($familiar[happy medium].familiar_is_usable() ? "/medium" : "") + ($familiar[Xiblaxian Holo-Companion].familiar_is_usable() ? "/holo-companion" : "") + " for +init."); + } + + + } + else if (evilness <= CYRPT_BOSS_EVILNESS) + subentry.modifiers.listAppend("+meat"); + entry.subentries.listAppend(subentry); + } + if (base_quest_state.mafia_internal_step == 2) + { + entry.subentries[0].entries.listAppend("Go talk to the council to finish the quest."); + entry.url = "place.php?whichplace=town"; + } + else if (base_quest_state.state_boolean["alcove finished"] && base_quest_state.state_boolean["cranny finished"] && base_quest_state.state_boolean["niche finished"] && base_quest_state.state_boolean["nook finished"]) + { + float bonerdagon_attack = (90 + monster_level_adjustment()); + + string line = "Fight bonerdagon!"; + if (my_path().id == PATH_HEAVY_RAINS) + line = "Fight auqadargon!"; + if (my_basestat($stat[moxie]) < bonerdagon_attack) + line += " (attack: " + bonerdagon_attack.round() + ")"; + entry.subentries[0].entries.listAppend(line); + } + task_entries.listAppend(entry); +} + + + + +string generateNinjaSafetyGuide(boolean show_colour) +{ + boolean can_survive = false; + float init_needed = $monster[ninja snowman assassin].monster_initiative(); + init_needed = monster_initiative($monster[Ninja snowman assassin]); + + float damage_taken = calculateCurrentNinjaAssassinMaxDamage(); + float damage_taken_always = calculateCurrentNinjaAssassinMaxEnvironmentalDamage(); + + string result; + if (initiative_modifier() >= init_needed) + { + if (my_hp() >= ceil(damage_taken_always) + 2) + can_survive = true; + result += "Keep"; + } + else + result += "Need"; + result += " +" + ceil(init_needed) + "% init"; + + if (damage_taken_always > my_hp()) + result += "/" + ceil(damage_taken_always) + " HP"; + + result += " to survive ninja, or "; + + //FIXME warn about damage_taken_always WITH INIT + + int min_safe_damage = (ceil(damage_taken) + 2) + (ceil(damage_taken_always) + 2) ; + if (my_hp() >= min_safe_damage) + { + result += "keep"; + can_survive = true; + } + else + result += "need"; + result += " HP above " + min_safe_damage + "."; + + if (my_path().id == PATH_CLASS_ACT_2 && monster_level_adjustment() > 50) + { + result += " Reduce ML to +50 to prevent elemental damage."; + can_survive = false; + } + + if (!can_survive && show_colour) + result = HTMLGenerateSpanFont(result, "red"); + return result; +} + + +void CopiedMonstersGenerateDescriptionForMonster(string monster_name, string [int] description, boolean show_details, boolean from_copy) +{ + if (!__misc_state["in run"]) + return; + monster_name = monster_name.to_lower_case(); + if (monster_name == "ninja snowman assassin") + { + description.listAppend(generateNinjaSafetyGuide(show_details)); + int components_missing = $items[ninja rope,ninja carabiner,ninja crampons].items_missing().count(); + if (components_missing > 0) + description.listAppend("Need to fight " + components_missing.int_to_wordy() + " more."); + else + description.listAppend("Don't need to fight anymore."); + + if (from_copy && $familiar[obtuse angel].familiar_is_usable() && $familiar[reanimated reanimator].familiar_is_usable()) + { + string line = "Make sure to copy with angel, not the reanimator."; + if (my_familiar() == $familiar[reanimated reanimator]) + line = HTMLGenerateSpanFont(line, "red"); + description.listAppend(line); + } + } + else if (monster_name == "quantum mechanic") + { + string line; + boolean requirements_met = false; + if (item_drop_modifier_ignoring_plants() < 150.0) + line += "Need "; + else + { + line += "Keep "; + requirements_met = true; + } + line += "+150% item for large box"; + if (show_details && !requirements_met) + line = HTMLGenerateSpanFont(line, "red"); + description.listAppend(line); + } + else if ($strings[bricko bat,bricko cathedral,bricko elephant,bricko gargantuchicken,bricko octopus,bricko ooze,bricko oyster,bricko python,bricko turtle,bricko vacuum cleaner] contains monster_name) + { + description.listAppend("Zero adventure cost, use to burn delay."); + } + else if (monster_name == "lobsterfrogman" && show_details) + { + string line; + + if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) + { + int number_to_fight = clampi(5 - $item[barrel of gunpowder].available_amount(), 0, 5); + line += number_to_fight.int_to_wordy().capitaliseFirstLetter() + " more to defeat. "; + } + + int lfm_attack = $monster[lobsterfrogman].base_attack + 5.0; + string attack_text = lfm_attack + " attack."; + + if (my_buffedstat($stat[moxie]) < lfm_attack) + attack_text = HTMLGenerateSpanFont(attack_text, "red"); + + line += attack_text; + description.listAppend(line); + } + else if (monster_name == "big swarm of ghuol whelps" || monster_name == "swarm of ghuol whelps" || monster_name == "giant swarm of ghuol whelps") + { + float monster_level = monster_level_adjustment_ignoring_plants(); + + monster_level = MAX(monster_level, 0); + + float cranny_beep_beep_beep = MAX(3.0,sqrt(monster_level)); + description.listAppend("~" + cranny_beep_beep_beep.roundForOutput(1) + " cranny beeps."); + } + else if (monster_name == "writing desk") + { + /*if ($item[telegram from Lady Spookyraven].available_amount() > 0) + description.listAppend(HTMLGenerateSpanFont("Read the telegram from Lady Spookyraven first.", "red")); + int desks_remaining = clampi(5 - get_property_int("writingDesksDefeated"), 0, 5); + if (desks_remaining > 0 && !get_property_ascension("lastSecondFloorUnlock") && $item[Lady Spookyraven's necklace].available_amount() == 0 && get_property("questM20Necklace") != "finished" && mafiaIsPastRevision(15244)) + description.listAppend(pluraliseWordy(desks_remaining, "desk", "desks").capitaliseFirstLetter() + " remaining.");*/ + description.listAppend("This doesn't work anymore."); + + } + else if (monster_name == "skinflute" || monster_name == "camel's toe") + { + description.listAppend("Have " + pluralise($item[star]) + " and " + pluralise($item[line]) + "."); + if (item_drop_modifier_ignoring_plants() < 234.0) + description.listAppend(HTMLGenerateSpanFont("Need +234% item.", "red")); + } + else if (monster_name == "source agent") + { + if (monster_level_adjustment() > 0) + description.listAppend("Possibly remove +ML."); + string stat_description; + + if (get_property_int("sourceAgentsDefeated") > 0) + stat_description += pluralise(get_property_int("sourceAgentsDefeated"), "agent", "agents") + " defeated so far. "; + stat_description += $monster[Source Agent].base_attack + " attack."; + float our_init = initiative_modifier(); + if ($skill[Overclocked].have_skill()) + our_init += 200; + float agent_initiative = $monster[Source Agent].base_initiative; + float chance_to_get_jump = clampf(100 - agent_initiative + our_init, 0.0, 100.0); + boolean might_not_gain_init = false; + boolean avoid_displaying_init_otherwise = false; + if (my_thrall() == $thrall[spaghetti elemental] && my_thrall().level >= 5 && monster_level_adjustment() <= 150) + { + stat_description += "|Will effectively gain initiative on agent."; + if (!__iotms_usable[$item[source terminal]] || get_property_int("_sourceTerminalPortscanUses") >= 3) + avoid_displaying_init_otherwise = true; + } + if (avoid_displaying_init_otherwise) + { + } + else if (chance_to_get_jump >= 100.0) + stat_description += "|Will gain initiative on agent."; + else if (chance_to_get_jump <= 0.0) + { + stat_description += "|Will not gain initiative on agent. Need " + round(agent_initiative - our_init) + "% more init."; + might_not_gain_init = true; + } + else + { + stat_description += "|" + round(chance_to_get_jump) + "% chance to gain initiative on agent."; + might_not_gain_init = true; + } + if (might_not_gain_init) + { + if (my_class() == $class[pastamancer] && $skill[bind spaghetti elemental].have_skill() && my_thrall() != $thrall[spaghetti elemental]) + { + stat_description += " Or run "; + if ($thrall[spaghetti elemental].level < 5) + stat_description += "and level up "; + stat_description += "a spaghetti elemental to block the first attack."; + } + } + description.listAppend(stat_description); + if (__last_adventure_location == $location[the haunted bedroom]) + description.listAppend("Won't appear in the haunted bedroom, so may want to go somewhere else?"); + if ($skill[Humiliating Hack].have_skill()) + { + string [int] delevelers; + if ($skill[ruthless efficiency].have_skill() && $effect[ruthlessly efficient].have_effect() == 0) + { + delevelers.listAppend("cast ruthless efficiency"); + } + if ($item[dark porquoise ring].available_amount() > 0 && $item[dark porquoise ring].equipped_amount() == 0 && $item[dark porquoise ring].can_equip()) + { + delevelers.listAppend("equip dark porquoise ring"); + } + if (delevelers.count() > 0) + { + description.listAppend("Possibly " + delevelers.listJoinComponents(", ", "or") + " for better deleveling."); + } + } + } + + if (__misc_state["monsters can be nearly impossible to kill"] && monster_level_adjustment() > 0) + description.listAppend(HTMLGenerateSpanFont("Possibly remove +ML to survive. (at +" + monster_level_adjustment() + " ML)", "red")); +} + +void generateCopiedMonstersEntry(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, boolean from_task) //if from_task is false, assumed to be from resources +{ + string [int] description; + boolean very_important = false; + int show_up_in_tasks_turn_cutoff = 10; + string title = ""; + int min_turns_until = -1; + string url = ""; + if (get_property_boolean("dailyDungeonDone")) + url = $location[the daily dungeon].getClickableURLForLocation(); + Counter romantic_arrow_counter = CounterLookup("Romantic Monster", ErrorMake(), true); + if (false && (romantic_arrow_counter.CounterIsRange() || get_property_int("_romanticFightsLeft") > 0)) + { + Vec2i turn_range = romantic_arrow_counter.CounterGetWindowRange(); + + title = "Arrowed " + __misc_state_string["Romantic Monster Name"].to_lower_case() + " appears "; + + if (turn_range.y <= 0) + title += "now or soon"; + else if (turn_range.x <= 0) + title += "between now and " + turn_range.y + " turns."; + else + title += "in [" + turn_range.x + " to " + turn_range.y + "] turns."; + + min_turns_until = turn_range.x; + + int fights_left = get_property_int("_romanticFightsLeft"); + if (fights_left > 1) + { + string line = fights_left + " fights left"; + + Vec2i estimated_range = Vec2iMake(15 * (fights_left - 1), 25 * (fights_left - 1)); + estimated_range.x += turn_range.x; + estimated_range.y += turn_range.y; + + line += " over ~" + (estimated_range.x + estimated_range.y) / 2 + " turns."; + + description.listAppend(line); + } + else if (fights_left == 1) + description.listAppend("Last fight."); + + + + + if (turn_range.x <= 0) + very_important = true; + } + if (from_task && min_turns_until > show_up_in_tasks_turn_cutoff) + return; + if (!from_task && min_turns_until <= show_up_in_tasks_turn_cutoff) + return; + + if (title != "") + { + CopiedMonstersGenerateDescriptionForMonster(__misc_state_string["Romantic Monster Name"], description, very_important, false); + } + + if (title != "") + { + int importance = 4; + if (very_important) + importance = -11; + ChecklistEntry entry = ChecklistEntryMake(__misc_state_string["obtuse angel name"], url, ChecklistSubentryMake(title, "", description), importance); + entry.tags.id = "Angel copy monster old obsolete"; + if (very_important) + task_entries.listAppend(entry); + else + optional_task_entries.listAppend(entry); + + } +} + +void SCopiedMonstersGenerateResourceForCopyType(ChecklistEntry [int] resource_entries, item shaking_object, string shaking_shorthand_name, string monster_name_property_name) +{ + if (shaking_object.available_amount() == 0 && shaking_object != $item[none]) + return; + + string url = "inventory.php?ftext=" + shaking_object; + + string [int] monster_description; + string monster_name = get_property(monster_name_property_name).HTMLEscapeString(); + CopiedMonstersGenerateDescriptionForMonster(monster_name, monster_description, true, true); + + if (get_auto_attack() != 0) + { + url = "account.php?tab=combat"; + monster_description.listAppend("Auto attack is on, disable it?"); + } + + //string line = monster_name.capitaliseFirstLetter() + HTMLGenerateIndentedText(monster_description); + string line = HTMLGenerateSpanOfClass(monster_name.capitaliseFirstLetter(), "r_bold"); + + if (monster_description.count() > 0) + line += "
" + monster_description.listJoinComponents("|"); + + string image_name = "__item " + shaking_object; + if (shaking_shorthand_name == "chateau painting") + { + image_name = "__item fancy oil painting"; + url = "place.php?whichplace=chateau"; + } + + resource_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(shaking_shorthand_name.capitaliseFirstLetter() + " monster trapped!", "", line)).ChecklistEntrySetIDTag("Copy item " + shaking_shorthand_name)); +} + +void SCopiedMonstersGenerateResource(ChecklistEntry [int] resource_entries) +{ + //Sources: + + boolean have_spooky_putty = $items[Spooky Putty ball,Spooky Putty leotard,Spooky Putty mitre,Spooky Putty sheet,Spooky Putty snake,Spooky Putty monster].available_amount() > 0; + + int copies_used = get_property_int("spookyPuttyCopiesMade") + get_property_int("_raindohCopiesMade"); + int copies_available = MIN(6,5*MIN($items[Spooky Putty ball,Spooky Putty leotard,Spooky Putty mitre,Spooky Putty sheet,Spooky Putty snake,Spooky Putty monster].available_amount(), 1) + 5*MIN($item[Rain-Doh black box].available_amount() + $item[rain-doh box full of monster].available_amount(), 1)); + int copies_left = copies_available - copies_used; + + string [int] potential_copies; + if (!__misc_state["in CS aftercore"]) + { + //√ghuol whelps, √modern zmobies, √wine racks, √lobsterfrogmen, √ninja assassin + if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) + potential_copies.listAppend("Lobsterfrogman."); + if (__quest_state["Level 7"].state_boolean["cranny needs speed tricks"]) + potential_copies.listAppend("Swarm of ghuol whelps."); + if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"]) + potential_copies.listAppend("Modern zmobies."); + if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && $items[ninja rope,ninja carabiner,ninja crampons].available_amount() == 0 && !have_outfit_components("eXtreme Cold-Weather Gear")) + potential_copies.listAppend("Ninja assassin."); + //if (!__quest_state["Level 11"].finished && !__quest_state["Level 11 Palindome"].finished && $item[talisman o' namsilat].available_amount() == 0 && $items[gaudy key,snakehead charrrm].available_amount() < 2 && my_path().id != PATH_G_LOVER) + //potential_copies.listAppend("Gaudy pirate - copy once for extra key."); //now obsolete + //√baa'baa. astronomer? √nuns trick brigand + //FIXME astronomer when we can calculate that + //if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) + //potential_copies.listAppend("Brigand - nuns trick."); + //possibly less relevant: + //√ghosts/skulls/bloopers...? + //seems very marginal + //if (!__quest_state["Level 13"].state_boolean["past keys"] && ($item[digital key].available_amount() + creatable_amount($item[digital key])) == 0) + //potential_copies.listAppend("Ghosts/morbid skulls/bloopers, for digital key. (marginal?)"); + //bricko bats, if they have bricko...? + //if (__misc_state["bookshelf accessible"] && $skill[summon brickos].skill_is_usable()) + //potential_copies.listAppend("Bricko bats...?"); + } + ChecklistEntry copy_source_entry; + copy_source_entry.tags.id = "Copy options resource"; + + if ( __iotms_usable[$item[Chateau Mantegna room key]] && !get_property_boolean("_chateauMonsterFought") && mafiaIsPastRevision(15115)) + { + string url = "place.php?whichplace=chateau"; + string header = "Chateau painting copy"; + string [int] description; + monster current_monster = get_property_monster("chateauMonster"); + + if (current_monster == $monster[none]) + header += " available"; + else + header += " fightable"; + + if (__misc_state["in run"]) + { + if ($item[alpine watercolor set].available_amount() == 0) + description.listAppend("Acquire an alpine watercolor set to copy something else."); + else + description.listAppend("Copy something else with alpine watercolor set."); + /*string line; + if (current_monster == $monster[none]) + line += "Options:"; + else + line += "Other options:"; + + if ($item[alpine watercolor set].available_amount() == 0) + { + //url = "shop.php?whichshop=chateau"; + line += " (buy alpine watercolor set first)"; + } + else + line += " (copy with alpine watercolor set)"; + + line += "|*" + potential_copies.listJoinComponents("|*"); + description.listAppend(line);*/ + } + + if (current_monster != $monster[none]) + { + string [int] monster_description; + CopiedMonstersGenerateDescriptionForMonster(current_monster, monster_description, true, true); + string line = HTMLGenerateSpanOfClass("Currently have " + current_monster.to_string() + ".", "r_bold"); + if (monster_description.count() > 0) + line += "|*" + monster_description.listJoinComponents("|*"); + description.listPrepend(line); + } + //resource_entries.listAppend(ChecklistEntryMake("__item fancy oil painting", url, ChecklistSubentryMake(header, "", description))); + + + copy_source_entry.subentries.listAppend(ChecklistSubentryMake(header, "", description)); + if (copy_source_entry.image_lookup_name == "") + copy_source_entry.image_lookup_name = "__item fancy oil painting"; + if (copy_source_entry.url == "") + copy_source_entry.url = "place.php?whichplace=chateau"; + } + if (copies_left > 0) + { + string [int] copy_source_list; + if (have_spooky_putty) + copy_source_list.listAppend("spooky putty"); + if ($item[Rain-Doh black box].available_amount() + $item[rain-doh box full of monster].available_amount() > 0) + copy_source_list.listAppend("rain-doh black box"); + + string copy_sources = copy_source_list.listJoinComponents("/"); + string name = ""; + //FIXME make this possibly say which one in the case of 6 (does that matter? how does that mechanic work?) + name = pluralise(copies_left, copy_sources + " copy", copy_sources + " copies") + " left"; + string [int] description;// = potential_copies; + + //resource_entries.listAppend(ChecklistEntryMake(copy_source_list[0], "", ChecklistSubentryMake(name, "", description))); + + copy_source_entry.subentries.listAppend(ChecklistSubentryMake(name, "", description)); + if (copy_source_entry.image_lookup_name == "") + copy_source_entry.image_lookup_name = copy_source_list[0]; + } + + if (!get_property_boolean("_cameraUsed") && (get_property("cameraMonster") == "") && $item[4-d camera].available_amount() > 0) + { + //resource_entries.listAppend(ChecklistEntryMake("__item 4-d camera", "", ChecklistSubentryMake("4-d camera copy available", "", potential_copies))); + + copy_source_entry.subentries.listAppend(ChecklistSubentryMake("4-d camera copy available", "", "")); + if (copy_source_entry.image_lookup_name == "") + copy_source_entry.image_lookup_name = "__item 4-d camera"; + } + if (!get_property_boolean("_iceSculptureUsed") && $item[unfinished ice sculpture].available_amount() > 0) + { + //resource_entries.listAppend(ChecklistEntryMake("__item unfinished ice sculpture", "", ChecklistSubentryMake("Ice sculpture copy available", "", potential_copies))); + + copy_source_entry.subentries.listAppend(ChecklistSubentryMake("Ice sculpture copy available", "", "")); + if (copy_source_entry.image_lookup_name == "") + copy_source_entry.image_lookup_name = "__item unfinished ice sculpture"; + } + if ($item[sticky clay homunculus].available_amount() > 0) + { + //resource_entries.listAppend(ChecklistEntryMake("__item sticky clay homunculus", "", ChecklistSubentryMake(pluralise($item[sticky clay homunculus].available_amount(), "sticky clay copy", "sticky clay copies") + " available", "", "Unlimited/day."))); + + copy_source_entry.subentries.listAppend(ChecklistSubentryMake(pluralise($item[sticky clay homunculus].available_amount(), "sticky clay copy", "sticky clay copies") + " available", "", "Unlimited/day.")); + if (copy_source_entry.image_lookup_name == "") + copy_source_entry.image_lookup_name = "__item sticky clay homunculus"; + } + if ($item[print screen button].available_amount() > 0) + { + copy_source_entry.subentries.listAppend(ChecklistSubentryMake(pluralise($item[print screen button].available_amount(), "print screen copy", "print screen copies") + " available", "", "")); + if (copy_source_entry.image_lookup_name == "") + copy_source_entry.image_lookup_name = "__item print screen button"; + } + if ($item[LOV Enamorang].available_amount() > 0) + { + copy_source_entry.subentries.listAppend(ChecklistSubentryMake(pluralise($item[LOV Enamorang]), "", "")); + if (copy_source_entry.image_lookup_name == "") + copy_source_entry.image_lookup_name = "__item lov enamorang"; + } + if (!get_property_boolean("_crappyCameraUsed") && $item[crappy camera].available_amount() > 0) + { + string [int] description;// = listCopy(potential_copies); + description.listPrepend("50% success rate"); + //resource_entries.listAppend(ChecklistEntryMake("__item crappy camera", "", ChecklistSubentryMake("Crappy camera copy available", "", description))); + + + copy_source_entry.subentries.listAppend(ChecklistSubentryMake("Crappy camera copy available", "", description)); + if (copy_source_entry.image_lookup_name == "") + copy_source_entry.image_lookup_name = "__item crappy camera"; + } + if (copy_source_entry.subentries.count() > 0) + { + ChecklistSubentry last_subentry = copy_source_entry.subentries[copy_source_entry.subentries.count() - 1]; + if (last_subentry.entries.count() > 0 && potential_copies.count() > 0) + { + copy_source_entry.subentries.listAppend(ChecklistSubentryMake("Potential targets:", "", potential_copies)); + } + else + last_subentry.entries.listAppendList(potential_copies); + resource_entries.listAppend(copy_source_entry); + } + + //Copies made: + + + generateCopiedMonstersEntry(resource_entries, resource_entries, false); + SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[Rain-Doh box full of monster], "rain doh", "rainDohMonster"); + SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[spooky putty monster], "spooky putty", "spookyPuttyMonster"); + if (!get_property_boolean("_cameraUsed")) + SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[shaking 4-d camera], "shaking 4-d camera", "cameraMonster"); + if (!get_property_boolean("_crappyCameraUsed")) + SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[shaking crappy camera], "shaking crappy camera", "crappyCameraMonster"); + if (!get_property_boolean("_photocopyUsed")) + SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[photocopied monster], "photocopied", "photocopyMonster"); + if (!get_property_boolean("_envyfishEggUsed")) + SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[envyfish egg], "envyfish egg", "envyfishMonster"); + if (!get_property_boolean("_iceSculptureUsed")) + SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[ice sculpture], "ice sculpture", "iceSculptureMonster"); + SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[screencapped monster], "screencapped", "screencappedMonster"); + + //if (__misc_state["Chateau Mantegna available"] && !get_property_boolean("_chateauMonsterFought") && mafiaIsPastRevision(15115)) + //SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[none], "chateau painting", "chateauMonster"); + + SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[wax bugbear], "wax bugbear", "waxMonster"); + SCopiedMonstersGenerateResourceForCopyType(resource_entries, $item[crude monster sculpture], "crude sculpture", "crudeMonster"); +} + +void SCopiedMonstersGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + generateCopiedMonstersEntry(task_entries, optional_task_entries, true); + +} + +//A quaint and curious import. + +void QLevel8Init() +{ + //questL08Trapper + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL08Trapper"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Trapper Quest"; + state.image_name = "trapper"; + state.council_quest = true; + + if (get_property("peteMotorbikeTires") == "Snow Tires" && state.started && !state.finished && state.mafia_internal_step < 4) //sort of hacky - they're not actually there, but... + { + state.mafia_internal_step = 4; + } + + + if (state.mafia_internal_step > 2) + state.state_boolean["Past mine"] = true; + if (state.mafia_internal_step > 3) + state.state_boolean["Mountain climbed"] = true; + if (state.mafia_internal_step > 5) + state.state_boolean["Groar defeated"] = true; + + state.state_string["ore needed"] = get_property("trapperOre").HTMLEscapeString(); + + if (my_level() >= 8 || my_path().id == PATH_EXPLOSIONS) + state.startable = true; + + __quest_state["Level 8"] = state; + __quest_state["Trapper"] = state; +} + + +void QLevel8GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 8"].in_progress) + return; + QuestState base_quest_state = __quest_state["Level 8"]; + string image_name = base_quest_state.image_name; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + string url = "place.php?whichplace=mclargehuge"; + string talk_to_trapper_string = "Go talk to the trapper."; + + float cold_resistance = numeric_modifier("cold resistance"); + string need_cold_res_string = "acquire " + (5.0 - cold_resistance).to_int() + " more " + HTMLGenerateSpanOfClass("cold resistance", "r_element_cold"); + + if (base_quest_state.mafia_internal_step == 1) + { + subentry.entries.listAppend(talk_to_trapper_string); + } + else if (!base_quest_state.state_boolean["Past mine"]) + { + string cheese_header; //string cheese + string [int] cheese_lines; + + cheese_header = MIN(3, $item[goat cheese].available_amount()) + "/3 goat cheese found"; + if ($item[goat cheese].available_amount() <3 ) + cheese_header += " (40% drop)"; + + boolean need_cheese = $item[goat cheese].available_amount() <3; + + if (need_cheese) + { + subentry.modifiers.listAppend("150% item"); + if (__misc_state["have olfaction equivalent"]) + subentry.modifiers.listAppend("olfact dairy goats"); + + + if ($skill[Advanced Saucecrafting].skill_is_usable() && fullness_limit() > 0 && __misc_state["can eat just about anything"] && my_path().id != PATH_SLOW_AND_STEADY) + cheese_lines.listAppend("Have " + pluralise($item[glass of goat\'s milk]) + " for magnesium (20% drop)"); + } + + subentry.entries.listAppend(cheese_header + HTMLGenerateIndentedText(cheese_lines)); + + + + string ore_header; + string [int] ore_lines; + item ore_needed = to_item(base_quest_state.state_string["ore needed"]); + + ore_header = MIN(3, ore_needed.available_amount()) + "/3 " + ore_needed + " found"; + + boolean need_ore = ore_needed.available_amount() <3; + if (need_ore) + { + string [int] potential_ore_sources; + potential_ore_sources.listAppend("Mining"); + if (!in_bad_moon()) + potential_ore_sources.listAppend("Clovering itznotyerzitzmine (one of each ore, consider if zap available?)"); + + + + boolean need_outfit = true; + if (have_outfit_components("Mining Gear")) + need_outfit = false; + if (my_path().id == PATH_AVATAR_OF_BORIS) + { + subentry.modifiers.listAppend("+150%/+1000% item"); + need_outfit = false; + potential_ore_sources.listClear(); + potential_ore_sources.listAppend("Fight mountain men in the mine (40%, 10% drop for each ore)"); + } + if (my_path().id == PATH_WAY_OF_THE_SURPRISING_FIST) + { + string have_skill_text = ""; + if (!skill_is_usable($skill[worldpunch])) + have_skill_text = " (you do not have this skill yet)"; + potential_ore_sources.listAppend("Earthen Fist will allow mining." + have_skill_text); + need_outfit = false; + } + // changed this to remove an is_unrestricted check; i think this still should work without it? + if (__iotms_usable[$item[Deck of Every Card]]) + potential_ore_sources.listAppend("Deck of Every Card - Mine card"); + ore_lines.listAppend("Potential sources of ore:" + HTMLGenerateIndentedText(potential_ore_sources)); + if (skill_is_usable($skill[unaccompanied miner])) + ore_lines.listAppend("You can free mine. Consider splitting mining over several days for zero-adventure cost."); + if (need_outfit) + { + subentry.modifiers.listAppend("-combat"); + if ($familiar[slimeling].familiar_is_usable()) + subentry.modifiers.listAppend("slimeling?"); + ore_lines.listAppend("Mining outfit not available. Consider acquiring one via -combat in mine"); + } + if (is_wearing_outfit("Mining Gear")) + { + url = "mining.php?mine=1"; + } + + } + subentry.entries.listAppend(ore_header + HTMLGenerateIndentedText(ore_lines)); + + if (!need_cheese && !need_ore) + { + subentry.entries.listClear(); + subentry.entries.listAppend(talk_to_trapper_string); + + } + } + else if (!base_quest_state.state_boolean["Mountain climbed"]) + { + //ninja: + string ninja_line; + boolean ninja_finishes_quest = false; + if (true) + { + string [int] ninja_path; + string [int] ninja_modifiers; + + item [int] items_needed; + if ($item[ninja rope].available_amount() == 0) items_needed.listAppend($item[ninja rope]); + if ($item[ninja crampons].available_amount() == 0) items_needed.listAppend($item[ninja crampons]); + if ($item[ninja carabiner].available_amount() == 0) items_needed.listAppend($item[ninja carabiner]); + + if (items_needed.count() == 0) + { + if (cold_resistance < 5.0) + ninja_path.listAppend(need_cold_res_string.capitaliseFirstLetter() + "."); + + ninja_path.listAppend("Climb the peak."); + ninja_finishes_quest = true; + } + else + { + ninja_path.listAppend("Need " + items_needed.listJoinComponents(", ", "and") + "."); + string [int] assassin_description; + + if (get_property_int("_romanticFightsLeft") > 0 && get_property_int("_romanticFightsLeft") >= items_needed.count() && get_property("romanticTarget") == "ninja snowman assassin") + { + ninja_path.listAppend("They will find you."); + } + else + { + ninja_modifiers.listAppend("+combat"); + ninja_path.listAppend("Run +combat in Lair of the Ninja Snowmen, fight assassins."); + CopiedMonstersGenerateDescriptionForMonster("ninja snowman assassin", assassin_description, true, false); + if (combat_rate_modifier() <= 0.0) + ninja_path.listAppend("Need more +combat, assassins won't appear at " + combat_rate_modifier().floor() + "% combat."); + else + { + int turns_spent = $location[lair of the ninja snowmen].turns_spent; + if (turns_spent != -1) + { + float chance = combat_rate_modifier() / 200.0 + turns_spent * 0.015; + if (turns_spent == 10 || turns_spent == 20 || turns_spent == 30 || chance >= 1.0) + ninja_path.listAppend("Assassin will appear next turn."); + else + ninja_path.listAppend((chance * 100.0).roundForOutput(0) + "% chance of assassins."); + } + } + + if (__quest_state["Level 11 Shen"].state_int.getFutureShenAssignments().listInvert() contains $location[Lair of the Ninja Snowmen]) + subentry.entries.listAppend("Could wait before going there? Shen will send you to the Ninja Lair later."); + } + ninja_path.listAppend(generateNinjaSafetyGuide(true)); + } + + ninja_line = "Ninja path:"; + + if (ninja_modifiers.count() > 0) + ninja_line += "|*" + ChecklistGenerateModifierSpan(ninja_modifiers) + "|"; + ninja_line += HTMLGenerateIndentedText(ninja_path.listJoinComponents("
")); + + if (ninja_finishes_quest) + ninja_line = ninja_path.listJoinComponents("
"); + } + //eXtreme outfit: + string extreme_line; + if (true) + { + string [int] extreme_path; + string [int] extreme_modifiers; + + + + item [int] items_needed = missing_outfit_components("eXtreme Cold-Weather Gear"); + + if (items_needed.count() == 0) + { + string [int] things_to_do; + if (!is_wearing_outfit("eXtreme Cold-Weather Gear")) + things_to_do.listAppend("wear eXtreme Cold-Weather Gear"); + + if (!$location[the extreme slope].noncombat_queue.contains_text("3 eXXXtreme 4ever 6pack")) + { + things_to_do.listAppend("run -combat"); + things_to_do.listAppend("become eXtreme"); + extreme_modifiers.listAppend("-combat"); + } + things_to_do.listAppend("jump onto the mountain top"); + extreme_path.listAppend(things_to_do.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + } + else + { + extreme_path.listAppend("Acquire outfit components: " + items_needed.listJoinComponents(", ", "and") + "."); + extreme_modifiers.listAppend("-combat"); + extreme_modifiers.listAppend("+item"); + if ($familiar[slimeling].familiar_is_usable()) + extreme_modifiers.listAppend("slimeling?"); + extreme_path.listAppend("Run -combat and maybe +item on the eXtreme slope."); + } + + extreme_line = "Extreme path:"; + + if (extreme_modifiers.count() > 0) + extreme_line += "|*" + ChecklistGenerateModifierSpan(extreme_modifiers) + "|"; + extreme_line += HTMLGenerateIndentedText(extreme_path.listJoinComponents("
")); + + } + if (!ninja_finishes_quest) + subentry.entries.listAppend("Find a way to climb the peak."); + subentry.entries.listAppend(ninja_line); + if (!ninja_finishes_quest) //ninja need not tricks + subentry.entries.listAppend(extreme_line); + } + else if (!base_quest_state.state_boolean["Groar defeated"]) + { + int turns_remaining = MAX(0, 4 - $location[mist-shrouded peak].turnsAttemptedInLocation()); + + if (get_property("peteMotorbikeTires") == "Snow Tires") + turns_remaining = 1; + + string [int] todo; + if (cold_resistance < 5.0) + todo.listAppend(need_cold_res_string); + + + float groar_attack = (120 + monster_level_adjustment()); + + string line = "fight Groar at the peak"; + if (my_basestat($stat[moxie]) < groar_attack) + line += " (attack: " + groar_attack.round() + ")"; + + todo.listAppend(line); + subentry.entries.listAppend(todo.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + + if (turns_remaining > 1) + { + subentry.modifiers.listAppend("+meat"); + subentry.entries.listAppend("Optionally run +meat for " + pluraliseWordy((turns_remaining - 1), "turn", "turns") + ". (200 base meat drop)"); + } + + image_name = "Yeti"; + } + else + { + subentry.entries.listAppend(talk_to_trapper_string); + } + + + + task_entries.listAppend(ChecklistEntryMake(image_name, url, subentry, $locations[itznotyerzitz mine,the goatlet, lair of the ninja snowmen, the extreme slope,mist-shrouded peak, itznotyerzitz mine (in disguise)]).ChecklistEntrySetIDTag("Council L8 trapper quest")); +} + + +void QLevel9Init() +{ + //questL09Topping + //oilPeakProgress + //twinPeakProgress + //booPeakProgress + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL09Topping"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can do quest in GG + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Highland Lord Quest"; + state.image_name = "orc chasm"; + state.council_quest = true; + + //Recorded in-run: + //twinPeakProgress(user, now '1', default 0) - +stench one done + //twinPeakProgress(user, now '3', default 0) - +stench, +item ones done + //twinPeakProgress(user, now '7', default 0) - +stench, +item, jar ones done + //twinPeakProgress(user, now '15', default 0) - finished + //twinPeakProgress(user, now '3', default 0) -> item done, stench done, jar not done, init not done, quest started + + if (state.mafia_internal_step > 1) + { + state.state_boolean["bridge complete"] = true; + } + else + { + int bridge_progress = get_property_int("chasmBridgeProgress"); + int fasteners_have = bridge_progress + $item[thick caulk].available_amount() + $item[long hard screw].available_amount() + $item[messy butt joint].available_amount() + 5 * $item[smut orc keepsake box].usable_amount() + 5 * $item[snow boards].usable_amount(); + int lumber_have = bridge_progress + $item[morningwood plank].available_amount() + $item[raging hardwood plank].available_amount() + $item[weirdwood plank].available_amount() + 5 * $item[smut orc keepsake box].usable_amount() + 5 * $item[snow boards].usable_amount(); + if (my_path().id == PATH_LICENSE_TO_ADVENTURE && get_property_boolean("bondBridge")) + { + fasteners_have += 15; + lumber_have += 15; + } + + int fasteners_needed = MAX(0, 30 - fasteners_have); + int lumber_needed = MAX(0, 30 - lumber_have); + + state.state_int["bridge fasteners needed"] = fasteners_needed; + state.state_int["bridge lumber needed"] = lumber_needed; + } + + if (my_level() >= 9 || my_path().id == PATH_EXPLOSIONS) + state.startable = true; + + + state.state_boolean["can complete twin peaks quest quickly"] = true; + + if (my_path().id == PATH_BEES_HATE_YOU) + state.state_boolean["can complete twin peaks quest quickly"] = false; + + state.state_float["oil peak pressure"] = get_property_float("oilPeakProgress"); + if ($location[oil peak].noncombat_queue.contains_text("Unimpressed with Pressure")) + state.state_float["oil peak pressure"] = 0.0; + state.state_int["twin peak progress"] = get_property_int("twinPeakProgress"); + state.state_int["a-boo peak hauntedness"] = get_property_int("booPeakProgress"); + if ($location[a-boo peak].noncombat_queue.contains_text("Come On Ghosty, Light My Pyre")) + state.state_int["a-boo peak hauntedness"] = 0; + + + if (!state.state_boolean["bridge complete"]) //haven't gotten over there yet. not sure what mafia says at this point, so set some defaults: + { + state.state_int["twin peak progress"] = 0; + state.state_float["oil peak pressure"] = 310.66; + state.state_int["a-boo peak hauntedness"] = 100; + } + if (state.finished) + { + state.state_boolean["bridge complete"] = true; + + state.state_int["twin peak progress"] = 15; + state.state_float["oil peak pressure"] = 0.0; + state.state_int["a-boo peak hauntedness"] = 0; + } + + if (state.state_float["oil peak pressure"] > 500.0) //not sure what causes this. detecting this situation + { + state.state_float["oil peak pressure"] = 310.66; + state.state_boolean["oil peak pressure bug in effect"] = true; + } + + + int twin_progress = state.state_int["twin peak progress"]; + + state.state_boolean["Peak Stench Completed"] = (twin_progress & 1) > 0; + state.state_boolean["Peak Item Completed"] = (twin_progress & 2) > 0; + state.state_boolean["Peak Jar Completed"] = (twin_progress & 4) > 0; + state.state_boolean["Peak Init Completed"] = (twin_progress & 8) > 0; + + state.state_int["peak tests remaining"] = 0; + foreach s in $strings[Peak Stench Completed,Peak Item Completed,Peak Jar Completed,Peak Init Completed] + { + if (!state.state_boolean[s]) + state.state_int["peak tests remaining"] += 1; + } + + __quest_state["Level 9"] = state; + __quest_state["Highland Lord"] = state; +} + +void QLevel9GenerateTasksSidequests(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Level 9"]; + + if (base_quest_state.state_int["a-boo peak hauntedness"] > 0) + { + boolean should_delay = false; + string [int] details; + string [int] modifiers; + int clues_needed = ceil(MIN(base_quest_state.state_int["a-boo peak hauntedness"], 90).to_float() / 30.0); + + if (true) + { + int clues_remaining = MAX(0, clues_needed - $item[a-boo clue].available_amount()); + string [int] tasks; + if (base_quest_state.state_int["a-boo peak hauntedness"] > 90) + tasks.listAppend("get down to 90% hauntedness"); + if (clues_remaining > 0) + tasks.listAppend("collect " + clues_remaining.int_to_wordy() + " a-boo clues"); + tasks.listAppend("use/survive each clue to finish quest.|May want to consider delaying until end of the run"); + details.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + } + + modifiers.listAppend("+567% item"); + details.listAppend(base_quest_state.state_int["a-boo peak hauntedness"] + "% hauntedness."); + + float item_drop_multiplier = (100.0 + $location[a-boo peak].item_drop_modifier_for_location())/100.0; + + if (true) + { + string line = "Have " + pluralise(lookupItems("a-boo clue,glued a-boo clue").available_amount(), $item[a-boo clue]) + "."; + + float clue_drop_rate = clampf(item_drop_multiplier * 0.15, 0.0, 1.0); + line += " " + clue_drop_rate.roundForOutput(2) + " clues/adventure at +" + ((item_drop_multiplier - 1) * 100.0).roundForOutput(1) + "% item."; + + details.listAppend(line); + } + + + if (base_quest_state.state_int["a-boo peak hauntedness"] <= 90 && __misc_state["can use clovers"] && $item[a-boo clue].available_amount() < clues_needed) + { + details.listAppend("Can clover for two A-Boo clues."); + } + + + + + int spooky_damage_taken_cumulative = 0; + int cold_damage_taken_cumulative = 0; + + int [int] spooky_damage_levels; + int [int] cold_damage_levels; + + int [int] damage_levels = listMake(13, 25, 50, 125, 250); + + foreach key in damage_levels + { + int damage = damage_levels[key]; + if ($item[glass pie plate].equipped_amount() > 0) + damage /= 2; + + int spooky_damage_at_level = damageTakenByElement(damage, $element[spooky]); + int cold_damage_at_level = damageTakenByElement(damage, $element[cold]); + + spooky_damage_taken_cumulative += spooky_damage_at_level; + cold_damage_taken_cumulative += cold_damage_at_level; + + spooky_damage_levels.listAppend(spooky_damage_taken_cumulative); + cold_damage_levels.listAppend(cold_damage_taken_cumulative); + } + + boolean can_survive_clues_now = false; + if (true) + { + string line; + + int hp_damage_taken = spooky_damage_levels[4] + cold_damage_levels[4] + 2; + string hp_string = hp_damage_taken + " HP"; + if (hp_damage_taken >= my_hp()) + hp_string = HTMLGenerateSpanFont(hp_string, "red"); + + if (hp_damage_taken <= my_maxhp()) + can_survive_clues_now = true; + line = "Need " + hp_string + " (" + HTMLGenerateSpanOfClass(spooky_damage_levels[4] + " spooky", "r_element_spooky") + ", " + HTMLGenerateSpanOfClass(cold_damage_levels[4] + " cold", "r_element_cold") + ") to survive 30% effective A-Boo clues."; + if (hp_damage_taken >= my_hp()) + { + hp_damage_taken = spooky_damage_levels[3] + cold_damage_levels[3] + 2; + string hp_string = hp_damage_taken + " HP"; + if (hp_damage_taken >= my_hp()) + hp_string = HTMLGenerateSpanFont(hp_string, "red"); + + line += "|Or "; + line += hp_string; + line += " to survive 22% effectiveness clues."; + } + if ($item[glass pie plate].available_amount() > 0 && $item[glass pie plate].can_equip() && $item[glass pie plate].equipped_amount() == 0) + line += "|Equip the glass pie plate for half damage."; + + details.listAppend(line); + } + + if (!black_market_available() && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST && my_path().id != PATH_NUCLEAR_AUTUMN) + { + details.listAppend("Possibly unlock the black market first, for cans of black paint. (+2 " + HTMLGenerateSpanOfClass("spooky", "r_element_spooky") + "/" + HTMLGenerateSpanOfClass("cold", "r_element_cold") + " res buff, 1k meat)"); + } + if ($item[a-boo clue].available_amount() * 30 >= base_quest_state.state_int["a-boo peak hauntedness"] && my_level() < 13) //wait for later + should_delay = true; + if (can_survive_clues_now) + should_delay = false; + + ChecklistEntry checklist_entry = ChecklistEntryMake("a-boo peak", "place.php?whichplace=highlands", ChecklistSubentryMake("A-Boo Peak", modifiers, details), $locations[a-boo peak]); + checklist_entry.tags.id = "Council L9 quest a-boo peak progress"; + if (should_delay) + { + checklist_entry.importance_level = 11; + future_task_entries.listAppend(checklist_entry); + } + else + task_entries.listAppend(checklist_entry); + } + else if (!$location[a-boo peak].noncombat_queue.contains_text("Come On Ghosty, Light My Pyre")) + { + string [int] details; + string [int] modifiers; + + details.listAppend("Light the fire!"); + + ChecklistEntry checklist_entry = ChecklistEntryMake("a-boo peak", "place.php?whichplace=highlands", ChecklistSubentryMake("A-Boo Peak", modifiers, details), $locations[a-boo peak]); + checklist_entry.tags.id = "Council L9 quest a-boo peak done"; + task_entries.listAppend(checklist_entry); + } + if (base_quest_state.state_int["twin peak progress"] < 15) + { + string [int] details; + string [int] modifiers; + string url = "place.php?whichplace=highlands"; + + if (base_quest_state.state_boolean["can complete twin peaks quest quickly"]) + { + int progress = base_quest_state.state_int["twin peak progress"]; + + boolean stench_completed = base_quest_state.state_boolean["Peak Stench Completed"]; + boolean item_completed = base_quest_state.state_boolean["Peak Item Completed"]; + boolean jar_completed = base_quest_state.state_boolean["Peak Jar Completed"]; + boolean init_completed = base_quest_state.state_boolean["Peak Init Completed"]; + + boolean can_complete_stench = false; + boolean can_complete_item = false; + boolean can_complete_jar = false; + boolean can_complete_init = false; + + boolean have_at_least_one_usable_option = false; + + + if (!stench_completed && numeric_modifier("stench resistance") >= 4.0) + can_complete_stench = true; + if (!item_completed) + { + int effective_familiar_weight = my_familiar().familiar_weight() + numeric_modifier("familiar weight"); + + int familiar_weight_from_familiar_equipment = $slot[familiar].equipped_item().numeric_modifier("familiar weight"); //need to cancel it out + + float familiar_item_drop = my_familiar().numeric_modifier("item drop", effective_familiar_weight - familiar_weight_from_familiar_equipment, $slot[familiar].equipped_item()); + //FIXME implement item_drop_modifier_for_location (friars does not count for this test, so maybe item_drop_modifier_ignoring_plants()) + float effective_non_familiar_item = $location[twin peak].item_drop_modifier_for_location() - familiar_item_drop + numeric_modifier("food drop"); + if (effective_non_familiar_item >= 50.0) + can_complete_item = true; + } + if (!jar_completed && $item[jar of oil].available_amount() > 0) + can_complete_jar = true; + if (!init_completed && (stench_completed && item_completed && jar_completed) && initiative_modifier() >= 40) + can_complete_init = true; + + if (can_complete_stench || can_complete_item || can_complete_jar || can_complete_init) + have_at_least_one_usable_option = true; + + if (!have_at_least_one_usable_option) + details.listAppend(HTMLGenerateSpanFont("Avoid adventuring in area until requirements met.", "red")); + + string [int] options_left; + + if (!stench_completed) + { + string line = "investigate room 37"; + if (options_left.count() == 0) + line = line.capitaliseFirstLetter(); //have to pre-capitalise because of possible HTML later + if (!can_complete_stench) + line = HTMLGenerateSpanFont(line, "gray"); + options_left.listAppend(line); + } + if (!item_completed) + { + string line = "search the pantry"; + if (options_left.count() == 0) + line = line.capitaliseFirstLetter(); + if (!can_complete_item) + line = HTMLGenerateSpanFont(line, "gray"); + options_left.listAppend(line); + } + if (!jar_completed) + { + string line = "follow the faint sound of music"; + if (options_left.count() == 0) + line = line.capitaliseFirstLetter(); + if (!can_complete_jar) + line = HTMLGenerateSpanFont(line, "gray"); + options_left.listAppend(line); + } + if (!init_completed) + { + string line = "you"; + if (options_left.count() == 0) + line = line.capitaliseFirstLetter(); + if (!can_complete_init) + line = HTMLGenerateSpanFont(line, "gray"); + options_left.listAppend(line); + } + + details.listAppend(options_left.listJoinComponents(", ", "and") + "."); + + boolean can_complete_using_trimmers = false; + if ($item[rusty hedge trimmers].available_amount() >= options_left.count()) //purely trimmers, now + { + can_complete_using_trimmers = true; + if (have_at_least_one_usable_option) + url = "inventory.php?ftext=rusty+hedge+trimmers"; + } + if (numeric_modifier("stench resistance") < 4.0 && !stench_completed) + { + details.listAppend("+" + (4.0 - numeric_modifier("stench resistance")).floor() + " more " + HTMLGenerateSpanOfClass("stench", "r_element_stench") + " resist required."); + } + if (!can_complete_using_trimmers) + { + modifiers.listAppend("-combat"); + modifiers.listAppend("+item"); + modifiers.listAppend("olfact a topiary animal"); + } + + if (!item_completed && !can_complete_item) + { + details.listAppend("+50% non-familiar item required. (+food works)"); + } + + if ($item[jar of oil].available_amount() == 0 && !jar_completed) + { + string line = HTMLGenerateSpanFont("Jar of oil required", "red") + "."; + if ($item[bubblin\' crude].available_amount() >= 12) + line += " Can make by multi-using 12 bubblin' crude."; + else + line += " Visit oil peak for bubblin' crude."; + details.listAppend(line); + } + if (initiative_modifier() < 40.0 && !init_completed) + { + string line = "+40% init required."; + if (options_left.count() > 1) + line = "+40% init will be required later."; + if ($familiar[oily woim].familiar_is_usable() && !($familiars[oily woim,happy medium] contains my_familiar())) + { + if (!(my_familiar() == $familiar[Xiblaxian Holo-Companion] && my_familiar() != $familiar[none])) + line += "|Run " + $familiar[oily woim] + " for +init."; + } + details.listAppend(line); + } + + if ($item[rusty hedge trimmers].available_amount() > 0) + { + if (!have_at_least_one_usable_option) + details.listAppend("Have " + pluraliseWordy(MIN(options_left.count(), $item[rusty hedge trimmers].available_amount()), $item[rusty hedge trimmers]) + "."); + else if ($item[rusty hedge trimmers].available_amount() > 1) + details.listAppend("Use " + pluraliseWordy(MIN(options_left.count(), $item[rusty hedge trimmers].available_amount()), $item[rusty hedge trimmers]) + "."); + else + details.listAppend("Use rusty hedge trimmers."); + } + + int ncs_need_to_visit_by_hand = MAX(0, options_left.count() - $item[rusty hedge trimmers].available_amount()); + int ncs_need_to_visit_with_hedge = options_left.count() - ncs_need_to_visit_by_hand; + if (have_at_least_one_usable_option && !can_complete_using_trimmers) + details.listAppend(generateTurnsToSeeNoncombat(80, ncs_need_to_visit_by_hand, "", 0, ncs_need_to_visit_with_hedge)); + + + } + else + { + details.listAppend("Spend 50 total turns in the twin peak."); + } + task_entries.listAppend(ChecklistEntryMake("twin peak", url, ChecklistSubentryMake("Twin Peak", modifiers, details), $locations[twin peak]).ChecklistEntrySetIDTag("Council L9 quest twin peak")); + } + boolean need_jar_of_oil = false; + if ($item[jar of oil].available_amount() == 0 && $item[bubblin\' crude].available_amount() < 12 && !base_quest_state.state_boolean["Peak Jar Completed"] && base_quest_state.state_boolean["can complete twin peaks quest quickly"]) + need_jar_of_oil = true; + + if (base_quest_state.state_float["oil peak pressure"] > 0.0 || need_jar_of_oil) + { + string [int] details; + string [int] modifiers; + + int oil_ml = monster_level_adjustment_for_location($location[oil peak]); + + if (my_path().id == PATH_HEAVY_RAINS) + { + //heavy rains ML doesn't affect which oil monster you get; cancel out the rain effect: + //int inherent_ml_reduction = monster_level_adjustment() - numeric_modifier("Monster Level"); + //oil_ml -= inherent_ml_reduction; + //FIXME this is complicated + } + + int turns_remaining_at_current_ml = 0; + if (base_quest_state.state_float["oil peak pressure"] > 0.0) + { + modifiers.listAppend("+100 ML"); + + + string line = "Run +" + HTMLGenerateSpanFont("20/50", "", "0.8em") + "/100 ML (at "; + string adjustment = (oil_ml > 0 ? "+" : "") + oil_ml + " ML"; + if (oil_ml < 100) + adjustment = HTMLGenerateSpanFont(adjustment, "red"); + adjustment += ")"; + details.listAppend(line + adjustment); + + + float pressure_reduced_per_turn = 0.0; + if ($item[dress pants].available_amount() > 0) + { + if ($item[dress pants].equipped_amount() > 0) + { + pressure_reduced_per_turn += 6.34; + } + else + { + if (oil_ml < 100) //only worth it <100 usually + details.listAppend("Wear dress pants."); + } + } + if (oil_ml >= 100) + pressure_reduced_per_turn += 63.4; + else if (oil_ml >= 50) + pressure_reduced_per_turn += 31.7; + else if (oil_ml >= 20) + pressure_reduced_per_turn += 19.02; + else + pressure_reduced_per_turn += 6.34; + + if (fabs(pressure_reduced_per_turn) > 0.01) + turns_remaining_at_current_ml = ceil(base_quest_state.state_float["oil peak pressure"] / pressure_reduced_per_turn); + + string line2 = pluralise(turns_remaining_at_current_ml, "turn", "turns") + " remaining at " + oil_ml + " ML."; + if (base_quest_state.state_boolean["oil peak pressure bug in effect"]) + line2 = "At most " + line2 + " (unable to track, sorry)"; + details.listAppend(line2); + + if (oil_ml < 50 && $item[dress pants].available_amount() == 0 && !in_hardcore()) + details.listAppend("If you can't reach +50 ML or more, possibly consider pulling and wearing dress pants. (lazy pull, doesn't add ML but saves 4 or 24 turns)"); + } + if (need_jar_of_oil) + { + modifiers.listAppend("+item"); + string item_drop_string = ""; + int [int] drop_rates; + if (oil_ml >= 100) + { + //last is possibly 10%, needs more spading + item_drop_string = "100%/30%/10% drops"; + drop_rates = listMake(100, 30, 10); + } + else if (oil_ml >= 50) + { + item_drop_string = "100%/30% drops"; + drop_rates = listMake(100, 30); + } + else if (oil_ml >= 20) + { + item_drop_string = "100%/10% drops"; + drop_rates = listMake(100, 10); + } + else + { + item_drop_string = "100% drop"; + drop_rates = listMake(100); + } + + float crudes_per_adventure = 0.0; + float item_drop_rate_multiplier = (100.0 + $location[oil peak].item_drop_modifier_for_location()) / 100.0; + foreach key in drop_rates + { + int rate = drop_rates[key]; + float effective_rate = MIN(1.0, rate.to_float() / 100.0 * item_drop_rate_multiplier); + crudes_per_adventure += effective_rate; + } + string crude_string = "~" + crudes_per_adventure.roundForOutput(1) + " crude/adventure."; + if (turns_remaining_at_current_ml > 0) + crude_string += " ~" + (crudes_per_adventure * turns_remaining_at_current_ml.to_float()).roundForOutput(1) + " crudes before fire lit."; + + + if ($item[bubblin' crude].available_amount() < 12) + { + details.listAppend("Run +item to acquire " + pluralise(MAX(0, 12 - $item[bubblin' crude].available_amount()), "more bubblin' crude", "more bubblin' crudes") + ". (" + item_drop_string + ")|" + crude_string); + if ($item[duskwalker syringe].available_amount() > 0) + details.listAppend("Use " + $item[duskwalker syringe].pluralise() + " in-combat for more crude."); + } + } + + task_entries.listAppend(ChecklistEntryMake("oil peak", "place.php?whichplace=highlands", ChecklistSubentryMake("Oil Peak", modifiers, details), $locations[oil peak]).ChecklistEntrySetIDTag("Council L9 quest oil peak progress")); + } + else if (!$location[oil peak].noncombat_queue.contains_text("Unimpressed with Pressure")) + { + string [int] details; + string [int] modifiers; + + details.listAppend("Light the fire!"); + + task_entries.listAppend(ChecklistEntryMake("oil peak", "place.php?whichplace=highlands", ChecklistSubentryMake("Oil Peak", modifiers, details), $locations[oil peak]).ChecklistEntrySetIDTag("Council L9 quest oil peak done")); + } +} + +void QLevel9GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 9"].in_progress) + return; + QuestState base_quest_state = __quest_state["Level 9"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + + string url = "place.php?whichplace=highlands"; + int tasks_before = task_entries.count() + optional_task_entries.count() + future_task_entries.count(); + + if (base_quest_state.mafia_internal_step == 1) + { + url = "place.php?whichplace=orc_chasm"; + //build bridge: + + //if (__misc_state["have olfaction equivalent"]) //don't remember what you'd olfact here + //subentry.modifiers.listAppend("olfaction"); + subentry.entries.listAppend("Build a bridge."); + + string smut_orc_noncombat_progress_string = get_property("smutOrcNoncombatProgress"); + boolean orc_tracking_supported = false; + if (smut_orc_noncombat_progress_string != "") + { + orc_tracking_supported = true; + } + float weapon_damage_actual = numeric_modifier("Weapon Damage"); + //correct numeric_modifier's response to actual: + foreach s in $slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3,familiar] + { + item it = s.equipped_item(); + if (it == $item[none]) continue; + if (it.to_slot() != $slot[weapon]) continue; + weapon_damage_actual -= it.get_power().to_float() * 0.15; + } + + int choice_1_pieces_gained = MAX(3, MIN(14, sqrt((my_buffedstat($stat[muscle]) + weapon_damage_actual) / 15.0 * (numeric_modifier("Weapon Damage Percent") / 100.0 + 1.0)))); + int choice_2_pieces_gained = MAX(3, MIN(14, sqrt((my_buffedstat($stat[mysticality]) + numeric_modifier("Spell Damage")) / 15.0 * (numeric_modifier("Spell Damage Percent") / 100.0 + 1.0)))); + int choice_3_pieces_gained = MAX(3, MIN(14, sqrt((my_buffedstat($stat[moxie]) / 30.0 * (numeric_modifier("Sleaze Resistance") * 0.69 + 1.0))))); + + if (orc_tracking_supported) + { + int smut_orc_noncombat_progress = smut_orc_noncombat_progress_string.to_int_silent(); + if (smut_orc_noncombat_progress < 15) + { + subentry.modifiers.listAppend("+item"); + subentry.modifiers.listAppend("-ML"); + int percent_to_nc = smut_orc_noncombat_progress.to_float() / 15.0 * 100; + subentry.entries.listAppend("Run as little monster level as possible.|Overkill the orcs with as much " + HTMLGenerateSpanOfClass("cold damage", "r_element_cold") + " as you can.|" + percent_to_nc + "% to NC."); + } + else + { + int best_choice_pieces = choice_1_pieces_gained; + string best_choice = "the first choice"; + if (choice_2_pieces_gained > best_choice_pieces) + { + best_choice = "the second choice"; + best_choice_pieces = choice_2_pieces_gained; + } + if (choice_3_pieces_gained > best_choice_pieces) + { + best_choice = "the third choice"; + best_choice_pieces = choice_3_pieces_gained; + } + + subentry.entries.listAppend("Next encounter will be the non-combat.|Choose " + best_choice + ". (" + best_choice_pieces + " pieces gained)"); + string line; + line += "Your buffing options are:"; + line += "|*Buff +muscle/weapon damage percent/weapon damage for the first NC option. (at " + choice_1_pieces_gained + " pieces)"; + line += "|*Or +myst/spell damage percent/spell damage for the second NC option. (at " + choice_2_pieces_gained + " pieces)"; + line += "|*Or +moxie/sleaze resistance and choose the third option at the NC. (at " + choice_3_pieces_gained + " pieces)"; + subentry.entries.listAppend(line); + } + } + else + { + subentry.modifiers.listAppend("+item"); + subentry.modifiers.listAppend("-ML"); + subentry.modifiers.listAppend("+moxie"); + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+sleaze resistance", "r_element_sleaze_desaturated")); + //FIXME show how effective you are at the moment. + subentry.entries.listAppend("Run as little monster level as possible.|Overkill the orcs with as much cold damage as you can."); + subentry.entries.listAppend("Then:"); + subentry.entries.listAppend("|*Buff +muscle/weapon damage/weapon damage percent for the first NC option."); + subentry.entries.listAppend("|*Or +myst/spell damage/spell damage percent for the second NC option."); + subentry.entries.listAppend("|*Or +moxie/sleaze resistance and choose the third option at the NC."); + } + + /*if (get_property("questM15Lol") != "finished" && ($item[bridge].available_amount() > 0 || $item[dictionary].available_amount() == 0) && false) //it's gone! + { + if ($item[bridge].available_amount() > 0) + subentry.entries.listAppend("Place the bridge."); + else if ($item[abridged dictionary].available_amount() > 0) + subentry.entries.listAppend("Untinker the abridged dictionary."); + else + subentry.entries.listAppend("Acquire an abridged dictionary from the pirates, untinker it."); + }*/ + + int fasteners_needed = base_quest_state.state_int["bridge fasteners needed"]; + int lumber_needed = base_quest_state.state_int["bridge lumber needed"]; + + if (__misc_state["can equip just about any weapon"]) + { + if (lumber_needed > 0) + { + if ($item[logging hatchet].available_amount() > 0 && $item[logging hatchet].equipped_amount() == 0) + subentry.entries.listAppend("Possibly equip that logging hatchet."); + else if ($item[logging hatchet].available_amount() == 0 && canadia_available()) + subentry.entries.listAppend("Possibly acquire a logging hatchet. (first adventure in Camp Logging Camp in Little Canadia)"); + } + + if (fasteners_needed > 0) + { + if ($item[loadstone].available_amount() > 0 && $item[loadstone].equipped_amount() == 0) + subentry.entries.listAppend("Possibly equip that loadstone."); + else if ($item[loadstone].available_amount() == 0 && !__quest_state["Level 8"].state_boolean["Past mine"]) + subentry.entries.listAppend("Possibly find a loadstone in the mine."); + } + } + + if (($item[snow berries].available_amount() > 0 || $item[ice harvest].available_amount() > 0) && $item[snow boards].available_amount() < 4) + subentry.entries.listAppend("Possibly make snow boards."); + if (__misc_state["can use clovers"]) + subentry.entries.listAppend("Possibly clover for 3 lumber and 3 fasteners."); + + + string [int] line; + if (fasteners_needed > 0) + line.listAppend(fasteners_needed + " fasteners"); + if (lumber_needed > 0) + line.listAppend(lumber_needed + " lumber"); + + if (lumber_needed + fasteners_needed == 0) + { + //finished + subentry.modifiers.listClear(); + subentry.entries.listClear(); + subentry.entries.listAppend("Build a bridge!"); + } + if ($item[smut orc keepsake box].available_amount() > 0) + subentry.entries.listAppend("Open " + pluralise($item[smut orc keepsake box]) + "."); + if (line.count() > 0) { + subentry.entries.listAppend("Need " + line.listJoinComponents(" ", "and") + "."); + + if (__quest_state["Level 11 Shen"].state_int.getFutureShenAssignments().listInvert() contains $location[The Smut Orc Logging Camp]) + subentry.entries.listAppend("Could wait before going there? Shen will send you here later."); + } + } + /*else if (base_quest_state.mafia_internal_step == 2) + { + //bridge built, talk to angus: + subentry.entries.listAppend("Talk to Angus in the Highland Lord's tower."); + }*/ + else if (base_quest_state.mafia_internal_step == 2 || base_quest_state.mafia_internal_step == 3) + { + //do three peaks: + //subentry.entries.listAppend("Light the fires!"); + if ($location[oil peak].noncombat_queue.contains_text("Unimpressed with Pressure") && $location[a-boo peak].noncombat_queue.contains_text("Come On Ghosty, Light My Pyre") && base_quest_state.state_int["twin peak progress"] == 15) + subentry.entries.listAppend("Talk to Lord Angus to finish the quest."); + else + subentry.entries.listAppend("Light the fires!"); + QLevel9GenerateTasksSidequests(task_entries, optional_task_entries, future_task_entries); + } + else if (base_quest_state.mafia_internal_step == 4) + { + //fires lit, talk to angus again: + subentry.entries.listAppend("Talk to Angus in the Highland Lord's tower."); + } + int tasks_after = task_entries.count() + optional_task_entries.count() + future_task_entries.count(); + if (tasks_before == tasks_after) //if our sidequests didn't add anything, show something: + task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the smut orc logging camp,a-boo peak,oil peak,twin peak]).ChecklistEntrySetIDTag("Council L9 quest highlands")); +} + + +void QLevel10Init() +{ + //questL10Garbage + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL10Garbage"); + + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Castle Quest"; + state.image_name = "castle"; + state.council_quest = true; + + + boolean beanstalk_grown = false; + if ($items[Model airship,Plastic Wrap Immateria,Gauze Immateria,Tin Foil Immateria,Tissue Paper Immateria,S.O.C.K.].available_amount() > 0) + beanstalk_grown = true; + if (state.finished) + beanstalk_grown = true; + if ($location[the penultimate fantasy airship].turnsAttemptedInLocation() > 0) + beanstalk_grown = true; + if (state.mafia_internal_step > 1) + beanstalk_grown = true; + + state.state_boolean["beanstalk grown"] = beanstalk_grown; + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + state.state_boolean["beanstalk grown"] = true; + + if (my_level() >= 10 || my_path().id == PATH_EXPLOSIONS) + state.startable = true; + + __quest_state["Level 10"] = state; + __quest_state["Castle"] = state; +} + + +void QLevel10GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 10"].in_progress) + return; + QuestState base_quest_state = __quest_state["Level 10"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + string image_name = base_quest_state.image_name; + string url = "place.php?whichplace=beanstalk"; + + boolean add_as_future_task = false; + if ($item[s.o.c.k.].available_amount() == 0 && my_path().id != PATH_EXPLOSION) + { + //FIXME delay if ballroom song not set + image_name = "penultimate fantasy airship"; + if (!base_quest_state.state_boolean["beanstalk grown"]) + { + if ($item[enchanted bean].available_amount() == 0) + { + subentry.entries.listAppend("Acquire enchanted bean from a beanbat."); + subentry.modifiers.listAppend("+100% item"); + url = $location[the beanbat chamber].getClickableURLForLocation(); + } + else + { + subentry.entries.listAppend("Grow the beanstalk."); + url = "place.php?whichplace=plains"; + } + } + else + { + int turns_spent = $location[the penultimate fantasy airship].turns_spent; + int turns_delay = -1; + + boolean need_minus_combat = true; + if (turns_spent == -1) + need_minus_combat = true; + else if (turns_spent < 5) + { + need_minus_combat = false; + turns_delay = 5 - turns_spent; + } + else if (turns_spent < 10 && $item[Tissue Paper Immateria].available_amount() > 0) + { + need_minus_combat = false; + turns_delay = 10 - turns_spent; + } + else if (turns_spent < 15 && $item[Tin Foil Immateria].available_amount() > 0) + { + need_minus_combat = false; + turns_delay = 15 - turns_spent; + } + else if (turns_spent < 20 && $item[Gauze Immateria].available_amount() > 0) + { + need_minus_combat = false; + turns_delay = 20 - turns_spent; + } + else if (turns_spent < 25 && $item[Plastic Wrap Immateria].available_amount() > 0) + { + need_minus_combat = false; + turns_delay = 25 - turns_spent; + } + + //boolean need_minus_combat_only_for_model_airship = false; + if ($item[model airship].available_amount() == 0 && turns_spent >= 5) + { + //if (!need_minus_combat) + //need_minus_combat_only_for_model_airship = true; + need_minus_combat = true; + } + + + if (need_minus_combat) + subentry.modifiers.listAppend("-combat"); + else + subentry.modifiers.listAppend("possibly +combat"); + + if (__misc_state["free runs available"]) + subentry.modifiers.listAppend("free runs"); + if (turns_spent < 25) + { + if (__misc_state["have hipster"]) + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + } + + boolean have_more_than_enough_sgeeas = false; + if ($item[soft green echo eyedrop antidote].available_amount() >= 30 || !in_ronin()) + have_more_than_enough_sgeeas = true; + + string [int] things_we_want_item_for; + + if ($skill[Transcendent Olfaction].skill_is_usable() && !have_more_than_enough_sgeeas) + { + string line = "SGEEA"; + if ($item[soft green echo eyedrop antidote].available_amount() > 0) + line += " (have " + $item[soft green echo eyedrop antidote].available_amount() + ")"; + things_we_want_item_for.listAppend(line); + } + + + //immateria: + + item [int] immaterias_missing = $items[Tissue Paper Immateria,Tin Foil Immateria,Gauze Immateria,Plastic Wrap Immateria].items_missing(); + + if (turns_delay != -1 && !need_minus_combat) + { + //subentry.entries.listAppend(pluraliseWordy(turns_delay, "turn", "turns").capitaliseFirstLetter() + " delay until -combat relevant."); + string line = "After " + pluraliseWordy(turns_delay, "turn", "turns") + " delay, "; + if (immaterias_missing.count() == 0) + subentry.entries.listAppend(line + "find Cid."); + else + subentry.entries.listAppend(line + "find " + immaterias_missing.count().int_to_wordy() + " more immateria."); + //subentry.entries.listAppend(line + "find the immateria: " + listJoinComponents(immaterias_missing, ", ", "and")); + } + else + { + if (immaterias_missing.count() == 0) + subentry.entries.listAppend("Find Cid. (-combat)"); + else + { + subentry.entries.listAppend("Find " + immaterias_missing.count().int_to_wordy() + " more immateria. (-combat)"); + //subentry.entries.listAppend("Find the immateria (-combat): " + listJoinComponents(immaterias_missing, ", ", "and")); + } + } + + //FIXME it would be nice to track this + if (turns_spent == -1) + subentry.entries.listAppend("25 total turns of delay."); + else if (turns_spent < 25) + subentry.entries.listAppend(pluralise(25 - turns_spent, "turn", "turns") + " total delay remaining."); + if ($skill[Transcendent Olfaction].skill_is_usable() && !(get_property("olfactedMonster") == "Quiet Healer") && !have_more_than_enough_sgeeas) + subentry.entries.listAppend("Potentially olfact quiet healer for SGEEAs"); + + if ($items[amulet of extreme plot significance,mohawk wig].items_missing().count() > 0 && $familiar[slimeling].familiar_is_usable()) + subentry.modifiers.listAppend("slimeling?"); + + if ($item[model airship].available_amount() == 0) + subentry.entries.listAppend("Acquire model airship from non-combat. (speeds up quest)"); + if ($item[amulet of extreme plot significance].available_amount() == 0) + { + things_we_want_item_for.listAppend("amulet of extreme plot significance"); + subentry.entries.listAppend("Acquire amulet of extreme plot significance (quiet healer, 10% drop) to speed up opening ground floor."); + } + if ($item[mohawk wig].available_amount() == 0) + { + things_we_want_item_for.listAppend("Mohawk wig"); + subentry.entries.listAppend("Acquire mohawk wig (Burly Sidekick, 10% drop) to speed up top floor."); + } + if (things_we_want_item_for.count() > 0) + { + subentry.modifiers.listAppend("+item"); + subentry.entries.listAppend("Potentially run +item for " + listJoinComponents(things_we_want_item_for, ", ", "and") + "."); + } + } + } + else + { + url = "place.php?whichplace=giantcastle"; + if (base_quest_state.mafia_internal_step >= 11) //(get_property("lastEncounter") == "Keep On Turnin' the Wheel in the Sky") + { + url = "place.php?whichplace=town"; + subentry.entries.listAppend("Talk to the council to finish quest."); + } + else if ($location[The Castle in the Clouds in the Sky (Top floor)].locationAvailable()) + { + float turn_estimation = -1.0; + float non_combat_rate = 1.0 - (0.95 + combat_rate_modifier() / 100.0); + if (non_combat_rate < 0.11111111111111) //every nine adventures, minimum + non_combat_rate = 0.11111111111111; + + //FIXME turn estimation for all routes, not just mohawk wig/model airship + + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("Top floor. Run -combat."); + if ($item[mohawk wig].equipped_amount() == 0 && $item[mohawk wig].available_amount() > 0) + { + string line = "Wear your mohawk wig"; + if (!$item[mohawk wig].can_equip()) + { + add_as_future_task = true; + line += ", once you can equip it"; + } + line += "."; + subentry.entries.listAppend(HTMLGenerateSpanFont(line, "red")); + } + if ($item[mohawk wig].available_amount() == 0 && !in_hardcore()) + subentry.entries.listAppend("Potentially pull and wear a mohawk wig."); + if ($item[model airship].available_amount() == 0 && my_path().id != PATH_EXPLOSIONS) + { + if ($item[mohawk wig].available_amount() == 0) //no wig, no airship + subentry.entries.listAppend("Backfarm for a model airship in the fantasy airship. (non-combat option, run -combat)"); + else + subentry.entries.listAppend("Potentially backfarm for a model airship in the fantasy airship. (non-combat option, run -combat)"); //always suggest this - backfarming for model airship is faster than spending time in top floor, I think + } + + if ($item[mohawk wig].available_amount() > 0 && $item[model airship].available_amount() > 0) + { + if (non_combat_rate != 0.0) + turn_estimation = 1.0 / non_combat_rate; + } + + //We don't suggest trying to complete this quest with the record, even if they lack the mohawk wig/model airship - I feel as though that would take quite a number of turns? + //It's a 95% combat location (max nine/ten turns between non-combats), and the non-combats are split between two different sets. + //There might be some internal mechanics to make it faster? Don't know. + image_name = "goggles? yes!"; + + if (turn_estimation != -1.0) + subentry.entries.listAppend("~" + turn_estimation.roundForOutput(1) + " turns left on average."); + + //Check if Shen is going to send them here (and not to the Hole in the Sky before that) + int top_floor_index = 0; + int hole_in_the_sky_index = 0; + foreach index, destination in __quest_state["Level 11 Shen"].state_int.getFutureShenAssignments() { + if (destination == $location[The Castle in the Clouds in the Sky (Top floor)]) + top_floor_index = index; + else if (destination == $location[The Hole in the Sky]) + hole_in_the_sky_index = index; + } + if (top_floor_index > hole_in_the_sky_index) + subentry.entries.listAppend("Hold on before going there; Shen will send you here later."); + } + else if ($location[The Castle in the Clouds in the Sky (Ground floor)].locationAvailable()) + { + int turns_spent = $location[The Castle in the Clouds in the Sky (Ground floor)].turns_spent; + int turns_remaining = 11; + if (turns_spent != -1) + { + turns_remaining = 11 - turns_spent; + subentry.entries.listAppend("Ground floor. Spend " + pluraliseWordy(turns_remaining, "more turn", "more turns") + " here to unlock top floor."); + } + else + subentry.entries.listAppend("Ground floor. Spend eleven turns here to unlock top floor."); + + image_name = "castle stairs up"; + + if (__misc_state["need to level"]) + subentry.entries.listAppend("Possibly acquire the very overdue library book from a non-combat. (stats)"); + + boolean request_minus_combat = false; + if ($item[electric boning knife].available_amount() == 0 && __quest_state["Level 13"].state_boolean["wall of bones will need to be defeated"] && !$skill[garbage nova].skill_is_usable()) + { + request_minus_combat = true; + subentry.modifiers.listAppend("-combat"); + string line = "Try to acquire the electric boning knife if you see it. (foodie NC)"; + string [int] ncs_to_spend_turn_on; + foreach s in $strings[There's No Ability Like Possibility,Putting Off Is Off-Putting,Huzzah!] + { + if (!$location[The Castle in the Clouds in the Sky (Ground floor)].noncombat_queue.contains_text(s)) + { + ncs_to_spend_turn_on.listAppend(s); + } + } + if (ncs_to_spend_turn_on.count() > 0) + line += "|Avoid skipping NCs " + ncs_to_spend_turn_on.listJoinComponents(", ", "and") + " exactly once each, to make the knife appear faster. (don't do this after unlocking the top floor)"; + subentry.entries.listAppend(line); + } + if (!request_minus_combat && CounterWanderingMonsterMayHitNextTurn() && !CounterWanderingMonsterWillHitNextTurn()) + { + request_minus_combat = true; + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("If you seek out and skip NCs here, they can tell you if your wandering monster is up next turn.|Then you can adventure somewhere else for a turn, and burn more delay here."); + } + + if (true) + { + if (__misc_state["have hipster"]) + { + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + } + if (__misc_state["free runs available"]) + subentry.modifiers.listAppend("free runs"); + } + } + else + { + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("Basement. Run -combat."); + + float turn_estimation = -1.0; + float non_combat_rate = 1.0 - (0.95 + combat_rate_modifier() / 100.0); + if (non_combat_rate < 0.11111111111111) //every nine adventures, minimum + non_combat_rate = 0.11111111111111; + if ($item[amulet of extreme plot significance].available_amount() > 0) + { + if ($item[amulet of extreme plot significance].equipped_amount() == 0) + subentry.entries.listAppend("Possibly " + HTMLGenerateSpanFont("wear the amulet of extreme plot significance.", "red") + "|Or search for the non-combat, skip it, equip the amulet, and adventure again."); + + if (non_combat_rate != 0.0) + turn_estimation = 1.0 / non_combat_rate; + + + } + else + { + boolean have_usable_umbrella = (__misc_state["can equip just about any weapon"] && $item[titanium assault umbrella].available_amount() > 0); + + if (!in_hardcore()) + subentry.entries.listAppend("Potentially pull and wear an amulet of extreme plot significance."); + if (have_usable_umbrella && $item[titanium assault umbrella].equipped_amount() == 0) + subentry.entries.listAppend("Equip your titanium assault umbrella."); + if ($item[massive dumbbell].available_amount() == 0) + { + if (have_usable_umbrella) + { + subentry.entries.listAppend("Grab the massive dumbbell from gym if you can't reach the ground floor otherwise."); + + if (non_combat_rate != 0.0) + turn_estimation = (2.0 / 3.0) * (2.0 / non_combat_rate) + (1.0 / 3.0) * (1.0 / non_combat_rate); //1/3rd chance of instant completion with umbrella + } + else + { + subentry.entries.listAppend("Grab the massive dumbbell from gym."); + if (non_combat_rate != 0.0) + { + turn_estimation = 1.0 / non_combat_rate + (1.0 / (non_combat_rate * (2.0 / 3.0))); + } + } + + } + else + { + subentry.entries.listAppend("Place the massive dumbbell in the Open Source dumbwaiter."); + if (non_combat_rate != 0.0) + turn_estimation = 1.0 / (non_combat_rate * (2.0 / 3.0)); + } + } + + if (turn_estimation != -1.0) + subentry.entries.listAppend("~" + turn_estimation.roundForOutput(1) + " turns left on average."); + + image_name = "lift, bro"; + } + } + + ChecklistEntry entry = ChecklistEntryMake(image_name, url, subentry, $locations[the penultimate fantasy airship, the castle in the clouds in the sky (basement), the castle in the clouds in the sky (ground floor), the castle in the clouds in the sky (top floor)]); + entry.tags.id = "Council L10 giant castle quest"; + if (add_as_future_task) + future_task_entries.listAppend(entry); + else + task_entries.listAppend(entry); +} +//Our strategy for the copperhead quest is probably not very good. Largely because it looks complicated and I (Ezandora) made a few guesses. + +void QLevel11CopperheadInit() +{ + if (true) { + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL11Ron"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Zeppelin Quest"; //"Merry-Go-Ron"; + state.image_name = "__item copperhead charm (rampant)"; //__item bitchin ford anglia + + state.state_int["protestors remaining"] = clampi(80 - get_property_int("zeppelinProtestors"), 0, 80); + + state.state_boolean["need protestor speed tricks"] = true; + if (state.mafia_internal_step >= 3) + state.state_int["protestors remaining"] = 0; + if (state.state_int["protestors remaining"] <= 1) + state.state_boolean["need protestor speed tricks"] = false; + + state.state_boolean["should output"] = state.in_progress && __quest_state["Level 11"].state_boolean["have diary"] && (__misc_state["in run"] || $location[the red zeppelin].turns_spent > 0 || __last_adventure_location == $location[a mob of zeppelin protesters]); + + __quest_state["Level 11 Ron"] = state; + } + if (true) { + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL11Shen"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Copperhead Club Quest"; //"Of Mice and Shen"; + state.image_name = "__item copperhead charm"; //"__effect Ancient Annoying Serpent Poison"; + + state.state_boolean["should output"] = state.in_progress && __quest_state["Level 11"].state_boolean["have diary"] && (__misc_state["in run"] || $location[the copperhead club].turns_spent > 0); + + + //other than in exploathing, if mafia_internal_step == 1, we haven't "locked" which items are going to be asked + if (state.state_boolean["should output"] && (state.mafia_internal_step > 1 || my_path().id == PATH_KINGDOM_OF_EXPLOATHING)) { + state.state_int["Shen meetings"] = state.mafia_internal_step / 2; + state.state_int["snakes slain"] = (state.mafia_internal_step - 1) / 2; + + + static boolean have_wrong_predictions; + + int daycount_when_first_met_Shen = get_property_int("shenInitiationDay"); + + //If we are currently looking for a snake + if (state.mafia_internal_step % 2 == 0) { //2, 4 or 6 + state.state_boolean["on an assignment"] = true; + + //Verify if mafia's quest item matches the predicted one. If it doesn't, stop predicting assignments for the rest of the session + if (my_path().id != PATH_KINGDOM_OF_EXPLOATHING) { //we know this path has a hardcoded set of requests + item quest_item = get_property_item("shenQuestItem"); + item predicted_quest_item = __shen_start_day_to_assignments[daycount_when_first_met_Shen] [state.state_int["Shen meetings"]]; + if (quest_item != predicted_quest_item) + have_wrong_predictions = true; + } + } + state.state_int["Shen initiation day"] = have_wrong_predictions ? 0 : daycount_when_first_met_Shen; + } + + __quest_state["Level 11 Shen"] = state; + } +} + +void QLevel11RonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + /* + questL11Ron + Merry-Go-Ron + started - Search for Ron Copperhead on the Red Zeppelin. + step1 - Fight your way through the mob of zeppelin protesters. + step2 - All aboard! All aboard the Red Zeppelin! + step3 - Search the Red Zeppelin for Ron Copperhead. + step4 - Barge into Ron Copperhead's cabin in the Red Zeppelin and beat him up! + finshed - You recovered half of the Talisman o' Nam from Ron Copperhead. Brilliant! + */ + QuestState base_quest_state = __quest_state["Level 11 Ron"]; + if (!base_quest_state.state_boolean["should output"]) + return; + + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + + string url = $location[A Mob of Zeppelin Protesters].getClickableURLForLocation(); + + + if (base_quest_state.mafia_internal_step <= 2 && base_quest_state.state_int["protestors remaining"] <= 1) { + subentry.entries.listAppend("Adventure in the mob of protestors."); + } else if (base_quest_state.mafia_internal_step <= 2) { + //Fight your way through the mob of zeppelin protesters. + subentry.entries.listAppend("Scare away " + pluraliseWordy(base_quest_state.state_int["protestors remaining"], "more protestor", "more protestors") + "."); + subentry.modifiers.listAppend("-combat"); + subentry.modifiers.listAppend("+567% item"); + if (__misc_state["have olfaction equivalent"]) + subentry.modifiers.listAppend("olfact cultists"); + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("sleaze damage", "r_element_sleaze")); + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("sleaze spell damage", "r_element_sleaze")); + //Two olfaction targets here seem to be cultists or lynyrd skinner. + //Cultists seem much better. + //Cigarette lighter is a 15% drop. when used in combat against protestors, removes quite a few + + boolean [item] relevant_lynyrdskin_items; + relevant_lynyrdskin_items[$item[lynyrdskin cap]] = true; + relevant_lynyrdskin_items[$item[lynyrdskin breeches]] = true; + if (__misc_state["Torso aware"]) + relevant_lynyrdskin_items[$item[lynyrdskin tunic]] = true; + + if ($item[lynyrd musk].available_amount() > 0 && $effect[Musky].have_effect() == 0 && $item[lynyrd musk].item_is_usable()) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Use lynyrd musk.", "red")); + url = "inventory.php?ftext=lynyrd+musk"; + } + if ($item[cigarette lighter].available_amount() > 0 && base_quest_state.state_boolean["need protestor speed tricks"] && my_path().id != PATH_POCKET_FAMILIARS) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Use cigarette lighter in-combat.", "red")); + } + if ($item[lynyrd snare].available_amount() > 0 && $items[lynyrdskin cap,lynyrdskin tunic,lynyrdskin breeches].items_missing().count() > 0 && $item[lynyrd snare].item_is_usable() && get_property_int("_lynyrdSnareUses") < 3 && $item[lynyrd snare].item_is_usable()) { + subentry.entries.listAppend("Possibly use the lynyrd snare. (free combat)"); + } + string [int] what_not_not_to_wear; + foreach it in relevant_lynyrdskin_items { + if (it.available_amount() == 0) + continue; + if (it.equipped_amount() > 0) + continue; + what_not_not_to_wear.listAppend(it.to_string().replace_string("lynyrdskin ", "")); + } + + if ($item[pocket wish].have() || ($item[genie bottle].have() && get_property_int("_genieWishesUsed") < 3)) { + int current_sleaze_damage = numeric_modifier("sleaze damage") + numeric_modifier("sleaze spell damage"); + string [int] options; + if ($effect[Fifty Ways to Bereave Your Lover].have_effect() == 0) + options.listAppend("Fifty Ways to Bereave Your Lover for +100 sleaze damage"); + if ($effect[Dirty Pear].have_effect() == 0) + options.listAppend("Dirty Pear for 2x sleaze damage; currently +" + current_sleaze_damage + " total damage"); + string line = "Could wish for sleaze damage"; + if (options.count() > 0) + line += ", like " + options.listJoinComponents(", ", "or"); + line += "."; + subentry.entries.listAppend(line); + } + float sleaze_protestors_cleared = MAX(3.0, sqrt(numeric_modifier("sleaze damage") + numeric_modifier("sleaze spell damage"))); + if (sleaze_protestors_cleared > 3) + subentry.entries.listAppend(HTMLGenerateSpanOfClass("Sleaze", "r_element_sleaze") + " damage will clear " + sleaze_protestors_cleared.roundForOutput(1) + " protestors."); //FIXME do we want to list the amount they'll need to increase that? + + if (what_not_not_to_wear.count() > 0) { + subentry.entries.listAppend("Equip your lynyrdskin " + what_not_not_to_wear.listJoinComponents(", ", "and") + "?"); + url = "inventory.php?ftext=lynyrd"; + } + + if ($skill[Transcendent Olfaction].skill_is_usable() && !(get_property_monster("olfactedMonster") == $monster[Blue Oyster cultist]) && base_quest_state.state_boolean["need protestor speed tricks"]) + subentry.entries.listAppend("Olfact blue oyster cultists for protestor-skipping lighters."); + + if ($item[lynyrd skin].available_amount() > 0 && $skill[armorcraftiness].skill_is_usable()) { + item [int] missing_equipment = relevant_lynyrdskin_items.items_missing(); + if (missing_equipment.count() > 0) { + string [int] missing_equipment_output_string; + foreach key, it in missing_equipment { + missing_equipment_output_string.listAppend(it.to_string().replace_string("lynyrdskin ", "")); + } + string joining_string = "or"; + if (missing_equipment.count() <= $item[lynyrd skin].available_amount()) + joining_string = "and"; + string line = "Craft lynyrdskin " + missing_equipment_output_string.listJoinComponents(", ", joining_string); + + line += "."; + boolean can_likely_freecraft = false; + if ($effect[inigo's incantation of inspiration].have_effect() >= 5) + can_likely_freecraft = true; + if ($item[thor's pliers].available_amount() > 0 && get_property_int("_thorsPliersCrafting") < 10) //FIXME is _thorsPliersCrafting correct? suspect mafia tracks it incorrectly, I saw it at 9 after a run. smithing, probably + can_likely_freecraft = true; + if (get_property_int("homebodylCharges") > 0) + can_likely_freecraft = true; + + //_legionJackhammerCrafting <3 + if ($items[Loathing Legion abacus,Loathing Legion can opener,Loathing Legion chainsaw,Loathing Legion corkscrew,Loathing Legion defibrillator,Loathing Legion double prism,Loathing Legion electric knife,Loathing Legion flamethrower,Loathing Legion hammer,Loathing Legion helicopter,Loathing Legion jackhammer,Loathing Legion kitchen sink,Loathing Legion knife,Loathing Legion many-purpose hook,Loathing Legion moondial,Loathing Legion necktie,Loathing Legion pizza stone,Loathing Legion rollerblades,Loathing Legion tape measure,Loathing Legion tattoo needle,Loathing Legion universal screwdriver,Loathing Legion Knife].available_amount() > 0 && get_property_int("_legionJackhammerCrafting") < 3) { + if ($item[Loathing Legion jackhammer].available_amount() == 0 && !can_likely_freecraft) { + line += " (fold loathing legion knife into jackhammer first)"; + } + can_likely_freecraft = true; + } + + if (!can_likely_freecraft) + line += " (1 adventure, not worth it?)"; + + subentry.entries.listAppend(line); + + } + } + if (!__quest_state["Level 11 Shen"].finished && $item[Flamin' Whatshisname].available_amount() == 0) + subentry.entries.listAppend("Could adventure in the Copperhead Club first for Flamin' Whatshisnames."); + } else if (base_quest_state.mafia_internal_step <= 4) { + //All aboard! All aboard the Red Zeppelin! + subentry.entries.listAppend("Search for Ron in the zeppelin."); + //possibly 50% chance of no progress without a ticket (unconfirmed chat rumour) + + if (my_path().id != PATH_POCKET_FAMILIARS) { + subentry.modifiers.listAppend("+234% item"); + foreach m in $monsters[Red Herring,Red Snapper] { + if (!m.is_banished()) + subentry.modifiers.listAppend("banish " + m); + } + + if (__misc_state["have olfaction equivalent"]) + subentry.modifiers.listAppend("olfact red butler"); + } + + if ($item[red zeppelin ticket].available_amount() == 0) { + if ($item[priceless diamond].available_amount() > 0 && black_market_available()) + subentry.entries.listAppend("Trade in your priceless diamond for a red zeppelin ticket."); + else if (my_meat() >= $item[red zeppelin ticket].npc_price() && my_meat() >= 4000 && black_market_available()) + subentry.entries.listAppend("Purchase a red zeppelin ticket in the black market."); + else if (!__quest_state["Level 11 Shen"].finished && black_market_available()) + subentry.entries.listAppend("Could adventure in the Copperhead Club first for a ticket. (greatly speeds up area)"); + else + subentry.entries.listAppend("No ticket."); + } + + if (my_path().id != PATH_POCKET_FAMILIARS) { + if (get_property_int("_glarkCableUses") < 5) { + if ($skill[Transcendent Olfaction].skill_is_usable() && !(get_property_monster("olfactedMonster") == $monster[red butler])) + subentry.entries.listAppend("Olfact red butlers for glark cables."); + + if ($item[glark cable].available_amount() > 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Use glark cable in-combat.", "red")); + } + subentry.entries.listAppend(get_property_int("_glarkCableUses") + " / 5 glark cables used today (free kills)."); + } else { + subentry.entries.listAppend("Already used all 5 glark cables for the day."); + } + } + + if ($item[priceless diamond].available_amount() > 0 && $item[red zeppelin ticket].available_amount() == 0) { + subentry.modifiers.listClear(); + subentry.entries.listClear(); + subentry.entries.listAppend("Acquire a Red Zeppelin ticket from the black market."); + url = "shop.php?whichshop=blackmarket"; + } + } else if (base_quest_state.mafia_internal_step == 5) { + //Barge into Ron Copperhead's cabin in the Red Zeppelin and beat him up! + subentry.entries.listAppend("Defeat Ron in the zeppelin."); + } + + + + + ChecklistEntry entry = ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[A Mob of Zeppelin Protesters,The Red Zeppelin]); + entry.tags.id = "Council L11 quest copperhead Ron"; + + if (!__misc_state["in run"] || $item[talisman o' namsilat].available_amount() > 0) + optional_task_entries.listAppend(entry); + else + task_entries.listAppend(entry); +} + +void QLevel11ShenGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + /* + questL11Shen + Of Mice and Shen + started - Go to the Copperhead Club and find Shen, the man mentioned in your father's diary. + step1 - (no unique message) + step2 - (no unique message) + step3 - (no unique message) + step4 - (no unique message) + step5 - (no unique message) + step6 - (no unique message) + finished - You retrieved half of the Talisman o' Nam from Shen Copperhead. Nice! + + Guesses: + 1 - Need to meet shen for the first time. + 2 - shen met the first time, go do as he asks + 3 - monster done, now go find shen + 4 - shen met second time, go do as he asks + 5 - second monster done, go now find shen + 6 - shen found, go find the third monster + 7 - third monster defeated, shen find go + finished*/ + + QuestState base_quest_state = __quest_state["Level 11 Shen"]; + if (!base_quest_state.state_boolean["should output"]) + return; + + ChecklistEntry entry; + entry.url = $location[the copperhead club].getClickableURLForLocation(); + entry.image_lookup_name = base_quest_state.image_name; + entry.tags.id = "Council L11 quest copperhead Shen"; + entry.should_highlight = $locations[the copperhead club] contains __last_adventure_location; + + ChecklistSubentry subentry; + entry.subentries.listAppend(subentry); //changes made to subentry past this line will still appear. Done now to make sure this one is above the club subentry. + subentry.header = base_quest_state.quest_name; + + item [int] current_assignments; + if (my_path().id == PATH_EXPLOSIONS) + current_assignments = __shen_exploathing_assignments; + else if (__shen_start_day_to_assignments contains base_quest_state.state_int["Shen initiation day"]) + current_assignments = __shen_start_day_to_assignments[base_quest_state.state_int["Shen initiation day"]]; + + entry.should_highlight = entry.should_highlight || current_assignments.shenAssignmentsJoinLocationsStartingAfter(base_quest_state.state_int["snakes slain"]).listInvert() contains __last_adventure_location; + + + if (base_quest_state.mafia_internal_step <= 1) { //Need to meet shen for the first time. + subentry.entries.listAppend("Adventure in the Copperhead Club and meet Shen."); + subentry.entries.listAppend("This will give you unremovable -5 stat poison."); + if (my_path().id == PATH_EXPLOSIONS) + subentry.entries.listAppend("On this path, he'll always ask for: |*• " + current_assignments.shenAssignmentsJoinLocations().listJoinComponents("|*• ")); + else { + int daycount = my_daycount(); + if (__shen_start_day_to_assignments contains daycount) + subentry.entries.listAppend("If you meet him today, he'll send you to:|*• " + __shen_start_day_to_assignments[daycount].shenAssignmentsJoinLocations().listJoinComponents("|*• ")); + if (__shen_start_day_to_assignments contains ++daycount) + subentry.entries.listAppend("Tomorrow will instead be:|*• " + __shen_start_day_to_assignments[daycount].shenAssignmentsJoinLocations().listJoinComponents("|*• ")); + } + // This used to be true in old metas, but hasn't been true for a while. Commenting it out. + // if (my_daycount() == 1 && my_path().id != PATH_EXPLOSIONS) + // subentry.entries.listAppend("Perhaps wait until tomorrow before starting this; day 2's shen bosses are more favourable."); + } else { + int club_turns_spent = $location[the copperhead club].turns_spent; + int next_guaranteed_meeting = base_quest_state.state_int["Shen meetings"] * 5; + int total_delay_remaining = 15 - (3 - base_quest_state.state_int["Shen meetings"]) - club_turns_spent; + boolean is_disguised = $effect[Crappily Disguised as a Waiter].have_effect() > 0; + string club_hazard = get_property("copperheadClubHazard"); //none, gong, fire, ice + boolean need_diamond = $items[priceless diamond,Red Zeppelin ticket].available_amount() == 0 && __quest_state["Level 11 Ron"].mafia_internal_step < 5 && my_meat() < 5000 && my_path().id != PATH_NUCLEAR_AUTUMN; + boolean need_flaming_whatshisname = __quest_state["Level 11 Ron"].state_boolean["need protestor speed tricks"]; + + string [int] club_modifiers; + club_modifiers.listAppend("+234% item"); + club_modifiers.listAppend("olfact ninja dressed as a waiter"); + if (club_hazard != "gong") + club_modifiers.listAppend("-ML"); //hail of bullets damage is ~9 + your +ML + + string [int] club_entries; + //unnamed cocktail is 15% + //ninja dressed as a waiter has 30% disguise + //waiter dressed as a ninja has 20% disguise + //Behind the 'Stache can have a single state: gong, ice, or lanterns on fire + //ice -> priceless diamond + //fire -> setting unnamed cocktail on fire + //gong -> prevents damage taken (not speed relevant) + //and averages 0.64285714285714 unnamed cocktails per attempt (which takes a turn?) + //so let's see... + //you first want the priceless diamond for the ticket, otherwise you have the 50% chance(?) of losing progress + //soo... run 234% item for the disguise? + //after that, you theoretically want to upgrade cocktails, but... + //to do that, you need a second disguise, which means possibly olfacting? then olfacting the bartender. + + //alternatively, olfact the ninja, then use disguises to collect cocktails + //each one saves up to seven protestors if you see the NC (at -25% combat, the likelyhood is 11.6% per turn) + + string line = "Use crappy waiter disguise (have " + $item[crappy waiter disguise].available_amount() + ") for a free NC (doesn't burn delay)."; + if (club_hazard == "" || club_hazard == "none" || club_hazard == "fire" && !need_flaming_whatshisname || club_hazard == "ice" && !need_diamond) { + if (need_diamond) + line += "|*Bucket: fights may give a priceless diamond."; + else if (need_flaming_whatshisname) + line += "|*Lanterns: fights turn Unnamed cocktails in inventory into Flaming whatshisname."; + else + line += "|*Gong: prevents the start of fight damage."; + } else if (club_hazard == "ice") + club_entries.listAppend("Fight club monsters (not wanderers) for a chance at a priceless diamond."); + else if (club_hazard == "fire") + club_entries.listAppend("Fight club monsters (not wanderers) with an Unnamed cocktail in inventory to turn it into a Flaming Whatshisname."); + line += "|*Steal: gain 1 Unnamed cocktail + 3-4 other things"; + if (club_hazard == "fire" && need_flaming_whatshisname) + line += " (have " + $item[Flamin' Whatshisname].item_amount() + ")"; + line += "."; + club_entries.listAppend(line); + club_entries.listAppend("Potentially save some disguises until the end to maybe save a turn."); + + + + if (base_quest_state.state_boolean["on an assignment"]) { //2, 4 or 6 + location assignment_location = __shen_items_to_locations[get_property_item("shenQuestItem")]; + + if (assignment_location != $location[none]) { + entry.url = assignment_location.getClickableURLForLocation(); + subentry.entries.listAppend("Adventure in " + assignment_location + (assignment_location == $location[The VERY Unquiet Garves] ? " (or the Unquiet Garves, but make a choice and stick to it)" : "") + "."); + } else { + subentry.entries.listAppend("Fight the " + base_quest_state.state_int["Shen meetings"].int_to_position_wordy() + " monster wherever Shen told you to go."); + } + + if (total_delay_remaining - 1 > 0) { + ChecklistSubentry club_subentry; + club_subentry.header = "Back at the club"; + club_subentry.modifiers.listAppendList(club_modifiers); + + if (club_turns_spent < next_guaranteed_meeting) + club_subentry.entries.listAppend("Delay for " + pluralise(next_guaranteed_meeting - club_turns_spent, "more turn", "more turns") + " in the Copperhead Club."); + club_subentry.entries.listAppend((total_delay_remaining - 1) + "-" + total_delay_remaining + " total delay remaining in the club."); + club_subentry.entries.listAppendList(club_entries); + + entry.subentries.listAppend(club_subentry); + } + } else if (club_turns_spent >= next_guaranteed_meeting) { + subentry.entries.listAppend("Meet Shen in the Copperhead Club.|Will meet him next turn."); + } else { + subentry.entries.listAppend("Find Shen in the Copperhead Club."); + if (club_turns_spent == next_guaranteed_meeting - 1) { + subentry.entries.listAppend((is_disguised ? "~25" : "50") + "% chance of finding him next turn."); + if (base_quest_state.state_int["Shen meetings"] == 3) { + if ($item[crappy waiter disguise].item_amount() > 0) + subentry.entries.listAppend("Use waiter disguises to have a chance at getting it early.").HTMLGenerateSpanFont(is_disguised ? "red" : "dark"); + if (is_disguised) + subentry.entries.listAppend("Have a disguise on; give it a go."); + } + } else { + subentry.modifiers.listAppendList(club_modifiers); + + string line; + line += "Can show up in " + (next_guaranteed_meeting - club_turns_spent - 1).pluralise("more turn", "more turns") + ";"; + line += " ensured in " + (next_guaranteed_meeting - club_turns_spent) + "."; + line += "|" + (total_delay_remaining - 1) + "-" + total_delay_remaining + " total delay remaining."; + subentry.entries.listAppend(line); + } + subentry.entries.listAppendList(club_entries); + } + } + + + if (!__misc_state["in run"] || $item[talisman o' namsilat].available_amount() > 0) + optional_task_entries.listAppend(entry); + else + task_entries.listAppend(entry); +} + + +void QLevel11PyramidInit() +{ + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL11Pyramid"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Pyramid Quest"; + state.image_name = "Pyramid"; + __quest_state["Level 11 Pyramid"] = state; +} + +void QLevel11PyramidGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 11"].in_progress) + return; + if (__quest_state["Level 11 Pyramid"].finished) + return; + + QuestState base_quest_state = __quest_state["Level 11 Pyramid"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + string url = ""; + if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"]) + return; + //Desert explored. + + boolean definitely_have_staff_of_ed = false; + if (2286.to_item().available_amount() > 0 && 2268.to_item().available_amount() > 0 && 2180.to_item().available_amount() > 0) + definitely_have_staff_of_ed = true; + + if ($item[2325].available_amount() + $item[2325].creatable_amount() + $item[7961].available_amount() + $item[7961].creatable_amount() == 0 && !definitely_have_staff_of_ed) + { + //Staff of ed. + //subentry.entries.listAppend("Find the Staff of Ed."); + future_task_entries.listAppend(ChecklistEntryMake("Pyramid", "", ChecklistSubentryMake("Head down the pyramid", "", "Find the Staff of Ed."))); + return; + } + else if (!base_quest_state.in_progress && $location[the upper chamber].turnsAttemptedInLocation() == 0) + { + url = "place.php?whichplace=desertbeach"; + subentry.entries.listAppend("Visit the pyramid, click on it."); + } + else + { + /* + How the new pyramid seemingly works: + Adventure six times in the upper chamber with -combat. (delay, free runs relevant) This unlocks the middle chamber with the adventure "Down Dooby-Doo Down Down" + Adventure six times in the middle chamber with +400% item and banishes. (delay, free runs relevant). This unlocks the lower chamber. + Adventure five times in the middle chamber with +400% item and banishes. (delay, free runs relevant) This unlocks the control chamber. + After that, you handle the control chamber and solve the puzzle. One tomb ratchet/crumbling wooden wheel advances the puzzle by one step. So, you can farm tomb ratchets (+item) or wooden wheels (-combat). There's so much delay in the middle chamber though... + "Under Control" is the control room unlock. + + */ + //middleChamberUnlock, lowerChamberUnlock, controlRoomUnlock implemented + url = "place.php?whichplace=pyramid"; + boolean done_with_wheel_turning = false; //FIXME set this + boolean should_generate_control_room_information = false; + boolean ed_chamber_open = get_property_boolean("pyramidBombUsed"); + if (get_property_boolean("middleChamberUnlock") || $location[the middle chamber].turnsAttemptedInLocation() > 0 || $location[the upper chamber].noncombat_queue.contains_text("Down Dooby-Doo Down Down")) + { + //middle chamber unlocked: + if (get_property_boolean("controlRoomUnlock") || $location[the middle chamber].noncombat_queue.contains_text("Under Control")) + { + //control room unlocked: + should_generate_control_room_information = true; + //FIXME implement this + //FIXME suggest the better route + subentry.modifiers.listAppend("+400% item OR -combat"); + subentry.modifiers.listAppend("olfact tomb rats"); + subentry.entries.listAppend("Can find crumbling wooden wheels in the upper chamber (-combat), or tomb ratchets in the middle chamber (+400% item, olfact rats)"); + } + /*else if (get_property_boolean("lowerChamberUnlock") || $location[the middle chamber].noncombat_queue.contains_text("Further Down Dooby-Doo Down Down")) + { + //lower chamber unlocked: + subentry.entries.listAppend("Adventure in the middle chamber for five total turns to unlock the control room."); + subentry.modifiers.listAppend("+400% item"); + subentry.modifiers.listAppend("olfact tomb rats"); + if (__misc_state["have hipster"]) + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + if (__misc_state["free runs available"]) + subentry.modifiers.listAppend("free runs"); + }*/ + else + { + //unlock lower chamber: + int turns_spent = $location[the middle chamber].turns_spent; + + int turns_remaining = MAX(0, 11 - turns_spent); + subentry.entries.listAppend("Adventure in the middle chamber for " + pluraliseWordy(turns_remaining, "more turn", "more turns") + " to unlock the control room."); + + subentry.modifiers.listAppend("+400% item"); + subentry.modifiers.listAppend("olfact tomb rats"); + if (__misc_state["have hipster"]) + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + if (__misc_state["free runs available"]) + subentry.modifiers.listAppend("free runs"); + + } + if ($item[tangle of rat tails].available_amount() > 0) + subentry.entries.listAppend("Use tangle of rat tails against tomb rats for more tomb ratchets."); + if (my_path().id == PATH_HEAVY_RAINS && $item[catfish whiskers].available_amount() > 0 && $effect[Fishy Whiskers].have_effect() == 0 && $item[tangle of rat tails].available_amount() > 0) + subentry.entries.listAppend("Possibly use catfish whiskers to find more tomb ratchets."); + } + else + { + //unlock middle chamber: + int turns_spent = $location[the upper chamber].turns_spent; + int turns_remaining = MAX(0, 6 - turns_spent); + subentry.entries.listAppend("Adventure in the upper chamber for " + pluraliseWordy(turns_remaining, "more turn", "more turns") + " to unlock the middle chamber."); + subentry.modifiers.listAppend("-combat"); + if (__misc_state["have hipster"]) + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + if (__misc_state["free runs available"]) + subentry.modifiers.listAppend("free runs"); + } + + + //Generate spin cycle: + + //this is not very good code: + boolean have_pyramid_position = false; + int pyramid_position = get_property_int("pyramidPosition"); + + //Uncertain: + //if (get_property_ascension("lastPyramidReset")) + if (pyramid_position > 0) //does this work? + have_pyramid_position = true; + + //I think there are... five positions? + //1=Ed, 2=bad, 3=vending machine, 4=token, 5=bad + int next_position_needed = -1; + int additional_turns_after_that = 0; + string task; + done_with_wheel_turning = false; + if (2318.to_item().available_amount() > 0 || ed_chamber_open) + { + //need 1 + next_position_needed = 1; + additional_turns_after_that = 0; + + int ed_ml = 180 + monster_level_adjustment_for_location($location[the lower chambers]); + task = "fight Ed in the lower chambers"; + if (ed_ml > my_buffedstat($stat[moxie])) + task += " (" + ed_ml + " attack)"; + + if (ed_chamber_open) + done_with_wheel_turning = true; + } + else if ($item[ancient bronze token].available_amount() > 0) + { + //need 3 + next_position_needed = 3; + additional_turns_after_that = 3; + task = "acquire " + 2318.to_item().to_string() + " in lower chamber"; + } + else + { + //need 4 + next_position_needed = 4; + additional_turns_after_that = 3 + 4; + task = "acquire token in lower chamber"; + } + + int spins_needed = (next_position_needed - pyramid_position + 10) % 5; + int total_spins_needed = spins_needed + additional_turns_after_that; + int spins_available = $item[tomb ratchet].available_amount() + $item[crumbling wooden wheel].available_amount(); + + int extra_spin_sources_needed = clampi(total_spins_needed - spins_available, 0, 11); + + //Pyramid unlocked: + if (should_generate_control_room_information) + { + + string [int] tasks; + if (spins_needed > 0) + { + if (spins_needed == 1) + tasks.listAppend("spin the pyramid One More Time"); + else + tasks.listAppend("spin the pyramid " + spins_needed.int_to_wordy() + " times"); + if ($item[tomb ratchet].available_amount() + $item[crumbling wooden wheel].available_amount() > 0) + url = "place.php?whichplace=pyramid&action=pyramid_control"; + } + tasks.listAppend(task); + + + if (!have_pyramid_position) + { + tasks.listClear(); + //tasks.listAppend("look at the pyramid"); //I dunno + } + + if (ed_chamber_open && done_with_wheel_turning) + { + subentry.modifiers.listClear(); + subentry.entries.listClear(); + } + + if (tasks.count() > 0) + subentry.entries.listPrepend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + else + subentry.entries.listAppend("Spin the control room, search the lower chambers! Then fight Ed."); + + if (ed_chamber_open && my_path().id == PATH_EXPLOSIONS && lookupItem("low-pressure oxygen tank").equipped_amount() == 0) + { + subentry.modifiers.listAppend("+hp regen"); + subentry.entries.listAppend("Keep +hp regen up, so you survive the multi-round fight without the oxygen tank?"); + } + } + + if (!done_with_wheel_turning) + { + if (extra_spin_sources_needed > 0) + subentry.entries.listAppend("Need " + HTMLGenerateSpanFont(int_to_wordy(extra_spin_sources_needed), "red") + " more ratchet/wheel" + ((extra_spin_sources_needed > 1) ? "s" : "") + "."); + else + subentry.entries.listAppend("Have enough wheels."); + /*if (amount > 0) + subentry.entries.listAppend(pluralise(amount, "wheel turn", "wheel turns") + " available.");*/ + if ($item[tangle of rat tails].available_amount() > 0 && extra_spin_sources_needed > 0) + subentry.entries.listAppend(pluralise($item[tangle of rat tails]) + " available."); + } + + } + + task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the upper chamber,the lower chambers, the middle chamber]).ChecklistEntrySetIDTag("Council L11 quest pyramid")); +} + +void QLevel11DesertInit() +{ + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL11Desert"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Desert Quest"; + state.image_name = "Pyramid"; //"__item instant karma"; + + int gnasir_progress = get_property_int("gnasirProgress"); + + state.state_boolean["Stone Rose Given"] = (gnasir_progress & 1) > 0; + state.state_boolean["Black Paint Given"] = (gnasir_progress & 2) > 0; + state.state_boolean["Killing Jar Given"] = (gnasir_progress & 4) > 0; + state.state_boolean["Manual Pages Given"] = (gnasir_progress & 8) > 0; + state.state_boolean["Wormridden"] = (gnasir_progress & 16) > 0; + + state.state_int["Desert Exploration"] = get_property_int("desertExploration"); + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + state.state_int["Desert Exploration"] = 100; + state.state_boolean["Desert Explored"] = (state.state_int["Desert Exploration"] == 100); + if (state.finished) { //in case mafia doesn't detect it properly + state.state_int["Desert Exploration"] = 100; + state.state_boolean["Desert Explored"] = true; + } + + + + boolean have_uv_compass_equipped = false; + + if (!__misc_state["can equip just about any weapon"]) + have_uv_compass_equipped = true; + if ($item[UV-resistant compass].equipped_amount() > 0) + have_uv_compass_equipped = true; + if ($item[ornate dowsing rod].equipped_amount() > 0) + have_uv_compass_equipped = true; + + state.state_boolean["Have UV-Compass eqipped"] = have_uv_compass_equipped; + + __quest_state["Level 11 Desert"] = state; +} + +void QLevel11DesertGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 11 Desert"].in_progress && __quest_state["Level 11"].mafia_internal_step < 3) + return; + QuestState base_quest_state = __quest_state["Level 11 Desert"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + string url = "place.php?whichplace=desertbeach"; + + if (base_quest_state.state_boolean["Desert Explored"]) + return; + + int exploration = base_quest_state.state_int["Desert Exploration"]; + int exploration_remaining = 100 - exploration; + float exploration_per_turn = 1.0; + if ($item[ornate dowsing rod].available_amount() > 0) + exploration_per_turn += 2.0; //FIXME make completely accurate for first turn? not enough information available + else if ($item[uv-resistant compass].available_amount() > 0) + exploration_per_turn += 1.0; + if (my_path().id == PATH_LICENSE_TO_ADVENTURE && get_property_boolean("bondDesert")) + exploration_per_turn += 2.0; + if ($item[survival knife].have() && __misc_state["can equip just about any weapon"] && $effect[ultrahydrated].have_effect() > 0) { + exploration_per_turn += 2.0; + } + + boolean have_blacklight_bulb = (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && get_property("peteMotorbikeHeadlight") == "Blacklight Bulb"); + if (have_blacklight_bulb) + exploration_per_turn += 2.0; + //FIXME deal with ultra-hydrated + + familiar camel = lookupFamiliar("Melodramedary"); + boolean canCamel = camel.familiar_is_usable(); + boolean haveCamel = my_familiar() == camel && camel != $familiar[none]; + if (haveCamel) + exploration_per_turn += 1.0; + + int combats_remaining = exploration_remaining; + combats_remaining = ceil(to_float(exploration_remaining) / exploration_per_turn); + subentry.entries.listAppend(exploration_remaining + "% exploration remaining. (" + pluralise(combats_remaining, "combat", "combats") + ")"); + if ($effect[ultrahydrated].have_effect() == 0 && my_path().id != PATH_G_LOVER) { + if (__last_adventure_location == $location[the arid, extra-dry desert]) { + string [int] description; + description.listAppend("Adventure in the Oasis."); + if ($items[11-leaf clover].available_amount() > 0) + description.listAppend("Potentially clover for 20 turns, versus 5."); + if (!get_property_boolean("fireExtinguisherDesertUsed") && __iotms_usable[$item[industrial fire extinguisher]] && get_property_int("_fireExtinguisherCharge") > 20) + description.listAppend("Or, use 20% fire extinguisher charge in the desert to drink the foam."); + task_entries.listAppend(ChecklistEntryMake("__effect ultrahydrated", "place.php?whichplace=desertbeach", ChecklistSubentryMake("Acquire ultrahydrated effect", "", description), -11).ChecklistEntrySetIDTag("Council L11 quest desert ultrahydrated")); + } + //if (exploration > 0) + //subentry.entries.listAppend("Need ultra-hydrated from The Oasis. (potential clover for 20 turns)"); + } + if (exploration < 10) { + int turns_until_gnasir_found = -1; + if (exploration_per_turn != 0.0) + turns_until_gnasir_found = ceil(to_float(10 - exploration) / exploration_per_turn); + + subentry.entries.listAppend("Find Gnasir after " + pluralise(turns_until_gnasir_found, "turn", "turns") + "."); + } else if (get_property_int("gnasirProgress") == 0 && exploration <= 14 && !$location[the arid, extra-dry desert].noncombat_queue.contains_text("A Sietch in Time")) { + subentry.entries.listAppend("Find Gnasir next turn."); + } else { + boolean need_pages = false; + if (!base_quest_state.state_boolean["Black Paint Given"]) { + if ($item[can of black paint].available_amount() == 0) { + if (black_market_available()) + subentry.entries.listAppend("Buy can of black paint, give it to Gnasir."); + } else + subentry.entries.listAppend("Give can of black paint to Gnasir."); + } + if (!base_quest_state.state_boolean["Stone Rose Given"]) { + if ($item[stone rose].available_amount() > 0) + subentry.entries.listAppend("Give stone rose to Gnasir."); + else { + string line = "Potentially adventure in Oasis for stone rose"; + line += "."; + if (delayRemainingInLocation($location[the oasis]) > 0) { + string hipster_text = ""; + if (__misc_state["have hipster"]) { + hipster_text = " (use " + __misc_state_string["hipster name"] + ")"; + } + line += "|Delay for " + pluralise(delayRemainingInLocation($location[the oasis]), "turn", "turns") + hipster_text + "."; + } + subentry.entries.listAppend(line); + } + } + if (my_path().id == PATH_G_LOVER) { //FIXME todo? + } else if (!base_quest_state.state_boolean["Manual Pages Given"]) { + if ($item[worm-riding manual page].available_amount() == 15) + subentry.entries.listAppend("Give Gnasir the worm-riding manual pages."); + else { + int remaining = 15 - $item[worm-riding manual page].available_amount(); + + subentry.entries.listAppend("Find " + pluralise(remaining, "more worm-riding manual page", "more worm-riding manual pages") + "."); + need_pages = true; + } + + } else if (!base_quest_state.state_boolean["Wormridden"]) { + subentry.modifiers.listAppend("rhythm"); + if ($item[drum machine].available_amount() > 0) { + subentry.entries.listAppend("Use drum machine."); + } + } + if (!base_quest_state.state_boolean["Wormridden"] && $item[drum machine].available_amount() == 0 && my_path().id != PATH_G_LOVER) { + if (base_quest_state.state_boolean["Manual Pages Given"]) + subentry.entries.listAppend("Potentially acquire drum machine from blur. (+234% item), use drum machine."); + else + subentry.entries.listAppend("Potentially acquire drum machine from blur. (+234% item), collect/return pages, then use drum machine."); + subentry.modifiers.listAppend("+234% item"); + } + if (!base_quest_state.state_boolean["Killing Jar Given"]) { + if ($item[killing jar].available_amount() > 0) + subentry.entries.listAppend("Give Gnasir the killing jar."); + else + subentry.entries.listAppend("Potentially find killing jar. (banshee, haunted library, 10% drop, YR?)"); + } + + if (__misc_state["have hipster"]) { + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + + string line = __misc_state_string["hipster name"].capitaliseFirstLetter() + " for free combats"; + if (need_pages) + line += " and manual pages"; + line += "."; + subentry.entries.listAppend(line); + } + } + if ($effect[ultrahydrated].have_effect() == 0 && my_path().id != PATH_G_LOVER) { + if (exploration > 0) + subentry.entries.listAppend("Acquire ultrahydrated effect from oasis. (potential clover for 20 adventures)"); + } + if ($item[desert sightseeing pamphlet].available_amount() > 0) { + if ($item[desert sightseeing pamphlet].available_amount() == 1) + subentry.entries.listAppend("Use your desert sightseeing pamphlet. (+15% exploration)"); + else + subentry.entries.listAppend("Use your desert sightseeing pamphlets. (+15% exploration)"); + } + int campgroundMilestoneCount = __campground[$item[milestone]]; + if (campgroundMilestoneCount > 0) { + string milestonesPlural = campgroundMilestoneCount == 1 ? "" : "s"; + subentry.entries.listAppend(HTMLGenerateSpanFont("Harvest your rock garden milestone" + milestonesPlural + "!", "red")); + } + if ($item[milestone].available_amount() > 0 && $item[milestone].item_is_usable()) { + string milestonesPlural = $item[milestone].available_amount() == 1 ? "" : "s"; + subentry.entries.listAppend("Use your milestone" + mileStonesPlural + ". (+5% exploration each)"); + } + if (!base_quest_state.state_boolean["Have UV-Compass eqipped"] && __quest_state["Level 11 Desert"].state_int["Desert Exploration"] < 99) { + boolean should_output_compass_in_red = true; + string line = ""; + string line_extra = ""; + if ($item[ornate dowsing rod].available_amount() > 0) { + line = "Equip the ornate dowsing rod."; + url = "inventory.php?ftext=ornate+dowsing+rod"; + } else { + if ($item[uv-resistant compass].available_amount() == 0 && !(my_path().id == PATH_LICENSE_TO_ADVENTURE && get_property_boolean("bondDesert")) && my_path().id != PATH_EXPLOSIONS) { + line = "Acquire"; + if (have_blacklight_bulb || haveCamel) { + line = "Possibly acquire"; + should_output_compass_in_red = false; + } + + line += " UV-resistant compass, equip for faster desert exploration. (shore vacation)"; + if ($item[Shore Inc. Ship Trip Scrip].available_amount() > 0) + url = "shop.php?whichshop=shore"; + + if ($item[odd silver coin].available_amount() > 0 || $item[grimstone mask].available_amount() > 0 || get_property("grimstoneMaskPath") != "") { //FIXME check for the correct grimstoneMaskPath + line_extra += "|Or acquire ornate dowsing rod from Paul's Boutique? (5 odd silver coins)"; + } + + } else if ($item[uv-resistant compass].available_amount() > 0) { + line = "Equip the UV-resistant compass."; + url = "inventory.php?ftext=uv-resistant+compass"; + } + } + if (canCamel && !haveCamel) { + if (line == "") + line += "Bring along Melodramedary."; + else + line_extra += "|Or bring along Melodramedary."; + } + if ($item[survival knife].have() && ($item[survival knife].equipped_amount() == 0)) { + if (line == "") + line += "Equip your survival knife (only effective while Ultrahydrated)"; + else + line_extra += "|Equip your survival knife (only effective while Ultrahydrated)"; + } + if (line != "") { + if (should_output_compass_in_red) + line = HTMLGenerateSpanFont(line, "red"); + line += line_extra; + subentry.entries.listAppend(line); + } + + } else { + if (canCamel && !haveCamel) { + subentry.entries.listAppend("Could bring along Melodramedary."); + } + } + task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the arid\, extra-dry desert,the oasis]).ChecklistEntrySetIDTag("Council L11 quest desert exploration")); +} + +void QLevel11PalindomeInit() +{ + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL11Palindome"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Palindome Quest"; + state.image_name = "Palindome"; + + state.state_boolean["Need instant camera"] = false; + if ($item[photograph of a dog].available_amount() + $item[disposable instant camera].available_amount() == 0 && state.mafia_internal_step < 3) + state.state_boolean["Need instant camera"] = true; + if (7270.to_item().available_amount() > 0 || my_path().id == PATH_POCKET_FAMILIARS || my_path().id == PATH_G_LOVER) + state.state_boolean["Need instant camera"] = false; + + state.state_boolean["dr. awkward's office unlocked"] = false; + if (state.mafia_internal_step > 2) + state.state_boolean["dr. awkward's office unlocked"] = true; + if (get_property_int("palindomeDudesDefeated") >= 5 && 7262.to_item().available_amount() == 0) //inference + state.state_boolean["dr. awkward's office unlocked"] = true; + __quest_state["Level 11 Palindome"] = state; +} + +void QLevel11PalindomeGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //FIXME add whitey's grove fallthrough + + if (!__quest_state["Level 11 Palindome"].in_progress && __quest_state["Level 11"].mafia_internal_step <3) //questL11Palindome unstarted until uncertain time + return; + if (__quest_state["Level 11 Palindome"].finished) + return; + if (__quest_state["Level 11"].finished) + return; + if (__quest_state["Level 11"].mafia_internal_step <3 ) + return; + if (($item[Staff of Ed\, almost].available_amount() > 0 || $item[2325].available_amount() > 0 || $item[2268].available_amount() > 0) && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) + return; + + QuestState base_quest_state = __quest_state["Level 11 Palindome"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + string url; + + if (base_quest_state.mafia_internal_step < 2 && $item[talisman o' namsilat].available_amount() == 0 && $items[Copperhead Charm,Copperhead Charm (rampant)].items_missing().count() == 0) { + url = "craft.php?mode=combine"; + subentry.entries.listAppend("Paste the two copperhead charms together to acquire the talisman o' nam."); + } else if (base_quest_state.mafia_internal_step < 2 && $item[talisman o' namsilat].available_amount() == 0) { + //1 -> find palindome + string [int] quests; + if (!__quest_state["Level 11 Shen"].finished) + quests.listAppend("copperhead"); + if (!__quest_state["Level 11 Ron"].finished) + quests.listAppend("zeppelin"); + subentry.entries.listAppend("Find the palindome by completing the " + quests.listJoinComponents("/") + " quest."); + } else { + url = "place.php?whichplace=palindome"; + if ($item[talisman o' namsilat].equipped_amount() == 0) + url = "inventory.php?ftext=talisman+o'+namsilat"; + + + /* + Quest steps: + Adventure in palindome, acquire: + photograph of a dog (7263) by taking a picture of one of the racecar twins(?) with a disposable instant camera + photograph of an ostrich egg (7265) + photograph of a red nugget (7264) + photograph of god + stunt nuts for wet stunt nut stew + "I Love Me, Vol. I" (7262) (dropped from monster, possibly drab bard?, possibly after rest are available?) + Use I love me, volume 1. This removes it from your inventory, and unlocks the office. + Arrange the photographs on the shelf: + god, red nugget, dog, ostrich egg + This gives 2 Love Me, Vol. 2 (7270) + Read it to unlock mr. alarm in left office. It will disappear. + He'll tell you to go acquire wet stunt nut stew. Adventure in whitey's grove as per usual. + Cook wet stunt nut stew. + Go talk to mr. alarm. He'll give a mega gem. + Go fight Dr. Awkward with both equipped. + + */ + + if ($item[mega gem].available_amount() > 0 || base_quest_state.mafia_internal_step == 5) + { + //5 -> fight dr. awkward + string [int] tasks; + if ($item[talisman o' namsilat].equipped_amount() == 0) + tasks.listAppend("equip the Talisman o' Nam"); + if ($item[mega gem].equipped_amount() == 0) + tasks.listAppend("equip the Mega Gem"); + + tasks.listAppend("fight Dr. Awkward in his office"); + subentry.entries.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + } + else if (base_quest_state.mafia_internal_step == 3 && 7270.to_item().available_amount() > 0 && false) + { + //doesn't seem to work? + subentry.entries.listAppend("Use 2 Love Me, Vol. 2, then talk to Mr. Alarm in his office."); + } + else if (base_quest_state.mafia_internal_step == 4 || base_quest_state.mafia_internal_step == 3) + { + //4 -> acquire wet stunt nut stew, give to mr. alarm + //FIXME handle alternate route + //step3 not supported yet, so we have this instead: + if (base_quest_state.mafia_internal_step == 3) + { + if (!(7270.to_item().available_amount() > 0 && false)) + subentry.entries.listAppend("Use 2 Love Me, Vol. 2, then talk to Mr. Alarm in his office. Then:"); + } + + if ($item[wet stunt nut stew].available_amount() == 0) + { + if (($item[bird rib].available_amount() > 0 && $item[lion oil].available_amount() > 0 || $item[wet stew].available_amount() > 0) && $item[stunt nuts].available_amount() > 0) + { + url = "craft.php?mode=cook"; + subentry.entries.listAppend("Cook wet stunt nut stew."); + } + else + { + url = "place.php?whichplace=woods"; + subentry.entries.listAppend("Acquire and make wet stunt nut stew."); + if ($item[wet stunt nut stew].available_amount() == 0 && $item[stunt nuts].available_amount() == 0) + subentry.entries.listAppend("Acquire stunt nuts from Bob Racecar or Racecar Bob in Palindome. (30% drop)"); + if ($item[wet stew].available_amount() == 0 && ($item[bird rib].available_amount() == 0 || $item[lion oil].available_amount() == 0)) + { + string [int] components; + monster [int] monsters_need_to_meet; + if ($item[bird rib].available_amount() == 0) + { + components.listAppend($item[bird rib]); + monsters_need_to_meet.listAppend($monster[whitesnake]); + } + if ($item[lion oil].available_amount() == 0) + { + components.listAppend($item[lion oil]); + monsters_need_to_meet.listAppend($monster[white lion]); + } + string line = "Adventure in Whitey's Grove to acquire " + components.listJoinComponents("", "and") + "."; + + line += "|"; + int food_drop_have = $location[whitey's grove].item_drop_modifier_for_location() + numeric_modifier("food drop"); + if (food_drop_have >= 300.0) + { + line += "Have +300% item"; + } + else + { + line += HTMLGenerateSpanFont("Need +300% item", "red") + " (missing " + (300 - food_drop_have) + "%)"; + } + line += " and +combat."; + if (familiar_is_usable($familiar[jumpsuited hound dog])) + line += " (hound dog is useful for this)"; + subentry.entries.listAppend(line); + + if ($item[white page].available_amount() > 0) + subentry.entries.listAppend("Can use your white pages to dial up a " + monsters_need_to_meet.listJoinComponents(", ", "or a") + "."); + + subentry.modifiers.listAppend("+combat"); + subentry.modifiers.listAppend("+300% item/food drop"); + if (__quest_state["Level 6"].finished && !get_property_boolean("friarsBlessingReceived")) + { + subentry.entries.listAppend("Can use friars blessing for +30% food drop."); + } + if ($item[Gene Tonic: Goblin].available_amount() > 0 && $effect[Human-Goblin Hybrid].have_effect() == 0) + { + subentry.entries.listAppend("Use goblin gene tonic for +50% food drop."); + } + if (!in_hardcore()) + subentry.entries.listAppend("Or pull wet stew."); + } + subentry.entries.listAppend("Or try the alternate route in the Palindome."); + } + } + else + { + subentry.entries.listAppend("Talk to Mr. Alarm."); + if ($item[talisman o' namsilat].equipped_amount() == 0) + subentry.entries.listAppend("Equip the Talisman o' Nam."); + } + //if (7270.to_item() != $item[none] && 7270.to_item().available_amount() > 0) + //url = "place.php?whichplace=palindome"; + } + else if (base_quest_state.mafia_internal_step == 3 || 7270.to_item().available_amount() > 0) + { + string [int] tasks; + //talk to mr. alarm to unlock whitey's grove + if (7270.to_item().available_amount() > 0) + { + url = "inventory.php?ftext=2+love+me"; + tasks.listAppend("use 2 Love Me, Vol. 2"); + } + if ($item[wet stunt nut stew].available_amount() > 0) + tasks.listAppend("talk to Mr. Alarm"); + else + tasks.listAppend("talk to Mr. Alarm to unlock Whitey's Grove"); + + subentry.entries.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + if ($item[talisman o' namsilat].equipped_amount() == 0) + subentry.entries.listAppend("Equip the Talisman o' Nam."); + } + else + { + boolean dr_awkwards_office_unlocked = base_quest_state.state_boolean["dr. awkward's office unlocked"]; //no way to track this at the moment + string single_entry_mode = ""; + boolean need_to_adventure_in_palindome = false; + boolean need_palindome_location = true; + + //Need: + //√Wet stunt nut stew / stunt nuts + //√"I Love Me, Vol. I" (7262) + //√instant camera -> 7263 photograph of a dog + //√7264 photograph of a red nugget + //√7265 photograph of an ostrich egg + //√photograph of god + subentry.entries.listAppend("Adventure in the palindome."); + + if ($item[photograph of a dog].available_amount() == 0) + { + if (my_path().id == PATH_POCKET_FAMILIARS || my_path().id == PATH_G_LOVER) + { + need_to_adventure_in_palindome = true; + subentry.entries.listAppend("Defeat Bob Racecar or Racecar Bobs until you acquire the photograph of a dog."); + } + else if ($item[disposable instant camera].available_amount() == 0) + { + subentry.modifiers.listClear(); + url = $location[the haunted bedroom].getClickableURLForLocation(); + single_entry_mode = "Adventure in the haunted bedroom for a disposable instant camera."; + int monsters_in_zone = 0; + foreach m in $monsters[animated mahogany nightstand,animated ornate nightstand,animated rustic nightstand,elegant animated nightstand,Wardröb nightstand] + { + //monster m = s.to_monster(); + if (!m.is_banished() || m == $monster[none]) + monsters_in_zone += 1; + } + if (monsters_in_zone == 0) + monsters_in_zone = 5; + + if (!in_hardcore() && (get_property("questM21Dance") == "finished" || $location[the haunted ballroom].turnsAttemptedInLocation() > 0 || $item[Lady Spookyraven's finest gown].available_amount() > 0)) + single_entry_mode += "|Or pull for it. (saves " + pluraliseWordy(monsters_in_zone, "turn", "turns") + ")"; + need_palindome_location = false; + } + else + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Photograph Bob Racecar or Racecar Bob", "red") + " with disposable instant camera."); + need_to_adventure_in_palindome = true; + } + } + + if ($item[stunt nuts].available_amount() + $item[wet stunt nut stew].available_amount() == 0 && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) + { + subentry.modifiers.listAppend("+234% item"); + subentry.entries.listAppend("Possibly acquire stunt nuts from Bob Racecar or Racecar Bob. (30% drop)"); + need_to_adventure_in_palindome = true; + } + + + string [int] missing_ncs; + if ($item[photograph of a red nugget].available_amount() == 0) + { + missing_ncs.listAppend("photograph of a red nugget"); + } + if ($item[photograph of an ostrich egg].available_amount() == 0) + { + missing_ncs.listAppend("photograph of an ostrich egg"); + } + if ($item[photograph of god].available_amount() == 0) + { + missing_ncs.listAppend("photograph of god"); + } + if (missing_ncs.count() > 0) + { + subentry.modifiers.listAppend("-combat"); //initial spading suggests at least two of these are affected by -combat, need more data + subentry.entries.listAppend("Find " + missing_ncs.listJoinComponents(", ", "and") + " from non-combats, run -combat"); + need_to_adventure_in_palindome = true; + } + + + + + //This must be after all other need_to_adventure_in_palindome checks: + if (7262.to_item().available_amount() == 0 && !dr_awkwards_office_unlocked) //I love me, Vol. I + { + int dudes_left = clampi(5 - get_property_int("palindomeDudesDefeated"), 0, 5); + + if (__misc_state["have olfaction equivalent"] && __misc_state_string["olfaction equivalent monster"] != "Racecar Bob" && __misc_state_string["olfaction equivalent monster"] != "Bob Racecar" && __misc_state_string["olfaction equivalent monster"] != "Drab Bard" && dudes_left > 1) + { + subentry.modifiers.listAppend("olfact racecar"); + subentry.entries.listAppend("Olfact Bob Racecar or Racecar Bob."); + } + subentry.entries.listAppend("Defeat " + pluraliseWordy(dudes_left, "more dude", "more dudes") + " in the palindome."); + need_to_adventure_in_palindome = true; + } + else if (7262.to_item().available_amount() > 0) + { + if (!need_to_adventure_in_palindome) + { + url = "inventory.php?ftext=I+love+me"; + subentry.entries.listAppend("Use I Love Me, Vol. I. Then place the photographs in Dr. Awkward's Office."); + } + else + { + subentry.entries.listAppend("Have I Love Me, Vol. I. Collect photographs and such in the Palindome first."); + } + } + + if (!need_to_adventure_in_palindome) + { + if (subentry.entries contains 0) + remove subentry.entries[0]; //remove "Adventure in the palindome" by index - this is hacky + } + + if (!need_to_adventure_in_palindome && dr_awkwards_office_unlocked) + { + subentry.modifiers.listClear(); + single_entry_mode = "Place items on shelves in Dr. Awkward's office.|Order is god, red nugget, dog, and ostrich egg."; + } + + if (single_entry_mode != "") + { + subentry.entries.listClear(); + subentry.entries.listAppend(single_entry_mode); + } + if (need_palindome_location && $item[talisman o' namsilat].equipped_amount() == 0) + subentry.entries.listAppend("Equip the Talisman o' Nam."); + } + } + + boolean [location] relevant_locations = makeConstantLocationArrayMutable($locations[the poop deck, belowdecks,cobb's knob laboratory,whitey's grove]); + relevant_locations[$location[Inside the Palindome]] = true; + + task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, relevant_locations).ChecklistEntrySetIDTag("Council L11 quest palindome")); +} + +void QLevel11ManorInit() +{ + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL11Manor"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Lord Spookyraven Quest"; + state.image_name = "Spookyraven manor"; + + if (($items[2286,Headpiece of the Staff of Ed].available_amount() > 0 || to_item("2325").available_amount() > 0) && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) //eye of ed + QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + + boolean use_fast_route = true; + if (!__misc_state["can equip just about any weapon"]) + use_fast_route = false; + if (my_path().id == PATH_NUCLEAR_AUTUMN && in_hardcore()) + use_fast_route = false; + if (in_bad_moon()) //This is possible, but certainly not plausible. + use_fast_route = false; + + state.state_boolean["Can use fast route"] = use_fast_route; + + __quest_state["Level 11 Manor"] = state; +} + +void QLevel11ManorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 11 Manor"].in_progress) + return; + if (__quest_state["Level 11"].mafia_internal_step <3 ) //strange bug where questL11MacGuffin = started, questL11Manor = step1 + return; + + QuestState base_quest_state = __quest_state["Level 11 Manor"]; + ChecklistSubentry subentry; + string url = ""; + subentry.header = base_quest_state.quest_name; + string image_name = base_quest_state.image_name; + if (true) + { + boolean use_fast_route = base_quest_state.state_boolean["Can use fast route"]; + boolean recipe_will_be_autoread = (($item[lord spookyraven's spectacles].available_amount() > 0) && use_fast_route) && get_property_boolean("autoCraft"); + boolean recipe_was_autoread_with_glasses = (get_property("spookyravenRecipeUsed") == "with_glasses"); + boolean recipe_was_autoread = recipe_was_autoread_with_glasses || (get_property("spookyravenRecipeUsed") == "no_glasses"); + //FIXME spectacles first? + if (!$location[the haunted ballroom].locationAvailable()) + return; + if (!$location[the haunted ballroom].noncombat_queue.contains_text("We'll All Be Flat") && base_quest_state.mafia_internal_step < 2) + { + url = "place.php?whichplace=manor2"; + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("Run -combat in the haunted ballroom."); + image_name = "Haunted Ballroom"; + if (delayRemainingInLocation($location[the haunted ballroom]) > 0) + { + string line = "Delay for " + pluralise(delayRemainingInLocation($location[the haunted ballroom]), "turn", "turns") + "."; + if (__misc_state["have hipster"]) + { + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + } + subentry.entries.listAppend(line); + } + } + else + { + url = "manor3.php"; + + if (use_fast_route && $item[lord spookyraven's spectacles].available_amount() == 0 && !recipe_was_autoread) + { + url = $location[the haunted bedroom].getClickableURLForLocation(); + subentry.entries.listAppend("Acquire Lord Spookyraven's spectacles from the haunted bedroom.|Unless you're using the slow route, in which case ignore this."); + image_name = "__item Lord Spookyraven's spectacles"; + } + else if ($item[recipe: mortar-dissolving solution].available_amount() == 0 && !__setting_debug_mode && !recipe_was_autoread) + { + if (recipe_will_be_autoread) + { + subentry.entries.listAppend("Click on the suspicious masonry in the basement."); + image_name = "__item recipe: mortar-dissolving solution"; + } + else if (use_fast_route && $item[lord spookyraven's spectacles].equipped_amount() == 0) + { + url = "inventory.php?ftext=lord+spookyraven's+spectacles"; + subentry.entries.listAppend("Equip Lord Spookyraven's Spectacles, click on the suspicious masonry in the basement, then read the recipe."); + image_name = "__item Lord Spookyraven's spectacles"; + } + else + { + subentry.entries.listAppend("Click on the suspicious masonry in the basement, then read the recipe."); + image_name = "__item recipe: mortar-dissolving solution"; + } + + } + else + { + //FIXME also make sure that is relevant when in the haunted bedroom/missing items + //FIXME detect the chamber being opened + boolean output_final_fight_info = base_quest_state.mafia_internal_step >= 4; + if (use_fast_route && !output_final_fight_info) + { + if ($item[wine bomb].available_amount() > 0) + { + output_final_fight_info = true; + } + else if ($item[unstable fulminate].available_amount() > 0) + { + string [int] tasks; + if ($item[unstable fulminate].equipped_amount() == 0) + { + url = "inventory.php?ftext=unstable+fulminate"; + tasks.listAppend(HTMLGenerateSpanFont("Equip unstable fulminate", "red")); + } + image_name = "monstrous boiler"; + + int ml_needed = 82; + int inherent_ml_modifier = 0; + //if (my_path().id == PATH_HEAVY_RAINS) //need to test this + //inherent_ml_modifier = 82 - 40; //maybe? + ml_needed -= inherent_ml_modifier; + tasks.listAppend("adventure in the haunted boiler room with +" + ml_needed + " ML"); + subentry.modifiers.listAppend("+" + ml_needed + " ML"); + + subentry.entries.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + + int current_ml = $location[The Haunted Boiler Room].monster_level_adjustment_for_location(); + + if (current_ml < ml_needed) + { + subentry.modifiers.listAppend("olfact boiler"); + } + else + { + string [int] banish_targets; + if (!$monster[coaltergeist].is_banished()) + banish_targets.listAppend("coaltergeist"); + if (!$monster[steam elemental].is_banished()) + banish_targets.listAppend("steam elemental"); + if (banish_targets.count() > 0) + subentry.modifiers.listAppend("banish " + banish_targets.listJoinComponents(", ")); + } + + float degrees_per_fight = 10 + floor(MAX((current_ml + inherent_ml_modifier).to_float(), 0.0) / 2.0); + + int boilers_needed = clampi(ceil(50.1 / degrees_per_fight.to_float()), 1, 6); + + monster boiler_monster = $monster[monstrous boiler]; + float [monster] appearance_rates = $location[The Haunted Boiler Room].appearance_rates_adjusted(); + + + float boiler_per_adventure = appearance_rates[boiler_monster] / 100.0; + + if (boiler_per_adventure > 0.0) + { + float turns_needed = boilers_needed.to_float() / boiler_per_adventure; + subentry.entries.listAppend("~" + turns_needed.roundForOutput(1) + " total turns to charge fulminate."); + } + else if ((appearance_rates contains boiler_monster) && boiler_monster != $monster[none]) + { + subentry.entries.listAppend("Seemingly unable to find boilers. They miss you. They look up to you."); + } + } + else if (!recipe_was_autoread_with_glasses) + { + subentry.entries.listAppend("Need to " + ($item[lord spookyraven's spectacles].available_amount() == 0 ? "acquire and " : "") + "equip Lord Spookyraven's spectacles and read the recipe before you can use the quick route."); + } + else + { + //FIXME implement this differently? + boolean need_item_modifier = false; + if ($item[bottle of Chateau de Vinegar].available_amount() == 0) + { + //+booze? +food seemingly doesn't work on this one + subentry.entries.listAppend("Find bottle of Chateau de Vinegar from possessed wine rack in the haunted wine cellar."); + subentry.modifiers.listAppend("olfact wine rack"); + need_item_modifier = true; + image_name = "possessed wine rack"; + } + if ($item[blasting soda].available_amount() == 0) + { + subentry.entries.listAppend("Find blasting soda from the cabinet in the haunted laundry room."); + subentry.modifiers.listAppend("olfact cabinet"); + need_item_modifier = true; + + if (image_name == base_quest_state.image_name) + image_name = "cabinet of Dr. Limpieza"; + } + if (need_item_modifier) + { + subentry.modifiers.listPrepend("+1900% item"); //+item, increasing drop + subentry.entries.listAppend("Base drop rate is 5%, then 10%, 15%, etc, for each wine rack/cabinet defeated, individually."); + } + + if ($item[bottle of Chateau de Vinegar].available_amount() > 0 && $item[blasting soda].available_amount() > 0) + { + url = "craft.php?mode=cook"; + string line = "Cook unstable fulminate."; + if (!__misc_state["can cook for free"]) + line += " (1 adventure)"; + subentry.entries.listAppend(line); + image_name = "__item unstable fulminate"; + } + } + } + if (!output_final_fight_info) + { + item [location] searchables; + searchables[$location[the haunted kitchen]] = $item[loosening powder]; + searchables[$location[the haunted conservatory]] = $item[powdered castoreum]; + searchables[$location[the haunted bathroom]] = $item[drain dissolver]; + searchables[$location[the haunted gallery]] = $item[triple-distilled turpentine]; + searchables[$location[the haunted laboratory]] = $item[detartrated anhydrous sublicalc]; + searchables[$location[the haunted storage room]] = $item[triatomaceous dust]; + + + item [location] missing_searchables; + foreach l in searchables + { + item it = searchables[l]; + if (it.available_amount() == 0) + missing_searchables[l] = it; + } + + if (missing_searchables.count() > 0) + { + string [int] places; + foreach l in missing_searchables + { + item it = searchables[l]; + //places.listAppend(it.capitaliseFirstLetter() + " in " + l + "."); + places.listAppend(l.to_string().replace_string("The Haunted ", "")); + } + string line = "Scavenger hunt! "; + if (use_fast_route) + line = "Alternatively, scavenger hunt! (likely much slower)|*"; + //line += "Go search for:|*" + places.listJoinComponents("
|*"); + line += "Go search in the Haunted " + places.listJoinComponents(", ", "and") + "."; + subentry.entries.listAppend(line); + /*if (!recipe_was_autoread) + subentry.entries.listAppend("Read the recipe.");*/ + + //are these scheduled, or regular NCs? + //assuming scheduled for now + if (__misc_state["free runs available"]) + { + subentry.modifiers.listAppend("free runs"); + } + if (__misc_state["have hipster"]) + { + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + } + } + else + { + subentry.entries.listClear(); + subentry.modifiers.listClear(); + output_final_fight_info = true; + } + + } + if (output_final_fight_info) + { + image_name = "Demon Summon"; + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + { + subentry.entries.listAppend("Talk to Lord Spookyraven."); + } + else if (my_path().id == PATH_VAMPIRE) + { + subentry.entries.listAppend("Fight the path-specific boss."); + } + else + { + subentry.modifiers.listAppend("elemental resistance"); + subentry.entries.listAppend("Fight Lord Spookyraven."); + + if ($effect[Red Door Syndrome].have_effect() == 0 && my_meat() > 1000 && black_market_available() && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING && my_path().id != PATH_POCKET_FAMILIARS && $item[can of black paint].item_is_usable()) + { + subentry.entries.listAppend("A can of black paint can help with fighting him." + (my_meat() < 20000 ? " Bit pricy. (1k meat)" : "")); + } + } + } + //This is covered elsewhere, in that mess of if statements up there. + /*if (use_fast_route && !recipe_was_autoread_with_glasses) + { + if ($item[unstable fulminate].available_amount() == 0 && !output_final_fight_info && $item[bottle of Chateau de Vinegar].available_amount() == 0 && $item[bottle of Chateau de Vinegar].available_amount() == 0 && !recipe_will_be_autoread) + subentry.entries.listAppend("Remember to wear Spookyraven's spectacles/read the recipe if you haven't."); + } + else if (!recipe_was_autoread) + subentry.entries.listAppend("Remember to read the recipe if you haven't.");*/ + } + } + } + + boolean [location] relevant_locations; + relevant_locations[$location[the haunted ballroom]] = true; + relevant_locations[$location[summoning chamber]] = true; + relevant_locations[$location[the haunted wine cellar]] = true; + relevant_locations[$location[The Haunted Boiler Room]] = true; + relevant_locations[$location[The Haunted Laundry Room]] = true; + foreach l in $locations[the haunted kitchen,the haunted conservatory,the haunted bathroom,the haunted gallery,the haunted laboratory,the haunted storage room] + relevant_locations[l] = true; + + + task_entries.listAppend(ChecklistEntryMake(image_name, url, subentry, relevant_locations).ChecklistEntrySetIDTag("Council L11 quest spookyraven manor")); +} + +boolean [item] __dense_liana_machete_items = $items[antique machete,Machetito,Muculent machete,Papier-mâchéte]; + +int numberOfDenseLianaFoughtInShrine(location shrine) +{ + //need to check the combat names due to wanderers: + int dense_liana_defeated = 0; + string [int] area_combats_seen = shrine.locationSeenCombats(); + foreach key, s in area_combats_seen + { + if (s == "dense liana") + dense_liana_defeated += 1; + } + return dense_liana_defeated; +} + +void QLevel11HiddenCityInit() { + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL11Worship"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Hidden City Quest"; + state.image_name = "Hidden City"; + + state.state_boolean["Hospital finished"] = (get_property_int("hiddenHospitalProgress") >= 8); + state.state_boolean["Bowling alley finished"] = (get_property_int("hiddenBowlingAlleyProgress") >= 8); + state.state_boolean["Apartment finished"] = (get_property_int("hiddenApartmentProgress") >= 8); + state.state_boolean["Office finished"] = (get_property_int("hiddenOfficeProgress") >= 8); + + state.state_boolean["need machete for liana"] = true; + foreach it in __dense_liana_machete_items { + if (it.available_amount() > 0) { + state.state_boolean["need machete for liana"] = false; + break; + } + } + + int lianas_left; + foreach shrine in $locations[a massive ziggurat,an overgrown shrine (northwest),an overgrown shrine (southwest),an overgrown shrine (northeast),an overgrown shrine (southeast)] { + lianas_left += 3 - shrine.numberOfDenseLianaFoughtInShrine(); + } + state.state_int["lianas left"] = lianas_left; + + if (get_property_int("hiddenBowlingAlleyProgress") >= 1 && get_property_int("hiddenHospitalProgress") >= 1 && get_property_int("hiddenApartmentProgress") >= 1 && get_property_int("hiddenOfficeProgress") >= 1 && $location[a massive Ziggurat].numberOfDenseLianaFoughtInShrine() >= 3 && state.mafia_internal_step >= 4) + state.state_int["lianas left"] = 0; + + if (state.state_int["lianas left"] == 0) + state.state_boolean["need machete for liana"] = false; + + if (!__misc_state["can equip just about any weapon"]) { + state.state_boolean["need machete for liana"] = false; + } + + + if (state.finished) { + state.state_boolean["Hospital finished"] = true; + state.state_boolean["Bowling alley finished"] = true; + state.state_boolean["Apartment finished"] = true; + state.state_boolean["Office finished"] = true; + state.state_boolean["need machete for liana"] = false; + } + + __quest_state["Level 11 Hidden City"] = state; +} + + +void generateHiddenAreaUnlockForShrine(string [int] description, location shrine) { + item machete = $item[none]; + + foreach macheteItem in __dense_liana_machete_items { + if (macheteItem.available_amount() > 0) { + machete = macheteItem; + } + } + + boolean hasMachete = machete != $item[none]; + boolean hasMacheteEquipped = machete.equipped_amount() > 0; + int lianaRemaining = MAX(0, 3 - shrine.numberOfDenseLianaFoughtInShrine()); + + if (shrine != $location[a massive ziggurat]) { + description.listAppend("Unlock by visiting " + shrine + "."); + } + + if (lianaRemaining > 0 && shrine.noncombatTurnsAttemptedInLocation() == 0) { + description.listAppend("Fight " + lianaRemaining + " more liana."); + + if (__misc_state["can equip just about any weapon"] && my_path().id != PATH_POCKET_FAMILIARS) { + if (!hasMachete) { + description.listAppend("Acquire a machete first."); + } else if (!hasMacheteEquipped) { + description.listAppend(HTMLGenerateSpanFont("Equip your " + machete + " first.", "red")); + } + } + } +} + +void QLevel11HiddenCityGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 11 Hidden City"].in_progress) + return; + if (__quest_state["Level 11"].mafia_internal_step <3 ) //strange bug where questL11MacGuffin = started, questL11Manor = step1 + return; + + QuestState base_quest_state = __quest_state["Level 11 Hidden City"]; + ChecklistEntry entry; + entry.url = "place.php?whichplace=hiddencity"; + entry.image_lookup_name = base_quest_state.image_name; + entry.tags.id = "Council L11 quest hidden city"; + entry.should_indent_after_first_subentry = true; + entry.should_highlight = $locations[the hidden temple, the hidden apartment building, the hidden hospital, the hidden office building, the hidden bowling alley, the hidden park, a massive ziggurat,an overgrown shrine (northwest),an overgrown shrine (southwest),an overgrown shrine (northeast),an overgrown shrine (southeast)] contains __last_adventure_location; + + if (!__quest_state["Hidden Temple Unlock"].finished) + { + return; + } + else if (!locationAvailable($location[the hidden park])) + { + entry.image_lookup_name = "Hidden Temple"; + entry.url = "place.php?whichplace=woods"; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + subentry.entries.listAppend("Unlock the hidden city via the hidden temple."); + if ($item[the Nostril of the Serpent].available_amount() == 0 && !get_property_ascension("lastTempleButtonsUnlock")) + subentry.entries.listAppend("Need nostril of the serpent."); + if ($item[stone wool].available_amount() > 0 && my_path().id != PATH_G_LOVER) + { + if ($effect[Stone-Faced].have_effect() == 0) + entry.url = "inventory.php?ftext=stone+wool"; + subentry.entries.listAppend(pluralise($item[stone wool]) + " available."); + } + if (my_path().id == PATH_G_LOVER) + { + subentry.modifiers.listAppend("-combat"); + if (__iotms_usable[lookupItem("genie bottle")]) + { + subentry.entries.listAppend("Genie wish for the \"stone-faced\" effect, then adventure in the temple."); + } + } + entry.subentries.listAppend(subentry); + } + else + { + if (true) + { + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + entry.subentries.listAppend(subentry); + } + //8 appears to be "finished"--"got stone triangle" + //7 appears to be "defeated the protector spirit"--"have stone sphere" + //2-6 appears to be "number of bowling balls used + 1" (only for bowling alley) + //1 appears to be "area unlocked" + boolean hidden_tavern_unlocked = get_property_ascension("hiddenTavernUnlock"); + boolean janitors_relocated_to_park = get_property_ascension("relocatePygmyJanitor"); + boolean have_machete = false; + + have_machete = __dense_liana_machete_items.available_amount() > 0; + int bowling_progress = get_property_int("hiddenBowlingAlleyProgress"); + int hospital_progress = get_property_int("hiddenHospitalProgress"); + int apartment_progress = get_property_int("hiddenApartmentProgress"); + int office_progress = get_property_int("hiddenOfficeProgress"); + + if (!base_quest_state.state_boolean["need machete for liana"]) + have_machete = true; + + boolean at_last_spirit = false; + + if (bowling_progress == 8 && hospital_progress == 8 && apartment_progress == 8 && office_progress == 8 || $item[stone triangle].available_amount() == 4) + { + at_last_spirit = true; + ChecklistSubentry subentry; + subentry.header = "Massive Ziggurat"; + //Instead of checking for four stone triangles, we check for the lack of all four stone spheres. That way it should detect properly after you fight the boss (presumably losing stone triangles), and lost? + + int spheres_available = $item[moss-covered stone sphere].available_amount() + $item[dripping stone sphere].available_amount() + $item[crackling stone sphere].available_amount() + $item[scorched stone sphere].available_amount(); + + if (spheres_available > 0) + { + subentry.entries.listAppend("Acquire stone triangles"); + } + else + { + if ($location[a massive ziggurat].numberOfDenseLianaFoughtInShrine() <3 && $location[a massive ziggurat].noncombatTurnsAttemptedInLocation() == 0) + { + generateHiddenAreaUnlockForShrine(subentry.entries,$location[a massive ziggurat]); + } + else + { + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + { + subentry.entries.listAppend("Talk to the protector spectre."); + } + else + { + subentry.modifiers.listAppend("elemental damage"); + subentry.entries.listAppend(`Fight the protector spectre! ({pluralise(3-$location[a massive ziggurat].numberOfDenseLianaFoughtInShrine(), "liana left", "lianas left")})`); + } + } + } + + entry.subentries.listAppend(subentry); + } + if (!at_last_spirit) + { + if ((!janitors_relocated_to_park && !$monster[pygmy janitor].is_banished()) || (!have_machete && my_path().id != PATH_POCKET_FAMILIARS)) + { + ChecklistSubentry subentry; + subentry.header = "Hidden Park"; + + subentry.modifiers.listAppend("-combat"); + if (!have_machete && my_path().id != PATH_POCKET_FAMILIARS) + { + int turns_remaining = MAX(0, 7 - $location[the hidden park].turnsAttemptedInLocation()); + string line; + line += "Adventure for "; + if (turns_remaining == 1) + line += "One More Turn"; + else + line += turns_remaining.int_to_wordy() + " more turns"; + line += " here for antique machete to clear dense lianas."; + if (canadia_available()) + line += "|Or potentially use muculent machete by acquiring forest tears. (kodama, Outskirts of Camp Logging Camp, 30% drop or clover)"; + subentry.entries.listAppend(line); + } + if (!janitors_relocated_to_park) + subentry.entries.listAppend("Potentially relocate janitors to park via non-combat."); + else + subentry.entries.listAppend("Acquire useful items from dumpster with -combat."); + if (__misc_state["have hipster"]) + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + if (__misc_state["free runs available"]) + subentry.modifiers.listAppend("free runs"); + if (my_basestat($stat[muscle]) < 62) + { + string line = "Will need " + (62 - my_basestat($stat[muscle])) + " more muscle to equip machete."; + subentry.entries.listAppend(line); + } + + entry.subentries.listAppend(subentry); + } + } + + if (apartment_progress < 8) { + ChecklistSubentry subentry; + subentry.header = "Hidden Apartment"; + if (apartment_progress == 7 || $item[moss-covered stone sphere].available_amount() > 0) { + subentry.entries.listAppend("Place moss-covered stone sphere in shrine."); + } else if (apartment_progress == 0) { + generateHiddenAreaUnlockForShrine(subentry.entries,$location[an overgrown shrine (Northwest)]); + } else { + int totalTurnsSpent = $location[the hidden apartment building].turns_spent; + + int delayForNextNoncombat; + + if (totalTurnsSpent < 9) { + delayForNextNoncombat = 8 - totalTurnsSpent; + } else { + delayForNextNoncombat = 7 - (totalTurnsSpent - 9) % 8; + } + + string [int] curseSources; + curseSources.listAppend("• Fighting a shaman."); + if (hidden_tavern_unlocked) { + curseSources.listAppend("• Drinking a cursed punch from the tavern."); + } else { + curseSources.listAppend("• " + HTMLGenerateSpanFont("Drinking a cursed punch from the tavern after you unlock it.", "grey")); + } + + if ($effect[thrice-cursed].have_effect() > 0) { + subentry.entries.listAppend("You're thrice-cursed. Fight the protector spirit!"); + } else if ($effect[twice-cursed].have_effect() > 0) { + subentry.entries.listAppend("Need 1 more curse. Get cursed by:" + curseSources.HTMLGenerateIndentedText()); + } else if ($effect[once-cursed].have_effect() > 0) { + subentry.entries.listAppend("Need 2 more curses. Get cursed by:" + curseSources.HTMLGenerateIndentedText()); + } else { + subentry.entries.listAppend("Need 3 more curses. Get cursed by:" + curseSources.HTMLGenerateIndentedText()); + } + + if (delayForNextNoncombat > 0) { + subentry.entries.listAppend("Delay for " + pluralise(delayForNextNoncombat, "turn", "turns") + " to fight spirit."); + } else { + subentry.entries.listAppend("Fight spirit next turn by choosing " + HTMLGenerateSpanOfClass("[Go to the Thrice-Cursed Penthouse]", "r_bold")); + } + + // Warnings + if (my_class() == $class[pastamancer] && my_thrall() == $thrall[Vampieroghi] && my_thrall().level >= 5) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Change your thrall - Vampieroghi will remove curses.", "red")); + } + + if ($effect[Ancient Fortitude].have_effect() > 0 && $effect[thrice-cursed].have_effect() == 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Remove Ancient Fortitude effect - you will not be cursed while that effect is up.", "red")); + } + + if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && $skill[Shake it off].skill_is_usable()) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Avoid using Shake It Off to heal", "red") + ", it'll remove the curse."); + } + + if (__misc_state["have hipster"]) { + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + } + } + entry.subentries.listAppend(subentry); + } + if (office_progress < 8) { + ChecklistSubentry subentry; + subentry.header = "Hidden Office"; + if (office_progress == 7 || $item[crackling stone sphere].available_amount() > 0) { + subentry.entries.listAppend("Place crackling stone sphere in shrine."); + } else if (office_progress == 0){ + generateHiddenAreaUnlockForShrine(subentry.entries,$location[an overgrown shrine (Northeast)]); + } else { + int numberOfFilesFound = $item[McClusky file (page 1)].available_amount() + $item[McClusky file (page 2)].available_amount() + $item[McClusky file (page 3)].available_amount() + $item[McClusky file (page 4)].available_amount() + $item[McClusky file (page 5)].available_amount(); + int numberOfFilesLeft = 5 - numberOfFilesFound; + + boolean hasMcCluskyFile = $item[McClusky file (complete)].available_amount() > 0; + boolean hasBoringBinderClip = $item[Boring binder clip].available_amount() > 0; + + int totalTurnsSpent = $location[the hidden office building].turns_spent; + + int delayForNextNoncombat = (totalTurnsSpent == 0) ? 5 : (4 - (totalTurnsSpent - 1) % 5); + + if (!hasMcCluskyFile && numberOfFilesLeft > 0) { + subentry.entries.listAppend("Kill " + pluralise(numberOfFilesLeft, "more pygmy witch accountant", "more pygmy witch accountants") + " for their files."); + } + + if (delayForNextNoncombat == 0) { + if (hasMcCluskyFile) { + subentry.entries.listAppend("Fight the Ancient protector spirit next turn by choosing " + HTMLGenerateSpanOfClass("[Knock on the boss's office door]", "r_bold")); + } else if (!hasBoringBinderClip) { + subentry.entries.listAppend("Find the binder clip next turn by choosing " + HTMLGenerateSpanOfClass("[Raid the supply cabinet]", "r_bold")); + } else { + subentry.entries.listAppend(HTMLGenerateSpanFont("Don't have the full McClusky files but noncombat is next turn. Consider adventuring in the apartment building.", "red")); + } + } else { + string message = "Delay for " + pluralise(delayForNextNoncombat, "turn", "turns") + " to"; + if (hasBoringBinderClip || hasMcCluskyFile) { + message += " fight spirit."; + } else { + message += " find boring binder clip."; + } + subentry.entries.listAppend(message); + } + + if (__misc_state["have hipster"]) { + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + } + } + entry.subentries.listAppend(subentry); + } + if (hospital_progress < 8) { + + ChecklistSubentry subentry; + subentry.header = "Hidden Hospital"; + + if (hospital_progress == 7 || $item[dripping stone sphere].available_amount() > 0) { + subentry.entries.listAppend("Place dripping stone sphere in shrine."); + } else if (hospital_progress == 0) { + generateHiddenAreaUnlockForShrine(subentry.entries,$location[an overgrown shrine (Southwest)]); + } else { + boolean [item] outfitPieces = $items[bloodied surgical dungarees,surgical mask,head mirror].makeConstantItemArrayMutable(); + + # TODO maybe support it differently, the scalpel will still drop in that case + if (__misc_state["can equip just about any weapon"]) { + outfitPieces[$item[half-size scalpel]] = true; + } + + if (__misc_state["Torso aware"]) { + outfitPieces[$item[surgical apron]] = true; + } + + item [int] ownedOutfitPieces; + item [int] unequippedOutfitPieces; + + string unownedOutfitMessage = "Fight pygmy surgeons to get surgeon gear:"; + foreach outfitPiece in outfitPieces { + if (outfitPiece.available_amount() > 0) { + ownedOutfitPieces.listAppend(outfitPiece); + + if (outfitPiece.equipped_amount() == 0) { + unequippedOutfitPieces.listAppend(outfitPiece); + } + } else { + unownedOutfitMessage += "|* • " + outfitPiece; + } + } + + if (unequippedOutfitPieces.count() > 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip your " + unequippedOutfitPieces.listJoinComponents(", ", "and") + " first.", "red")); + } + + if (ownedOutfitPieces.count() < 5) { + subentry.entries.listAppend(unownedOutfitMessage); + subentry.modifiers.listAppend("olfact surgeon"); + } + + int numberOfEquippedPieces = ownedOutfitPieces.count() - unequippedOutfitPieces.count(); + subentry.entries.listAppend((numberOfEquippedPieces * 10) + "% chance to fight spirit."); + + int totalTurnsSpent = $location[The Hidden Hospital].turns_spent; + subentry.entries.listAppend(HTMLGenerateSpanFont("Alternatively, burn " + (31 - totalTurnsSpent) + " more turns.", "grey")); + } + + entry.subentries.listAppend(subentry); + } + + if (bowling_progress < 8) { + + ChecklistSubentry subentry; + + subentry.header = "Hidden Bowling Alley"; + subentry.modifiers.listAppend("+150% item, olfact bowler"); + + if (bowling_progress == 7 || $item[scorched stone sphere].available_amount() > 0) { + subentry.entries.listAppend("Place scorched stone sphere in shrine."); + } else if (bowling_progress == 0) { + generateHiddenAreaUnlockForShrine(subentry.entries,$location[an overgrown shrine (southeast)]); + } else { + int numberOfRollsLeft = 6 - bowling_progress; + int bowlingBallsNeeded = numberOfRollsLeft - $item[bowling ball].available_amount_including_closet(); + int bowlingBallsInInventory = $item[bowling ball].available_amount(); + + if (bowlingBallsNeeded > 0) { + subentry.entries.listAppend("Find " + bowlingBallsNeeded + " more bowling balls by fighting pygmy bowlers."); + } + + if (numberOfRollsLeft > 0) { + subentry.entries.listAppend("Adventure " + numberOfRollsLeft + " more times with bowling balls to fight spirit."); + } + + if (hidden_tavern_unlocked) { + if (!$monster[drunk pygmy].is_banished()) { + if ($item[bowl of scorpions].item_amount() == 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Buy bowl of scorpions from the Hidden Tavern to free run.", "red")); + } else { + subentry.entries.listAppend("Use bowl of scorpions on drunk pygmy for free run."); + } + } + } else { + subentry.entries.listAppend(HTMLGenerateSpanFont("Unlock the hidden tavern for free runs from drunk pygmies.", "grey")); + } + } + + entry.subentries.listAppend(subentry); + } + + if (!at_last_spirit) + { + if ($location[a massive ziggurat].numberOfDenseLianaFoughtInShrine() < 3) { + ChecklistSubentry subentry; + subentry.header = "Massive Ziggurat"; + generateHiddenAreaUnlockForShrine(subentry.entries,$location[a massive ziggurat]); + entry.subentries.listAppend(subentry); + } + + if (!hidden_tavern_unlocked && my_path().id != PATH_G_LOVER && my_path().id != PATH_BEES_HATE_YOU) + { + ChecklistSubentry subentry; + subentry.header = "Hidden Tavern"; + boolean should_output = true; + + if ($item[book of matches].available_amount() > 0) + subentry.entries.listAppend(HTMLGenerateSpanFont("Use book of matches.", "red")); + else + { + if (janitors_relocated_to_park) + subentry.entries.listAppend("Possibly acquire and use book of matches from janitors. (Pygmy janitors, Hidden Park, 20% drop)"); + else + subentry.entries.listAppend("Possibly acquire and use book of matches from janitors. (Pygmy janitors, everywhere in the hidden city, 20% drop)"); + + string [int] tavern_provides; + if (bowling_progress < 7 && __misc_state["free runs usable"]) + tavern_provides.listAppend("Free runs from drunk pygmys."); + if (__misc_state["can drink just about anything"]) + { + if (apartment_progress < 8) + tavern_provides.listAppend("Curses for hidden apartment."); + int adventures_given = 15; + if ($skill[the ode to booze].skill_is_usable()) + adventures_given += 6; + + if (my_path().id != PATH_SLOW_AND_STEADY) + tavern_provides.listAppend("Nightcap drink. (Fog Murderer for " + adventures_given + " adventures)"); + } + if (tavern_provides.count() > 0) + subentry.entries.listAppend("Hidden Tavern provides:|*" + tavern_provides.listJoinComponents("|*")); + else + should_output = false; //don't bother, no reason to... I think? + + } + if (should_output) + entry.subentries.listAppend(subentry); + } + } + } + + if (entry.subentries.count() > 0) { + task_entries.listAppend(entry); + } +} + +void QLevel11HiddenTempleInit() +{ + QuestState state; + + if (get_property_ascension("lastTempleUnlock")) + QuestStateParseMafiaQuestPropertyValue(state, "finished"); + else if (__quest_state["Level 2"].startable) + { + QuestStateParseMafiaQuestPropertyValue(state, "started"); + } + else + QuestStateParseMafiaQuestPropertyValue(state, "unstarted"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_EXPLOSIONS) state.finished = true; + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Hidden Temple Unlock"; + state.image_name = "spooky forest"; + + __quest_state["Hidden Temple Unlock"] = state; +} + +void QLevel11HiddenTempleGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Hidden Temple Unlock"].in_progress) + return; + if (my_path().id == PATH_G_LOVER) return; + if (my_path().id == PATH_SEA) return; + + QuestState base_quest_state = __quest_state["Hidden Temple Unlock"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + + if (delayRemainingInLocation($location[the spooky forest]) > 0) + { + string hipster_text = ""; + if (__misc_state["have hipster"]) + { + hipster_text = " (use " + __misc_state_string["hipster name"] + ")"; + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + } + string line = "Delay for " + pluralise(delayRemainingInLocation($location[the spooky forest]), "turn", "turns") + hipster_text + "."; + subentry.entries.listAppend(line); + subentry.entries.listAppend("Run -combat after that."); + } + else + { + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("Run -combat in the spooky forest."); + } + if (__misc_state["free runs available"]) + { + subentry.modifiers.listAppend("free runs"); + subentry.entries.listAppend("Free run from low-stat monsters."); + } + + int ncs_remaining = 0; + + if ($item[spooky sapling].available_amount() == 0) + { + if (my_meat() < 100) + subentry.entries.listAppend("Obtain 100 meat for spooky sapling."); + else + subentry.entries.listAppend("Acquire spooky sapling.|*Follow the old road" + __html_right_arrow_character + "Talk to the hunter" + __html_right_arrow_character + "Buy a tree"); + ncs_remaining += 1; + } + + if ($item[tree-holed coin].available_amount() == 0) + { + if ($item[spooky temple map].available_amount() == 0) + { + //no coin, no map + subentry.entries.listAppend("Acquire tree-holed coin, then map.|*Explore the stream" + __html_right_arrow_character + "Squeeze into the cave"); + ncs_remaining += 2; + } + else + { + //no coin, have map, nothing to do here + } + } + else + { + if ($item[spooky temple map].available_amount() == 0) + { + //coin, no map + subentry.entries.listAppend("Acquire spooky temple map.|*Brave the dark thicket" + __html_right_arrow_character + "Follow the coin" + __html_right_arrow_character + "Insert coin to continue"); + + ncs_remaining += 1; + } + else + { + //wait, what? + subentry.entries.listAppend("how did we get here?"); + } + } + if ($item[spooky-gro fertilizer].item_amount() == 0) + { + subentry.entries.listAppend("Acquire spooky-gro fertilizer.|*Brave the dark thicket" + __html_right_arrow_character + "Investigate the dense foliage" + (in_hardcore() ? "" : "|*Or pull.")); + ncs_remaining += 1; + } + if ($item[spooky temple map].available_amount() > 0 && $item[spooky-gro fertilizer].item_amount() > 0 && $item[spooky sapling].available_amount() > 0) + { + subentry.modifiers.listClear(); + subentry.entries.listClear(); + subentry.entries.listAppend("Use the spooky temple map."); + } + + if (ncs_remaining > 0) + { + float spooky_forest_nc_rate = clampNormalf(1.0 - (85.0 + combat_rate_modifier()) / 100.0); + + float turns_remaining = -1.0; + float turns_per_nc = 7.0; + if (spooky_forest_nc_rate > 0.0) + turns_per_nc = MIN(7.0, 1.0 / spooky_forest_nc_rate); + + turns_remaining = ncs_remaining.to_float() * turns_per_nc; + turns_remaining += delayRemainingInLocation($location[the spooky forest]); + + subentry.entries.listAppend("~" + turns_remaining.roundForOutput(1) + " turns remain at " + combat_rate_modifier().floor() + "% combat."); + } + + if (my_level() < 6) + subentry.entries.listAppend("There's also another unlock quest at level six, but it's slower."); + else + subentry.entries.listAppend("There's also another unlock quest, but it's slower."); + + ChecklistEntry entry = ChecklistEntryMake(base_quest_state.image_name, "place.php?whichplace=woods", subentry, $locations[the spooky forest]); + entry.tags.id = "Council spooky forest hidden temple"; //ich... + + if (!__quest_state["Manor Unlock"].state_boolean["ballroom song effectively set"]) + { + entry.subentries[0].entries.listAppend(HTMLGenerateSpanOfClass("Wait until -combat ballroom song set.", "r_bold")); + future_task_entries.listAppend(entry); + } + else + { + task_entries.listAppend(entry); + } +} + + +void QLevel11Init() +{ + //questL11MacGuffin, questL11Manor, questL11Palindome, questL11Pyramid, questL11Worship + //hiddenApartmentProgress, hiddenBowlingAlleyProgress, hiddenHospitalProgress, hiddenOfficeProgress, hiddenTavernUnlock + //relocatePygmyJanitor, relocatePygmyLawyer + + + /* + gnasirProgress is a bitmap of things you've done with Gnasir to advance desert exploration: + + stone rose = 1 + black paint = 2 + killing jar = 4 + worm-riding manual pages (15) = 8 + successful wormride = 16 + */ + if (true) + { + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL11MacGuffin"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_GREY_GOO) state.finished = true; + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "MacGuffin Quest"; + state.image_name = "MacGuffin"; + state.council_quest = true; + + if (my_level() >= 11 || my_path().id == PATH_EXPLOSIONS) + state.startable = true; + + state.state_boolean["have diary"] = state.mafia_internal_step >= 3; + + __quest_state["Level 11"] = state; + __quest_state["MacGuffin"] = state; + } + + QLevel11CopperheadInit(); + QLevel11PyramidInit(); + QLevel11DesertInit(); + QLevel11PalindomeInit(); + QLevel11ManorInit(); + QLevel11HiddenCityInit(); + QLevel11HiddenTempleInit(); +} + +void QLevel11BaseGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 11"].in_progress) + return; + + QuestState base_quest_state = __quest_state["Level 11"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + string url = ""; + string image_name = base_quest_state.image_name; + boolean make_entry_future = false; + + if (base_quest_state.mafia_internal_step < 2) + { + subentry.header = "Unlock the Black Market"; + image_name = "Black Forest"; + //This needs better spading. + //Side info: in the livestream, the flag [blackforestexplore] => 55 was visible, as well as [blackforestprogress] => 5 + + //Unlock black market: + url = "place.php?whichplace=woods"; + + string combat_rate_string = "+5% combat"; + + subentry.modifiers.listAppend(combat_rate_string); + subentry.entries.listAppend("Adventure in the Black Forest with " + combat_rate_string + "."); + + if ($item[blackberry galoshes].available_amount() > 0) + { + if ($item[blackberry galoshes].equipped_amount() == 0) + { + string line = HTMLGenerateSpanFont("Equip blackberry galoshes", "red") + " to speed up exploration"; + + if (!$item[blackberry galoshes].can_equip()) + { + make_entry_future = true; + line += ", once you can equip them"; + } + line += "."; + subentry.entries.listAppend(line); + } + } + else + { + if (!in_hardcore()) + subentry.entries.listAppend("Possibly pull and wear the blackberry galoshes?"); + //it seems unlikely finding the galoshes in HC would be worth it? maaaybe in no-familiar paths, but probably not? sneaky pete, perhaps + //subentry.entries.listAppend("Possibly make the blackberry galoshes via NC, if you get three blackberries."); + } + + boolean [familiar] relevant_familiars = $familiars[reassembled blackbird,reconstituted crow]; + familiar bird_needed_familiar; + item bird_needed; + if (my_path().id == PATH_BEES_HATE_YOU) + { + bird_needed_familiar = $familiar[reconstituted crow]; + bird_needed = $item[reconstituted crow]; + } + else + { + bird_needed_familiar = $familiar[reassembled blackbird]; + bird_needed = $item[reassembled blackbird]; + } + item [int] missing_components = missingComponentsToMakeItem(bird_needed); + + //FIXME clean this up: + //FIXME test if having a reassembled blackbird in your inventory is more than enough in any path? + //FIXME handle both reassembled blackbird and reconstituted crow as familiar + + if (missing_components.count() > 0 && bird_needed.available_amount() == 0) + { + subentry.modifiers.listAppend("+100% item"); //FIXME what is the drop rate for bees hate you items? we don't know... + } + + if (bird_needed_familiar.familiar_is_usable()) + { + if (bird_needed.available_amount() == 0 && missing_components.count() == 0) + { + subentry.entries.listAppend("Make a " + bird_needed + "."); + } + else if (!(relevant_familiars contains my_familiar()) && bird_needed.available_amount() == 0) + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Bring along " + bird_needed_familiar + " to speed up quest.", "red")); + } + else if ((relevant_familiars contains my_familiar()) && bird_needed.available_amount() > 0) + { + subentry.entries.listAppend("Bring along another familiar, you don't need to use the bird anymore."); + } + } + if (bird_needed.available_amount() == 0) + { + string line = ""; + line = "Acquire " + bird_needed + "."; + + if (missing_components.count() == 0) + line += " You have all the parts, make it."; + else + line += " Parts needed: " + missing_components.listJoinComponents(", ", "and"); + subentry.entries.listAppend(line); + } + int black_forest_progress = get_property_int("blackForestProgress"); + if (black_forest_progress >= 1 && __quest_state["Level 13"].state_boolean["wall of skin will need to be defeated"] && $item[beehive].available_amount() == 0) + { + subentry.entries.listAppend("Find a beehive for the tower, from the non-combat.|*" + listMake("Head toward the blackberry patch", "Head toward the buzzing sound", "Keep going", "Almost... there...").listJoinComponents(__html_right_arrow_character) + "|*Costs two extra turns. Skip if you're towerkilling."); + } + //if (black_forest_progress > 0) + subentry.entries.listAppend("~" + (black_forest_progress * 20) + "% finished."); + } + else if (base_quest_state.mafia_internal_step < 3) + { + //Vacation: + if ($item[forged identification documents].available_amount() == 0) + { + subentry.header = "Buy forged identification documents"; + image_name = "__item forged identification documents"; + url = "shop.php?whichshop=blackmarket"; + subentry.entries.listAppend("From the black market."); + if ($item[can of black paint].available_amount() == 0) + subentry.entries.listAppend("Also buy a can of black paint while you're there, for the desert quest."); + } + else + { + url = "place.php?whichplace=desertbeach"; + subentry.header = "Vacation at the shore"; + image_name = "__item your father's MacGuffin diary"; + string diary_owner = "your father's"; + if (my_path().id == PATH_GELATINOUS_NOOB) + diary_owner = "an archeologist's"; + subentry.entries.listAppend("To acquire " + diary_owner + " diary."); + } + } + else if (base_quest_state.mafia_internal_step < 4) + { + //Have diary: + if (to_item("2334").available_amount() == 0) //$item[holy macguffin] has shadow aliasing problem + { + //nothing to say + //subentry.entries.listAppend("Retrieve the MacGuffin."); + return; + } + else + { + url = "place.php?whichplace=town"; + subentry.entries.listAppend("Speak to the council."); + } + } + + ChecklistEntry entry = ChecklistEntryMake(image_name, url, subentry, $locations[the black forest]); + entry.tags.id = "Council L11 quest diary"; + + if (make_entry_future) + future_task_entries.listAppend(entry); + else + task_entries.listAppend(entry); +} + +void QLevel11GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id == PATH_COMMUNITY_SERVICE) + return; + QLevel11RonGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel11ShenGenerateTasks(task_entries, optional_task_entries, future_task_entries); + if (!__misc_state["in run"]) + return; + //Such a complicated quest. + QLevel11BaseGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel11ManorGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel11PalindomeGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel11DesertGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel11PyramidGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel11HiddenCityGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel11HiddenTempleGenerateTasks(task_entries, optional_task_entries, future_task_entries); +} + + +static +{ + item [string][int] __if_potions_with_numeric_modifiers; + + + /*void ItemFilterInitialise() + { + boolean [string] modifier_names = $strings[Meat Drop,Initiative,Muscle,Mysticality,Moxie,Muscle Percent,Mysticality Percent,Moxie Percent]; + + foreach modifier_name in modifier_names + { + __if_potions_with_numeric_modifiers[modifier_name] = listMakeBlankItem(); + } + foreach it in $items[] + { + if (it.inebriety > 0 || it.fullness > 0 || it.spleen > 0) continue; + effect e = it.to_effect(); + if (e == $effect[none]) continue; + foreach modifier_name in modifier_names + { + if (e.numeric_modifier(modifier_name) > 0.0) + { + __if_potions_with_numeric_modifiers[modifier_name].listAppend(it); + } + } + } + } + + + ItemFilterInitialise();*/ +} + + +void ItemFilterInitialisePotionsForModifier(string numeric_modifier) +{ + if (__if_potions_with_numeric_modifiers contains numeric_modifier) + return; + __if_potions_with_numeric_modifiers[numeric_modifier] = listMakeBlankItem(); + + foreach it in $items[] + { + if (it.inebriety > 0 || it.fullness > 0 || it.spleen > 0) continue; + effect e = it.to_effect(); + if (e == $effect[none]) continue; + if (e.numeric_modifier(numeric_modifier) != 0.0) + { + __if_potions_with_numeric_modifiers[numeric_modifier].listAppend(it); + } + } +} + + +item [int] ItemFilterGetPotionsWithNumericModifiers(string [int] modifiers) +{ + item [int] potions; + boolean [item] seen_potions; + foreach key, modifier_string in modifiers + { + item [int] first_layer_list; + if (!(__if_potions_with_numeric_modifiers contains modifier_string)) + ItemFilterInitialisePotionsForModifier(modifier_string); + + first_layer_list = __if_potions_with_numeric_modifiers[modifier_string]; + + + foreach key, it in first_layer_list + { + if (!it.is_unrestricted()) + continue; + if (seen_potions contains it) + continue; + potions.listAppend(it); + seen_potions[it] = true; + } + } + + return potions; +} + +item [int] ItemFilterGetPotionsCouldPullToAddToNumericModifier(string [int] modifiers, float minimum_modifier, boolean [item] blacklist) +{ + item [int] relevant_potions_first_layer = ItemFilterGetPotionsWithNumericModifiers(modifiers); + + item [int] relevant_potions; + foreach key, it in relevant_potions_first_layer + { + if (it.available_amount() > 0) continue; + if (!it.tradeable && it.storage_amount() == 0) continue; + if (!it.item_is_usable()) continue; + effect e = it.to_effect(); + if (e.have_effect() > 0) continue; + if (!e.effect_is_usable()) continue; + float v = 0; + foreach key, modifier_string in modifiers + v += e.numeric_modifier(modifier_string); + if (v != 0.0 && v >= minimum_modifier && !(blacklist contains it)) + { + relevant_potions.listAppend(it); + } + } + if (modifiers.count() == 2) + sort relevant_potions by -(value.effect_modifier("effect").numeric_modifier(modifiers[0]) + value.effect_modifier("effect").numeric_modifier(modifiers[1])); + else + sort relevant_potions by -value.effect_modifier("effect").numeric_modifier(modifiers[0]); + + return relevant_potions; +} + + +item [int] ItemFilterGetPotionsCouldPullToAddToNumericModifier(string modifier_string, float minimum_modifier, boolean [item] blacklist) +{ + return ItemFilterGetPotionsCouldPullToAddToNumericModifier(listMake(modifier_string), minimum_modifier, blacklist); +} + + +void QLevel12Init() +{ + //questL12War + //fratboysDefeated, hippiesDefeated + //sidequestArenaCompleted, sidequestFarmCompleted, sidequestJunkyardCompleted, sidequestLighthouseCompleted, sidequestNunsCompleted, sidequestOrchardCompleted + //warProgress + + //Sidequests: + //state_boolean["Lighthouse Finished"] + //state_boolean["Orchard Finished"] + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL12War"); + + // Finish the quest state in paths that don't need the tile. + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + // if (my_path().id == PATH_GREY_GOO) state.finished = true; // can complete in gg + if (my_path().id == PATH_SEA) state.finished = true; + + state.quest_name = "Island War Quest"; + state.image_name = "island war"; + state.council_quest = true; + + state.state_boolean["Arena Finished"] = (get_property("sidequestArenaCompleted") != "none"); + state.state_boolean["Farm Finished"] = (get_property("sidequestFarmCompleted") != "none"); + state.state_boolean["Junkyard Finished"] = (get_property("sidequestJunkyardCompleted") != "none"); + state.state_boolean["Lighthouse Finished"] = (get_property("sidequestLighthouseCompleted") != "none"); + state.state_boolean["Nuns Finished"] = (get_property("sidequestNunsCompleted") != "none"); + state.state_boolean["Orchard Finished"] = (get_property("sidequestOrchardCompleted") != "none"); + state.state_boolean["War started"] = (state.mafia_internal_step >= 2); + state.state_boolean["War in progress"] = state.state_boolean["War started"] && !state.finished; + + state.state_int["hippies left on battlefield"] = 1000 - get_property_int("hippiesDefeated"); + state.state_int["frat boys left on battlefield"] = 1000 - get_property_int("fratboysDefeated"); + + if (state.finished) + { + state.state_boolean["Arena Finished"] = true; + state.state_boolean["Farm Finished"] = true; + state.state_boolean["Junkyard Finished"] = true; + state.state_boolean["Lighthouse Finished"] = true; + state.state_boolean["Nuns Finished"] = true; + state.state_boolean["Orchard Finished"] = true; + } + if (my_path().id == PATH_EXPLOSIONS) + state.state_boolean["Lighthouse Finished"] = true; + int quests_completed_hippy = 0; + int quests_completed_frat = 0; + + foreach s in $strings[sidequestArenaCompleted,sidequestFarmCompleted,sidequestJunkyardCompleted,sidequestLighthouseCompleted,sidequestNunsCompleted,sidequestOrchardCompleted] + { + string property_value = get_property(s); + if (property_value == "hippy") + quests_completed_hippy += 1; + else if (property_value == "fratboy") + quests_completed_frat += 1; + } + + state.state_int["Quests completed for hippies"] = quests_completed_hippy; + state.state_int["Quests completed for frat boys"] = quests_completed_frat; + + if (!state.finished) + { + //define state.state_string["Side seemingly fighting for"] + //"hippy", "frat boys", "both", "" + + if (state.state_int["Quests completed for hippies"] > 0) + state.state_string["Side seemingly fighting for"] = "hippy"; + if (state.state_int["Quests completed for frat boys"] > 0) + state.state_string["Side seemingly fighting for"] = "frat boys"; + + if (state.state_int["hippies left on battlefield"] == 1000 && state.state_int["frat boys left on battlefield"] != 1000) + state.state_string["Side seemingly fighting for"] = "hippy"; + if (state.state_int["hippies left on battlefield"] != 1000 && state.state_int["frat boys left on battlefield"] == 1000) + state.state_string["Side seemingly fighting for"] = "frat boys"; + if (state.state_int["hippies left on battlefield"] != 1000 && state.state_int["frat boys left on battlefield"] != 1000) + state.state_string["Side seemingly fighting for"] = "both"; + if (state.state_int["Quests completed for hippies"] > 0 && state.state_int["Quests completed for frat boys"] > 0) + state.state_string["Side seemingly fighting for"] = "both"; + } + + if (false) + { + //Internal debugging: + state.state_boolean["Arena Finished"] = false; + state.state_boolean["Farm Finished"] = false; + state.state_boolean["Junkyard Finished"] = false; + state.state_boolean["Lighthouse Finished"] = false; + state.state_boolean["Nuns Finished"] = false; + state.state_boolean["Orchard Finished"] = false; + } + + if (my_level() >= 12 && my_path().id != PATH_EXPLOSIONS) + state.startable = true; + + __quest_state["Level 12"] = state; + __quest_state["Island War"] = state; +} + +void QLevel12GenerateTasksSidequests(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Level 12"]; + if (!base_quest_state.state_boolean["Orchard Finished"] && my_path().id != PATH_2CRS) + { + string [int] details; + string [int] modifiers; + + string url = "bigisland.php?place=orchard"; + modifiers.listAppend("+1000% item"); + if (__misc_state["yellow ray potentially available"]) + modifiers.listAppend("potential YR"); + + location next_location; + monster pickpocket_monster = $monster[none]; + boolean need_gland = false; + if ($item[heart of the filthworm queen].available_amount() > 0) + { + modifiers.listClear(); + details.listAppend("Go talk to the hippies to complete quest."); + } + else if ($effect[Filthworm Guard Stench].have_effect() > 0 || $item[Filthworm royal guard scent gland].available_amount() > 0) + { + if ($effect[Filthworm Guard Stench].have_effect() == 0) + { + url = "inventory.php?ftext=filthworm+royal+guard+scent+gland"; + details.listAppend("Use filthworm royal guard scent gland."); + } + modifiers.listClear(); + modifiers.listAppend("+meat"); + details.listAppend("Defeat the filthworm queen in the queen's chamber."); + next_location = $location[the filthworm queen's chamber]; + } + else if ($effect[Filthworm Drone Stench].have_effect() > 0 || $item[Filthworm drone scent gland].available_amount() > 0) + { + if ($effect[Filthworm Drone Stench].have_effect() == 0) + { + url = "inventory.php?ftext=filthworm+drone+scent+gland"; + details.listAppend("Use filthworm drone scent gland"); + } + details.listAppend("Adventure with +item in the guards' chamber."); + need_gland = true; + pickpocket_monster = $monster[filthworm royal guard]; + next_location = $location[the royal guard chamber]; + } + else if ($effect[Filthworm Larva Stench].have_effect() > 0 || $item[filthworm hatchling scent gland].available_amount() > 0) + { + if ($effect[Filthworm Larva Stench].have_effect() == 0) + { + url = "inventory.php?ftext=filthworm+hatchling+scent+gland"; + details.listAppend("Use filthworm hatchling scent gland"); + } + details.listAppend("Adventure with +item in the feeding chamber."); + need_gland = true; + pickpocket_monster = $monster[filthworm drone]; + next_location = $location[the feeding chamber]; + } + else + { + details.listAppend("Adventure with +item in the hatching chamber."); + need_gland = true; + pickpocket_monster = $monster[larval filthworm]; + next_location = $location[the hatching chamber]; + } + + if (__misc_state["can pickpocket"] && pickpocket_monster != $monster[none]) + { + int total_initiative_needed = pickpocket_monster.base_initiative; + int initiative_needed = total_initiative_needed - initiative_modifier(); + if (initiative_needed > 0) + details.listAppend("Need " + initiative_needed + "% more initiative to pickpocket every turn."); + } + + if (need_gland) + { + float effective_item_drop = next_location.item_drop_modifier_for_location() / 100.0; + //FIXME take into account pickpocketing, init, etc. + float average_glands_found_per_combat = MIN(1.0, (effective_item_drop + 1.0) * 0.1); + float turns_per_gland = -1.0; + if (average_glands_found_per_combat != 0.0) + turns_per_gland = 1.0 / average_glands_found_per_combat; + details.listAppend("~" + roundForOutput(turns_per_gland, 1) + " turns per gland."); + } + + optional_task_entries.listAppend(ChecklistEntryMake("Island War Orchard", url, ChecklistSubentryMake("Island War Orchard Quest", modifiers, details), $locations[the hatching chamber, the feeding chamber, the royal guard chamber, the filthworm queen's chamber]).ChecklistEntrySetIDTag("Council L12 quest side orchard filthworms")); + } + if (!base_quest_state.state_boolean["Farm Finished"]) + { + string [int] details; + details.listAppend("Great flappin' beasts, with webbed feet and bills! dooks!"); + string [int] modifiers; + modifiers.listAppend("+meat"); + + string [int] tasks; + + boolean [string] area_known_ncs = $strings[Cornered!,Cornered Again!,How Many Corners Does this Stupid Barn Have!?]; + int ncs_seen = 0; + string [int] location_ncs = $location[McMillicancuddy's Barn].locationSeenNoncombats(); + foreach key, s in location_ncs + { + if (area_known_ncs contains s) + { + ncs_seen += 1; + } + } + + if (ncs_seen < 3 || my_location() == $location[McMillicancuddy's Barn]) + { + tasks.listAppend("make a fence out of the barbed wire"); + tasks.listAppend("knock over the lantern"); + tasks.listAppend("dump out the drum"); + details.listAppend((!get_property_boolean("chaosButterflyThrown") ? "Remember to use a chaos butterfly in combat before clearing the barn.|Then " : "Remember: ") + tasks.listJoinComponents(", ", "and") + "."); + + + if (__misc_state["free runs available"]) + modifiers.listAppend("free runs in barn"); + } + optional_task_entries.listAppend(ChecklistEntryMake("Island War Farm", "bigisland.php?place=farm", ChecklistSubentryMake("Island War Farm Quest", modifiers, details), $locations[mcmillicancuddy's farm,mcmillicancuddy's barn,mcmillicancuddy's pond,mcmillicancuddy's back 40,mcmillicancuddy's other back 40,mcmillicancuddy's granary,mcmillicancuddy's bog,mcmillicancuddy's family plot,mcmillicancuddy's shady thicket]).ChecklistEntrySetIDTag("Council L12 quest side farm")); + } + if (!base_quest_state.state_boolean["Nuns Finished"] && my_path().id != PATH_2CRS) + { + string [int] details; + int meat_gotten = get_property_int("currentNunneryMeat"); + int meat_remaining = 100000 - meat_gotten; + details.listAppend(meat_remaining + " meat remaining."); + + float meat_drop_multiplier = meat_drop_modifier() / 100.0 + 1.0; + vec2i brigand_meat_drop_range = vec2iMake(800 * meat_drop_multiplier, 1200 * meat_drop_multiplier); + vec2i turn_range; + if (brigand_meat_drop_range.x != 0 && brigand_meat_drop_range.y != 0) + turn_range = vec2iMake(ceil(to_float(meat_remaining) / to_float(brigand_meat_drop_range.y)), + ceil(to_float(meat_remaining) / to_float(brigand_meat_drop_range.x))); + if (my_path().id == PATH_2CRS) + turn_range = Vec2iMake(MAX(100, turn_range.x), MAX(100, turn_range.y)); + + + + string turns_extra = "."; + string [int] extra_details; + if (get_property("boomBoxSong") == "Total Eclipse of Your Meat") + { + vec2i brigand_meat_drop_range_sing = vec2iMake(820 * meat_drop_multiplier, 1230 * meat_drop_multiplier); + vec2i turn_range_sing; + if (brigand_meat_drop_range_sing.x != 0 && brigand_meat_drop_range_sing.y != 0) + turn_range_sing = vec2iMake(ceil(to_float(meat_remaining) / to_float(brigand_meat_drop_range_sing.y)), + ceil(to_float(meat_remaining) / to_float(brigand_meat_drop_range_sing.x))); + turns_extra = ", if you don't sing."; + if (turn_range_sing.x == turn_range.x && turn_range_sing.y == turn_range.y) + { + turns_extra = "."; + } + else if (turn_range_sing.x == turn_range_sing.y) + details.listAppend(pluralise(turn_range_sing.x, "turn", "turns") + " remaining, if you sing."); + else + details.listAppend("[" + turn_range_sing.x + " to " + turn_range_sing.y + "] turns remaining, if you sing."); + extra_details.listAppend("Be sure to Sing Along with your boombox every turn."); + /*float without = meat_remaining / (1000.0 * meat_drop_multiplier); + float with = meat_remaining / (1025.0 * meat_drop_multiplier); + details.listAppend("Singing saves " + (without - with) + " turns.");*/ + } + + + //FIXME consider looking into tracking how long until the semi-rare item runs out, for turn calculation + if (turn_range.x == turn_range.y) + details.listAppend(pluralise(turn_range.x, "turn", "turns") + " remaining" + turns_extra); + else + details.listAppend("[" + turn_range.x + " to " + turn_range.y + "] turns remaining" + turns_extra); + + + if (turn_range.x == 1 && turn_range.y == 2) + { + float chance = 1.0 - TriangularDistributionCalculateCDF(meat_remaining + 1, brigand_meat_drop_range.x, brigand_meat_drop_range.y); + details.listAppend((chance * 100.0).floor() + "% chance of completing in one turn."); + } + + if ($item[ice nine].available_amount() == 0 && __misc_state["can equip just about any weapon"] && $item[ice harvest].available_amount() >= 9 && $item[ice nine].is_unrestricted() && $item[miracle whip].available_amount() == 0) //is this safe? unfinished ice sculpture is really nice, and ice bucket in sneaky pete... + details.listAppend("Possibly make and equip an ice nine. (+30% meat 1h weapon)"); + + if ($effect[Sinuses For Miles].have_effect() > 0 && !get_property_ascension("lastTempleAdventures") && $item[stone wool].available_amount() > 0 && get_property_ascension("lastTempleUnlock")) + details.listAppend("Potentially use stone wool and visit the hidden temple to extend Sinuses for Miles for 3 turns."); + + + if (my_path().id == PATH_HEAVY_RAINS && $skill[Make it Rain].skill_is_usable() && turn_range.y > 1) + details.listAppend("Cast Make it Rain each fight. (+300%? meat)"); + if ($item[Sneaky Pete's leather jacket (collar popped)].equipped_amount() > 0 && turn_range.y > 1) + details.listAppend("Could unpop your collar. (+20% meat)"); + + if (__misc_state_int["pulls available"] > 0 && meat_drop_modifier() < 1000.0) + { + int limit = 100; + if (meat_drop_modifier() < 800.0) + limit = 50; + if (my_path().id == PATH_G_LOVER) + limit = 25; + limit = 0; //show them all - we'll go based off of turns saved + boolean [item] blacklist = $items[uncle greenspan's bathroom finance guide,black snowcone]; + item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Meat Drop", limit, blacklist); + string [int] relevant_potions_output; + float average_turns_currently = meat_remaining / ((meat_drop_modifier() / 100.0 + 1.0) * 1000.0); + foreach key, it in relevant_potions + { + effect e = it.to_effect(); + if (!e.effect_is_usable()) + continue; + if (!it.item_is_usable()) + continue; + //average_turns_currently - + float meat_dropped_per_turn_with_item = ((meat_drop_modifier() + e.numeric_modifier("meat drop")) / 100.0 + 1.0) * 1000.0; + float turns_saved = average_turns_currently - meat_remaining / meat_dropped_per_turn_with_item; + if (turns_saved < 1.0) continue; + relevant_potions_output.listAppend(it + " (" + e.numeric_modifier("meat drop").roundForOutput(0) + "%, " + turns_saved.roundForOutput(1) + " turns saved)"); + } + + if (relevant_potions_output.count() > 0) + details.listAppend("Could try pulling " + relevant_potions_output.listJoinComponents(", ", "or") + "."); + } + details.listAppendList(extra_details); + optional_task_entries.listAppend(ChecklistEntryMake("Island War Nuns", "bigisland.php?place=nunnery", ChecklistSubentryMake("Island War Nuns Quest", "+meat", details), $locations[the themthar hills]).ChecklistEntrySetIDTag("Council L12 quest side nuns")); + } + if (!base_quest_state.state_boolean["Junkyard Finished"]) + { + string [int] details; + if ($item[molybdenum magnet].available_amount() == 0) + { + details.listAppend("Talk to Yossarian first."); + } + else + { + location [item] items_and_locations; + items_and_locations[$item[molybdenum hammer]] = $location[Next to that Barrel with Something Burning in it]; + items_and_locations[$item[molybdenum pliers]] = $location[Near an Abandoned Refrigerator]; + items_and_locations[$item[molybdenum crescent wrench]] = $location[Over Where the Old Tires Are]; + items_and_locations[$item[molybdenum screwdriver]] = $location[Out By that Rusted-Out Car]; + boolean have_all = true; + + string [location][int] location_monsters; + location_monsters[$location[Next to that Barrel with Something Burning in it]] = listMake("tool batwinged", "vegetable"); + location_monsters[$location[Out By that Rusted-Out Car]] = listMake("tool vegetable", "erudite"); + location_monsters[$location[Near an Abandoned Refrigerator]] = listMake("tool spider", "batwinged"); + location_monsters[$location[Over Where the Old Tires Are]] = listMake("tool erudite", "spider"); + + location [int][monster] banishment_locations; //it's time we had a talk... about your hair! it's gone too far! + banishment_locations[1][$monster[batwinged gremlin]] = $location[Near an Abandoned Refrigerator]; + banishment_locations[1][$monster[erudite gremlin]] = $location[Out By that Rusted-Out Car]; + banishment_locations[1][$monster[spider gremlin]] = $location[Over Where the Old Tires Are]; + banishment_locations[1][$monster[vegetable gremlin]] = $location[Next to that Barrel with Something Burning in it]; + + + banishment_locations[0][$monster[batwinged gremlin]] = $location[Next to that Barrel with Something Burning in it]; + banishment_locations[0][$monster[erudite gremlin]] = $location[Over Where the Old Tires Are]; + banishment_locations[0][$monster[spider gremlin]] = $location[Near an Abandoned Refrigerator]; + banishment_locations[0][$monster[vegetable gremlin]] = $location[Out By that Rusted-Out Car]; + + foreach key in banishment_locations + { + foreach m in banishment_locations[key] + { + if (!m.is_banished()) + continue; + location l = banishment_locations[key][m]; + + if (key == 0 && location_monsters[l][key].contains_text("tool ")) + location_monsters[l][key] = "tool " + HTMLGenerateSpanFont(location_monsters[l][key].replace_string("tool ", ""), "grey", ""); + else + location_monsters[l][key] = HTMLGenerateSpanFont(location_monsters[l][key], "grey"); + } + } + + + + item [int] item_display_order = listMake($item[molybdenum hammer],$item[molybdenum pliers],$item[molybdenum crescent wrench],$item[molybdenum screwdriver]); //make a path + string [int] areas_left_strings; + //foreach it in items_and_locations + + string [location] location_shorthand_name; + location_shorthand_name[$location[Next to that Barrel with Something Burning in it]] = "Barrel"; + location_shorthand_name[$location[Out By that Rusted-Out Car]] = "Car"; + location_shorthand_name[$location[Near an Abandoned Refrigerator]] = "Refrigerator"; + location_shorthand_name[$location[Over Where the Old Tires Are]] = "Tires"; + + foreach key in item_display_order + { + item it = item_display_order[key]; + location loc = items_and_locations[it]; + if (it.available_amount() > 0) + { + continue; + } + else + have_all = false; + + string location_display_name; + if (location_shorthand_name contains loc) + location_display_name = location_shorthand_name[loc]; + else + location_display_name = loc.to_string().to_lower_case(); + + areas_left_strings.listAppend("" + location_display_name + " - " + location_monsters[loc].listJoinComponents(", ")); + } + if (areas_left_strings.count() > 0) + details.listAppend("Areas left:|*" + areas_left_strings.listJoinComponents("
|*")); + if (have_all) + details.listAppend("Talk to Yossarian to complete quest."); + else + { + if ($item[dictionary].available_amount() > 0 && $item[dictionary].item_is_usable()) + { + details.listAppend("Read from the dictionary to stasis gremlins."); + } + else if ($item[facsimile dictionary].available_amount() > 0 && $item[facsimile dictionary].item_is_usable()) + { + details.listAppend("Read from the facsimile dictionary to stasis gremlins."); + } + else if ($item[seal tooth].available_amount() > 0 && $item[seal tooth].item_is_usable()) + { + details.listAppend("Use your seal tooth to stasis gremlins."); + } + else if ($skill[suckerpunch].skill_is_usable()) + { + details.listAppend("Cast suckerpunch to stasis gremlins."); + } + else if ($item[seal tooth].item_is_usable() && my_path().id != PATH_ZOMBIE_SLAYER) + details.listAppend(HTMLGenerateSpanFont("Acquire a seal tooth", "red") + " to stasis gremlins. (from hermit)"); + else if ($item[beehive].available_amount() > 0) + details.listAppend("Use your beehive to stasis gremlins."); + + if (!$monster[A.M.C. gremlin].is_banished()) + details.listAppend("Potentially banish A.M.C. Gremlin."); + } + } + optional_task_entries.listAppend(ChecklistEntryMake("Island War Junkyard", "bigisland.php?place=junkyard", ChecklistSubentryMake("Island War Junkyard Quest", listMake("+DR", "+DA", "+HP", "+moxie"), details), $locations[next to that barrel with something burning in it,near an abandoned refrigerator,over where the old tires are,out by that rusted-out car]).ChecklistEntrySetIDTag("Council 12 quest side junkyard Yossarian")); + } + if (!base_quest_state.state_boolean["Lighthouse Finished"]) + { + string [int] details; + + int gunpowder_needed = MAX(0, 5 - $item[barrel of gunpowder].available_amount()); + + + string [int] modifiers; + if (gunpowder_needed > 0) + { + modifiers = listMake("+combat", "copies"); + details.listAppend("Need " + gunpowder_needed.pluralise("more barrel", "more barrels") + " of gunpowder."); + + + + //this is an approximation: + //off by a little over half a turn on average + float effective_combat_rate = (11.0 / 12.0) * clampNormalf(0.1 + combat_rate_modifier() / 100.0) + (1.0 / 12.0) * 1.0; + float turns_per_lobster = -1.0; + if (effective_combat_rate != 0.0) + turns_per_lobster = 1.0 / effective_combat_rate; + + + float turns_to_complete = gunpowder_needed.to_float() * turns_per_lobster; + + //I had the data lying around, so why not? + //misses <-10 and >30, but the estimate above will catch that + float [int][int] lfm_simulation_data; + lfm_simulation_data[5][-10] = 60.00; lfm_simulation_data[5][-5] = 40.02; lfm_simulation_data[5][0] = 29.92; lfm_simulation_data[5][5] = 23.84; lfm_simulation_data[5][10] = 19.76; lfm_simulation_data[5][15] = 16.84; lfm_simulation_data[5][20] = 14.66; lfm_simulation_data[5][25] = 13.00; lfm_simulation_data[4][-10] = 48.00; lfm_simulation_data[4][-5] = 32.27; lfm_simulation_data[4][0] = 24.20; lfm_simulation_data[4][5] = 19.29; lfm_simulation_data[4][10] = 16.00; lfm_simulation_data[4][15] = 13.68; lfm_simulation_data[4][20] = 11.96; lfm_simulation_data[4][25] = 10.63; lfm_simulation_data[3][-10] = 36.00; lfm_simulation_data[3][-5] = 24.53; lfm_simulation_data[3][0] = 18.47; lfm_simulation_data[3][5] = 14.78; lfm_simulation_data[3][10] = 12.34; lfm_simulation_data[3][15] = 10.59; lfm_simulation_data[3][20] = 9.26; lfm_simulation_data[3][25] = 8.20; lfm_simulation_data[2][-10] = 24.00; lfm_simulation_data[2][-5] = 16.79; lfm_simulation_data[2][0] = 12.84; lfm_simulation_data[2][5] = 10.38; lfm_simulation_data[2][10] = 8.68; lfm_simulation_data[2][15] = 7.40; lfm_simulation_data[2][20] = 6.40; lfm_simulation_data[2][25] = 5.60; lfm_simulation_data[1][-10] = 12.00; lfm_simulation_data[1][-5] = 9.19; lfm_simulation_data[1][0] = 7.17; lfm_simulation_data[1][5] = 5.72; lfm_simulation_data[1][10] = 4.66; lfm_simulation_data[1][15] = 3.87; lfm_simulation_data[1][20] = 3.29; lfm_simulation_data[1][25] = 2.84; lfm_simulation_data[5][26] = 12.71; lfm_simulation_data[5][27] = 12.44; lfm_simulation_data[5][28] = 12.18; lfm_simulation_data[5][29] = 11.93; lfm_simulation_data[5][30] = 11.69; lfm_simulation_data[4][26] = 10.40; lfm_simulation_data[4][27] = 10.17; lfm_simulation_data[4][28] = 9.96; lfm_simulation_data[4][29] = 9.75; lfm_simulation_data[4][30] = 9.56; lfm_simulation_data[3][26] = 8.01; lfm_simulation_data[3][27] = 7.83; lfm_simulation_data[3][28] = 7.65; lfm_simulation_data[3][29] = 7.48; lfm_simulation_data[3][30] = 7.32; lfm_simulation_data[2][26] = 5.46; lfm_simulation_data[2][27] = 5.33; lfm_simulation_data[2][28] = 5.20; lfm_simulation_data[2][29] = 5.07; lfm_simulation_data[2][30] = 4.96; lfm_simulation_data[1][26] = 2.76; lfm_simulation_data[1][27] = 2.69; lfm_simulation_data[1][28] = 2.62; lfm_simulation_data[1][29] = 2.56; lfm_simulation_data[1][30] = 2.50; + + if (lfm_simulation_data[gunpowder_needed] contains combat_rate_modifier().to_int()) + { + turns_to_complete = lfm_simulation_data[gunpowder_needed][combat_rate_modifier().to_int()]; + if (gunpowder_needed != 0.0) + turns_per_lobster = turns_to_complete / gunpowder_needed.to_float(); + } + + details.listAppend("~" + roundForOutput(turns_to_complete, 1) + " turns to complete quest at " + combat_rate_modifier().floor() + "% combat.|~" + roundForOutput(turns_per_lobster, 1) + " turns per lobster."); + + string macrometeorite_source; + + if ($skill[meteor lore].have_skill() && get_property_int("_macrometeoriteUses") < 10) + macrometeorite_source = "macrometeorite"; + else if (lookupItem("Powerful Glove").have() && 100 - get_property_int("_powerfulGloveBatteryPowerUsed") >= 10) + macrometeorite_source = "Replace Enemy"; + + if (macrometeorite_source != "") + { + details.listAppend("Could use " + macrometeorite_source + " on a wandering monster (portscan, voting, holiday monster...) to guarantee an LFM."); + if (macrometeorite_source == "Replace Enemy" && !lookupItem("Powerful Glove").equipped()) + details.listAppend("Equip the Powerful Glove, first."); + + if (lookupItem(""I Voted!" sticker").available_amount() > 0 && get_property_int("_voteFreeFights") >= 3) + { + if (total_turns_played() % 11 == 1 && get_property_int("lastVoteMonsterTurn") < total_turns_played()) + { + details.listAppend("Voting monster now!"); + } + else + { + int turns_to_next_voting_monster = 11 - (((total_turns_played() % 11) - 1 + 11) % 11); + details.listAppend("Voting monster will appear in " + pluralise(turns_to_next_voting_monster, "more turn", "more turns") + "."); + } + + } + } + + int sabersOwned = lookupItem("Fourth of May Cosplay Saber").available_amount() + lookupItem("replica Fourth of May Cosplay Saber").available_amount(); + + if (sabersOwned > 0 && get_property_int("_saberForceUses") < 5 && gunpowder_needed > 1) + { + int saber_fights_left = MIN(get_property_int("_saberForceMonsterCount"), 3); + boolean already_sabering_lfm = get_property_monster("_saberForceMonster") == $monster[lobsterfrogman] && saber_fights_left > 0; + + if (!already_sabering_lfm || already_sabering_lfm && saber_fights_left < gunpowder_needed) { + details.listAppend("Could Use the Force (friends) on a LFM to guarantee two more."); + + if (already_sabering_lfm && saber_fights_left > 1) //sabering now would waste some copies + details.listAppend("Finish fighting " + (saber_fights_left - 1).pluralise("more copy", "more copies") + ", first."); + else if (!lookupItem("Fourth of May Cosplay Saber").equipped()) + details.listAppend("Equip the Fourth of May saber, first."); + } + } + } + else + details.listAppend("Talk to the lighthouse keeper to finish quest."); + + + optional_task_entries.listAppend(ChecklistEntryMake("Island War Lighthouse", "bigisland.php?place=lighthouse", ChecklistSubentryMake("Island War Lighthouse Quest", modifiers, details), $locations[sonofa beach]).ChecklistEntrySetIDTag("Council L12 quest side lighthouse gunpowder LFM")); + } + if (!base_quest_state.state_boolean["Arena Finished"] && my_path().id != PATH_G_LOVER && my_path().id != PATH_POCKET_FAMILIARS) + { + string [int] modifiers; + modifiers.listAppend("+ML"); + float percent_done = clampf(get_property_int("flyeredML") / 10000.0 * 100.0, 0.0, 100.0); + int ml_remaining = 10000 - get_property_int("flyeredML"); + string [int] details; + if (percent_done >= 100.0) + { + modifiers.listClear(); + details.listAppend("Turn in quest."); + } + else + { + if ($item[jam band flyers].available_amount() == 0 && $item[rock band flyers].available_amount() == 0) + details.listAppend("Acquire fliers."); + details.listAppend(round(percent_done, 1) + "% ML completed, " + ml_remaining + " ML remains."); + } + + //Normally, this would be bigisland.php?place=concert + //But that could theoretically complete the quest for the wrong side, if they're wearing the wrong uniform and misclick. + optional_task_entries.listAppend(ChecklistEntryMake("Island War Arena", "bigisland.php", ChecklistSubentryMake("Island War Arena Quest", modifiers, details)).ChecklistEntrySetIDTag("Council L12 quest side arena")); + + if (ml_remaining > 0 && ($item[jam band flyers].available_amount() > 0 || $item[rock band flyers].available_amount() > 0)) + { + item it = $item[jam band flyers]; + if ($item[rock band flyers].available_amount() > 0 && $item[jam band flyers].available_amount() == 0) + it = $item[rock band flyers]; + task_entries.listAppend(ChecklistEntryMake(it, "", ChecklistSubentryMake("Flyer with " + it + " every combat", "+ML", details), -11).ChecklistEntrySetIDTag("Council L12 quest side advertise reminder")); + } + } +} + + +void QLevel12GenerateBattlefieldDescription(ChecklistSubentry subentry, string side, int enemies_remaining, int enemies_defeated_per_combat, string enemy_name, string enemy_name_plural, string boss_name, string [int] sidequest_list, string [int] base_sidequest_list) +{ + if (enemies_defeated_per_combat == 0) + return; + + int enemies_defeated = 1000 - enemies_remaining; + string line; + if (enemies_remaining > 0) + { + line = pluralise(enemies_remaining, enemy_name, enemy_name_plural) + " left."; + } + else + { + line += "Fight " + boss_name + "!"; + if (my_path().id == PATH_DEMIGUISE && $effect[Flared Nostrils].have_effect() > 0) + line += "|" + HTMLGenerateSpanFont("Remove Flared Nostrils", "red") + " or you will die."; + if (my_path().id == PATH_DEMIGUISE) + { + int damage_taken = 0; + damage_taken += ceil(my_maxhp() * 2.0 * (1.0 - elemental_resistance($element[stench]) / 100.0)); + if ($effect[flared nostrils].have_effect() > 0) + damage_taken += ceil(my_maxhp() * 2.0 * 2.0); + else + damage_taken += ceil(my_maxhp() * 2.0 * (1.0 - elemental_resistance($element[sleaze]) / 100.0)); + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+stench res", "r_element_stench_desaturated")); + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+sleaze res", "r_element_sleaze_desaturated")); + + line += "|Will take " + damage_taken + " damage at the start of combat"; + if (damage_taken >= my_maxhp()) + line += ", " + HTMLGenerateSpanFont("which you cannot survive", "red"); + line += "."; + line += "|Run " + HTMLGenerateSpanOfClass("stench", "r_element_stench") + " and " + HTMLGenerateSpanOfClass("sleaze", "r_element_sleaze") + " resistance."; + if (my_hp() != my_maxhp()) + line += "|" + HTMLGenerateSpanFont("Also restore your HP.", "red"); + } + } + + string outfit_name; + if (side == "hippy") + outfit_name = "War Hippy Fatigues"; + if (side == "frat boy") + outfit_name = "Frat Warrior Fatigues"; + + if (outfit_name != "") + { + item [int] missing_outfit_components = missing_outfit_components(outfit_name); + if (missing_outfit_components.count() > 0) + line += "|*Missing outfit piece" + (missing_outfit_components.count() > 1 ? "s" : "") + " " + missing_outfit_components.listJoinComponents(", ", "and") + "."; + } + int turns_remaining = ceiling(enemies_remaining.to_float() / enemies_defeated_per_combat.to_float()); + if (turns_remaining > 0) + { + line += "|*" + pluralise(turns_remaining, "turn", "turns") + " remaining."; + line += " " + pluralise(enemies_defeated_per_combat, enemy_name, enemy_name_plural) + " defeated per combat."; + } + int enemies_to_defeat_for_unlock = -1; + string area_to_unlock = ""; + string [int] areas_unlocked_but_not_completed; + + boolean [string] areas_blocked; + if (my_path().id == PATH_G_LOVER || my_path().id == PATH_POCKET_FAMILIARS) + areas_blocked["Arena"] = true; + + foreach key, sidequest in base_sidequest_list + { + if (areas_blocked[sidequest]) + continue; + if (!__quest_state["Level 12"].state_boolean[sidequest + " Finished"]) + { + areas_unlocked_but_not_completed.listAppend(sidequest); + } + } + + if (my_path().id != PATH_BUGBEAR_INVASION) //FIXME test against trendy bugbear chef being needed + { + if (side == "frat boy" && __misc_state["free runs usable"]) + subentry.modifiers.listAppend("possibly olfact Green Ops Soldier"); + else if (side == "hippy") + subentry.modifiers.listAppend("possibly olfact Sorority Operator"); + } + + int [int] unlock_threshold; + unlock_threshold[0] = 64; + unlock_threshold[1] = 192; + unlock_threshold[2] = 458; + + for i from 2 to 0 by -1 + { + int threshold = unlock_threshold[i]; + if (areas_blocked[sidequest_list[i]]) continue; + if (!__quest_state["Level 12"].state_boolean[sidequest_list[i] + " Finished"]) + { + if (enemies_defeated < threshold) + { + area_to_unlock = sidequest_list[i]; + enemies_to_defeat_for_unlock = threshold - enemies_defeated; + } + else + { + areas_unlocked_but_not_completed.listAppend(sidequest_list[i]); + } + } + } + + if (enemies_to_defeat_for_unlock != -1) + { + int turns_to_reach = ceiling(enemies_to_defeat_for_unlock.to_float() / enemies_defeated_per_combat.to_float()); + line += "|*" + pluralise(turns_to_reach, "turn", "turns") + " (" + pluralise(enemies_to_defeat_for_unlock, enemy_name, enemy_name_plural) + ") to unlock " + area_to_unlock + "."; + } + + if (areas_unlocked_but_not_completed.count() > 0 && enemies_remaining > 0) + line += "|*Quests accessible: " + areas_unlocked_but_not_completed.listJoinComponents(", ", "and") + "."; + + subentry.entries.listAppend(line); + + if (enemies_remaining == 0) + { + string [int] items_to_turn_in_for; + if (__quest_state["Level 13"].state_boolean["shadow will need to be defeated"]) + { + if (side == "hippy") + items_to_turn_in_for.listAppend("filthy poultices for shadow"); + else + items_to_turn_in_for.listAppend("gauze garters for shadow"); + } + + string line2 = "Also, turn in gear to your home camp."; + if (items_to_turn_in_for.count() > 0) + line2 += " Acquire " + items_to_turn_in_for.listJoinComponents(", ", "and") + ", etc."; + subentry.entries.listAppend(line2); + } +} + +void QLevel12ExplosionsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_EXPLOSIONS) return; + if (QuestState("questL12HippyFrat").finished) return; + + string [int] description; + string url = "place.php?whichplace=exploathing"; + + int fratboys_defeated = get_property_int("fratboysDefeated"); + int hippies_defeated = get_property_int("hippiesDefeated"); + int fratboys_left = clampi(333 - fratboys_defeated, 0, 333); + int hippies_left = clampi(333 - hippies_defeated, 0, 333); + + if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues")) + description.listAppend("Find a uniform. Either calculate the universe 151st + YR, wish + YR?, pull, or yellow-ray a battlefield enemy with the outfit?"); + else if (!is_wearing_outfit("War Hippy Fatigues") && !is_wearing_outfit("Frat Warrior Fatigues")) + { + description.listAppend("Equip a war outfit first."); + url = "inventory.php?which=2"; + } + if ($items[jacob's rung,haunted paddle-ball].available_amount() == 0) + { + description.listAppend((!in_hardcore() ? "Pull/" : "") + "YR a jacob's rung or haunted paddle-ball, from the top floor of spookyraven manor.|Jacob's adder in the Haunted Laboratory or possessed toy chest in the The Haunted Nursery have them."); + } + else if ($items[jacob's rung,haunted paddle-ball].equipped_amount() == 0) + { + if ($item[haunted paddle-ball].have()) + { + description.listAppend("Equip haunted paddle-ball first."); + url = "inventory.php?ftext=haunted+paddle-ball"; + } + else if ($item[jacob's rung].have()) + { + description.listAppend("Equip jacob's rung first."); + url = "inventory.php?ftext=jacob's+rung"; + } + } + boolean likely_fighting_frats = false; + if (fratboys_defeated > 0 && fratboys_defeated > hippies_defeated) + { + likely_fighting_frats = true; + if (fratboys_left <= 0) + description.listAppend("Fight the Man!"); + else + description.listAppend("Defeat " + pluralise(fratboys_left, "more fratboy", "more fratboys") + "."); + } + else + { + if (hippies_left <= 0) + description.listAppend("Fight the Big Wisniewski!"); + else + description.listAppend("Defeat " + pluralise(hippies_left, "more hippy", "more hippies") + "."); + } + + + int battlefield_turns = lookupLocation("The Exploaded Battlefield").turns_spent; + int turns_until_next_war_nc = -1; + if (battlefield_turns < 7) + turns_until_next_war_nc = 7 - battlefield_turns; + else + { + turns_until_next_war_nc = (battlefield_turns + 7) % 7; + if (turns_until_next_war_nc != 0) + turns_until_next_war_nc = 7 - turns_until_next_war_nc; + } + + if (turns_until_next_war_nc == 0) + { + description.listAppend("Non-combat now. Throw high-adventure consumable to speed up war."); + } + else + description.listAppend(pluraliseWordy(turns_until_next_war_nc, "More Turn", "more turns").capitaliseFirstLetter() + " until war NC."); + + + if (likely_fighting_frats) + { + if (lookupItems("space wine").available_amount() == 0) + description.listAppend("Buy some space wine for the non-combat."); + } + else + { + if (lookupItems("pie man was not meant to eat,space chowder").available_amount() == 0) + description.listAppend("Buy some space chowder for the non-combat."); + } + + task_entries.listAppend(ChecklistEntryMake("island war", url, ChecklistSubentryMake("War!", "", description), 0).ChecklistEntrySetIDTag("Council L12 quest exploathing path")); +} + +void QLevel12GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id == PATH_EXPLOSIONS) + QLevel12ExplosionsGenerateTasks(task_entries, optional_task_entries, future_task_entries); + if (!__quest_state["Level 12"].in_progress) + return; + + QuestState base_quest_state = __quest_state["Level 12"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + + task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, "island.php", subentry, $locations[the battlefield (frat uniform), the battlefield (hippy uniform), The Orcish Frat House, The Hippy camp, wartime frat house, wartime frat house (hippy disguise), wartime hippy camp, wartime hippy camp (frat disguise)]).ChecklistEntrySetIDTag("Council L12 quest battlefield")); + if (base_quest_state.mafia_internal_step < 2) + { + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("Start the war!"); + + float noncombat_rate = 1.0 - (.85 + combat_rate_modifier() / 100.0); + float turns_remaining = -1.0; + if (noncombat_rate != 0.0) + turns_remaining = 3.0 / noncombat_rate; + + + if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues")) + { + //FIXME suggest routes to doing both. + subentry.entries.listAppend("Need either the war hippy fatigues or frat warrior fatigues outfit."); + if ($familiar[slimeling].familiar_is_usable()) + subentry.modifiers.listAppend("slimeling?"); + } + else + { + string [int] stats_needed; + if (my_basestat($stat[moxie]) < 70) + stats_needed.listAppend((70 - my_basestat($stat[moxie])) + " more moxie"); + if (my_basestat($stat[mysticality]) < 70) + stats_needed.listAppend((70 - my_basestat($stat[mysticality])) + " more mysticality"); + if (stats_needed.count() == 0) + subentry.entries.listAppend("Wear war outfit, run -combat, adventure in other side's camp."); + else + { + string line = "Acquire " + stats_needed.listJoinComponents(", ", "and") + " to wear war outfit."; + if (my_class() == $class[pastamancer] && (is_wearing_outfit("War Hippy Fatigues") || is_wearing_outfit("Frat Warrior Fatigues"))) + line += "|Or... wear it anyways, because you're a pastamancer."; + subentry.entries.listAppend(line); + } + + + //need 70 moxie, 70 myst + + } + if (false && $item[talisman o' namsilat].available_amount() == 0 && !__quest_state["Level 11 Palindome"].finished && my_path().id != PATH_G_LOVER) + { + subentry.entries.listAppend("May want to " + HTMLGenerateSpanFont("acquire the Talisman o' Nam", "red") + " first."); + } + + subentry.entries.listAppend(generateTurnsToSeeNoncombat(85, 3, "start war")); + } + else + { + int sides_completed_hippy = base_quest_state.state_int["Quests completed for hippies"]; + int sides_completed_frat = base_quest_state.state_int["Quests completed for frat boys"]; + + int frat_boys_left = base_quest_state.state_int["frat boys left on battlefield"]; + int hippies_left = base_quest_state.state_int["hippies left on battlefield"]; + + int frat_boys_defeated_per_combat = powi(2, sides_completed_hippy); + int hippies_defeated_per_combat = powi(2, sides_completed_frat); + + if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && get_property("peteMotorbikeCowling") == "Rocket Launcher") + { + frat_boys_defeated_per_combat += 3; + hippies_defeated_per_combat += 3; + } + if (my_path().id == PATH_LICENSE_TO_ADVENTURE && get_property_boolean("bondWar")) + { + frat_boys_defeated_per_combat += 3; + hippies_defeated_per_combat += 3; + } + + + subentry.modifiers.listAppend("+item"); + if (hippies_left < 1000 || (frat_boys_left == 1000 && hippies_left == 1000) || sides_completed_frat > 0) + QLevel12GenerateBattlefieldDescription(subentry, "frat boy", hippies_left, hippies_defeated_per_combat, "hippy", "hippies", "The Big Wisniewski", listMake("Orchard", "Nuns", "Farm"), listMake("Lighthouse", "Junkyard", "Arena")); + //specific exception to deal with 151st cheating: + if ((frat_boys_left < 1000 && !(frat_boys_left >= 998 && hippies_left < 1000)) || (frat_boys_left == 1000 && hippies_left == 1000) || sides_completed_hippy > 0) + QLevel12GenerateBattlefieldDescription(subentry, "hippy", frat_boys_left, frat_boys_defeated_per_combat, "frat boy", "frat boys", "The Man", listMake("Lighthouse", "Junkyard", "Arena"), listMake("Orchard", "Nuns", "Farm")); + + + if (frat_boys_left == 1 && hippies_left == 1) + { + if ($item[flaregun].available_amount() > 0) + subentry.entries.listAppend("Wossname time! Adventure on battlefield, use a flaregun."); + else if (!in_hardcore()) + subentry.entries.listAppend("Pull a flaregun for wossname."); + else if (__misc_state["fax equivalent accessible"]) + subentry.entries.listAppend("Fax smarmy pirate, run +234% item (or YR) for flaregun for wossname."); + else + subentry.entries.listAppend("That almost was a wossname, but you needed more flare."); + } + + item [int] items_to_closet_for_desert_hippy; + foreach it in $items[reinforced beaded headband,round purple sunglasses,bullet-proof corduroys,beer helmet,distressed denim pants,bejeweled pledge pin] + { + if (it.available_amount() == 0) + continue; + items_to_closet_for_desert_hippy.listAppend(it); + } + + if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues")) + { + string line = "Visit the Arid, Extra-Dry Desert to find a hippy uniform."; + if (items_to_closet_for_desert_hippy.count() > 0) + line += "|But first closet " + items_to_closet_for_desert_hippy.listJoinComponents(", ", "and"); + subentry.entries.listAppend(line); + } + //FIXME Add when spaded: + /*else if (!have_outfit_components("War Hippy Fatigues")) + { + string line = "If you want a hippy uniform without visiting the battlefield, adventure in the Arid, Extra-Dry Desert."; + if (items_to_closet_for_desert_hippy.count() > 0) + line += "|But first closet " + items_to_closet_for_desert_hippy.listJoinComponents(", ", "and"); + subentry.entries.listAppend(line); + }*/ + + QLevel12GenerateTasksSidequests(task_entries, optional_task_entries, future_task_entries); + } + +} + + +effect [element] __flavour_lookup; +__flavour_lookup[$element[hot]] = $effect[Spirit of Cayenne]; +__flavour_lookup[$element[cold]] = $effect[Spirit of Peppermint]; +__flavour_lookup[$element[stench]] = $effect[Spirit of Garlic]; +__flavour_lookup[$element[spooky]] = $effect[Spirit of Wormwood]; +__flavour_lookup[$element[sleaze]] = $effect[Spirit of Bacon Grease]; + +float damageForElementAgainstElement(float base_damage, element attacking_element, element defence_element) +{ + if (defence_element == $element[none] || attacking_element == $element[none]) + return base_damage; + if (attacking_element == defence_element) + return MIN(base_damage, 1); + if (base_damage < 1) + return 0.0; + + boolean [element] relevant_elements = $elements[sleaze,stench,hot,spooky,cold]; + float [element,element] attack_versus_element; + foreach e1 in relevant_elements + { + foreach e2 in relevant_elements + { + if (e1 == e2) + attack_versus_element[e1][e2] = 0.0; + else + attack_versus_element[e1][e2] = 1.0; + } + } + attack_versus_element[$element[sleaze]][$element[stench]] = 2.0; + attack_versus_element[$element[sleaze]][$element[hot]] = 2.0; + + attack_versus_element[$element[stench]][$element[hot]] = 2.0; + attack_versus_element[$element[stench]][$element[spooky]] = 2.0; + + attack_versus_element[$element[hot]][$element[spooky]] = 2.0; + attack_versus_element[$element[hot]][$element[cold]] = 2.0; + + attack_versus_element[$element[spooky]][$element[cold]] = 2.0; + attack_versus_element[$element[spooky]][$element[sleaze]] = 2.0; + + attack_versus_element[$element[cold]][$element[sleaze]] = 2.0; + attack_versus_element[$element[cold]][$element[stench]] = 2.0; + + + float final = MAX(1, base_damage * attack_versus_element[attacking_element][defence_element]); + return final; +} + +element currentFlavourElement() +{ + foreach s, d in __flavour_lookup + { + if (d.have_effect() != 0) + return s; + } + return $element[none]; +} + +//Does not take into account spell criticals, as they're random by nature. +//FIXME support 100% criticals, I suppose + +Vec2f spellFormulaDamageRange(float multiplier, float damage_cap, Vec2f base_damage_range, float buffed_myst_percentage, element e) +{ + Vec2f range = Vec2fMake(0.0, 0.0); + range.x = base_damage_range.x + floor(my_buffedstat($stat[mysticality]) * buffed_myst_percentage) + numeric_modifier("spell damage"); + range.y = base_damage_range.y + floor(my_buffedstat($stat[mysticality]) * buffed_myst_percentage) + numeric_modifier("spell damage"); + + if (e != $element[none]) + { + float element_spell_damage = numeric_modifier(e + " spell damage"); + range.x += element_spell_damage; + range.y += element_spell_damage; + } + if (damage_cap > 0.0) + { + range.x = MIN(damage_cap, range.x); + range.y = MIN(damage_cap, range.y); + } + range.x *= multiplier; + range.y *= multiplier; + + range.x *= 1.0 + numeric_modifier("spell damage percent") / 100.0; + range.y *= 1.0 + numeric_modifier("spell damage percent") / 100.0; + + range.x = ceil(range.x); + range.y = ceil(range.y); + return range; +} + +Record SEDRDamageSource +{ + element element_type; + Vec2f damage_range; +}; + +SEDRDamageSource SEDRDamageSourceMake(element e, Vec2f damage_range) +{ + SEDRDamageSource result; + result.element_type = e; + result.damage_range = damage_range; + return result; +} + +void listAppend(SEDRDamageSource [int] list, SEDRDamageSource entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +float MLDamageMultiplier() +{ + float ml_damage_multiplier = 1.0; + ml_damage_multiplier = MIN(1.0, 1.0 - MIN(monster_level_adjustment() * 0.4 / 100.0, 0.5)); //FIXME investigate negative ML + return ml_damage_multiplier; +} + +Vec2f skillExpectedDamageRangeAlternate(monster m, skill s) +{ + //FIXME spade how on earth to properly calculate this + //for instance, how does elemental spell damage work? + float ml_damage_multiplier = MLDamageMultiplier(); + + element flavour_element = currentFlavourElement(); + + int monster_group_size = 1; + //FIXME add a bunch of these, or feature request to mafia: + if (m == $monster[wall of bones]) + monster_group_size = 100; //FIXME spade + + element [int] active_lanterns; + + if ($item[Rain-Doh green lantern].equipped_amount() > 0) + active_lanterns.listAppend($element[stench]); + else if ($item[snow mobile].equipped_amount() > 0) + active_lanterns.listAppend($element[cold]); + + element [int] pastamancer_active_lanterns = active_lanterns.listCopy(); + if ($item[porcelain porkpie].equipped_amount() > 0) //ONLY for pastamancer spells + pastamancer_active_lanterns.listAppend($element[sleaze]); + + + SEDRDamageSource [int] damage_sources; + + if (s == $skill[saucegeyser]) + { + float multiplier = MIN(3.0, monster_group_size); + element saucegeyser_element = $element[hot]; + if (m.defense_element == $element[hot] || m.defense_element == $element[sleaze] || m.defense_element == $element[stench]) + saucegeyser_element = $element[cold]; + else if (m.defense_element == $element[cold] || m.defense_element == $element[spooky]) + saucegeyser_element = $element[hot]; + else + { + //complicated + //we pick the one with more spell damage + //FIXME the exact calculation in-game is probably "whichever element does more damage" + //we should be doing that now, but we aren't handling hotform/coldform/etc + //or double-ice + //but spading suggests if hot spell damage is greater than cold spell damage, it'll always be hot against non-elementals. if they're equal, it's random. if it's less than, it's always cold. + if (numeric_modifier("hot spell damage") > numeric_modifier("cold spell damage")) + saucegeyser_element = $element[hot]; + else + saucegeyser_element = $element[cold]; + } + Vec2f saucegeyser_base = spellFormulaDamageRange(multiplier, 0.0, Vec2fMake(60.0, 70.0), 0.4, saucegeyser_element); + //FIXME is the group damage multiplier before or after bonus spell damage? + damage_sources.listAppend(SEDRDamageSourceMake(saucegeyser_element, saucegeyser_base)); + foreach key, e in active_lanterns + damage_sources.listAppend(SEDRDamageSourceMake(e, saucegeyser_base)); + } + else + return Vec2fMake(-1.0, -1.0); + Vec2f expected_damage_range = Vec2fMake(0.0, 0.0); + + foreach key, damage_source in damage_sources + { + expected_damage_range.x += ml_damage_multiplier * damageForElementAgainstElement(damage_source.damage_range.x, damage_source.element_type, m.defense_element); + expected_damage_range.y += ml_damage_multiplier * damageForElementAgainstElement(damage_source.damage_range.y, damage_source.element_type, m.defense_element); + } + + return expected_damage_range; +} + +float skillExpectedDamageAlternate(monster m, skill s) +{ + Vec2f range = skillExpectedDamageRangeAlternate(m, s); + return (range.x + range.y) * 0.5; +} + +//Active attacks, stinging damage. + +int PDS_DAMAGE_TYPE_NONE = 0; +int PDS_DAMAGE_TYPE_ACTIVE = 1; +int PDS_DAMAGE_TYPE_STINGING = 2; + +int PDS_SOURCE_TYPE_NONE = 0; +int PDS_SOURCE_TYPE_EFFECT = 1; +int PDS_SOURCE_TYPE_COMBAT_ITEM = 2; +int PDS_SOURCE_TYPE_EQUIPMENT = 3; +int PDS_SOURCE_TYPE_COMBAT_SKILL = 4; +int PDS_SOURCE_TYPE_FAMILIAR = 5; +int PDS_SOURCE_TYPE_BJORN_FAMILIAR = 6; //also crown + +record PassiveDamageSource +{ + int damage_type; + int source_type; //item, etc + float chance_of_acting; + int max_rounds_act; //0 for unlimited + + Vec2f [element] damage_range; + + + effect source_effect; //if effect + item source_effect_potion; //if effect + skill source_effect_skill; //if effect + item source_equipment; //if equipment + item source_combat_item; //if combat item + skill source_combat_skill; //if combat skill + familiar source_familiar; //familiar or bjorn familiar +}; + +PassiveDamageSource PassiveDamageSourceMake(int damage_type, int source_type) +{ + PassiveDamageSource pds; + pds.damage_type = damage_type; + pds.source_type = source_type; + pds.chance_of_acting = 1.0; + + return pds; +} + +void PassiveDamageSourceAddDamage(PassiveDamageSource pds, float min_damage, float max_damage, element e) +{ + Vec2f range; + range.x = min_damage; + range.y = max_damage; + if (pds.damage_range contains e) + { + range.x += pds.damage_range[e].x; + range.y += pds.damage_range[e].y; + } + pds.damage_range[e] = range; +} + +void PassiveDamageSourceAddDamage(PassiveDamageSource pds, float amount, element e) +{ + PassiveDamageSourceAddDamage(pds, amount, amount, e); +} + +void PassiveDamageSourceAddDamage(PassiveDamageSource pds, float physical_only) +{ + PassiveDamageSourceAddDamage(pds, physical_only, $element[none]); +} + +void listAppend(PassiveDamageSource [int] list, PassiveDamageSource entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +PassiveDamageSource listExactLastObject(PassiveDamageSource [int] list) //WARNING only works for linear arrays +{ + if (list.count() == 0) + return PassiveDamageSourceMake(0, 0); + return list[list.count() - 1]; +} + +static +{ + PassiveDamageSource [int] __known_sources; + void PDSInitialiseDoNotCallThis() + { + if (__known_sources.count() > 0) + return; + //Create every source: + //FIXME add + __known_sources.listAppend(PassiveDamageSourceMake(PDS_DAMAGE_TYPE_ACTIVE, PDS_SOURCE_TYPE_EQUIPMENT)); + __known_sources.listExactLastObject().PassiveDamageSourceAddDamage(1, 11, $element[none]); //FIXME WRONG + __known_sources.listExactLastObject().source_equipment = $item[hand in glove]; + + //FIXME wrong, but a good preliminary: + foreach it in $items[MagiMechTech NanoMechaMech,bottle opener belt buckle,old school calculator watch,ant hoe,ant pick,ant pitchfork,ant rake,ant sickle,fishy wand,moveable feast,oversized fish scaler,plastic pumpkin bucket,replica plastic pumpkin bucket,tiny bowler,cup of infinite pencils,double-ice box,smirking shrunken head,mr. haggis,stapler bear,dubious loincloth,muddy skirt,bottle of Goldschnöckered,acid-squirting flower,ironic oversized sunglasses,hippy protest button,cannonball charrrm bracelet,groovy prism necklace,spiky turtle shoulderpads,double-ice cap,parasitic headgnawer,eelskin hat,balloon shield,hot plate,Ol' Scratch's stove door,Oscus's garbage can lid,eelskin shield,eelskin pants,buddy bjorn,shocked shell,crown of thrones] + { + __known_sources.listAppend(PassiveDamageSourceMake(PDS_DAMAGE_TYPE_ACTIVE, PDS_SOURCE_TYPE_EQUIPMENT)); + __known_sources.listExactLastObject().PassiveDamageSourceAddDamage(1); + __known_sources.listExactLastObject().source_equipment = it; + } + foreach e in $effects[Skeletal Warrior,Skeletal Cleric,Skeletal Wizard,Bone Homie,Burning\, Man,Biologically Shocked,EVISCERATE!,Fangs and Pangs,Permanent Halloween,Curse of the Black Pearl Onion,Long Live GORF,Apoplectic with Rage,Dizzy with Rage,Quivering with Rage,Jabañero Saucesphere,Psalm of Pointiness,Drenched With Filth,Stuck-Up Hair,It's Electric!,Smokin',Jalapeño Saucesphere,Scarysauce,spiky shell,Boner Battalion] + { + __known_sources.listAppend(PassiveDamageSourceMake(PDS_DAMAGE_TYPE_ACTIVE, PDS_SOURCE_TYPE_EFFECT)); + __known_sources.listExactLastObject().PassiveDamageSourceAddDamage(1); + __known_sources.listExactLastObject().source_effect = e; + } + + foreach f in $familiars[] + { + if (!(f.physical_damage || f.elemental_damage) && !($familiars[Doppelshifter,Comma Chameleon,Mad Hatrack,Robot Reindeer,Fancypants Scarecrow,Mini-Adventurer] contains f)) + continue; + __known_sources.listAppend(PassiveDamageSourceMake(PDS_DAMAGE_TYPE_ACTIVE, PDS_SOURCE_TYPE_FAMILIAR)); + __known_sources.listExactLastObject().chance_of_acting = 0.333; //most + __known_sources.listExactLastObject().PassiveDamageSourceAddDamage(1); + __known_sources.listExactLastObject().source_familiar = f; + } + } + + PDSInitialiseDoNotCallThis(); +} + + +PassiveDamageSource [int] PDSGetActiveDamageSources() +{ + PassiveDamageSource [int] result; + + foreach key, pds in __known_sources + { + boolean should_add = false; + if (pds.source_type == PDS_SOURCE_TYPE_EFFECT) + { + if (pds.source_effect.have_effect() > 0) + should_add = true; + } + else if (pds.source_type == PDS_SOURCE_TYPE_COMBAT_ITEM) + { + //Nothing + } + else if (pds.source_type == PDS_SOURCE_TYPE_EQUIPMENT) + { + if (pds.source_equipment.equipped_amount() > 0) + should_add = true; + } + else if (pds.source_type == PDS_SOURCE_TYPE_COMBAT_SKILL) + { + //Nothing + } + else if (pds.source_type == PDS_SOURCE_TYPE_FAMILIAR) + { + if (my_familiar() == pds.source_familiar) + should_add = true; + } + else if (pds.source_type == PDS_SOURCE_TYPE_BJORN_FAMILIAR) + { + if (my_bjorned_familiar() == pds.source_familiar && $item[buddy bjorn].equipped_amount() > 0) + should_add = true; + if (my_enthroned_familiar() == pds.source_familiar && $item[crown of thrones].equipped_amount() > 0) + should_add = true; + } + if (should_add) + result.listAppend(pds); + } + + return result; +} + +//Does not return sources already in effect +PassiveDamageSource [int] PDSGetPotentialDamageSources() +{ + PassiveDamageSource [int] result; + + foreach key, pds in __known_sources + { + boolean should_add = false; + if (pds.source_type == PDS_SOURCE_TYPE_EFFECT) + { + if (pds.source_effect.have_effect() == 0) + { + if (pds.source_effect_potion.available_amount() > 0) + should_add = true; + if (pds.source_effect_skill.have_skill() && pds.source_effect_skill.is_unrestricted()) + should_add = true; + } + } + else if (pds.source_type == PDS_SOURCE_TYPE_COMBAT_ITEM) + { + if (pds.source_combat_item.available_amount() > 0) + should_add = true; + } + else if (pds.source_type == PDS_SOURCE_TYPE_EQUIPMENT) + { + if (pds.source_equipment.equipped_amount() == 0 && pds.source_equipment.can_equip() && pds.source_equipment.available_amount() > 0) + should_add = true; + } + else if (pds.source_type == PDS_SOURCE_TYPE_COMBAT_SKILL) + { + //FIXME is this correct? + if (pds.source_combat_skill.have_skill() && pds.source_combat_skill.is_unrestricted()) + should_add = true; + } + else if (pds.source_type == PDS_SOURCE_TYPE_FAMILIAR) + { + if (pds.source_familiar.familiar_is_usable() && my_familiar() != pds.source_familiar) + should_add = true; + } + else if (pds.source_type == PDS_SOURCE_TYPE_BJORN_FAMILIAR) + { + //FIXME add + } + if (should_add) + result.listAppend(pds); + } + + return result; +} + + +string [int] PDSGenerateDescriptionToUneffectPassives() +{ + string [int] effect_types; + string [int] equipment_types; + string [int] familiar_types; //you know, because we often bring two or more familiars... with us... avatar of susie? + string [int] bjorn_familiar_types; + foreach key, pds in PDSGetActiveDamageSources() + { + if (pds.source_type == PDS_SOURCE_TYPE_EFFECT) + { + effect_types.listAppend(pds.source_effect); + } + else if (pds.source_type == PDS_SOURCE_TYPE_EQUIPMENT) + { + equipment_types.listAppend(pds.source_equipment); + } + else if (pds.source_type == PDS_SOURCE_TYPE_FAMILIAR) + { + familiar_types.listAppend(pds.source_familiar); + } + else if (pds.source_type == PDS_SOURCE_TYPE_BJORN_FAMILIAR) + { + bjorn_familiar_types.listAppend(pds.source_familiar); + } + } + string [int] result; + if (effect_types.count() > 0) + result.listAppend("Uneffect " + effect_types.listJoinComponents(", ", "and") + "."); + if (equipment_types.count() > 0) + result.listAppend("Unequip " + equipment_types.listJoinComponents(", ", "and") + "."); + if (familiar_types.count() > 0) + result.listAppend("Change familiar from " + familiar_types.listJoinComponents(", ", "and") + "."); + if (bjorn_familiar_types.count() > 0) + result.listAppend("Change bjorn/crown familiar from " + bjorn_familiar_types.listJoinComponents(", ", "and") + "."); + if (get_property("_horsery") == "pale horse") //FIXME make generic + result.listAppend("Change to a different horse."); + + return result; +} + +boolean PDSFamiliarCouldPossiblyAttack(familiar f) +{ + if (f.combat) return true; + foreach key, pds in __known_sources + { + if (pds.source_type == PDS_SOURCE_TYPE_FAMILIAR) + { + if (f == pds.source_familiar) + return true; + } + } + return false; +} + + + +Record TFWMInternalModifier +{ + string description; + boolean have; + boolean obtainable_now; + boolean obtainable_theoretically; + float bonus; + + boolean from_familiar_equipment; +}; + +boolean TFWMInternalModifierEquals(TFWMInternalModifier a, TFWMInternalModifier b) +{ + if (a.description != b.description) + return false; + if (a.have != b.have) + return false; + if (a.obtainable_now != b.obtainable_now) + return false; + if (a.obtainable_theoretically != b.obtainable_theoretically) + return false; + if (a.bonus != b.bonus) + return false; + if (a.from_familiar_equipment != b.from_familiar_equipment) + return false; + return true; +} + +TFWMInternalModifier TFWMInternalModifierMake(string description, boolean have, boolean obtainable_now, boolean obtainable_theoretically, float bonus, boolean from_familiar_equipment) +{ + TFWMInternalModifier result; + result.description = description; + result.have = have; + result.obtainable_now = obtainable_now; + result.obtainable_theoretically = obtainable_theoretically; + result.bonus = bonus; + result.from_familiar_equipment = from_familiar_equipment; + + return result; +} + +TFWMInternalModifier TFWMInternalModifierMake(string description, boolean have, boolean obtainable_now, boolean obtainable_theoretically, float bonus) +{ + return TFWMInternalModifierMake(description, have, obtainable_now, obtainable_theoretically, bonus, false); +} + +TFWMInternalModifier TFWMInternalModifierMake() +{ + return TFWMInternalModifierMake("", false, false, false, 0); +} + +TFWMInternalModifier TFWMInternalModifierMake(skill s) +{ + effect e = s.to_effect(); + string description = s; + if (e != $effect[none] && e.have_effect() == 0) + description += " (cast)"; + + float weight_modifier = 0.0; + if (e != $effect[none]) + weight_modifier = e.numeric_modifier("familiar weight"); + else + weight_modifier = s.numeric_modifier("familiar weight"); + + return TFWMInternalModifierMake(description, s.skill_is_usable(), s.skill_is_usable(), s.skill_is_usable(), weight_modifier); +} + +TFWMInternalModifier TFWMInternalModifierMake(item equippable_item) +{ + if (equippable_item.available_amount() == 0) + return TFWMInternalModifierMake(); + float weight_modifier = equippable_item.numeric_modifier("familiar weight"); + + if (equippable_item == $item[crown of thrones]) + weight_modifier = 5.0; + + + string description = equippable_item; + if (equippable_item.equipped_amount() == 0) + description += " (equip)"; + + TFWMInternalModifier result = TFWMInternalModifierMake(description, true, true, true, weight_modifier); + + if (equippable_item.to_slot() == $slot[familiar]) + result.from_familiar_equipment = true; + return result; +} + +void listAppend(TFWMInternalModifier [int] list, TFWMInternalModifier entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + + +//Returns TRUE if they currently have, or can easily have, enough to pass. +//Example use: +/* + string [int] how; + string [int] immediately_obtainable; + string [int] missing_potentials; + FloatHandle missing_weight; + return !generateTowerFamiliarWeightMethod(how, immediately_obtainable, missing_potentials, missing_weight); +*/ +boolean generateTowerFamiliarWeightMethod(string [int] how, string [int] immediately_obtainable, string [int] missing_potentials, FloatHandle missing_weight) +{ + missing_weight.f = 0.0; + if (__quest_state["Level 13"].finished) //no need + return true; + if (!__misc_state["in run"]) + return true; + if (__misc_state["familiars temporarily blocked"]) + return true; + + + //Not the best of solutions, but... + + TFWMInternalModifier [int] weight_modifiers; + + //amphibian sympathy + weight_modifiers.listAppend(TFWMInternalModifierMake($skill[amphibian sympathy])); + //leash of linguini + weight_modifiers.listAppend(TFWMInternalModifierMake($skill[leash of linguini])); + //empathy of the newt + weight_modifiers.listAppend(TFWMInternalModifierMake($skill[empathy of the newt])); + //knob goblin pet-buffing spray + if ($item[knob goblin pet-buffing spray].available_amount() > 0 || dispensary_available() || $effect[heavy petting].have_effect() > 0 && false) + { + weight_modifiers.listAppend(TFWMInternalModifierMake("knob goblin pet-buffing spray", true, true, true, 5.0)); + } + else if (__misc_state["can equip just about any weapon"]) + { + weight_modifiers.listAppend(TFWMInternalModifierMake("knob goblin pet-buffing spray (unlock cobb's knob dispensary)", false, false, true, 5.0)); + } + //hippy concert + if (get_property("sidequestArenaCompleted") == "hippy" && !get_property_boolean("concertVisited") || $effect[Optimist Primal].have_effect() > 0) + { + boolean have_effect = $effect[Optimist Primal].have_effect() > 0; + weight_modifiers.listAppend(TFWMInternalModifierMake("Optimist Primal (hippy concert)", have_effect, have_effect || !get_property_boolean("concertVisited"), true, 5.0)); + } + //irradiated pet snacks + if ($item[irradiated pet snacks].available_amount() > 0 || $effect[healthy green glow].have_effect() > 0) + { + boolean have_effect = $effect[healthy green glow].have_effect() > 0; + weight_modifiers.listAppend(TFWMInternalModifierMake("irradiated pet snacks", have_effect, true, true, 10.0)); + } + else if (__misc_state["can eat just about anything"] || (__misc_state["can drink just about anything"] && __misc_state["VIP available"])) + { + weight_modifiers.listAppend(TFWMInternalModifierMake("irradiated pet snacks (lucky adventure, menagerie level 2)", false, false, true, 10.0)); + } + if (__misc_state["VIP available"] && __misc_state["can drink just about anything"]) + { + if (get_property_int("_speakeasyDrinksDrunk") <3 && availableDrunkenness() >= 3 && $item[clan speakeasy].is_unrestricted()) + { + boolean have_effect = $effect[1701].have_effect() > 0; //hip to the jive + weight_modifiers.listAppend(TFWMInternalModifierMake("Speakeasy hot socks", have_effect, true, true, 10.0)); + } + + } + //billiards + if (__misc_state["VIP available"] && get_property_int("_poolGames") <3 && $item[Clan pool table].is_unrestricted() || $effect[Billiards Belligerence].have_effect() > 0) + { + boolean have_effect = $effect[Billiards Belligerence].have_effect() > 0; + weight_modifiers.listAppend(TFWMInternalModifierMake("VIP Pool (play aggressively)", have_effect, have_effect || (get_property_int("_poolGames") <3), true, 5.0)); + } + //tea party + if (($item["DRINK ME" potion].available_amount() > 0 || $effect[Down the Rabbit Hole].have_effect() > 0) && (!get_property_boolean("_madTeaParty") || $effect[You Can Really Taste the Dormouse].have_effect() > 0)) + { + boolean have_effect = $effect[You Can Really Taste the Dormouse].have_effect() > 0; + weight_modifiers.listAppend(TFWMInternalModifierMake("Mad hatter (reinforced beaded headband)", have_effect, have_effect, true, 5.0)); + } + //beastly paste + if ($item[beastly paste].available_amount() > 0 || $effect[Beastly Flavor].have_effect() > 0) + { + boolean have_effect = $effect[Beastly Flavor].have_effect() > 0; + weight_modifiers.listAppend(TFWMInternalModifierMake("beastly paste (4 spleen)", have_effect, true, true, 3.0)); + } + else if ($familiar[pair of stomping boots].familiar_is_usable()) + { + weight_modifiers.listAppend(TFWMInternalModifierMake("beastly paste (4 spleen, stomp beasts)", false, false, true, 3.0)); + } + //resolution + if ($item[resolution: be kinder].available_amount() > 0 || $effect[Kindly Resolve].have_effect() > 0) + { + boolean have_effect = $effect[Kindly Resolve].have_effect() > 0; + weight_modifiers.listAppend(TFWMInternalModifierMake("resolution: be kinder", have_effect, true, true, 5.0)); + } + else if ($skill[summon resolutions].skill_is_usable() && __misc_state["bookshelf accessible"]) + { + weight_modifiers.listAppend(TFWMInternalModifierMake("resolution: be kinder (summon)", false, false, true, 5.0)); + } + //green candy heart + skill candy_hearts = $skill[Summon Candy Heart]; + if ($item[green candy heart].available_amount() > 0 || $effect[Heart of Green].have_effect() > 0) + { + boolean have_effect = $effect[Heart of Green].have_effect() > 0; + weight_modifiers.listAppend(TFWMInternalModifierMake("green candy heart", have_effect, true, true, 3.0)); + } + else if (candy_hearts.skill_is_usable() && __misc_state["bookshelf accessible"] && candy_hearts != $skill[none]) + { + weight_modifiers.listAppend(TFWMInternalModifierMake("green candy heart (summon)", false, false, true, 3.0)); + } + + //sugar sheet, sugar shield + if ($item[astral pet sweater].available_amount() == 0 && ($item[snow suit].available_amount() == 0 || $item[snow suit].numeric_modifier("familiar weight") < 10.0)) + { + if ($item[sugar shield].available_amount() > 0) + weight_modifiers.listAppend(TFWMInternalModifierMake($item[sugar shield])); + else if ($item[sugar sheet].available_amount() > 0) + { + weight_modifiers.listAppend(TFWMInternalModifierMake("sugar shield (use sugar sheet)", false, true, true, 10.0, true)); + } + else if ($skill[Summon Sugar Sheets].skill_is_usable() && __misc_state["bookshelf accessible"]) + { + //TFWMInternalModifier TFWMInternalModifierMake(string description, boolean have, boolean obtainable_now, boolean obtainable_theoretically, float bonus) + weight_modifiers.listAppend(TFWMInternalModifierMake("sugar shield (summon sugar sheet)", false, false, true, 10.0, true)); + } + } + //ittah bittah hookah + weight_modifiers.listAppend(TFWMInternalModifierMake($item[ittah bittah hookah])); + //lead necklace + weight_modifiers.listAppend(TFWMInternalModifierMake($item[lead necklace])); + //snow suit - numeric_modifier($item[snow suit], "familiar weight") + weight_modifiers.listAppend(TFWMInternalModifierMake($item[snow suit])); + //astral pet sweater + weight_modifiers.listAppend(TFWMInternalModifierMake($item[astral pet sweater])); + + //greaves of the whatever + weight_modifiers.listAppend(TFWMInternalModifierMake($item[greaves of the murk lord])); + //furry halo + weight_modifiers.listAppend(TFWMInternalModifierMake($item[furry halo])); + //CoT, if they have the right familiars + if ($familiars[Animated Macaroni Duck, Autonomous Disco Ball, Barrrnacle, Gelatinous Cubeling, Ghost Pickle on a Stick, Misshapen Animal Skeleton, Pair of Ragged Claws, Penguin Goodfella, Spooky Pirate Skeleton].have_familiar_replacement()) + { + weight_modifiers.listAppend(TFWMInternalModifierMake($item[crown of thrones])); + } + + + //Find best familiar equipment: + TFWMInternalModifier best_familiar_equipment; + foreach key in weight_modifiers + { + TFWMInternalModifier weight_modifier = weight_modifiers[key]; + if (weight_modifier.have && weight_modifier.from_familiar_equipment) + { + if (weight_modifier.bonus > best_familiar_equipment.bonus) + best_familiar_equipment = weight_modifier; + } + } + + float total = 0.0; + foreach key in weight_modifiers + { + TFWMInternalModifier weight_modifier = weight_modifiers[key]; + string description = weight_modifier.description; + description += " (+" + weight_modifier.bonus.floor() + ")"; + if (weight_modifier.have) + { + if (best_familiar_equipment.have && weight_modifier.from_familiar_equipment && !TFWMInternalModifierEquals(best_familiar_equipment, weight_modifier)) //not our chosen familiar equipment + continue; + how.listAppend(description); + total += weight_modifier.bonus; + } + else if (weight_modifier.obtainable_now) + { + immediately_obtainable.listAppend(description); + } + else if (weight_modifier.obtainable_theoretically) + { + missing_potentials.listAppend(description); + } + + } + missing_weight.f = MAX(0, 19 - total); + + if (numeric_modifier("familiar weight") >= 19.0) + return true; + if (total >= 19.0) + return true; + else + return false; +} + + + +string generatePotatoSuggestion() +{ + if (familiar_is_usable($familiar[fancypants scarecrow]) && $item[swashbuckling pants].available_amount() > 0) + return "Run swashbuckling pants on scarecrow. (2x potato)"; + else if (familiar_is_usable($familiar[fancypants scarecrow]) && $item[spangly mariachi pants].available_amount() > 0) + return "Run spangly mariachi pants on scarecrow. (2x potato)"; + else if (familiar_is_usable($familiar[mad hatrack]) && $item[spangly sombrero].available_amount() > 0) + return "Run spangly sombrero on mad hatrack. (2x potato)"; + else + return "Run a potato familiar if you can."; +} + + +void QLevel13Init() +{ + //questL13Final + + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questL13Final"); + if (__misc_state["in aftercore"] || my_path().id == PATH_BUGBEAR_INVASION || my_path().id == PATH_SEA || my_path().id == PATH_GREY_GOO || (!state.in_progress && my_path().id == PATH_ACTUALLY_ED_THE_UNDYING)) //FIXME mafia may track the ed L13 quest under this variable + QuestStateParseMafiaQuestPropertyValue(state, "finished"); //never will start + if (__misc_state["Example mode"]) + QuestStateParseMafiaQuestPropertyValue(state, "step6"); + state.quest_name = "Naughty Sorceress Quest"; + state.image_name = "naughty sorceress lair"; + state.council_quest = true; + + state.state_string["Stat race type"] = ""; //telescope1 + state.state_string["Elemental damage race type"] = ""; //telescope2 + + //FIXME these all need checking: + string [string] telescope1_messages_to_type; + telescope1_messages_to_type["all wearing sunglasses and dancing"] = "moxie"; + telescope1_messages_to_type["standing around flexing their muscles and using grip exercisers"] = "muscle"; + telescope1_messages_to_type["sitting around playing chess and solving complicated-looking logic puzzles"] = "mysticality"; + + string [string] telescope2_messages_to_type; + telescope2_messages_to_type["greasy-looking people furtively skulking around"] = "sleaze"; + telescope2_messages_to_type["people, all of whom appear to be on fire"] = "hot"; //??? + telescope2_messages_to_type["people, clustered around a group of igloos"] = "cold"; + telescope2_messages_to_type["people, surrounded by a cloud of eldritch mist"] = "spooky"; //??? + telescope2_messages_to_type["people, surrounded by garbage and clouds of flies"] = "stench"; + + string [string] telescope3_messages_to_type; + string [string] telescope4_messages_to_type; + string [string] telescope5_messages_to_type; + + telescope3_messages_to_type["creepy-looking black bushes on the outskirts of a hedge maze"] = "spooky"; + telescope3_messages_to_type["nasty-looking, dripping green bushes on the outskirts of a hedge maze"] = "stench"; //stench? sleaze? + telescope3_messages_to_type["purplish, greasy-looking hedges"] = "sleaze"; //??? + telescope3_messages_to_type["smoldering bushes on the outskirts of a hedge maze"] = "hot"; //??? + telescope3_messages_to_type["frost-rimed bushes on the outskirts of a hedge maze"] = "cold"; + + telescope4_messages_to_type["a greasy purple cloud hanging over the center of the maze"] = "sleaze"; + telescope4_messages_to_type["smoke rising from deeper within the maze"] = "hot"; //???? + telescope4_messages_to_type["a miasma of eldritch vapors rising from deeper within the maze"] = "spooky"; //???? + telescope4_messages_to_type["a cloud of green gas hovering over the maze"] = "stench"; //???? + telescope4_messages_to_type["wintry mists rising from deeper within the maze"] = "cold"; + + telescope5_messages_to_type["occasionally disgorging a bunch of ice cubes"] = "cold"; + telescope5_messages_to_type["that occasionally vomits out a greasy ball of hair"] = "sleaze"; //??? + telescope5_messages_to_type["surrounded by creepy black mist"] = "spooky"; //??? + telescope5_messages_to_type["disgorging a really surprising amount of sewage"] = "stench"; //??? + telescope5_messages_to_type["with lava slowly oozing out of it"] = "hot"; //??? + + state.state_string["Stat race type"] = get_property("nsChallenge1"); //telescope1_messages_to_type[get_property("telescope1")]; + if (state.state_string["Stat race type"] == "none") + state.state_string["Stat race type"] = ""; + state.state_string["Elemental damage race type"] = get_property("nsChallenge2"); //telescope2_messages_to_type[get_property("telescope2")]; + if (state.state_string["Elemental damage race type"] == "none") + state.state_string["Elemental damage race type"] = ""; + + string [int] elements_needed = listMake(telescope3_messages_to_type[get_property("telescope3")], telescope4_messages_to_type[get_property("telescope4")], telescope5_messages_to_type[get_property("telescope5")]); + + boolean have_all_elements = true; + foreach key, e in elements_needed + { + if (e.length() == 0) + { + have_all_elements = false; + break; + } + } + state.state_string["Hedge maze elements needed"] = ""; + if (have_all_elements) + state.state_string["Hedge maze elements needed"] = elements_needed.listJoinComponents("|"); + + state.state_boolean["past races"] = state.mafia_internal_step >= 4; + + state.state_boolean["Init race completed"] = get_property_int("nsContestants1") != -1; + state.state_boolean["Stat race completed"] = get_property_int("nsContestants2") != -1; + state.state_boolean["Elemental damage race completed"] = get_property_int("nsContestants3") != -1; + if (state.finished || state.state_boolean["past races"]) + { + state.state_boolean["Init race completed"] = true; + state.state_boolean["Stat race completed"] = true; + state.state_boolean["Elemental damage race completed"] = true; + } + + state.state_boolean["past hedge maze"] = state.mafia_internal_step >= 6; + state.state_boolean["past keys"] = state.mafia_internal_step >= 7; + + state.state_boolean["past tower level 1"] = state.mafia_internal_step >= 8; + state.state_boolean["past tower level 2"] = state.mafia_internal_step >= 9; + state.state_boolean["past tower level 3"] = state.mafia_internal_step >= 10; + state.state_boolean["past tower level 4"] = state.mafia_internal_step >= 11; + state.state_boolean["past tower level 5"] = state.mafia_internal_step >= 12; + + state.state_boolean["past tower monsters"] = state.state_boolean["past tower level 3"]; //5 + state.state_boolean["wall of skin will need to be defeated"] = !state.state_boolean["past tower level 1"]; + state.state_boolean["wall of meat will need to be defeated"] = !state.state_boolean["past tower level 2"]; + state.state_boolean["wall of bones will need to be defeated"] = !state.state_boolean["past tower level 3"]; + state.state_boolean["shadow will need to be defeated"] = !state.state_boolean["past tower level 5"]; + //FIXME what paths don't fight the shadow? + state.state_boolean["king waiting to be freed"] = (state.mafia_internal_step >= 14 && !state.finished); + + //",," => {1:"",2:"",3:""} => {1:,2:,3:} => {:true,:true,:true} + boolean [item] keys_used = get_property("nsTowerDoorKeysUsed").split_string_alternate(",").listConvertToItem().listInvert(); + + foreach base_key in __ns_tower_door_base_keys { + state.state_boolean[base_key.name + " used"] = (keys_used contains base_key) || state.state_boolean["past keys"]; + } + + if (my_path().id == PATH_LOW_KEY_SUMMER) { + foreach index, LKS_key in LKS_keys { + if (LKS_key.it != $item[none]) { + LKS_key.was_used = (keys_used contains LKS_key.it) || state.state_boolean["past keys"]; + state.state_boolean[LKS_key.it.name + " used"] = LKS_key.was_used; + } + } + } + + //Silent, Shell Up, Sauceshell + + boolean other_quests_completed = true; + for i from 2 to 12 + { + if (!__quest_state["Level " + i].finished) + { + other_quests_completed = false; + } + } + if (other_quests_completed && (my_level() >= 13 || my_path().id == PATH_EXPLOSIONS)) + state.startable = true; + + + __quest_state["Level 13"] = state; + __quest_state["Lair"] = state; +} + + +void QLevel13GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Level 13"].in_progress) + return; + QuestState base_quest_state = __quest_state["Level 13"]; + ChecklistSubentry subentry; + ChecklistSubentry [int] subentries; + subentries.listAppend(subentry); + subentry.header = base_quest_state.quest_name; + string url = "place.php?whichplace=nstower"; + + string image_name = base_quest_state.image_name; + + boolean should_output_main_entry = true; + if (!base_quest_state.state_boolean["past races"] && (base_quest_state.state_string["Stat race type"].length() == 0 || base_quest_state.state_string["Elemental damage race type"].length() == 0)) + { + subentry.header = "Visit the registration desk"; + subentry.entries.listAppend("Find out what the races are, first."); + image_name = "lair registration desk"; + } + else if (base_quest_state.mafia_internal_step == 3) + { + image_name = "lair registration desk"; + subentry.header = "Visit the registration desk"; + subentry.entries.listAppend("Claim your prize!"); + url = "place.php?whichplace=nstower&action=ns_01_contestbooth"; + } + else if (!base_quest_state.state_boolean["past races"]) + { + image_name = "lair registration desk"; + remove subentries[0]; + + if (!base_quest_state.state_boolean["Init race completed"]) + { + string [int] description; + float current_value = numeric_modifier("initiative"); + + description.listAppend("Currently " + current_value.floor() + "%."); + + if (current_value < 400.0) + { + description.listAppend("Need " + (400.0 - current_value).roundForOutput(1) + "% more initiative for #2."); + + if (!($familiars[oily woim,Xiblaxian Holo-Companion] contains my_familiar()) && !__misc_state["familiars temporarily blocked"]) + { + familiar [int] init_familiar_evaluation_order; + init_familiar_evaluation_order.listAppend($familiar[Xiblaxian Holo-Companion]); + init_familiar_evaluation_order.listAppend($familiar[oily woim]); + foreach key, f in init_familiar_evaluation_order + { + if (f.familiar_is_usable()) + { + description.listAppend("Try switching to your " + f + "."); + break; + } + } + } + if (__misc_state_int["pulls available"] > 0) + { + boolean [item] blacklist;// = $items[hare brush,freddie's blessing of mercury,ruby on canes]; + item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Initiative", 30, blacklist); + string [int] relevant_potions_output; + foreach key, it in relevant_potions + { + float initiative_modifier = it.to_effect().numeric_modifier("Initiative"); + if ($effect[Bow-Legged Swagger].have_effect() > 0) + initiative_modifier *= 2.0; + relevant_potions_output.listAppend(it + " (" + initiative_modifier.roundForOutput(0) + "%)"); + } + + if (relevant_potions_output.count() > 0) + description.listAppend("Could try pulling " + relevant_potions_output.listJoinComponents(", ", "or") + "."); + } + } + else + description.listAppend("Take the test now, you should(?) make second place."); + + subentries.listAppend(ChecklistSubentryMake("Compete in the init race", "+init", description)); + } + if (!base_quest_state.state_boolean["Stat race completed"]) + { + stat stat_type = base_quest_state.state_string["Stat race type"].to_stat(); + string [int] description; + float current_value = my_buffedstat(stat_type); + + + //FIXME find this value; current is a guess + //highest seen #3 is 577 moxie + if (current_value < 600.0) + { + description.listAppend("Need " + (600.0 - current_value).roundForOutput(1) + " more " + stat_type.to_lower_case() + " for #2."); + } + else + description.listAppend("Take the test now, you should(?) make second place."); + + if (stat_type != $stat[none] && current_value < 600.0) + { + if (__misc_state_int["pulls available"] > 0) + { + float base_stat = MAX(1.0, my_basestat(stat_type)); + + //Rümpelstiltz,gummi snake,handful of laughing willow bark,dennis's blessing of minerva,smart watch,mer-kin smartjuice,lump of saccharine maple sap,burt's blessing of bacchus,augmented-reality shades,mer-kin cooljuice,lobos mints,mariachi toothpaste,disco horoscope (virgo),pressurized potion of pulchritude,pressurized potion of perspicacity,pressurized potion of puissance,handful of crotchety pine needles,bruno's blessing of mars,fitness wristband,gummi salamander,bottle of fire,banana smoothie,banana supersucker,ennui-flavored potato chips,moonds,ultrasoldier serum,kumquat supersucker,mer-kin strongjuice, + boolean [item] blacklist = $items[snake,M-242,sparkler]; //limited/expensive/unusable content + item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier(stat_type, MIN(600 - current_value, 25), blacklist); + item [int] relevant_potions_source_2 = ItemFilterGetPotionsCouldPullToAddToNumericModifier(stat_type + " percent", 25.0 / base_stat * 100.0, blacklist); + + relevant_potions.listAppendList(relevant_potions_source_2); + + sort relevant_potions by -(value.to_effect().numeric_modifier(stat_type) + (value.to_effect().numeric_modifier(stat_type + " percent") / 100.0 * my_basestat(stat_type))); + + + string [int] relevant_potions_output; + foreach key, it in relevant_potions + { + float total = (it.to_effect().numeric_modifier(stat_type) + (it.to_effect().numeric_modifier(stat_type + " percent") / 100.0 * my_basestat(stat_type))); + string line = it + " (" + total.roundForOutput(1) + ")"; + //if (it.mall_price() >= 15000) //for internal use, to fill out the blacklist + //line = HTMLGenerateSpanFont(line, "red", ""); + relevant_potions_output.listAppend(line); + } + + if (relevant_potions_output.count() > 0) + description.listAppend("Could try pulling " + relevant_potions_output.listJoinComponents(", ", "or") + "."); + } + } + + subentries.listAppend(ChecklistSubentryMake("Compete in the " + stat_type + " race", "+" + stat_type.to_string().to_lower_case(), description)); + } + if (!base_quest_state.state_boolean["Elemental damage race completed"]) + { + element element_type = base_quest_state.state_string["Elemental damage race type"].to_element(); + + string [int] description; + + string element_class = "r_element_" + element_type; + string element_class_desaturated = element_class + "_desaturated"; + + float current_value = numeric_modifier(element_type + " damage") + numeric_modifier(element_type + " spell damage"); + if (current_value < 100.0) + { + description.listAppend("Need " + (100.0 - current_value).roundForOutput(1) + " more " + HTMLGenerateSpanOfClass(element_type + " damage ", element_class) + " + " + HTMLGenerateSpanOfClass(element_type + " spell damage", element_class) + " for #2."); + + + if (__misc_state_int["pulls available"] > 0) + { + boolean [item] blacklist = $items[witch's brew,boiling seal blood]; + item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier(listMake(element_type + " damage", element_type + " spell damage"), 30, blacklist); + string [int] relevant_potions_output; + foreach key, it in relevant_potions + { + relevant_potions_output.listAppend(it + " (" + (it.to_effect().numeric_modifier(element_type + " damage") + it.to_effect().numeric_modifier(element_type + " spell damage")).roundForOutput(0) + ")"); + } + + if (relevant_potions_output.count() > 0) + description.listAppend("Could try pulling " + relevant_potions_output.listJoinComponents(", ", "or") + "."); + } + } + else + description.listAppend("Take the test now, you should(?) make second place."); + description.listAppend("Currently " + current_value.roundForOutput(1) + "."); + + subentries.listAppend(ChecklistSubentryMake("Compete in the " + HTMLGenerateSpanOfClass(element_type + " damage", element_class) + " race", listMake("+" + HTMLGenerateSpanOfClass(element_type + " damage", element_class_desaturated), "+" + HTMLGenerateSpanOfClass(element_type + " spell damage", element_class_desaturated)), description)); + } + + int total_contestants_to_fight = 0; + foreach s in $strings[nsContestants1,nsContestants2,nsContestants3] + { + if (get_property_int(s) > 0) + total_contestants_to_fight += get_property_int(s); + } + if (total_contestants_to_fight > 0) + { + subentries.listAppend(ChecklistSubentryMake("Fight " + pluraliseWordy(total_contestants_to_fight, "more contestant", "more contestants"), "", "")); + } + else if (subentries.count() == 0) + { + //hmm... + subentries.listAppend(ChecklistSubentryMake("Visit the registration desk", "", "Claim your prize!")); + url = "place.php?whichplace=nstower&action=ns_01_contestbooth"; + } + else if (total_contestants_to_fight == 0) + url = "place.php?whichplace=nstower&action=ns_01_contestbooth"; + //nsContestants1 - default -1 + //nsContestants2 - default -1 + //nsContestants3 - default -1 + } + else if (base_quest_state.mafia_internal_step == 4) + { + subentry.header = "Attend your coronation"; + image_name = "__item Snow Queen Crown"; + } + else if (!base_quest_state.state_boolean["past hedge maze"]) + { + //FIXME individualised room support + //need X more hot resistance, Y more Z resistance to pass elemental tests + subentry.header = "Find your way through the Hedge Maze"; + image_name = "__item hedge maze puzzle"; + int current_room = get_property_int("currentHedgeMazeRoom"); + if (current_room >= 9) + { + subentry.entries.listAppend("Almost there..."); + } + else + { + int [element] elements_needed_to_pass; + string [int] resists_needed_for_hedge_maze = base_quest_state.state_string["Hedge maze elements needed"].split_string_alternate("\\|"); + float total_damage_taken_from_resists = 0.0; + if (resists_needed_for_hedge_maze.count() > 0) + { + foreach key, element_name in resists_needed_for_hedge_maze + { + element e = element_name.to_element(); + if (e == $element[none]) //wha? + continue; + elements_needed_to_pass[e] = 7; + float percentage = 0.0; + if (key == 0) percentage = 0.9; + if (key == 1) percentage = 0.8; + if (key == 2) percentage = 0.7; + float resist = e.elemental_resistance() / 100.0; + float damage_taken = my_maxhp() * percentage * (1.0 - resist); + total_damage_taken_from_resists += damage_taken; + } + } + else + { + total_damage_taken_from_resists = 10000; + elements_needed_to_pass[$element[hot]] = 7; + elements_needed_to_pass[$element[stench]] = 7; + elements_needed_to_pass[$element[spooky]] = 7; + elements_needed_to_pass[$element[cold]] = 7; + elements_needed_to_pass[$element[sleaze]] = 7; + } + + int [element] amount_missing; + foreach e, amount_needed in elements_needed_to_pass + { + subentry.modifiers.listAppend("+" + HTMLGenerateSpanOfClass(amount_needed + " " + e + " resistance", "r_element_" + e + "_desaturated")); + float amount_have = numeric_modifier(e + " resistance"); + if (amount_have < amount_needed) + { + amount_missing[e] = amount_needed - amount_have; + } + } + if (amount_missing.count() > 0 && total_damage_taken_from_resists >= my_maxhp()) + { + if ($familiar[exotic parrot].familiar_is_usable() && !__misc_state["familiars temporarily blocked"]) + subentry.entries.listAppend("Potentially switch to the exotic parrot."); + + string [int] amount_missing_string; + foreach e, amount in amount_missing + { + amount_missing_string.listAppend(HTMLGenerateSpanOfClass(amount + " more " + e + " resistance", "r_element_" + e)); + } + subentry.entries.listAppend("Need " + amount_missing_string.listJoinComponents(", ", "and") + " to safely make it through the maze quickly."); + } + else + { + subentry.modifiers.listClear(); + subentry.entries.listAppend("Choose the second option each time to save the most turns."); + } + if (my_hp() < my_maxhp() && current_room <= 1) + { + //FIXME only output this if we won't make it. + subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); + } + } + + //elemental tests are 1, 4, 7 + //9 is escape + //subentry.entries.listAppend("currentHedgeMazeRoom = " + get_property_int("currentHedgeMazeRoom")); + } + else if (!base_quest_state.state_boolean["past keys"]) + { + url = "place.php?whichplace=nstower_door"; + subentry.header = "Open the tower door"; + + item [int] missing_keys; + foreach base_key in __ns_tower_door_base_keys { + if (!base_quest_state.state_boolean[base_key.name + " used"] && base_key.available_amount() == 0) { + /*string key_name_output = base_key.name.replace_string(" key", ""); + key_name_output = HTMLGenerateSpanFont(key_name_output, "grey");*/ //unused + missing_keys.listAppend(base_key); + } + } + if (my_path().id == PATH_LOW_KEY_SUMMER) { + foreach index, LKS_key in LKS_keys { + if (!LKS_key.was_used) + missing_keys.listAppend(LKS_key.it); + } + } + + if (missing_keys.count() == 0) { + subentry.entries.listAppend("Open the doorknob."); + } else { + subentry.entries.listAppend("Find " + pluraliseWordy(missing_keys.count(), "more key", "more keys") + " for the door"); + } + + if (my_path().id != PATH_LOW_KEY_SUMMER) { //has its own file, Low Key.ash, when in Low Key Summer + foreach keyIndex, key in missing_keys { + subentry.entries.listAppend(key); + } + } + + } + else if (!base_quest_state.state_boolean["past tower level 1"]) + { + //wall of skin + subentry.header = "Defeat the Wall of Skin"; + if ($item[beehive].available_amount() > 0) + { + subentry.entries.listAppend("Use the beehive against it."); + } + else + { + subentry.entries.listAppend("Either find the beehive in the black forest (-combat), or towerkill."); + subentry.entries.listAppend("Lots of passive damage sources."); + if (my_path().id == PATH_BIG) + subentry.entries.listAppend("Towerkilling is likely impractical in BIG?"); + //Originally I wanted this to properly calculate the exact amount of damage you can do against the wall of skin. + //But, I feel like that would be super complicated and prone to error. + //So, we'll just give suggestions and hope it works out. + boolean have_prismatic_damage = true; + string [int] prismatic_damage_needed; + foreach e in $elements[hot,cold,sleaze,stench,spooky] + { + if (numeric_modifier(e + " damage") > 0) continue; + have_prismatic_damage = false; + prismatic_damage_needed.listAppend(e); + } + string [int] methods; + string [int] skills_to_cast; + foreach s in $skills[spiky shell,Jalapeño Saucesphere,The Psalm of Pointiness,Scarysauce] + { + if (s.to_effect().have_effect() > 0) + continue; + if (!s.have_skill()) + continue; + if (!s.is_unrestricted()) + continue; + skills_to_cast.listAppend(s); + } + if (skills_to_cast.count() > 0) + { + methods.listAppend("Cast " + skills_to_cast.listJoinComponents(", ", "and") + "."); + } + if ($item[colorful toad].have() && $item[colorful toad].item_is_usable() && $item[colorful toad].to_effect().have_effect() == 0 && !have_prismatic_damage && my_path().id != PATH_2CRS) + methods.listAppend("Use colorful toad for +prismatic damage."); + familiar desired_familiar = $familiar[none]; + if ($familiar[mu].familiar_is_usable()) + { + methods.listAppend("Run extra +familiar weight for your mu; it will attack more often."); + desired_familiar = $familiar[mu]; + } + else if ($familiar[Imitation Crab].familiar_is_usable()) + desired_familiar = $familiar[Imitation Crab]; + else if ($familiar[Sludgepuppy].familiar_is_usable()) + desired_familiar = $familiar[Sludgepuppy]; + else if ($familiar[mini-crimbot].familiar_is_usable()) + { + desired_familiar = $familiar[mini-crimbot]; + //(crimbotArm - "STAL-1 UltraFist" or "Frostronic Hypercoil"/crimbotChassis - "Music Box Box"/crimbotPropulsion - "X-1 Hover Rocket") + string [int] configure_options; + if (get_property("crimbotChassis") == "") + configure_options.listAppend("Music Box Box"); + if (get_property("crimbotArm") == "") + configure_options.listAppend("STAL-1 UltraFist"); + if (get_property("crimbotPropulsion") == "") + configure_options.listAppend("X-1 Hover Rocket"); + if (configure_options.count() > 0) + methods.listAppend("Configure mini-crimbot for " + configure_options.listJoinComponents(" / ") + "."); + } + + if (!__misc_state["familiars temporarily blocked"] && desired_familiar != $familiar[none] && my_familiar() != desired_familiar) + { + methods.listAppend("Switch to familiar " + desired_familiar + "."); + } + item [int] items_to_equip; + foreach it in $items[hand in glove,bottle opener belt buckle,buddy bjorn,smirking shrunken head,kremlin's greatest briefcase] + { + if (!it.have()) continue; + if (it.equipped()) continue; + items_to_equip.listAppend(it); + } + if (items_to_equip.count() > 0) + { + methods.listAppend("Equip " + items_to_equip.listJoinComponents(", ", "and") + "?"); + } + if ($item[buddy bjorn].equipped() && $familiar[misshapen animal skeleton].familiar_is_usable() && my_bjorned_familiar() != $familiar[misshapen animal skeleton]) + methods.listAppend("Put misshapen animal skeleton in the buddy bjorn."); + + if (!have_prismatic_damage) + { + methods.listAppend("Gain prismatic damage. Need " + prismatic_damage_needed.listJoinComponents(", ", "and") + "."); + } + + if (monster_level_adjustment() > 0) + methods.listAppend("Reduce monster level."); + + + string [int] attack_methods; + if ($skill[shieldbutt].skill_is_usable()) + attack_methods.listAppend("shieldbutt if you can hit" + ($slot[off-hand].equipped_item().item_type() != "shield" ? " but equip a shield first" : "")); + if ($skill[headbutt].skill_is_usable()) + attack_methods.listAppend("headbutt if you can hit" + ($slot[hat].equipped_item() == $item[none] ? " but equip a hat first" : "")); + if ($skill[belch the rainbow].skill_is_usable()) + attack_methods.listAppend("belch the rainbow"); + if ($skill[clobber].skill_is_usable()) + attack_methods.listAppend("clobber"); + attack_methods.listAppend("regular attack(?)"); + if (attack_methods.count() > 0) + { + methods.listAppend("Attack using " + attack_methods.listJoinComponents(", ", "or") + "."); + } + + /* + + item best_shield = $item[none]; + foreach it in __items_shields + { + if (it.to_slot() != $slot[off-hand]) continue; + if (it.item_type() != "shield") continue; + if (!it.can_equip()) continue; + if (it.available_amount() == 0) continue; + if (it.get_power() > best_shield.get_power() || best_shield == $item[none]) + best_shield = it; + } + */ + if (methods.count() > 0) + subentry.entries.listAppend("Towerkilling ideas:|*" + methods.listJoinComponents("
")); + if (my_hp() < my_maxhp()) + { + //FIXME only output this if we won't make it. + subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); + } + } + } + else if (!base_quest_state.state_boolean["past tower level 2"]) + { + //wall of meat + //current assumption is it's a [160, 240] drop, and you need to clear one thousand (thousand slimy) meats + subentry.header = "Defeat the Wall of Meat"; + subentry.modifiers.listAppend("+526% meat"); + + float current_value = numeric_modifier("meat drop"); + if (current_value < 526.0) + { + subentry.entries.listAppend("Need " + (526.0 - current_value).roundForOutput(0) + "% more meat drop to always complete in a single turn."); + + float meat_multiplier = 1.0 + current_value / 100.0; + float chance = 1.0 - TriangularDistributionCalculateCDF(1001.0, 160.0 * meat_multiplier, 240.0 * meat_multiplier); + if (chance > 0.0) + subentry.entries.listAppend((chance * 100.0).floor() + "% chance of completing in one turn."); + } + else + subentry.entries.listAppend("Should take one turn."); + + if (__misc_state_int["pulls available"] > 0 && current_value < 526.0) + { + float delta = 526.0 - current_value; + boolean [item] blacklist = $items[uncle greenspan's bathroom finance guide,black snowcone,sorority brain,blue grass,salt wages,perl necklace]; + item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Meat Drop", MIN(25, delta), blacklist); + string [int] relevant_potions_output; + foreach key, it in relevant_potions + { + relevant_potions_output.listAppend(it + " (" + it.to_effect().numeric_modifier("meat drop").roundForOutput(0) + "%)"); + } + + if (relevant_potions_output.count() > 0) + subentry.entries.listAppend("Could try pulling " + relevant_potions_output.listJoinComponents(", ", "or") + "."); + } + //FIXME does mafia have a tracking variable for meat dropped? + //FIXME REST + //estimated turns? + if (my_hp() < my_maxhp()) + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); + } + } + else if (!base_quest_state.state_boolean["past tower level 3"]) + { + subentry.header = "Defeat the Wall of Bones"; + //wall of bones + if ($item[electric boning knife].available_amount() > 0) + { + subentry.entries.listAppend("Use the electric boning knife against it."); + } + else + { + //suggest towerkilling methods + //removing passive damage sources + //support saucegeyser, intimidating mien, grease up, and future airport skills (or lack thereof) + //strategy: saucegeyser three times, then either saucegeyser One More Time or unleash grease up/intimidating mien/future airport skills + //FIXME REST + subentry.entries.listAppend("Either find the electric boning knife on the ground floor of the castle in the clouds in the sky (-combat), or towerkill:"); + subentry.entries.listAppend("Make sure to remove all sources of passive damage."); + + string [int] passives_to_remove = PDSGenerateDescriptionToUneffectPassives(); + if (passives_to_remove.count() > 0) + subentry.entries.listAppend(HTMLGenerateSpanFont(passives_to_remove.listJoinComponents("|"), "red")); + //FIXME HACK USE A LIBRARY + /*string [int] things_to_do; + foreach it in $items[hand in glove,MagiMechTech NanoMechaMech,bottle opener belt buckle,old school calculator watch,ant hoe,ant pick,ant pitchfork,ant rake,ant sickle,fishy wand,moveable feast,oversized fish scaler,plastic pumpkin bucket,tiny bowler,cup of infinite pencils,double-ice box,smirking shrunken head,mr. haggis,stapler bear,dubious loincloth,muddy skirt,bottle of Goldschnöckered,acid-squirting flower,ironic oversized sunglasses,hippy protest button,cannonball charrrm bracelet,groovy prism necklace,spiky turtle shoulderpads,double-ice cap,parasitic headgnawer,eelskin hat,balloon shield,hot plate,Ol' Scratch's stove door,Oscus's garbage can lid,eelskin shield,eelskin pants,buddy bjorn] + { + if (it.equipped_amount() > 0) + things_to_do.listAppend("unequip " + it); + } + foreach e in $effects[Skeletal Warrior,Skeletal Cleric,Skeletal Wizard,Bone Homie,Burning\, Man,Biologically Shocked,EVISCERATE!,Fangs and Pangs,Permanent Halloween,Curse of the Black Pearl Onion,Long Live GORF,Apoplectic with Rage,Dizzy with Rage,Quivering with Rage,Jabañero Saucesphere,Psalm of Pointiness,Drenched With Filth,Stuck-Up Hair,It's Electric!,Smokin',Jalapeño Saucesphere,Scarysauce,spiky shell] + { + if (e.have_effect() > 0) + things_to_do.listAppend("uneffect " + e); + } + if (things_to_do.count() > 0) + subentry.entries.listAppend(HTMLGenerateSpanFont(things_to_do.listJoinComponents(", ", "and").capitaliseFirstLetter() + ".", "red"));*/ + + //FIXME Firegate - spade, etc + + //Firegate is 100% myst, +30-40 damage, but unaffected by spell damage % (and possibly spell damage?) + //Garbage nova is 40% myst, etc, but affected by spell damage %/spell damage. + //So, we have to calculate which one is better and suggest that. (garbage nova may be better, in fact) + if ($skill[Garbage Nova].skill_is_usable()) + { + //Special note on calculations: + //Spell damage percent is multiplied before the group size multiplier, then floored. + //I believe this means against a size 100 monster, garbage nova will always deal damage in multiples of 50 + //It also means estimation can be wildly off without taking that into account. + //Also, stench spell damage counts double, maybe? + float buffed_myst = my_buffedstat($stat[mysticality]); + float spell_damage = numeric_modifier("spell damage"); + float stench_spell_damage = numeric_modifier("stench spell damage"); + float spell_damage_percent = numeric_modifier("spell damage percent"); + float monster_level = monster_level_adjustment_ignoring_plants(); + float spell_damage_multiplier = 1.0 + spell_damage_percent / 100.0; + float monster_damage_multiplier = 1.0 - min(50.0, monster_level * 0.4) / 100.0; + + //Estimate: 62894 + //Actual: 63263 + + //Current damage formulas: + //min = floor((45.0 + floor(0.4 * buffed_myst) + spell_damage + stench_spell_damage * 2.0) * (1.0 + spell_damage_percent / 100.0)) * ceil(group_size * 0.5) + //max = floor((50.0 + floor(0.4 * buffed_myst) + spell_damage + stench_spell_damage * 2.0) * (1.0 + spell_damage_percent / 100.0)) * ceil(group_size * 0.5) + //group_size = 100 + //then apply damage resistance: damage_out = floor(damage_in * (1.0 - min(50.0, ml * 0.4)) / 100.0)); + //damage must be >= 5k + + string [int] tasks; + + int min_myst_needed = 1000; + //5000 = floor(floor((45.0 + floor(0.4 * buffed_myst) + spell_damage + stench_spell_damage * 2.0) * spell_damage_multiplier) * 50.0 * monster_damage_multiplier) + //approximation: + //buffed_myst = 2.5 * (5000 / monster_damage_multiplier / 50.0 / spell_damage_multiplier - spell_damage - stench_spell_damage * 2.0 - 45.0) + //hmm... 138 to 388 myst without anything else? yes + //though -100 myst with 50 stench spell damage is also enough + + float divisor = monster_damage_multiplier * 50.0 * spell_damage_multiplier; + if (divisor == 0.0) + divisor = 0.001; + min_myst_needed = ceil(2.5 * (5000 / divisor - spell_damage - stench_spell_damage * 2.0 - 45.0)); + + int per_round_damage = floor(floor((45.0 + floor(0.4 * buffed_myst) + spell_damage + stench_spell_damage * 2.0) * spell_damage_multiplier) * 50.0 * monster_damage_multiplier); + + + int casts_needed = 4; + if (per_round_damage != 0) + casts_needed = clampi(ceil(20000.0 / to_float(per_round_damage)), 1, 4); + + if (my_buffedstat($stat[mysticality]) < min_myst_needed) + { + tasks.listAppend(HTMLGenerateSpanFont("buff up to " + min_myst_needed + " mysticality", "red")); + if (monster_level > 0) + tasks.listAppend("possibly reduce ML"); + } + tasks.listAppend("cast garbage nova " + pluraliseWordy(casts_needed, "time", "times")); + + if (tasks.count() > 0) + subentry.entries.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + + subentry.entries.listAppend(per_round_damage + " damage/round."); + } + else if ($skill[saucegeyser].skill_is_usable()) + { + boolean need_modifier_output = true; + if (my_familiar() != $familiar[magic dragonfish] && $familiar[magic dragonfish].familiar_is_usable() && !__misc_state["familiars temporarily blocked"]) + subentry.entries.listAppend("Potentially switch to the magic dragonfish."); + if ($item[meteorb].have() && !$item[meteorb].equipped()) + subentry.entries.listAppend("Potentially equip meteorb."); + //Calculate saucegeyser damage: + float expected_saucegeyser_damage = skillExpectedDamageRangeAlternate($monster[wall of bones], $skill[saucegeyser]).x; + if ($item[meteorb].equipped()) + expected_saucegeyser_damage *= 2.0; + + subentry.entries.listAppend("Expected saucegeyser minimum damage: " + expected_saucegeyser_damage.roundForOutput(0)); + if (expected_saucegeyser_damage >= 5000.0) + { + subentry.entries.listAppend("Cast saucegeyser four times."); + need_modifier_output = false; + } + else + { + float hp_remaining = 20000.0 - expected_saucegeyser_damage * 3.0; + + float [skill] airport_skill_per_turn_damage_multiplier; + float [skill] airport_skill_base_damage; + + airport_skill_per_turn_damage_multiplier[$skill[grease up]] = 5.0; + airport_skill_base_damage[$skill[grease up]] = 30.0; + + airport_skill_per_turn_damage_multiplier[$skill[Intimidating Mien]] = 2.0; + airport_skill_base_damage[$skill[Intimidating Mien]] = 15.0; + + string [skill] airport_skill_name_of_combat_skill; + + airport_skill_name_of_combat_skill[$skill[grease up]] = "Unleash the Greash"; + airport_skill_name_of_combat_skill[$skill[Intimidating Mien]] = "Thousand-Yard Stare"; + + + float ml_damage_multiplier = MLDamageMultiplier(); + if (ml_damage_multiplier != 1.0) + { + //FIXME this is correct... right? hmm... + foreach s in airport_skill_base_damage + { + airport_skill_base_damage[s] *= ml_damage_multiplier; + airport_skill_per_turn_damage_multiplier[s] *= ml_damage_multiplier; + } + } + + skill chosen_skill = $skill[none]; + int chosen_skill_total_mp_cost = 0; + int chosen_skill_turns_left_to_cast = 0; + foreach s in airport_skill_base_damage + { + if (!s.skill_is_usable()) + continue; + float base_damage = airport_skill_base_damage[s]; + float variable_damage = airport_skill_per_turn_damage_multiplier[s]; + effect skill_effect = s.to_effect(); + + if (variable_damage == 0.0) + continue; + int total_turns_needed_of_effect = ceil((hp_remaining - base_damage) / variable_damage); + int turns_to_cast = MAX(0, total_turns_needed_of_effect - skill_effect.have_effect()); + + int mp_cost = MAX(0, s.mp_cost() * turns_to_cast / MAX(1.0, s.turns_per_cast().to_float())); + + if (chosen_skill == $skill[none] || chosen_skill_total_mp_cost > mp_cost) + { + chosen_skill = s; + chosen_skill_total_mp_cost = mp_cost; + chosen_skill_turns_left_to_cast = turns_to_cast; + } + } + if (chosen_skill != $skill[none]) + { + if (chosen_skill_turns_left_to_cast > 0) + { + string expected_meat_cost = ceil(chosen_skill_total_mp_cost * __misc_state_float["meat per MP"]); + + //string line = "Acquire " + chosen_skill_turns_left_to_cast + " more turns of " + chosen_skill + ".|Expected meat cost: "; + string line = "Cast " + chosen_skill + " "; + int cast_amount = ceil(chosen_skill_turns_left_to_cast.to_float() / MAX(1.0, chosen_skill.turns_per_cast().to_float())); + + if (cast_amount == 1) + line += "One More Time."; + else + line += cast_amount + " more times."; + + line += "|Expected meat cost: "; + + if (expected_meat_cost > my_meat()) + line += HTMLGenerateSpanFont(expected_meat_cost, "red"); + else + line += expected_meat_cost; + subentry.modifiers.listAppend("-mana cost"); + subentry.entries.listAppend(line); + } + else + { + subentry.entries.listAppend("Cast saucegeyser three times, then cast " + airport_skill_name_of_combat_skill[chosen_skill] + "."); + need_modifier_output = false; + } + } + else if ($item[hand turkey outline].is_unrestricted()) //FIXME test if we have an airport skill + { + subentry.entries.listAppend("Cast saucegeyser three times, then an airport skill?"); + } + } + if (my_hp() < my_maxhp()) + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); + } + if (my_mp() < $skill[saucegeyser].mp_cost() * 4.0) + subentry.entries.listAppend(HTMLGenerateSpanFont("Restore some MP first.", "red")); + if (__iotms_usable[lookupItem("candy cane sword cane")]) + subentry.entries.listAppend("Also, consider using your Candy Cane Sword Cane's surprisingly sweet slash to cut the wall's HP by 75%!"); + if (need_modifier_output) + { + subentry.modifiers.listAppend("mysticality"); + subentry.modifiers.listAppend("spell damage"); + subentry.modifiers.listAppend("spell damage percent"); + if (monster_level_adjustment() > 0) + subentry.modifiers.listAppend("-ML"); + } + } + if ($skill[splattersmash].skill_is_usable() && my_id() == 1557284) + { + //(30-40 damage + (muscle - monster defence)) * 100 / 4 + //Two jam band bootlegs make that 1000 defence 250. If you have funksling, that's 487 buffed muscle needed. + // + subentry.entries.listAppend(HTMLGenerateSpanFont("Write splattersmash + jam band bootleg code.", "red")); + } + } + } + else if (!base_quest_state.state_boolean["past tower level 4"]) + { + //stare into the looking glass, or break it + subentry.header = "Face the looking glass"; + if (my_path().id == PATH_VAMPIRE) + { + subentry.entries.listAppend("Gaze upon... nothing."); + } + else + { + subentry.entries.listAppend("Two options here."); + subentry.entries.listAppend("Gazing upon the looking glass will cost a turn, but makes the naughty sorceress much easier."); + subentry.entries.listAppend("Breaking the mirror will save a turn, but makes the NS fight much more difficult."); + } + } + else if (!base_quest_state.state_boolean["past tower level 5"] && my_path().id == PATH_VAMPIRE) + { + subentry.header = "Fight the mirror"; + subentry.entries.listAppend("It has, like, 3000 HP. You can handle it, right?"); + } + else if (!base_quest_state.state_boolean["past tower level 5"]) + { + //at top of tower (fight shadow??) + //8 -> fight shadow + int total_initiative_needed = $monster[Your Shadow].monster_initiative(); + subentry.modifiers.listAppend("+HP"); + subentry.modifiers.listAppend("+" + total_initiative_needed + "% init"); + subentry.header = "Fight your shadow"; + foreach it in $items[attorney's badge, navel ring of navel gazing, replica navel ring of navel gazing] + { + if (it.available_amount() > 0 && it.equipped_amount() == 0) + subentry.entries.listAppend("Possibly equip your " + it + ". (blocks shadow)"); + } + + string [int] healing_items_available; + foreach it in $items[filthy poultice,gauze garter,red pixel potion,Dreadsylvanian seed pod,soggy used band-aid,Mer-kin healscroll,scented massage oil,extra-strength red potion,red potion] + { + if (it.item_amount() == 0) + continue; + if (!it.item_is_usable()) continue; + if (it.item_amount() == 1) + healing_items_available.listAppend(it.to_string()); + else + healing_items_available.listAppend(it.pluralise()); + } + if (healing_items_available.count() > 0) + subentry.entries.listAppend("Healing items available: " + healing_items_available.listJoinComponents(", ", "and") + "."); + else + subentry.entries.listAppend("May want to go find some healing items."); + + + int initiative_needed = total_initiative_needed - initiative_modifier(); + if (initiative_needed > 0 && !$skill[Ambidextrous Funkslinging].skill_is_usable()) + subentry.entries.listAppend("Need " + initiative_needed + "% more initiative."); + if (my_hp() < my_maxhp()) + { + //FIXME only output this if we won't make it. + subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); + } + } + else if (!base_quest_state.state_boolean["king waiting to be freed"]) + { + //At NS. Good luck, we're all counting on you. + if (my_path().id != PATH_HEAVY_RAINS) + { + subentry.modifiers.listAppend("+moxie, DA equipment"); + subentry.modifiers.listAppend("no buffs"); + if (!__misc_state["familiars temporarily blocked"]) + subentry.modifiers.listAppend("attack familiar"); + } + image_name = "naughty sorceress"; + subentry.header = "She awaits"; + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + { + subentry.header = "You await"; + image_name = "Disco Bandit"; + } + if (my_path().id == PATH_LICENSE_TO_ADVENTURE) + { + subentry.header = "\"Blofeld\" awaits"; + image_name = "__monster \"Blofeld\""; + } + //don't think blocking works anymore? not sure + /*if (!__misc_state["familiars temporarily blocked"] && my_path().id != PATH_HEAVY_RAINS) + { + string potato_suggestion = generatePotatoSuggestion(); + + subentry.entries.listAppend(potato_suggestion); + }*/ + + if ($item[The Lot's engagement ring].equipped_amount() > 0) + { + subentry.entries.listAppend("You and her? Good luck!"); + } + + /*if ($item[The Lot's engagement ring].available_amount() > 0 && $item[The Lot's engagement ring].equipped_amount() == 0) + { + subentry.entries.listAppend("Potentially equip the lot's engagement ring for an alternate ending.|(sigh... if only)"); + }*/ + + if (my_path().id == PATH_HEAVY_RAINS) + { + subentry.modifiers.listAppend("many buffs"); + if ($familiar[warbear drone].have_familiar()) + subentry.entries.listAppend("Run a warbear drone if you can."); + + subentry.entries.listAppend("Try to run as many buffs as you can. (one removed per round, have " + my_effects().count() + ")"); + subentry.entries.listAppend("Try to have as many damage sources as possible. (40? damage cap per source)"); + subentry.entries.listAppend("Only your weapon, offhand, and familiar equipment(?) are relevant this fight."); + if ($item[crayon shavings].available_amount() > 0) + subentry.entries.listAppend("Try repeatedly using crayon shavings?"); + if ($skill[frigidalmatian].skill_is_usable() && my_maxmp() >= 300 && $effect[Frigidalmatian].have_effect() == 0) + subentry.entries.listAppend("Try casting Frigidalmatian."); + } + if (my_hp() < my_maxhp() && !get_property("lastEncounter").contains_text("The Naughty Sorceress") && __last_adventure_location != $location[The Naughty Sorceress' Chamber] && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Restore your HP first.", "red")); + } + + } + else if (base_quest_state.state_boolean["king waiting to be freed"]) + { + //King is waiting in his prism. + + boolean trophies_are_possible = false; + + //ehh, disable displaying this, mostly because it's in the way + //if (in_hardcore()) + //trophies_are_possible = true; //Gourdcore, Golden Meat Stack + + if (trophies_are_possible) + task_entries.listAppend(ChecklistEntryMake("__item puzzling trophy", "trophy.php", ChecklistSubentryMake("Check for trophies", "10k meat, trophy requirements", "Certain trophies are missable after freeing the king")).ChecklistEntrySetIDTag("Path end trophies")); + should_output_main_entry = false; + + + if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) + { + if (availableDrunkenness() > 0) + { + task_entries.listAppend(ChecklistEntryMake("__item gibson", "inventory.php?which=1", ChecklistSubentryMake("Drink " + availableDrunkenness() + " drunkenness", "", "Freeing the king reduces your liver capacity.")).ChecklistEntrySetIDTag("Path end max liver usage")); + } + } + + if (my_path().id == PATH_HEAVY_RAINS) + { + if ($skill[rain dance].skill_is_usable() && my_rain() >= 10) + { + int times = floor(my_rain().to_float() / 10.0); + task_entries.listAppend(ChecklistEntryMake("__effect Rain Dancin'", "skills.php", ChecklistSubentryMake("Cast Rain Dance " + pluraliseWordy(times, "time", "times"), "", "+20% item buff for aftercore.")).ChecklistEntrySetIDTag("Path end rain dance")); + } + } + + if ($item[Yearbook Club Camera].available_amount() > 0 && $item[Yearbook Club Camera].equipped_amount() == 0) + { + task_entries.listAppend(ChecklistEntryMake("__item yearbook club camera", "inventory.php?ftext=yearbook+club+camera", ChecklistSubentryMake("Equip the yearbook club camera", "", "Before prism break. Otherwise, it'll disappear.")).ChecklistEntrySetIDTag("Path end yearbook camera")); + } + + } + //I need to delete this code, but I love it so much. Look at all that towerkilling suggestions! sob + /*else if (base_quest_state.mafia_internal_step > 4 && base_quest_state.mafia_internal_step < 11) + { + //step4 through step9 - 5 - 10 + //at tower, time to kill monsters! + + + int level = -1; + + if (base_quest_state.mafia_internal_step == 5) + level = 1; + else if (base_quest_state.mafia_internal_step == 6) + level = 2; + else if (base_quest_state.mafia_internal_step == 7) + level = 3; + else if (base_quest_state.mafia_internal_step == 8) + level = 4; + else if (base_quest_state.mafia_internal_step == 9) + level = 5; + else if (base_quest_state.mafia_internal_step == 10) + level = 6; + + boolean output_tower_killing_ideas = false; + item monster_item = __misc_state_string["Tower monster item " + level].to_item(); + + subentry.entries.listAppend("Tower monster on floor " + level + "."); + if (monster_item != $item[none]) + { + if (monster_item.available_amount() > 0) + subentry.entries.listAppend("Use " + HTMLGenerateSpanOfClass(monster_item, "r_bold") + "."); + else + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Need " + HTMLGenerateSpanOfClass(monster_item, "r_bold") + ".", "red")); + output_tower_killing_ideas = true; + } + } + else + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Need unknown item.", "red")); + output_tower_killing_ideas = true; + } + + if (output_tower_killing_ideas) + { + string [int] tower_killing_ideas; + + if (my_path().id == PATH_HEAVY_RAINS && $skill[thunder bird].skill_is_usable() && my_thunder() >= 5 && $skill[curse of weaksauce].skill_is_usable()) + { + string [int] line; + if ($skill[itchy curse finger].skill_is_usable()) + { + line.listAppend("cast curse of weaksauce"); + line.listAppend("cast a stun"); + } + else + { + line.listAppend("cast a stun"); + line.listAppend("cast curse of weaksauce"); + } + line.listAppend("cast thunder bird/stun/staggers repeatedly under defense is below zero"); + line.listAppend("attack"); + tower_killing_ideas.listAppend(line.listJoinComponents(", ", "then").capitaliseFirstLetter()); + } + else if ($skill[curse of weaksauce].skill_is_usable() && $item[crayon shavings].available_amount() >= 2) //currently disabled because while it'll work in theory, I haven't tested it + { + string [int] line; + if ($skill[itchy curse finger].skill_is_usable()) + { + line.listAppend("cast curse of weaksauce"); + line.listAppend("cast a stun"); + } + else + { + line.listAppend("cast a stun"); + line.listAppend("cast curse of weaksauce"); + } + line.listAppend("throw two crayon shavings"); + line.listAppend("stagger/stun until defense is below zero"); + + line.listAppend("attack"); + tower_killing_ideas.listAppend(line.listJoinComponents(", ", "then").capitaliseFirstLetter()); + } + + //Familiar sources: + if (!__misc_state["familiars temporarily blocked"]) + { + string potato_suggestion = generatePotatoSuggestion(); + tower_killing_ideas.listAppend(potato_suggestion); + + + //Bjorn: + if ($familiar[mariachi chihuahua].have_familiar()) + { + if ($item[buddy bjorn].available_amount() > 0) + { + if (my_bjorned_familiar() != $familiar[mariachi chihuahua]) + tower_killing_ideas.listAppend("Put your mariachi chihuahua in your buddy bjorn. (50% stagger)"); + } + else if ($item[crown of thrones].available_amount() > 0) + { + if (my_enthroned_familiar() != $familiar[mariachi chihuahua]) + tower_killing_ideas.listAppend("Put your mariachi chihuahua in your crown of thrones. (50% stagger)"); + } + } + } + + if ($item[attorney's badge].available_amount() > 0 && $item[attorney's badge].equipped_amount() == 0) + tower_killing_ideas.listAppend("Could equip attorney's badge for more blocking."); + if ($item[navel ring of navel gazing].available_amount() > 0 && $item[navel ring of navel gazing].equipped_amount() == 0) + tower_killing_ideas.listAppend("Could equip navel ring of navel gazing for more blocking."); + + + + string [int] stun_sources; + string [int] stagger_sources; + + + //Stun/stagger sources: + //(this is not a comprehensive list) + //√shadow noodles, √thunderstrike, √soul bubble + //√potato, √bjorned chihuahua, √attorney's badge, √navel ring + + //√ply reality, √entangling noodles as not-pastamancer, √pantsgiving 2x, √deft hands, DNA...?, √3x disco dances... + //√airblaster gun + //√club foot IF seal clubber + //√Break It On Down + //√gob of wet hair, √gyroscope, √macrame net, √ornate picture frame, √palm-frond net(?), √Rain-Doh indigo cup, √superamplified boom box, √Throw Shield (OPS), √tongue depressor + + //√gas balloon, √brick of sand(?), √chloroform rag, naughty paper shuriken, √sausage bomb, √floorboard cruft + //√dumb mud will insta if available + //√finger cuffs (support acquiring) + //√Rain-Doh blue balls + //√CSA obedience grenade, √The Lost Comb + //Accordion Bash if AT wearing an accordion FIXME do that + //Shell Up(?) + //sooooooul finger? does it work? 40 saucery... + + if ($item[Game Grid ticket].item_amount() > 0 && $item[Game Grid ticket].is_unrestricted()) + tower_killing_ideas.listAppend("Could acquire " + $item[Game Grid ticket].item_amount() + " finger cuffs. (stun)"); + if ($skill[shadow noodles].skill_is_usable()) + stun_sources.listAppend("shadow noodles"); + if ($skill[thunderstrike].skill_is_usable()) + stun_sources.listAppend("thunderstrike"); + if ($skill[soul saucery].skill_is_usable() && my_class() == $class[sauceror]) + stun_sources.listAppend("soul bubble"); + + foreach it in $items[gas balloon,brick of sand,chloroform rag,sausage bomb,floorboard cruft,finger cuffs,CSA obedience grenade,The Lost Comb] + { + if (it.item_amount() == 0 || !it.is_unrestricted()) + continue; + stun_sources.listAppend(it.pluraliseWordy()); + } + if ($item[naughty paper shuriken].available_amount() > 0) + stun_sources.listAppend("naughty paper shuriken"); + if ($item[Rain-Doh blue balls].available_amount() > 0) + stun_sources.listAppend("Rain-Doh blue balls"); + + if ($skill[shell up].skill_is_usable() && ($effect[Blessing of the Storm Tortoise].have_effect() > 0 || $effect[Grand Blessing of the Storm Tortoise].have_effect() > 0 || $effect[Glorious Blessing of the Storm Tortoise].have_effect() > 0)) + stun_sources.listAppend("Shell Up"); + if ($skill[Accordion Bash].skill_is_usable()) + { + string line = "Accordion Bash"; + if ($slot[weapon].equipped_item().item_type() != "accordion") + line = HTMLGenerateSpanFont(line + " (equip accordion)", "gray"); + stun_sources.listAppend(line); + } + + if ($item[thor's pliers].equipped_amount() > 0) + stagger_sources.listAppend("ply reality"); + if (my_class() != $class[pastamancer] && $skill[entangling noodles].skill_is_usable()) + stagger_sources.listAppend("entangling noodles"); + if ($item[pantsgiving].equipped_amount() > 0) + { + stagger_sources.listAppend("pocket crumbs"); + stagger_sources.listAppend("air dirty laundry"); + } + if (my_class() == $class[disco bandit] && $skill[deft hands].skill_is_usable()) + stagger_sources.listAppend("first combat item thrown"); + if (my_class() == $class[disco bandit] && $skill[Disco State of Mind].skill_is_usable() && $skill[Flashy Dancer].skill_is_usable()) + { + if ($skill[disco dance of doom].skill_is_usable()) + stagger_sources.listAppend("disco dance"); + if ($skill[Disco Dance II: Electric Boogaloo].skill_is_usable()) + stagger_sources.listAppend("disco dance II"); + if ($skill[Disco Dance 3: Back in the Habit].skill_is_usable()) + stagger_sources.listAppend("disco dance 3"); + } + if ($item[airblaster gun].equipped_amount() > 0) + stagger_sources.listAppend("air blast"); + if (my_class() == $class[seal clubber] && $skill[club foot].skill_is_usable()) + { + int stun_rounds = 0; + + stun_rounds = MIN(3, my_fury()); + if ($slot[weapon].equipped_item().item_type() == "club") + stun_rounds += 1; + + if (stun_rounds == 1) + stagger_sources.listAppend("club foot"); + else if (stun_rounds > 1) + stun_sources.listAppend("club foot"); + } + if ($skill[Break It On Down].skill_is_usable()) + stagger_sources.listAppend("break it on down"); + + foreach it in $items[gob of wet hair,gyroscope,macrame net,ornate picture frame,palm-frond net,superamplified boom box] + { + if (it.item_amount() == 0 || !it.is_unrestricted()) + continue; + stagger_sources.listAppend(it.pluraliseWordy()); + } + if ($item[operation patriot shield].equipped_amount() > 0) + stagger_sources.listAppend("throw shield"); + if ($item[Rain-Doh indigo cup].available_amount() > 0) + stagger_sources.listAppend("Rain-Doh indigo cup"); + if ($item[tongue depressor].available_amount() > 0) + stagger_sources.listAppend("tongue depressor"); + + if (stun_sources.count() > 0) + tower_killing_ideas.listAppend("Stuns: " + stun_sources.listJoinComponents(", ", "and")); + if (stagger_sources.count() > 0) + tower_killing_ideas.listAppend("Stagger sources: " + stagger_sources.listJoinComponents(", ", "and")); + + + + + if ($item[small golem].available_amount() > 0) + { + if ($skill[Ambidextrous Funkslinging].skill_is_usable() && $item[slime stack].available_amount() > 0) + tower_killing_ideas.listAppend("Small golem available. Funksling early in combat with a slime stack for 3k damage/round."); + else + tower_killing_ideas.listAppend("Small golem available. Use early in combat for 3k damage/round."); + } + if ($item[slime stack].available_amount() > 0) + tower_killing_ideas.listAppend($item[slime stack].pluralise() + " available. (15% damage)"); + + if ($skill[frigidalmatian].skill_is_usable() && my_maxmp() >= 300 && $effect[Frigidalmatian].have_effect() == 0) + tower_killing_ideas.listAppend("Possibly cast Frigidalmatian."); + + if (monster_level_adjustment() > 0) + tower_killing_ideas.listAppend(HTMLGenerateSpanFont("Try to reduce your ML", "red") + ", as it reduces damage done to them."); + + if ((my_path().id == PATH_HEAVY_RAINS || $item[water wings for babies].available_amount() >= 3) && $item[water wings for babies].equipped_amount() <3) + tower_killing_ideas.listAppend("Equip three water wings for babies to reduce ML. (increased damage)"); + + if (tower_killing_ideas.count() > 0) + subentry.entries.listAppend("Or towerkill (very difficult):" + HTMLGenerateIndentedText(tower_killing_ideas.listJoinComponents("
"))); + else + subentry.entries.listAppend("Or towerkill."); + + if ($item[dumb mud].available_amount() > 0) + subentry.entries.listAppend("Or just use dumb mud, which will insta-kill a tower monster."); + } + + if (level <= 3) + url = "lair4.php"; + else + url = "lair5.php"; + }*/ + + if (should_output_main_entry) + task_entries.listAppend(ChecklistEntryMake(image_name, url, subentries).ChecklistEntrySetIDTag("Council L13 quest")); +} + + +void QManorInit() +{ + QuestState state; + + + state.state_boolean["need ballroom song set"] = false; + + if (my_path().id == PATH_GELATINOUS_NOOB || in_bad_moon()) + state.state_boolean["need ballroom song set"] = true; + + //Trace every quest where it's worth setting the song: + //Let's see... + //L2: relevant + //L3: relevant...? (skipping NCs) + //L5: theoretically relevant (acquiring the KGE outfit without semi-rare) + //L6: relevant + //L7: relevant (two areas) + //L8: relevant (climbing the mountain, acquiring mining outfit) + //L9: relevant (twin peak) + //L10: relevant (everywhere) + //HitS: relevant (unlock) + //L11: relevant (black forest, ballroom, pirates, hidden park, temple unlock, city unlock without semi-rare) + //L12: relevant (starting the war) + //L13: relevant, but marginal (south of the border, zap wand) + //Pirates: relevant (acquiring outfit) + if (__misc_state["can reasonably reach -25% combat"]) + state.state_boolean["need ballroom song set"] = false; + if (my_turncount() >= 200) + state.state_boolean["need ballroom song set"] = false; + + + if (__misc_state_string["ballroom song"] == "-combat") + state.state_boolean["need ballroom song set"] = false; + + if ($location[the haunted ballroom].delayRemainingInLocation() == 0) //probably not worth it anymore + state.state_boolean["need ballroom song set"] = false; + + if ($location[the haunted ballroom].delayRemainingInLocation() > 0) + state.state_boolean["ballroom needs delay burned"] = true; + + state.state_boolean["ballroom song effectively set"] = !state.state_boolean["need ballroom song set"]; + if (combat_rate_modifier() <= -25.0) + state.state_boolean["ballroom song effectively set"] = true; + if (__quest_state["Level 13"].in_progress || (__quest_state["Level 13"].finished && my_path().id != PATH_BUGBEAR_INVASION) || questPropertyPastInternalStepNumber("questL13Final", 1)) + state.state_boolean["ballroom song effectively set"] = true; + + if (state.state_boolean["ballroom song effectively set"]) + state.state_boolean["need ballroom song set"] = false; + + + + if (locationAvailable($location[the haunted ballroom]) && !(state.state_boolean["need ballroom song set"] || state.state_boolean["ballroom needs delay burned"])) + QuestStateParseMafiaQuestPropertyValue(state, "finished"); + else + { + QuestStateParseMafiaQuestPropertyValue(state, "started"); + } + if (my_path().id == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + if (my_path().id == PATH_SEA) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + state.quest_name = "Spookyraven Manor Unlock"; + state.image_name = "Spookyraven Manor"; + + + /*location zone_to_work_on = $location[none]; + if (!locationAvailable($location[the haunted billiards room])) + { + zone_to_work_on = $location[the haunted billiards room]; + } + else if (!locationAvailable($location[the haunted library])) + { + zone_to_work_on = $location[the haunted library]; + } + else if (!locationAvailable($location[the haunted bedroom])) + { + zone_to_work_on = $location[the haunted bedroom]; + } + else if (!locationAvailable($location[the haunted ballroom])) + { + zone_to_work_on = $location[the haunted ballroom]; + } + state.state_string["zone to work on"] = zone_to_work_on;*/ + + __quest_state["Manor Unlock"] = state; +} + + +void QManorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__quest_state["Manor Unlock"].in_progress && __misc_state["in run"]) + return; + if (my_level() < 5 && my_ascensions() == 0 && !QuestState("questM21Dance").in_progress) return; //not yet possible + + boolean should_output_optionally = false; + boolean should_output_futurally = false; + QuestState base_quest_state = __quest_state["Manor Unlock"]; + + boolean [location] relevant_locations = $locations[the haunted kitchen, the haunted library, the haunted billiards room, the haunted bedroom, the haunted ballroom, the haunted gallery, the haunted bathroom]; + //$locations[the haunted kitchen, the haunted library, the haunted billiards room, the haunted bedroom, the haunted ballroom]; + + + if (!__misc_state["in run"] && !(relevant_locations contains __last_adventure_location)) + return; + ChecklistSubentry subentry; + //subentry.header = "Unlock Spookyraven Manor"; + + //This is currently very incomplete, sorry. + + string url = ""; + + string image_name; + + boolean ballroom_probably_open = false; + if ($location[the haunted ballroom].turnsAttemptedInLocation() > 0) + ballroom_probably_open = true; + if (__misc_state_string["ballroom song"] != "") //FALSE if they haven't ascended since the revamp, I guess + ballroom_probably_open = true; + if (get_property("questM21Dance") == "finished") + ballroom_probably_open = true; + + boolean second_floor_probably_open = false; + + //if (to_item("7301").available_amount() == 0 || to_item("7302").available_amount() == 0) //first floor can be skipped via faxing + //second_floor_probably_open = false; + if (get_property_ascension("lastSecondFloorUnlock")) //updates properly now + second_floor_probably_open = true; + if (get_property("questM20Necklace") == "finished") //mafia will erroneously set questM20Necklace to finished in certain (unknown) cases. could be an error in QuestDatabase.java's reset(), but I am uncertain what caused the bug locally (it also set lastSecondFloorUnlock to current, though it is not unlocked) note - still in effect. additional information: south of the border? + second_floor_probably_open = true; + + if ($item[Lady Spookyraven's necklace].available_amount() > 0) //mostly + second_floor_probably_open = true; + if ($item[telegram from Lady Spookyraven].available_amount() > 0) + second_floor_probably_open = false; + + if (second_floor_probably_open && __misc_state["in run"]) + { + if ($item[Lady Spookyraven's necklace].available_amount() > 0 && get_property("questM20Necklace") != "finished") + { + subentry.header = "Speak to Lady Spookyraven"; + url = $location[the haunted kitchen].getClickableURLForLocation(); + image_name = "Lady Spookyraven"; + subentry.entries.listAppend("Give her her necklace."); + } + else + { + QuestState dance_quest_state; + QuestStateParseMafiaQuestProperty(dance_quest_state, "questM21Dance"); + if (!dance_quest_state.finished && !($location[the haunted ballroom].noncombat_queue.contains_text("Having a Ball in the Ballroom"))) + { + ChecklistSubentry [int] subentries; + //Haunted gallery, bathroom, bedroom + url = $location[the haunted gallery].getClickableURLForLocation(); + + + if (dance_quest_state.mafia_internal_step <= 1) + { + subentries.listAppend(ChecklistSubentryMake("Speak to Lady Spookyraven", "", "To open the haunted gallery, bathroom, and bedroom.")); + image_name = "Lady Spookyraven"; + } + else + { + if ($item[Lady Spookyraven's dancing shoes].available_amount() == 0 && dance_quest_state.mafia_internal_step < 4) + { + //NC (louvre or leave it) in gallery + string [int] modifiers; + string [int] description; + + description.listAppend("Find Lady Spookyraven's dancing shoes in the Louvre non-combat."); + + subentries.listAppend(ChecklistSubentryMake("Search in the Haunted Gallery", modifiers, description)); + if (image_name.length() == 0) + image_name = "__item antique painting of a landscape"; + + boolean garden_banished = CounterLookup("Garden Banished").CounterExists(); + + boolean need_minus_combat = false; + + if (delayRemainingInLocation($location[the haunted gallery]) > 0) + { + string line = "Delay for " + pluralise(delayRemainingInLocation($location[the haunted gallery]), "turn", "turns") + "."; + if (__misc_state["have hipster"]) + { + modifiers.listAppend(__misc_state_string["hipster name"]+"?"); + } + if (!garden_banished) + { + line += " Try to find the garden NC to banish it."; + need_minus_combat = true; + } + description.listAppend(line); + } + else + need_minus_combat = true; + + if (need_minus_combat) + modifiers.listAppend("-combat"); + + modifiers.listAppend("+meat"); + } + if ($item[Lady Spookyraven's powder puff].available_amount() == 0 && dance_quest_state.mafia_internal_step < 4) + { + string [int] modifiers; + string [int] description; + description.listAppend("Find Lady Spookyraven's powder puff. (NC leads to cosmetics wraith)"); + //combat rate extremely approximate, needs spading + + if (delayRemainingInLocation($location[the haunted bathroom]) == 0) + description.listAppend(generateTurnsToSeeNoncombat(85, 1, "find cosmetics wraith", 10 - delayRemainingInLocation($location[the haunted bathroom]), delayRemainingInLocation($location[the haunted bathroom]))); + subentries.listAppend(ChecklistSubentryMake("Search in the Haunted Bathroom", modifiers, description)); + + if (image_name.length() == 0) + image_name = "__item bottle of Monsieur Bubble"; + if (delayRemainingInLocation($location[the haunted bathroom]) > 0) + { + string line = "Delay for " + pluralise(delayRemainingInLocation($location[the haunted bathroom]), "turn", "turns") + "."; + if (__misc_state["have hipster"]) + { + modifiers.listAppend(__misc_state_string["hipster name"]+"?"); + } + description.listAppend(line); + } + else + modifiers.listAppend("-combat"); + } + if ($item[Lady Spookyraven's finest gown].available_amount() == 0 && dance_quest_state.mafia_internal_step < 4) + { + //elegant nightstand in bedroom (banish?) + //also acquire disposable instant camera. spectacles...? + //banishing may not help much? + string [int] modifiers; + string [int] description; + + description.listAppend("Find Lady Spookyraven's finest gown in the elegant nightstand."); + + string [int] items_needed_from_ornate_drawer; + + if ($item[lord spookyraven's spectacles].available_amount() == 0 && __quest_state["Level 11 Manor"].state_boolean["Can use fast route"]) + items_needed_from_ornate_drawer.listAppend("lord spookyraven's spectacles"); + + if (__quest_state["Level 11 Palindome"].state_boolean["Need instant camera"] && 7266.to_item().available_amount() == 0) + items_needed_from_ornate_drawer.listAppend("disposable instant camera"); + + + if (items_needed_from_ornate_drawer.count() > 0) + { + description.listAppend("Banish non-ornate drawers."); + modifiers.listAppend("banish non-ornate"); + } + else + { + description.listAppend("Banish non-elegant drawers."); + modifiers.listAppend("banish non-elegant"); + } + + if (items_needed_from_ornate_drawer.count() > 0) + description.listAppend("Also acquire " + items_needed_from_ornate_drawer.listJoinComponents(", ", "and") + " from the ornate drawer."); + + + if (delayRemainingInLocation($location[the haunted bedroom]) > 0) + { + string line = "Delay for " + pluralise(delayRemainingInLocation($location[the haunted bedroom]), "turn", "turns") + "."; + if (__misc_state["have hipster"]) + { + line += " (use " + __misc_state_string["hipster name"] + ")"; + modifiers.listAppend(__misc_state_string["hipster name"]); + } + description.listAppend(line); + } + + + subentries.listAppend(ChecklistSubentryMake("Search in the Haunted Bedroom", modifiers, description)); + if (image_name.length() == 0) + image_name = "Haunted Bedroom"; + + } + if ($item[Lady Spookyraven's dancing shoes].available_amount() > 0 && $item[Lady Spookyraven's powder puff].available_amount() > 0 && $item[Lady Spookyraven's finest gown].available_amount() > 0 || dance_quest_state.mafia_internal_step == 4) + { + if (dance_quest_state.mafia_internal_step < 4) + { + subentry.header = "Speak with Lady Spookyraven"; + subentry.entries.listAppend("Dancing."); + } + else + { + subentry.header = "Dance with Lady Spookyraven"; + subentry.entries.listAppend("Adventure in the Haunted Ballroom."); + subentry.entries.listAppend("Gives stats."); + } + image_name = "Lady Spookyraven"; + } + } + //FIXME suggest acquiring instant camera and spectacles + if (subentries.count() > 0) + { + task_entries.listAppend(ChecklistEntryMake(image_name, url, subentries, relevant_locations)); + } + } + else + { + if (base_quest_state.state_boolean["ballroom needs delay burned"] && __quest_state["Level 11"].mafia_internal_step < 3) + { + ChecklistSubentry [int] subentries2; + string [int] modifiers2; + if (__misc_state["have hipster"]) + modifiers2.listAppend(__misc_state_string["hipster name"]); + if (__misc_state["free runs available"]) + modifiers2.listAppend("free runs"); + + subentries2.listAppend(ChecklistSubentryMake("Burn " + pluralise($location[the haunted ballroom].delayRemainingInLocation(), "turn", "turns") + " delay in haunted ballroom", modifiers2, "")); + ChecklistEntry entry2 = ChecklistEntryMake("__half Haunted Ballroom", $location[the haunted ballroom].getClickableURLForLocation(), subentries2, $locations[the haunted ballroom]); + entry2.tags.id = "Manor spookyraven ballroom delay"; + entry2.importance_level = 5; + optional_task_entries.listAppend(entry2); + //subentry.header = ; + } + if (base_quest_state.state_boolean["need ballroom song set"]) + { + subentry.header = "Possibly set -combat ballroom song"; + url = $location[the haunted ballroom].getClickableURLForLocation(); + image_name = "__item the Legendary Beat"; + subentry.modifiers.listAppend("-combat"); + + subentry.entries.listAppend("Adventure in the Haunted Ballroom. May not be relevant."); + if (!$location[the haunted ballroom].noncombat_queue.contains_text("Curtains")) //initiate NC rejection + subentry.entries.listAppend(HTMLGenerateSpanFont("Do not skip the curtains NC the first time", "red") + ", this will make the ballroom song more likely to appear."); + + if (my_turncount() > 200 || base_quest_state.state_boolean["ballroom song effectively set"]) + { + should_output_optionally = true; + } + subentry.entries.listAppend(generateTurnsToSeeNoncombat(90, 2, "")); //may be 90% now? is this worth setting anymore? + } + } + } + } + else if ($item[telegram from Lady Spookyraven].available_amount() > 0) + { + //telegram is removed on using it, even on old copies of mafia + subentry.header = "Read telegram from Lady Spookyraven"; + url = "inventory.php?ftext=telegram+from+Lady+Spookyraven"; + image_name = "__item telegram from Lady Spookyraven"; + } + else if (to_item("7301").available_amount() == 0) //Spookyraven billiards room key + { + if (my_path().id == PATH_COMMUNITY_SERVICE && __last_adventure_location != $location[the haunted kitchen]) + return; + if (!__misc_state["in run"] && __last_adventure_location != $location[the haunted kitchen]) return; + subentry.header = "Adventure in the Haunted Kitchen"; + url = $location[the haunted kitchen].getClickableURLForLocation(); + image_name = "__item tiny knife and fork"; + subentry.entries.listAppend("To unlock the Haunted Billiards Room."); + + /*if (get_property_monster("romanticTarget") == $monster[writing desk] && get_property_int("_romanticFightsLeft") > 0 || get_property_int("writingDesksDefeated") > 0 && __misc_state["in run"]) + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Avoid adventuring here,", "red") + " as you seem to be using the writing desk trick?|Need to fight " + pluraliseWordy(clampi(5 - get_property_int("writingDesksDefeated"), 0, 5), "more writing desk.", "more writing desks.")); + should_output_futurally = true; + }*/ + + float hot_resistance = MIN(numeric_modifier("hot resistance"), 9.0); + float stench_resistance = MIN(numeric_modifier("stench resistance"), 9.0); + + int more_hot_needed = 9 - hot_resistance.to_int(); + int more_stench_needed = 9 - stench_resistance.to_int(); + + + string [int] needed_resists; + if (more_hot_needed > 0) + needed_resists.listAppend(more_hot_needed + " more " + HTMLGenerateSpanOfClass("hot", "r_element_hot") + " resistance"); + if (more_stench_needed > 0) + needed_resists.listAppend(more_stench_needed + " more " + HTMLGenerateSpanOfClass("stench", "r_element_stench") + " resistance"); + + //subentry.entries.listAppend("Run 9 " + HTMLGenerateSpanOfClass("hot", "r_element_hot") + " resistance and " + HTMLGenerateSpanOfClass("stench", "r_element_stench") + " resistance to search faster."); + + float drawers_per_turn = 1.0 + MAX(hot_resistance / 6.0, 0.0) + MAX(stench_resistance / 6.0, 0.0); + + int drawers_needed = MAX(0, 21 - get_property_int("manorDrawerCount")); + + int total_turns = ceil(drawers_needed / drawers_per_turn) + 1; + + if (drawers_needed == 0.0) + subentry.entries.listAppend("Find the key next turn."); + else { + string line; + if (hot_resistance <= 0 && stench_resistance <= 0) + line = "1 drawer"; //roundForOutput returns a string, incompatible with pluralise() + else + line = drawers_per_turn.roundForOutput(1) + " drawers"; + line += " searched per turn.|"; + + if (drawers_needed > drawers_per_turn.floor()) { + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("hot res", "r_element_hot_desaturated")); + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("stench res", "r_element_stench_desaturated")); + + line += "~"; + if (needed_resists.count() > 0) { + subentry.entries.listAppend("Run " + needed_resists.listJoinComponents(", ", "and") + " to search faster."); + if (!__misc_state["familiars temporarily blocked"] && $familiar[exotic parrot].familiar_is_usable() && my_familiar() != $familiar[exotic parrot]) + subentry.entries.listAppend("Possibly bring along your exotic parrot."); + } + } + + line += total_turns + " turns remaining, " + drawers_needed + " drawers remaining."; + subentry.entries.listAppend(line); + } + + if (__misc_state["have hipster"]) + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + + if (inebriety_limit() > 10 && my_inebriety() < 10) + subentry.entries.listAppend("Try not to drink past ten, the billiards room is next."); + } + else if (to_item("7302").available_amount() == 0) //Spookyraven library key + { + //Find key: + subentry.header = "Adventure in the Haunted Billiards Room"; + url = $location[the Haunted Billiards Room].getClickableURLForLocation(); + image_name = "__item pool cue"; + subentry.entries.listAppend("To unlock the Haunted Library."); + + int estimated_pool_skill = get_property_int("poolSkill"); + + /*if ($effect[chalky hand].have_effect() > 0) + estimated_pool_skill += 3; + + if ($item[2268].equipped_amount() > 0) //staff of fats + estimated_pool_skill += 5; + if (to_item("7961").equipped_amount() > 0) + estimated_pool_skill += 5; + if ($item[pool cue].equipped_amount() > 0) + estimated_pool_skill += 3; + if ($effect[chalked weapon].have_effect() > 0) + estimated_pool_skill += 5; + if ($effect[video... games?].have_effect() > 0) + estimated_pool_skill += 5; + if ($effect[swimming with sharks].have_effect() > 0) + estimated_pool_skill += 3;*/ + estimated_pool_skill += numeric_modifier("pool skill"); + + int theoretical_hidden_pool_skill = 0; + if (my_inebriety() <= 10) + theoretical_hidden_pool_skill = my_inebriety(); + else + theoretical_hidden_pool_skill = 10 - (my_inebriety() - 10) * 2; + + estimated_pool_skill += theoretical_hidden_pool_skill; + estimated_pool_skill += clampi(floor(2.0 * sqrt(get_property("poolSharkCount").to_float())), 0, 10); + + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("Train pool skill via -combat. Need 14 up to 18(?) total pool skill.|Have ~" + estimated_pool_skill + " pool skill."); + + int missing_pool_skill = MAX(18 - estimated_pool_skill, 0); + + if (missing_pool_skill > 0) + { + if ($item[Staff of Ed, almost].available_amount() > 0) + { + subentry.entries.listAppend("Untinker the Staff of Ed, almost."); + } + else if ($item[2268].available_amount() > 0) //staff of fats + { + if ($item[2268].equipped_amount() == 0) //staff of fats + { + subentry.entries.listAppend("Equip the Staff of Fats for +pool skill."); + } + } + else + { + if ($item[pool cue].available_amount() == 0) + { + subentry.entries.listAppend("Find pool cue."); + } + else if (my_path().id == PATH_GELATINOUS_NOOB) + { + subentry.entries.listAppend("Absorb pool cue for +pool skill?"); + } + else if ($item[pool cue].equipped_amount() == 0) + { + subentry.entries.listAppend("Equip pool cue for +pool skill."); + } + } + if ($effect[chalky hand].have_effect() == 0& $item[handful of hand chalk].available_amount() > 0) + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Use handful of hand chalk", "red") + " for +pool skill and faster pool skill training."); + url = "inventory.php?ftext=handful+of+hand+chalk"; + } + } + + if (inebriety_limit() > 0) + { + int desired_drunkenness = MIN(inebriety_limit(), 10); + if (my_inebriety() < desired_drunkenness) + { + int more_drunkenness = MIN(availableDrunkenness(), MIN(missing_pool_skill, desired_drunkenness - my_inebriety())); + if (more_drunkenness > 0) + subentry.entries.listAppend("Consider drinking " + more_drunkenness + " more drunkenness."); + } + + if (missing_pool_skill > 0 && my_inebriety() > 10) + subentry.entries.listAppend(HTMLGenerateSpanFont("Consider waiting for rollover for better pool skill.", "red") + " (you're over 10 drunkenness.)"); + } + if (my_inebriety() > 0 && false) + { + //shortly after rollover during the revamp, drunkenness affected listed pool skill in the quest log + //exact values were 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 8, 6, 4, 2, 0, -2, -4, -6, -8 + + string pool_skill_string; + if (theoretical_hidden_pool_skill >= 0) + pool_skill_string = "+"; + pool_skill_string += theoretical_hidden_pool_skill; + subentry.entries.listAppend("Drunkenness effect: " + pool_skill_string + " pool skill."); + } + } + else if (!second_floor_probably_open) + { + //Library: + subentry.header = "Adventure in the Haunted Library"; + url = $location[the Haunted Billiards Room].getClickableURLForLocation(); + image_name = "__item very overdue library book"; + subentry.modifiers.listAppend("olfact writing desk"); + + int desks_remaining = clampi(5 - get_property_int("writingDesksDefeated"), 0, 5); + subentry.entries.listAppend("To unlock the second floor."); + subentry.entries.listAppend("Defeat " + pluraliseWordy(desks_remaining, "more writing desk", "more writing desks") + " to acquire a necklace."); + + boolean need_killing_jar = false; + if ($item[killing jar].available_amount() == 0 && !__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && !__quest_state["Level 11 Desert"].state_boolean["Killing Jar Given"]) + { + need_killing_jar = true; + subentry.modifiers.listAppend("+900% item"); + subentry.entries.listAppend("Try to acquire a killing jar to speed up the desert later.|10% drop from banshee librarian."); + } + if (!need_killing_jar && (!$monster[banshee librarian].is_banished() || !$monster[bookbat].is_banished())) + { + subentry.modifiers.listAppend("banish rest"); + } + + } + if (subentry.header != "") + { + if (image_name.length() == 0) + image_name = base_quest_state.image_name; + ChecklistEntry entry = ChecklistEntryMake(image_name, url, subentry, relevant_locations); + entry.tags.id = "Manor spookyraven quest"; + if (should_output_futurally) + future_task_entries.listAppend(entry); + else if (should_output_optionally) + optional_task_entries.listAppend(entry); + else + task_entries.listAppend(entry); + } +} + + +void QPirateInit() +{ + //questM12Pirate ? + //lastPirateInsult1 through lastPirateInsult8 + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questM12Pirate"); + state.quest_name = "Pirate Quest"; + state.image_name = "pirate quest"; + + state.state_boolean["valid"] = false; // now invalid by default since the 2020 change + + if (my_path().id == PATH_LOW_KEY_SUMMER) + state.state_boolean["valid"] = true; + + if (__misc_state["mysterious island available"] && state.state_boolean["valid"]) { + state.startable = true; + if (!state.in_progress && !state.finished) { + QuestStateParseMafiaQuestPropertyValue(state, "started"); + } + } + + + boolean hot_wings_relevant = knoll_available() || $item[frilly skirt].available_amount() > 0 || !in_hardcore(); + if (state.mafia_internal_step >= 4) //done that already + hot_wings_relevant = false; + boolean need_more_hot_wings = $item[hot wing].available_amount() <3 && hot_wings_relevant; + + state.state_boolean["hot wings relevant"] = hot_wings_relevant; + state.state_boolean["need more hot wings"] = need_more_hot_wings; + + + int insult_count = 0; + for i from 1 to 8 { + if (get_property_boolean("lastPirateInsult" + i)) + insult_count += 1; + } + state.state_int["insult count"] = insult_count; + + if ($item[Orcish Frat House blueprints].available_amount() > 0 && state.mafia_internal_step <3 ) + QuestStateParseMafiaQuestPropertyValue(state, "step2"); + + //Certain characters are in weird states, I think? (now obsolete; these two quests are no longer linked) + /*if ($item[pirate fledges].available_amount() > 0 || $item[talisman o\' namsilat].available_amount() > 0) + QuestStateParseMafiaQuestPropertyValue(state, "finished");*/ + __quest_state["Pirate Quest"] = state; +} + + +void QPirateCoveGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (__quest_state["Island War"].state_boolean["War in progress"]) return; + + QuestState base_quest_state = __quest_state["Pirate Quest"]; + ChecklistSubentry subentry; + subentry.header = base_quest_state.quest_name; + string url = ""; + + + boolean have_outfit = have_outfit_components("Swashbuckling Getup"); + if ($item[pirate fledges].available_amount() > 0) + have_outfit = true; + boolean is_a_pirate = is_wearing_outfit("Swashbuckling Getup") || $item[pirate fledges].equipped_amount() > 0; + + int insult_count = base_quest_state.state_int["insult count"]; + + float [int] insult_success_likelyhood; + //haven't verified these numbers, need to double-check + insult_success_likelyhood[0] = 0.0; + insult_success_likelyhood[1] = 0.0; + insult_success_likelyhood[2] = 0.0; + insult_success_likelyhood[3] = 0.0179; + insult_success_likelyhood[4] = 0.071; + insult_success_likelyhood[5] = 0.1786; + insult_success_likelyhood[6] = 0.357; + insult_success_likelyhood[7] = 0.625; + insult_success_likelyhood[8] = 1.0; + + boolean delay_for_future = false; + boolean can_acquire_cocktail_napkins = false; + + if (in_ronin() && $item[Talisman o\' Namsilat].available_amount() == 0 && my_path().id != PATH_LOW_KEY_SUMMER) + subentry.entries.listAppend(HTMLGenerateSpanFont("Pirates won't help you in-run anymore.", "red")); + + if (!have_outfit) { + url = "island.php"; + string line = "Acquire outfit."; + + item [int] outfit_pieces = outfit_pieces("Swashbuckling Getup"); + item [int] outfit_pieces_needed; + foreach key in outfit_pieces { + item piece = outfit_pieces[key]; + if (piece.available_amount() == 0) + outfit_pieces_needed.listAppend(piece); + } + line += " Need " + outfit_pieces_needed.listJoinComponents(", ", "and") + "."; + subentry.entries.listAppend(line); + + subentry.modifiers.listAppend("+item"); + subentry.modifiers.listAppend("-combat"); + + if ($familiar[slimeling].familiar_is_usable()) + subentry.modifiers.listAppend("slimeling?"); + + int ncs_relevant = 0; //out of six + if ($item[stuffed shoulder parrot].available_amount() == 0 || $item[eyepatch].available_amount() == 0) + ncs_relevant += 1; + if ($item[eyepatch].available_amount() == 0 || $item[swashbuckling pants].available_amount() == 0) + ncs_relevant += 1; + if ($item[swashbuckling pants].available_amount() == 0 || $item[stuffed shoulder parrot].available_amount() == 0) + ncs_relevant += 1; + + float average_combat_rate = clampNormalf(.6 + combat_rate_modifier() / 100.0); + float average_nc_rate = 1.0 - average_combat_rate; + + float average_useful_nc_rate = average_nc_rate * (ncs_relevant.to_float() / 6.0); + //FIXME make this more accurate + float turns_remaining = -1.0; + if (average_useful_nc_rate != 0.0) + turns_remaining = outfit_pieces_needed.count().to_float() / average_useful_nc_rate; + subentry.entries.listAppend("Run -combat in the obligatory pirate's cove." + "|~" + turns_remaining.roundForOutput(1) + " turns remain at " + combat_rate_modifier().floor() + "% combat."); + + if (!__quest_state["Manor Unlock"].state_boolean["ballroom song effectively set"]) { + subentry.entries.listAppend(HTMLGenerateSpanOfClass("Wait until -combat ballroom song set.", "r_bold")); + delay_for_future = true; + } + } else { + url = "place.php?whichplace=cove"; + + if (!is_a_pirate) + url = "inventory.php?which=2"; + + boolean have_all_fcle_items = false; + + if (base_quest_state.mafia_internal_step == 1) { + can_acquire_cocktail_napkins = true; + //caronch gave you a map + if ($item[Cap'm Caronch's nasty booty].available_amount() == 0 && $item[Cap'm Caronch's Map].available_amount() > 0) { + url = "inventory.php?ftext=cap'm+caronch's+map"; + subentry.entries.listAppend("Use Cap'm Caronch's Map, fight a booty crab."); + subentry.entries.listAppend("Possibly run +meat. (300 base drop)"); + subentry.modifiers.listAppend("+meat"); + } else if (have_outfit) { + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("Find Cap'm Caronch in Barrrney's Barrr."); + } + } else if (base_quest_state.mafia_internal_step == 2) { + can_acquire_cocktail_napkins = true; + //give booty back to caronch + subentry.entries.listAppend("Find Cap'm Caronch in Barrrney's Barrr."); + } else if (base_quest_state.mafia_internal_step == 3) { + can_acquire_cocktail_napkins = true; + //have blueprints, catburgle + string line = "Use the Orcish Frat House blueprints"; + if (insult_count < 6) { + subentry.modifiers.listAppend("+20% combat"); + line += ", once you have at least six insults"; //in certain situations five might be slightly faster? but that skips a lot of combats, so probably not + } + line += "."; + + string method; + if (have_outfit_components("Frat Boy Ensemble") && __misc_state["can equip just about any weapon"]) { + string [int] todo; + if (!is_wearing_outfit("Frat Boy Ensemble")) + todo.listAppend("wear frat boy ensemble"); + todo.listAppend("attempt a frontal assault"); + method = todo.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."; + } else if ($item[mullet wig].available_amount() > 0 && $item[briefcase].available_amount() > 0) { + string [int] todo; + if ($item[mullet wig].equipped_amount() == 0) + todo.listAppend("wear mullet wig"); + todo.listAppend("go in through the side door"); + method = todo.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."; + } else if (knoll_available() || ($item[frilly skirt].available_amount() > 0 && $item[hot wing].available_amount() >= 3)) { + string [int] todo; + if (insult_count < 6) + todo.listAppend("acquire at least six insults"); + if ($item[hot wing].available_amount() <3 ) + todo.listAppend("acquire " + pluralise((3 - $item[hot wing].available_amount()), "more hot wing", "more hot wings")); + if ($item[frilly skirt].equipped_amount() == 0) + todo.listAppend("wear frilly skirt"); + todo.listAppend("catburgle"); + string line2 = todo.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."; + method = line2; + } else { + //Non-knoll sign. + //I think the fastest method is frilly skirt? + if ($item[hot wing].available_amount() >= 3 && my_familiar() != $familiar[black cat]) + method = "Farm a frilly skirt in the knoll gym. (+300% item)"; + else { + method = "Acquire a frat boy outfit in the frat house? (-combat" + (my_level() < 9 ? " after level 9" : "") + ")"; + if (!__quest_state["Level 6"].finished) + method += "|Or collect hot wings from the friar demons" + ($item[frilly skirt].available_amount() == 0 ? ", and frilly skirt from the knoll gym" : "") + "."; + } + } + line += "|" + method; + subentry.entries.listAppend(line); + } else if (base_quest_state.mafia_internal_step == 4) { + //acquired teeth, give them back + subentry.entries.listAppend("Find Cap'm Caronch in Barrrney's Barrr. (next adventure)"); + } else if (base_quest_state.mafia_internal_step == 5) { + //ricketing + subentry.entries.listAppend("Play beer pong."); + subentry.entries.listAppend("If you want more insults now, adventure in the Obligatory Pirate's Cove, not in the Barrr."); + } else if (base_quest_state.mafia_internal_step == 6) { + //f'c'le + //We can't tell them which ones they need, precisely, since they may have already used them. + //We can tell them which ones they have... but it's still unreliable. I guess a single message if they have all three? + string line = "F'c'le."; + string additional_line = ""; + + item [int] missing_washing_items = $items[rigging shampoo,mizzenmast mop,ball polish].items_missing(); + + if (missing_washing_items.count() == 0) { + have_all_fcle_items = true; + url = "inventory.php?which=3"; + line += " " + HTMLGenerateSpanFont("Use rigging shampoo, mizzenmast mop, and ball polish", "red") + ", then adventure to complete quest."; + } else { + subentry.modifiers.listAppend("+234% item"); + subentry.modifiers.listAppend("+20% combat"); + string [int] missing_washing_items_wordy; + foreach key in missing_washing_items { + if (missing_washing_items [key] == $item[rigging shampoo]) + missing_washing_items_wordy.listAppend("rigging shampoo (cleanly pirate)"); + else if (missing_washing_items [key] == $item[mizzenmast mop]) + missing_washing_items_wordy.listAppend("mizzenmast mop (curmudgeonly pirate)"); + else if (missing_washing_items [key] == $item[ball polish]) + missing_washing_items_wordy.listAppend("ball polish (creamy pirate)"); + } + line += " Run +234% item, +combat, and collect " + missing_washing_items_wordy.listJoinComponents(", ", "and") + "."; + if ($location[the f'c'le].item_drop_modifier_for_location() < 234.0) + additional_line = "This location can be a nightmare without +234% item."; + + subentry.modifiers.listAppend("banish chatty/crusty pirate"); + } + + subentry.entries.listAppend(line); + if (!have_all_fcle_items) + subentry.entries.listAppend("Don't use the items right away: we can't tell if you did!"); + if (additional_line != "") + subentry.entries.listAppend(additional_line); + if (!($monster[clingy pirate (female)].is_banished() || $monster[clingy pirate (male)].is_banished()) && $item[cocktail napkin].available_amount() > 0 && !have_all_fcle_items) { + subentry.entries.listAppend("Use cocktail napkin on clingy pirate to " + (__misc_state["free runs usable"] ? "free run/" : "") + "banish."); + } + } else if (base_quest_state.mafia_internal_step == 7) { + //The Poop Deck + if (__quest_state["Level 11"].mafia_internal_step < 3) { + if (my_path().id == PATH_COMMUNITY_SERVICE || __quest_state["Level 11"].mafia_internal_step == 0 && get_property_int("lastCouncilVisit") >= 11) { //They CANNOT get the password, and are only here for the zone itself + QuestStateParseMafiaQuestPropertyValue(base_quest_state, "finished"); + subentry.entries.listAppend("Watch out for that recurring non-combat..."); + } else + subentry.entries.listAppend("Come back when you've read from your father's MacGuffin diary, or you'll keep getting beaten up by the recurring non-combat."); + } else { + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("Run -combat on the Poop Deck to unlock belowdecks."); + subentry.entries.listAppend(generateTurnsToSeeNoncombat(80, 1, "unlock belowdecks")); + } + } + + if (base_quest_state.mafia_internal_step <= 3 && my_inebriety() > 0) { + subentry.entries.listAppend("Could wait until rollover; one of the non-combats can become a combat at zero drunkenness."); + } + + + if (__misc_state["free runs available"] && !can_acquire_cocktail_napkins && !have_all_fcle_items) + subentry.modifiers.listAppend("free runs"); + } + boolean should_output_insult_data = false; + if ($item[the big book of pirate insults].available_amount() > 0 || have_outfit) + should_output_insult_data = true; + if (base_quest_state.mafia_internal_step >= 6) + should_output_insult_data = false; + + if (should_output_insult_data) { + string line = "At " + pluralise(insult_count, "insult", "insults") + ". " + roundForOutput(insult_success_likelyhood[insult_count] * 100, 1) + "% chance of beer pong success."; + if (insult_count < 8) + line += "|Insult every pirate with the big book of pirate insults."; + subentry.entries.listAppend(line); + } + if ($item[the big book of pirate insults].available_amount() == 0 && base_quest_state.mafia_internal_step < 6 && have_outfit) + subentry.entries.listAppend(HTMLGenerateSpanFont("Buy the big book of pirate insults.", "red")); + + if (can_acquire_cocktail_napkins && $item[cocktail napkin].available_amount() == 0) { + subentry.modifiers.listAppend("+item"); + subentry.entries.listAppend("Try to acquire a cocktail napkin to speed up F'c'le. (10% drop, marginal)"); + } + + if (have_outfit && !is_a_pirate) { + string line; + if ($item[pirate fledges].available_amount() > 0 && my_basestat($stat[mysticality]) >= 60) { + line = "Wear pirate fledges."; + } else if (!is_wearing_outfit("Swashbuckling Getup")) { + string [int] stats_needed; + if (my_basestat($stat[moxie]) < 25) + stats_needed.listAppend("moxie"); + if (my_basestat($stat[mysticality]) < 25) + stats_needed.listAppend("mysticality"); + line = "Wear swashbuckling getup."; + + if (stats_needed.count() > 0) { + delay_for_future = true; + line += HTMLGenerateSpanOfClass(" Need 25 " + stats_needed.listJoinComponents(", ", "and"), "r_bold") + "."; + } + } + subentry.entries.listAppend(line); + } + + ChecklistEntry entry = ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the obligatory pirate's cove, barrrney's barrr, the f'c'le,The Poop Deck]); + entry.tags.id = "Island pirates quest"; + entry.tags.combination = "pirates"; + + if (__misc_state["in run"] && base_quest_state.state_boolean["valid"]) { + if (delay_for_future) + future_task_entries.listAppend(entry); + else + task_entries.listAppend(entry); + } else + optional_task_entries.listAppend(entry); +} + +void QPoopDeckGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //O Cap'm, My Cap'm helper; the main feature of this section, now! + ChecklistSubentry subentry; + subentry.header = "Sail the sea"; + string url = "place.php?whichplace=cove"; + + if ($item[pirate fledges].equipped_amount() == 0) { + subentry.entries.listAppend("Wear pirate fledges."); + url = "inventory.php?ftext=pirate+fledges"; + } + + if (true) { //for when the last o'cap'm, my cap'm property will be implemented (if) + if (my_meat() < 977) { + subentry.entries.listAppend(HTMLGenerateSpanOfClass("Start by acquiring 977 meat.", "r_bold") + (__misc_state["need to level"] ? ", to gain extra stats from the other NC" : "") + "."); + } else { + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("Adventure on the Poop Deck until you get O Cap'm, My Cap'm."); + } + } else { + //how many turns they'll need to burn in the zone to get the adventure again + } + + subentry.entries.listAppend("*Sail to (48,47) to get an El Vibrato power sphere (or buy from mall)."); + if (item_amount_almost_everywhere(lookupItem("El Vibrato trapezoid")) == 0 && $location[El Vibrato Island].turns_spent == 0 && __campground[lookupItem("El Vibrato trapezoid")] == 0) { //mafia only registers the trapezoid in the campground from revisiton 20267 and onward + string line = "*Sail to (63,29) to get an El Vibrato trapezoid."; + if (!mafiaIsPastRevision(20267)) //Means that we can't trust "__campground[lookupItem("El Vibrato trapezoid")] == 0" to be accurate + line += HTMLGenerateSpanFont(" Don't do this if you've already set up a portal at your campground.", "red"); + + if (lookupItem("El Vibrato power sphere").item_amount() == 0) + line += "|*Need an El Vibrato power sphere in inventory. Buy from mall?"; + line += "|*Gives an item that creates a portal to El Vibrato Island at your campground (will need to keep it charged with more power spheres)."; + subentry.entries.listAppend(line); + } + subentry.entries.listAppend("*Or sail to (1,1) to get a random ancient cursed key/chest."); + if (__misc_state["need to level"]) { + string coordinates; + if (my_primestat() == $stat[muscle]) + coordinates = "(56, 14)"; + else if (my_primestat() == $stat[mysticality]) + coordinates = "(3, 35)"; + else if (my_primestat() == $stat[moxie]) + coordinates = "(5, 39)"; + if (coordinates != "") + subentry.entries.listAppend("Could sail to " + coordinates + " for stats?"); + } + + ChecklistEntry entry = ChecklistEntryMake("ship wheel", url, subentry, $locations[The Poop Deck]); + entry.tags.id = "Island pirates poop deck sailing"; + entry.tags.combination = "pirates"; + + if (__misc_state["in run"] && __quest_state["Pirate Quest"].state_boolean["valid"] && __quest_state["Pirate Quest"].in_progress) //To match if QPirateCoveGenerateTasks is being displayed in task or optional_task + task_entries.listAppend(entry); + else + optional_task_entries.listAppend(entry); +} + +void QPirateGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //Show the tile IF: they started the quest, and the quest is valid in this path, OR, they started the quest, and are adventuring in the relevant locations, OR, they started the quest, and are out of run. + if (__quest_state["Pirate Quest"].in_progress && (__quest_state["Pirate Quest"].state_boolean["valid"] || $locations[the obligatory pirate's cove, barrrney's barrr, the f'c'le, the poop deck] contains __last_adventure_location || !__misc_state["in run"])) + QPirateCoveGenerateTasks(task_entries, optional_task_entries, future_task_entries); + + if ($location[The Poop Deck] == __last_adventure_location || __quest_state["Pirate Quest"].mafia_internal_step == 7) + QPoopDeckGenerateTasks(task_entries, optional_task_entries, future_task_entries); +} + + +//"started", "finished" observed for questG04Nemesis + +void QNemesisInit() +{ + if (!($classes[seal clubber, turtle tamer, pastamancer, sauceror, disco bandit, accordion thief] contains my_class())) + return; + //questG04Nemesis + QuestState state; + + + QuestStateParseMafiaQuestProperty(state, "questG04Nemesis"); + if (my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + state.quest_name = "Nemesis Quest"; + state.image_name = "__half Nemesis"; + + if (my_basestat(my_primestat()) >= 12) + state.startable = true; + if (!mafiaIsPastRevision(15935) && state.mafia_internal_step > 1) + state.mafia_internal_step += 4; //hack to support old versions, probably won't work + + __quest_state["Nemesis"] = state; +} + +void QNemesisGenerateIslandTasks(ChecklistSubentry subentry) +{ + if (my_class() == $class[disco bandit]) + { + skill [int] rave_skills_needed; + if (!$skill[Break It On Down].skill_is_usable()) + rave_skills_needed.listAppend($skill[Break It On Down]); + if (!$skill[Pop and Lock It].skill_is_usable()) + rave_skills_needed.listAppend($skill[Pop and Lock It]); + if (!$skill[Run Like the Wind].skill_is_usable()) + rave_skills_needed.listAppend($skill[Run Like the Wind]); + + monster [skill] rave_skills_to_monster; + rave_skills_to_monster[$skill[Break It On Down]] = $monster[breakdancing raver]; + rave_skills_to_monster[$skill[Pop and Lock It]] = $monster[pop-and-lock raver]; + rave_skills_to_monster[$skill[run like the wind]] = $monster[running man]; + + boolean have_all_rave_skills = (rave_skills_needed.count() == 0); + if (!$skill[gothy handwave].skill_is_usable()) + { + subentry.entries.listAppend("Talk to the girl in a black dress."); + } + else if (!have_all_rave_skills) + { + //Learn dance moves. + string [int] monsters_to_fight; + foreach key in rave_skills_needed + { + skill rave_skill = rave_skills_needed[key]; + monsters_to_fight.listAppend(rave_skills_to_monster[rave_skill].to_string()); + } + subentry.entries.listAppend("Learn dance moves from the " + monsters_to_fight.listJoinComponents(", ", "and") + "."); + } + else + { + //Acquire ravosity. + if (numeric_modifier("raveosity") >= 7) + { + subentry.entries.listAppend("Talk to the guard."); + } + else + { + int extra_raveosity_from_equip = 0; + item [int] items_have_but_unequipped; + foreach it in $items[rave visor,baggy rave pants,pacifier necklace,teddybear backpack,glowstick on a string,candy necklace,rave whistle,blue glowstick,green glowstick,purple glowstick,pink glowstick,orange glowstick,yellow glowstick] + { + if (it.available_amount() > 0 && it.equipped_amount() == 0) + { + items_have_but_unequipped.listAppend(it); + extra_raveosity_from_equip += numeric_modifier(it, "raveosity").to_int(); + } + } + + int raveosity_needed = (7 - (extra_raveosity_from_equip + numeric_modifier("raveosity").to_int())); + + if (raveosity_needed > 0) + { + string line = "Rave steal to find "; + + if (raveosity_needed == 1) + line += "One More Raveosity."; + else + line += raveosity_needed.int_to_wordy() + " more raveosity."; + subentry.entries.listAppend(line); + } + + if (items_have_but_unequipped.count() > 0) + subentry.entries.listAppend("Wear " + items_have_but_unequipped.listJoinComponents(", ", "and") + "."); + } + } + } + else if (my_class() == $class[accordion thief]) + { + if ($item[hacienda key].available_amount() >= 5) + subentry.entries.listAppend("All keys found. Fight in the Hacienda."); + else + { + subentry.modifiers.listAppend("-combat"); + int keys_needed = MAX(0, 5 - $item[hacienda key].available_amount()); + subentry.entries.listAppend(pluraliseWordy(keys_needed, "key", "keys").capitaliseFirstLetter() + " to go."); + subentry.entries.listAppend("Four are from the non-combat; one is from pick-pocketing a mariachi."); + } + } + else if (my_class() == $class[pastamancer]) + { + if ($item[spaghetti cult robe].available_amount() > 0) + { + if ($item[spaghetti cult robe].equipped_amount() == 0) + subentry.entries.listAppend("Equip spaghetti cult robe, then enter the lair."); + else + subentry.entries.listAppend("Enter the lair."); + } + else if (my_thrall() == $thrall[spaghetti elemental]) + { + string [int] tasks; + if ($thrall[spaghetti elemental].level <3) + { + string line = "level your cute and adorable spaghetti elemental to 3"; + if ($item[experimental carbon fiber pasta additive].available_amount() > 0) + { + line += " (use the experimental carbon fiber pasta additive)"; + } + tasks.listAppend(line); + } + tasks.listAppend("defeat an evil spaghetti cult middle-manager"); + + subentry.entries.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + } + else if ($skill[Bind Spaghetti Elemental].skill_is_usable()) + { + subentry.entries.listAppend("Cast Bind Spaghetti Elemental."); + } + else + { + if ($item[decoded cult documents].available_amount() > 0) + { + subentry.entries.listAppend("Use decoded cult documents."); + } + else + { + if ($item[encoded cult documents].available_amount() == 0) + subentry.entries.listAppend("Acquire encoded cult documents from a protestor."); + + int missing_cult_memos = MAX(0, 5 - $item[cult memo].available_amount()); + if (missing_cult_memos > 0) + { + subentry.entries.listAppend("Acquire another " + pluralise(missing_cult_memos, $item[cult memo]) + " from middle-managers."); + } + else if ($item[encoded cult documents].available_amount() > 0) + { + subentry.entries.listAppend("Use cult memos."); + } + } + } + } + else if (my_class() == $class[turtle tamer]) + { + if ($item[Fouet de tortue-dressage].available_amount() == 0) + subentry.entries.listAppend("Talk to a guy in the bushes."); + else + { + if ($item[Fouet de tortue-dressage].equipped_amount() == 0) + subentry.entries.listAppend("Equip Fouet de tortue-dressage."); + subentry.entries.listAppend("Use Apprivoisez la tortue on french turtles a bunch, save them!|Then talk to the guy in the bushes."); + } + } + else if (my_class() == $class[sauceror]) + { + if ($item[bottle of Gü-Gone].available_amount() == 0) + subentry.entries.listAppend("Visit the boat."); + else + { + /* + lastSlimeVial3891(user, now 'intensity', default ) + lastSlimeVial3892(user, now 'moxiousness', default ) + lastSlimeVial3893(user, now 'eyesight', default ) + lastSlimeVial3894(user, now 'mentalism', default ) + lastSlimeVial3895(user, now 'muscle', default ) + lastSlimeVial3896(user, now 'slimeform', default ) + */ + if ($effect[slimeform].have_effect() > 0) + subentry.entries.listAppend("Wiggle into the lair.|Also, go visit your mom in the slimetube."); + else + { + + boolean [item] tertiary_potions = $items[vial of vermilion slime,vial of amber slime,vial of chartreuse slime,vial of teal slime,vial of purple slime,vial of indigo slime]; + + item slimeform_potion = $item[none]; + item [int] creatable_unknown_potions; + foreach potion in tertiary_potions + { + string property_value = get_property("lastSlimeVial" + potion.to_int()); + if (property_value.length() == 0) + { + if (potion.available_amount() + potion.creatable_amount() > 0) + creatable_unknown_potions.listAppend(potion); + } + else if (property_value == "slimeform") + slimeform_potion = potion; + } + if (slimeform_potion != $item[none] && slimeform_potion.creatable_amount() + slimeform_potion.available_amount() > 0) + { + subentry.entries.listAppend("Use a " + slimeform_potion + " to gain slimeform."); + //FIXME URL + } + else + { + subentry.entries.listAppend("Use the " + $item[bottle of Gü-Gone] + " on slime, make potions to get slimeform."); + if (creatable_unknown_potions.count() > 0 && slimeform_potion == $item[none]) + { + boolean need_to_make = false; + foreach key, it in creatable_unknown_potions + { + if (it.available_amount() == 0 && it.creatable_amount() > 0) + need_to_make = true; + } + + string line = "Try"; + if (need_to_make) + line += " making and"; + line += " using " + creatable_unknown_potions.listJoinComponents(", ", "or") + "."; + subentry.entries.listAppend(line); + } + } + } + } + } + else if (my_class() == $class[seal clubber]) + { + if ($item[hellseal disguise].available_amount() > 0) + { + subentry.entries.listAppend("Approach the dark cave."); + } + else if ($item[hellseal hide].available_amount() >= 6 && $item[hellseal sinew].available_amount() >= 6 && $item[hellseal brain].available_amount() >= 6) + { + subentry.entries.listAppend("Speak with Phineas."); + } + else + { + int seal_screeches = get_property_int("_sealScreeches"); + string screech_name = "screech"; + if (my_path().id == PATH_KOLHS) //KOLHS support + screech_name = "samuel powers"; + if ($item[seal tooth].available_amount() == 0) + { + subentry.entries.listAppend("Acquire a seal tooth from the hermit."); + } + else + subentry.entries.listAppend("Use a seal tooth to damage the hellseal pups until they screech, once each."); + if ($skill[lunging thrust-smack].have_skill()) + { + subentry.entries.listAppend("Use lunging thrust-smack against the mother hell seals."); + } + else + { + subentry.entries.listAppend("Buy lunging thrust-smack from your guild."); + } + subentry.entries.listAppend(pluraliseWordy(seal_screeches, "seal " + screech_name, "seal " + screech_name + "es").capitaliseFirstLetter() + "."); + + + int sinew_need = clampi(6 - $item[hellseal sinew].available_amount(), 0, 6); + int brains_have = clampi(6 - $item[hellseal brain].available_amount(), 0, 6); + int hides_have = clampi(6 - $item[hellseal hide].available_amount(), 0, 6); + + string [int] items_needed_list; + foreach it in $items[hellseal sinew,hellseal brain,hellseal hide] + { + int remaining = clampi(6 - it.available_amount(), 0, 6); + if (remaining == 0) continue; + string name_short = it.to_string().replace_string("hellseal ", ""); + string name_short_plural = it.plural.to_string().replace_string("hellseal ", ""); + items_needed_list.listAppend(pluraliseWordy(remaining, "more " + name_short, "more " + name_short_plural)); + } + if (items_needed_list.count() == 0) + { + } + else + { + subentry.entries.listAppend("Need " + items_needed_list.listJoinComponents(", ", "and") + "."); + } + + + string [int] passive_uneffect_description = PDSGenerateDescriptionToUneffectPassives(); + if (passive_uneffect_description.count() > 0) + subentry.entries.listAppend(HTMLGenerateSpanFont(passive_uneffect_description.listJoinComponents("|"), "red")); + + if (!$slot[weapon].equipped_item().weapon_is_club()) + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip a club" + ($effect[Iron Palms].have_effect() > 0 ? " or sword" : "") + " first.", "red")); + } + } + } +} + + +void QNemesisGenerateClownTasks(ChecklistSubentry subentry) +{ + item [class] legendary_epic_weapon_craftable_source; + legendary_epic_weapon_craftable_source[$class[seal clubber]] = $item[distilled seal blood]; + legendary_epic_weapon_craftable_source[$class[turtle tamer]] = $item[turtle chain]; + legendary_epic_weapon_craftable_source[$class[pastamancer]] = $item[high-octane olive oil]; + legendary_epic_weapon_craftable_source[$class[sauceror]] = $item[peppercorns of power]; + legendary_epic_weapon_craftable_source[$class[disco bandit]] = $item[vial of mojo]; + legendary_epic_weapon_craftable_source[$class[accordion thief]] = $item[golden reeds]; + + subentry.entries.listAppend("Search in the Fun House."); + int clownosity = numeric_modifier("Clowniness").floor(); + int clownosity_needed = MAX(100 - clownosity, 0); + + if (clownosity_needed > 0) + { + string [int] available_clown_sources; + string [int] missing_sources; + + item [slot] possible_outfit; + foreach it in $items[clown wig,clown whip,clownskin buckler,clownskin belt,clownskin harness,polka-dot bow tie,balloon sword,balloon helmet,foolscap fool's cap,bloody clown pants,clown shoes,big red clown nose] + { + int clownosity = numeric_modifier(it, "Clowniness").floor(); + string description = it + " (" + clownosity + ")"; + if (it.available_amount() + it.creatable_amount() > 0 && it.equipped_amount() == 0 && it.can_equip()) + { + available_clown_sources.listAppend(description); + if (possible_outfit[it.to_slot()].numeric_modifier("Clowniness").floor() < clownosity) + possible_outfit[it.to_slot()] = it; + } + if (it.available_amount() == 0) + missing_sources.listAppend(description); + } + + item [int] suggested_outfit; + int clownosity_possible = 0; + foreach key in possible_outfit + { + clownosity_possible += possible_outfit[key].numeric_modifier("Clowniness").floor(); + suggested_outfit.listAppend(possible_outfit[key]); + if (clownosity_possible >= clownosity_needed) + break; + } + //Remove extraneous pieces: + foreach key in suggested_outfit + { + int clownosity = suggested_outfit[key].numeric_modifier("Clowniness").floor(); + if (clownosity_possible - clownosity >= clownosity_needed) + { + clownosity_possible -= clownosity; + remove suggested_outfit[key]; + } + + } + string line = "Need " + clownosity_needed + " more clowniness."; + + if (available_clown_sources.count() > 0) + { + if (clownosity_possible >= clownosity_needed) + { + string line2 = "Equip " + suggested_outfit.listJoinComponents(", ", "and") + "."; + if (__last_adventure_location == $location[The "Fun" House]) + line2 = HTMLGenerateSpanFont(line2, "red"); + line += "|" + line2; + } + else + line += "|Equip " + available_clown_sources.listJoinComponents(", ", "or") + "."; + } + if (missing_sources.count() > 0 && clownosity_possible < clownosity_needed) + { + if (!in_ronin()) + line += "|Could buy " + missing_sources.listJoinComponents(", ", "or") + "."; + else + line += "|Find sources in the Fun House."; + } + int delay_turns_remaining = delayRemainingInLocation($location[the "fun" house]); + if (delay_turns_remaining > 0) + { + subentry.entries.listAppend(pluraliseWordy(delay_turns_remaining, "more turn", "more turns").capitaliseFirstLetter() + " before non-combat can show up."); + } + + subentry.entries.listAppend(line); + + } +} + +void QNemesisGenerateCaveTasks(ChecklistSubentry subentry, item legendary_epic_weapon) +{ + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questG05Dark", true); + + //place.php?whichplace=mountains&action=mts_caveblocked leads to an non-leaving NC (skippable) + //place.php?whichplace=nemesiscave + + subentry.entries.listAppend("Visit the sinister cave, solve the new quest."); + subentry.modifiers.listAppend("+item"); +} + +void QNemesisGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + + + /* + mafia ordering: + 1 -> acquire disco banjo + 2 -> defeat the clown prince + 3 -> make shagadelic disco banjo, talk to your guild + 4 -> wait for guild to find out where your nemesis is hiding + 5 -> time to visit the dark and dank and sinister cave + 6 -> defeated nemesis in cave, let's go talk to the guild + 7 -> they aren't impressed, wait for assassins + 8 -> first assassin appeared + 9 -> first assassin defeated + 10 -> second assassin appeared + 11 -> second assassin defeated + 12 -> third assassin appeared + 13 -> third assassin defeated + 14 -> final assassin appeared + 15 -> final assassin defeated, go find the lair + 16 -> we're at the island, do island stuff + 17 -> "got away. Again." + 18 -> lava maze solved + 19 -> final form [cue music] + + (same ordering we use) + */ + + + QuestState base_quest_state = __quest_state["Nemesis"]; + if (base_quest_state.finished) + return; + if (!($classes[seal clubber,turtle tamer,pastamancer,sauceror,disco bandit,accordion thief] contains my_class())) + return; + if (!__misc_state["guild open"]) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + string url = ""; + + //volcanoMaze1 through volcanoMaze5 is relevant, blank when not available + + boolean have_legendary_epic_weapon = false; + boolean have_epic_weapon = false; + + item [class] class_epic_weapons; + item [class] class_legendary_epic_weapons; + item [class] class_legendary_epic_weapon_craftable_sources; + item [class] class_ultimate_legendary_epic_weapons; + + class_epic_weapons[$class[seal clubber]] = $item[bjorn's hammer]; + class_epic_weapons[$class[turtle tamer]] = $item[mace of the tortoise]; + class_epic_weapons[$class[pastamancer]] = $item[pasta spoon of peril]; + class_epic_weapons[$class[sauceror]] = $item[5-alarm saucepan]; + class_epic_weapons[$class[disco bandit]] = $item[disco banjo]; + class_epic_weapons[$class[accordion thief]] = $item[rock and roll legend]; + item epic_weapon = class_epic_weapons[my_class()]; + + + class_legendary_epic_weapons[$class[seal clubber]] = $item[hammer of smiting]; + class_legendary_epic_weapons[$class[turtle tamer]] = $item[chelonian morningstar]; + class_legendary_epic_weapons[$class[pastamancer]] = $item[greek pasta spoon of peril]; + class_legendary_epic_weapons[$class[sauceror]] = $item[17-alarm saucepan]; + class_legendary_epic_weapons[$class[disco bandit]] = $item[shagadelic disco banjo]; + class_legendary_epic_weapons[$class[accordion thief]] = $item[squeezebox of the ages]; + item legendary_epic_weapon = class_legendary_epic_weapons[my_class()]; + + + class_legendary_epic_weapon_craftable_sources[$class[seal clubber]] = $item[distilled seal blood]; + class_legendary_epic_weapon_craftable_sources[$class[turtle tamer]] = $item[turtle chain]; + class_legendary_epic_weapon_craftable_sources[$class[pastamancer]] = $item[high-octane olive oil]; + class_legendary_epic_weapon_craftable_sources[$class[sauceror]] = $item[peppercorns of power]; + class_legendary_epic_weapon_craftable_sources[$class[disco bandit]] = $item[vial of mojo]; + class_legendary_epic_weapon_craftable_sources[$class[accordion thief]] = $item[golden reeds]; + item legendary_epic_weapon_craftable_source = class_legendary_epic_weapon_craftable_sources[my_class()]; + + + class_ultimate_legendary_epic_weapons[$class[seal clubber]] = $item[Sledgehammer of the Vælkyr]; + class_ultimate_legendary_epic_weapons[$class[turtle tamer]] = $item[Flail of the Seven Aspects]; + class_ultimate_legendary_epic_weapons[$class[pastamancer]] = $item[Wrath of the Capsaician Pastalords]; + class_ultimate_legendary_epic_weapons[$class[sauceror]] = $item[Windsor Pan of the Source]; + class_ultimate_legendary_epic_weapons[$class[disco bandit]] = $item[Seeger's Unstoppable Banjo]; + class_ultimate_legendary_epic_weapons[$class[accordion thief]] = $item[The Trickster's Trikitixa]; + item ultimate_legendary_epic_weapon = class_ultimate_legendary_epic_weapons[my_class()]; + + if (epic_weapon.available_amount_ignoring_storage() > 0) + have_epic_weapon = true; + if (legendary_epic_weapon.available_amount_ignoring_storage() > 0) + have_legendary_epic_weapon = true; + + if (!__misc_state["in aftercore"] && !have_legendary_epic_weapon && $location[the unquiet garves].turns_spent == 0) + return; + + + string [class] first_boss_name; + first_boss_name[$class[Seal Clubber]] = "Gorgolok, the Infernal Seal"; + first_boss_name[$class[Turtle Tamer]] = "Stella, the Turtle Poacher"; + first_boss_name[$class[Pastamancer]] = "Spaghetti Elemental"; + first_boss_name[$class[Sauceror]] = "Lumpy, the Sinister Sauceblob"; + first_boss_name[$class[Disco Bandit]] = "The Spirit of New Wave"; + first_boss_name[$class[Accordion Thief]] = "Somerset Lopez, Dread Mariachi"; + + if (!base_quest_state.started) + { + subentry.entries.listAppend("Speak to your guild to start the quest.|Then adventure in the Unquiet Garves until you unlock the tomb of the unknown, and solve the puzzle."); + url = "guild.php"; + return; + } + else if (base_quest_state.mafia_internal_step <= 4) + { + //1 One of your guild leaders has tasked you to recover a mysterious and unnamed artifact stolen by your Nemesis. Your first step is to smith an Epic Weapon + + //1 can be when Tomb of the Unknown Your Class Here is unlocked (think there's a missing quest step here?) + //2 can be fighting ghost + //4 can be nearing end + //5 -> return it + //6 -> returning (? + if (have_epic_weapon && false) //not true anymore + { + subentry.entries.listAppend("Speak to your guild."); + url = "guild.php"; + } + else + { + item starter_item_needed; + if (my_class() == $class[seal clubber]) + starter_item_needed = $item[seal-clubbing club]; + else if (my_class() == $class[turtle tamer]) + starter_item_needed = $item[helmet turtle]; + else if (my_class() == $class[pastamancer]) + starter_item_needed = $item[pasta spoon]; + else if (my_class() == $class[sauceror]) + starter_item_needed = $item[saucepan]; + else if (my_class() == $class[disco bandit]) + starter_item_needed = $item[disco mask]; + else if (my_class() == $class[accordion thief]) + starter_item_needed = $item[stolen accordion]; + + //subentry.entries.listAppend("Acquire " + epic_weapon + "."); + if (starter_item_needed.item_amount() == 0) + subentry.entries.listAppend("Acquire a " + starter_item_needed + "."); + else if ($location[The Unquiet Garves].noncombat_queue.contains_text("Tomb of the Unknown Your Class Here")) + { + subentry.entries.listAppend("Solve the puzzle at the unknown tomb."); + + string puzzle_answer; + if (my_class() == $class[seal clubber]) + puzzle_answer = "The answer is \"Boredom\"."; + else if (my_class() == $class[turtle tamer]) + puzzle_answer = "The answer is \"Friendship\"."; + else if (my_class() == $class[pastamancer]) + puzzle_answer = "The answer is \"Binding pasta thralls\"."; + else if (my_class() == $class[sauceror]) + puzzle_answer = "The answer is \"Power\"."; + else if (my_class() == $class[disco bandit]) + puzzle_answer = "The answer is \"Me. Duh\"."; + else if (my_class() == $class[accordion thief]) + puzzle_answer = "The answer is \"Music\"."; + string puzzle_answer_html = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(puzzle_answer, "r_tooltip_inner_class") + "Hover over to see the answer.", "r_tooltip_outer_class"); + subentry.entries.listAppend(puzzle_answer_html); + } + else { + subentry.entries.listAppend("Adventure in the Unquiet Garves until you unlock the tomb of the unknown, then solve the puzzle."); + if (__quest_state["Level 11 Shen"].state_int.getFutureShenAssignments().listInvert() contains $location[The VERY Unquiet Garves]) + subentry.entries.listAppend("Could wait before going there? Shen will send you to the garves later."); + } + url = "place.php?whichplace=cemetery"; + } + } + else if (base_quest_state.mafia_internal_step == 5) + { + subentry.entries.listAppend("Speak to your guild."); + url = "guild.php"; + } + else if (base_quest_state.mafia_internal_step <= 6) + { + //6 To unlock the full power of the Legendary Epic Weapon, you must defeat Beelzebozo, the Clown Prince of Darkness, + QNemesisGenerateClownTasks(subentry); + url = "place.php?whichplace=plains"; + } + else if (base_quest_state.mafia_internal_step >= 7 && base_quest_state.mafia_internal_step <= 9) + { + if (have_legendary_epic_weapon) + { + subentry.entries.listAppend("Speak to your guild."); + url = "guild.php"; + } + else + { + subentry.entries.listAppend("Make " + legendary_epic_weapon + "."); + subentry.entries.listAppend("Recipe is " + epic_weapon + " + " + legendary_epic_weapon_craftable_source + "."); + url = "craft.php?mode=smith"; + } + } + else if (base_quest_state.mafia_internal_step == 10) + { + //??? + subentry.entries.listAppend("Speak to your guild?"); + } + else if (base_quest_state.mafia_internal_step >= 11 && base_quest_state.mafia_internal_step <= 16) + { + //QNemesisGenerateCaveTasks(subentry, legendary_epic_weapon); + if (base_quest_state.mafia_internal_step == 11 || base_quest_state.mafia_internal_step == 12) + { + url = "place.php?whichplace=mountains"; + //The hunt for your Nemesis is on! Better check out that cave they sent you to. + //Figure out how to get into your Nemesis' cave. If you're stumped, maybe your guild can help? + + skill skill_needed; + string skill_choice_name; + + if (my_class() == $class[seal clubber]) + { + skill_needed = $skill[wrath of the wolverine]; + skill_choice_name = "wolverine"; + } + else if (my_class() == $class[disco bandit]) + { + //Focus on your disco state of mind + skill_needed = $skill[disco state of mind]; + skill_choice_name = "disco state of mind"; + } + else if (my_class() == $class[sauceror]) + { + skill_needed = $skill[stream of sauce]; + skill_choice_name = "stream of sauce"; + } + else if (my_class() == $class[turtle tamer]) + { + skill_needed = $skill[amphibian sympathy]; + skill_choice_name = "sympathize with an amphibian"; + } + else if (my_class() == $class[pastamancer]) + { + skill_needed = $skill[entangling noodles]; + skill_choice_name = "entangle the wall with noodles"; + } + else if (my_class() == $class[accordion thief]) + { + skill_needed = $skill[accordion bash]; + skill_choice_name = "bash the wall with your accordion"; + } + //Stream of sauce? + //entangling noodles? + if (skill_needed != $skill[none] && !skill_needed.have_skill()) + { + subentry.entries.listAppend("Learn " + skill_needed + " from guild trainer."); + url = "guild.php?place=trainer"; + } + else if (skill_needed != $skill[none]) + { + subentry.entries.listAppend("Click on the nemesis cave, choose " + skill_choice_name + "."); + } + else + subentry.entries.listAppend("Solve the cave entrance puzzle."); + } + else if (base_quest_state.mafia_internal_step >= 13 && base_quest_state.mafia_internal_step <= 15) + { + url = "place.php?whichplace=nemesiscave"; + //The cavern is full of weird mushrooms, but where's your Nemesis? + //more fizzing spore pods to blow up the blockade in your Nemesis' cave. + //Take those fizzing spore pods to the rubble! + + item needed_item = $item[fizzing spore pod]; + + if (needed_item.available_amount() < 6) + { + subentry.modifiers.listAppend("+item"); + subentry.modifiers.listAppend("olfact angry mushroom guy"); + subentry.entries.listAppend("Adventure in the fungal nethers, collect " + pluraliseWordy(clampi(6 - needed_item.item_amount(), 0, 6), needed_item) + ", make rubble go boom!"); + } + else + { + if (needed_item.item_amount() < 6) + { + int delta = 6 - needed_item.item_amount(); + subentry.entries.listAppend("Pull " + pluralise(delta, $item[fizzing spore pod]) + " from hangk's, make rubble go boom!"); + } + else + subentry.entries.listAppend("Make rubble go boom!"); + } + } + else if (base_quest_state.mafia_internal_step == 16) + { + url = "place.php?whichplace=nemesiscave"; + //Boom! Time to bring the fight to your stinking Nemesis in that stinking cave! + subentry.entries.listAppend("Fight your nemesis in the nemesis cave."); + subentry.entries.listAppend("Do nemesis caves just get rented out on a time-share nemesis basis?|For the month of june, you'll be rueing the day! What? I paid how much?"); + } + } + else if (base_quest_state.mafia_internal_step >= 17 && base_quest_state.mafia_internal_step < 26) + { + // You have successfully shown your Nemesis what for, and claimed an ancient hat of power. It's pretty sweet + // You showed the Epic Hat to the class leader back at your guild, but they didn't seem much impressed. I guess all this Nemesis nonsense isn't quite finished yet, but at least with your Nemesis in hiding again you won't have to worry about it for a while. + // It appears as though some nefarious ne'er-do-well has put a contract on your head + // You handily dispatched some thugs who were trying to collect on your bounty, but something tells you they won't be the last ones to try + + // Whoever put this hit out on you (like you haven't guessed already) has sent Mob Penguins to do their dirty work. Do you know any polar bears you could hire as bodyguards + // So much for those mob penguins that were after your head! If whoever put this hit out on you wants you killed (which, presumably, they do) they'll have to find some much more competent thugs + // have been confirmed: your Nemesis has put the order out for you to be hunted down and killed, and now they're sending their own guys instead of contracting out + // Bam! So much for your Nemesis' assassins! If that's the best they've got, you have nothing at all to worry about + // You had a run-in with some crazy mercenary or assassin or... thing that your Nemesis sent to do you in once and for all. A run-in followed by a run-out, evidently, + string assassin_up_next = ""; + int assassins_left = -1; + + if (mafiaIsPastRevision(14330)) + { + if (base_quest_state.mafia_internal_step < 20) + { + assassin_up_next = "menacing thug"; + assassins_left = 4; + } + else if (base_quest_state.mafia_internal_step < 22) + { + assassin_up_next = "Mob Penguin hitman"; + assassins_left = 3; + } + else if (base_quest_state.mafia_internal_step < 24) + { + if (my_class() == $class[seal clubber]) + assassin_up_next = "hunting seal"; + else if (my_class() == $class[turtle tamer]) + assassin_up_next = "turtle trapper"; + else if (my_class() == $class[pastamancer]) + assassin_up_next = "evil spaghetti cult assassin"; + else if (my_class() == $class[sauceror]) + assassin_up_next = "béarnaise zombie"; + else if (my_class() == $class[disco bandit]) + assassin_up_next = "flock of seagulls"; + else if (my_class() == $class[accordion thief]) + assassin_up_next = "mariachi bandolero"; + + assassins_left = 2; + } + else + { + if (my_class() == $class[seal clubber]) + assassin_up_next = "Argarggagarg the Dire Hellseal"; + else if (my_class() == $class[turtle tamer]) + assassin_up_next = "Safari Jack, Small-Game Hunter"; + else if (my_class() == $class[pastamancer]) + assassin_up_next = "Yakisoba the Executioner"; + else if (my_class() == $class[sauceror]) + assassin_up_next = "Heimandatz, Nacho Golem"; + else if (my_class() == $class[disco bandit]) + assassin_up_next = "Jocko Homo"; + else if (my_class() == $class[accordion thief]) + assassin_up_next = "The Mariachi With No Name"; + assassins_left = 1; + } + } + + if (assassins_left != -1) + { + string line = "Wait for " + pluraliseWordy(assassins_left, "more assassin", "more assassins"); + + //int min_turns_left = 0; + //int max_turns_left = 0; + float average_turns_left = 0; + + int effective_assassins_left = assassins_left; + //35 to 50 + Counter nemesis_assassin_window = CounterLookup("Nemesis Assassin"); + if (nemesis_assassin_window.CounterExists() && nemesis_assassin_window.CounterIsRange()) + { + //min_turns_left += nemesis_assassin_window.range_start_turn; + //max_turns_left += nemesis_assassin_window.range_end_turn; + average_turns_left += (nemesis_assassin_window.range_start_turn + nemesis_assassin_window.range_end_turn).to_float() / 2.0; + effective_assassins_left -= 1; + } + + + effective_assassins_left = clampi(effective_assassins_left, 0, 4); + //min_turns_left += 35 * effective_assassins_left; + //max_turns_left += 50 * effective_assassins_left; + average_turns_left += 42.5 * effective_assassins_left.to_float(); + + //I wonder if showing max_turns_left would be less confusing here... + line += " over ~" + average_turns_left.roundForOutput(0) + " turns."; + subentry.entries.listAppend(line); + } + else + subentry.entries.listAppend("Wait for assassins."); + + //if (base_quest_state.mafia_internal_step < 20) + //subentry.entries.listAppend("Umm... you may need to talk to your guild(?)|Something about this step is weird."); + + if (assassin_up_next != "") + subentry.entries.listAppend(assassin_up_next.capitaliseFirstLetter() + " up next."); + + if (my_basestat(my_primestat()) < 90) + subentry.entries.listAppend("Level to 90 " + my_primestat().to_lower_case() + "."); + + if (my_class() == $class[pastamancer] && my_thrall() != $thrall[spaghetti elemental] && $skill[bind spaghetti elemental].have_skill() && $thrall[spaghetti elemental].level < 3) + { + subentry.entries.listAppend("Cast Bind Spaghetti Elemental to level up your spaghetti elemental to three in advance."); + } + if (base_quest_state.mafia_internal_step == 17) + { + subentry.entries.listAppend("Possibly speak to your guild?"); + url = "guild.php"; + } + } + else if (base_quest_state.mafia_internal_step == 15 && false) + { + // Now that you've dealt with your Nemesis' assassins and found a map to the secret tropical island volcano lair, it's time to take the fight to your foe. Booyah + //find island + url = "inventory.php?ftext=secret+tropical+island+volcano+lair+map"; + subentry.entries.listAppend("Use the secret tropical island volcano lair map."); + } + else if (base_quest_state.mafia_internal_step == 27 || base_quest_state.mafia_internal_step == 26) //mafia bug(?) - doesn't advance properly + { + // You've arrived at the secret tropical island volcano lair, and it's time to finally put a stop to this Nemesis nonsense once and for all. As soon as you can find where they're hiding. Maybe you can find someone to ask + if ($location[The Nemesis' Lair].turnsAttemptedInLocation() > 0) + { + if (my_class() == $class[disco bandit]) + subentry.entries.listAppend("Fight daft punk, then your nemesis face to face.|Then solve the volcano maze."); + else + subentry.entries.listAppend("Fight goons, then your nemesis.|Then solve the volcano maze."); + } + else + QNemesisGenerateIslandTasks(subentry); + url = "volcanoisland.php"; + } + else if (base_quest_state.mafia_internal_step >= 28 && base_quest_state.mafia_internal_step <= 30) + { + // Congratulations on solving the lava maze, which is probably the biggest pain-in-the-ass puzzle in the entire game! Hooray! (Unless you cheated, in which case + if (base_quest_state.mafia_internal_step == 21) + subentry.entries.listAppend("Solve the volcano maze, then fight your nemesis."); + else + subentry.entries.listAppend("Fight your nemesis."); + url = "volcanomaze.php"; + if (legendary_epic_weapon.equipped_amount() == 0 && ultimate_legendary_epic_weapon.equipped_amount() == 0) + subentry.entries.listAppend("Equip " + legendary_epic_weapon + "."); + if (my_class() == $class[sauceror]) + { + string [int] missing_saucespheres; + foreach s in $skills[elemental saucesphere,Jalapeño Saucesphere,antibiotic saucesphere,scarysauce] + { + effect e = s.to_effect(); + if (e.have_effect() > 0) + continue; + string line = s.to_string(); + + if (!s.skill_is_usable()) + line = HTMLGenerateSpanFont(line, "grey"); + + missing_saucespheres.listAppend(line); + } + if (missing_saucespheres.count() > 0) + { + subentry.entries.listAppend("Acquire saucespheres: " + missing_saucespheres.listJoinComponents(", ", "and") + "."); + } + } + if (my_class() == $class[pastamancer]) + { + subentry.entries.listAppend("Run a potato familiar, and alternate casting entangling noodles twice/some sort of attack to keep the demon blocked."); + } + } + + boolean [location] relevant_locations; + foreach l in $locations[the unquiet garves,the "fun" house, the nemesis' lair, the broodling grounds, the outer compound, the temple portico, convention hall lobby, outside the club, the island barracks, the poop deck] + relevant_locations[l] = true; + relevant_locations[$location[the fungal nethers]] = true; + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, relevant_locations).ChecklistEntrySetIDTag("Guild nemesis quest")); +} + +//merkinQuestPath + +void QSeaInit() +{ + // While in 11,037 leagues under the sea, you want this showing no matter what. + + if (my_path().id != 55){ + //Have they adventured anywhere underwater? + boolean have_adventured_in_relevant_area = false; + foreach l in $locations[the briny deeps, the brinier deepers, the briniest deepests, an octopus's garden,the wreck of the edgar fitzsimmons, the mer-kin outpost, madness reef,the marinara trench, the dive bar,anemone mine, the coral corral, mer-kin elementary school,mer-kin library,mer-kin gymnasium,mer-kin colosseum,the caliginous abyss] { + if (l.turnsAttemptedInLocation() > 0 || my_location() == l) { + have_adventured_in_relevant_area = true; + break; + } + } + //don't list the quest unless they've started on the path under the sea: + if (!have_adventured_in_relevant_area && $items[Mer-kin trailmap,Mer-kin lockkey,Mer-kin stashbox,wriggling flytrap pellet,damp old boot,Grandma's Map,Grandma's Chartreuse Yarn,Grandma's Fuchsia Yarn,Grandma's Note,black glass].available_amount() == 0) + return; + } + + + if (true) { + QuestState state; + + state.state_string["path"] = get_property("merkinQuestPath"); + if (state.state_string["path"] == "done") + QuestStateParseMafiaQuestPropertyValue(state, "finished"); + else + QuestStateParseMafiaQuestPropertyValue(state, "started"); + + state.quest_name = "Sea Quest"; + state.image_name = "Sea"; + + boolean have_crappy_disguise = have_outfit_components("Crappy Mer-kin Disguise"); + state.state_boolean["have scholar disguise"] = have_outfit_components("Mer-kin Scholar's Vestments"); + state.state_boolean["have gladiator disguise"] = have_outfit_components("Mer-kin Gladiatorial Gear"); + state.state_boolean["can fight dad sea monkee"] = $items[Goggles of Loathing,Stick-Knife of Loathing,Scepter of Loathing,Jeans of Loathing,Treads of Loathing,Belt of Loathing,Pocket Square of Loathing].items_missing().count() <= 1; + state.state_boolean["have one outfit"] = have_crappy_disguise || state.state_boolean["have scholar disguise"] || state.state_boolean["have gladiator disguise"]; + + __quest_state["Sea Temple"] = state; + } + if (true) { + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questS02Monkees"); + state.quest_name = "Hey, Hey, They're Sea Monkees"; + state.image_name = "Sea Monkey Castle"; + + if (get_property_boolean("mapToTheSkateParkPurchased")) + state.state_string["skate park status"] = get_property("skateParkStatus"); //"", "war", "ice", "roller", "peace" + + + __quest_state["Sea Monkees"] = state; + } +} + +void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name, QuestState temple_quest_state) +{ + string temple_path = temple_quest_state.state_string["path"]; + boolean can_fight_dad_sea_monkee = temple_quest_state.state_boolean["can fight dad sea monkee"]; + boolean have_any_outfit = temple_quest_state.state_boolean["have one outfit"] || temple_quest_state.state_boolean["can fight dad sea monkee"]; + + if (!have_any_outfit) { + subentry.entries.listAppend("Acquire crappy mer-kin disguise from grandma sea monkee."); + return; + } + + boolean at_boss = false; + boolean at_gladiator_boss = false; + boolean at_scholar_boss = false; + if (temple_path == "gladiator") { + image_name.s = "Shub-Jigguwatt"; + at_gladiator_boss = true; + } else if (temple_path == "scholar") { + image_name.s = "Yog-Urt"; + at_scholar_boss = true; + } + at_boss = at_gladiator_boss || at_scholar_boss; + + if (!at_boss || at_gladiator_boss) { + string [int] description; + string [int] modifiers; + //gladiator: + if (at_gladiator_boss) { + description.listAppend("Buff muscle, equip a powerful weapon."); + description.listAppend("Delevel him for a bit, then attack with your weapon."); + if ($item[crayon shavings].available_amount() > 0) description.listAppend("|*Your crayon shavings are great for this!"); + description.listAppend("Make sure not to have anything along that will attack him. (familiars, etc)"); + //umm... this probably won't be updated: + string [int] things_to_do; + foreach it in $items[hand in glove,MagiMechTech NanoMechaMech,bottle opener belt buckle,old school calculator watch,ant hoe,ant pick,ant pitchfork,ant rake,ant sickle,fishy wand,moveable feast,oversized fish scaler,replica plastic pumpkin bucket,plastic pumpkin bucket,tiny bowler,cup of infinite pencils,double-ice box,smirking shrunken head,mr. haggis,stapler bear,dubious loincloth,muddy skirt,bottle of Goldschnöckered,acid-squirting flower,ironic oversized sunglasses,hippy protest button,cannonball charrrm bracelet,groovy prism necklace,spiky turtle shoulderpads,double-ice cap,parasitic headgnawer,eelskin hat,balloon shield,hot plate,Ol' Scratch's stove door,Oscus's garbage can lid,eelskin shield,eelskin pants] { + if (it.equipped_amount() > 0) + things_to_do.listAppend("unequip " + it); + } + foreach e in $effects[Skeletal Warrior,Skeletal Cleric,Skeletal Wizard,Bone Homie,Burning\, Man,Biologically Shocked,EVISCERATE!,Fangs and Pangs,Permanent Halloween,Curse of the Black Pearl Onion,Long Live GORF,Apoplectic with Rage,Dizzy with Rage,Quivering with Rage,Jabañero Saucesphere,Psalm of Pointiness,Drenched With Filth,Stuck-Up Hair,It's Electric!,Smokin',Jalapeño Saucesphere,Scarysauce,spiky shell] { + if (e.have_effect() > 0) + things_to_do.listAppend("uneffect " + e); + } + if (things_to_do.count() > 0) + description.listAppend(HTMLGenerateSpanFont(things_to_do.listJoinComponents(", ", "and").capitaliseFirstLetter() + ".", "red")); + + if ($item[dark porquoise ring].equipped_amount() == 0) { + string line = "Possibly "; + if ($item[dark porquoise ring].available_amount() == 0) + line += "acquire and "; + line += "equip a dark porquoise ring to use fewer delevelers."; + description.listAppend(line); + } + if ($effect[Ruthlessly Efficient].have_effect() == 0) { + if ($skill[Ruthless Efficiency].have_skill()) { + description.listAppend("Possibly cast Ruthless Efficiency to delevel faster."); + } else if ($item[Crimbot ROM: Ruthless Efficiency (dirty)].available_amount() > 0) { + description.listAppend("Possibly use Crimbot ROM: Ruthless Efficiency (dirty) and cast it to delevel faster."); + } else if ($item[Crimbot ROM: Ruthless Efficiency].available_amount() > 0) { + description.listAppend("Possibly use Crimbot ROM: Ruthless Efficiency and cast it to delevel faster."); + } + } + if (my_mp() > 0) + description.listAppend(HTMLGenerateSpanFont("Try to reduce your MP to 0", "red") + " before fighting him."); + } else { + if (!temple_quest_state.state_boolean["have gladiator disguise"]) { + description.listAppend("Acquire gladiatorial outfit.|Components can be found by running +combat in the gymnasium.|Make the outfit with grandma."); + modifiers.listAppend("+combat"); + } else { + string shrap_suggestion = "Shrap is nice for this."; + if (!$skill[shrap].skill_is_usable()) { + if ($item[warbear metalworking primer (used)].available_amount() > 0) { + shrap_suggestion += " (use your used copy of warbear metalworking primer)"; + } else + shrap_suggestion += " (from warbear metalworking primer)"; + } + modifiers.listAppend("spell damage percent"); + modifiers.listAppend("mysticality"); + description.listAppend("Fight in the colosseum!"); + description.listAppend("Easy way is to buff mysticality and spell damage percent, then cast powerful spells.
" + shrap_suggestion); + description.listAppend("There's another way, but it's a bit complicated. Check the wiki?"); + + if (get_property("lastColosseumRoundWon") != "") { //backwards compatibility + int colosseum_round = get_property_int("lastColosseumRoundWon"); + int enemy_level = colosseum_round / 3; + string enemy_type, counter_weapon, counter_weapon_property; + + switch (colosseum_round % 3) { + case 0: + //missing the net GAIN cue: 1 turn of Gutballed (-300% muscle) + //missing the net LOSS cue: increase... monster level..? + //missing the net NEUTRALITY cue: reduces every future incoming damage to 1, for a few rounds + enemy_type = (enemy_level > 3 ? "Georgepaul, the B" : "a mer-kin b") + "alldodger"; + counter_weapon = "Mer-kin dragnet"; + counter_weapon_property = "gladiatorNetMovesKnown"; + break; + case 1: + //missing the blade SLING cue: heals + //missing the blade ROLLER ("rolls") cue: 1 turn of Nettled (-300% moxie) + //missing the blade RUNNER cue: hits for 1/2 of you max HP + enemy_type = (enemy_level > 3 ? "Johnringo, the N" : "a mer-kin n") + "etdragger"; + counter_weapon = "Mer-kin switchblade"; + counter_weapon_property = "gladiatorBladeMovesKnown"; + break; + case 2: + //missing the ball BUST cue: reflects all damage for a few rounds + //missing the ball SWEAT cue: increase attack? shrug off delevels? + //missing the ball SACK cue: unequips your weapon + enemy_type = (enemy_level > 3 ? "Ringogeorge, the B" : "a mer-kin b") + "ladeswitcher"; + counter_weapon = "Mer-kin dodgeball"; + counter_weapon_property = "gladiatorBallMovesKnown"; + break; + } + int colosseum_skills_known = get_property_int(counter_weapon_property); + + description.listAppend("Next fight is against " + enemy_type + "."); + if (counter_weapon.to_item().equipped_amount() == 0 && colosseum_skills_known > 0 && enemy_level > 0) + description.listAppend("Equip your " + counter_weapon + (colosseum_skills_known == 3 ? "." : "..?")); + //could be developped more? + } + + //if ($item[Mer-kin gladiator mask].equipped_amount() == 0 || $item[Mer-kin gladiator tailpiece].equipped_amount() == 0) + //description.listAppend("Equip the Mer-kin Gladiatorial Gear."); + } + } + string modifier_string = ""; + if (modifiers.count() > 0) + modifier_string = ChecklistGenerateModifierSpan(modifiers); + if (description.count() > 0) + subentry.entries.listAppend("Gladiator path" + HTMLGenerateIndentedText(modifier_string + description.listJoinComponents("
"))); + } + if (!at_boss || at_scholar_boss) { + string [int] description; + string [int] modifiers; + //scholar: + if (at_scholar_boss) { + description.listAppend("Wear several mer-kin prayerbeads and possibly a mer-kin gutgirdle."); + description.listAppend("Avoid wearing any +hp gear or buffs. Ideally, you want low HP."); + description.listAppend("Each round, use a different healing item, until you lose the Suckrament effect.
After that, your stats are restored. Fully heal, then " + HTMLGenerateSpanOfClass("attack with elemental damage", "r_bold") + "."); + string [item] potential_healers; + potential_healers[$item[mer-kin healscroll]] = "mer-kin healscroll (full HP)"; + potential_healers[$item[scented massage oil]] = "scented massage oil (full HP)"; + potential_healers[$item[soggy used band-aid]] = "soggy used band-aid (full HP)"; + potential_healers[$item[sea gel]] = "sea gel (+500 HP)"; + potential_healers[$item[waterlogged scroll of healing]] = "waterlogged scroll of healing (+250 HP)"; + potential_healers[$item[extra-strength red potion]] = "extra-strength red potion (+200 HP)"; + potential_healers[$item[red pixel potion]] = "red pixel potion (+100-120 HP)"; + potential_healers[$item[red potion]] = "red potion (+100 HP)"; + potential_healers[$item[filthy poultice]] = "filthy poultice (+80-120 HP)"; + potential_healers[$item[gauze garter]] = "gauze garter (+80-120 HP)"; + potential_healers[$item[green pixel potion]] = "green pixel potion (+40-60 HP)"; + potential_healers[$item[cartoon heart]] = "cartoon heart (40-60 HP)"; + potential_healers[$item[red plastic oyster egg]] = "red plastic oyster egg (+35-40 HP)"; + string [int] description_healers; + + foreach it in potential_healers { + if (it.item_amount() > 0) + description_healers.listAppend(potential_healers[it]); + else + description_healers.listAppend(HTMLGenerateSpanFont(potential_healers[it], "red")); + } + description.listAppend("Potential healing items:|*" + description_healers.listJoinComponents("|*")); + } else { + if (!temple_quest_state.state_boolean["have scholar disguise"]) { + description.listAppend("Acquire scholar outfit.|Components can be found by running -combat in the elementary school.|Make the outfit with grandma."); + modifiers.listAppend("-combat"); + } else { + if ($item[Mer-kin dreadscroll].available_amount() == 0) { + description.listAppend("Adventure in the library. Find the dreadscroll."); + modifiers.listAppend("-combat"); + } else { + if ($effect[deep-tainted mind].have_effect() > 0) + description.listAppend("Solve the dreadscroll.
Wait for Deep-Tainted Mind to wear off."); + else + description.listAppend("Solve the dreadscroll."); + + string [int] unknown_clues; + + /* + Mer-kin Library 1 -> dreadScroll1 + Mer-kin healscroll -> dreadScroll2 + Deep Dark Visions -> dreadScroll3 + Mer-kin knucklebone -> dreadScroll4 + Mer-kin killscroll -> dreadScroll5 + Mer-kin Library 2 -> dreadScroll6 + Mer-kin worktea -> dreadScroll7 + Mer-kin Library 3 -> dreadScroll8 + */ + + int known_clue_count = 0; + boolean [int] known_clues; + int library_clues_known = 0; + for i from 1 to 8 { + string property_name = "dreadScroll" + i; + int property_value = get_property_int(property_name); + + if (property_value >= 1 && property_value <= 4) { + known_clue_count += 1; + known_clues[i] = true; + + if (i == 1 || i == 6 || i == 8) + library_clues_known += 1; + } + } + + boolean need_to_learn_vocabulary = false; + + if (library_clues_known < 3) { + unknown_clues.listAppend((3 - library_clues_known).int_to_wordy().capitaliseFirstLetter() + " non-combats in the library. (vocabulary)"); + need_to_learn_vocabulary = true; + } + if (!known_clues[5]) { + unknown_clues.listAppend("Use a mer-kin killscroll in combat. (vocabulary)"); + need_to_learn_vocabulary = true; + } + if (!known_clues[2]) { + unknown_clues.listAppend("Use a mer-kin healscroll in combat. (vocabulary)"); + need_to_learn_vocabulary = true; + } + if (!known_clues[4]) + unknown_clues.listAppend("Use a mer-kin knucklebone."); + if (!known_clues[3]) + unknown_clues.listAppend("Cast deep dark visions."); + if (!known_clues[7]) + unknown_clues.listAppend("Eat sushi with mer-kin worktea."); + + if (unknown_clues.count() > 0) + description.listAppend("Clues are from:|*-" + unknown_clues.listJoinComponents("|*-")); + + if (need_to_learn_vocabulary) { + int vocabulary = get_property_int("merkinVocabularyMastery"); + if (vocabulary < 100) { + int word_quizzes_needed = clampi(10 - vocabulary / 10, 1, 10); + description.listAppend("At " + (vocabulary) + "% Mer-Kin vocabulary. (use " + pluralise(word_quizzes_needed, $item[mer-kin wordquiz]) + " with a mer-kin cheatsheet)"); + } else + description.listAppend("Mer-Kin vocabulary mastered."); + } + if (known_clue_count > 0) { + if (known_clue_count == 8) + description.listAppend("Have all clues."); + else + description.listAppend("Have " + known_clue_count + " out of 8 clues."); + } + } + } + } + string modifier_string = ""; + if (modifiers.count() > 0) + modifier_string = ChecklistGenerateModifierSpan(modifiers); + if (description.count() > 0) + subentry.entries.listAppend("Scholar path" + HTMLGenerateIndentedText(modifier_string + description.listJoinComponents("
"))); + } + if (!at_boss && can_fight_dad_sea_monkee) { + string [int] description; + + description.listAppend("Equip Clothing of Loathing, go to the temple."); + description.listAppend("Cast 120MP hobopolis spells at him."); + description.listAppend("Use Mafia's \"dad\" GCLI command to see which element to use which round."); + if (my_mp() < 1200) + description.listAppend("Will need 1200MP, or less if using shrap/volcanometeor showeruption."); + + string [int] modifiers_needed_150; + foreach s in $stats[] { + if (s.my_basestat() < 150) + modifiers_needed_150.listAppend((150 - s.my_basestat()) + " more " + s.to_lower_case()); + } + + if (modifiers_needed_150.count() > 0) + description.listAppend("Need " + modifiers_needed_150.listJoinComponents(", ", "and") + " to wear Clothing of Loathing."); + + if (description.count() > 0) + subentry.entries.listAppend("Dad sea monkee path" + HTMLGenerateIndentedText(description.listJoinComponents("
"))); + } + + item [class] class_to_scholar_item; + item [class] class_to_gladiator_item; + + class_to_scholar_item[$class[seal clubber]] = $item[Cold Stone of Hatred]; + class_to_scholar_item[$class[turtle tamer]] = $item[Girdle of Hatred]; + class_to_scholar_item[$class[pastamancer]] = $item[Staff of Simmering Hatred]; + class_to_scholar_item[$class[sauceror]] = $item[Pantaloons of Hatred]; + class_to_scholar_item[$class[disco bandit]] = $item[Fuzzy Slippers of Hatred]; + class_to_scholar_item[$class[accordion thief]] = $item[Lens of Hatred]; + + class_to_gladiator_item[$class[seal clubber]] = $item[Ass-Stompers of Violence]; + class_to_gladiator_item[$class[turtle tamer]] = $item[Brand of Violence]; + class_to_gladiator_item[$class[pastamancer]] = $item[Novelty Belt Buckle of Violence]; + class_to_gladiator_item[$class[sauceror]] = $item[Lens of Violence]; + class_to_gladiator_item[$class[disco bandit]] = $item[Pigsticker of Violence]; + class_to_gladiator_item[$class[accordion thief]] = $item[Jodhpurs of Violence]; + + item scholar_item = class_to_scholar_item[my_class()]; + item gladiator_item = class_to_gladiator_item[my_class()]; + + if (!at_boss) { + string line = "Can acquire " + scholar_item + " (scholar) or " + gladiator_item + " (gladiator)"; + if (can_fight_dad_sea_monkee) + line += " or " + $item[pocket square of loathing] + " (dad)"; + subentry.entries.listAppend(line); + } else if (at_gladiator_boss) + subentry.entries.listAppend("Will acquire " + gladiator_item + "."); + else if (at_scholar_boss) + subentry.entries.listAppend("Will acquire " + scholar_item + "."); +} + +//Hmm. Possibly show taffy in resources, if they're under the sea? + +void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState temple_quest_state = __quest_state["Sea Temple"]; + QuestState monkees_quest_state = __quest_state["Sea Monkees"]; + + if (!__misc_state["in aftercore"] && !monkees_quest_state.started || temple_quest_state.quest_name == "") + return; + + //Will have 4 possible tiles. 1 is the main questline, and always appear, and the 3 others only appear once they diverge from the main questline (if unfinished, of course) + //Tile 1 is the old man's boot (first since needs no adventuring once diverged). Diverges from the main questline when freeing big brother. + //Tile 2 is the main questline, which goes up to the Mer-Kin temple boss(es). (in other words, main questline = mer-kin questline, with all of its prerequisites) + //Tile 3 is the sea monkey questline (ends with finding Mom sea monkey). Diverges from the main questline when asking grandpa about grandma. + //Tile 4 is the skate park. Diverges from the main questline when freeing big brother. Only shows once you buy the map to the skate park. + + //Tile 1 + if (get_property("questS01OldGuy") != "finished" && monkees_quest_state.mafia_internal_step >= 3) { + string url, title, modifiers; + string [int] description; + if (get_property_boolean("dampOldBootPurchased")) { + url = "place.php?whichplace=sea_oldman"; + title = "Return damp old boot to the old man"; + if ($item[fishy pipe].available_amount() == 0) + description.listAppend("Choose the fishy pipe."); + else if ($item[das boot].available_amount() == 0) + description.listAppend("Choose the das boot."); + else + description.listAppend("Choose the damp old wallet."); + } else { + url = "monkeycastle.php?who=2"; + title = "Buy the old man's boot from Big Brother"; + modifiers = "50 sand dollars"; + int sand_dollars = $item[sand dollar].item_amount(); + if (sand_dollars < 50) + description.listAppend("Have " + sand_dollars.pluralise("sand dollar", "sand dollars") + " on hand."); + } + optional_task_entries.listAppend(ChecklistEntryMake("__item damp old boot", url, ChecklistSubentryMake(title, modifiers, description)).ChecklistEntrySetIDTag("Sea old man boot quest")); + } + + + //Tiles 2, 3 and 4 all want fishy, but we don't want to put the full notification in each of them. So instead, we initialize the 3 ChecklistSubentries here, add the general reminder to all of them, and add the how_to to the first that will be displayed. + ChecklistSubentry temple_subentry, sea_monkey_subentry, skate_park_subentry; + + boolean should_output_temple_questline = !temple_quest_state.finished; + boolean should_output_sea_monkey_questline = !monkees_quest_state.finished && monkees_quest_state.mafia_internal_step >= 7; + + string get_fishy, how_to_get_fishy; + if ($effect[fishy].have_effect() == 0) { + get_fishy = "Acquire fishy."; + how_to_get_fishy = "|*Easy way: Lucky adventure in the brinier deeps, 20 turns."; + if ($item[fishy pipe].available_amount() > 0 && !get_property_boolean("_fishyPipeUsed")) + how_to_get_fishy += "|*Use fishy pipe."; + if (monkees_quest_state.state_string["skate park status"] == "ice" && !get_property_boolean("_skateBuff1")) + how_to_get_fishy += "|*Visit Lutz at the Skate Park."; + + if (should_output_temple_questline) { + temple_subentry.entries.listAppend(get_fishy + how_to_get_fishy); + sea_monkey_subentry.entries.listAppend(get_fishy); + skate_park_subentry.entries.listAppend(get_fishy); + } else if (should_output_sea_monkey_questline) { + sea_monkey_subentry.entries.listAppend(get_fishy + how_to_get_fishy); + skate_park_subentry.entries.listAppend(get_fishy); + } else + skate_park_subentry.entries.listAppend(get_fishy + how_to_get_fishy); + } + + + //Tile 2 + string image_name = temple_quest_state.image_name; + string url = "seafloor.php"; + + temple_subentry.header = temple_quest_state.quest_name; + boolean need_minus_combat_modifier = false; + + + if (should_output_temple_questline) { + if (get_property("seahorseName").length() == 0) { + boolean professional_roper = false; + //merkinLockkeyMonster questS01OldGuy questS02Monkees + //Need to reach the temple: + if (get_property("lassoTraining") != "expertly") { + string line; + if ($item[sea lasso].item_amount() == 0) + line += HTMLGenerateSpanFont((in_ronin() ? "Acquire" : "Buy") + " and use a sea lasso in each combat.", "red"); + else + line += "Use a sea lasso in each combat."; + if ($item[sea cowboy hat].equipped_amount() == 0) + line += "|*Wear a sea cowboy hat to improve roping."; + if ($item[sea chaps].equipped_amount() == 0) + line += "|*Wear sea chaps to improve roping."; + temple_subentry.entries.listAppend(line); + } else { + professional_roper = true; + string line; + if ($item[sea lasso].item_amount() == 0) + line += "Buy a sea lasso."; + if ($item[sea cowbell].item_amount() < 3) { + int needed_amount = MAX(3 - $item[sea cowbell].item_amount(), 0); + if (line != "") line += " "; + line += "Buy " + pluraliseWordy(needed_amount, "sea cowbell", "sea cowbells") + "."; + } + if (line != "") + temple_subentry.entries.listAppend(line); + } + location class_grandpa_location; + if (my_primestat() == $stat[muscle]) + class_grandpa_location = $location[Anemone Mine]; + if (my_primestat() == $stat[mysticality]) + class_grandpa_location = $location[The Marinara Trench]; + if (my_primestat() == $stat[moxie]) + class_grandpa_location = $location[the dive bar]; + + int grandpa_ncs_remaining = 3; + + //Match NC names to prevent other NCs interfering with tracking: + int [string] noncombat_names; + noncombat_names["Lost and Found and Lost Again"] = 2; + noncombat_names["Respect Your Elders"] = 1; + noncombat_names["You've Hit Bottom"] = 0; + noncombat_names["Kids Today"] = 1; + noncombat_names["Not a Micro Fish"] = 0; + noncombat_names["No Country Music for Old Men"] = 2; + noncombat_names["Salty Old Men"] = 1; + noncombat_names["Boxing the Juke"] = 0; + noncombat_names["Bar Hunting"] = 2; + noncombat_names["The Salt of the Sea"] = 1; + noncombat_names["Ode to the Sea"] = 0; + foreach nc in noncombat_names { + if (class_grandpa_location.noncombat_queue.contains_text(nc)) + grandpa_ncs_remaining = MIN(grandpa_ncs_remaining, noncombat_names[nc]); + } + + //Detect where we are: + //This won't work beyond talking to little brother, my apologies (fixed since) + if (get_property_boolean("corralUnlocked") || $location[the coral corral].turnsAttemptedInLocation() > 0) { + //Coral corral. Banish strategy. + string sea_horse_details; + if (!professional_roper) + sea_horse_details = HTMLGenerateSpanFont("|But first, train up your roping skills.", "red"); + else + sea_horse_details = "|Once found, use three sea cowbells on him, then a sea lasso."; + temple_subentry.entries.listAppend("Look for your sea horse in the Coral Corral." + sea_horse_details); + string [int] banish_monsters; + monster [int] monster_list = $location[the coral corral].get_monsters(); + foreach key in monster_list { + monster m = monster_list[key]; + if (!m.is_banished() && m != $monster[wild seahorse]) + banish_monsters.listAppend(m.to_string()); + } + if (banish_monsters.count() > 1) + temple_subentry.entries.listAppend("Banish " + banish_monsters.listJoinComponents(", ", "and") + " with separate banish sources to speed up area."); + } else if (monkees_quest_state.mafia_internal_step >= 7 || $location[the mer-kin outpost].turnsAttemptedInLocation() > 0) { + //Find lockkey as well. + //Then stash box. Mention monster source. + //Use trailmap. + //Ask grandpa about currents. + if ($item[Mer-kin trailmap].available_amount() > 0) { + temple_subentry.entries.listAppend("Use Mer-kin trailmap."); + } else if ($item[Mer-kin stashbox].available_amount() > 0) { + temple_subentry.entries.listAppend("Open stashbox."); + } else if ($item[Mer-kin lockkey].available_amount() > 0) { + string nc_details = ""; + monster lockkey_monster = get_property_monster("merkinLockkeyMonster"); + if (lockkey_monster == $monster[Mer-kin burglar]) { + nc_details = "Stashbox is in the camouflaged tent."; + } else if (lockkey_monster == $monster[Mer-kin raider]) { + nc_details = "Stashbox is in the skull-bedecked tent."; + } else if (lockkey_monster == $monster[Mer-kin healer]) { + nc_details = "Stashbox is in the glyphed tent."; + } + + need_minus_combat_modifier = true; + temple_subentry.entries.listAppend("Adventure in the Mer-Kin outpost, find non-combat.|" + nc_details); + } else { + temple_subentry.entries.listAppend("Adventure in the Mer-Kin outpost to acquire a lockkey."); + temple_subentry.entries.listAppend("Unless you discovered the currents already (can't tell), in which case go ask grandpa about currents."); + } + } else if (monkees_quest_state.mafia_internal_step == 6 || grandpa_ncs_remaining == 0) { + url = "monkeycastle.php?who=3"; + temple_subentry.entries.listAppend("Ask grandpa about his wife to unlock the Mer-Kin outpost."); + } else if (monkees_quest_state.mafia_internal_step == 5 || class_grandpa_location.turnsAttemptedInLocation() > 0) { + //Find grandpa in one of the three zones. + need_minus_combat_modifier = true; + temple_subentry.entries.listAppend("Find grandpa sea monkee in " + class_grandpa_location + ".|" + pluraliseWordy(grandpa_ncs_remaining, "non-combat remains", "non-combats remain").capitaliseFirstLetter() + "."); + if(grandpa_ncs_remaining == 3) temple_subentry.entries.listAppend("|*Make sure you talk to little brother, too; the quest only starts when you talk to him!"); + } else if (monkees_quest_state.mafia_internal_step == 4) { + //Talk to little brother. + temple_subentry.entries.listAppend("Talk to little brother."); + url = "monkeycastle.php"; + } else if (monkees_quest_state.mafia_internal_step == 3) { + //Talk to big brother. + temple_subentry.entries.listAppend("Talk to big brother."); + url = "monkeycastle.php"; + } else if (monkees_quest_state.mafia_internal_step == 2 || $location[The Wreck of the Edgar Fitzsimmons].turnsAttemptedInLocation() > 0) { + //Adventure in wreck, free big brother. + need_minus_combat_modifier = true; + temple_subentry.entries.listAppend("Free big brother. Adventure in the wreck.|Then talk to him and little brother, find grandpa."); + } else if (monkees_quest_state.mafia_internal_step == 1) { + if ($item[wriggling flytrap pellet].available_amount() > 0) { + url = "inventory.php?ftext=wriggling+flytrap+pellet"; + temple_subentry.entries.listAppend("Open a wriggling flytrap pellet, talk to little brother."); + } else { + //Talk to little brother + temple_subentry.entries.listAppend("Talk to little brother."); + url = "monkeycastle.php"; + } + } else { + //Octopus's garden, obtain wriggling flytrap pellet + if ($item[wriggling flytrap pellet].available_amount() == 0) { + temple_subentry.entries.listAppend("Adventure in octopus's garden, find a wriggling flytrap pellet from a Neptune flytrap."); + temple_subentry.modifiers.listAppend("olfact Neptune flytrap"); + } else { + url = "inventory.php?ftext=wriggling+flytrap+pellet"; + temple_subentry.entries.listAppend("Open a wriggling flytrap pellet, talk to little brother."); + } + } + + //Find grandma IF they don't have a disguise/cloathing. + } else { + url = "seafloor.php?action=currents"; + StringHandle image_name_handle; + image_name_handle.s = image_name; + QSeaGenerateTempleEntry(temple_subentry, image_name_handle, temple_quest_state); + image_name = image_name_handle.s; + } + } + + if (need_minus_combat_modifier) + temple_subentry.modifiers.listAppend("-combat"); + + if (should_output_temple_questline) + optional_task_entries.listAppend(ChecklistEntryMake(image_name, url, temple_subentry, $locations[the brinier deepers, an octopus's garden,the wreck of the edgar fitzsimmons, the mer-kin outpost, madness reef,the marinara trench, the dive bar,anemone mine, the coral corral, mer-kin elementary school,mer-kin library,mer-kin gymnasium,mer-kin colosseum,the caliginous abyss]).ChecklistEntrySetIDTag("Sea mer-kin main quest")); + + + //Tile 3 + url = "seafloor.php"; + boolean [location] relevant_locations = {$location[the caliginous abyss]:true}; + + sea_monkey_subentry.header = monkees_quest_state.quest_name; + need_minus_combat_modifier = false; + + + if (should_output_sea_monkey_questline) { + if (monkees_quest_state.mafia_internal_step == 13) { + //Have black glass; only need to find mom. No progress tracking yet (the progress mechanic for this zone is not yet fully understood...) + string line; + line += "Adventure in the Caliginous Abyss. Find Mom Sea Monkey."; + if ($item[shark jumper].equipped_amount() == 0) + line += "|*Wear a shark jumper to speed up area."; + if ($item[scale-mail underwear].equipped_amount() == 0) + line += "|*Wear a scale-mail underwear to speed up area."; + if ($effect[Jelly Combed].have_effect() == 0) + line += "|*Use a Comb jelly to speed up area."; + + sea_monkey_subentry.entries.listAppend(line); + + if ($item[black glass].equipped_amount() == 0) { + url = "inventory.php?ftext=black+glass"; + sea_monkey_subentry.entries.listAppend("Equip the black glass."); + } + } else if (monkees_quest_state.mafia_internal_step == 12) { + url = "monkeycastle.php?who=2"; + sea_monkey_subentry.modifiers.listAppend("13 sand dollars"); + sea_monkey_subentry.entries.listAppend('"Buy" the black glass from big brother. Will get a full refund.'); + + int sand_dollars = $item[sand dollar].item_amount(); + if (sand_dollars < 13) + sea_monkey_subentry.entries.listAppend("Have " + sand_dollars.pluralise("sand dollar", "sand dollars") + " on hand."); + } else if (monkees_quest_state.mafia_internal_step == 11) { + //Discover the existence of the black glass + url = "monkeycastle.php"; + sea_monkey_subentry.entries.listAppend("Talk to big brother."); + } else if (monkees_quest_state.mafia_internal_step == 10) { + //Lil' bro caught big bro acting weird, and it's not linked to puberty... + url = "monkeycastle.php"; + sea_monkey_subentry.entries.listAppend("Talk to little brother."); + } else if (monkees_quest_state.mafia_internal_step == 9) { + //assembled grandma's map, now to find her + need_minus_combat_modifier = true; + relevant_locations[$location[the mer-kin outpost]] = true; + sea_monkey_subentry.entries.listAppend("Adventure at the mer-kin outpost, find grandma."); + } else if (monkees_quest_state.mafia_internal_step == 8 || !temple_quest_state.state_boolean["have one outfit"] && monkees_quest_state.mafia_internal_step == 7) { + //7=unlocked outpost, but didn't find grandma's note. 8=found grandma's note + string line = "Optionally, rescue grandma.|"; + item [int] missing_items = $items[Grandma's Chartreuse Yarn,Grandma's Fuchsia Yarn,Grandma's Note].items_missing(); + + if (missing_items.count() == 0) { + url = "monkeycastle.php?who=3"; + line += "Ask grandpa about the note."; + } else { + need_minus_combat_modifier = true; + relevant_locations[$location[the mer-kin outpost]] = true; + line += "Adventure at the mer-kin outpost, find " + missing_items.listJoinComponents(", ", "and") + "."; + } + sea_monkey_subentry.entries.listAppend(line); + } else + should_output_sea_monkey_questline = false; + } + + if (need_minus_combat_modifier) + sea_monkey_subentry.modifiers.listAppend("-combat"); + + if (should_output_sea_monkey_questline) + optional_task_entries.listAppend(ChecklistEntryMake(monkees_quest_state.image_name, url, sea_monkey_subentry, relevant_locations).ChecklistEntrySetIDTag("Sea monkey branch quest")); + + + //Tile 4 + if (monkees_quest_state.state_string["skate park status"] == "war") { //map purchased, and conflict still ongoing + skate_park_subentry.header = "Sea Side Story"; + skate_park_subentry.modifiers.listAppend("-combat"); + + int [item] skate_park_ncs_progress = { $item[skate blade]:0, $item[brand new key]:0, $item[skate board]:0 }; + + //Match NC names to prevent other NCs interfering with tracking: + int [item] [string] noncombat_names; + noncombat_names[$item[skate blade]]["Prayer of the Roller Skates"] = 1; + noncombat_names[$item[skate blade]]["Rollerbawl"] = 2; + noncombat_names[$item[skate blade]]["Holey Rollers"] = 3; //park now ice + noncombat_names[$item[brand new key]]["The Onbringing"] = 1; + noncombat_names[$item[brand new key]]["Choreography Amongst the Coral"] = 2; + noncombat_names[$item[brand new key]]["The Last of the Ice Skates"] = 3; //park now roller + noncombat_names[$item[skate board]]["A Boarding Party"] = 1; + noncombat_names[$item[skate board]]["A Board of Education"] = 2; + noncombat_names[$item[skate board]]["A Boarding Pass"] = 3; //park now peace + foreach faction_weapon, nc in noncombat_names { + if ($location[The Skate Park].noncombat_queue.contains_text(nc)) + skate_park_ncs_progress[faction_weapon] = MAX(skate_park_ncs_progress[faction_weapon], noncombat_names[faction_weapon][nc]); + } + + int highest_progress_seen; + item [int] factions_at_highest_progress; + + foreach faction_weapon, faction_progress in skate_park_ncs_progress { + if (faction_progress >= highest_progress_seen && faction_progress > 0) { + if (faction_progress > highest_progress_seen) { + factions_at_highest_progress.listClear(); + highest_progress_seen = faction_progress; + } + factions_at_highest_progress.listAppend(faction_weapon); + } + } + + string [int] factions; + + foreach faction_weapon, faction_progress in skate_park_ncs_progress { + string line; + + line += "• Use a " + faction_weapon.name + " for "; + + if (faction_weapon == $item[skate blade]) + line += "Fishy"; + else if (faction_weapon == $item[brand new key]) + line += "-30% pressure penalty (not recommended)"; + else if (faction_weapon == $item[skate board]) + line += "1 sand dollar/combat, +25% item drop and +10 fam weight (all 3 apply in underwater zones only)"; + + if (faction_weapon.equipped_amount() > 0 && $slot[weapon].equipped_item() != faction_weapon) + line += "
" + HTMLGenerateSpanFont("Weapon needs to be in your " + (faction_weapon.weapon_hands() > 1 ? "HANDS" : "MAIN-hand"), "red"); + + factions.listAppend(line.HTMLGenerateSpanFont(highest_progress_seen > 0 && highest_progress_seen > faction_progress && faction_weapon.equipped_amount() == 0 ? "gray" : "dark")); + } + + skate_park_subentry.entries.listAppend("Adventure in A Rumble Near the Fountain with a faction's weapon to unlock (a) daily 30 turns buff(s)." + factions.listJoinComponents("
").HTMLGenerateIndentedText()); + + if (factions_at_highest_progress.count() > 0) + skate_park_subentry.entries.listAppend("At " + highest_progress_seen + "/3 NCs with " + factions_at_highest_progress.listJoinComponents(", ", "and") + (factions_at_highest_progress.count() > 1 ? " (will have to make a decision)" : "") + "."); + + optional_task_entries.listAppend(ChecklistEntryMake("Skate Park", "sea_skatepark.php", skate_park_subentry, $locations[The Skate Park]).ChecklistEntrySetIDTag("Sea skate park war quest")); + } +} + +void QSpaceElvesInit() +{ + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questF04Elves"); + + state.quest_name = "Repair the Elves' Shield Generator Quest"; + state.image_name = "spooky little girl"; + + if (my_basestat(my_primestat()) >= 12) + state.startable = true; + + + __quest_state["Space Elves"] = state; +} + + +void QSpaceElvesGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Space Elves"]; + if (base_quest_state.finished) + return; + + string url = "place.php?whichplace=spaaace"; + + boolean turns_spent_in_locations_already = false; + if ($locations[Domed City of Ronaldus,Domed City of Grimacia,Hamburglaris Shield Generator].turnsAttemptedInLocation() > 0) + turns_spent_in_locations_already = true; + + if (!turns_spent_in_locations_already && $effect[transpondent].have_effect() == 0) //suggest it when they go to spaaace, otherwise, don't bug them? + return; + if (in_ronin() && $effect[transpondent].have_effect() == 0 && $item[transporter transponder].available_amount() == 0) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + subentry.entries.listAppend("Gives 200 lunar isotopes and Elvish Paradise access."); + + if (base_quest_state.mafia_internal_step < 3) + { + string [int] ronald_map_entries; + string [int] grimace_map_entries; + if ($item[e.m.u. rocket thrusters].available_amount() == 0) + ronald_map_entries.listAppend("Ronald map" + __html_right_arrow_character + "Try the Swimming Pool" + __html_right_arrow_character + "To the Left, to the Left" + __html_right_arrow_character + "Take the Red Door"); + if ($item[E.M.U. joystick].available_amount() == 0) + ronald_map_entries.listAppend("Ronald map" + __html_right_arrow_character + "Check out the Armory" + __html_right_arrow_character + "My Left Door" + __html_right_arrow_character + "Crawl through the Ventilation Duct"); + if ($item[E.M.U. harness].available_amount() == 0) + grimace_map_entries.listAppend("Grimace map" + __html_right_arrow_character + "Check out the Coat Check" + __html_right_arrow_character + "Exit, Stage Left" + __html_right_arrow_character + "Be the Duke of the Hazard"); + if ($item[E.M.U. helmet].available_amount() == 0) + grimace_map_entries.listAppend("Grimace map" + __html_right_arrow_character + "Check out the Coat Check" + __html_right_arrow_character + "Stage Right, Even" + __html_right_arrow_character + "Try the Starboard Door"); + if (ronald_map_entries.count() > 0) + { + string header = "Ronald prime:"; + string [int] line; + int maps_needed = ronald_map_entries.count() - $item[map to safety shelter ronald prime].available_amount(); + if (maps_needed > 0) + { + if (subentry.modifiers.count() == 0) + subentry.modifiers.listAppend("+item"); + line.listAppend("Acquire " + pluralise(maps_needed, $item[map to safety shelter ronald prime])); + } + + line.listAppendList(ronald_map_entries); + + + subentry.entries.listAppend(header + HTMLGenerateIndentedText(line.listJoinComponents("
"))); + } + if (grimace_map_entries.count() > 0) + { + string header = "Grimace prime:"; + string [int] line; + int maps_needed = grimace_map_entries.count() - $item[map to safety shelter grimace prime].available_amount(); + if (maps_needed > 0) + { + if (subentry.modifiers.count() == 0) + subentry.modifiers.listAppend("+item"); + line.listAppend("Acquire " + pluralise(maps_needed, $item[map to safety shelter grimace prime])); + } + + line.listAppendList(grimace_map_entries); + subentry.entries.listAppend(header + HTMLGenerateIndentedText(line.listJoinComponents("
"))); + } + if (ronald_map_entries.count() == 0 && grimace_map_entries.count() == 0) + subentry.entries.listAppend("Look for the spooky little girl on Grimacia or Ronaldus."); + //else if ($items[map to safety shelter ronald prime, map to safety shelter grimace prime].available_amount() > 0) + else if ((ronald_map_entries.count() > 0 && $item[map to safety shelter ronald prime].available_amount() > 0) || (grimace_map_entries.count() > 0 && $item[map to safety shelter grimace prime].available_amount() > 0)) + url = "inventory.php?ftext=map+to+safety+shelter"; + } + else if (base_quest_state.mafia_internal_step == 3) + { + if ($item[spooky little girl].equipped_amount() == 0) + subentry.entries.listAppend("Equip spooky little girl."); + else if ($item[spooky little girl].available_amount() == 0) + subentry.entries.listAppend("spooky"); + else + { + subentry.entries.listAppend("Adventure in Grimacia with spooky little girl for eleven turns."); + } + + } + else if (base_quest_state.mafia_internal_step == 4) + { + if ($item[E.M.U. Unit].equipped_amount() == 0) + subentry.entries.listAppend("Equip E.M.U. Unit."); + else + subentry.entries.listAppend("Adventure at the Hamburglaris Shield Generator, solve puzzle."); + } + if ($effect[Transpondent].have_effect() == 0) + { + subentry.entries.listClear(); + subentry.entries.listAppend("Gives 200 lunar isotopes and Elvish Paradise access."); + subentry.entries.listAppend("Use transporter transponder to reach spaaace."); + if ($item[transporter transponder].available_amount() > 0) + url = "inventory.php?ftext=transporter+transponder"; + else + url = "mall.php"; + } + + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[domed city of ronaldus, domed city of grimacia,hamburglaris shield generator]).ChecklistEntrySetIDTag("Space elves generator quest")); +} + +void QAzazelInit() +{ + //questG04Azazel + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questM10Azazel"); + + state.quest_name = "Azazel Quest"; + state.image_name = "steel margarita"; + + if (my_basestat(my_primestat()) >= 12 && __quest_state["Level 6"].finished) + state.startable = true; + + __quest_state["Azazel"] = state; +} + +record AzazelBandMember +{ + string name; + item [int] desired_items; +}; + +AzazelBandMember AzazelBandMemberMake(string name, item [int] desired_items) +{ + AzazelBandMember result; + result.name = name; + result.desired_items = desired_items; + return result; +} + +AzazelBandMember AzazelBandMemberMake(string name, item it1, item it2) +{ + return AzazelBandMemberMake(name, listMake(it1, it2)); +} + +void listAppend(AzazelBandMember [int] list, AzazelBandMember entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void QAzazelGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Azazel"]; + + foreach consumable in $items[steel lasagna,steel margarita,steel-scented air freshener] + { + if (consumable.available_amount() == 0) + continue; + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + string line = "Consume " + consumable; + if ((consumable == $item[steel lasagna] && availableFullness() < 5) || (consumable == $item[steel-scented air freshener] && availableSpleen() < 5)) + line += " once you have enough space"; + line += "."; + subentry.entries.listAppend(line); + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, "", subentry).ChecklistEntrySetIDTag("Azazel steel organ consume")); + return; + } + + if (base_quest_state.finished) + return; + + + if ($skill[Stomach of Steel].skill_is_usable() || $skill[Liver of Steel].skill_is_usable() || $skill[Spleen of Steel].skill_is_usable()) + return; + + if (!__quest_state["Level 6"].finished) + return; + + //We don't suggest or give advice on this quest in-run unless the player spends an adventure in one of the zones. + //If that happens, they're probably sure they want the consumable items. + if (!__misc_state["in aftercore"] && $locations[The Laugh Floor, Infernal Rackets Backstage].turnsAttemptedInLocation() == 0 && $items[Azazel's unicorn,Azazel's lollipop,Azazel's tutu].available_amount() == 0 && !in_bad_moon()) + return; + + + ChecklistEntry entry; + entry.url = "pandamonium.php"; + entry.image_lookup_name = base_quest_state.image_name; + entry.tags.id = "Azazel steel organ quest"; + entry.should_indent_after_first_subentry = true; + entry.should_highlight = $locations[the laugh floor, infernal rackets backstage] contains __last_adventure_location; + + if (true) + { + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + subentry.entries.listAppend("Gives +5 consumable space."); + + if ($item[Azazel's unicorn].available_amount() > 0 && $item[Azazel's lollipop].available_amount() > 0 && $item[Azazel's tutu].available_amount() > 0) + { + subentry.entries.listAppend("Speak to Azazel."); + } + entry.subentries.listAppend(subentry); + } + + boolean need_imp_airs = false; + boolean need_bus_passes = false; + if ($item[Azazel's tutu].available_amount() == 0) + { + //collect 5 cans of imp air and 5 bus passes + ChecklistSubentry subentry; + + subentry.header = "Azazel's tutu"; + + int imp_air_needed = MAX(0, 5 - $item[imp air].available_amount()); + int bus_passes_needed = MAX(0, 5 - $item[bus pass].available_amount()); + if (imp_air_needed == 0 && bus_passes_needed == 0) + { + if ($item[imp air].item_amount() < 5) + subentry.entries.listAppend("Pull imp air."); + if ($item[bus pass].item_amount() < 5) + subentry.entries.listAppend("Pull bus passes."); + subentry.entries.listAppend("Speak to the stranger."); + } + else + { + if (imp_air_needed > 0) + { + string line; + line = "Need " + pluralise(imp_air_needed, $item[imp air]) + ", from the laugh floor."; + if (!in_ronin()) + line += " Or the mall."; + subentry.entries.listAppend(line); + need_imp_airs = true; + } + if (bus_passes_needed > 0) + { + string line; + line = "Need " + pluralise(bus_passes_needed, $item[bus pass]) + ", from backstage."; + if (!in_ronin()) + line += " Or the mall."; + subentry.entries.listAppend(line); + need_bus_passes = true; + } + } + entry.subentries.listAppend(subentry); + } + + + if ($item[Azazel's unicorn].available_amount() == 0) + { + ChecklistSubentry subentry; + + subentry.header = "Azazel's unicorn"; + + int [item] band_items_available; + int band_items_found = 0; + foreach it in $items[comfy pillow,giant marshmallow,booze-soaked cherry,sponge cake,beer-scented teddy bear,gin-soaked blotter paper] + { + if (it.available_amount() > 0) + band_items_found += 1; + band_items_available[it] = it.available_amount(); + } + + //Try to solve the puzzle: + //Hmm... FIXME is there any way to determine which ones we've given to band members? + + AzazelBandMember [int] band_members; + band_members.listAppend(AzazelBandMemberMake("Bognort", $item[giant marshmallow], $item[gin-soaked blotter paper])); + band_members.listAppend(AzazelBandMemberMake("Stinkface", $item[beer-scented teddy bear], $item[gin-soaked blotter paper])); + band_members.listAppend(AzazelBandMemberMake("Flargwurm", $item[booze-soaked cherry], $item[sponge cake])); + band_members.listAppend(AzazelBandMemberMake("Jim", $item[sponge cake], $item[comfy pillow])); + + string [int] quest_completion_instructions; + boolean can_complete_quest = true; + foreach key in band_members + { + AzazelBandMember musician = band_members[key]; + boolean found_item = false; + foreach key2 in musician.desired_items + { + item it = musician.desired_items[key2]; + if (band_items_available[it] > 0) + { + quest_completion_instructions.listAppend("Give " + musician.name + " a " + it + "."); + band_items_available[it] -= 1; + found_item = true; + break; + } + } + if (!found_item) + can_complete_quest = false; + } + + if (can_complete_quest) + { + if (need_bus_passes) + subentry.entries.listAppend("Run +item backstage."); + subentry.entries.listAppend("Talk to Sven.|*" + quest_completion_instructions.listJoinComponents("|*")); + } + else + { + string and_item = ""; + if (need_bus_passes) + and_item = " and +item"; + subentry.entries.listAppend("Run -combat" + and_item + " backstage."); + subentry.entries.listAppend("Need band components."); + subentry.modifiers.listAppend("-combat"); + } + if (need_bus_passes) + { + subentry.modifiers.listAppend("+item"); + subentry.modifiers.listAppend("olfact serialbus"); + } + + entry.subentries.listAppend(subentry); + } + if ($item[Azazel's lollipop].available_amount() == 0) + { + //comedy club - fight on! + ChecklistSubentry subentry; + + subentry.header = "Azazel's lollipop"; + + + if ($item[observational glasses].available_amount() > 0) + { + //talk to mourn + string line = "Talk to Mourn."; + if ($item[observational glasses].equipped_amount() == 0) + line = "Equip the observational glasses, talk to mourn."; + subentry.entries.listAppend(line); + } + else + { + subentry.modifiers.listAppend("+combat"); + string and_item = ""; + if (need_imp_airs) + and_item = " and +item"; + subentry.entries.listAppend("Run +combat" + and_item + " on the laugh floor, find Larry."); + } + + if (need_imp_airs) + { + subentry.modifiers.listAppend("+item"); + subentry.modifiers.listAppend("olfact ch imp"); + } + entry.subentries.listAppend(subentry); + } + + if ((my_path().id == PATH_TEETOTALER || my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_OF_THE_PLUMBER) && availableFullness() < 5) + entry.subentries.listAppend(ChecklistSubentryMake(HTMLGenerateSpanFont("Won't work, need five fullness to eat lasagna.", "red"), "", "")); + + if (my_path().id == PATH_OXYGENARIAN && availableSpleen() < 5) + entry.subentries.listAppend(ChecklistSubentryMake(HTMLGenerateSpanFont("Won't work, need five spleen to consume steel-scented air freshener.", "red"), "", "")); + + optional_task_entries.listAppend(entry); +} + + +void QUntinkerInit() +{ + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questM01Untinker"); + + state.quest_name = "Untinker's Quest"; + state.image_name = "rusty screwdriver"; + + state.startable = $location[the spooky forest].locationAvailable(); + + __quest_state["Untinker"] = state; +} + + +void QUntinkerGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Untinker"]; + if (base_quest_state.finished || !base_quest_state.startable) + return; + + if (my_path().id == PATH_EXPLOSION || my_path().id == PATH_GREY_GOO) return; + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + string url = ""; + + if ($item[rusty screwdriver].available_amount() > 0 || base_quest_state.mafia_internal_step == 0) + { + subentry.entries.listAppend("Speak to the Untinker."); + url = "place.php?whichplace=forestvillage&action=fv_untinker_quest"; + } + else + { + //Acquire rusty screwdriver: + if (knoll_available()) + { + subentry.entries.listAppend("Speak to Innabox in Degrassi Knoll."); + url = "place.php?whichplace=knoll_friendly"; + } + else + { + url = "place.php?whichplace=knoll_hostile"; + subentry.entries.listAppend("Retrieve screwdriver from the Degrassi Knoll Garage.|(25% superlikely)"); + if (__misc_state["free runs available"]) + { + subentry.modifiers.listAppend("free runs"); + } + if (__misc_state["have hipster"]) + { + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + } + } + } + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the degrassi knoll garage]).ChecklistEntrySetIDTag("Untinker quest")); +} + + +void QArtistInit() +{ + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questM02Artist"); + + if (!state.started && $items[pail of pretentious paint, pretentious paintbrush, pretentious palette].available_amount() > 0) + QuestStateParseMafiaQuestPropertyValue(state, "started"); + + if (my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_GREY_GOO) //cannot be done + QuestStateParseMafiaQuestPropertyValue(state, "unstarted"); + + state.quest_name = "Pretentious Artist's Quest"; + state.image_name = "__item pretentious palette"; + + state.startable = true; + + __quest_state["Artist"] = state; +} + + +void QArtistGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Artist"]; + if (!base_quest_state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + string active_url = ""; + + boolean output_modifiers = false; + if ($item[pretentious palette].available_amount() == 0) + { + //haunted pantry + if (active_url == "") + active_url = $location[the haunted pantry].getClickableURLForLocation(); + subentry.entries.listAppend("Adventure in the haunted pantry for palette. (25% superlikely)"); + output_modifiers = true; + } + if ($item[pretentious paintbrush].available_amount() == 0) + { + //cobb's knob + if (active_url == "") + active_url = $location[the outskirts of Cobb's Knob].getClickableURLForLocation(); + subentry.entries.listAppend("Adventure in the outskirts of Cobb's Knob for paintbrush. (25% superlikely)"); + output_modifiers = true; + } + if ($item[pail of pretentious paint].available_amount() == 0) + { + //sleazy back alley + if (active_url == "") + active_url = $location[the sleazy back alley].getClickableURLForLocation(); + subentry.entries.listAppend("Adventure in the sleazy back alley for pail of paint. (25% superlikely)"); + output_modifiers = true; + } + + if (output_modifiers) + { + if (__misc_state["free runs available"]) + { + subentry.modifiers.listAppend("free runs"); + } + if (__misc_state["have hipster"]) + { + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + } + } + + if ($item[pretentious palette].available_amount() > 0 && $item[pretentious paintbrush].available_amount() > 0 && $item[pail of pretentious paint].available_amount() > 0) + { + subentry.entries.listAppend("Talk to the pretentious artist."); + active_url = "place.php?whichplace=town_wrong"; + } + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[the sleazy back alley, the outskirts of cobb's knob, the haunted pantry]).ChecklistEntrySetIDTag("Pretentious artist quest")); +} +void QLegendaryBeatInit() +{ + if ($item[Map to Professor Jacking's laboratory].available_amount() == 0) + return; + //questI02Beat + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questI02Beat"); + + if (!state.started) + { + QuestStateParseMafiaQuestPropertyValue(state, "started"); + } + + state.quest_name = "Quest for the Legendary Beat"; + state.image_name = "__item the Legendary Beat"; + + if (state.in_progress) + { + //FIXME temporary code + //no way to detect if the legendary beat was found + //if (state.mafia_internal_step < 2 && $location[professor jacking's small-o-fier].turnsAttemptedInLocation() > 0 || $location[professor jacking's huge-a-ma-tron].turnsAttemptedInLocation() > 0) + //state.mafia_internal_step = 2; + } + + __quest_state["Legendary Beat"] = state; +} + +void QLegendaryBeatGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[Map to Professor Jacking's laboratory].available_amount() == 0) + return; + + QuestState base_quest_state = __quest_state["Legendary Beat"]; + if (!base_quest_state.in_progress) + return; + + //FIXME temporary: + if (!($locations[professor jacking's small-o-fier, professor jacking's huge-a-ma-tron] contains __last_adventure_location)) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + //FIXME support for fruit machine sidequest? + + if (base_quest_state.mafia_internal_step == 1 && false) + { + subentry.entries.listAppend("Defeat Professor Jacking."); + } + else if (base_quest_state.mafia_internal_step == 2 || true) + { + //Main quest, in reverse order: + if ($item[can-you-dig-it?].available_amount() > 0 && $effect[stubbly legs].have_effect() > 0) + { + subentry.modifiers.listAppend("-combat"); + //6/7 + string [int] tasks; + if ($item[can-you-dig-it?].equipped_amount() == 0) + tasks.listAppend("equip can-you-dig-it?"); + tasks.listAppend("adventure in Small-O-Fier, find non-combat, dig your way to safety"); + subentry.entries.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + } + else if ($item[can-you-dig-it?].available_amount() > 0 && $effect[smooth legs].have_effect() > 0) + { + //5 + subentry.entries.listAppend("Gaze into the mirror."); + subentry.entries.listAppend("Before you do, though, possibly look for/copy smooth jazz scabie factoids in the Small-O-Fier."); + } + else if ($effect[smooth legs].have_effect() > 0) + { + //4 + if ($effect[literally insane].have_effect() > 0 && $effect[broken dancing].have_effect() > 0 && $item[crazyleg's razor].available_amount() > 0) + subentry.entries.listAppend("Use Crazyleg's razor repeatedly to extend smooth legs effect."); + + subentry.modifiers.listAppend("-combat"); + subentry.modifiers.listAppend("+item"); + subentry.entries.listAppend("Adventure in Small-O-Fier, find ocean non-combat, fight a smooth jazz scabie for can-you-dig-it?"); + + } + else if ($effect[literally insane].have_effect() > 0 && $effect[broken dancing].have_effect() > 0 && $item[crazyleg's razor].available_amount() > 0) + { + //3 + subentry.entries.listAppend("Use Crazyleg's razor. (repeatedly)"); + } + else if ($effect[literally insane].have_effect() + $item[world's most unappetizing beverage].available_amount() > 0 && $effect[broken dancing].have_effect() + $item[squirmy violent party snack].available_amount() > 0 && $item[crazyleg's razor].available_amount() > 0) + { + string [int] tasks; + boolean waiting = false; + if ($effect[literally insane].have_effect() == 0) + { + if (availableDrunkenness() < 1) + { + waiting = true; + tasks.listAppend("wait until you have 1 drunkenness available"); + } + else + tasks.listAppend("drink the world's most unappetizing beverage"); + } + if ($effect[broken dancing].have_effect() == 0) + { + if (availableFullness() < 1) + { + tasks.listAppend("wait until you have 1 fullness available"); + waiting = true; + } + else if (!waiting) + tasks.listAppend("eat a squirmy violent party snack"); + } + subentry.entries.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + } + else + { + boolean need_nc = false; + //Need: + //crazyleg's razor + //literally insane / world's most unappetizing beverage / (hair of the calf and can of depilatory cream) + //broken dancing / squirmy violent party snack / (a dance upon the palate/tiny frozen prehistoric meteorite jawbreaker) + if ($item[crazyleg's razor].available_amount() == 0) + { + subentry.entries.listAppend("Acquire crazyleg's razor.|*Adventure in the Huge-A-Ma-Tron, defeat the Fearsome Wacken."); + } + if ($effect[literally insane].have_effect() + $item[world's most unappetizing beverage].available_amount() > 0) + { + //nothing, have them + } + else if ($item[world's most unappetizing beverage].creatable_amount() > 0) + { + subentry.entries.listAppend("Create the world's most unappetizing beverage."); + } + else + { + //parts: + if ($item[hair of the calf].available_amount() == 0) + { + need_nc = true; + subentry.entries.listAppend("Acquire hair of the calf.|*Adventure in Small-O-Fier, climb up a hair."); + } + if ($item[can of depilatory cream].available_amount() == 0) + { + need_nc = true; + subentry.entries.listAppend("Acquire can of depilatory cream.|*Adventure in Small-O-Fier, find non-combat."); + } + } + + if ($effect[broken dancing].have_effect() + $item[squirmy violent party snack].available_amount() > 0) + { + //nothing, have them + } + else if ($item[squirmy violent party snack].creatable_amount() > 0) + { + subentry.entries.listAppend("Create a squirmy violent party snack."); + } + else + { + //parts: + if ($item[a dance upon the palate].available_amount() == 0) + { + subentry.entries.listAppend("Acquire a dance upon the palate.|*Adventure in Huge-A-Ma-Tron, crouch down and lick the world."); + } + if ($item[tiny frozen prehistoric meteorite jawbreaker].available_amount() == 0) + { + string [int] meteorite_details; + + boolean [item] relevant_fruits = $items[blackberry, cherry, olive, plum, sea blueberry, strawberry]; //cheap ones, not all of them + item chosen_fruit = $item[blackberry]; + foreach it in relevant_fruits + { + if (it.available_amount() > 0) + { + chosen_fruit = it; + break; + } + } + + if (chosen_fruit.available_amount() == 0) + meteorite_details.listAppend("Acquire a " + chosen_fruit + "."); + meteorite_details.listAppend("Put a " + chosen_fruit + " in the fruit machine if you haven't."); + if ($effect[hurricane force].have_effect() == 0) + { + need_nc = true; + meteorite_details.listAppend("Adventure in the Huge-A-Ma-Tron, dance on top of the world."); + } + else + { + meteorite_details.listAppend("Adventure in the Huge-A-Ma-Tron, defeat a loose coalition of yetis, snowmen, and goats."); + } + subentry.entries.listAppend("Acquire a tiny frozen prehistoric meteorite jawbreaker.|*" + meteorite_details.listJoinComponents("|*")); + + + } + } + + if (need_nc) + subentry.modifiers.listAppend("-combat"); + } + } + + task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, "", subentry, $locations[professor jacking's small-o-fier, professor jacking's huge-a-ma-tron]).ChecklistEntrySetIDTag("Legendary beat quest")); +} +//Currently disabled. Complicated. + +void QMemoriesInit() +{ + if (true) + return; + if (true) + { + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questF01Primordial"); + + state.quest_name = "Primordial Fear Quest"; + state.image_name = "__item empty agua de vida bottle"; + + + __quest_state["Primordial Fear"] = state; + } + if (true) + { + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questF02Hyboria"); + + state.quest_name = "Hyboria Quest"; + state.image_name = "__item empty agua de vida bottle"; + + + __quest_state["Hyboria"] = state; + } + if (true) + { + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questF03Future"); + + state.quest_name = "Future Quest"; + state.image_name = "__item empty agua de vida bottle"; + + + __quest_state["Future"] = state; + } +} + + +void QMemoriesPrimordialFearGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Primordial Fear"]; + if (!base_quest_state.in_progress) + return; + string active_url = ""; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + //FIXME implement this + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[the primordial soup]).ChecklistEntrySetIDTag("Memories quest primordial fear")); +} + +void QMemoriesHyboriaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Hyboria"]; + if (!base_quest_state.in_progress) + return; + string active_url = ""; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + //FIXME implement this + + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[the jungles of ancient loathing]).ChecklistEntrySetIDTag("Memories quest hyboria")); +} + +void QMemoriesFutureGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Future"]; + if (!base_quest_state.in_progress) + return; + string active_url = ""; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + //FIXME implement this + + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[seaside megalopolis]).ChecklistEntrySetIDTag("Memories quest future")); +} + +void QMemoriesGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (true) + return; + if (__quest_state["Primordial Fear"].in_progress) + { + QMemoriesPrimordialFearGenerateTasks(task_entries, optional_task_entries, future_task_entries); + } + else if (__quest_state["Hyboria"].in_progress) + { + QMemoriesHyboriaGenerateTasks(task_entries, optional_task_entries, future_task_entries); + } + else if (__quest_state["Future"].in_progress) + { + QMemoriesFutureGenerateTasks(task_entries, optional_task_entries, future_task_entries); + } +} + +void QWhiteCitadelInit() +{ + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questG02Whitecastle"); + + //sorry, no way to query for familiar name + state.quest_name = my_name().HTMLEscapeString() + " and Kumar Go To White Citadel"; + if (my_familiar() == $familiar[black cat]) + state.quest_name = my_name().HTMLEscapeString() + " and Luna Go To White Citadel"; + state.image_name = "__item White Citadel burger"; + + if ($item[White Citadel Satisfaction Satchel].available_amount() > 0 && state.mafia_internal_step < 11) + QuestStateParseMafiaQuestPropertyValue(state, "step10"); + if ($effect[SOME PIGS].have_effect() == 2147483647 && state.mafia_internal_step < 7) + QuestStateParseMafiaQuestPropertyValue(state, "step6"); + + __quest_state["White Citadel"] = state; +} + +void QWhiteCitadelGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__misc_state["in aftercore"] && !in_bad_moon() && my_location() != $location[the road to the white citadel] && __last_adventure_location != $location[the road to the white citadel]) //not yet + return; + if (!__misc_state["guild open"]) //bugged + return; + QuestState base_quest_state = __quest_state["White Citadel"]; + if (!base_quest_state.in_progress && !(in_bad_moon() && !base_quest_state.started)) + return; + + boolean using_black_cat_equivalent = ($familiars[O.A.F.,black cat] contains my_familiar()); + + if (__misc_state["in run"] && $location[The Road to the White Citadel].turnsAttemptedInLocation() == 0 && !in_bad_moon()) //not until they're sure + return; + + boolean add_as_future_task = false; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + string active_url = "place.php?whichplace=woods"; + + if (in_bad_moon()) + { + string [int] reasons; + if (base_quest_state.mafia_internal_step < 6) + reasons.listAppend("duonoculars"); + if (base_quest_state.mafia_internal_step < 8) + reasons.listAppend("food from the wand of pigification"); + if (base_quest_state.mafia_internal_step < 11) + reasons.listAppend("an epic drink"); + + if (reasons.count() > 0) + subentry.entries.listAppend("Relevant in Bad Moon for " + reasons.listJoinComponents(", ", "and") + "."); + } + if (!base_quest_state.started) + { + if (QuestState("questG01Meatcar").finished || $item[bitchin' meatcar].available_amount() > 0) + { + subentry.entries.listAppend("Visit your friend at the guild to start the quest."); + active_url = "guild.php"; + } + else + { + subentry.entries.listAppend("Build a meatcar first."); + active_url = ""; + } + } + else if (base_quest_state.mafia_internal_step == 1) + { + //1 Find the road to the White Citadel, somewhere in Whitey's Grove. + //Unlock the road to white citadel: + subentry.modifiers.listAppend("+15% combat"); + subentry.modifiers.listAppend("free runs"); + subentry.entries.listAppend("Adventure in Whitey's Grove, unlock the road to the White Citadel."); + } + else if (base_quest_state.mafia_internal_step >= 2 && base_quest_state.mafia_internal_step <= 4) + { + //2 You've found the Road to the White Citadel! Now you can begin your quest there. + //3 Make your way through the dark forest near the Road to the White Citadel + //4 pairs of burnouts near the Road to the White Citadel. + int burnouts_defeated = get_property_int("burnoutsDefeated"); + int burnouts_remaining = 30 - burnouts_defeated; + + subentry.modifiers.listAppend("+item"); + + subentry.entries.listAppend("Adventure on the Road to White Citadel, defeat " + pluraliseWordy(burnouts_remaining, "more set of burn-outs", "more burn-outs") + "."); + + item opium_grenade = $item[opium grenade]; + + if (burnouts_remaining > 1) + { + if (opium_grenade.storage_amount() > 1 && pulls_remaining() == -1 && ceil(burnouts_remaining / 3.0) > $item[opium grenade].item_amount()) + subentry.entries.listAppend("Pull some opium grenades from hagnk's."); + else if (opium_grenade.storage_amount() > 0 && pulls_remaining() == -1 && ceil(burnouts_remaining / 3.0) > $item[opium grenade].item_amount()) + subentry.entries.listAppend("Pull an opium grenade from hagnk's."); + else if (opium_grenade.available_amount() == 1) + subentry.entries.listAppend("Throw an opium grenade at burnouts."); + else if (opium_grenade.available_amount() > 1) + subentry.entries.listAppend("Throw opium grenades at burnouts."); + } + + if ($item[poppy].available_amount() >= 2) + { + string line = "Make opium grenade. (meatpaste poppy + poppy)"; + if (opium_grenade.available_amount() == 0) + line = HTMLGenerateSpanFont(line, "red"); + subentry.entries.listAppend(line); + } + + //turn estimation why not? + float grenades_have_now = opium_grenade.available_amount().to_float() + $item[poppy].available_amount().to_float() * 0.5; + + float poppy_one_drop_rate = clampNormalf(0.3 * (1.0 + $location[the road to the white citadel].item_drop_modifier_for_location() / 100.0)); + float poppy_two_drop_rate = clampNormalf(0.1 * (1.0 + $location[the road to the white citadel].item_drop_modifier_for_location() / 100.0)); + if (using_black_cat_equivalent) + { + //strangely, there's no public listing of the batting away rates of these familiars + //umm... let's go with the assumption of 25%. + //data we have: 35 items batted, 120 items not batted, 22.5% rate. so 20-25%? + poppy_one_drop_rate *= 0.75; + poppy_two_drop_rate *= 0.75; + } + + if (my_path().id == PATH_HEAVY_RAINS) + { + float washaway_rate = $location[The Road to the White Citadel].washaway_rate_of_location(); + + poppy_one_drop_rate *= (1.0 - washaway_rate); + poppy_two_drop_rate *= (1.0 - washaway_rate); + } + + float grenades_per_combat = clampf((poppy_one_drop_rate + poppy_two_drop_rate) * 0.5, 0.0, 1.0); + + float turns_remaining = burnouts_remaining; + float burnouts_defeated_per_turn = 1.0 + grenades_per_combat * 2.0; + + //How many can we cover with the grenades we have? + int maximum_grenades_needed = ceil(burnouts_remaining / 3.0); + grenades_have_now = MIN(maximum_grenades_needed, grenades_have_now); + + turns_remaining = grenades_have_now; + int burnouts_remaining_after_turns = MAX(0, burnouts_remaining - turns_remaining * 3.0); + + if (burnouts_defeated_per_turn > 0.0) + turns_remaining += burnouts_remaining_after_turns / burnouts_defeated_per_turn; + + //turns_remaining = burnouts_remaining - MIN(maximum_grenades_needed, grenades_have_now) * 3; + + /*if (burnouts_defeated_per_turn > 0.0) + { + //very approximate: + float operating_burnouts_remaining = burnouts_remaining; + + operating_burnouts_remaining -= 3.0 * grenades_have_now; + //turns_remaining = grenades_have_now * 1.0; + + turns_remaining = operating_burnouts_remaining / burnouts_defeated_per_turn; + }*/ + + turns_remaining = clampf(turns_remaining, 1.0, 30.0); + if (turns_remaining < 1.05) + subentry.entries.listAppend("One More Turn remaining."); + else + subentry.entries.listAppend("~" + turns_remaining.roundForOutput(1) + " turns remaining."); + + } + else if (base_quest_state.mafia_internal_step == 5) + { + //5 Defeat the terrible biclops guarding the Road to the White Citadel. + subentry.entries.listAppend("Defeat the terrible biclops on the Road to the White Citadel."); + } + else if (base_quest_state.mafia_internal_step == 6) + { + //6 (Make your way through the dark forest near the Road to the White Citadel) + subentry.entries.listAppend("Adventure on the Road to the White Citadel."); + + string line; + + line = "Careful: this will turn your familiars into pigs"; + if (!using_black_cat_equivalent) + line = HTMLGenerateSpanFont(line, "red"); //ruby red spanners + line += ", who are unable to do anything, until you defeat Circe."; + + if (using_black_cat_equivalent) + line += "|Um... not that you'll mind."; + subentry.entries.listAppend(line); + } + else if (base_quest_state.mafia_internal_step == 7) + { + //7 Get into the witch's hut near the Road to the White Citadel. You could break the door down, but that seems risky. Maybe you can find a key somewhere? + subentry.entries.listAppend("Kick in the front door of the witch, on the Road to the White Citadel."); + subentry.entries.listAppend("This will bring back your familiars."); + if (my_familiar() == $familiar[black cat]) + { + add_as_future_task = true; + subentry.entries.listAppend("Or possibly don't. Poor kitty..."); + } + else if (my_familiar() == $familiar[O.A.F.]) + { + add_as_future_task = true; + subentry.entries.listAppend("Or possibly don't. Poor robot..."); + } + } + else if (base_quest_state.mafia_internal_step == 8 || base_quest_state.mafia_internal_step == 9) + { + //8 (Make your way through the dark forest near the Road to the White Citadel) + //9 Get through the cave full of shiny, delicious, enticing treasure chests near the Road to the White Citadel. + subentry.entries.listAppend("Adventure on the Road to the White Citadel, ignoring the treasure chests."); + } + else if (base_quest_state.mafia_internal_step == 10) + { + //10 Defeat the final obstacle on your way down the Road to the White Citadel. + subentry.entries.listAppend("Defeat Elpízo & Crosybdis, on the Road to the White Citadel, then collect the White Citadel Satisfaction Satchel."); + } + else if (base_quest_state.mafia_internal_step == 11 && $item[White Citadel Satisfaction Satchel].available_amount() == 0) + { + //11 lunch at the White Citadel. + subentry.entries.listAppend("Visit the white citadel for the White Citadel Satisfaction Satchel."); + } + else if (base_quest_state.mafia_internal_step == 11 || $item[White Citadel Satisfaction Satchel].available_amount() > 0) + { + //11 lunch at the White Citadel. + //Visit guild: + subentry.entries.listAppend("Visit your friend at the guild."); + active_url = "guild.php"; + } +//final You've delivered a satchel of incredibly greasy food to someone you barely know. Plus, you can now shop at White Citadel whenever you want. Awesome! + + + boolean [location] relevant_locations; + relevant_locations[$location[whitey's grove]] = true; + relevant_locations[$location[the road to the white citadel]] = true; + + string image_name = base_quest_state.image_name; + if (my_familiar() == $familiar[black cat]) + image_name = "__familiar black cat"; + + + ChecklistEntry entry = ChecklistEntryMake(image_name, active_url, subentry, relevant_locations); + entry.tags.id = "White citadel guild quest"; + if (add_as_future_task) + future_task_entries.listAppend(entry); + else + optional_task_entries.listAppend(entry); +} + + +void QWizardOfEgoInit() +{ + //if (!__misc_state["in aftercore"]) //not yet + //return; + if ($items[Manual of Dexterity,Manual of Labor,Manual of Transmission].available_amount() > 0) //finished already + return; + + //questM02Artist + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questG03Ego"); + if (my_path().id == PATH_GREY_GOO) QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + if (!state.finished) + { + //FIXME temporary code + //Update internal step locally: + //(this is buggy) + if (state.mafia_internal_step < 7 && $item[dusty old book].available_amount() > 0) + { + state.mafia_internal_step = 7; + } + if (state.mafia_internal_step < 1 && $location[The Unquiet Garves].noncombat_queue.contains_text("A Grave Mistake") || $location[The VERY Unquiet Garves].noncombat_queue.contains_text("A Grave Mistake")) + state.mafia_internal_step = 1; + if (state.mafia_internal_step < 2 && $location[The Unquiet Garves].noncombat_queue.contains_text("A Grave Situation") || $location[The VERY Unquiet Garves].noncombat_queue.contains_text("A Grave Situation")) + state.mafia_internal_step = 2; + + if (state.mafia_internal_step < 2 && $item[Fernswarthy's key].available_amount() > 0) + state.mafia_internal_step = 2; + + if (state.mafia_internal_step < 4 && $location[tower ruins].turnsAttemptedInLocation() > 0 && $item[Fernswarthy's key].available_amount() > 0) + state.mafia_internal_step = 4; + + if (state.mafia_internal_step < 5 && $location[tower ruins].noncombat_queue.contains_text("Staring into Nothing")) + state.mafia_internal_step = 5; + if (state.mafia_internal_step < 6 && $location[tower ruins].noncombat_queue.contains_text("Into the Maw of Deepness")) + state.mafia_internal_step = 6; + if (state.mafia_internal_step < 7 && $location[tower ruins].noncombat_queue.contains_text("Take a Dusty Look!")) + state.mafia_internal_step = 7; + + if (!state.in_progress && state.mafia_internal_step > 0 && $item[Fernswarthy's key].available_amount() > 0) + { + QuestStateParseMafiaQuestPropertyValue(state, "step" + (state.mafia_internal_step - 1)); + } + } + + state.quest_name = "The Wizard of Ego"; + state.image_name = "__item dilapidated wizard hat"; + + state.startable = true; + + __quest_state["Wizard of Ego"] = state; +} + + +void QWizardOfEgoGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Wizard of Ego"]; + if (!base_quest_state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + string url = ""; + if (base_quest_state.mafia_internal_step == 7 || $item[dusty old book].available_amount() > 0) + { + //7 You found some kind of dusty old book in Fernswarthy's tower. Hopefully that's enough to keep that guy in your guild off your case. + url = "guild.php"; + subentry.entries.listAppend("Speak to the guild."); + } + else if (base_quest_state.mafia_internal_step == 1) + { + url = "place.php?whichplace=plains"; + //1 You've been tasked with digging up the grave of an ancient and powerful wizard and bringing back a key that was buried with him. What could possibly go wrong? + if ($item[Fernswarthy's key].available_amount() > 0) + { + url = "guild.php"; + subentry.entries.listAppend("Return to your guild."); + } + else if ($items[grave robbing shovel, rusty grave robbing shovel].item_amount() == 0 && $item[grave robbing shovel].equipped_amount() == 0 && $item[rusty grave robbing shovel].equipped_amount() == 0) + { + string line = "Acquire a grave robbing shovel."; + if ($items[grave robbing shovel, rusty grave robbing shovel].available_amount() == 0) + line += " (from mall)"; + else if ($item[grave robbing shovel].storage_amount() + $item[rusty grave robbing shovel].storage_amount() > 0) + { + line += " (from hagnk's)"; + url = "storage.php?which=2"; + } + subentry.entries.listAppend(line); + } + else + { + url = "place.php?whichplace=cemetery"; + subentry.entries.listAppend("Adventure at the unquiet garves."); + } + } + else if (base_quest_state.mafia_internal_step == 2) + { + //2 Well, you got the key and turned it in -- mission accomplished. How much do you wanna bet, though, that they won't be able to find anyone else to search the tower, and you'll be stuck with the dirty work again? + url = "guild.php"; + subentry.entries.listAppend("Speak to the guild."); + } + else if (base_quest_state.mafia_internal_step == 3) + { + //3 Much as you expected, you've been given back the key to Fernswarthy's tower and ordered to investigate. + url = "fernruin.php"; + subentry.entries.listAppend("Adventure in the tower ruins."); + } + else if (base_quest_state.mafia_internal_step == 4) + { + //4 You've unlocked Fernswarthy's tower. Now you just have to find something to show your guild leaders, to prove you haven't just been slacking off this whole time. + //Unlocking just means visiting the area. + url = "fernruin.php"; + subentry.entries.listAppend("Adventure in the tower ruins. Three more non-combats remain."); + } + else if (base_quest_state.mafia_internal_step == 5) + { + //5 You've found some stairs in Fernswarthy's tower, but they don't lead to much. Better keep looking. + url = "fernruin.php"; + subentry.entries.listAppend("Adventure in the tower ruins. Two more non-combats remain."); + } + else if (base_quest_state.mafia_internal_step == 6) + { + //6 You've found a trapdoor to Fernswarthy's basement, which is potentially interesting and/or dangerous. It's probably not what your Guild is interested in, though, so you should probably keep looking. + url = "fernruin.php"; + subentry.entries.listAppend("Adventure in the tower ruins. One more non-combat remain."); + } + + boolean [location] relevant_locations; + relevant_locations[$location[The Unquiet Garves]] = true; + relevant_locations[$location[The VERY Unquiet Garves]] = true; + relevant_locations[$location[Tower Ruins]] = true; + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, relevant_locations).ChecklistEntrySetIDTag("Fernswarthy wizard guild quest")); +} + +void QSpookyravenLightsOutGenerateEntry(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, boolean from_task) //if from_task is false, assumed to be from resources +{ + //nextSpookyravenElizabethRoom + //nextSpookyravenStephenRoom + + if (get_property_int("lastLightsOutTurn") >= total_turns_played()) + return; + + string next_elizabeth_room = get_property("nextSpookyravenElizabethRoom"); + string next_stephen_room = get_property("nextSpookyravenStephenRoom"); + location next_elizabeth_location = next_elizabeth_room.to_location(); + location next_stephen_location = next_stephen_room.to_location(); + + int turns_until_next_lights_out = -1; + + //Thought about enabling this, but it's better to only show it when they ask for spookyraven tracking, I think... + //then again, spookyraven tracking doesn't work well with automation (auto-aborts, even if adventuring in relevant locations) + //turns_until_next_lights_out = 37 - total_turns_played() % 37; + + Counter lights_out_counter = CounterLookup("Spookyraven Lights Out"); + if (lights_out_counter.CounterExists() && !lights_out_counter.CounterIsRange()) + { + //turns_until_next_lights_out = lights_out_counter.CounterGetNextExactTurn(); //LYING. + turns_until_next_lights_out = 37 - total_turns_played() % 37; + } + + + if (turns_until_next_lights_out == 37) + turns_until_next_lights_out = 0; + + if (turns_until_next_lights_out == -1) + return; + + string url = ""; + + ChecklistSubentry [int] important_subentries; + if (turns_until_next_lights_out == 0 && from_task) + { + //now + if (next_stephen_location != $location[none]) + { + string [location][int] stephen_area_descriptions; + stephen_area_descriptions[$location[The Haunted Bedroom]] = listMake("Search for a light", "Search a nearby nightstand", "Check a nightstand on your left"); + stephen_area_descriptions[$location[The Haunted Nursery]] = listMake("Search for a lamp", "Search over by the (gaaah) stuffed animals", "Examine the Dresser", "Open the bear and put your hand inside", "Unlock the box"); + stephen_area_descriptions[$location[The Haunted Conservatory]] = listMake("Make a torch", "Examine the graves", "Examine the grave marked \"Crumbles\""); + stephen_area_descriptions[$location[The Haunted Billiards Room]] = listMake("Search for a light", "What the heck, let's explore a bit", "Examine the taxidermy heads"); + stephen_area_descriptions[$location[The Haunted Wine Cellar]] = listMake("Try to find a light", "Keep your cool", "Investigate the wine racks", "Examine the Pinot Noir rack"); + stephen_area_descriptions[$location[The Haunted Boiler Room]] = listMake("Look for a light", "Search the barrel", "No, but I will anyway"); + stephen_area_descriptions[$location[The Haunted Laboratory]] = listMake("Search for a light", "Check it out", "Examine the weird machines", "Enter 23-47-99 and turn on the machine", "Oh god"); + + string [int] description; + + string first_line = ""; + if (__misc_state["in run"]) + { + if (__misc_state["familiars temporarily blocked"]) + first_line += "Not useful this run. "; + else + first_line += "Situationally useful (+familiar weight) in-run. "; + } + if (next_stephen_location == $location[The Haunted Laboratory]) + first_line += HTMLGenerateSpanFont("Will take a turn.", "red"); + else + first_line += "Will not take a turn."; + + if (first_line != "") + description.listAppend(first_line); + + string line = "Adventure in " + next_stephen_room; + if (next_stephen_location == $location[The Haunted Laboratory]) + line += " to fight Stephen Spookyraven"; + line += "."; + if (stephen_area_descriptions contains next_stephen_location) + line += "|*" + stephen_area_descriptions[next_stephen_location].listJoinComponents(__html_right_arrow_character) + "."; + description.listAppend(line); + + url = next_stephen_location.getClickableURLForLocation(); + + important_subentries.listAppend(ChecklistSubentryMake("Stephen Spookyraven Quest", "", description)); + } + + + if (next_elizabeth_location != $location[none]) + { + string [location][int] elizabeth_area_descriptions; + elizabeth_area_descriptions[$location[The Haunted Storage Room]] = listMake("Look out the Window"); + elizabeth_area_descriptions[$location[The Haunted Laundry Room]] = listMake("Check a Pile of Stained Sheets"); + elizabeth_area_descriptions[$location[The Haunted Bathroom]] = listMake("Inspect the Bathtub"); + elizabeth_area_descriptions[$location[The Haunted Kitchen]] = listMake("Make a Snack"); + elizabeth_area_descriptions[$location[The Haunted Library]] = listMake("Go to the Childrens' Section"); + elizabeth_area_descriptions[$location[The Haunted Ballroom]] = listMake("Dance with Yourself"); + elizabeth_area_descriptions[$location[The Haunted Gallery]] = listMake("Check out the Tormented Damned Souls Painting"); + + string [int] description; + string first_line = ""; + if (__misc_state["in run"]) + first_line += "Not useful in-run. "; + if (next_elizabeth_location == $location[The Haunted Gallery]) + first_line += HTMLGenerateSpanFont("Will take a turn.", "red"); + else + first_line += "Will not take a turn."; + + if (first_line != "") + description.listAppend(first_line); + + string line = "Adventure in " + next_elizabeth_room; + if (next_elizabeth_location == $location[The Haunted Gallery]) + line += " to fight Elizabeth Spookyraven"; + line += "."; + if (elizabeth_area_descriptions contains next_elizabeth_location) + line += "|*" + elizabeth_area_descriptions[next_elizabeth_location].listJoinComponents(__html_right_arrow_character) + "."; + description.listAppend(line); + + + if (url.length() == 0) + url = next_elizabeth_location.getClickableURLForLocation(); + + important_subentries.listAppend(ChecklistSubentryMake("Elizabeth Spookyraven Quest", "", description)); + } + } + else if ((turns_until_next_lights_out < 6 && from_task) || (turns_until_next_lights_out >= 6 && !from_task)) + { + //Soon... + //FIXME should we show this? + string [int] available_questlines; + if (next_stephen_location != $location[none]) + available_questlines.listAppend("Stephen"); + if (next_elizabeth_location != $location[none]) + available_questlines.listAppend("Elizabeth"); + if (available_questlines.count() > 0) + { + optional_task_entries.listAppend(ChecklistEntryMake("__half Lights Out", "", ChecklistSubentryMake("Lights Out in " + pluralise(turns_until_next_lights_out, "adventure", "adventures"), "", available_questlines.listJoinComponents(", ", "and") + " quest " + (available_questlines.count() > 1 ? "lines" : "line") + "."), (from_task ? 5 : 8)).ChecklistEntrySetIDTag("Manor lights out prediction")); //difference if they come from task or not? + } + } + + if (important_subentries.count() > 0) + { + if (url == "place.php?whichplace=manor2" && !get_property_ascension("lastSecondFloorUnlock")) + url = ""; + task_entries.listAppend(ChecklistEntryMake("__half Lights Out", url, important_subentries, -11).ChecklistEntrySetIDTag("Manor lights out now")); + } +} + +void QSpookyravenLightsOutGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QSpookyravenLightsOutGenerateEntry(task_entries, optional_task_entries, true); + + if (get_property_int("lastLightsOutTurn") < total_turns_played() && total_turns_played() % 37 == 0 && __misc_state["in run"]) + { + string [int] exploit_description; + string url = ""; + if (__iotms_usable[$item[haunted doghouse]]) + { + location [int] possible_locations; + boolean [location] all_lights_out_locations; + all_lights_out_locations[$location[the haunted storage room]] = true; + all_lights_out_locations[$location[the haunted Laundry Room]] = true; + //all_lights_out_locations[$location[the haunted Bathroom]] = true; //Very small chance of a demon name, which costs a turn. It happened to me! + all_lights_out_locations[$location[the haunted Kitchen]] = true; + all_lights_out_locations[$location[the haunted Library]] = true; + all_lights_out_locations[$location[the haunted Ballroom]] = true; + all_lights_out_locations[$location[the haunted Gallery]] = true; + if ($location[the haunted Bedroom].turns_spent < 10) + all_lights_out_locations[$location[the haunted Bedroom]] = true; + all_lights_out_locations[$location[the haunted Nursery]] = true; + all_lights_out_locations[$location[the haunted Conservatory]] = true; + all_lights_out_locations[$location[the haunted Billiards Room]] = true; + all_lights_out_locations[$location[the haunted Wine Cellar]] = true; + all_lights_out_locations[$location[the haunted Boiler Room]] = true; + all_lights_out_locations[$location[the haunted Laboratory]] = true; + + foreach l in all_lights_out_locations + { + if (l.combatTurnsAttemptedInLocation() < 5) + continue; + if (l.noncombat_queue.contains_text("Wooooooof!")) + continue; + possible_locations.listAppend(l); + } + if (possible_locations.count() > 0) + { + exploit_description.listAppend("Adventure in " + possible_locations.listJoinComponents(", ", "or") + " to potentially trigger a halloweiner adventure.|It won't cost a turn."); + url = possible_locations[0].getClickableURLForLocation(); + } + } + if ($item[turkey blaster].available_amount() + $item[turkey blaster].creatable_amount() > 0 && availableSpleen() >= 2 && get_property_int("_turkeyBlastersUsed") < 3) + { + location [int] possible_locations; + foreach l in $locations[the haunted gallery,the haunted bathroom] + { + if (l.delayRemainingInLocation() >= 4 && l.locationAvailable()) + { + possible_locations.listAppend(l); + + } + } + if (possible_locations.count() > 0) + { + exploit_description.listAppend("Adventure in " + possible_locations.listJoinComponents(", ", "or") + ", then chew a turkey blaster to burn delay."); + if (url == "") + url = possible_locations[0].getClickableURLForLocation(); + } + } + if (exploit_description.count() > 0) + task_entries.listAppend(ChecklistEntryMake("__half Lights Out", url, ChecklistSubentryMake("Lights Out Exploit", "", exploit_description), -11).ChecklistEntrySetIDTag("Manor lights out suggest exploit")); + } +} + +void QSpookyravenLightsOutGenerateResource(ChecklistEntry [int] resource_entries) +{ + QSpookyravenLightsOutGenerateEntry(resource_entries, resource_entries, false); +} + + +void QFeloniaInit() +{ + //questM03Bugbear + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questM03Bugbear"); + + state.quest_name = "Felonia"; + state.image_name = "__item knoll mushroom"; + + state.startable = knoll_available(); + + __quest_state["Felonia"] = state; +} + + +void QFeloniaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Felonia"]; + if (!base_quest_state.in_progress) + return; + if (!knoll_available()) + return; + if (__misc_state["familiars temporarily blocked"]) //cannot complete + return; + if (__misc_state["in run"] && $location[the bugbear pen].turnsAttemptedInLocation() == 0) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + string url = "place.php?whichplace=knoll_friendly"; + + if (get_property("lastEncounter") == "Felonia, Queen of the Spooky Gravy Fairies") + { + subentry.header = "Speak to Mayor Zapruder"; + } + else if (base_quest_state.mafia_internal_step == 1) + { + //Acquire annoying pitchfork: + subentry.header = "Tame the Bugbears"; + if ($item[annoying pitchfork].available_amount() == 0) + { + if (!in_ronin()) + { + subentry.entries.listAppend("Acquire annoying pitchfork in the mall."); + url = "mall.php"; + } + else + { + subentry.entries.listAppend("Acquire annoying pitchfork from an annoying spooky gravy fairy in the Bugbear Pens."); + } + } + else + subentry.entries.listAppend("Speak to Mayor Zapruder to give him the annoying pitchfork."); + } + else if (base_quest_state.mafia_internal_step == 2) + { + //Acquire the right mushroom: + subentry.header = "Summon a Mushroom Familiar"; + + if ($item[frozen mushroom].available_amount() > 0 && $item[stinky mushroom].available_amount() > 0 && $item[flaming mushroom].available_amount() > 0) + { + subentry.entries.listAppend("Speak to Mayor Zapruder to give him mushrooms."); + } + else + { + subentry.entries.listAppend("Grow the mushroom Mayor Zapruder wants."); + url = "knoll_mushrooms.php"; + } + } + else if (base_quest_state.mafia_internal_step == 3) + { + //defeat felonia: + subentry.header = "Defeat Felonia"; + + boolean currently_using_a_relevant_familiar = false; + familiar fairy_to_use = $familiar[none]; + foreach f in $familiars[Flaming Gravy Fairy,Frozen Gravy Fairy,Stinky Gravy Fairy,Sleazy Gravy Fairy,spooky gravy fairy] + { + if (f.have_familiar()) + fairy_to_use = f; + if (my_familiar() == f) + currently_using_a_relevant_familiar = true; + } + if ($familiar[spooky gravy fairy].have_familiar()) + fairy_to_use = $familiar[spooky gravy fairy]; + + if (fairy_to_use == $familiar[none]) + { + item [int] fairies_can_grow; + foreach it in $items[pregnant flaming mushroom,pregnant frozen mushroom,pregnant stinky mushroom,pregnant oily golden mushroom,pregnant gloomy black mushroom] + { + fairies_can_grow.listAppend(it); + } + if (fairies_can_grow.count() == 0) + { + subentry.entries.listAppend("Um... try to find a gravy fairy somehow."); + } + else + { + subentry.entries.listAppend("Grow one of " + fairies_can_grow.listJoinComponents(", ", "or") + "."); + } + } + else if (!currently_using_a_relevant_familiar) + { + subentry.entries.listAppend("Bring along a " + fairy_to_use + "."); + url = "familiar.php"; + } + else + { + boolean need_minus_combat = false; + if ($item[inexplicably glowing rock].available_amount() > 0 && $item[spooky glove].available_amount() > 0) + { + string [int] tasks; + if ($item[spooky glove].equipped_amount() == 0) + { + tasks.listAppend("equip the spooky glove"); + url = "inventory.php?ftext=spooky+glove"; + } + tasks.listAppend("defeat Felonia"); + + subentry.entries.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + " in the Spooky Gravy Burrow."); + need_minus_combat = true; + } + else + { + item [int] items_needed; + if ($item[inexplicably glowing rock].available_amount() == 0) + { + items_needed.listAppend($item[inexplicably glowing rock]); + need_minus_combat = true; + } + + if ($item[spooky glove].available_amount() == 0) + { + if ($item[spooky fairy gravy].available_amount() > 0 && $item[small leather glove].available_amount() > 0) + { + url = "craft.php?mode=cook"; + subentry.entries.listAppend("Make and wear a spooky glove. (cook spooky fairy gravy + small leather glove)"); + } + else + { + if ($item[spooky fairy gravy].available_amount() == 0) + { + items_needed.listAppend($item[spooky fairy gravy]); + need_minus_combat = true; + } + if ($item[small leather glove].available_amount() == 0) + { + subentry.modifiers.listAppend("+900% item"); + items_needed.listAppend($item[small leather glove]); + subentry.entries.listAppend("Or buy small leather glove in the mall."); + } + } + } + if (items_needed.count() > 0) + { + subentry.entries.listPrepend("Adventure in the Spooky Gravy Burrow for " + items_needed.listJoinComponents(", ", "and") + "."); + } + } + + if (need_minus_combat) + subentry.modifiers.listPrepend("-combat?"); + } + } + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[the bugbear pen,the spooky gravy burrow]).ChecklistEntrySetIDTag("Felonia knoll quest")); +} + +void QGuildInit() +{ + if (!($classes[seal clubber,turtle tamer,pastamancer,sauceror,disco bandit,accordion thief] contains my_class())) + return; + if (my_path().id == PATH_POCKET_FAMILIARS) + return; + //questM02Artist + QuestState state; + + if ($classes[seal clubber,turtle tamer] contains my_class()) + QuestStateParseMafiaQuestProperty(state, "questG09Muscle"); + if ($classes[pastamancer,sauceror] contains my_class()) + QuestStateParseMafiaQuestProperty(state, "questG07Myst"); + if ($classes[disco bandit,accordion thief] contains my_class()) + QuestStateParseMafiaQuestProperty(state, "questG08Moxie"); + if (guild_store_available()) + QuestStateParseMafiaQuestPropertyValue(state, "finished"); + + + + //state.quest_name = "Guilded Youth"; + state.quest_name = "Join your guild"; + if (my_class() == $class[seal clubber]) + state.image_name = "__item seal-clubbing club"; + else if (my_class() == $class[turtle tamer]) + state.image_name = "__item helmet turtle"; + else if (my_class() == $class[pastamancer]) + state.image_name = "__item pasta spoon"; + else if (my_class() == $class[sauceror]) + state.image_name = "__item saucepan"; + else if (my_class() == $class[disco bandit]) + state.image_name = "__item disco mask"; + else if (my_class() == $class[accordion thief]) + state.image_name = "__item stolen accordion"; + + if (state.mafia_internal_step < 2 && ($item[11-inch knob sausage].available_amount() > 0 || $item[exorcised sandwich].available_amount() > 0 && $location[the sleazy back alley].noncombat_queue.contains_text("Now's Your Pants!"))) + { + QuestStateParseMafiaQuestPropertyValue(state, "step1"); + } + + state.startable = !(my_path().id == PATH_GREY_GOO && $classes[seal clubber,turtle tamer] contains my_class()); + + __quest_state["Guild"] = state; +} + + +void QGuildGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!($classes[seal clubber,turtle tamer,pastamancer,sauceror,disco bandit,accordion thief] contains my_class())) + return; + if (my_path().id == PATH_POCKET_FAMILIARS) + return; + if (my_path().id == PATH_NUCLEAR_AUTUMN) + return; + QuestState base_quest_state = __quest_state["Guild"]; + if (base_quest_state.finished || !base_quest_state.startable) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + string active_url = ""; + + if (__misc_state["in run"] && my_path().id != PATH_PICKY && !in_bad_moon()) + { + if ($classes[pastamancer,sauceror] contains my_class() && $location[the haunted pantry].turnsAttemptedInLocation() == 0) + return; + if ($classes[disco bandit,accordion thief] contains my_class() && $location[the sleazy back alley].turnsAttemptedInLocation() == 0) + return; + if (!base_quest_state.started && !($classes[seal clubber,turtle tamer] contains my_class())) + return; + } + + boolean [location] relevant_location; + + if (!base_quest_state.started) + { + subentry.entries.listAppend("Talk to your guild chief."); + active_url = "guild.php"; + } + else if (base_quest_state.mafia_internal_step == 1) + { + boolean output_modifiers = false; + if ($classes[seal clubber,turtle tamer] contains my_class()) + { + //cobb's knob + active_url = $location[the outskirts of Cobb's Knob].getClickableURLForLocation(); + relevant_location[$location[the outskirts of Cobb's Knob]] = true; + subentry.entries.listAppend("Adventure in the outskirts of Cobb's Knob to find the sausage."); + output_modifiers = true; + } + if ($classes[pastamancer,sauceror] contains my_class()) + { + //haunted pantry + active_url = $location[the haunted pantry].getClickableURLForLocation(); + relevant_location[$location[the haunted pantry]] = true; + subentry.entries.listAppend("Adventure in the haunted pantry to exorcise the poltersandwich."); + output_modifiers = true; + } + if ($classes[disco bandit,accordion thief] contains my_class()) + { + //sleazy back alley + relevant_location[$location[the sleazy back alley]] = true; + if ($slot[pants].equipped_item() == $item[none]) + { + active_url = "inventory.php?which=2"; + subentry.entries.listAppend("Equip some pants."); + } + else + { + active_url = $location[the sleazy back alley].getClickableURLForLocation(); + subentry.entries.listAppend("Adventure in the sleazy back alley to steal your own pants."); + output_modifiers = true; + } + } + + if (output_modifiers) + { + if (__misc_state["free runs available"]) + { + subentry.modifiers.listAppend("free runs"); + } + if (__misc_state["have hipster"]) + { + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + } + } + } + else if (base_quest_state.mafia_internal_step == 2) + { + subentry.entries.listAppend("Talk to your guild chief."); + active_url = "guild.php"; + } + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, relevant_location).ChecklistEntrySetIDTag("Guild unlock quest")); +} + +void QSleazeAirportBuffJimmyGenerateTasks(ChecklistEntry [int] task_entries, QuestState [string] SBBState) +{ + if (SBBState["questESlMushStash"].in_progress) + { + //jimmy, fun-guy + //run +item, collect 10 pencil thin mushrooms (item) + ChecklistSubentry subentry; + subentry.header = "Pencil-Thin Mush Stash"; + + item item_to_collect = $item[pencil thin mushroom]; + int remaining_of_item = MAX(0, 10 - item_to_collect.item_amount()); + if (SBBState["questESlMushStash"].mafia_internal_step > 2 || remaining_of_item <= 0) + subentry.entries.listAppend("Return to Buff Jimmy."); + else if (SBBState["questESlAudit"].in_progress) + subentry.entries.listAppend("Need to finish Audit-Tory Hallucinations, first."); + else + { + subentry.modifiers.listAppend("+item"); + subentry.entries.listAppend("Adventure in the The Fun-Guy Mansion and collect " + pluraliseWordy(remaining_of_item, "more " + item_to_collect.name, "more " + item_to_collect.plural) + "."); + } + + task_entries.listAppend(ChecklistEntryMake("__item pencil thin mushroom", "place.php?whichplace=airport_sleaze", subentry, $locations[The Fun-Guy Mansion])); + } + else if (SBBState["questESlCheeseburger"].in_progress) + { + //jimmy, diner + //buffJimmyIngredients - need 15(?) + //equip Paradaisical Cheeseburger recipe, olfact Sloppy Seconds Burgers + ChecklistSubentry subentry; + subentry.header = "Paradise Cheeseburger"; + + int remaining_of_item = MAX(0, 15 - get_property_int("buffJimmyIngredients")); + if (SBBState["questESlCheeseburger"].mafia_internal_step > 2 || remaining_of_item <= 0) + subentry.entries.listAppend("Return to Buff Jimmy."); + else + { + subentry.modifiers.listAppend("olfact Burgers"); + subentry.entries.listAppend("Adventure in the Sloppy Seconds Diner and collect " + pluraliseWordy(remaining_of_item, "more ingredient", "more ingredients") + "."); + if ($item[Paradaisical Cheeseburger recipe].available_amount() > 0 && $item[Paradaisical Cheeseburger recipe].equipped_amount() == 0) + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the Paradaisical Cheeseburger recipe.", "red")); + } + + task_entries.listAppend(ChecklistEntryMake("__item hamburger", "place.php?whichplace=airport_sleaze", subentry, $locations[Sloppy Seconds Diner])); + } + else if (SBBState["questESlSalt"].in_progress) + { + //jimmy, yacht + //collect 50 salty sailor salts (item), olfact son of a son of a sailor, run +ML, want fishy + ChecklistSubentry subentry; + subentry.header = "Lost Shaker of Salt"; + + item item_to_collect = $item[salty sailor salt]; + int remaining_of_item = MAX(0, 50 - item_to_collect.item_amount()); + if (SBBState["questESlSalt"].mafia_internal_step > 2 || remaining_of_item <= 0) + subentry.entries.listAppend("Return to Buff Jimmy."); + else + { + subentry.modifiers.listAppend("+ML"); + subentry.modifiers.listAppend("olfact son of a son of a sailor"); + subentry.entries.listAppend("Adventure in The Sunken Party Yacht and collect " + pluraliseWordy(remaining_of_item, "more salt", "more salts") + "."); + if ($effect[fishy].have_effect() == 0) + subentry.entries.listAppend("Try to acquire Fishy effect."); + } + + task_entries.listAppend(ChecklistEntryMake("__item salty sailor salt", "place.php?whichplace=airport_sleaze", subentry, $locations[The Sunken Party Yacht])); + } +} +void QSleazeAirportTacoDanGenerateTasks(ChecklistEntry [int] task_entries, QuestState [string] SBBState) +{ + if (SBBState["questESlAudit"].in_progress) + { + //questESlAudit + //taco dan, fun-guy + //look for 10 Taco Dan's Taco Stand's Taco Receipt (item). requires Sleight of Mind effect from sleight-of-hand mushrooms dropped from area + ChecklistSubentry subentry; + subentry.header = "Audit-Tory Hallucinations"; + + item item_to_collect = $item[Taco Dan's Taco Stand's Taco Receipt]; + int remaining_of_item = MAX(0, 10 - item_to_collect.item_amount()); + if (SBBState["questESlAudit"].mafia_internal_step > 2 || remaining_of_item <= 0) + subentry.entries.listAppend("Return to Taco Dan."); + else + { + if ($effect[sleight of mind].have_effect() == 0 && $item[sleight-of-hand mushroom].available_amount() > 0) + subentry.entries.listAppend(HTMLGenerateSpanFont("Use sleight-of-hand mushroom", "red") + " to acquire receipts."); + subentry.entries.listAppend("Adventure in the The Fun-Guy Mansion and collect " + pluraliseWordy(remaining_of_item, "more receipt", "more receipts") + "."); + } + + task_entries.listAppend(ChecklistEntryMake("__item Taco Dan's Taco Stand's Taco Receipt", "place.php?whichplace=airport_sleaze", subentry, $locations[The Fun-Guy Mansion])); + } + else if (SBBState["questESlCocktail"].in_progress) + { + //taco dan, diner + //tacoDanCocktailSauce + //equip Taco Dan's Taco Stand Cocktail Sauce Bottle, olfact Sloppy Seconds Cocktails + ChecklistSubentry subentry; + subentry.header = "Cocktail as old as Cocktime"; + + int remaining_of_item = MAX(0, 15 - get_property_int("tacoDanCocktailSauce")); + if (SBBState["questESlCocktail"].mafia_internal_step > 2 || remaining_of_item <= 0) + subentry.entries.listAppend("Return to Taco Dan."); + else + { + subentry.modifiers.listAppend("olfact Cocktails"); + subentry.entries.listAppend("Adventure in the Sloppy Seconds Diner and collect " + remaining_of_item.int_to_wordy() + " more sauce."); + if ($item[Taco Dan's Taco Stand Cocktail Sauce Bottle].available_amount() > 0 && $item[Taco Dan's Taco Stand Cocktail Sauce Bottle].equipped_amount() == 0) + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the Taco Dan's Taco Stand Cocktail Sauce Bottle.", "red")); + } + + task_entries.listAppend(ChecklistEntryMake("__item Taco Dan's Taco Stand Cocktail Sauce Bottle", "place.php?whichplace=airport_sleaze", subentry, $locations[Sloppy Seconds Diner])); + } + else if (SBBState["questESlFish"].in_progress) + { + //taco dan, yacht + //tacoDanFishMeat + //collect 300 fish meat, olfact taco fish, run +meat, want fishy + ChecklistSubentry subentry; + subentry.header = "Dirty Fishy Dish"; + + int remaining_of_item = MAX(0, 300 - get_property_int("tacoDanFishMeat")); + if (SBBState["questESlFish"].mafia_internal_step > 2 || remaining_of_item <= 0) + subentry.entries.listAppend("Return to Taco Dan."); + else + { + subentry.modifiers.listAppend("+meat"); + subentry.modifiers.listAppend("olfact taco fish"); + subentry.entries.listAppend("Adventure in The Sunken Party Yacht and collect " + remaining_of_item.int_to_wordy() + " more fish meat."); + if ($effect[fishy].have_effect() == 0) + subentry.entries.listAppend("Try to acquire Fishy effect."); + } + + task_entries.listAppend(ChecklistEntryMake("__item fishy fish", "place.php?whichplace=airport_sleaze", subentry, $locations[The Sunken Party Yacht])); + } +} +void QSleazeAirportBrodenGenerateTasks(ChecklistEntry [int] task_entries, QuestState [string] SBBState) +{ + if (SBBState["questESlBacteria"].in_progress) + { + //broden, fun-guy, brodenBacteria + //+all(?) elemental resistance + //collect 10 bacteria + ChecklistSubentry subentry; + subentry.header = "Cultural Studies"; + + int remaining_of_item = MAX(0, 10 - get_property_int("brodenBacteria")); + if (SBBState["questESlBacteria"].mafia_internal_step > 2 || remaining_of_item <= 0) + subentry.entries.listAppend("Return to Broden."); + else if (SBBState["questESlMushStash"].in_progress) + subentry.entries.listAppend("Need to finish Pencil-Thin Mush Stash, first."); + else if (SBBState["questESlAudit"].in_progress) + subentry.entries.listAppend("Need to finish Audit-Tory Hallucinations, first."); + else + { + subentry.modifiers.listAppend("+elemental resistance"); + subentry.entries.listAppend("Adventure in the The Fun-Guy Mansion and collect " + remaining_of_item.int_to_wordy() + " more bacteria."); + } + + task_entries.listAppend(ChecklistEntryMake("__item chainsaw chain", "place.php?whichplace=airport_sleaze", subentry, $locations[The Fun-Guy Mansion])); + } + else if (SBBState["questESlSprinkles"].in_progress) + { + //broden, diner + //brodenSprinkles + //equip sprinkle shaker, olfact Sloppy Seconds Sundaes + ChecklistSubentry subentry; + subentry.header = "A Light Sprinkle"; + + int remaining_of_item = MAX(0, 15 - get_property_int("brodenSprinkles")); + if (SBBState["questESlSprinkles"].mafia_internal_step > 2 || remaining_of_item <= 0) + subentry.entries.listAppend("Return to Broden."); + else + { + subentry.modifiers.listAppend("olfact Sundaes"); + subentry.entries.listAppend("Adventure in the Sloppy Seconds Diner and collect " + remaining_of_item.int_to_wordy() + " more sprinkles."); + if ($item[sprinkle shaker].available_amount() > 0 && $item[sprinkle shaker].equipped_amount() == 0) + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the sprinkle shaker.", "red")); + } + + task_entries.listAppend(ChecklistEntryMake("__item sprinkle shaker", "place.php?whichplace=airport_sleaze", subentry, $locations[Sloppy Seconds Diner])); + } + else if (SBBState["questESlDebt"].in_progress) + { + //broden, yacht + //collect 15 bike rental broupon (item), olfact drownedbeat, want fishy + ChecklistSubentry subentry; + subentry.header = "Beat Dead the Deadbeats"; + + item item_to_collect = $item[bike rental broupon]; + int remaining_of_item = MAX(0, 15 - item_to_collect.item_amount()); + if (SBBState["questESlDebt"].mafia_internal_step > 2 || remaining_of_item <= 0) + subentry.entries.listAppend("Return to Broden."); + else + { + subentry.modifiers.listAppend("olfact drownedbeat"); + subentry.entries.listAppend("Adventure in The Sunken Party Yacht and collect " + pluraliseWordy(remaining_of_item, "more " + item_to_collect.name, "more " + item_to_collect.plural) + "."); + if ($effect[fishy].have_effect() == 0) + subentry.entries.listAppend("Try to acquire Fishy effect."); + } + + task_entries.listAppend(ChecklistEntryMake("__item fixed-gear bicycle", "place.php?whichplace=airport_sleaze", subentry, $locations[The Sunken Party Yacht])); + } +} + + +void QSleazeAirportUMDGenerateTasks(ChecklistEntry [int] task_entries) +{ + if (!__misc_state["sleaze airport available"]) + return; + if (get_property("umdLastObtained") != "") { // && !__misc_state["in run"] + string umd_date_obtained = get_property("umdLastObtained"); + + int day_in_year_acquired_umd = format_date_time("yyyy-MM-dd", umd_date_obtained, "D").to_int(); + int year_umd_acquired = format_date_time("yyyy-MM-dd", umd_date_obtained, "yyyy").to_int(); + + string todays_date = today_to_string(); + int today_day_in_year = format_date_time("yyyyMMdd", todays_date, "D").to_int(); + int todays_year = format_date_time("yyyyMMdd", todays_date, "yyyy").to_int(); + + //We compute the delta of days since last UMD obtained. If it's seven or higher, they can obtain it. + //If the year is different, more complicated. + //Umm... this will inevitably have an off by one error from me not looking closely enough. + + boolean has_been_seven_days = false; + if (year_umd_acquired != todays_year) { + //Query the number of days in last year, then subtract it from day_in_year_acquired_umd. + + int days_in_last_year = format_date_time("yyyy-MM-dd", todays_year + "-12-31", "D").to_int(); //this may work well past the year 10k. if it doesn't and you track down this bug and it's a problem, hello from eight thousand years ago! + + day_in_year_acquired_umd -= days_in_last_year * (todays_year - year_umd_acquired); //this is technically incorrect due to leap years, but it'll still result in proper checking. do not use for delta code + } + + if (today_day_in_year - day_in_year_acquired_umd >= 7) + has_been_seven_days = true; + if (has_been_seven_days) { + string [int] description; + description.listAppend("Adventure in the Sunken Party Yacht.|Choose the first option from a non-combat that appears every twenty adventures."); + description.listAppend("Found once every seven days."); + if ($effect[fishy].have_effect() == 0) + description.listAppend("Possibly acquire fishy effect first."); + if ($item[clara's bell].available_amount() > 0 && !get_property_boolean("_claraBellUsed")) + description.listAppend("Use clara's bell to instantly acquire. Won't need fishy."); + ChecklistEntry entry = ChecklistEntryMake("__item ultimate mind destroyer", $location[The Sunken Party Yacht].getClickableURLForLocation(), ChecklistSubentryMake("Ultimate Mind Destroyer collectable", "free runs", description), $locations[The Sunken Party Yacht]); + entry.tags.id = "Airport sleaze UMD"; + task_entries.listAppend(entry); + } + } +} + +void QSleazeAirportGenerateTasks(ChecklistEntry [int] task_entries) +{ + /* + questESlMushStash - Jimmy, Fun-Guy + questESlAudit - Taco Dan, Fun-Guy + questESlBacteria - Broden, Fun-Guy, brodenBacteria + + questESlCheeseburger - Jimmy, Sloppy Seconds Diner, buffJimmyIngredients(?) + questESlCocktail - Taco Dan, Sloppy Seconds Diner, tacoDanCocktailSauce + questESlSprinkles - Broden, Sloppy Seconds Diner, brodenSprinkles + + questESlSalt - Jimmy, Sunken Yacht + questESlFish - Taco Dan, Sunken Yacht, tacoDanFishMeat + questESlDebt - Broden, Sunken Yacht + */ + //if (__misc_state["in run"] && !($locations[the sunken party yacht,sloppy seconds diner,the fun-guy mansion] contains __last_adventure_location)) //too many + //return; + QuestState [string] SBBState; + SBBState["questESlMushStash"] = QuestState("questESlMushStash"); + SBBState["questESlCheeseburger"] = QuestState("questESlCheeseburger"); + SBBState["questESlSalt"] = QuestState("questESlSalt"); + SBBState["questESlAudit"] = QuestState("questESlAudit"); + SBBState["questESlCocktail"] = QuestState("questESlCocktail"); + SBBState["questESlFish"] = QuestState("questESlFish"); + SBBState["questESlBacteria"] = QuestState("questESlBacteria"); + SBBState["questESlSprinkles"] = QuestState("questESlSprinkles"); + SBBState["questESlDebt"] = QuestState("questESlDebt"); + + ChecklistEntry [int] subtask_entries; + QSleazeAirportBuffJimmyGenerateTasks(subtask_entries, SBBState); + QSleazeAirportTacoDanGenerateTasks(subtask_entries, SBBState); + QSleazeAirportBrodenGenerateTasks(subtask_entries, SBBState); + + if (subtask_entries.count() > 0) { + //Combine them into one entry, for convenience: + ChecklistEntry final_entry; + boolean first = true; + foreach key, entry in subtask_entries { + if (first) { + final_entry = entry; + first = false; + } else { + foreach key2, subentry in entry.subentries { + final_entry.subentries.listAppend(subentry); + } + if (entry.should_highlight) + final_entry.should_highlight = true; + } + + } + final_entry.tags.id = "Airport sleaze quest group"; + + task_entries.listAppend(final_entry); + } + + QSleazeAirportUMDGenerateTasks(task_entries); +} + +//Conspiracy Island Omega Button +RegisterTaskGenerationFunction("IOTMConspiracyIslandGenerateTasks"); +void IOTMConspiracyIslandGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__misc_state["spooky airport available"]) + return; + //press the button! + ChecklistEntry entry; + entry.url = "place.php?whichplace=airport_spooky_bunker&action=si_controlpanel"; + entry.image_lookup_name = "__item big red button"; + entry.importance_level = 8; + int omegaPower = get_property_int("controlPanelOmega"); + if (!get_property_boolean("_controlPanelUsed")) + { + entry.subentries.listAppend(ChecklistSubentryMake(omegaPower + "% Conspiracy Island Omega power", "", "At 100%, press Omega Button to reset better quests.")); + if (!get_property_boolean("controlPanel8") == false) + entry.subentries.listAppend(ChecklistSubentryMake("", "", "Press 1912 Button.")); + if (!get_property_boolean("controlPanel9") == false) + entry.subentries.listAppend(ChecklistSubentryMake("", "", "Press 0-0Z-E Button.")); + } + if (omegaPower == 100) + entry.subentries.listAppend(ChecklistSubentryMake("100% power! Reset to gain new quests and then uze 0-0Z-E again!")); + if (entry.subentries.count() > 0) + { + optional_task_entries.listAppend(entry); + } +} + +void QSpookyAirportJunglePunGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item encrypted micro-cassette recorder"; + state.quest_name = "Pungle in the Jungle"; + QuestStateParseMafiaQuestProperty(state, "questESpJunglePun"); + + if (!state.in_progress) + return; + item recorder = $item[encrypted micro-cassette recorder]; + + if (recorder.available_amount() == 0) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_spooky"; + + + int puns_remaining = 11 - get_property_int("junglePuns"); + if (state.mafia_internal_step <= 2 && puns_remaining > 0) { + subentry.entries.listAppend("Adventure in The Deep Dark Jungle."); + subentry.modifiers.listAppend("+myst"); + + if (recorder.equipped_amount() == 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + recorder.name + ".", "red")); + url = "inventory.php?ftext=encrypted+micro-cassette+recorder"; + } + + subentry.entries.listAppend(pluraliseWordy(puns_remaining, "pun", "puns").capitaliseFirstLetter() + " remaining."); + } else { + url = "place.php?whichplace=airport_spooky&action=airport2_radio"; + subentry.entries.listAppend("Return to the radio and reply."); + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Deep Dark Jungle]).ChecklistEntrySetIDTag("Airport spooky jungle_pun quest")); +} + +void QSpookyAirportFakeMediumGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__familiar happy medium"; + state.quest_name = "Fake Medium at Large"; + QuestStateParseMafiaQuestProperty(state, "questESpFakeMedium"); + + if (!state.in_progress) + return; + item collar = $item[ESP suppression collar]; + + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_spooky"; + + + if (state.mafia_internal_step == 1 && collar.available_amount() == 0) { + subentry.entries.listAppend("Adventure in The Secret Government Laboratory, find a non-combat every twenty turns."); + if (__misc_state["free runs available"]) + subentry.modifiers.listAppend("free runs"); + if (__misc_state["have hipster"]) + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + + string [int,int] solutions; + + solutions.listAppend(listMake("dust motes float", "star")); + solutions.listAppend(listMake("circle of light", "circle")); + solutions.listAppend(listMake("waves a fly away", "waves")); + solutions.listAppend(listMake("square one", "square")); + solutions.listAppend(listMake("expression only adds to your anxiety", "plus")); + + + subentry.entries.listAppend("The last line of the adventure text gives the solution:|*" + HTMLGenerateSimpleTableLines(solutions)); + + if ($item[Personal Ventilation Unit].equipped_amount() == 0 && $item[Personal Ventilation Unit].available_amount() > 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + $item[Personal Ventilation Unit].name + ".", "red")); + url = $item[Personal Ventilation Unit].invSearch(); + } + } else { + url = "place.php?whichplace=airport_spooky&action=airport2_radio"; + subentry.entries.listAppend("Return to the radio and reply."); + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Secret Government Laboratory]).ChecklistEntrySetIDTag("Airport spooky fake_medium quest")); +} + + +void QSpookyAirportClipperGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item military-grade fingernail clippers"; + state.quest_name = "The Big Clipper"; + QuestStateParseMafiaQuestProperty(state, "questESpClipper"); + + if (!state.in_progress) + return; + item clipper = $item[military-grade fingernail clippers]; + + if (clipper.available_amount() == 0) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_spooky"; + + + int fingernails_remaining = 23 - get_property_int("fingernailsClipped"); + if (state.mafia_internal_step == 1 && fingernails_remaining > 0) { + subentry.entries.listAppend("Adventure in The Mansion of Dr. Weirdeaux, use the military-grade fingernail clippers on the monsters three times per fight."); + + int turns_remaining = ceil(fingernails_remaining.to_float() / 3.0); + + subentry.entries.listAppend(fingernails_remaining + " fingernails / " + pluralise(turns_remaining, "turn", "turns") + " remaining."); + } else { + url = "place.php?whichplace=airport_spooky&action=airport2_radio"; + subentry.entries.listAppend("Return to the radio and reply."); + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Mansion of Dr. Weirdeaux]).ChecklistEntrySetIDTag("Airport spooky clipper quest")); +} + +void QSpookyAirportEveGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item vial of patchouli oil"; //science lab + state.quest_name = "Choking on the Rind"; + QuestStateParseMafiaQuestProperty(state, "questESpEVE"); + + if (!state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_spooky"; + + + if (state.mafia_internal_step < 2) { + subentry.entries.listAppend("Adventure in The Secret Government Laboratory, find a non-combat every twenty turns.|At the choice adventure, choose " + listMake("Left", "Left", "Right", "Left", "Right").listJoinComponents(__html_right_arrow_character) + "."); + if (__misc_state["free runs available"]) + subentry.modifiers.listAppend("free runs"); + if (__misc_state["have hipster"]) + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); + + if ($item[Personal Ventilation Unit].equipped_amount() == 0 && $item[Personal Ventilation Unit].available_amount() > 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + $item[Personal Ventilation Unit].name + ".", "red")); + url = $item[Personal Ventilation Unit].invSearch(); + } + } else { + url = "place.php?whichplace=airport_spooky&action=airport2_radio"; + subentry.entries.listAppend("Return to the radio and reply."); + } + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Secret Government Laboratory]).ChecklistEntrySetIDTag("Airport spooky EVE quest")); +} + + + +void QSpookyAirportSmokesGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item pack of smokes"; + state.quest_name = "Everyone's Running Out of Smokes"; + QuestStateParseMafiaQuestProperty(state, "questESpSmokes"); + + if (!state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_spooky"; + + item smokes = $item[pack of smokes]; + + if (state.mafia_internal_step < 2 && smokes.available_amount() < 10) { + subentry.entries.listAppend("Adventure in The Deep Dark Jungle and collect smokes from the smoke monster."); + subentry.modifiers.listAppend("olfact smoke monster"); + + if (smokes != $item[none]) { + subentry.entries.listAppend(pluraliseWordy(clampi(10 - smokes.available_amount(), 0, 10), "more pack of smokes", "more packs of smokes").capitaliseFirstLetter() + " remaining."); + } + } else { + url = "place.php?whichplace=airport_spooky&action=airport2_radio"; + subentry.entries.listAppend("Return to the radio and reply."); + } + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Deep Dark Jungle]).ChecklistEntrySetIDTag("Airport spooky smoke quest")); +} + + +void QSpookyAirportGoreGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item gore bucket"; + state.quest_name = "Gore Tipper"; + QuestStateParseMafiaQuestProperty(state, "questESpGore"); + + if (!state.in_progress) + return; + item bucket = $item[gore bucket]; + + if (bucket.available_amount() == 0) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_spooky"; + + + int gore_remaining = 100 - get_property_int("goreCollected"); + if (state.mafia_internal_step <= 2 && gore_remaining > 0) { + subentry.entries.listAppend("Adventure in The Secret Government Laboratory."); + subentry.modifiers.listAppend("+meat"); + string [int] items_to_equip; + if (bucket.equipped_amount() == 0) { + items_to_equip.listAppend("gore bucket"); + } + if ($item[Personal Ventilation Unit].equipped_amount() == 0 && $item[Personal Ventilation Unit].available_amount() > 0) { + items_to_equip.listAppend("Personal Ventilation Unit"); + } + if (items_to_equip.count() > 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + items_to_equip.listJoinComponents(", ", "and") + ".", "red")); + url = items_to_equip[0].invSearch(); + } + subentry.entries.listAppend(pluralise(gore_remaining, "pound", "pounds") + " remaining."); + } else { + url = "place.php?whichplace=airport_spooky&action=airport2_radio"; + subentry.entries.listAppend("Return to the radio and reply."); + } + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Secret Government Laboratory]).ChecklistEntrySetIDTag("Airport spooky gore quest")); +} + + +void QSpookyAirportOutOfOrderGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item GPS-tracking wristwatch"; + state.quest_name = "Out of Order"; + QuestStateParseMafiaQuestProperty(state, "questESpOutOfOrder"); + + if (!state.in_progress) + return; + item wristwatch = $item[GPS-tracking wristwatch]; + + if (wristwatch.available_amount() == 0) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_spooky"; + + + if (state.mafia_internal_step <= 2 && $item[Project T. L. B.].item_amount() == 0) { + subentry.modifiers.listAppend("+init"); + + if (wristwatch.equipped_amount() == 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + wristwatch.name + ".", "red")); + url = wristwatch.invSearch(); + } else + subentry.entries.listAppend("Adventure in The Deep Dark Jungle."); + } else { + url = "place.php?whichplace=airport_spooky&action=airport2_radio"; + subentry.entries.listAppend("Return to the radio and reply."); + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Deep Dark Jungle]).ChecklistEntrySetIDTag("Airport spooky out_of_order quest")); +} + + +void QSpookyAirportSerumGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item experimental serum P-00"; + state.quest_name = "Serum Sortie"; + QuestStateParseMafiaQuestProperty(state, "questESpSerum"); + + if (!state.in_progress) + return; + item serum = $item[experimental serum P-00]; + + if (serum == $item[none]) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_spooky"; + + + if (state.mafia_internal_step <= 2 && serum.item_amount() < 5) { + if (serum.available_amount() >= 5) { + subentry.entries.listAppend("Pull " + pluralise(5 - serum.item_amount(), serum) + "."); + } else { + subentry.modifiers.listAppend("+item"); + + subentry.entries.listAppend("Adventure in The Mansion of Dr. Weirdeaux, collect " + int_to_wordy(5 - serum.available_amount()) + " more " + serum.plural + "."); + } + } else { + url = "place.php?whichplace=airport_spooky&action=airport2_radio"; + subentry.entries.listAppend("Return to the radio and reply."); + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[The Mansion of Dr. Weirdeaux]).ChecklistEntrySetIDTag("Airport spooky serum quest")); +} + +void QSpookyAirportWeirdeauxGenerateTasks(ChecklistEntry [int] task_entries) +{ + if (__last_adventure_location != $location[The Mansion of Dr. Weirdeaux] || my_level() >= 256) + return; + if (in_ronin()) + return; + if (QuestState("questESpClipper").in_progress) + return; + + string url = "place.php?whichplace=airport_spooky"; + string [int] description; + string [int] modifiers; + if (!$skill[curse of marinara].have_skill()) { + if (my_class() == $class[sauceror]) { + description.listAppend("Buy curse of marinara from the guild trainer."); + url = "guild.php?place=trainer"; + } else if ($classes[disco bandit,disco bandit,seal clubber,turtle tamer,disco bandit,pastamancer,accordion thief,disco bandit] contains my_class()) { + description.listAppend("Ascend sauceror to buy curse of marinara."); + url = "ascend.php"; + } else + description.listAppend("Become a sauceror at the end of this ascension, to buy curse of marinara."); + } else { + if ($skill[utensil twist].have_skill() && $item[dinsey's pizza cutter].available_amount() > 0) { + string [int] tasks; + if ($item[dinsey's pizza cutter].equipped_amount() == 0) + tasks.listAppend("equip Dinsey's Pizza Cutter"); + tasks.listAppend("cast curse of marinara"); + tasks.listAppend("keep monster stunned"); + tasks.listAppend("cast utensil twist repeatedly in combat"); + + description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + } else { + if ($skill[utensil twist].have_skill()) { + description.listAppend("Possibly acquire Dinsey's pizza cutter by fighting Wart Dinsey as a Pastamancer."); + } else if ($item[dinsey's pizza cutter].available_amount() > 0) { + description.listAppend("Possibly acquire the pastamancer skill Utensil Twist."); + } else { + description.listAppend("Possibly acquire the pastamancer skill Utensil Twist and Dinsey's pizza cutter by fighting Wart Dinsey as a Pastamancer."); + } + //Drunkula's bell - 15% to 20% of your buffed myst as damage? + //right bear arm - Grizzly Scene, once/fight, 50% HP damage + //Staff of the Headmaster's Victuals - chefstaff (requires skill), jiggle does 30% of monster HP + //Great Wolf's lice - reduces monster attack/def by 30%. ??? + //great wolf's right paw, great wolf's left paw - gives Great Slash ability, which deals 1/3rd buffed muscle damage per paw equipped + description.listAppend("Cast curse of marinara at the start of combat, and keep monster stunned."); + string [item] other_relevant_items; + other_relevant_items[$item[drunkula's bell]] = "throw in combat to deal damage"; + other_relevant_items[$item[right bear arm]] = "grizzly scene deals 50% HP damage"; + if ($skill[Spirit of Rigatoni].skill_is_usable()) + other_relevant_items[$item[Staff of the Headmaster's Victuals]] = "jiggle for 30% HP damage"; + other_relevant_items[$item[Great Wolf's lice]] = "throw in combat to deal damage"; + other_relevant_items[$item[great wolf's left paw]] = "great slash skill deals damage"; + other_relevant_items[$item[great wolf's right paw]] = "great slash skill deals damage"; + + string [int] possibilities; + foreach it, desc in other_relevant_items { + if (it.available_amount() == 0) + continue; + string line = it.capitaliseFirstLetter() + " - " + desc + "."; + if (it.to_slot() != $slot[none] && it.equipped_amount() == 0) + line += " (equip)"; + possibilities.listAppend(line); + } + if (possibilities.count() > 0) + description.listAppend("Try:|*" + possibilities.listJoinComponents("|*").capitaliseFirstLetter()); + } + + modifiers.listAppend("+spooky resistance"); + + string [int] blocking_sources; + if (!__misc_state["familiars temporarily blocked"]) + blocking_sources.listAppend("a potato familiar"); + foreach it in $items[Drunkula's ring of haze,Mesmereyes™ contact lenses,attorney's badge,ancient stone head,navel ring of navel gazing] { + if (it.available_amount() == 0) + continue; + if (it.equipped_amount() > 0) + continue; + string line = it; + if (it.equipped_amount() == 0) + line += " (equip)"; + blocking_sources.listAppend(line); + } + if (my_class() == $class[pastamancer]) + blocking_sources.listAppend("spaghetti elemental thrall"); + if (blocking_sources.count() > 0) + description.listAppend("Use sources of blocking, like " + blocking_sources.listJoinComponents(", ", "and") + "."); + } + + //description.listAppend("Or use " + pluralise(clampi(256 - my_level(), 0, 256), "ultimate wad", "ultimate wads") + "."); //reasonable + + task_entries.listAppend(ChecklistEntryMake("__effect Incredibly Hulking", url, ChecklistSubentryMake("Gain " + pluralise(clampi(256 - my_level(), 0, 256), "level", "levels"), modifiers, description), $locations[The Mansion of Dr. Weirdeaux]).ChecklistEntrySetIDTag("Airport spooky weirdeaux")); +} + +void QSpookyAirportGenerateTasks(ChecklistEntry [int] task_entries) +{ + if (!__misc_state["spooky airport available"]) + return; + //if (__misc_state["in run"] && !($locations[the mansion of dr. weirdeaux,the secret government laboratory,the deep dark jungle] contains __last_adventure_location)) //a common strategy is to accept an island quest in-run, then finish it upon prism break to do two quests in a day. so, don't clutter their interface unless they're adventuring there? hmm... + //return; + + QSpookyAirportClipperGenerateTasks(task_entries); + QSpookyAirportEVEGenerateTasks(task_entries); + QSpookyAirportSmokesGenerateTasks(task_entries); + QSpookyAirportSerumGenerateTasks(task_entries); + QSpookyAirportOutOfOrderGenerateTasks(task_entries); + QSpookyAirportFakeMediumGenerateTasks(task_entries); + QSpookyAirportGoreGenerateTasks(task_entries); + QSpookyAirportJunglePunGenerateTasks(task_entries); + QSpookyAirportWeirdeauxGenerateTasks(task_entries); +} + +// + +void QStenchAirportFishTrashGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item trash net"; + state.quest_name = "Teach a Man to Fish Trash"; + QuestStateParseMafiaQuestProperty(state, "questEStFishTrash"); + + if (!state.in_progress) + return; + item trash_net = $item[trash net]; + + if (trash_net.available_amount() == 0) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_stench"; + + + if (state.mafia_internal_step <= 2) { + if (trash_net.equipped_amount() == 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + trash_net + ".", "red")); + url = trash_net.invSearch(); + } else { + int turns_remaining = clampi(get_property_int("dinseyFilthLevel") / 5, 0, 20); + subentry.entries.listAppend("Adventure in Pirates of the Garbage Barges for " + pluraliseWordy(turns_remaining, "more turn", "more turns") + "."); + } + } else { + subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); + state.image_name = "stench airport kiosk"; + url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[pirates of the garbage barges]).ChecklistEntrySetIDTag("Airport stench fish_trash quest")); +} + +void QStenchAirportNastyBearsGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item black picnic basket"; + state.quest_name = "Nasty, Nasty Bears"; + QuestStateParseMafiaQuestProperty(state, "questEStNastyBears"); + + if (!state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_stench"; + + + int bears_left = 8 - get_property_int("dinseyNastyBearsDefeated"); + if (state.mafia_internal_step < 3 && bears_left > 0) { + subentry.entries.listAppend("Adventure in Uncle Gator's Country Fun-Time Liquid Waste Sluice, defeat " + pluraliseWordy(bears_left, "more nasty bear", "more nasty bears") + "."); + + if (__misc_state["have olfaction equivalent"]) + subentry.modifiers.listAppend("olfact nasty bears?"); + } else { + subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); + state.image_name = "stench airport kiosk"; + url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[Uncle Gator's Country Fun-Time Liquid Waste Sluice]).ChecklistEntrySetIDTag("Airport stench nasty_bears quest")); +} + +void QStenchAirportSocialJusticeIGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item ms. accessory"; + state.quest_name = "Social Justice Adventurer I"; + QuestStateParseMafiaQuestProperty(state, "questEStSocialJusticeI"); + + if (!state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_stench"; + + + int adventures_left = 15 - get_property_int("dinseySocialJusticeIProgress"); + if (state.mafia_internal_step < 2 && adventures_left > 0) { + subentry.entries.listAppend("Adventure in Pirates of the Garbage Barges " + pluraliseWordy(adventures_left, "more time", "more times") + "."); + } else { + subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); + state.image_name = "stench airport kiosk"; + url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[Pirates of the Garbage Barges]).ChecklistEntrySetIDTag("Airport stench social_justice_1 quest")); +} + +void QStenchAirportSocialJusticeIIGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__monster black knight"; + state.quest_name = "Social Justice Adventurer II"; + QuestStateParseMafiaQuestProperty(state, "questEStSocialJusticeII"); + + if (!state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_stench"; + + + if (state.mafia_internal_step < 2) { + int adventures_left = clampi(15 - get_property_int("dinseySocialJusticeIIProgress"), 0, 15); + subentry.entries.listAppend("Adventure in Uncle Gator's Country Fun-Time Liquid Waste Sluice " + pluraliseWordy(adventures_left, "more time", "more times") + "."); + } else { + subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); + state.image_name = "stench airport kiosk"; + url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[Uncle Gator's Country Fun-Time Liquid Waste Sluice]).ChecklistEntrySetIDTag("Airport stench social_justice_2 quest")); +} + +void QStenchAirportSuperLuberGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item lube-shoes"; + state.quest_name = "Super Luber"; + QuestStateParseMafiaQuestProperty(state, "questEStSuperLuber"); + + if (!state.in_progress) + return; + item quest_item = $item[lube-shoes]; + + if (quest_item.available_amount() == 0) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_stench"; + + + if (state.mafia_internal_step <= 2) { + if (quest_item.equipped_amount() == 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + quest_item.name + ".", "red")); + url = quest_item.invSearch(); + } else { + subentry.entries.listAppend("Adventure in Barf Mountain, return to the kiosk after riding the rollercoaster."); + subentry.modifiers.listAppend("optional +meat"); + if ($effect[How to Scam Tourists].have_effect() == 0 && $item[How to Avoid Scams].available_amount() > 0) + subentry.entries.listAppend("Use How to Avoid Scams to farm extra meat, if you want."); + + } + } else { + subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); + state.image_name = "stench airport kiosk"; + url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[barf mountain]).ChecklistEntrySetIDTag("Airport stench super_luber quest")); +} + +void QStenchAirportZippityDooDahGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item tea for one"; + state.quest_name = "Whistling Zippity-Doo-Dah"; + QuestStateParseMafiaQuestProperty(state, "questEStZippityDooDah"); + + if (!state.in_progress) + return; + item quest_item = $item[Dinsey mascot mask]; + + if (quest_item.available_amount() == 0) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_stench"; + + int turns_remaining = clampi(15 - get_property_int("dinseyFunProgress"), 0, 15); + + if (state.mafia_internal_step <= 2) { + if (quest_item.equipped_amount() == 0) { + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip the " + quest_item.name + ".", "red")); + url = quest_item.invSearch(); + } else { + subentry.entries.listAppend("Adventure in the Toxic Teacups for " + pluraliseWordy(turns_remaining, "more turn", "more turns") + "."); + } + } else { + subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); + state.image_name = "stench airport kiosk"; + url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[the toxic teacups]).ChecklistEntrySetIDTag("Airport stench zippity quest")); +} + +void QStenchAirportWillWorkForFoodGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item complimentary Dinsey refreshments"; + state.quest_name = "Will Work With Food"; + QuestStateParseMafiaQuestProperty(state, "questEStWorkWithFood"); + + if (!state.in_progress) + return; + + item quest_item = $item[complimentary Dinsey refreshments]; + + if (quest_item.available_amount() == 0) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_stench"; + + int tourists_to_feed = clampi(30 - get_property_int("dinseyTouristsFed"), 0, 30); + if (state.mafia_internal_step == 1) { + subentry.entries.listAppend("Adventure in Barf Mountain, use complimentary Dinsey refreshments on garbage/angry tourists."); + subentry.entries.listAppend(pluraliseWordy(tourists_to_feed, "more remains", "more remain").capitaliseFirstLetter() + "."); + subentry.modifiers.listAppend("olfact angry/garbage tourists"); + + } else { + subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); + state.image_name = "stench airport kiosk"; + url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[barf mountain]).ChecklistEntrySetIDTag("Airport stench refreshments quest")); +} + +void QStenchAirportGiveMeFuelGenerateTasks(ChecklistEntry [int] task_entries) +{ + QuestState state; + state.image_name = "__item toxic globule"; + state.quest_name = "Give me fuel"; + QuestStateParseMafiaQuestProperty(state, "questEStGiveMeFuel"); + + if (!state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = state.quest_name; + string url = "place.php?whichplace=airport_stench"; + + if ($item[toxic globule].available_amount() < 20) { + int globules_needed = clampi(20 - $item[toxic globule].available_amount(), 0, 20); + if (!in_ronin()) { + subentry.entries.listAppend("Buy " + pluralise(globules_needed, "more toxic globule", "more toxic globules") + " in the mall."); + url = "mall.php"; + } else { + subentry.modifiers.listAppend("+unknown"); + subentry.entries.listAppend("Adventure in the Toxic Teacups and collect " + pluralise(globules_needed, "more toxic globule", "more toxic globules") + "."); + } + } else { + if ($item[toxic globule].item_amount() < 20) { + int globules_needed = clampi(20 - $item[toxic globule].item_amount(), 0, 20); + subentry.entries.listAppend("Pull " + pluralise(globules_needed, "more toxic globule", "more toxic globules") + "."); + } else { + subentry.entries.listAppend("Collect wages from the employee assignment kiosk."); + state.image_name = "stench airport kiosk"; + url = "place.php?whichplace=airport_stench&action=airport3_kiosk"; + } + } + + task_entries.listAppend(ChecklistEntryMake(state.image_name, url, subentry, $locations[the toxic teacups]).ChecklistEntrySetIDTag("Airport stench fuel quest")); +} + +void QStenchAirportGarbageGenerateTasks(ChecklistEntry [int] task_entries) +{ + if (get_property_boolean("_dinseyGarbageDisposed")) + return; + ChecklistSubentry subentry; + subentry.header = "Turn in garbage"; + subentry.entries.listAppend("Maintenance Tunnels Access" + __html_right_arrow_character + "Waste Disposal."); + if ($item[bag of park garbage].item_amount() == 0) { + if ($item[bag of park garbage].available_amount() > 0) + subentry.entries.listAppend("Have one, somewhere..."); + else { + string line = "Fight barf mountain Garbage tourists"; + if (!in_ronin()) + line += " or buy from mall"; + subentry.entries.listAppend(line + "."); + } + } + task_entries.listAppend(ChecklistEntryMake("__item bag of park garbage", "place.php?whichplace=airport_stench&action=airport3_tunnels", subentry).ChecklistEntrySetIDTag("Airport stench garbage")); +} + +void QStenchAirportWartDinseyGenerateTasks(ChecklistEntry [int] task_entries) +{ + if (get_property_ascension("lastWartDinseyDefeated")) + return; + + item dinsey_item; + if (my_class() == $class[seal clubber]) + dinsey_item = $item[Dinsey's oculus]; + else if (my_class() == $class[turtle tamer]) + dinsey_item = $item[Dinsey's radar dish]; + else if (my_class() == $class[pastamancer]) + dinsey_item = $item[Dinsey's pizza cutter]; + else if (my_class() == $class[sauceror]) + dinsey_item = $item[Dinsey's brain]; + else if (my_class() == $class[disco bandit]) + dinsey_item = $item[Dinsey's pants]; + else if (my_class() == $class[accordion thief]) + dinsey_item = $item[Dinsey's glove]; + if (!($classes[seal clubber,turtle tamer,pastamancer,sauceror,disco bandit,accordion thief] contains my_class())) //class-specific items only drop when you're class-specific + return; + + if (last_monster() != $monster[Wart Dinsey]) { + if (dinsey_item == $item[none] || haveAtLeastXOfItemEverywhere(dinsey_item, 1)) + return; + } + boolean [item] keycards = $items[keycard α,keycard β,keycard γ,keycard δ]; + + item [int] missing_keycards; + foreach it in keycards { + if (it.available_amount() == 0) { + missing_keycards.listAppend(it); + } + } + if (missing_keycards.count() > 0) + return; + + + string url = "place.php?whichplace=airport_stench&action=airport3_tunnels"; + string [int] description; + string [int] modifiers; + modifiers.listAppend("+" + MAX(250, $monster[Wart Dinsey].base_initiative) + "% init"); + modifiers.listAppend("+lots all resistance"); + + item mercenary_pistol = $item[mercenary pistol]; + description.listAppend("Run +resistance, deal many sources of non-stench damage to him. (100 damage cap)"); + if (mercenary_pistol.available_amount() > 0) { + string [int] tasks; + if (mercenary_pistol.equipped_amount() == 0) + tasks.listAppend("equip a mercenary pistol"); + item clip = $item[special clip: boneburners]; + if (clip.item_amount() == 0 && $item[special clip: splatterers].item_amount() > 0) + clip = $item[special clip: splatterers]; + if (clip.item_amount() == 0) { + tasks.listAppend("acquire a few clips of " + clip); + } + tasks.listAppend("throw " + clip + " in combat"); + + description.listAppend(tasks.listJoinComponents(", ").capitaliseFirstLetter() + "."); + } else { + description.listAppend("The mercenary pistol is useful for this, if you can acquire one."); + } + description.listAppend("Will acquire a " + dinsey_item + "."); + + task_entries.listAppend(ChecklistEntryMake("__item " + dinsey_item, url, ChecklistSubentryMake("Defeat Wart Dinsey", modifiers, description)).ChecklistEntrySetIDTag("Airport stench Wart_Dinsey")); +} + +void QStenchAirportGenerateTasks(ChecklistEntry [int] task_entries) +{ + if (!__misc_state["stench airport available"]) + return; + //if (__misc_state["in run"] && !($locations[Pirates of the Garbage Barges,Barf Mountain,The Toxic Teacups,Uncle Gator's Country Fun-Time Liquid Waste Sluice] contains __last_adventure_location)) + //return; + QStenchAirportFishTrashGenerateTasks(task_entries); + QStenchAirportNastyBearsGenerateTasks(task_entries); + QStenchAirportSocialJusticeIGenerateTasks(task_entries); + QStenchAirportSocialJusticeIIGenerateTasks(task_entries); + QStenchAirportSuperLuberGenerateTasks(task_entries); + QStenchAirportZippityDooDahGenerateTasks(task_entries); + QStenchAirportGarbageGenerateTasks(task_entries); + QStenchAirportGiveMeFuelGenerateTasks(task_entries); + QStenchAirportWillWorkForFoodGenerateTasks(task_entries); + QStenchAirportWartDinseyGenerateTasks(task_entries); +} + +// + +void QHotAirportLavaCoLampGenerateTasks(ChecklistEntry [int] task_entries) +{ + if (in_ronin()) + return; + + if (__last_adventure_location != $location[LavaCo™ Lamp Factory]) //dave's not here, man + return; + + item [int] missing_lamps = $items[Red LavaCo Lamp™,Green LavaCo Lamp™,Blue LavaCo Lamp™].items_missing(); + + if (missing_lamps.count() == 0) + return; + + string url = "place.php?whichplace=airport_hot"; + string [int] modifiers; + string [int] description; + + + description.listAppend("+5 adventures/+sleepstatgain offhand, useful in ascension."); + + //One at a time: + + item targeting_lamp = missing_lamps[0]; + string [int] colours_missing; + foreach key, it in missing_lamps + colours_missing.listAppend(it.to_string().replace_string(" LavaCo Lamp™", "")); + + string colour = colours_missing[0]; + + item capped_item = to_item("capped " + colour + " lava bottle"); + item uncapped_item = to_item("uncapped " + colour + " lava bottle"); + item lava_glob_item = to_item(colour + " lava globs"); + + + if (capped_item.available_amount() == 0) { + boolean have_all_items = true; + if ($item[SMOOCH bottlecap].available_amount() == 0) { + have_all_items = false; + string line; + line = "Acquire a SMOOCH bottlecap by eating SMOOCH soda"; + if (availableFullness() == 0) + line += " later"; + line += "."; + + description.listAppend(line); + } + //uncapped red lava bottle + if (uncapped_item.available_amount() == 0) { + have_all_items = false; + string [int] subdescription; + if (lava_glob_item.available_amount() == 0) { + subdescription.listAppend("Acquire " + lava_glob_item + " in LavaCo NC: Use the glob dyer" + __html_right_arrow_character + "Dye them " + colour + "."); + } + if ($item[full lava bottle].available_amount() > 0) { + if (lava_glob_item.available_amount() > 0) { + subdescription.listAppend("Use " + lava_glob_item + "."); + url = lava_glob_item.invSearch(); + } + } else { + if ($item[empty lava bottle].item_amount() > 0) { + subdescription.listAppend("Adventure in the LavaCo™ Lamp Factory, use the squirter."); + } else if ($item[empty lava bottle].available_amount() > 0) { + subdescription.listAppend("Acquire an empty lava bottle. (From hagnk's?)"); + } else { + if ($item[New Age healing crystal].item_amount() > 0) { + subdescription.listAppend("Adventure in the LavaCo™ Lamp Factory, use the klin."); + } else + subdescription.listAppend("Acquire New Age healing crystal from the mall or the mine."); + } + } + + description.listAppend("Acquire an " + uncapped_item + ".|*" + subdescription.listJoinComponents("|*")); + } + if (have_all_items) { //capped_item.creatable_amount() > 0) //BUG: capped_item.creatable_amount() > 0 when only having cap + description.listAppend("Make " + capped_item + " (" + uncapped_item + " + SMOOCH bottlecap)"); + url = "craft.php?mode=combine"; + } + } else if ($item[LavaCo™ Lamp housing].available_amount() > 0) { + description.listAppend("Combine " + capped_item + " and LavaCo™ Lamp housing."); + url = "craft.php?mode=combine"; + } + + if ($item[LavaCo™ Lamp housing].available_amount() == 0) { + boolean have_all_items = true; + if ($item[crystalline light bulb].item_amount() == 0) { + have_all_items = false; + + if ($item[glowing New Age crystal].item_amount() > 0) { + description.listAppend("Adventure in the LavaCo™ Lamp Factory, use the bulber."); + } else { + description.listAppend("Acquire glowing New Age crystal. (mall, or healing crystal golem in the mine))"); + } + } + if ($item[heat-resistant sheet metal].item_amount() == 0) { + have_all_items = false; + description.listAppend("Buy heat-resistant sheet metal from the mall."); + } + if ($item[insulated gold wire].item_amount() == 0) { + have_all_items = false; + + + if ($item[insulated gold wire].available_amount() > 0) { + description.listAppend("Acquire insulated gold wire. (in hagnk's?)"); + } else if ($item[insulated gold wire].creatable_amount() > 0) { + description.listAppend("Make insulated gold wire. (thin gold wire + unsmoothed velvet"); + url = "craft.php?mode=combine"; + } else { + if ($item[thin gold wire].available_amount() == 0) { + if ($item[1\,970 carat gold].item_amount() == 0) { + description.listAppend("Acquire 1,970 carat gold by mining in the mine."); + } else { + description.listAppend("Adventure in the LavaCo™ Lamp Factory, use the wire puller."); + } + } + if ($item[unsmoothed velvet].available_amount() == 0) + description.listAppend("Buy unsmoothed velvet in the mall."); + } + } + + if (have_all_items) { + description.listAppend("At the LavaCo™ NC, use the chassis assembler."); + } + } + + + task_entries.listAppend(ChecklistEntryMake("__item " + missing_lamps[0], url, ChecklistSubentryMake("Make a " + colours_missing.listJoinComponents(", ", "and") + " LavaCo Lamp™", modifiers, description), $locations[LavaCo™ Lamp Factory]).ChecklistEntrySetIDTag("Airport hot lavaco_lamp")); +} + +void QHotAirportSuperduperheatedMetalGenerateTasks(ChecklistEntry [int] task_entries) +{ + int metal_sheets = lookupItem("Heat-resistant sheet metal").item_amount(); + string image; + string header; + string [int] description; + + if (!get_property_boolean("_volcanoSuperduperheatedMetal") && (__last_adventure_location == $location[The Bubblin\' Caldera] || !__misc_state["in run"])) { + image = "__item superduperheated metal"; + header = "Get superduperheated metal"; + if (metal_sheets > 0) + description.listAppend("Adventure in the Bubblin' Caldera. ~1/20 chance of superduperheated metal."); + else + description.listAppend("Get some (scraps of) heat-resistant sheet metal in your inventory."); + } else if (__last_adventure_location == $location[The Bubblin\' Caldera] && metal_sheets > 0) { + image = "__item superheated metal"; + header = "Don't waste more Heat-resistant sheet metal"; + description.listAppend("Already got Superduperheated metal today. Closet your Heat-resistant sheet metal (unless you want Superheated metal for the SMOOCH uniform)."); + } + + if (description.count() > 0) + task_entries.listAppend(ChecklistEntryMake(image, "place.php?whichplace=airport_hot", ChecklistSubentryMake(header, "", description), $locations[The Bubblin\' Caldera]).ChecklistEntrySetIDTag("Airport hot superduperheated")); +} + +void QHotAirportWLFBunkerGenerateTasks(ChecklistEntry [int] task_entries) +{ + if (get_property_boolean("_volcanoItemRedeemed")) + return; + + /* + _volcanoItem1, _volcanoItem2, _volcanoItem3 + _volcanoItemCount1, _volcanoItemCount2, _volcanoItemCount3 + */ + int [int] volcano_item_id; + int [int] volcano_item_count; + for i from 1 to 3 { + volcano_item_id [i] = get_property_int("_volcanoItem" + i); // volcano_item_id [1st / 2nd / 3rd] => item ID + volcano_item_count [volcano_item_id [i]] = get_property_int("_volcanoItemCount" + i); // volcano_item_count [item ID] => amount asked + } + string url = "place.php?whichplace=airport_hot"; + string subtitle; + string [int] description; + boolean [location] relevant_locations; + + if (volcano_item_id [1] == 0 && volcano_item_id [2] == 0 && volcano_item_id [3] == 0) { + url = "place.php?whichplace=airport_hot&action=airport4_questhub"; + description.listAppend("Visit the W.L.F. bunker to learn today's accepted items."); + } else { + boolean [item] volcano_item; // rearranged in a format that is compatible with "contains" (also going from ID to $item) + foreach i in volcano_item_id { + if (volcano_item_id [i] == 0) { + description.listAppend("Mafia's parsing of item " + i + " went wrong."); + remove volcano_item_id [i]; + } else + volcano_item [lookupItem(volcano_item_id [i])] = true; + } + + /* + The Bubblin' Caldera + 8517 => SMOOCH bracers + 8522 => superduperheated metal + 8504 => Lavalos core + 8496 => The One Mood Ring + The Velvet / Gold Mine + 8516 => smooth velvet bra + 8425 => New Age healing crystal + 8505 => half-melted hula girl + 8497 => Mr. Choch's bone + LavaCo™ Lamp Factory + 8470 => gooey lava globs + 8523 => fused fuse + 8498 => Mr. Cheeng's 'stache + 8506 => glass ceiling fragments + The SMOOCH Army HQ + 8446 => SMOOCH bottlecap + 8500 => the tongue of Smimmons + 8501 => Raul's guitar pick + 8502 => Pener's crisps + 8503 => signed deuce + Discotheque + 8499 => Saturday Night thermometer*/ + + void WLFBunkerTasks(string [int] map, item it, int amount_normally_asked, string acquisition_text) { + if (!(volcano_item contains it)) + return; + + boolean this_isnt_right = volcano_item_count [it.to_int()] != amount_normally_asked; + + string text; + if (volcano_item_count [it.to_int()] > 1) //"5 (wait that's not right...) the tongues of Smimmons", "3 smooth velvet bras" + text += volcano_item_count [it.to_int()] + (this_isnt_right ? " (wait, that's not right...) " : " ") + it.plural; + else //"Raul's guitar pick", "New Age healing crystal x1 (wait that's not right...)" + text += it.name.capitaliseFirstLetter() + (this_isnt_right ? " x1 (wait, that's not right...)" : ""); + + text += " (have " + it.item_amount() + ")."; + text += "|*" + acquisition_text; + map.listAppend(text); + + remove volcano_item [it]; + } + + string GenerateCommonZoneSpecificNCText(location l) { + return HTMLGenerateSpanOfClass("Win", "r_bold") + " 50 fights in " + l + " on the " + HTMLGenerateSpanOfClass("same day", "r_bold") + " to get the zone's 1/day NC."; + } + + if (true) { + string [int] caldera; + string nc_text = GenerateCommonZoneSpecificNCText($location[The Bubblin' Caldera]); + + caldera.WLFBunkerTasks($item[SMOOCH bracers], 3, "Multi-use 5 ingots of superheated metal (from adventuring in the caldera with heat-resistant sheet metal (from SMOOCH or mall) in inventory, or buy from mall) (each)."); + caldera.WLFBunkerTasks($item[superduperheated metal], 1, get_property_boolean("_volcanoSuperduperheatedMetal") ? "Buy from mall." : "Look at the tile above this one (or buy from mall)."); + caldera.WLFBunkerTasks($item[Lavalos core], 1, nc_text + " Head for the roaring (fight)."); + caldera.WLFBunkerTasks($item[The One Mood Ring], 1, nc_text + " Head for the singing."); + + if (caldera.count() > 0) { + relevant_locations [$location[The Bubblin' Caldera]] = true; + description.listAppend("In " + $location[The Bubblin' Caldera] + ":" + caldera.listJoinComponents("|").HTMLGenerateIndentedText()); + } + } + if (true) { + string [int] VGmine; + string nc_text = GenerateCommonZoneSpecificNCText($location[The Velvet / Gold Mine]); + + VGmine.WLFBunkerTasks($item[smooth velvet bra], 3, "Multi-use 3 pieces of unsmooth velvet (from mining) (each) (or buy from mall)."); + VGmine.WLFBunkerTasks($item[New Age healing crystal], 5, "Fight healing crystal golems or mine (or buy from mall)."); + VGmine.WLFBunkerTasks($item[half-melted hula girl], 1, nc_text + " Check out HR."); + VGmine.WLFBunkerTasks($item[Mr. Choch's bone], 1, nc_text + " Head to the boss's shack (fight)."); + + if (VGmine.count() > 0) { + relevant_locations [$location[The Velvet / Gold Mine]] = true; + description.listAppend("In " + $location[The Velvet / Gold Mine] + ":" + VGmine.listJoinComponents("|").HTMLGenerateIndentedText()); + } + } + if (true) { + string [int] lavaco; + string nc_text = GenerateCommonZoneSpecificNCText($location[LavaCo™ Lamp Factory]); + + lavaco.WLFBunkerTasks($item[gooey lava globs], 5, "Fight lava golems (or buy from mall)."); + lavaco.WLFBunkerTasks($item[fused fuse], 1, "Sabotage the machine at the NC that happens every 10 turns."); + lavaco.WLFBunkerTasks($item[Mr. Cheeng's 'stache], 1, nc_text + " Go into the boss's office (fight)."); + lavaco.WLFBunkerTasks($item[glass ceiling fragments], 1, nc_text + " Go up the stairs."); + + if (lavaco.count() > 0) { + relevant_locations [$location[LavaCo™ Lamp Factory]] = true; + description.listAppend("In " + $location[LavaCo™ Lamp Factory] + ":" + lavaco.listJoinComponents("|").HTMLGenerateIndentedText()); + } + } + if (true) { + string [int] SMOOCH; + string nc_text = GenerateCommonZoneSpecificNCText($location[The SMOOCH Army HQ]) + " Open door #"; + + SMOOCH.WLFBunkerTasks($item[SMOOCH bottlecap], 1, 'Eat ("drink") a SMOOCH soda (or buy from mall).'); + SMOOCH.WLFBunkerTasks($item[the tongue of Smimmons], 1, nc_text + "1."); + SMOOCH.WLFBunkerTasks($item[Raul's guitar pick], 1, nc_text + "2."); + SMOOCH.WLFBunkerTasks($item[Pener's crisps], 1, nc_text + "3."); + SMOOCH.WLFBunkerTasks($item[signed deuce], 1, nc_text + "4."); + + if (SMOOCH.count() > 0) { + relevant_locations [$location[The SMOOCH Army HQ]] = true; + description.listAppend("In " + $location[The SMOOCH Army HQ] + ":" + SMOOCH.listJoinComponents("|").HTMLGenerateIndentedText()); + } + } + description.WLFBunkerTasks($item[Saturday Night thermometer], 1, get_property_boolean("_infernoDiscoVisited") ? "Elevator's already been used today :(" : "Rock a disco style of 3, go to the discotheque's elevator, go to the third floor."); + + if (volcano_item.count() > 0) + description.listAppend(pluralise(volcano_item.count(), "of the items was", "of the items were") + " unregistered."); + if (volcano_item_id.count() - volcano_item.count() > 1) //if - > 1... + subtitle = "One of:"; + } + + task_entries.listAppend(ChecklistEntryMake("__item volcoino", url, ChecklistSubentryMake("Help smash the system!", subtitle, description), relevant_locations).ChecklistEntrySetIDTag("Airport hot WLF quest")); +} + +void QHotAirportGenerateTasks(ChecklistEntry [int] task_entries) +{ + if (!__misc_state["hot airport available"]) + return; + + QHotAirportLavaCoLampGenerateTasks(task_entries); + QHotAirportSuperduperheatedMetalGenerateTasks(task_entries); + QHotAirportWLFBunkerGenerateTasks(task_entries); + + if ($item[lucky gold ring].available_amount() > 0 && !get_property_boolean("_luckyGoldRingVolcoino")) { + string url; + string title = "Adventure with "; + if ($item[lucky gold ring].equipped_amount() == 0) { + title = "Equip "; + url = $item[lucky gold ring].invSearch(); + } + task_entries.listAppend(ChecklistEntryMake("__item lucky gold ring", url, ChecklistSubentryMake(title + " your Lucky Gold Ring", "~1% volcoino/combat", "Can give 1 volcoino per day.")).ChecklistEntrySetIDTag("Airport hot lucky_gold_ring")); + } +} + +void QHotAirportGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["hot airport available"]) + return; + //Elevator: + if (!get_property_boolean("_infernoDiscoVisited")) { + int potential_disco_style_level = 0; + int current_disco_style_level = 0; + item [int] items_to_equip_for_additional_style; + foreach it in $items[smooth velvet pocket square,smooth velvet socks,smooth velvet hat,smooth velvet shirt,smooth velvet hanky,smooth velvet pants] { + if (it.equipped_amount() > 0) + current_disco_style_level += 1; + else if (it.available_amount() > 0) + potential_disco_style_level += 1; + } + potential_disco_style_level += current_disco_style_level; + + string [int] description; + string url = "place.php?whichplace=airport_hot&action=airport4_zone1"; + if (current_disco_style_level == 0) + url = "inventory.php?ftext=smooth+velvet"; + /* + Requires... disco style? (velvet gear) + Floor 1: Gain 100 points in each stat! + Floor 2: Get a temporary boost to Item Drops! + Floor 3: Fight Travoltron! + Floor 4: Reduce your Drunkenness by 1 + Floor 5: Go backwards in time by 5 Adventures! + Floor 6: Get a Volcoino! + */ + Record DiscoFloor + { + int floor_number; + string description; + boolean grey_out; + }; + DiscoFloor DiscoFloorMake(int floor_number, string description, boolean grey_out) + { + DiscoFloor floor; + floor.floor_number = floor_number; + floor.description = description; + floor.grey_out = grey_out; + return floor; + } + DiscoFloor DiscoFloorMake(int floor_number, string description) + { + return DiscoFloorMake(floor_number, description, false); + } + void listAppend(DiscoFloor [int] list, DiscoFloor entry) + { + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; + } + + DiscoFloor [int] floors; + if (__misc_state["need to level"]) + floors.listAppend(DiscoFloorMake(1, "+100 all substats.")); + + floors.listAppend(DiscoFloorMake(2, "+100% item for 20 turns.")); + floors.listAppend(DiscoFloorMake(3, "Fight Travoltron.")); + if (inebriety_limit() > 0) { + if (my_inebriety() == 0) + floors.listAppend(DiscoFloorMake(4, "-1 drunkenness. (drink first)", true)); + else + floors.listAppend(DiscoFloorMake(4, "-1 drunkenness.")); + } + if (my_path().id != PATH_SLOW_AND_STEADY) + floors.listAppend(DiscoFloorMake(5, "+5 adventures, extend effects.")); + floors.listAppend(DiscoFloorMake(6, "Gain a volcoino.")); + + foreach key, floor in floors { + if (floor.floor_number > potential_disco_style_level) + continue; + + string line = "Floor " + floor.floor_number + ": " + floor.description; + if (floor.floor_number > current_disco_style_level || floor.grey_out) { + if (floor.floor_number > current_disco_style_level) + line += " (wear smooth velvet)"; + line = HTMLGenerateSpanFont(line, "grey"); + } + description.listAppend(line); + } + + if (items_to_equip_for_additional_style.count() > 0 && potential_disco_style_level > current_disco_style_level) + description.listAppend("Can equip " + items_to_equip_for_additional_style.listJoinComponents(", ", "and") + " for more style."); + + //fancy tophat, insane tophat, brown felt tophat, isotophat, tiny top hat and cane + if (potential_disco_style_level > 0) + resource_entries.listAppend(ChecklistEntryMake("__item disco ball", url, ChecklistSubentryMake("One elevator ride", "", description), 5).ChecklistEntrySetIDTag("Airport hot disco_elevator resource")); + } +} + +void QColdAirportGenerateTasks(ChecklistEntry [int] task_entries) +{ + if (!__misc_state["cold airport available"]) + return; + string desired_walford_item = get_property("walfordBucketItem").to_lower_case(); + if ($item[Walford's bucket].available_amount() > 0 && QuestState("questECoBucket").in_progress && desired_walford_item != "") { //need quest tracking as well, you keep the bucket. FIXME should we be testing against desired_walford_item? + string title = ""; + string [int] modifiers; + string [int] description; + string url = $location[The Ice Hotel].getClickableURLForLocation(); + int progress = get_property_int("walfordBucketProgress"); + if (progress >= 100) { + url = "place.php?whichplace=airport_cold&action=glac_walrus"; + title = "Talk to Walford"; + description.listAppend("Turn in the quest."); + } else { + title = "Walford's quest"; + + modifiers.listAppend("-combat"); + string [int] options; + + options.listAppend("The Ice Hole" + ($effect[fishy].have_effect() == 0 ? " with fishy" : "") + ". (5% per turn)"); + + string [int] tasks; + string hotel_string = "The Ice Hotel."; + boolean nc_helps_in_hotel = true; + if (desired_walford_item == "milk" || desired_walford_item == "rain") + nc_helps_in_hotel = false; + if (nc_helps_in_hotel) { + if ($item[bellhop's hat].equipped_amount() == 0 && desired_walford_item != "moonbeams") + tasks.listAppend("equip bellhop's hat"); + tasks.listAppend("run -combat"); + } + if (desired_walford_item == "moonbeams" && $slot[hat].equipped_item() != $item[none]) { + tasks.listAppend("unequip your hat"); + } + if (desired_walford_item == "blood") + tasks.listAppend("use tin snips every fight"); + if (desired_walford_item == "chicken" && numeric_modifier("food drop") < 50.0) { + modifiers.listAppend("+50% food drop"); + tasks.listAppend("run +50% food drop"); + } + if (desired_walford_item == "milk" && numeric_modifier("booze drop") < 50.0) { + modifiers.listAppend("+50% booze drop"); + tasks.listAppend("run +50% booze drop"); + } + if (desired_walford_item == "rain") + tasks.listAppend("cast hot spells"); + //FIXME verify all (ice?) + + if (!get_property_boolean("_iceHotelRoomsRaided")) + tasks.listAppend("collect once/day certificates"); + if (tasks.count() > 0) + hotel_string += " " + tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; + + options.listAppend(hotel_string); + + tasks.listClear(); + string vkyea_string = "VYKEA."; + boolean nc_helps_in_vykea = true; + if (desired_walford_item == "blood") + nc_helps_in_vykea = false; + if (nc_helps_in_vykea) { + tasks.listAppend("run -combat"); + } + if (desired_walford_item == "moonbeams" && $slot[hat].equipped_item() != $item[none]) { + tasks.listAppend("unequip your hat"); + } + if (desired_walford_item == "blood") + tasks.listAppend("use tin snips every fight"); + if (desired_walford_item == "bolts" && $item[VYKEA hex key].equipped_amount() == 0) + tasks.listAppend("equip VYKEA hex key"); + if (desired_walford_item == "chum" && meat_drop_modifier() < 250.0) { + modifiers.listAppend("+250% meat"); + tasks.listAppend("run +250% meat"); + } + if (desired_walford_item == "balls" && item_drop_modifier() < 50) { + modifiers.listAppend("+50% item"); + tasks.listAppend("run +50% item"); + } + if (!get_property_boolean("_VYKEALoungeRaided")) + tasks.listAppend("collect once/day certificates"); + + if (tasks.count() > 0) + vkyea_string += " " + tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; + + options.listAppend(vkyea_string); + + tasks.listClear(); + if ($item[Walford's bucket].equipped_amount() == 0) { + url = "inventory.php?ftext=walford's+bucket"; + tasks.listAppend("equip walford's bucket"); + } + tasks.listAppend("adventure on the glacier"); + description.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + ":|*" + options.listJoinComponents("
|*")); + + + description.listAppend(progress + "% done collecting " + desired_walford_item + "."); + } + task_entries.listAppend(ChecklistEntryMake("__item Walford's bucket", url, ChecklistSubentryMake(title, modifiers, description), $locations[The Ice Hotel,VYKEA,The Ice Hole]).ChecklistEntrySetIDTag("Airport cold walford quest")); + } +} + +void QAirportGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + ChecklistEntry [int] chosen_entries = optional_task_entries; + if (__misc_state["in run"]) + chosen_entries = future_task_entries; + + QSleazeAirportGenerateTasks(chosen_entries); + QSpookyAirportGenerateTasks(chosen_entries); + QStenchAirportGenerateTasks(chosen_entries); + QHotAirportGenerateTasks(chosen_entries); + QColdAirportGenerateTasks(chosen_entries); +} + +void QAirportGenerateResource(ChecklistEntry [int] resource_entries) +{ + QHotAirportGenerateResource(resource_entries); +} + + +void QSubject37Init() +{ + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questM13Escape"); + + + state.quest_name = "The Pretty Good Escape"; + state.image_name = "__item mysterious silver lapel pin"; + + state.startable = true; + + __quest_state["Subject 37"] = state; +} + + +void QSubject37GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Subject 37"]; + if (!base_quest_state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + string active_url = $location[Cobb's Knob Menagerie, Level 1].getClickableURLForLocation(); + + /* +started Subject 37 wants you to investigate the Cobb's Knob Laboratories and find out what they're planning. +step1 Take the file you found back to Subject 37. +step2 Subject 37 wants something from the BASIC Elementals on level 1 of the Cobb's Knob Menagerie. +step3 Take the GOTO back to Subject 37. +step4 Subject 37 wants some weremoose spit from level 2 of the Cobb's Knob Menagerie. +step5 Take the spit back to Subject 37. +step6 Subject 37 wants some abominable blubber from level 3 of the Cobb's Knob Menagerie. +step7 Take the blubber back to Subject 37. +step8 You've done a good turn, and helped Subject 37 make his escape from the Cobb's Knob Menagerie. + */ + + boolean need_to_return_goto = base_quest_state.mafia_internal_step <= 3; + boolean need_to_return_weremoose = base_quest_state.mafia_internal_step <= 5; + boolean need_to_return_blubber = base_quest_state.mafia_internal_step <= 7; + + if (base_quest_state.mafia_internal_step == 1) + { + subentry.entries.listAppend("Acquire a subject 37 file from Knob Goblin Very Mad Scientist."); + if (!$monster[Knob Goblin Mad Scientist].is_banished()) + subentry.modifiers.listAppend("banish Knob Goblin Mad Scientist"); + active_url = $location[Cobb's Knob Laboratory].getClickableURLForLocation(); + } + else if (base_quest_state.mafia_internal_step == 2) + { + subentry.entries.listAppend("Return the file to Subject 37."); + } + else + { + item [int] items_to_buy_in_mall; + if (need_to_return_goto && $item[goto].available_amount() == 0) + { + //234% item from BASIC elemental + if (!in_ronin()) + { + items_to_buy_in_mall.listAppend($item[goto]); + } + else + { + subentry.modifiers.listAppend("+234% item"); + subentry.entries.listAppend("10 ADVENTURE \"MENAGERIE LEVEL 1\"|20 PRINT \"COLLECT GOTO FROM BASIC ELEMENTAL\"|30 GOTO 10"); + } + } + if (need_to_return_weremoose && $item[weremoose spit].available_amount() == 0) + { + //+item? from weremoose + if (!in_ronin()) + { + items_to_buy_in_mall.listAppend($item[weremoose spit]); + } + else + { + if (subentry.modifiers.count() == 0) + subentry.modifiers.listAppend("+item?"); + subentry.entries.listAppend("Collect weremoose spit from a weremoose in Menagerie Level 2."); + } + } + if (need_to_return_blubber && $item[abominable blubber].available_amount() == 0) + { + //234% item from Portly Abomination + if (!in_ronin()) + { + items_to_buy_in_mall.listAppend($item[abominable blubber]); + } + else + { + if (subentry.modifiers.count() == 0) + subentry.modifiers.listAppend("+234% item"); + subentry.entries.listAppend("Collect abominable blubber from a Portly Abomination in Menagerie Level 3."); + } + } + if (items_to_buy_in_mall.count() > 0) + { + subentry.entries.listAppend("Buy " + items_to_buy_in_mall.listJoinComponents(", ", "and") + " from the mall."); + active_url = "mall.php"; + } + if (subentry.entries.count() == 0) + { + subentry.entries.listAppend("Speak to Subject 37."); + } + } + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[]).ChecklistEntrySetIDTag("Subject 37 quest")); +} +void QMartyInit() +{ + //questM03Bugbear + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questM18Swamp"); + + state.quest_name = "Marty's Quest"; + state.image_name = "__item maple leaf"; + + state.startable = canadia_available(); + + __quest_state["Marty"] = state; +} + +void QMartyGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Marty"]; + if (!base_quest_state.in_progress) + return; + if (!canadia_available()) + return; + if (__misc_state["in run"] && $location[The Edge of the Swamp].turnsAttemptedInLocation() == 0) + return; + + string url = "place.php?whichplace=marais"; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + boolean minus_combat_relevant = false; + string [int] missing_fork_ncs; + if (!$location[The Dark and Spooky Swamp].locationAvailable()) + missing_fork_ncs.listAppend("left"); + else { + string [int] missing_sophie_ncs; + if (!$location[The Corpse Bog].locationAvailable()) + missing_sophie_ncs.listAppend("the bog"); + else if ($item[Phil Bunion's axe].available_amount() == 0) + subentry.entries.listAppend("Adventure in the Corpse Bog to defeat the ghost of Phil Bunion."); + + if (!$location[The Ruined Wizard Tower].locationAvailable()) + missing_sophie_ncs.listAppend("the stone tower"); + else if ($item[shrunken navigator head].available_amount() == 0 && $item[branch from the Great Tree].available_amount() == 0) { + subentry.entries.listAppend("Adventure in the Ruined Wizard Tower to find a shrunken navigator head."); + minus_combat_relevant = true; + } + + if (missing_sophie_ncs.count() > 0) { + minus_combat_relevant = true; + subentry.entries.listAppend("Adventure in the Dark and Spooky Swamp, go towards " + missing_sophie_ncs.listJoinComponents(" and ") + " in Sophie's Choice."); + } + } + + if (!$location[The Wildlife Sanctuarrrrrgh].locationAvailable()) + missing_fork_ncs.listAppend("right"); + else { + string [int] missing_bad_to_worst_ncs; + if (!$location[Swamp Beaver Territory].locationAvailable()) + missing_bad_to_worst_ncs.listAppend("the swamp beaver territory"); + else if ($item[shrunken navigator head].available_amount() > 0 && $item[branch from the Great Tree].available_amount() == 0) { + minus_combat_relevant = true; + subentry.entries.listAppend("Adventure in the Swamp Beaver Territory, follow the shrunken navigator head's directions, and defeat a conservationist hippy."); + } + + if (!$location[The Weird Swamp Village].locationAvailable()) + missing_bad_to_worst_ncs.listAppend("the village"); + else if ($item[bouquet of swamp roses].available_amount() == 0) { + subentry.entries.listAppend("Adventure in the Weird Swamp Village to defeat a swamp skunk."); + subentry.modifiers.listAppend("+item?"); + } + + if (missing_bad_to_worst_ncs.count() > 0) { + minus_combat_relevant = true; + subentry.entries.listAppend("Adventure in the Wildlife Sanctuarrrrrgh, go towards " + missing_bad_to_worst_ncs.listJoinComponents(" and ") + " in From Bad to Worst."); + } + } + + if (missing_fork_ncs.count() > 0) { + minus_combat_relevant = true; + subentry.entries.listAppend("Adventure in the edge of the swamp, go " + missing_fork_ncs.listJoinComponents(" and ") + " in Stick a Fork In It."); + } + if (minus_combat_relevant) //....? + subentry.modifiers.listAppend("-combat?"); + + if ($items[Phil Bunion's axe,bouquet of swamp roses,branch from the Great Tree].items_missing().count() == 0) + { + subentry.entries.listAppend("Go talk to Marty to finish the quest."); + url = "place.php?whichplace=canadia"; + } + + boolean [location] relevant_locations; + relevant_locations[$location[the edge of the swamp]] = true; + relevant_locations[$location[The Dark and Spooky Swamp]] = true; + relevant_locations[$location[The Corpse Bog]] = true; + relevant_locations[$location[The Ruined Wizard Tower]] = true; + relevant_locations[$location[The Wildlife Sanctuarrrrrgh]] = true; + relevant_locations[$location[Swamp Beaver Territory]] = true; + relevant_locations[$location[The Weird Swamp Village]] = true; + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, relevant_locations).ChecklistEntrySetIDTag("Marty Canadia quest")); +} + +void QMeatsmithInit() +{ + //questM23Meatsmith + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questM23Meatsmith"); + + state.quest_name = "Helping Make Ends Meat"; + state.image_name = "__item gnawed-up dog bone"; + + state.startable = true; + + __quest_state["Meatsmith"] = state; +} + + +void QMeatsmithGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Meatsmith"]; + if (base_quest_state.finished) + return; + + if (__last_adventure_location != $location[the skeleton store] || __last_adventure_location == $location[none]) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + string active_url = "place.php?whichplace=town_market"; + + boolean done = false; + boolean have_reason_to_add = false; + + if (!base_quest_state.started) + { + have_reason_to_add = true; + subentry.entries.listAppend("Go talk to the meatsmith to start the quest."); + } + else if (base_quest_state.mafia_internal_step == 1) + { + have_reason_to_add = true; + if ($item[skeleton store office key].available_amount() == 0) + { + subentry.entries.listAppend("Check out the cash register at the NC."); + } + else + { + subentry.entries.listAppend("Head into the manager's office at the NC."); + } + } + else if (base_quest_state.mafia_internal_step == 2) + { + have_reason_to_add = true; + done = true; + subentry.entries.listAppend("Return to the meatsmith."); + active_url = "shop.php?whichshop=meatsmith"; + } + + if ($item[ring of telling skeletons what to do].item_amount() == 0) + { + if (!have_reason_to_add) + subentry.header = "The Skeleton Store"; + string line = "Could acquire a ring of telling skeletons what to do, by opening the chest at the NC"; + if ($item[skeleton key].item_amount() == 0) + line += HTMLGenerateSpanFont(" after acquiring a skeleton key", "red"); + + line += "."; + subentry.entries.listAppend(line); + have_reason_to_add = true; + } + + if (!done) + subentry.entries.listAppend("Non-combat appears every fourth adventure."); //except the first time for some reason? needs spading + + boolean [location] relevant_locations; + relevant_locations[$location[the skeleton store]] = true; + + if (have_reason_to_add) + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, relevant_locations).ChecklistEntrySetIDTag("Meatsmith skeleton store quest")); +} +void QGalaktikInit() +{ + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questM24Doc"); + + + state.quest_name = "What's Up, Doc?"; + state.image_name = "__item pretty flower"; + + state.startable = true; + + __quest_state["Galaktik"] = state; +} + + +void QGalaktikGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Galaktik"]; + if (!base_quest_state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + string active_url = "place.php?whichplace=town_wrong"; + string image_name = base_quest_state.image_name; + + string [int] missing_item_descriptions; + foreach it in $items[swindleblossom,fraudwort,shysterweed] + { + if (it.available_amount() >= 3) + continue; + missing_item_descriptions.listAppend(pluraliseWordy(3 - it.available_amount(), "more " + it, "more " + it.plural)); + } + + if (missing_item_descriptions.count() > 0) + { + subentry.entries.listAppend("Collect " + missing_item_descriptions.listJoinComponents(", ", "and") + " in the overgrown lot."); + if ($item[brown paper bag mask].available_amount() > 0 && $item[brown paper bag mask].equipped_amount() == 0) + subentry.entries.listAppend("Could equip the brown paper bag mask to meet the Lot's wife, if you haven't already."); + + if (__misc_state["in run"] && __last_adventure_location != $location[the overgrown lot] && !in_bad_moon()) + return; + } + else + { + //shop.php?whichshop=doc&action=talk + active_url = "shop.php?whichshop=doc&action=talk"; + subentry.entries.listAppend("Return to Doc Galaktik."); + //image_name = "__familiar o.a.f."; + } + + optional_task_entries.listAppend(ChecklistEntryMake(image_name, active_url, subentry, $locations[the overgrown lot]).ChecklistEntrySetIDTag("Doc Galaktik flower quest")); +} + +void QOldLandfillInit() +{ + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questM19Hippy"); + + state.quest_name = "Give a Hippy a Boat"; + state.image_name = "__item junk junk"; + + state.startable = true; + + __quest_state["Old Landfill"] = state; +} + + +void QOldLandfillGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Old Landfill"]; + //if (!base_quest_state.in_progress) //this isn't actively tracked, so the best we can do is checking the last adventure location + //return; + if ($item[junk junk].available_amount() > 0) //FIXME returning to the hippy + return; + if (__last_adventure_location != $location[the old landfill] && !base_quest_state.in_progress) + return; + if (__misc_state["mysterious island available"]) + return; + + ChecklistSubentry subentry; + subentry.entries.listAppend("Unlocks the Mysterious Island."); + + item [int] missing_boat_items = $items[old claw-foot bathtub,old clothesline pole,antique cigar sign].items_missing(); + + subentry.header = base_quest_state.quest_name; + + string active_url = "place.php?whichplace=woods"; + + if ($item[worse homes and gardens].available_amount() > 0 && missing_boat_items.count() == 0) + { + active_url = "shop.php?whichshop=junkmagazine"; + subentry.entries.listAppend("Use worse homes and gardens, craft a junk junk."); + } + else + { + string [int] nc_instructions = listMake("Go left", "Flush a bunch of toilets"); + + if ($item[old claw-foot bathtub].available_amount() == 0) + { + nc_instructions = listMake("Go left", "Take the tub"); + } + else if ($item[old clothesline pole].available_amount() == 0) + { + nc_instructions = listMake("Go center", "Take the antenna"); + } + else if ($item[antique cigar sign].available_amount() == 0) + { + nc_instructions = listMake("Go right", "Take the sign"); + } + + + if (missing_boat_items.count() > $item[funky junk key].available_amount() || $item[worse homes and gardens].available_amount() == 0) + { + subentry.modifiers.listAppend("+item"); + subentry.entries.listAppend("Adventure in the Old Landfill with +item."); + } + else + subentry.entries.listAppend("Adventure in the Old Landfill."); + + subentry.entries.listAppend("At the choice adventure, choose:|*" + nc_instructions.listJoinComponents(__html_right_arrow_character) + "."); + } + + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, active_url, subentry, $locations[the old landfill]).ChecklistEntrySetIDTag("Old landfill hippy quest")); +} +//questM25Armorer +void QMadnessBakeryInit() +{ + QuestState state; + + QuestStateParseMafiaQuestProperty(state, "questM25Armorer"); + + state.quest_name = "Lending a Hand (and a Foot)"; + state.image_name = "__item unlit birthday cake"; + + + __quest_state["Madness Bakery"] = state; +} + + +void QMadnessBakeryGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QuestState base_quest_state = __quest_state["Madness Bakery"]; + if (!base_quest_state.in_progress) + return; + + ChecklistSubentry subentry; + + subentry.header = base_quest_state.quest_name; + + string url = "place.php?whichplace=town_right"; + + if ($item[no-handed pie].available_amount() > 0 || base_quest_state.mafia_internal_step >= 5) + { + subentry.entries.listAppend("Talk to the leggerer."); + url = "place.php?whichplace=town_market"; + } + else + { + //step1 seems to exist, but no information on office visits left + //step2 - cake lord + //step3 - in the progress of talking to madeline + //step4 - acquire cake + //step5 - melon lord? + subentry.entries.listAppend("Adventure in the Madness Bakery|Choose the first option in the non-combat repeatedly."); + } + + optional_task_entries.listAppend(ChecklistEntryMake(base_quest_state.image_name, url, subentry, $locations[Madness Bakery]).ChecklistEntrySetIDTag("Armory madness bakery quest")); +} +void Q8BitInit() +{ + // This is a convoluted enough keygen method that I'm refactoring it as a quest as + // opposed to a set. This could be wrong! But I think it is a good exercise. + QuestState state; + + // Set the state as "started" if you have the continuum transfunctioner. + if (!state.started && $items[continuum transfunctioner].available_amount() > 0) + state.started = true; + + // Finish this quest if you are in 11,037 Leagues Under the Sea, so the tiles never generate. + if (my_path().id == PATH_SEA) state.finished = true; + + // Finish this quest if you are in community service, so the tiles never generate. + if (my_path().id == PATH_COMMUNITY_SERVICE) state.finished = true; + + // Finish this quest tile if you are in Kingdom of Exploathing, as 8-bit doesn't exist there. + if (my_path().id == PATH_KINGDOM_OF_EXPLOATHING) state.finished = true; + + // Finish this quest tile if you are no longer in-run. Currently commented for testing. + if (!__misc_state["in run"]) state.finished = true; + + boolean haveDigitalKey = $item[digital key].available_amount() > 0; + boolean turnedInDigitalKey = __quest_state["Level 13"].state_boolean["digital key used"]; + + if (haveDigitalKey || turnedInDigitalKey) state.finished = true; + + // Establish basic information for tile generation + state.quest_name = "Digital Key Quest"; + state.image_name = "__item digital key"; // if the bespoke logic fails + // state.image_name = "inexplicable door"; + state.council_quest = true; + + // Total 8-bit score + state.state_int["currentScore"] = get_property_int("8BitScore"); + + // Bonus zone is tracked via the 8BitColor pref; black/red/blue/green are the zone colors + state.state_string["currentColor"] = get_property("8BitColor"); + + if (state.state_string["currentColor"] == "") state.state_string["currentColor"] = "black"; + + __quest_state["Digital Key"] = state; +} + +void Q8bitRealmGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] future_task_entries) +{ + // In 2023, there was a large rework of the 8-bit realm. Instead of needing 30 white + // pixels to generate your Digital Key, you now need a certain amount of score. This + // new tile is an attempt to help users figure out the new 8-bit zone! + + // Read in the information initialized in the quest initializer. + QuestState base_quest_state = __quest_state["Digital Key"]; + + // Do not generate tiles if you do not need the digital key anymore. + if (base_quest_state.finished) { return; } + + // Because I'm doing nested subentries, the broader quest is a ChecklistEntry. + ChecklistEntry entry; + entry.url = "place.php?whichplace=8bit"; + entry.image_lookup_name = base_quest_state.image_name; + entry.tags.id = "Digital Key Pixels 8bit L13"; + entry.should_indent_after_first_subentry = true; + entry.subentries.listAppend(ChecklistSubentryMake(base_quest_state.quest_name)); + entry.should_highlight = $locations[Vanya's Castle, The Fungus Plains, Megalo-City, Hero's Field] contains __last_adventure_location; + + // NOTE: Technically speaking, I think some of this probably -should- be in the Q8BitInit() + // function. However, I like the fact that this lets me read in currentColor as an index + // key on this data; while you can make state.state_int[] and state.state_string[] fields, + // it seems much less straightforward to make int/string fields keyed by a string but with + // proper reference parameters. So instead, I initialize a ton of crap here. Hopefully the + // comments help make everything a bit cleaner and clearer! + + // Make it easier to reference currentColor, as it keys everything else. + string currentColor = base_quest_state.state_string["currentColor"]; + + // Will use the keys of this array as the loop key later. + string [string] helpfulModifier; + + helpfulModifier["black"] = "Initiative"; + helpfulModifier["red"] = "Meat Drop"; + helpfulModifier["blue"] = "Damage Absorption"; + helpfulModifier["green"] = "Item Drop"; + + // I'm using the same math that Beldur did in the 8-bit relay. These are the associated + // values needed to make the expectedPoints equation work; basically, it's the level + // of the modifier you need to see actual point generation increase. + int [string] minimumToAddPoints; + + minimumToAddPoints["black"] = 300; + minimumToAddPoints["red"] = 150; + minimumToAddPoints["blue"] = 300; + minimumToAddPoints["green"] = 100; + + // NOTE: to get to the max point, you add 300 to any of the minimumToAddPoints lol + + // Mapping zones for fun and profit, but mostly to make future things easier. + string [string] zoneMap; + + zoneMap["black"] = "Vanya's Castle"; + zoneMap["red"] = "The Fungus Plains"; + zoneMap["blue"] = "Megalo-City"; + zoneMap["green"] = "Hero's Field"; + + // Storing this so the tile can tell which zone is next. This made me realize that I, like a + // fool, ordered every one of these black/red/blue/green instead of the actual order of + // black/blue/green/red. Sorry, mom. Sorry, college. + string [string] nextColor; + + nextColor["black"] = "blue"; + nextColor["red"] = "black"; + nextColor["blue"] = "green"; + nextColor["green"] = "red"; + + int bonusTurnsRemaining = 5 - get_property("8BitBonusTurns").to_int(); + + // Populate user's modifier for each bonus; iterates through black/red/blue/green + int [string] userModifier; + + foreach key in helpfulModifier + userModifier[key] = numeric_modifier(helpfulModifier[key]); + + // Populate expected points in each zone + int [string] expectedPoints; + int addedBonus; + int denominator; + int rawPoints; + boolean isCurrentZoneBonus; + + foreach key in helpfulModifier + { + isCurrentZoneBonus = (currentColor == key); + addedBonus = (isCurrentZoneBonus ? 100 : 50); + denominator = (isCurrentZoneBonus ? 10 : 20); + rawPoints = min(300, max(0, userModifier[key] - minimumToAddPoints[key])); + + expectedPoints[key] = addedBonus + round(rawPoints/denominator) * 10; + } + + // Figure out if the user is better-suited to adventure elsewhere. + string highestPointColor = currentColor; + + foreach key, value in expectedPoints { + if (value > expectedPoints[currentColor]) { + if (value > expectedPoints[highestPointColor]) { + highestPointColor = key; + } + } + } + + // Now that we have calculated everything, we can finally make the tile! Before the very + // detailed subentry, we have a quick statement of what the quest wants you to do. We + // do this by adding to the subentries[0] guy. + entry.subentries[0].entries.listAppend("Gain "+pluralise(max(10000-base_quest_state.state_int["currentScore"],0), "more point","more points")+" to get your digital key."); + + // OK, now we make our subentry for the bonus zone. + ChecklistSubentry subentry; + + // We have a return up top for a finished quest. As a result, it should only hit !started + // in the right order, even if our finishing reassignment in QuestInit doesn't work. + if (!base_quest_state.started) + { + subentry.header = "Go listen to a crackpot!"; + entry.url = "place.php?whichplace=forestvillage&action=fv_mystic"; + entry.image_lookup_name = "__item continuum transfunctioner"; + subentry.entries.listAppend("Visit the crackpot mystic for your transfunctioner."); + } + else if (base_quest_state.state_int["currentScore"] < 10000) { + + subentry.header = "BONUS ZONE: "+zoneMap[currentColor]+" ("+pluralise(bonusTurnsRemaining, "more fight", "more fights")+")"; + + // Modify the overarching image to match the current zone. + entry.image_lookup_name = zoneMap[currentColor]; + + // Establish easier shorthand for the active bonus modifier. + string activeMod = helpfulModifier[currentColor]; + string neededModifier = to_string(minimumToAddPoints[currentColor]+300); + + // Add nice shorthand text to the subentry w/ the stat to maximize. + if (activeMod == "Initiative") {subentry.modifiers.listAppend("+"+neededModifier+"% init");} + if (activeMod == "Meat Drop") {subentry.modifiers.listAppend("+"+neededModifier+"% meat");} + if (activeMod == "Damage Absorption") {subentry.modifiers.listAppend("+"+neededModifier+" DA");} + if (activeMod == "Item Drop") {subentry.modifiers.listAppend("+"+neededModifier+"% item");} + if (zoneMap[currentColor] != "Megalo-City") {subentry.modifiers.listAppend("outdoor zone");} + + // Give descriptive information about the current zone. + if (expectedPoints[currentColor] == 400) + { + // If the user is at maximum, color the tile a bit and be merry. + subentry.entries.listAppend(HTMLGenerateSpanFont("MAXIMUM POINTS!",currentColor)); + subentry.entries.listAppend("Adventure in "+HTMLGenerateSpanFont(""+zoneMap[currentColor]+"", currentColor)+" for 400 points per turn!"); + } + else + { + // If the user is not at maximum, point out what they need to buff. + subentry.entries.listAppend("Current expected points: "+to_string(expectedPoints[currentColor])); + + string percentCharacter = (activeMod != "Damage Absorption" ? "%" : ""); + string modifierNeededText = to_string(minimumToAddPoints[currentColor]+300 - userModifier[currentColor])+percentCharacter; + + string buffUpLine = "Consider buffing "+HTMLGenerateSpanFont(helpfulModifier[currentColor], currentColor)+" for more points."; + buffUpLine += "|*You need "+modifierNeededText+" more for max points."; + subentry.entries.listAppend(buffUpLine); + } + + // In both cases, show the # of turns remaining of bonus in this zone. + subentry.entries.listAppend("In "+pluralise(bonusTurnsRemaining, "more fight", "more fights")+", bonus zone will be "+HTMLGenerateSpanFont(zoneMap[nextColor[currentColor]],nextColor[currentColor])+"."); + + if (highestPointColor != currentColor) { + subentry.entries.listAppend("Alternate Route:|*"+HTMLGenerateSpanFont("At current stats, you'd earn "+expectedPoints[highestPointColor]+" points per fight at "+zoneMap[highestPointColor]+". Not recommended!","gray")); + } + + // If they don't have the transfunctioner equipped, equip it and change the URL. + if ($item[continuum transfunctioner].equipped_amount() == 0) + { + entry.url = "inventory.php?ftext=continuum+transfunctioner"; + subentry.entries.listAppend(HTMLGenerateSpanFont("Equip your transfunctioner to access the realm.", "red")); + + } + } + + entry.subentries.listAppend(subentry); + + // Add small subentry near the end w/ current score! But only add it if they have their transfunctioner. + if (base_quest_state.started) { + ChecklistSubentry keyCompletionSubentry; + + keyCompletionSubentry.header = "Projected Key Completion"; + keyCompletionSubentry.modifiers.listAppend("Current Score: "+to_string(base_quest_state.state_int["currentScore"])+" of 10000"); + + if (base_quest_state.state_int["currentScore"] < 10000) + { + int pointsLeft = 10000 - base_quest_state.state_int["currentScore"]; + int minimumTurnsToGetKey = ceil(pointsLeft / 400.0); // ceil always rounds up, so any fraction of a leftover turn will add 1 + keyCompletionSubentry.entries.listAppend("If you max your bonus, you'll have your key in "+pluralise(minimumTurnsToGetKey, "more turn", "more turns")+"."); + } + else + { + keyCompletionSubentry.entries.listAppend("Woah, 10000 points??? That's this life's high score!"); + keyCompletionSubentry.entries.listAppend("Visit the Treasure House to claim your hard-earned Digital Key."); + } + entry.subentries.listAppend(keyCompletionSubentry); + } + + // If the user is below level 5, probably have better things to be doing unless they're + // already maxed out at the relevant bonus zone; ergo, shift the tile to "Future Tasks" + + if (my_level() > 5 || expectedPoints[currentColor] == 400) + task_entries.listAppend(entry); + else + future_task_entries.listAppend(entry); + +} + + +void Q8bitRealmGenerateResource(ChecklistEntry [int] resource_entries) +{ + // This resource tile is still valuable for newbies who need/want red pixel potions. Somewhat + // ironically, this is actually more useful post-revamp since newbies have more reason to + // get black pixels. It might be slightly annoying for some speedrunners, but they can just + // hide the tile if they don't like it. + + // ... though even I can't pretend we want this in aftercore, lol + if (!__misc_state["in run"] || !in_ronin()) + return; + + // Comment originally from Ezandora noting good things in the pixel shop: + // - Blue pixel potion - [50,80] MP restore + // - monster bait - +5% combat + // - pixel sword - +15% init + // - red pixel potion - [100,120] HP restore - the shadow knows + // - pixel whip - useful against vampires + + string [item] craftables; + int [item] max_craftables_wanted; + craftables[$item[pixel bread]] = "+50% meat"; + craftables[$item[pixel whiskey]] = "+50% item"; + craftables[$item[blue pixel potion]] = "~65 MP restore"; + craftables[$item[monster bait]] = "+5% combat"; + max_craftables_wanted[$item[monster bait]] = 1; + + // Only generate red pixels if you need them for tower healing. They sell like shit. + if (__quest_state["Level 13"].state_boolean["shadow will need to be defeated"]) + craftables[$item[red pixel potion]] = "~110 HP restore; good for shadow"; + if ($locations[dreadsylvanian castle,the spooky forest,The Haunted Sorority House,The Daily Dungeon] contains __last_adventure_location) //known vampire locations. it's perfectly reasonable to test against the sorority house, here in 2023 + { + craftables[$item[pixel whip]] = "vampire killer"; + max_craftables_wanted[$item[pixel whip]] = 1; + } + + max_craftables_wanted[$item[blue pixel potion]] = 11; + max_craftables_wanted[$item[red pixel potion]] = 4; //4 minimum to out-shadow + + string [int] crafting_list_have; + string [int] crafting_list_cannot; + foreach it, reason in craftables + { + if (it.available_amount() >= MAX(1, max_craftables_wanted[it])) + continue; + string line = it; + + if (max_craftables_wanted[it] != 1 && it.creatable_amount() > 0) + line = pluralise(it.creatable_amount(), it); + line += ": " + reason; + if (it.creatable_amount() == 0) + { + line = HTMLGenerateSpanFont(line, "grey"); + crafting_list_cannot.listAppend(line); + } + else + crafting_list_have.listAppend(line); + } + if (crafting_list_have.count() > 0) + { + string [int] crafting_list = crafting_list_have; + crafting_list.listAppendList(crafting_list_cannot); + string pixels_have = "Craft a few Pixel sundries"; + resource_entries.listAppend(ChecklistEntryMake("__item red pixel potion", "shop.php?whichshop=mystic", ChecklistSubentryMake(pixels_have, "", crafting_list), 10).ChecklistEntrySetIDTag("Crackpot mystic pixel crafting resource")); + } +} + +void Q8bitRealmGenerateMissingItems(ChecklistEntry [int] items_needed_entries) +{ + // This is still helpful, but mostly for KoE, the only remaining path where you need + // to generate white pixels for the digital key. Keep it just for KoE? Heh. + + if (!__misc_state["in run"] && !__misc_state["Example mode"]) + return; + if (__quest_state["Level 13"].state_boolean["digital key used"]) + return; + if (my_path().id == PATH_COMMUNITY_SERVICE) + return; + + if ($item[digital key].available_amount() == 0) { + string url = "place.php?whichplace=8bit"; + if (my_path().id == PATH_KINGDOM_OF_EXPLOATHING) + url = "shop.php?whichshop=exploathing"; + string [int] options; + // I had a change of heart and kept it for normal runs too. Dreams can come true. + if (__quest_state["Digital Key"].state_int["currentScore"] > 9999) { + options.listAppend("Visit 8-bit Realm's Treasure House and claim your key!"); + } else if (my_path().id == PATH_KINGDOM_OF_EXPLOATHING) { + options.listAppend("Go fight invader bullets, or find some way to fight a Ghost."); + } else { + options.listAppend("Visit the 8-bit Realm and max your score to claim a Digital Key."); + } + items_needed_entries.listAppend(ChecklistEntryMake("__item digital key", url, ChecklistSubentryMake("Digital key", "", options)).ChecklistEntrySetIDTag("Council L13 quest tower door digital key")); + } +} + + + + + +void QuestsInit() +{ + QPirateInit(); + QLevel2Init(); + QLevel3Init(); + QLevel4Init(); + QLevel5Init(); + QLevel6Init(); + QLevel7Init(); + QLevel8Init(); + QLevel9Init(); + QLevel10Init(); + QLevel11Init(); + QLevel12Init(); + QLevel13Init(); + QNemesisInit(); + QSeaInit(); + QSpaceElvesInit(); + QAzazelInit(); + QUntinkerInit(); + QArtistInit(); + QLegendaryBeatInit(); + QMemoriesInit(); + QWhiteCitadelInit(); + QWizardOfEgoInit(); + QFeloniaInit(); + QGuildInit(); + QSubject37Init(); + QMartyInit(); + QMeatsmithInit(); + QGalaktikInit(); + QOldLandfillInit(); + QMadnessBakeryInit(); + QManorInit(); + Q8BitInit(); +} + + +void QuestsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + QLevel2GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel3GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel4GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel5GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel6GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel7GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel8GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel9GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel10GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel11GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel12GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLevel13GenerateTasks(task_entries, optional_task_entries, future_task_entries); + + QManorGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QPirateGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QNemesisGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QSeaGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QSpaceElvesGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QAzazelGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QGuildGenerateTasks(task_entries, optional_task_entries, future_task_entries); + + QUntinkerGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QArtistGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QLegendaryBeatGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QMemoriesGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QWhiteCitadelGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QWizardOfEgoGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QSpookyravenLightsOutGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QFeloniaGenerateTasks(task_entries, optional_task_entries, future_task_entries); + + QAirportGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QSubject37GenerateTasks(task_entries, optional_task_entries, future_task_entries); + QMartyGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QMeatsmithGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QGalaktikGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QOldLandfillGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QMadnessBakeryGenerateTasks(task_entries, optional_task_entries, future_task_entries); + + Q8bitRealmGenerateTasks(task_entries, future_task_entries); +} + +void QuestsGenerateResources(ChecklistEntry [int] resource_entries) +{ + QSpookyravenLightsOutGenerateResource(resource_entries); + QAirportGenerateResource(resource_entries); + Q8bitRealmGenerateResource(resource_entries); +} + + +string [int] luckyOptions(int cloversAvailable) { + // Generate lucky suggestions from available options. Ordered in rough + // order according to which ones are available when. + string [int] allTheLuckyStuff; + int cloversAdjusted = cloversAvailable; + + // Very basic protestors calculations with rough amounts for certain + // weird paths. Assumption in standard/unrestricted is 3-clover mob. + int protestorsRemaining = clampi(80 - get_property_int("zeppelinProtestors"), 0, 80); + if (__quest_state["Level 11"].mafia_internal_step < 3) protestorsRemaining = 80; + int protestorsPerClover = 27; // 3 clover mob + + switch (my_path()) { + case $path[Legacy of Loathing]: + protestorsPerClover = 20; // 4 clover mob + case $path[Avatar of Boris]: + protestorsPerClover = 16; // 5 clover mob + case $path[G-Lover]: + protestorsPerClover = 1; // cannot use clovers RIP + } + + int projectedZeppClovers = ceil(protestorsRemaining.to_float()/protestorsPerClover.to_float()); + + // Wand variable needed to ensure we know the # of letters remaining + int lettersStillNeeded = __misc_state_int["ruby w needed"] + __misc_state_int["metallic a needed"] + __misc_state_int["lowercase n needed"] + __misc_state_int["heavy d needed"]; + + // Variables needed for a-boo nonsense + int aBooHauntedness = __quest_state["Level 9"].state_int["a-boo peak hauntedness"]; + int cluesNeeded = ceil(MIN(aBooHauntedness, 100).to_float() / 30.0); + int aBooCloversNeeded = ceil(cluesNeeded/2); + + // Desert ultrahydrated remaining + int exploration = __quest_state["Level 11 Desert"].state_int["Desert Exploration"]; + int explorationRemaining = 100 - exploration; + int roughUHTurnsNeeded = ceil(explorationRemaining.to_float()/2.0); + + // Append the lucky thing you can get, if you actually need it. Priority is because: + + // - Ore is an early clover dump that (in modern meta) generally wants either an early MM or an + // early clover. If you can't solve ore otherwise, this saves an absurd amount of turns + // - Zeppelin is the most important clover dump in-run traditionally; saves a good 5-6 turns + // apiece, more in some paths + // - Wand is necessary in almost every path, and next-most-important after zepp/ore. Saves a + // good 3-ish turns on having to lose an NS fight and find the wand in the cemetary + // - Ultrahydrated saves 2-ish turns in some paths + // - Mick's saves about 2 turns in some paths as well, but less so generally + // - A-Boo clues save half a turn apiece because you save 1 turn on a two clover a-boo + + // Beyond these, there is a mild case for some of the elemental damage clovers, but I + // don't think they warrant adding. Possibly worth adding to the actual tower test + // tile if you're at the tower test, but even then. Meh. + + if (!__quest_state["Level 8"].state_boolean["Past mine"] && $location[Itznotyerzitz Mine].locationAvailable()) + allTheLuckyStuff.listAppend("Ore"); + if (protestorsRemaining > 10 && protestorsPerClover > 15) + allTheLuckyStuff.listAppend("Zeppelin Mob (x"+projectedZeppClovers+")"); + cloversAdjusted = MAX(cloversAdjusted - projectedZeppClovers, 3); + if (__misc_state["wand of nagamar needed"] && lettersStillNeeded > 0) + allTheLuckyStuff.listAppend("Wand of Nagamar"); + if (roughUHTurnsNeeded > 5) + allTheLuckyStuff.listAppend("Ultrahydrated"); + if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) + allTheLuckyStuff.listAppend("Mick's Icyvapohotness Inhaler"); + if (aBooHauntedness > 0) + allTheLuckyStuff.listAppend("A-Boo Clues (x"+aBooCloversNeeded+")"); + cloversAdjusted = MAX(cloversAdjusted - aBooCloversNeeded, 3); + + string [int] selectedOptions; + + foreach key, luckyStuff in allTheLuckyStuff { + if (key < cloversAdjusted) selectedOptions.listAppend(luckyStuff); + } + + return selectedOptions; +} + + +//Clovers and Lucky +RegisterResourceGenerationFunction("LuckyGenerateResource"); +void LuckyGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["in run"]) return; + { + string [int] description; + string url; + description.listAppend(HTMLGenerateSpanFont("Have a Lucky adventure!", "green")); + + // Figure out how many clovers you have available/possible and join the needed components + int cloversAvailable = clampi(3 - get_property_int("_cloversPurchased"), 0, 3); + int cloversPossible = $item[11-leaf clover].available_amount() + cloversAvailable; + description.listAppend(luckyOptions(cloversPossible).listJoinComponents(", ")); + + + + if ($item[11-leaf clover].available_amount() > 0) + { + url = invSearch("11-leaf clover"); + resource_entries.listAppend(ChecklistEntryMake("__item 11-leaf clover", url, ChecklistSubentryMake(pluralise($item[11-leaf clover]), "Inhale leaves for good luck", description), 2).ChecklistEntrySetCombinationTag("fortune")); + } + if ($item[[10883]astral energy drink].available_amount() > 0 && $item[11-leaf clover].available_amount() == 0) + { + url = invSearch("astral energy drink"); + resource_entries.listAppend(ChecklistEntryMake("__item [10883]astral energy drink", url, ChecklistSubentryMake(pluralise(available_amount($item[[10883]astral energy drink]),"astral energy drink", "astral energy drinks"), "Costs 5 spleen each", description), 2).ChecklistEntrySetCombinationTag("fortune")); + } + else if ($item[[10883]astral energy drink].available_amount() > 0 && $item[11-leaf clover].available_amount() > 0) + { + url = invSearch("astral energy drink"); + resource_entries.listAppend(ChecklistEntryMake("__item [10883]astral energy drink", url, ChecklistSubentryMake(pluralise(available_amount($item[[10883]astral energy drink]),"astral energy drink", "astral energy drinks"), "Costs 5 spleen each", ""), 2).ChecklistEntrySetCombinationTag("fortune")); + } + + // Add a reminder to buy clovers if you haven't yet + string [int] hermitDescription; + if (cloversAvailable > 0) + { + url = "hermit.php"; + string title = HTMLGenerateSpanFont("Hey! You! GRAB YOUR CLOVERS!", "green"); + hermitDescription.listAppend(cloversAvailable + " in stock at the Hermit"); + resource_entries.listAppend(ChecklistEntryMake("__item 11-leaf clover", url, ChecklistSubentryMake(title, hermitDescription), -11).ChecklistEntrySetIDTag("Clover resource")); + } + } +} + +RegisterTaskGenerationFunction("LuckyGenerateTasks"); +void LuckyGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($effect[lucky!].have_effect() > 0) { + string [int] description; + string main_title = HTMLGenerateSpanFont("You feel lucky, punk!", "green") + ""; + + // Figure out how many clovers you have available/possible and join the needed components + int cloversAvailable = clampi(3 - get_property_int("_cloversPurchased"), 0, 3); + int cloversPossible = $item[11-leaf clover].available_amount() + cloversAvailable; + + if (__misc_state["in run"] && my_path().id == 44) { // path is grey you lol + description.listAppend("1x ore, 1x freezerburned ice cube, 1x full-length mirror."); + } + else if (__misc_state["in run"]) { + description.listAppend(luckyOptions(cloversPossible).listJoinComponents(", ")); + } + else { + description.listAppend("I dunno. Full-length mirror?"); + } + task_entries.listAppend(ChecklistEntryMake("__item 11-leaf clover", "", ChecklistSubentryMake(main_title, description), -11).ChecklistEntrySetIDTag("Fortune adventure now")); + } +} + +boolean HITSStillRelevant() +{ + if (__misc_state["Example mode"]) + return true; + if (!__misc_state["in run"]) + return false; + if (__quest_state["Level 13"].state_boolean["Richard's star key used"]) + return false; + if (!__quest_state["Level 10"].finished && my_path().id != PATH_EXPLOSIONS) + return false; + if (my_path().id == PATH_COMMUNITY_SERVICE) + return false; + + return true; +} + +void QHitsInit() +{ + //This isn't really a quest... + QuestState state; + + state.quest_name = "Hole in the Sky"; + state.image_name = "Hole in the Sky"; + + + int charts_want = 0; + int stars_want = 0; + int lines_want = 0; + + if ($item[richard\'s star key].available_amount() == 0 && HITSStillRelevant()) + { + charts_want += 1; + stars_want += 8; + lines_want += 7; + } + + state.state_int["star charts needed"] = MAX(0, charts_want - $item[star chart].available_amount()); + state.state_int["stars needed"] = MAX(0, stars_want - $item[star].available_amount()); + state.state_int["lines needed"] = MAX(0, lines_want - $item[line].available_amount()); + + __quest_state["Hole in the Sky"] = state; +} + +void QHitsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!HITSStillRelevant()) + return; + ChecklistSubentry subentry; + subentry.header = "Hole in the Sky"; + + string active_url = ""; + //Super unclear code. Sorry. + //FIXME rewrite now that we don't need equipment + + int star_charts_needed = 0; + int stars_needed_base = 0; + int lines_needed_base = 0; + + string [int] item_names_needed; + + if ($item[richard\'s star key].available_amount() == 0) + { + star_charts_needed += 1; + stars_needed_base += 8; + lines_needed_base += 7; + item_names_needed.listAppend($item[richard\'s star key]); + } + int [int] stars_needed_options; + int [int] lines_needed_options; + string [int] needed_options_names; + if (needed_options_names.count() == 0) + { + stars_needed_options.listAppend(stars_needed_base + 0); + lines_needed_options.listAppend(lines_needed_base + 0); + } + + //Convert what we need total to what's remaining: + int star_charts_remaining = MAX(0, star_charts_needed - $item[star chart].available_amount()); + int [int] stars_remaining; + int [int] lines_remaining; + string [int] remaining_options_names; + + boolean have_met_stars_requirement = true; + boolean have_met_lines_requirement = true; + + foreach key in stars_needed_options + { + if (needed_options_names contains key) + remaining_options_names[key] = needed_options_names[key]; + stars_remaining[key] = MAX(0, stars_needed_options[key] - $item[star].available_amount()); + lines_remaining[key] = MAX(0, lines_needed_options[key] - $item[line].available_amount()); + + if (stars_remaining[key] > 0) + have_met_stars_requirement = false; + if (lines_remaining[key] > 0) + have_met_lines_requirement = false; + } + + if (__misc_state["Example mode"]) + { + star_charts_remaining = 1; + have_met_stars_requirement = false; + have_met_lines_requirement = false; + } + + if (have_met_stars_requirement) + { + //Have all stars, suggest star sword (least lines) + //Remove non-sword: + foreach key in remaining_options_names + { + if (remaining_options_names[key] != "star sword") + { + remove remaining_options_names[key]; + remove stars_remaining[key]; + remove lines_remaining[key]; + } + } + } + else if (have_met_lines_requirement) + { + //Have all lines, suggest star crossbow (least stars) + //Remove non-crossbow: + foreach key in remaining_options_names + { + if (remaining_options_names[key] != "star crossbow") + { + remove remaining_options_names[key]; + remove stars_remaining[key]; + remove lines_remaining[key]; + } + } + } + if (remaining_options_names.count() > 0) + { + item_names_needed.listAppend(remaining_options_names.listJoinComponents("/", "")); + } + + if (item_names_needed.count() == 0) + return; + + + if (!$location[the hole in the sky].locationAvailable()) + { + //find a way to space: + subentry.modifiers.listAppend("-combat"); + subentry.entries.listAppend("Run -combat on the top floor of the castle for the steam-powered model rocketship.|From steampunk non-combat, unlocks Hole in the Sky."); + active_url = "place.php?whichplace=giantcastle"; + + + subentry.entries.listAppend(generateTurnsToSeeNoncombat(95, 1, "", 9)); + } + else + { + active_url = "place.php?whichplace=beanstalk"; + //We've made it out to space: + subentry.entries.listAppend("Need " + item_names_needed.listJoinComponents(", ", "and") + "."); + + string [int] required_components; + if (star_charts_remaining > 0) + required_components.listAppend(pluralise(star_charts_remaining, $item[star chart])); + foreach key in stars_remaining + { + string [int] line; + if (stars_remaining[key] > 0) + line.listAppend(pluralise(stars_remaining[key], $item[star])); + if (lines_remaining[key] > 0) + line.listAppend(pluralise(lines_remaining[key], $item[line])); + string route = ""; + if (remaining_options_names contains key) + { + route = " (" + remaining_options_names[key]; + if (stars_remaining.count() > 1) + route += " route"; + route += ")"; + } + if (line.count() > 0) + required_components.listAppend(line.listJoinComponents(" / ") + route); + } + if (required_components.count() > 0) + { + if (star_charts_remaining == 1 && have_met_stars_requirement && have_met_lines_requirement && !in_hardcore()) + { + subentry.entries.listAppend("Can pull a star chart."); + } + //require more components: + if (remaining_options_names.count() <= 1) + subentry.entries.listAppend("Need " + required_components.listJoinComponents(", ", "")); + else + subentry.entries.listAppend("Need:|*" + required_components.listJoinComponents("|*", "or")); + + //FIXME if we need only one type, recommend a different monster to olfact + + if (star_charts_remaining > 0 && in_hardcore()) + { + //olfact nothing, interferes with astronomers + //they prefer interferometry + } + else if (!have_met_stars_requirement || !have_met_lines_requirement) + { + if (my_ascensions() % 2 == 0) + subentry.entries.listAppend("Olfact skinflute."); + else + subentry.entries.listAppend("Olfact camel's toe."); + } + + if (!have_met_stars_requirement || !have_met_lines_requirement) + subentry.modifiers.listAppend("+234% item"); + + if ($familiar[space jellyfish].familiar_is_usable()) + { + //Space Directions NC: + //39, 46 + int turns_spent = $location[the hole in the sky].turns_spent; + boolean nc_up = false; + int turns_to_next_nc = 0; + if (turns_spent < 2) + turns_to_next_nc = 2 - turns_spent; + else + turns_to_next_nc = 7 - (turns_spent - 2) % 7; + + if (turns_spent == 2) + nc_up = true; + else if ((turns_spent - 2) % 7 == 0) + nc_up = true; + if (nc_up) + { + //Apparently skipping the NC just makes it re-appear the next adventure? + if (true) //get_property("lastEncounter") != "Space Directions") + { + string line = ""; + string [int] choices; + boolean an = false; + if (star_charts_remaining > 0) + { + choices.listAppend("astronomer"); + an = true; + } + if (!have_met_stars_requirement || !have_met_lines_requirement) + { + choices.listAppend("camel's toe"); + } + if ($familiar[space jellyfish] != my_familiar()) + line = HTMLGenerateSpanFont("Bring along your space jellyfish", "red") + ", it'll let you choose a " + choices.listJoinComponents(", ", "or"); + else + line = "Jellyfish NC next adventure. Will let you fight a" + (an ? "n" : "") + " " + choices.listJoinComponents(", ", "or"); + /*if (star_charts_remaining > 0) + { + choices.listAppend("astronomer"); + line = HTMLGenerateSpanFont("Bring along your space jellyfish", colour) + ", it'll let you choose an astronomer/camel"; + } + else + line = HTMLGenerateSpanFont("Possibly bring along your space jellyfish", colour) + ", it'll let you choose an camel";*/ + line += " this adventure."; + if (!have_met_stars_requirement || !have_met_lines_requirement) + line += "|Though that will reduce your +item, so choose wisely."; + subentry.entries.listAppend(line); + } + } + else + { + if (get_property_int("singleFamiliarRun").to_familiar() != $familiar[space jellyfish] && $familiar[space jellyfish] == my_familiar()) + { + subentry.entries.listAppend(HTMLGenerateSpanFont("Switch to another familiar?", "red")); + } + string line = pluraliseWordy(turns_to_next_nc, "more turn", "more turns").capitaliseFirstLetter() + " to jellyfish choice NC."; + subentry.entries.listAppend(line); + } + } + + if (__quest_state["Level 11 Shen"].state_int.getFutureShenAssignments().listInvert() contains $location[The Hole in the Sky]) + subentry.entries.listAppend("Could wait before going here? Shen will send you here later."); + } + else { + active_url = "shop.php?whichshop=starchart"; + subentry.entries.listAppend("Can make Richard's Star Key."); + } + } + optional_task_entries.listAppend(ChecklistEntryMake("hole in the sky", active_url, subentry, $locations[the hole in the sky, the castle in the clouds in the sky (top floor)]).ChecklistEntrySetIDTag("Hole in the sky quest")); +} + + +void QHitsGenerateMissingItems(ChecklistEntry [int] items_needed_entries) +{ + if (!__misc_state["in run"] && !__misc_state["Example mode"]) + return; + if (__quest_state["Level 13"].state_boolean["Richard\'s star key used"] || $item[richard\'s star key].available_amount() > 0) + return; + + QuestState state = __quest_state["Hole in the Sky"]; + + string url = $location[the hole in the sky].getClickableURLForLocation(); + if (state.state_int["star charts needed"] + state.state_int["stars needed"] + state.state_int["lines needed"] == 0) + url = "shop.php?whichshop=starchart"; + else if (!$location[the hole in the sky].locationAvailable()) + url = $location[The Castle in the Clouds in the Sky (basement)].getClickableURLForLocation(); + string [int] oh_my_stars_and_gauze_garters; + oh_my_stars_and_gauze_garters.listAppend(MIN(1, $item[star chart].available_amount()) + "/1 star chart"); + oh_my_stars_and_gauze_garters.listAppend(MIN(8, $item[star].available_amount()) + "/8 stars"); + oh_my_stars_and_gauze_garters.listAppend(MIN(7, $item[line].available_amount()) + "/7 lines"); + items_needed_entries.listAppend(ChecklistEntryMake("__item richard\'s star key", url, ChecklistSubentryMake("Richard\'s star key", "", oh_my_stars_and_gauze_garters.listJoinComponents(", ", "and"))).ChecklistEntrySetIDTag("Council L13 tower door richard star key")); +} + +void SFamiliarsGenerateEntry(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, boolean from_task) +{ + if (get_property_int("_badlyRomanticArrows") == 0 && (familiar_is_usable($familiar[obtuse angel]) || familiar_is_usable($familiar[reanimated reanimator])) && my_path().id != PATH_LIVE_ASCEND_REPEAT && my_path().id != PATH_G_LOVER) + { + if (!__misc_state["in aftercore"] && !from_task) + return; + if (__misc_state["in aftercore"] && from_task) + return; + string familiar_image = __misc_state_string["obtuse angel name"]; + string [int] description; + string title = "Arrow monster"; + if (familiar_image == "reanimated reanimator") + title = "Wink at monster"; + string url; + if (!($familiars[obtuse angel, reanimated reanimator] contains my_familiar())) + url = "familiar.php"; + + if ($familiar[reanimated reanimator].familiar_is_usable() || ($familiar[obtuse angel].familiar_is_usable() && $familiar[obtuse angel].familiar_equipment() == $item[quake of arrows])) + description.listAppend("Three wandering copies."); + else + description.listAppend("Two wandering copies."); + + string [int] potential_targets; + //a short list: + //FIXME writing desk + if (__quest_state["Level 7"].state_int["alcove evilness"] > 31) + potential_targets.listAppend("modern zmobie"); + + if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && $items[ninja rope,ninja carabiner,ninja crampons].available_amount() == 0 && !have_outfit_components("eXtreme Cold-Weather Gear")) + potential_targets.listAppend("ninja assassin"); + + if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) + potential_targets.listAppend("lobsterfrogman"); + + if (!__quest_state["Level 12"].state_boolean["Nuns Finished"] && have_outfit_components("Frat Warrior Fatigues") && have_outfit_components("War Hippy Fatigues")) //brigand trick + potential_targets.listAppend("brigand"); + + // Adding KoE check to the romantic arrow check for a ghost monster, since this is only useful in KoE now. + if (!familiar_is_usable($familiar[angry jung man]) && in_hardcore() && my_path().id == PATH_KINGDOM_OF_EXPLOATHING && !__quest_state["Level 13"].state_boolean["digital key used"] && ($item[digital key].available_amount() + creatable_amount($item[digital key])) == 0 && __misc_state["fax equivalent accessible"]) + potential_targets.listAppend("ghost"); + + if (__misc_state["in run"] && ($items[bricko eye brick,bricko airship,bricko bat,bricko cathedral,bricko elephant,bricko gargantuchicken,bricko octopus,bricko ooze,bricko oyster,bricko python,bricko turtle,bricko vacuum cleaner].available_amount() > 0 || $skill[summon brickos].skill_is_usable())) + potential_targets.listAppend("BRICKO monster"); + + if (potential_targets.count() > 0) + description.listAppend("Possibly a " + potential_targets.listJoinComponents(", ", "or") + "."); + + optional_task_entries.listAppend(ChecklistEntryMake(familiar_image, url, ChecklistSubentryMake(title, "", description), 6).ChecklistEntrySetIDTag("Romantic-like familiar copy make")); + } + + + if ($familiar[Crimbo Shrub].familiar_is_usable() && my_path().id != PATH_G_LOVER) + { + boolean should_output = false; + if (__misc_state["in run"]) + { + if (from_task) + should_output = true; + } + else + { + if (!from_task) + should_output = true; + } + if (get_property("shrubGifts") == "meat" && $effect[everything looks red].have_effect() == 0 && should_output) + { + string url = ""; + string title = "Open a Big Red Present in combat"; + if (!from_task) + title = "Big Red Present openable in combat"; + string description = "Gives 2.5k meat."; + if (my_familiar() != $familiar[Crimbo Shrub]) + { + url = "familiar.php"; + if (from_task) + title = "Switch to Crimbo Shrub to open a big red present"; + else + description = "Switch to Crimbo Shrub first.|" + description; + } + optional_task_entries.listAppend(ChecklistEntryMake("__item dense meat stack", url, ChecklistSubentryMake(title, "", description), 6).ChecklistEntrySetIDTag("Crimbo shrub familiar big red present")); + } + } +} + +void SFamiliarsPuckGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["in run"]) return; + if (my_path().id == PATH_G_LOVER) return; // cannot use puck (or submarine/yellow pixels) in g-lover + + ChecklistSubentry [int] puck_subentries; + item yellow_pixel = $item[yellow pixel]; + string url = ""; + familiar relevant_familiar = $familiar[Ms. Puck Man]; + if (!relevant_familiar.familiar_is_usable() && $familiar[Puck Man].familiar_is_usable()) + relevant_familiar = $familiar[Puck Man]; + if ($familiar[Ms. Puck Man].familiar_is_usable() || $familiar[Puck Man].familiar_is_usable()) + { + int power_pills_remaining = MAX(0, MIN(11, my_daycount() + 1) - get_property_int("_powerPillDrops")); + if (power_pills_remaining > 0) + { + string [int] description; + + string line = "Saves a turn each."; + if (my_familiar() != $familiar[Ms. Puck Man] && my_familiar() != $familiar[Puck Man] && url.length() == 0) + { + url = "familiar.php"; + line += " Drops from " + relevant_familiar + "."; + } + description.listAppend(line); + + puck_subentries.listAppend(ChecklistSubentryMake(pluralise(power_pills_remaining, "power pill", "power pills") + " obtainable", "", description)); + } + + if ($item[power pill].available_amount() > 0) + { + string header = $item[power pill].pluralise().capitaliseFirstLetter(); + int power_pill_uses_left = clampi(20 - get_property_int("_powerPillUses"), 0, 20); + if (power_pill_uses_left < $item[power pill].available_amount()) + { + if (power_pill_uses_left == 0) + header += " (not usable today)"; + else + header += " (" + power_pill_uses_left + " usable today)"; + } + resource_entries.listAppend(ChecklistEntryMake("__item power pill", "", ChecklistSubentryMake(header, "", "Use in combat to instakill without costing a turn.")).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Puck man familiar power pill free kill")); + } + } + if (yellow_pixel != $item[none] && yellow_pixel.available_amount() > 0 && in_ronin()) + { + string title = pluralise(yellow_pixel); + string [int] description; + url = "shop.php?whichshop=mystic"; //"place.php?whichplace=forestvillage&action=fv_mystic"; + //Pixel coin - 10 yellow pixels - 2k autosell (marginal) + //minature power pill - 15 yellow pixels - +100% all stats, 30 turns + //pixel star - 15 yellow pixels, 2 black pixels - 30 turns of +100% HP/MP/spell damage/weapon damage + //pixel banana - 10 yellow pixels, 1 black pixel - 2-size awesome food, 10 turns of +30% item + //pixel beer - 10 yellow pixels, 5 white pixels - 2-size awesome drunk, 10 turns of +3 stats/fight (15 mainstat) + boolean [item] items_to_always_show; + items_to_always_show[$item[yellow pixel potion]] = true; + if (!__misc_state["mysterious island available"]) + items_to_always_show[$item[yellow submarine]] = true; + + item [int] evalulation_order; + evalulation_order.listAppend($item[yellow pixel potion]); + evalulation_order.listAppend($item[pixel coin]); //before potions + + string [item] reasons; + reasons[$item[pixel coin]] = "Autosells for 2000 meat."; + reasons[$item[pixel star]] = "+100% HP/MP/spell/weapon damage. (30 turns)"; + reasons[$item[miniature power pill]] = "+100% stats. (30 turns)"; + reasons[$item[yellow pixel potion]] = "+20ML. (20 turns)"; + if (!__misc_state["mysterious island available"]) + reasons[$item[yellow submarine]] = "island unlock"; + //these (should) show up in mafia's consumption manager, so disabled + /*if (__misc_state["can eat just about anything"]) + reasons[$item[pixel banana]] = "2-size awesome food, 10 turns of +30% item."; + if (__misc_state["can drink just about anything"]) + reasons[$item[pixel beer]] = "2-size awesome drunk, 10 turns of +3 stats/fight.";*/ + + boolean [item] evaluated; + foreach key, it in evalulation_order + evaluated[it] = true; + foreach it in reasons + { + if (!(evaluated contains it)) + { + evaluated[it] = true; + evalulation_order.listAppend(it); + } + } + + foreach key, it in evalulation_order + { + string reason = reasons[it]; + if (reason.length() == 0) + continue; + if (it == $item[none]) + continue; + if (it.creatable_amount() == 0 && !items_to_always_show[it]) + continue; + string line; + line = it.capitaliseFirstLetter() + ": " + reason; + if (it.creatable_amount() == 0) + line = HTMLGenerateSpanFont(line, "grey"); + description.listAppend(line); + } + string [int] consumables; + if (__misc_state["can eat just about anything"]) + consumables.listAppend("food"); + if (__misc_state["can drink just about anything"]) + consumables.listAppend("drink"); + if (consumables.count() > 0) + { + string line = consumables.listJoinComponents(", ").capitaliseFirstLetter() + "."; + if ($item[yellow pixel].available_amount() < 10) + line = HTMLGenerateSpanFont(line, "grey"); + description.listAppend(line); + } + int importance = 9; + puck_subentries.listAppend(ChecklistSubentryMake(title, "", description)); + } + if (puck_subentries.count() > 0) + { + resource_entries.listAppend(ChecklistEntryMake("__familiar " + relevant_familiar, url, puck_subentries, 9).ChecklistEntrySetIDTag("Puck man familiar resource")); + } + +} + +void SFamiliarsGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (__misc_state["free runs usable"] && ($familiar[pair of stomping boots].familiar_is_usable() || ($skill[the ode to booze].skill_is_usable() && $familiar[Frumious Bandersnatch].familiar_is_usable()))) + { + int runaways_used = get_property_int("_banderRunaways"); + string name = runaways_used + " familiar runaways used"; + string [int] description; + string image_name = ""; + + string url = ""; + + if ($familiar[Frumious Bandersnatch].familiar_is_usable() && $skill[the ode to booze].skill_is_usable()) + { + image_name = "Frumious Bandersnatch"; + } + else if ($familiar[pair of stomping boots].familiar_is_usable()) + { + image_name = "pair of stomping boots"; + } + + if (!($familiars[Frumious Bandersnatch, pair of stomping boots] contains my_familiar())) + url = "familiar.php"; + + if (my_path().id != PATH_HEAVY_RAINS) + { + int snow_suit_runs = floor(numeric_modifier($item[snow suit], "familiar weight") / 5.0); + + if ($item[snow suit].available_amount() == 0) + snow_suit_runs = 0; + + if (snow_suit_runs >= 2) + description.listAppend("Snow Suit available (+" + snow_suit_runs + " runs)"); + else if ($item[sugar shield].available_amount() > 0) + description.listAppend("Sugar shield available (+2 runs)"); + } + + resource_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Bander-like familiar free run")); + } + + if (true) + { + int hipster_fights_available = __misc_state_int["hipster fights available"]; + + if (($familiar[artistic goth kid].familiar_is_usable() || $familiar[Mini-Hipster].familiar_is_usable()) && hipster_fights_available > 0 && my_path().id != PATH_LIVE_ASCEND_REPEAT && my_path().id != PATH_G_LOVER) + { + string name = ""; + string [int] description; + string hipster_image = __misc_state_string["hipster name"]; + + string hipster_name = __misc_state_string["hipster name"]; + if ($familiar[artistic goth kid].familiar_is_usable() && $familiar[Mini-Hipster].familiar_is_usable()) + { + hipster_name = "goth kid / mini-hipster"; + hipster_image = "__familiar Mini-hipster"; + } + + name = pluralise(hipster_fights_available, __misc_state_string["hipster name"] + " fight", hipster_name + " fights"); + + int [int] hipster_chances; + hipster_chances[7] = 50; + hipster_chances[6] = 40; + hipster_chances[5] = 30; + hipster_chances[4] = 20; + hipster_chances[3] = 10; + hipster_chances[2] = 10; + hipster_chances[1] = 10; + + string url = ""; + if (!($familiars[artistic goth kid,mini-hipster] contains my_familiar())) + url = "familiar.php"; + + description.listAppend(hipster_chances[hipster_fights_available] + "% chance of appearing."); + int importance = 0; + if (!__misc_state["in run"]) + importance = 6; + resource_entries.listAppend(ChecklistEntryMake(hipster_image, url, ChecklistSubentryMake(name, "", description), importance).ChecklistEntrySetIDTag("Hipster-like familiar hipster fights")); + } + } + + + if ($familiar[nanorhino].familiar_is_usable() && get_property_int("_nanorhinoCharge") == 100 && my_path().id != PATH_G_LOVER) + { + ChecklistSubentry [int] subentries; + string [int] description_banish; + + string url = ""; + + if (my_familiar() != $familiar[nanorhino]) + url = "familiar.php"; + + boolean tag_with_banish_tag = false; + if (get_property("_nanorhinoBanishedMonster") != "") description_banish.listAppend(get_property("_nanorhinoBanishedMonster").HTMLEscapeString().capitaliseFirstLetter() + " currently banished."); + if (get_property_int("_nanorhinoCharge") >= 100) + { + tag_with_banish_tag = true; + description_banish.listAppend("All day. Cast muscle combat skill" + (my_familiar() == $familiar[nanorhino] ? "" : " with nanorhino as your familiar") + "."); + } + if (__misc_state["have muscle class combat skill"]) + { + if (tag_with_banish_tag) + resource_entries.listAppend(ChecklistEntryMake("__familiar nanorhino", "", ChecklistSubentryMake("Nanorhino Banish", "", description_banish), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Nanorhino familiar banish")); + else + subentries.listAppend(ChecklistSubentryMake("Nanorhino Banish", "", description_banish)); + } + if (__misc_state["need to level"] && __misc_state["have mysticality class combat skill"]) + subentries.listAppend(ChecklistSubentryMake("Nanorhino Gray Goo", "", "130? mainstat, fire against non-item monster with >90 attack. Cast mysticality combat skill.")); + if (!$familiar[he-boulder].familiar_is_usable() && __misc_state["have moxie class combat skill"] && __misc_state["in run"]) + { + if ($effect[everything looks yellow].have_effect() > 0) + subentries.listAppend(ChecklistSubentryMake(HTMLGenerateSpanFont("Nanorhino Yellow Ray", "gray"), "", HTMLGenerateSpanFont("Cast moxie combat skill once everything looks yellow is gone.", "gray"))); + else + subentries.listAppend(ChecklistSubentryMake("Nanorhino Yellow Ray", "", "Cast moxie combat skill.")); + } + if (subentries.count() > 0) + resource_entries.listAppend(ChecklistEntryMake("__familiar nanorhino", url, subentries, 5).ChecklistEntrySetIDTag("Nanorhino familiar use charge")); + } + if (__misc_state["yellow ray available"] && !__misc_state["in run"]) //in-run version in Misc Tasks.ash + { + resource_entries.listAppend(ChecklistEntryMake(__misc_state_string["yellow ray image name"], "", ChecklistSubentryMake("Yellow ray available", "", "From " + __misc_state_string["yellow ray source"] + "."), 6).ChecklistEntrySetIDTag("Yellow-ray resource")); + } + + if (my_familiar() == $familiar[happy medium] || $familiar[happy medium].charges > 0 && $familiar[happy medium].familiar_is_usable()) //|| stuff + { + //FIXME request support for tracking medium combats. + string title; + string [int] description; + + int charges = $familiar[happy medium].charges; + int siphons = get_property_int("_mediumSiphons"); + + int adventures_to_next_at_most = 3 + siphons; + + if (charges == 3) + { + title = "Red medium"; + description.listAppend("4.25 turns/drunkenness."); + } + else if (charges == 2) + { + title = "Orange medium"; + description.listAppend("3.25 turns/drunkenness."); + description.listAppend(pluraliseWordy(adventures_to_next_at_most, "turn", "turns").capitaliseFirstLetter() + " (at most) to red."); + } + else if (charges == 1) + { + title = "Blue medium"; + description.listAppend("2.25 turns/drunkenness."); + description.listAppend(pluraliseWordy(adventures_to_next_at_most, "turn", "turns").capitaliseFirstLetter() + " (at most) to orange."); + } + else + { + title = "Uncharged medium"; + description.listAppend(pluraliseWordy(adventures_to_next_at_most, "turn", "turns").capitaliseFirstLetter() + " (at most) to blue. "); + } + string url; + if (my_familiar() != $familiar[happy medium]) + url = "familiar.php"; + + int importance = 6; + if (my_familiar() == $familiar[happy medium] || charges > 0) + importance = 0; + resource_entries.listAppend(ChecklistEntryMake("__familiar happy medium", url, ChecklistSubentryMake(title, "", description), importance).ChecklistEntrySetIDTag("Happy medium familiar siphon")); + } + if (my_familiar() == $familiar[steam-powered cheerleader] || $familiar[steam-powered cheerleader].familiar_is_usable() && get_property_int("_cheerleaderSteam") < 200) + { + string title; + string [int] description; + + int steam_remaining = get_property_int("_cheerleaderSteam"); + float multiplier = 1.0; + float next_multiplier_level = 1.0; + + int next_steam_level = 0; + + boolean has_socket_set = $familiar[steam-powered cheerleader].familiar_equipped_equipment() == $item[school spirit socket set]; + + if (steam_remaining >= 151) + { + multiplier = 1.4; + next_multiplier_level = 1.3; + next_steam_level = 150; + } + else if (steam_remaining >= 101) + { + multiplier = 1.3; + next_multiplier_level = 1.2; + next_steam_level = 100; + } + else if (steam_remaining >= 51) + { + multiplier = 1.2; + next_multiplier_level = 1.1; + next_steam_level = 50; + } + else if (steam_remaining >= 1) + { + multiplier = 1.1; + next_multiplier_level = 1.0; + next_steam_level = 0; + } + + int steam_at_this_level_remaining = steam_remaining - next_steam_level; + int turns_remaining_at_this_level = steam_at_this_level_remaining; + if (!has_socket_set) + turns_remaining_at_this_level = turns_remaining_at_this_level / 2; + + + + title = multiplier + "x fairy steam-powered cheerleader"; + + if (turns_remaining_at_this_level > 0) + description.listAppend(pluralise(turns_remaining_at_this_level, "turn remains", "turns remain") + " until " + next_multiplier_level + "x."); + + int importance = 6; + if (my_familiar() == $familiar[steam-powered cheerleader]) + importance = 0; + + + string url; + if (my_familiar() != $familiar[steam-powered cheerleader]) + url = "familiar.php"; + + + resource_entries.listAppend(ChecklistEntryMake("__familiar steam-powered cheerleader", url, ChecklistSubentryMake(title, "", description), importance).ChecklistEntrySetIDTag("Steam-powered cheerleader familiar steam")); + } + + if ($familiar[grim brother].familiar_is_usable() && !get_property_boolean("_grimBuff") && __misc_state["in run"]) //in aftercore, let the maximizer handle it? + { + string title; + string [int] description; + string url = "familiar.php?action=chatgrim&pwd=" + my_hash(); + + title = "Chat with grim brother"; + + description.listAppend("30 turns of +20% init or +HP/MP or +damage."); + int importance = 9; + resource_entries.listAppend(ChecklistEntryMake("__familiar grim brother", url, ChecklistSubentryMake(title, "", description), importance).ChecklistEntrySetIDTag("Grim brother familiar buff")); + } + + + SFamiliarsPuckGenerateResource(resource_entries); + + //FIXME small medium, organ grinder, charged boots + SFamiliarsGenerateEntry(resource_entries, resource_entries, false); +} + +void SFamiliarsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_familiar() == $familiar[none] && !__misc_state["single familiar run"] && !__misc_state["familiars temporarily blocked"] && !($locations[The Bandit Crossroads,The Towering Mountains,The Mystic Wood,The Putrid Swamp,The Cursed Village,The Sprawling Cemetery,The Old Rubee Mine,The Foreboding Cave,The Faerie Cyrkle,The Druidic Campsite,Near the Witch's House,The Evil Cathedral,The Barrow Mounds,The Cursed Village Thieves' Guild,The Troll Fortress,The Labyrinthine Crypt,The Lair of the Phoenix,The Dragon's Moor,Duke Vampire's Chateau,The Master Thief's Chalet,The Spider Queen's Lair,The Archwizard's Tower,The Ley Nexus,The Ghoul King's Catacomb,The Ogre Chieftain's Keep] contains __last_adventure_location)) + { + string image_name = "black cat"; + optional_task_entries.listAppend(ChecklistEntryMake(image_name, "familiar.php", ChecklistSubentryMake("Bring along a familiar", "", "")).ChecklistEntrySetIDTag("Bring familiar reminder")); + } + + if ($familiar[Crimbo Shrub].familiar_is_usable() && my_path().id != PATH_G_LOVER) + { + boolean configured = get_property("shrubGarland") != "" || get_property("shrubGifts") != "" || get_property("shrubLights") != "" || get_property("shrubTopper") != ""; + if (my_daycount() == 1 && get_property("_shrubDecorated") == "false") //default configuration exists, but + configured = false; + if (!configured && (__misc_state["in run"] || my_familiar() == $familiar[Crimbo Shrub]) && get_property("_shrubDecorated") == "false") + { + string [int] description; + + string [int] configuration_idea; + if (my_primestat() == $stat[muscle]) + configuration_idea.listAppend("Veiny Star"); + else if (my_primestat() == $stat[mysticality]) + configuration_idea.listAppend("LED Mandala"); + else if (my_primestat() == $stat[moxie]) + configuration_idea.listAppend("Angel With Sunglasses"); + + configuration_idea.listAppend("Frosted Lights"); //random pick really + + if (hippy_stone_broken()) + configuration_idea.listAppend("Barbed Wire"); + else + configuration_idea.listAppend("Popcorn Strands"); + + if (!__misc_state["yellow ray potentially available"] && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) //you really want the meat one in WOTSF (this works!) + configuration_idea.listAppend("Big Yellow-Wrapped Presents"); + else + configuration_idea.listAppend("Big Red-Wrapped Presents"); + + description.listAppend("Maybe " + configuration_idea.listJoinComponents(" / ") + "?"); + + string url = "familiar.php"; + + if ($item[box of old Crimbo decorations].available_amount() > 0) + url = "inv_use.php?pwd=" + my_hash() + "&whichitem=7958"; + + optional_task_entries.listAppend(ChecklistEntryMake("__item box of old Crimbo decorations", url, ChecklistSubentryMake("Configure your Crimbo Shrub", "", description), 6).ChecklistEntrySetIDTag("Crimbo shrub familiar decorate")); + } + /* + shrubGarland(user, now 'PvP', default ) + shrubGifts(user, now 'meat', default ) + shrubLights(user, now 'Cold', default ) + shrubTopper(user, now 'Moxie', default ) + */ + } + + SFamiliarsGenerateEntry(task_entries, optional_task_entries, true); +} + +void SDispensaryGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //Not sure how I feel about this. The dispensary is very useful, but not necessary to complete an ascension. + if (dispensary_available()) + return; + //It's even less useful now that they've changed the buffs. Sorry, dispensary. + if (true) + return; + if (!__misc_state["can equip just about any weapon"]) //need to wear KGE to learn the password + return; + + if (!__quest_state["Level 5"].started || !$location[cobb's knob barracks].locationAvailable()) + return; + if (__quest_state["Level 5"].finished && !have_outfit_components("Knob Goblin Elite Guard Uniform")) //level 5 quest completed, but they don't have KGE - I think we'll close the suggestion here, as they probably don't want to go back? maybe? it'll still show up in semi-rare if they care to + return; + if (!have_outfit_components("Knob Goblin Elite Guard Uniform") && __misc_state["in run"]) //don't bother unless they have the uniform + return; + + ChecklistSubentry subentry; + subentry.header = "Unlock Cobb's Knob Dispensary"; + + string [int] dispensary_advantages; + if (!black_market_available() && !__misc_state["MMJs buyable"]) + dispensary_advantages.listAppend("MP Restorative"); + dispensary_advantages.listAppend("+30% meat"); + dispensary_advantages.listAppend("+15% items"); + if (my_path().id != PATH_BEES_HATE_YOU && !__misc_state["familiars temporarily blocked"]) + dispensary_advantages.listAppend("+5 familiar weight"); + dispensary_advantages.listAppend("+1 mainstat/fight"); + + if (dispensary_advantages.count() > 0) + subentry.entries.listAppend("Access to " + dispensary_advantages.listJoinComponents(", ", "and") + " buff items."); + + if ($item[Cobb's Knob lab key].available_amount() == 0) + subentry.entries.listAppend("Find the cobb's knob lab key either laying around, or defeat the goblin king."); + else + { + if (have_outfit_components("Knob Goblin Elite Guard Uniform")) + { + if (!is_wearing_outfit("Knob Goblin Elite Guard Uniform")) + subentry.entries.listAppend("Wear KGE outfit, adventure in Cobb's Knob Barracks."); + else + subentry.entries.listAppend("Adventure in Cobb's Knob Barracks."); + } + else + subentry.entries.listAppend("Acquire KGE outfit"); + } + optional_task_entries.listAppend(ChecklistEntryMake("Dispensary", "cobbsknob.php", subentry, 10).ChecklistEntrySetIDTag("Dispensary cobb knob")); +} + +string [int] SSkillsPotentialCraftingOptions() +{ + string [int] potential_options; + if ($item[knob cake].available_amount() == 0 && !__quest_state["Level 6"].finished && my_path().id != PATH_COMMUNITY_SERVICE) + potential_options.listAppend("knob cake"); + if (__misc_state["can eat just about anything"]) + potential_options.listAppend("food"); + if (__misc_state["can drink just about anything"]) + potential_options.listAppend("drink"); + if ($skill[advanced saucecrafting].skill_is_usable()) + potential_options.listAppend("sauceror potions"); + return potential_options; +} + +void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (skill_is_usable($skill[inigo's incantation of inspiration])) { + int inigos_casts_remaining = 5 - get_property_int("_inigosCasts"); + string description = SSkillsPotentialCraftingOptions().listJoinComponents(", ").capitaliseFirstLetter(); + if (inigos_casts_remaining > 0) + resource_entries.listAppend(ChecklistEntryMake("__effect Inigo's Incantation of Inspiration", "skills.php", ChecklistSubentryMake(pluralise(inigos_casts_remaining, "Inigo's cast", "Inigo's casts") + " remaining", "", description), 4).ChecklistEntrySetIDTag("Inigo inspiration skill reminder")); + } + if (true) { + ChecklistEntry craft_entry; + craft_entry.image_lookup_name = "__item tenderizing hammer"; + craft_entry.url = "craft.php?mode=discoveries"; + craft_entry.tags.id = "Free crafts resource"; + craft_entry.importance_level = 4; + + int free_crafts_left = 0; + int free_cooks_left = 0; + int free_mixes_left = 0; + if ($effect[Inigo's Incantation of Inspiration].have_effect() >= 5) { + free_crafts_left += $effect[Inigo's Incantation of Inspiration].have_effect() / 5; + } + if ($effect[craft tea].have_effect() >= 5) { + free_crafts_left += $effect[craft tea].have_effect() / 5; + } + if ($skill[rapid prototyping].skill_is_usable()) { + free_crafts_left += clampi(5 - get_property_int("_rapidPrototypingUsed"), 0, 5); + } + if (lookupSkill("Expert Corner-Cutter").skill_is_usable()) { + free_crafts_left += clampi(5 - get_property_int("_expertCornerCutterUsed"), 0, 5); + } + if (get_property_int("homebodylCharges") > 0) { + free_crafts_left += (get_property_int("homebodylCharges")); + } + // adding cookbookbat free crafts into crafting tile + if (lookupFamiliar("Cookbookbat").familiar_is_usable()) { + string [int] description; + free_cooks_left += clampi(5 - get_property_int("_cookbookbatCrafting"), 0, 5); + string title = "free cooking"; + if (free_cooks_left > 0) { + craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_cooks_left, title, title + "s") + " remaining", free_crafts_left > 0 ? "COOKING only" : "", description)); + } + } + // holiday multitasking + if (lookupSkill("Holiday Multitasking").skill_is_usable()) { + free_crafts_left += clampi(3 - get_property_int("_holidayMultitaskingUsed"), 0, 3); + } + // elf guard cooking + if (lookupSkill("Elf Guard Cooking").skill_is_usable()) { + string [int] description; + free_cooks_left += clampi(3 - get_property_int("_elfGuardCookingUsed"), 0, 3); + string title = "free cooking"; + if (free_cooks_left > 0) { + craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_cooks_left, title, title + "s") + " remaining", free_crafts_left > 0 ? "COOKING only" : "", description)); + } + } + // cocktails of the age of sail + if (lookupSkill("Old-School Cocktailcrafting").skill_is_usable()) { + string [int] description; + free_mixes_left += clampi(3 - get_property_int("_oldSchoolCocktailCraftingUsed"), 0, 3); + string title = "free mixing"; + if (free_mixes_left > 0) { + craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_mixes_left, title, title + "s") + " remaining", free_crafts_left > 0 ? "MIXING only" : "", description)); + } + } + + int free_smiths_left = 0; + if (__campground[$item[warbear auto-anvil]] > 0) { + free_smiths_left += clampi(5 - get_property_int("_warbearAutoAnvilCrafting"), 0, 5); + } + int jackhammer_crafts_later = 0; + if ($items[Loathing Legion abacus,Loathing Legion can opener,Loathing Legion chainsaw,Loathing Legion corkscrew,Loathing Legion defibrillator,Loathing Legion double prism,Loathing Legion electric knife,Loathing Legion flamethrower,Loathing Legion hammer,Loathing Legion helicopter,Loathing Legion jackhammer,Loathing Legion kitchen sink,Loathing Legion knife,Loathing Legion many-purpose hook,Loathing Legion moondial,Loathing Legion necktie,Loathing Legion pizza stone,Loathing Legion rollerblades,Loathing Legion tape measure,Loathing Legion tattoo needle,Loathing Legion universal screwdriver,Loathing Legion Knife].available_amount() > 0) { + int jackhammer_crafts = clampi(3 - get_property_int("_legionJackhammerCrafting"), 0, 3); + if ($item[Loathing Legion jackhammer].available_amount() == 0) + jackhammer_crafts_later = jackhammer_crafts; + else + free_smiths_left += jackhammer_crafts; + } + if ($item[Thor's Pliers].available_amount() > 0) { + free_smiths_left += clampi(10 - get_property_int("_thorsPliersCrafting"), 0, 10); + } + if (free_smiths_left > 0 || jackhammer_crafts_later > 0) { + craft_entry.url = "craft.php?mode=discoveries&what=smith"; + //free_smiths_left += free_crafts_left; //naaaah + //FIXME remind them to buy a hammer (if no loathing jackhammer) + string [int] description; + if (jackhammer_crafts_later > 0) + description.listAppend("Get " + jackhammer_crafts_later + " more by folding your loathing legion knife into jackhammer."); + string title = "free smithing"; + if (knoll_available()) //innabox makes normal smithing free + title = "free advanced smithing"; + craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_smiths_left, title, title + "s") + " remaining", free_crafts_left > 0 ? "SMITHING only" : "", description)); + } + + if (free_crafts_left > 0) { + string description = SSkillsPotentialCraftingOptions().listJoinComponents(", ").capitaliseFirstLetter(); + craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_crafts_left, "free craft", "free crafts") + " remaining", free_smiths_left > 0 || jackhammer_crafts_later > 0 ? "Any crafting mode, including smithing" : "", description)); + } + + if (craft_entry.subentries.count() > 0) + resource_entries.listAppend(craft_entry); + } + + ChecklistSubentry [int] subentries; + int importance = 11; + string url; + + string [skill] skills_to_details; + string [skill] skills_to_urls; + string [skill] skills_to_title_notes; + skill [string][int] property_summons_to_skills; + int [string] property_summon_limits; + + property_summon_limits["reagentSummons"] = 1; + property_summon_limits["noodleSummons"] = 1; + property_summon_limits["cocktailSummons"] = 1; + property_summon_limits["grimoire1Summons"] = 1; + property_summon_limits["grimoire2Summons"] = 1; + property_summon_limits["grimoire3Summons"] = 1; + property_summon_limits["_grimoireGeekySummons"] = 1; + property_summon_limits["_grimoireConfiscatorSummons"] = 1; + property_summon_limits["_candySummons"] = 1; + + if ($skill[advanced saucecrafting].have_skill() && $skill[advanced saucecrafting].skill_is_usable()) + property_summons_to_skills["reagentSummons"] = listMake($skill[advanced saucecrafting], $skill[the way of sauce]); + if ($skill[Pastamastery].have_skill() && $skill[Pastamastery].skill_is_usable()) + property_summons_to_skills["noodleSummons"] = listMake($skill[Pastamastery], $skill[Transcendental Noodlecraft]); + if ($skill[Advanced Cocktailcrafting].have_skill() && $skill[Advanced Cocktailcrafting].skill_is_usable()) + property_summons_to_skills["cocktailSummons"] = listMake($skill[Advanced Cocktailcrafting], $skill[Superhuman Cocktailcrafting]); + property_summons_to_skills["_coldOne"] = listMake($skill[Grab a Cold One]); + property_summons_to_skills["_spaghettiBreakfast"] = listMake($skill[spaghetti breakfast]); + property_summons_to_skills["_discoKnife"] = listMake($skill[that's not a knife]); + property_summons_to_skills["_lunchBreak"] = listMake($skill[lunch break]); + property_summons_to_skills["_psychokineticHugUsed"] = listMake($skill[Psychokinetic Hug]); + property_summons_to_skills["_pirateBellowUsed"] = listMake($skill[Pirate Bellow]); + property_summons_to_skills["_holidayFunUsed"] = listMake($skill[Summon Holiday Fun!]); + property_summons_to_skills["_summonCarrotUsed"] = listMake($skill[Summon Carrot]); + property_summons_to_skills["_summonAnnoyanceUsed"] = listMake($skill[summon annoyance]); + property_summons_to_skills["_perfectFreezeUsed"] = listMake($skill[Perfect Freeze]); + property_summons_to_skills["_communismUsed"] = listMake($skill[Communism!]); + property_summons_to_skills["_preventScurvy"] = listMake(lookupSkill("Prevent Scurvy and Sobriety")); + + skills_to_title_notes[$skill[summon annoyance]] = get_property_int("summonAnnoyanceCost") + " swagger"; + + + + + + if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) { + property_summons_to_skills["_petePartyThrown"] = listMake($skill[Throw Party]); + property_summons_to_skills["_peteRiotIncited"] = listMake($skill[Incite Riot]); + + int audience_max = 30; + int hate_useful_max = 25; //ashes and soda max out early; more audience hatred only gives crates and grenades, not of absolute importance + if ($item[Sneaky Pete's leather jacket].equipped_amount() > 0 || $item[Sneaky Pete's leather jacket (collar popped)].equipped_amount() > 0) { + audience_max = 50; + hate_useful_max = 41; + } + + if (my_audience() < audience_max) + skills_to_details[$skill[Throw Party]] = "Ideally have " + audience_max + " audience love before casting."; + else + skills_to_details[$skill[Throw Party]] = "Gain party supplies."; + + if (my_audience() > -hate_useful_max) + skills_to_details[$skill[Incite Riot]] = "Ideally have " + hate_useful_max + " audience hate before casting."; + else + skills_to_details[$skill[Incite Riot]] = "This fire is out of control"; + } + if (my_path().id == PATH_AVATAR_OF_JARLSBERG) { + property_summons_to_skills["_jarlsCreamSummoned"] = listMake($skill[Conjure Cream]); + property_summons_to_skills["_jarlsEggsSummoned"] = listMake($skill[Conjure Eggs]); + property_summons_to_skills["_jarlsDoughSummoned"] = listMake($skill[Conjure Dough]); + property_summons_to_skills["_jarlsVeggiesSummoned"] = listMake($skill[Conjure Vegetables]); + property_summons_to_skills["_jarlsCheeseSummoned"] = listMake($skill[Conjure Cheese]); + property_summons_to_skills["_jarlsPotatoSummoned"] = listMake($skill[Conjure Potato]); + property_summons_to_skills["_jarlsMeatSummoned"] = listMake($skill[Conjure Meat Product]); + property_summons_to_skills["_jarlsFruitSummoned"] = listMake($skill[Conjure Fruit]); + } + if (my_path().id == PATH_AVATAR_OF_BORIS) { + property_summons_to_skills["_demandSandwich"] = listMake($skill[Demand Sandwich]); + property_summon_limits["_demandSandwich"] = 3; + } + + property_summons_to_skills["_requestSandwichSucceeded"] = listMake($skill[Request Sandwich]); + + property_summons_to_skills["grimoire1Summons"] = listMake($skill[Summon Hilarious Objects]); + property_summons_to_skills["grimoire2Summons"] = listMake($skill[Summon Tasteful Items]); + property_summons_to_skills["grimoire3Summons"] = listMake($skill[Summon Alice's Army Cards]); + property_summons_to_skills["_grimoireGeekySummons"] = listMake($skill[Summon Geeky Gifts]); + if (mafiaIsPastRevision(14300)) { + property_summons_to_skills["_grimoireConfiscatorSummons"] = listMake($skill[Summon Confiscated Things]); + skills_to_urls[$skill[Summon Confiscated Things]] = "campground.php?action=bookshelf"; + } + property_summons_to_skills["_candySummons"] = listMake($skill[Summon Crimbo Candy]); + property_summons_to_skills["_summonResortPassesUsed"] = listMake($skill[Summon Kokomo Resort Pass]); + property_summons_to_skills["_incredibleSelfEsteemCast"] = listMake(lookupSkill("Incredible Self-Esteem")); + skills_to_details[lookupSkill("Incredible Self-Esteem")] = "Gives or extends affirmation buffs."; + if (__misc_state["in run"] && lookupItem("Daily Affirmation: Always be Collecting").available_amount() > 0 && lookupItem("Daily Affirmation: Always be Collecting").to_effect().have_effect() == 0) + skills_to_details[lookupSkill("Incredible Self-Esteem")] += "|Possibly use Always be Collecting affirmation before casting."; + + foreach s in $skills[Summon Hilarious Objects,Summon Tasteful Items,Summon Alice's Army Cards,Summon Geeky Gifts] + skills_to_urls[s] = "campground.php?action=bookshelf"; + + + + int muscle_basestat = my_basestat($stat[muscle]); + item summoned_knife = $item[none]; + if (muscle_basestat < 10) + summoned_knife = $item[boot knife]; + else if (muscle_basestat < 20) + summoned_knife = $item[broken beer bottle]; + else if (muscle_basestat < 40) + summoned_knife = $item[sharpened spoon]; + else if (muscle_basestat < 60) + summoned_knife = $item[candy knife]; + else + summoned_knife = $item[soap knife]; + if (summoned_knife.available_amount() > 0 && summoned_knife != $item[none]) { + //already have the knife, don't annoy them: + //(or ask them to closet the knife?) + remove property_summons_to_skills["_discoKnife"]; + //skills_to_details[$skill[that's not a knife]] = "Closet " + summoned_knife + " first."; + } + + foreach property in property_summons_to_skills { + if (property_summon_limits[property] != 0 && get_property_int(property) >= property_summon_limits[property] || get_property_boolean(property)) + continue; + foreach key in property_summons_to_skills[property] { + skill s = property_summons_to_skills[property][key]; + if (!s.skill_is_usable()) + continue; + + string line = s.to_string(); + string [int] description; + if (s.mp_cost() > 0) { + line += " (" + s.mp_cost() + " MP)"; + //description.listAppend(s.mp_cost() + " MP"); + } + if (skills_to_title_notes contains s) { + line += " (" + skills_to_title_notes[s] + " )"; + } + string details = skills_to_details[s]; + if (details != "") + description.listAppend(details); + + + if (url.length() == 0) { + if (skills_to_urls contains s) + url = skills_to_urls[s]; + else + url = "skills.php"; + } + + subentries.listAppend(ChecklistSubentryMake(line, "", description)); + break; + } + } + + if (subentries.count() > 0) { + subentries.listPrepend(ChecklistSubentryMake("Skill summons:")); + ChecklistEntry entry = ChecklistEntryMake("__item Knob Goblin love potion", url, subentries, importance); + entry.tags.id = "Daily summon skills resource"; + entry.should_indent_after_first_subentry = true; + resource_entries.listAppend(entry); + } + + + if (lookupSkill("Evoke Eldritch Horror").skill_is_usable() && !get_property_boolean("_eldritchHorrorEvoked")) { + resource_entries.listAppend(ChecklistEntryMake("__skill Evoke Eldritch Horror", "skillz.php", ChecklistSubentryMake("Evoke Eldritch Horror", "", "Free fight."), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Evoke eldritch horror skill free fight")); + } + if (!get_property_boolean("_eldritchTentacleFought") && my_path().id != PATH_EXPLOSIONS && my_path().id != PATH_COMMUNITY_SERVICE) { + resource_entries.listAppend(ChecklistEntryMake("__skill Evoke Eldritch Horror", "place.php?whichplace=forestvillage&action=fv_scientist", ChecklistSubentryMake("Science Tent Tentacle", "", "Free fight."), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Daily forest tentacle free fight")); + } + +} + + +void SMiscItemsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[the crown of ed the undying].equipped_amount() > 0 && get_property("edPiece").length() == 0) { + string [int] description; + + if (__misc_state["need to level"]) { + if (my_primestat() == $stat[muscle]) + description.listAppend("Bear - +2 mainstat/fight"); + else if (my_primestat() == $stat[mysticality]) + description.listAppend("Owl - +2 mainstat/fight"); + else if (my_primestat() == $stat[moxie]) + description.listAppend("Puma - +2 mainstat/fight"); + description.listAppend("Hyena - +20 ML"); + } + description.listAppend("Mouse - +10% item, +20% meat"); + description.listAppend("Weasel - survive first hit, regenerate HP"); + optional_task_entries.listAppend(ChecklistEntryMake("__item the crown of ed the undying", "inventory.php?action=activateedhat", ChecklistSubentryMake("Configure the Crown of Ed the Undying", "", description), 5).ChecklistEntrySetIDTag("UNDYING crown config")); + } + + if (__misc_state["in run"]) { + //Suggest acquiring a stasis source: + //If you're not in ronin, you should acquire a source from hangk's. + //If you are: suckerpunch as DB -> dictionary -> facsimile dictionary -> seal tooth + + boolean currently_have_source = false; + if (my_class() == $class[disco bandit]) + currently_have_source = true; + else if ($items[dictionary,facsimile dictionary,seal tooth].item_amount() > 0) + currently_have_source = true; + + boolean have_reason = false; + //Try not to annoy anyone that doesn't currently have a reason to stasis: + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) //to always trigger the underworld + have_reason = true; + if ($effect[everything looks yellow].have_effect() == 0 && $familiar[he-boulder].familiar_is_usable()) //to reach the correct eye + have_reason = true; + if ($familiars[stocking mimic,cocoabo,star starfish,Animated Macaroni Duck,Midget Clownfish,Rock Lobster,Snow Angel,Twitching Space Critter,slimeling,mini-hipster] contains my_familiar()) //MP delaying. grill intentionally left off, because it doesn't act as often in later rounds(?) + have_reason = true; + if (__quest_state["Level 12"].state_boolean["War started"] && __quest_state["Level 12"].in_progress && !__quest_state["Level 12"].state_boolean["Junkyard Finished"]) + have_reason = true; + + if (!currently_have_source && have_reason) { + boolean try_for_seal_tooth = false; + if (in_ronin()) { + item pull_item = $item[none]; + foreach it in $items[dictionary,facsimile dictionary,seal tooth] { + if (it.available_amount() > 0) { + pull_item = it; + break; + } + } + if (pull_item != $item[none]) { + string [int] description; + description.listAppend("Useful for delaying in-fight."); + optional_task_entries.listAppend(ChecklistEntryMake("__item " + pull_item, "storage.php?which=3", ChecklistSubentryMake("Pull a " + pull_item, "", description), 5).ChecklistEntrySetIDTag("Stasis item suggestions pull")); + } else + try_for_seal_tooth = true; + } else { + try_for_seal_tooth = true; + } + if (my_path().id == PATH_NUCLEAR_AUTUMN) + try_for_seal_tooth = false; + + if (try_for_seal_tooth) { + string url = ""; + string [int] description; + if ($items[worthless trinket,worthless gewgaw,worthless knick-knack].available_amount() == 0) { + url = "shop.php?whichshop=generalstore"; + description.listAppend("Use chewing gum on a string."); + } else { + url = "hermit.php"; + description.listAppend("From the hermit."); + } + + description.listAppend("Useful for delaying in-fight."); + optional_task_entries.listAppend(ChecklistEntryMake("__item seal tooth", url, ChecklistSubentryMake("Acquire a seal tooth", "", description), 5).ChecklistEntrySetIDTag("Stasis item suggestions seal tooth")); + } + } + } +} + +void SMiscItemsGenerateResource(ChecklistEntry [int] resource_entries) +{ + int importance_level_item = 7; + int importance_level_unimportant_item = 8; + + boolean in_run = __misc_state["in run"] && in_ronin(); + + int navel_percent_chance_of_runaway = 20; + if (true) { + //Look up navel ring chances: + int [int] navel_ring_runaway_chance; + navel_ring_runaway_chance[0] = 100; + navel_ring_runaway_chance[1] = 100; + navel_ring_runaway_chance[2] = 100; + navel_ring_runaway_chance[3] = 80; + navel_ring_runaway_chance[4] = 80; + navel_ring_runaway_chance[5] = 80; + navel_ring_runaway_chance[6] = 50; + navel_ring_runaway_chance[7] = 50; + navel_ring_runaway_chance[8] = 50; + navel_ring_runaway_chance[9] = 20; + int navel_runaway_progress = get_property_int("_navelRunaways"); + + if (navel_ring_runaway_chance contains navel_runaway_progress) + navel_percent_chance_of_runaway = navel_ring_runaway_chance[navel_runaway_progress]; + } + boolean have_navel_type_equipment = false; + if (__iotms_usable[lookupItem("navel ring of navel gazing")]) { + have_navel_type_equipment = true; + string name = "Navel Ring runaways"; + + string url = ""; + if ($item[navel ring of navel gazing].equipped_amount() == 0) + url = "inventory.php?ftext=navel+ring+of+navel+gazing"; + + string [int] description; + description.listAppend(navel_percent_chance_of_runaway + "% chance of free runaway."); + resource_entries.listAppend(ChecklistEntryMake("__item navel ring of navel gazing", url, ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Navel ring of navel gazing")); + } + if (__iotms_usable[lookupItem("Greatest American Pants")]) { + have_navel_type_equipment = true; + string name = "Greatest American Pants"; + + string url = ""; + if ($item[greatest american pants].equipped_amount() == 0) + url = "inventory.php?ftext=greatest+american+pants"; + else + url = "inventory.php?action=activatesuperpants"; + + string [int] description; + description.listAppend(navel_percent_chance_of_runaway + "% chance of free runaway."); + + int buffs_remaining = 5 - get_property_int("_gapBuffs"); + if (buffs_remaining > 0) + description.listAppend(pluralise(buffs_remaining, "buff", "buffs") + " remaining."); + resource_entries.listAppend(ChecklistEntryMake("__item greatest american pants", url, ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Greatest american pants")); + } + if ($item[peppermint parasol].available_amount() > 0 && in_run && !have_navel_type_equipment) { + int parasol_progress = get_property_int("parasolUsed"); + string name = ""; + + name = parasol_progress + "/10 peppermint parasol uses"; + string [int] description; + description.listAppend(navel_percent_chance_of_runaway + "% chance of free runaway."); + resource_entries.listAppend(ChecklistEntryMake("__item peppermint parasol", "", ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Peppermint parasol resource")); + } + if ($item[pantsgiving].available_amount() > 0) { + ChecklistSubentry subentry = ChecklistSubentryMake("Pantsgiving", "", ""); + + string url = ""; + + if ($item[pantsgiving].equipped_amount() == 0) + url = "inventory.php?ftext=pantsgiving"; + + + int banishes_available = 5 - get_property_int("_pantsgivingBanish"); + if (banishes_available > 0 && $skill[Talk About Politics].skill_is_usable()) { + //subentry.entries.listAppend(pluralise(banishes_available, "banish", "banishes") + " available."); + string [int] tasks; + if ($item[pantsgiving].equipped_amount() == 0) + tasks.listAppend("equip pantsgiving"); + tasks.listAppend("cast talk about politics"); + resource_entries.listAppend(ChecklistEntryMake("__item pantsgiving", url, ChecklistSubentryMake(pluralise(banishes_available, "Pantsgiving banish", "Pantsgiving banishes"), "", tasks.listJoinComponents(", ").capitaliseFirstLetter() + "."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Pantsgiving banish")); + + } + + int pantsgiving_fullness_used = get_property_int("_pantsgivingFullness"); + int pantsgiving_adventures_used = get_property_int("_pantsgivingCount"); + int pantsgiving_pocket_crumbs_found = get_property_int("_pantsgivingCrumbs"); + int pantsgiving_potential_crumbs_remaining = 10 - pantsgiving_pocket_crumbs_found; + + int adventures_needed_for_fullness_boost = 5 * powi(10, pantsgiving_fullness_used); + int adventures_needed_for_fullness_boost_x2 = 5 * powi(10, 1 + pantsgiving_fullness_used); + int adventures_needed_for_fullness_boost_x3 = 5 * powi(10, 2 + pantsgiving_fullness_used); + int adventures_needed_for_fullness_boost_x4 = 5 * powi(10, 3 + pantsgiving_fullness_used); + + if (adventures_needed_for_fullness_boost > pantsgiving_adventures_used) { + int number_left = adventures_needed_for_fullness_boost - pantsgiving_adventures_used; + subentry.entries.listAppend(pluralise(number_left, "adventure", "adventures") + " until next fullness."); + } else { //already there + int number_left_for_next = -1; + string extra_fullness_available = "Fullness"; + if (pantsgiving_adventures_used >= adventures_needed_for_fullness_boost_x2) { + extra_fullness_available = "2x fullness"; + } else if (number_left_for_next == -1) + number_left_for_next = adventures_needed_for_fullness_boost_x2 - pantsgiving_adventures_used; + if (pantsgiving_adventures_used >= adventures_needed_for_fullness_boost_x3) { + extra_fullness_available = "3x fullness"; + } else if (number_left_for_next == -1) + number_left_for_next = adventures_needed_for_fullness_boost_x3 - pantsgiving_adventures_used; + if (pantsgiving_adventures_used >= adventures_needed_for_fullness_boost_x4) { + extra_fullness_available = "4x fullness (wh.. what?)"; + } else if (number_left_for_next == -1) + number_left_for_next = adventures_needed_for_fullness_boost_x4 - pantsgiving_adventures_used; + + if (availableFullness() == 0) { + subentry.entries.listAppend(extra_fullness_available + " available next adventure."); + } else + subentry.entries.listAppend(extra_fullness_available + " available when you're full."); + if (number_left_for_next != -1) + subentry.entries.listAppend(pluralise(number_left_for_next, "adventure", "adventures") + " until next stored fullness."); + } + + if (pantsgiving_potential_crumbs_remaining > 0 && $skill[pocket crumbs].skill_is_usable()) + subentry.entries.listAppend(pluralise(pantsgiving_potential_crumbs_remaining, " pocket crumb item", " pocket crumb items") + " left."); + + if (subentry.entries.count() > 0) { + ChecklistEntry entry = ChecklistEntryMake("__item pantsgiving", url, subentry); + entry.tags.id = "Pantsgiving resource"; + entry.should_indent_after_first_subentry = true; + resource_entries.listAppend(entry); + } + } + + + + if (__misc_state["free runs usable"] && in_run && $item[bottle of blank-out].available_amount() > 0) { + string [int] description; + string name; + int blankout_count = $item[bottle of blank-out].available_amount(); + name += pluralise(blankout_count, "blank-out", "blank-out"); + + if ($item[glob of blank-out].available_amount() == 0) + description.listAppend("Use blank-out for glob."); + if (get_property_boolean("_blankoutUsed")) + description.listAppend("Will have to wait until tomorrow to open."); + + resource_entries.listAppend(ChecklistEntryMake("__item Bottle of Blank-Out", "inventory.php?ftext=bottle+of+blank-out", ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Blank-out bottle resource")); + } + if (__misc_state["free runs usable"] && $item[glob of blank-out].available_amount() > 0) { + int uses_remaining = 5 - get_property_int("blankOutUsed"); + string [int] description; + string name; + description.listAppend("Use glob of blank-out in combat."); + if (!in_run) + description.listAppend("Will disappear when you ascend."); + + name = pluralise(uses_remaining, "blank-out runaway", "blank-out runaways"); + resource_entries.listAppend(ChecklistEntryMake("__item glob of blank-out", "", ChecklistSubentryMake(name, "", description)).ChecklistEntrySetIDTag("Blank-out glob free run")); + } + + if ($item[BitterSweetTarts].available_amount() > 0 && __misc_state["need to level"]) { + int stat_modifier = min(11, my_level()); + string [int] description; + description.listAppend("+" + stat_modifier + " stats/fight, 10 turns"); + if (my_level() < 11) { + description.listAppend("Wait until level 11 for full effectiveness"); + } + resource_entries.listAppend(ChecklistEntryMake("__item BitterSweetTarts", "inventory.php?ftext=bittersweettarts", ChecklistSubentryMake(pluralise($item[BitterSweetTarts]), "", description), importance_level_item).ChecklistEntrySetIDTag("Bittersweettarts resource")); + } + if ($item[polka pop].available_amount() > 0 && in_run) { + int item_and_meat_modifier = 5 * min(11, my_level()); + string [int] description; + description.listAppend("+" + item_and_meat_modifier + "% item, " + "+" + item_and_meat_modifier + "% meat"); + if (my_level() < 11) { + description.listAppend("Wait until level 11 for full effectiveness"); + } + resource_entries.listAppend(ChecklistEntryMake("__item polka pop", "", ChecklistSubentryMake(pluralise($item[polka pop]), "10 turns", description), importance_level_item).ChecklistEntrySetIDTag("Polka pop resource")); + } + + if ($item[frost flower].available_amount() > 0 && in_run && my_path().id != PATH_G_LOVER) { + string [int] description; + description.listAppend("+100% item, +200% meat, +25 ML, +100% init"); + resource_entries.listAppend(ChecklistEntryMake("__item frost flower", "inventory.php?ftext=frost+flower", ChecklistSubentryMake($item[frost flower].pluralise(), "50 turns", description), importance_level_item).ChecklistEntrySetIDTag("Frost flower resource")); + } + if (in_run) { + //Resolutions: + string [item] resolution_descriptions; + resolution_descriptions[$item[resolution: be happier]] = "+15% item (20 turns)"; + //resolution_descriptions[$item[resolution:be feistier]] = "+20 spell damage"; //information overload? + if (__misc_state["need to level"]) { + resolution_descriptions[$item[resolution: be stronger]] = "+2 muscle stats/combat (20 turns)"; + resolution_descriptions[$item[resolution: be smarter]] = "+2 mysticality stats/combat (20 turns)"; + resolution_descriptions[$item[resolution: be sexier]] = "+2 moxie stats/combat (20 turns)"; + } + resolution_descriptions[$item[resolution: be kinder]] = "+5 familiar weight (20 turns)"; + resolution_descriptions[$item[resolution: be luckier]] = "+5% item, +5% meat, +10% init, others (20 turns)"; //??? + if (my_path().id != PATH_SLOW_AND_STEADY) + resolution_descriptions[$item[resolution: be more adventurous]] = "+2 adventures at rollover"; + resolution_descriptions[$item[resolution: be wealthier]] = "+30% meat"; + + + + ChecklistSubentry [int] resolution_lines; + foreach it in resolution_descriptions { + if (it.available_amount() == 0) + continue; + string description = resolution_descriptions[it]; + + resolution_lines.listAppend(ChecklistSubentryMake(pluralise(it), "", description)); + } + if (resolution_lines.count() > 0) + resource_entries.listAppend(ChecklistEntryMake("__item resolution: be luckier", "inventory.php?ftext=resolution:+be", resolution_lines, importance_level_item).ChecklistEntrySetIDTag("Resolutions resource")); + + } + if (in_run) { + //doesn't show how much, because wahh I don't wanna write taffy code + string [item] taffy_descriptions; + taffy_descriptions[$item[pulled yellow taffy]] = "+meat, +item"; + if (__misc_state["need to level"]) { + taffy_descriptions[$item[pulled red taffy]] = "+moxie stats/fight"; + taffy_descriptions[$item[pulled orange taffy]] = "+muscle stats/fight"; + taffy_descriptions[$item[pulled violet taffy]] = "+mysticality stats/fight"; + } + taffy_descriptions[$item[pulled blue taffy]] = "+familiar weight, +familiar experience"; + string image_name = ""; + ChecklistSubentry [int] taffy_lines; + foreach it in taffy_descriptions { + if (it.available_amount() == 0) + continue; + string description = taffy_descriptions[it]; + if (image_name == "") + image_name = "__item " + it; + taffy_lines.listAppend(ChecklistSubentryMake(pluralise(it), "", description)); + } + if (taffy_lines.count() > 0) + resource_entries.listAppend(ChecklistEntryMake(image_name, "inventory.php?ftext=pulled", taffy_lines, importance_level_item).ChecklistEntrySetIDTag("Pulled taffy resource")); + + } + + + + if (in_run) { + if (7014.to_item().available_amount() > 0) //Louder than bomb + resource_entries.listAppend(ChecklistEntryMake("__item " + 7014.to_item().to_string(), "", ChecklistSubentryMake(pluralise(7014.to_item()), "", "Free run, 20-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Louder than bomb banish")); + if ($item[crystal skull].available_amount() > 0) + resource_entries.listAppend(ChecklistEntryMake("__item crystal skull", "", ChecklistSubentryMake(pluralise($item[crystal skull]), "", "Takes a turn, 20-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Crystal skull banish")); + + if ($item[harold's bell].available_amount() > 0 && $item[harold's bell].item_is_usable()) + resource_entries.listAppend(ChecklistEntryMake("__item harold's bell", "", ChecklistSubentryMake(pluralise($item[harold's bell]), "", "Takes a turn, 20-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Harold's bell banish")); + + if ($item[lost key].available_amount() > 0 && $item[lost key].item_is_usable()){ + string [int] details; + details.listAppend("Lost pill bottle is mini-fridge, take a nap, open the pill bottle."); + //FIXME does stunning work on tower monsters? + //if (!__quest_state["Level 13"].state_boolean["past tower monsters"] && (!$item[munchies pill].is_unrestricted() || !__misc_state["can eat just about anything"])) + //details.listAppend("The lost comb is turn on the TV, take a nap, pick up the comb. (towerkilling)"); + if ($classes[pastamancer,sauceror] contains my_class() && $skill[Transcendental Noodlecraft].skill_is_usable() && $skill[The Way of Sauce].skill_is_usable() && $skill[pulverize].skill_is_usable()) + details.listAppend("The lost glasses is mini-fridge, TV, glasses."); + resource_entries.listAppend(ChecklistEntryMake("__item lost key", "inventory.php?ftext=lost+key", ChecklistSubentryMake(pluralise($item[lost key]), "", details), importance_level_item).ChecklistEntrySetIDTag("Lost pill bottle resource")); + } + + if ($item[soft green echo eyedrop antidote].available_amount() > 0 && $skill[Transcendent Olfaction].skill_is_usable()) + resource_entries.listAppend(ChecklistEntryMake("__item soft green echo eyedrop antidote", "", ChecklistSubentryMake(pluralise($item[soft green echo eyedrop antidote]), "", "Removes unwanted effects; teleportitis-likes, debuffs, etc."), importance_level_unimportant_item).ChecklistEntrySetIDTag("SGEEA resource")); + + if ($item[sack lunch].available_amount() > 0) { + string [int] description; + int importance = importance_level_item; + if (my_level() < 11) { + description.listAppend("Wait until level 11+ to open for best food."); + importance = importance_level_unimportant_item; + } else { + description.listAppend("Safe to open."); + } + resource_entries.listAppend(ChecklistEntryMake("__item sack lunch", "inventory.php?ftext=sack+lunch", ChecklistSubentryMake(pluralise($item[sack lunch]), "", description), importance).ChecklistEntrySetIDTag("Sack lunch resource")); + } + + if (true) { + ChecklistSubentry [int] subentries; + string image_name = ""; + + string [item] descriptions; + descriptions[$item[NPZR chemistry set]] = "Open for 20 invisibility/irresistibility/irritability potions."; + descriptions[$item[invisibility potion]] = "-5% combat (20 turns)"; + descriptions[$item[irresistibility potion]] = "+5% combat (20 turns)"; + descriptions[$item[irritability potion]] = "+15 ML (20 turns)"; + + foreach it in $items[NPZR chemistry set,invisibility potion,irresistibility potion,irritability potion] { + if (it.available_amount() == 0) + continue; + if (image_name.length() == 0) + image_name = "__item " + it; + + subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", descriptions[it])); + } + + if (subentries.count() > 0) + resource_entries.listAppend(ChecklistEntryMake(image_name, "inventory.php?which=3", subentries, importance_level_item).ChecklistEntrySetIDTag("NPZR chemistry set resource")); + } + } + if ($item[smut orc keepsake box].available_amount() > 0 && !__quest_state["Level 9"].state_boolean["bridge complete"] && __misc_state["in run"]) + resource_entries.listAppend(ChecklistEntryMake("__item smut orc keepsake box", "inventory.php?ftext=smut+orc+keepsake+box", ChecklistSubentryMake(pluralise($item[smut orc keepsake box]), "", "Open for bridge building."), 0).ChecklistEntrySetIDTag("Smut orc keepsake box")); + + if ($item[wand of pigification].available_amount() > 0 && in_bad_moon() && __misc_state["in run"]) { + resource_entries.listAppend(ChecklistEntryMake("__item wand of pigification", "", ChecklistSubentryMake("Wand of pigification", "", "Use twice a day on monsters for good-level food."), 6).ChecklistEntrySetIDTag("Pigification wand resource")); + } + + int clovers_available = $items[11-leaf clover].available_amount() + $item[11-leaf clover].closet_amount(); + // Removing clover code and swapping to lucky code like TES has. + // if (my_path().id == PATH_BEES_HATE_YOU || my_path().id == PATH_G_LOVER) + // clovers_available = $item[ten-leaf clover].item_amount() + $item[ten-leaf clover].closet_amount(); + // if (clovers_available > 0 && in_run) { + // ChecklistSubentry subentry; + // subentry.header = pluralise(clovers_available, "clover", "clovers") + " available"; + + + // if (!__quest_state["Level 9"].state_boolean["bridge complete"]) + // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Orc logging camp, for bridge building. (3/3)", $location[the smut orc logging camp])); + // if ($item[a-boo clue].available_amount() < 4 && (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0 || !__quest_state["Level 9"].state_boolean["bridge complete"]) && my_path().id != PATH_G_LOVER) + // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("A-Boo clues. (2)", $location[a-boo peak])); + // if (__misc_state["wand of nagamar needed"] && $item[wand of nagamar].creatable_amount() == 0) + // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Wand of nagamar components (castle basement)", $location[the castle in the clouds in the sky (basement)])); + // boolean have_all_gum = $item[pack of chewing gum].available_amount() > 0 || ($item[jabañero-flavored chewing gum].available_amount() > 0 && $item[lime-and-chile-flavored chewing gum].available_amount() > 0 && $item[pickle-flavored chewing gum].available_amount() > 0 && $item[tamarind-flavored chewing gum].available_amount() > 0); + // if (__quest_state["Level 4"].state_int["areas unlocked"] + $item[sonar-in-a-biscuit].available_amount() < 2) + // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("2 sonar-in-a-biscuit (Guano Junction)", $location[guano junction])); + + // if (__quest_state["Level 11 Ron"].mafia_internal_step <= 2 && __quest_state["Level 11 Ron"].state_int["protestors remaining"] > 1) + // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Mob of zeppelin protestors NC", $location[A Mob of Zeppelin Protesters])); + // if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && !(get_property_boolean("lovebugsUnlocked") && $item[bottle of lovebug pheromones].is_unrestricted())) { //taking a gamble here - I'm assuming you'd never clover for ultrahydrated if you have lovebugs. even if you run out of ultrahydrated, you'll likely get it again in a hurry + // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Ultrahydrated (Oasis)", $location[the oasis])); + // } + // if (!__quest_state["Level 8"].state_boolean["Past mine"]) { + // item ore_needed = __quest_state["Level 8"].state_string["ore needed"].to_item(); + // if (ore_needed == $item[none]) + // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Mining ore. (1)", $location[itznotyerzitz mine])); + // else + // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability(ore_needed.capitaliseFirstLetter() + ". (1)", $location[itznotyerzitz mine])); + // } + // if (__misc_state["need to level"] && !__misc_state["Stat gain from NCs reduced"]) { + // location l = $location[none]; + // if (my_primestat() == $stat[moxie]) + // l = $location[the haunted ballroom]; + // else if (my_primestat() == $stat[mysticality]) + // l = $location[the haunted bathroom]; + // else if (my_primestat() == $stat[muscle]) + // l = $location[the haunted gallery]; + // subentry.entries.listAppend(HTMLGenerateFutureTextByLocationAvailability("Powerlevelling (" + l + ")", l)); + // } + // //put relevant tower items here + + // resource_entries.listAppend(ChecklistEntryMake("clover", "", subentry, 7).ChecklistEntrySetCombinationTag("clovers").ChecklistEntrySetIDTag("Ten-leaf clover resource")); + // } + // Turning off because lucky pills are garbage now. + + // if (in_run && $item[lucky pill].have() && availableSpleen() > 0) { + // string [int] description; + // description.listAppend("Chew for clovers."); + // resource_entries.listAppend(ChecklistEntryMake("__item lucky pill", "inventory.php?ftext=lucky+pill", ChecklistSubentryMake(pluralise($item[lucky pill]), "", description), importance_level_unimportant_item).ChecklistEntrySetCombinationTag("clovers").ChecklistEntrySetIDTag("Lucky pill resource")); + // } + if (in_run) { + if ($item[gameinformpowerdailypro magazine].available_amount() > 0) { + string [int] description; + description.listAppend("Zero-turn free SGEAA and scrolls"); + resource_entries.listAppend(ChecklistEntryMake("__item gameinformpowerdailypro magazine", "inventory.php?ftext=gameinformpowerdailypro+magazine", ChecklistSubentryMake(pluralise($item[gameinformpowerdailypro magazine]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Gameinformpowerdailypro magazine")); + } + } + if ($item[divine champagne popper].available_amount() > 0 && in_run) { + resource_entries.listAppend(ChecklistEntryMake("__item divine champagne popper", "", ChecklistSubentryMake(pluralise($item[divine champagne popper]), "", "Free run, 5-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Champagne popper banish")); + } + if (__misc_state["need to level"]) { + if ($item[dance card].available_amount() > 0 && my_primestat() == $stat[moxie] && in_ronin()) { + string [int] description; + description.listAppend("Gain ~" + round(__misc_state_float["dance card average stats"]) + " mainstat from delayed adventure in the haunted ballroom."); + resource_entries.listAppend(ChecklistEntryMake("__item dance card", "inventory.php?ftext=dance+card", ChecklistSubentryMake(pluralise($item[dance card]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Powerlevel dance card")); + } + } + if ($item[stone wool].available_amount() > 0 && in_ronin() && $item[stone wool].item_is_usable()) { + string [int] description; + string url = "inventory.php?ftext=stone+wool"; + int quest_needed = 2; + if ($item[the nostril of the serpent].available_amount() > 0 || get_property_ascension("lastTempleButtonsUnlock")) + quest_needed -= 1; + if (locationAvailable($location[the hidden park]) || !in_run) + quest_needed = 0; + + if (quest_needed > 0) + description.listAppend(quest_needed + " to unlock hidden city."); + if (__misc_state["need to level"]) + description.listAppend("Cave bar."); + if (!get_property_ascension("lastTempleAdventures") && my_path().id != PATH_SLOW_AND_STEADY) { + string line = "+3 adventures, +3 duration to ten effects. (once/ascension)"; + if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) + line += "|Can use to extend effects at nuns."; + description.listAppend(line); + } + if (!__misc_state["in run"] && $effect[stone-faced].have_effect() > 0) + url = $location[the hidden temple].getClickableURLForLocation(); + if (description.count() > 0) + resource_entries.listAppend(ChecklistEntryMake("__item stone wool", url, ChecklistSubentryMake(pluralise($item[stone wool]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Stone wool resource")); + } + if ($item[the legendary beat].available_amount() > 0 && !get_property_boolean("_legendaryBeat")) { + resource_entries.listAppend(ChecklistEntryMake("__item The Legendary Beat", "inventory.php?ftext=the+legendary+beat", ChecklistSubentryMake("The Legendary Beat", "", "+50% item. (20 turns)"), importance_level_item).ChecklistEntrySetIDTag("Legendary beat resource")); + + } + item zap_wand_owned; + if (true) { + zap_wand_owned = $item[none]; + foreach wand in $items[aluminum wand,ebony wand,hexagonal wand,marble wand,pine wand] { + if (wand.available_amount() > 0) { + zap_wand_owned = wand; + break; + } + } + if (zap_wand_owned != $item[none]) { + string url = "wand.php?whichwand=" + zap_wand_owned.to_int(); + int zaps_used = get_property_int("_zapCount"); + string [int] details; + if (zaps_used == 0) + details.listAppend("Can zap safely."); + else { + float [int] chances; + chances[1] = 75.0; + chances[2] = 18.75; + chances[3] = 1.5625; + float chance = chances[zaps_used]; + + if (zaps_used >= 4) + details.listAppend("Warning: Cannot zap."); + else + details.listAppend("Warning: " + roundForOutput(100.0 - chance, 1) + "% chance of explosion."); + if ($item[Platinum Yendorian Express Card].available_amount() > 0 && !get_property_boolean("expressCardUsed")) + details.listAppend("Platinum Yendorian Express Card usable."); + } + resource_entries.listAppend(ChecklistEntryMake(zap_wand_owned, url, ChecklistSubentryMake(pluralise(zaps_used, "zap", "zaps") + " used with " + zap_wand_owned, "", details), 10).ChecklistEntrySetIDTag("Zapping resource")); + } + } + + if (!get_property_boolean("_defectiveTokenChecked") && get_property_ascension("lastArcadeAscension")) { + resource_entries.listAppend(ChecklistEntryMake("__item jackass plumber home game", "place.php?whichplace=arcade", ChecklistSubentryMake("Broken arcade game", "", "May find a defective game grid token."), importance_level_item).ChecklistEntrySetIDTag("Defective game grid token check")); + } + if ($item[picky tweezers].available_amount() > 0 && !get_property_boolean("_pickyTweezersUsed")) { + resource_entries.listAppend(ChecklistEntryMake("__item picky tweezers", "inventory.php?ftext=picky+tweezers", ChecklistSubentryMake("Picky tweezers", "", "Acquire a single atom."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Picky tweezers resource")); + } + if ($item[defective Game Grid token].available_amount() > 0 && !get_property_boolean("_defectiveTokenUsed")) { + string [int] description; + description.listAppend("+5 to everything. (5 turns)"); + + resource_entries.listAppend(ChecklistEntryMake("__item defective Game Grid token", "inventory.php?ftext=defective+game+grid+token", ChecklistSubentryMake("Defective Game Grid Token", "", description), importance_level_item).ChecklistEntrySetIDTag("Defective game grid token use")); + } + if ($item[Platinum Yendorian Express Card].available_amount() > 0 && !get_property_boolean("expressCardUsed")) { + string [int] description; + string line = "Extends buffs, restores MP"; + if (get_property_int("_zapCount") > 0 && zap_wand_owned != $item[none] && zap_wand_owned.available_amount() > 0) + line += ", cools down " + zap_wand_owned; + line += "."; + description.listAppend(line); + resource_entries.listAppend(ChecklistEntryMake("__item Platinum Yendorian Express Card", "", ChecklistSubentryMake("Platinum Yendorian Express Card", "", description), importance_level_item).ChecklistEntrySetIDTag("Platinum yendorian express card")); + } + + + if ($item[mojo filter].available_amount() > 0 && get_property_int("currentMojoFilters") <3 && in_run) { + int mojo_filters_usable = MIN(my_spleen_use(), MIN(3 - get_property_int("currentMojoFilters"), $item[mojo filter].available_amount())); + string line = "Removes one spleen each."; + if (mojo_filters_usable != $item[mojo filter].available_amount()) + line += "|" + pluralise(mojo_filters_usable, "filter", "filters") + " usable."; + + if (mojo_filters_usable > 0) + resource_entries.listAppend(ChecklistEntryMake("__item mojo filter", "inventory.php?ftext=mojo+filter", ChecklistSubentryMake(pluralise($item[mojo filter]), "", line), importance_level_unimportant_item).ChecklistEntrySetIDTag("Mojo filter resource")); + } + if ($item[distention pill].available_amount() > 0 && !get_property_boolean("_distentionPillUsed") && in_run) { + resource_entries.listAppend(ChecklistEntryMake("__item distention pill", "inventory.php?ftext=distention+pill", ChecklistSubentryMake(pluralise($item[distention pill]), "", "Adds one extra fullness.|Once/day."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Distention pill resource")); + } + if ($item[synthetic dog hair pill].available_amount() > 0 && !get_property_boolean("_syntheticDogHairPillUsed") && in_run) { + resource_entries.listAppend(ChecklistEntryMake("__item synthetic dog hair pill", "inventory.php?ftext=synthetic+dog+hair+pill", ChecklistSubentryMake(pluralise($item[synthetic dog hair pill]), "", "Adds one extra drunkenness.|Once/day."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Dog hair pill resource")); + } + if ($item[the lost pill bottle].available_amount() > 0 && in_run && my_path().id != PATH_BEES_HATE_YOU) { + string header = pluralise($item[the lost pill bottle]); + if ($item[the lost pill bottle].available_amount() == 1) + header = $item[the lost pill bottle]; + resource_entries.listAppend(ChecklistEntryMake("__item the lost pill bottle", "inventory.php?ftext=the+lost+pill+bottle", ChecklistSubentryMake(header, "", "Open it."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Lost pill bottle")); + } + if ($item[Boozehounds Anonymous token].available_amount() > 0 && in_run && (__quest_state["White Citadel"].started || (__quest_state["Spooky Forest"].started && my_path().id != PATH_COMMUNITY_SERVICE))) { + resource_entries.listAppend(ChecklistEntryMake("__item Boozehounds Anonymous token", invSearch($item[Boozehounds Anonymous token]), ChecklistSubentryMake($item[Boozehounds Anonymous token].pluralise(), "free booze", ""), importance_level_unimportant_item).ChecklistEntrySetIDTag("Boozehound token resource")); + } + if (__misc_state["need to level"] && in_ronin()) { + if ($item[Marvin's marvelous pill].available_amount() > 0 && __misc_state["need to level moxie"]) { + resource_entries.listAppend(ChecklistEntryMake("__item Marvin's marvelous pill", "", ChecklistSubentryMake(pluralise($item[Marvin's marvelous pill]), "", "+20% to moxie gains. (10 turns)"), importance_level_unimportant_item).ChecklistEntrySetIDTag("Marvin pill resource")); + } + if ($item[drum of pomade].available_amount() > 0 && __misc_state["need to level moxie"]) { + resource_entries.listAppend(ChecklistEntryMake("__item drum of pomade", "", ChecklistSubentryMake(pluralise($item[drum of pomade]), "", "+15% to moxie gains. (10 turns)"), importance_level_unimportant_item).ChecklistEntrySetIDTag("Pomade drum resource")); + } + if ($item[baobab sap].available_amount() > 0 && __misc_state["need to level muscle"]) { + resource_entries.listAppend(ChecklistEntryMake("__item baobab sap", "", ChecklistSubentryMake(pluralise($item[baobab sap]), "", "+20% to muscle gains. (10 turns)"), importance_level_unimportant_item).ChecklistEntrySetIDTag("Baobab sap resource")); + } + if ($item[desktop zen garden].available_amount() > 0 && __misc_state["need to level mysticality"]) { + resource_entries.listAppend(ChecklistEntryMake("__item desktop zen garden", "", ChecklistSubentryMake(pluralise($item[desktop zen garden]), "", "+20% to mysticality gains. (10 turns)"), importance_level_unimportant_item).ChecklistEntrySetIDTag("Desktop zen garden resource")); + } + } + if ($item[munchies pill].available_amount() > 0 && fullness_limit() > 0 && in_run && my_path().id != PATH_SLOW_AND_STEADY) { + resource_entries.listAppend(ChecklistEntryMake("__item munchies pill", "", ChecklistSubentryMake(pluralise($item[munchies pill]), "", "+3 turns from fortune cookies and other low-fullness foods."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Munchies pill resource")); + } + if ($item[snow cleats].available_amount() > 0 && in_run) + resource_entries.listAppend(ChecklistEntryMake("__item snow cleats", "", ChecklistSubentryMake(pluralise($item[snow cleats]), "", "-5% combat, 30 turns."), importance_level_item).ChecklistEntrySetIDTag("Snow cleats resource")); + + if ($item[vitachoconutriment capsule].available_amount() > 0 && get_property_int("_vitachocCapsulesUsed") <3 && in_run) { + string [int] adventures_remaining; + int capsules_remaining = $item[vitachoconutriment capsule].available_amount(); + int vita_used = get_property_int("_vitachocCapsulesUsed"); + if (vita_used < 1) { + adventures_remaining.listAppend("+5"); + vita_used += 1; + capsules_remaining -= 1; + } + if (vita_used < 2 && capsules_remaining > 0) { + adventures_remaining.listAppend("+3"); + vita_used += 1; + capsules_remaining -= 1; + } + if (vita_used < 3 && capsules_remaining > 0) { + adventures_remaining.listAppend("+1"); + } + string line; + line = adventures_remaining.listJoinComponents("/") + " adventures"; + if (adventures_remaining.count() == 1) { //hacky + if (adventures_remaining[0] == "+1") + line = "+1 adventure"; + } + line += "."; + resource_entries.listAppend(ChecklistEntryMake("__item vitachoconutriment capsule", "inventory.php?ftext=vitachoconutriment+capsule", ChecklistSubentryMake(pluralise($item[vitachoconutriment capsule]), "", line), importance_level_unimportant_item).ChecklistEntrySetIDTag("Vitachoconutriment capsule")); + } + if (in_run && lookupItem("tryptophan dart").available_amount() > 0 && in_ronin() && lookupItem("tryptophan dart").item_is_usable()) { + resource_entries.listAppend(ChecklistEntryMake("__item tryptophan dart", "", ChecklistSubentryMake(pluralise(lookupItem("tryptophan dart")), "", "Non-free all-day banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Tryptophan dart banish")); + } + if (in_run && __misc_state["free runs usable"] && get_property_int("_humanMuskUses") < 3 && lookupItem("human musk").available_amount() > 0 && lookupItem("human musk") != $item[none]) { + resource_entries.listAppend(ChecklistEntryMake("__item human musk", "", ChecklistSubentryMake(MIN(lookupItem("human musk").available_amount(), 3 - get_property_int("_humanMuskUses")).pluralise("human musk", "human musks"), "", "Free run/banish. Consumes item."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Human musk banish")); + } + + if ($item[drum machine].available_amount() > 0 && in_run && (my_adventures() <= 1 || (availableDrunkenness() < 0 && availableDrunkenness() > -4 && my_adventures() >= 1)) && __quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && $item[drum machine].item_is_usable()) { + //Daycount strategy that never works, suggest: + string line = (100.0 * ((item_drop_modifier_ignoring_plants() / 100.0 + 1.0) * (1.0 / 1000.0))).roundForOutput(2) + "% chance of spice melange."; + if (my_adventures() == 0) + line += "|Need one adventure."; + resource_entries.listAppend(ChecklistEntryMake("__item drum machine", "inventory.php?ftext=drum+machine", ChecklistSubentryMake(pluralise($item[drum machine]), "", line), importance_level_unimportant_item).ChecklistEntrySetIDTag("Drum machine spice melange")); + } + + + if ($items[stinky cheese sword,stinky cheese diaper,stinky cheese wheel,stinky cheese eye,Staff of Queso Escusado].available_amount() > 0) { + if (!get_property_boolean("_stinkyCheeseBanisherUsed")) + resource_entries.listAppend(ChecklistEntryMake("__item stinky cheese eye", "", ChecklistSubentryMake("Stinky cheese eye banish", "", "Free run."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Stinky cheese banish")); + + int stinky_cheese_charge = min(100, get_property_int("_stinkyCheeseCount")); + string title; + string [int] description; + string url; + url = invSearch("stinky cheese"); + int importance = importance_level_item; + + if (stinky_cheese_charge < 100) { + title = pluralise(stinky_cheese_charge, "/ 100 stinky cheese charge", "/ 100 stinky cheese charges"); + description.listAppend("+" + pluralise(stinky_cheese_charge / 10, "adventure", "adventures") + "/day pants (max +10)."); + description.listAppend("Or +" + stinky_cheese_charge / 5 + "% item/meat accessory (max +20%)."); + } else { + title = "Fully charged stinky cheese"; + description.listAppend("+10 adventures/day pants."); + description.listAppend("Or +20% item/meat accessory."); + importance = importance_level_unimportant_item; + } + description.listAppend("Or some other stinky things."); + + resource_entries.listAppend(ChecklistEntryMake("__item Ched", url, ChecklistSubentryMake(title, "", description), importance).ChecklistEntrySetIDTag("Stinky cheese resource")); + } + + if ($item[mayfly bait necklace].available_amount() > 0 && get_property_int("_mayflySummons") < 30) { + int uses_remaining = 30 - get_property_int("_mayflySummons"); + string url = $item[mayfly bait necklace].equipped() ? "" : "inventory.php?ftext=mayfly+bait+necklace"; + resource_entries.listAppend(ChecklistEntryMake("__item mayfly bait necklace", url, ChecklistSubentryMake(pluralise(uses_remaining, "mayfly summon available", "mayfly summons available"), "This probably does something useful", $item[mayfly bait necklace].equipped() ? "" : "Equip the necklace first."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Mayfly bait necklace")); + } + + if (in_run) { + // As of the ELG change, tatters are worse than other options. Only show if the user doesn't have those options. + if ($item[tattered scrap of paper].available_amount() > 0 && __misc_state["free runs usable"] && $item[tattered scrap of paper].item_is_usable() && !__iotms_usable[lookupItem("spring shoes")] && !__iotms_usable[lookupItem("spring shoes")] && $item[roman candelabra].available_amount() == 0) { + string [int] description; + description.listAppend(($item[tattered scrap of paper].available_amount() / 2.0).roundForOutput(1) + " free runs."); + if (in_bad_moon()) + description.listAppend("Or save for demon summoning."); + resource_entries.listAppend(ChecklistEntryMake("__item tattered scrap of paper", "", ChecklistSubentryMake(pluralise($item[tattered scrap of paper]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Tattered paper scrap free run")); + } + if (2371.to_item().available_amount() > 0 && __misc_state["free runs usable"]) { //green smoke bomb + item it = 2371.to_item(); + string [int] description; + description.listAppend((it.available_amount() * 0.9).roundForOutput(1) + " free runs."); + resource_entries.listAppend(ChecklistEntryMake("__item " + it, "", ChecklistSubentryMake(pluralise(it), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Green smoke bomb free run")); + } + if ($item[dungeoneering kit].available_amount() > 0) { + string line = "Open it."; + if ($item[dungeoneering kit].available_amount() > 1) + line = "Open them."; + resource_entries.listAppend(ChecklistEntryMake("__item dungeoneering kit", "inventory.php?ftext=dungeoneering+kit", ChecklistSubentryMake(pluralise($item[dungeoneering kit]), "", line), importance_level_unimportant_item).ChecklistEntrySetIDTag("Dungeoneering kit resource")); + } + if ($item[Box of familiar jacks].available_amount() > 0) + resource_entries.listAppend(ChecklistEntryMake("__item box of familiar jacks", "", ChecklistSubentryMake(pluralise($item[Box of familiar jacks]), "", "Gives current familiar equipment."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Box of familiar jacks resource")); + if ($item[csa fire-starting kit].available_amount() > 0 && !get_property_boolean("_fireStartingKitUsed")) { + string [int] description; + description.listAppend("All-day 4 HP/MP regeneration."); + if (hippy_stone_broken()) + description.listAppend("3 PVP fights."); + resource_entries.listAppend(ChecklistEntryMake("__item csa fire-starting kit", "inventory.php?ftext=csa+fire-starting+kit", ChecklistSubentryMake($item[csa fire-starting kit], "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("CSA fire-starting kit")); + } + + if ($item[transporter transponder].available_amount() > 0) { + string [int] options; + if (__misc_state["need to level"]) + options.listAppend("powerleveling"); + if (fullness_limit() > 0 || inebriety_limit() > 0) + options.listAppend("yellow ray in grimace for synthetic dog hair/distention pill"); + + string description = "Spaaaaace access."; + if (options.count() > 0) + description += "|" + options.listJoinComponents(", ", "and").capitaliseFirstLetter(); + resource_entries.listAppend(ChecklistEntryMake("__item transporter transponder", "", ChecklistSubentryMake(pluralise($item[transporter transponder]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Transporter transponder resource")); + } + } + + foreach it in $items[[10882]carton of astral energy drinks,astral hot dog dinner,astral six-pack] { + if (it.available_amount() == 0) + continue; + resource_entries.listAppend(ChecklistEntryMake("__item " + it, "inventory.php?ftext=" + it.replace_string(" ", "+"), ChecklistSubentryMake(pluralise(it), "", "Open for astral consumables."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Astral consumable open")); + } + + if ($item[map to safety shelter grimace prime].available_amount() > 0) { + string line = "Use for synthetic dog hair or distention pill."; + if (__misc_state["in aftercore"]) + line += "|Will disappear when you ascend."; + resource_entries.listAppend(ChecklistEntryMake("__item " + $item[map to safety shelter grimace prime], "inventory.php?ftext=map+to+safety+shelter+grimace+prime", ChecklistSubentryMake(pluralise($item[map to safety shelter grimace prime]), "", line), importance_level_unimportant_item).ChecklistEntrySetIDTag("Grimace shelter map resource")); + } + if ($item[rusty hedge trimmers].available_amount() > 0 && __quest_state["Level 9"].state_int["twin peak progress"] != 15 && in_run) { + string [int] description; + description.listAppend("Use to visit the Twin Peak non-combat."); + resource_entries.listAppend(ChecklistEntryMake("__item " + $item[rusty hedge trimmers], "inventory.php?ftext=rusty+hedge+trimmers", ChecklistSubentryMake(pluralise($item[rusty hedge trimmers]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Rusty hedge trimmers")); + } + + if (in_run && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) { + string image_name = ""; + string [int] autosell_list; + boolean [item] autosellable_items = $items[meat stack, dense meat stack, really dense meat stack, solid gold bowling ball, fancy seashell necklace, commemorative war stein,huge gold coin].makeConstantItemArrayMutable(); + if (!__iotms_usable[lookupItem("diabolic pizza cube")]) + autosellable_items[$item[space blanket]] = true; + autosellable_items[$item[1952 Mickey Mantle card]] = true; + if ($item[pixel coin] != $item[none]) + autosellable_items[$item[pixel coin]] = true; + foreach it in autosellable_items { + if (it.available_amount() == 0) + continue; + autosell_list.listAppend(it.pluralise()); + + if (image_name.length() == 0) + image_name = "__item " + it; + } + + string [int] open_list; + foreach it in $items[old coin purse, old leather wallet, black pension check, ancient vinyl coin purse, warm subject gift certificate,shiny stones] { + if (it.available_amount() == 0) + continue; + if (!it.item_is_usable()) continue; + open_list.listAppend(it.pluralise()); + + if (image_name.length() == 0) + image_name = "__item " + it; + } + + string url = ""; + string [int] description; + if (autosell_list.count() > 0) { + url = "sellstuff_ugly.php"; + description.listAppend("Autosell " + autosell_list.listJoinComponents(", ", "and") + "."); + } + if (open_list.count() > 0) { + url = "inventory.php?which=3"; + description.listAppend("Open " + open_list.listJoinComponents(", ", "and") + "."); + } + + if (description.count() > 0) { + resource_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake("Meat", "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Meat giving items resource")); + } + } + //Penultimate Fantasy chest? + + item odd_silver_coin = $item[odd silver coin]; + if (odd_silver_coin.available_amount() > 0 && in_run) { + string [int] description; + string [int][int] table; + //cinnamon cannoli - 2 - 1 fullness awesome food. not worthwhile? + //expensive champagne - 3 - 1-drunkness epic drink. not worthwhile? + //polo trophy - 3 - +50ML for 15 turns + //table.listAppend(listMake("polo trophy", "+50ML for 15 turns, marginal?", "3 coins")); //costs three adventures to find. I guess it'd only be relevant for cave bars? even then... + //fancy oil painting - 4 - bridge building. 10 progress + if (!__quest_state["Level 9"].state_boolean["bridge complete"] && (__quest_state["Level 9"].state_int["bridge fasteners needed"] > 0 || __quest_state["Level 9"].state_int["bridge lumber needed"] > 0)) + table.listAppend(listMake("fancy oil painting", "10 fasteners, 10 lumber", "4 coins")); + //solid gold rosary - 5 - better cyrpt progression. need details (-4.5 evil?) + if (!__quest_state["Level 7"].state_boolean["alcove finished"] || !__quest_state["Level 7"].state_boolean["cranny finished"] || !__quest_state["Level 7"].state_boolean["niche finished"] || !__quest_state["Level 7"].state_boolean["nook finished"]) + table.listAppend(listMake("solid gold rosary", "-4.5? evilness from cyrpt", "5 coins")); + //ornate dowsing rod - 5 - better desert exploration (+2%) + + if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && $item[ornate dowsing rod].available_amount() == 0) + table.listAppend(listMake("ornate dowsing rod", "+2% desert exploration", "5 coins")); + description.listAppend(HTMLGenerateSimpleTableLines(table)); + + resource_entries.listAppend(ChecklistEntryMake("__item " + odd_silver_coin, "shop.php?whichshop=cindy", ChecklistSubentryMake(odd_silver_coin.pluralise(), "", description), importance_level_item).ChecklistEntrySetIDTag("Odd silver coin shop")); + } + item grimstone_mask = $item[grimstone mask]; + if (grimstone_mask.available_amount() > 0 && in_run) { + string [int] description; + + description.listAppend("Wear to take you places."); + description.listAppend("The prince's ball (stepmother) lets you find odd silver coins.|Up to six, one adventure each."); + //description.listAppend("Rumpelstiltskin's for towerkilling with small golem.|Small golem is a 5k/round combat item.|Involves the semi-rare in village. Don't know the details, sorry."); //only somewhat relevant in obscure edge cases + if ($effect[Human-Fish Hybrid].have_effect() == 0 && __iotms_usable[$item[Little Geneticist DNA-Splicing Lab]] && !__misc_state["familiars temporarily blocked"]) + description.listAppend("Candy witch for human-fish hybrid. (+10 familiar weight)"); + if (get_property("grimstoneMaskPath") != "") + description.listAppend("Currently on the path of " + get_property("grimstoneMaskPath") + "."); + + resource_entries.listAppend(ChecklistEntryMake("__item " + grimstone_mask, "inventory.php?ftext=grimstone+mask", ChecklistSubentryMake(grimstone_mask.pluralise(), "", description), importance_level_item).ChecklistEntrySetIDTag("Grimstone mask resource")); + } + + if (__campground[$item[spinning wheel]] > 0 && !get_property_boolean("_spinningWheel")) { + string [int] description; + int meat_gained = powi(MIN(30, my_level()), 3); + description.listAppend("Will gain " + meat_gained + " meat."); + if (availableDrunkenness() >= 0) { + if (my_level() < 8) + description.listAppend("Wait until you've leveled up more."); + else if (my_level() < 13) + description.listAppend("Possibly wait until you've leveled up more?"); + } + resource_entries.listAppend(ChecklistEntryMake("__item spinning wheel", "campground.php?action=workshed", ChecklistSubentryMake("Spinning wheel meat", "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Campground spinning wheel")); + } + + if ($item[very overdue library book].available_amount() > 0 && in_run && __misc_state["need to level"] && $item[very overdue library book].item_is_usable()) { + resource_entries.listAppend(ChecklistEntryMake("__item very overdue library book", "inventory.php?ftext=very+overdue+library+book", ChecklistSubentryMake("Very overdue library book", "", "Open for 63 moxie/mysticality/muscle."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Overdue book resource")); + } + + if ($item[chest of the Bonerdagon].available_amount() > 0 && in_run && my_path().id != PATH_BEES_HATE_YOU) { + string description = "Open for 150 muscle/mysticality/moxie and 3k meat."; + if (!$familiar[ninja pirate zombie robot].have_familiar()) + description += "|Unless you want to make an NPZR this ascension."; + resource_entries.listAppend(ChecklistEntryMake("__item chest of the Bonerdagon", "inventory.php?ftext=chest+of+the+Bonerdagon", ChecklistSubentryMake("chest of the Bonerdagon", "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Bonerdagon chest resource")); + } + + if ($item[smoke grenade].available_amount() > 0 && in_run) { + string description = "Turn-costing banish. (lasts 20 turns, no stats, no items, no meat)"; + resource_entries.listAppend(ChecklistEntryMake("__item smoke grenade", "", ChecklistSubentryMake(pluralise($item[Smoke grenade]), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Smoke grenade banish")); + } + + if ($item[pile of ashes].available_amount() > 0 && in_run) { + string description = "-10% combat. (20 turns)"; + resource_entries.listAppend(ChecklistEntryMake("__item pile of ashes", "inventory.php?ftext=pile+of+ashes", ChecklistSubentryMake(pluralise($item[pile of ashes]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Pile of ashes resource")); + } + if (to_item("7259").available_amount() > 0 && in_run) { //crate of firebombs + string description = "Open for elemental damage combat items."; + resource_entries.listAppend(ChecklistEntryMake("__item " + to_item("7259"), "inventory.php?ftext=" + to_item("7259").replace_string(" ", "+"), ChecklistSubentryMake(pluralise(to_item("7259")), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Crate of firebombs resource")); + } + + if ($item[gym membership card].available_amount() > 0 && in_run && __misc_state["need to level"]) { + int importance = importance_level_item; + string description = "Gives 30 muscle/mysticality/moxie stats.|Once per day."; + if (my_level() < 4) { + description += "|Not usable until level 4."; + importance = importance_level_unimportant_item; + } + resource_entries.listAppend(ChecklistEntryMake("__item gym membership card", "inventory.php?ftext=gym+membership+card", ChecklistSubentryMake(pluralise($item[gym membership card]), "", description), importance_level_item).ChecklistEntrySetIDTag("Gym membership card")); + } + + if (!get_property_boolean("_warbearGyrocopterUsed")) { + if ($item[warbear gyrocopter].available_amount() > 0) { + string [int] description; + description.listAppend("Usable once/day for a gyro. Only breaks a quarter of the time."); + if (!in_ronin()) + description.listAppend("Could always send it to yourself."); + resource_entries.listAppend(ChecklistEntryMake("__item warbear gyrocopter", "curse.php?whichitem=7038", ChecklistSubentryMake(pluralise($item[warbear gyrocopter]), "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Warbear gyrocopter resource")); + + } else if ($item[broken warbear gyrocopter].available_amount() > 0) { + resource_entries.listAppend(ChecklistEntryMake("__item broken warbear gyrocopter", "inventory.php?ftext=broken+warbear+gyrocopter", ChecklistSubentryMake(pluralise($item[broken warbear gyrocopter]), "", "Gyrocopters dream of the sky. Set one free!"), importance_level_unimportant_item).ChecklistEntrySetIDTag("Warbear gyrocopter broken")); + + } + } + if ($item[burned government manual fragment].available_amount() > 0) { + resource_entries.listAppend(ChecklistEntryMake("__item burned government manual fragment", "inventory.php?ftext=burned+government+manual+fragment", ChecklistSubentryMake(pluralise($item[burned government manual fragment]), "", "Foreign language study.|Will disappear on ascension."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Burned government manual fragment")); + } + + // Adding scorpion/glark resources; changed slghtly from TES tile by adding tavern unlock to display + if ($item[bowl of scorpions].available_amount() > 0 && get_property_int("_drunkPygmyBanishes") < 11 && my_path().id != PATH_G_LOVER && get_property_ascension("hiddenTavernUnlock")) + { + int uses_remaining = MIN($item[bowl of scorpions].available_amount(), clampi(11 - get_property_int("_drunkPygmyBanishes"), 0, 11)); + resource_entries.listAppend(ChecklistEntryMake("__item bowl of scorpions", "inventory.php?which=3&ftext=bowl+of+scorpions", ChecklistSubentryMake(pluralise(uses_remaining,$item[bowl of scorpions]), "", "Free fight when brought to Bowling Alley."), importance_level_unimportant_item).ChecklistEntrySetIDTag("daily free fight")); + } + + if ($item[glark cable].available_amount() > 0 && get_property_int("_glarkCableUses") < 5 && my_path().id != PATH_G_LOVER) + { + int uses_remaining = MIN($item[glark cable].available_amount(), clampi(5 - get_property_int("_glarkCableUses"), 0, 5)); + resource_entries.listAppend(ChecklistEntryMake("__item glark cable", "inventory.php?which=3&ftext=glark+cable", ChecklistSubentryMake(pluralise(uses_remaining,$item[glark cable]), "", "Free fight on the Red Zeppelin."), importance_level_unimportant_item).ChecklistEntrySetIDTag("daily free fight")); + } + if ($item[lynyrd snare].available_amount() > 0 && get_property_int("_lynyrdSnareUses") < 3 && $item[lynyrd snare].item_is_usable()) { // && in_run && __misc_state["need to level"]) + int uses_remaining = MIN($item[lynyrd snare].available_amount(), clampi(3 - get_property_int("_lynyrdSnareUses"), 0, 3)); + resource_entries.listAppend(ChecklistEntryMake("__item lynyrd snare", "inventory.php?ftext=lynyrd+snare", ChecklistSubentryMake(pluralise(uses_remaining,$item[lynyrd snare]), "", "Free fight when used."), importance_level_unimportant_item).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Lynyrd snare free fight")); + } + if (in_run && $item[red box].available_amount() > 0 && $item[red box].item_is_usable()) { + resource_entries.listAppend(ChecklistEntryMake("__item red box", "inventory.php?ftext=red+box", ChecklistSubentryMake(pluralise($item[red box]), "", "Open for stuff."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Red box resource")); + } + + if (in_run && $item[llama lama gong].available_amount() > 0) { + //fiddle fiddle fiddle + //I'm not sure anyone should actually do this, so fiddly! + boolean need_pickpocket = true; + if (my_primestat() == $stat[moxie]) + need_pickpocket = false; + + string [int] description; + string [int] birdform_description; + + //options: + + string [int] possible_pickpocket_locations; + + if (need_pickpocket) { + //bird form for pickpocket in crypt, filthworms, golems + + if (__quest_state["Level 7"].state_boolean["nook needs speed tricks"]) + possible_pickpocket_locations.listAppend("Cyrpt Nook"); + if (!__quest_state["Level 12"].state_boolean["Orchard Finished"]) + possible_pickpocket_locations.listAppend("filthworms"); + + if (possible_pickpocket_locations.count() == 0) + birdform_description.listAppend("Gives pickpocketing ability."); + else + birdform_description.listAppend("Gives pickpocketing ability for stealing from the " + possible_pickpocket_locations.listJoinComponents(", ", "and") + "."); + } + + string [element][int] element_options; + + foreach e in $elements[] + element_options[e] = listMakeBlankString(); + if (!__quest_state["Level 6"].finished) + element_options[$element[hot]].listAppend("friars quest"); + + if (__quest_state["Level 9"].state_float["oil peak pressure"] > 0.0) + element_options[$element[sleaze]].listAppend("oil peak"); + + if (!__quest_state["Level 12"].finished && __quest_state["Level 12"].state_string["Side seemingly fighting for"] == "hippy") + element_options[$element[sleaze]].listAppend("frat boys"); + + + if (!__quest_state["Level 7"].finished) + element_options[$element[spooky]].listAppend("cyrpt"); + + + if (!__quest_state["Level 12"].state_boolean["War started"]) + element_options[$element[stench]].listAppend("starting war against hippies"); + if (!__quest_state["Level 12"].state_boolean["Orchard Finished"]) + element_options[$element[stench]].listAppend("filthworms"); + + if (__quest_state["Level 11 Manor"].mafia_internal_step < 2) + element_options[$element[spooky]].listAppend("spookyraven ballroom"); + if (get_property("questM20Necklace") != "finished" && $item[Lady Spookyraven's powder puff].available_amount() == 0) + element_options[$element[spooky]].listAppend("spookyraven bathroom"); + + + + string [element] element_to_potion; + + if (__misc_state["need to level"]) + element_to_potion[$element[hot]] = "+6 stats/fight"; + element_to_potion[$element[sleaze]] = "+20 ML"; + element_to_potion[$element[spooky]] = "+60% item"; + + if (!__quest_state["Level 12"].state_boolean["Nuns Finished"] && $item[glimmering raven feather].available_amount() == 0 && $effect[Melancholy Burden].have_effect() == 0) + element_to_potion[$element[stench]] = "+60% meat"; + + + //string [int][int] monster_fight_table; + //monster_fight_table.listAppend(listMake(HTMLGenerateSpanOfClass("Monster element", "r_bold"), HTMLGenerateSpanOfClass("Areas", "r_bold"), HTMLGenerateSpanOfClass("Gives potion", "r_bold"))); + foreach e in element_options { + if (element_options[e].count() == 0) + continue; + if (!(element_to_potion contains e)) + continue; + + //monster_fight_table.listAppend(listMake(e.to_string(), element_options[e].listJoinComponents("
"), element_to_potion[e])); + birdform_description.listAppend("Fight " + e + " monsters (" + element_options[e].listJoinComponents(", ", "and") + ") for " + element_to_potion[e] + " spleen potion."); + } + + //if (monster_fight_table.count() > 1) + //birdform_description.listAppend(HTMLGenerateSimpleTableLines(monster_fight_table)); + + //√against hot (friars) for +6 stats/fight potion + //against sleaze (oil peak) for +ML potion + //against spooky (cyrpt, spookyraven ballroom/bathroom) for +60% items from monsters potion + //against stench (filthworms, starting war against hippy) for +60% meat potion + + //cast boner battalion to handle birdform? + //can only cast vicious talon slash/All-You-Can-Beat Wing Buffet 14 times, 15 leads to the feather you don't want (property birdformRoc maybe?) + + //FIXME implement birdform reminders? (like AVOID CASTING X) + + if (my_maxmp() >= 200 && $skill[Summon "Boner Battalion"].skill_is_usable() && !get_property_boolean("_bonersSummoned")) + description.listAppend("Possibly cast the battalion to handle birdform."); //yojimbos_law wants this here, so.. + + if (birdform_description.count() > 0) + description.listAppend(HTMLGenerateSpanOfClass("Birdform", "r_bold") + "|*" + birdform_description.listJoinComponents("|*
")); + + resource_entries.listAppend(ChecklistEntryMake("__item llama lama gong", "inventory.php?ftext=llama+lama+gong", ChecklistSubentryMake(pluralise($item[llama lama gong]), "", description), importance_level_item).ChecklistEntrySetIDTag("Llama lama gong resource")); + + } + + if (!in_run && get_property("_bittycar").length() == 0 && $items[BittyCar HotCar, BittyCar MeatCar,BittyCar SoulCar].available_amount() > 0) { + string [int] available_items; + string [int] available_descriptions; + string [item] item_descriptions; + item_descriptions[$item[BittyCar HotCar]] = "hot damage"; + item_descriptions[$item[BittyCar MeatCar]] = "extra meat"; + item_descriptions[$item[BittyCar SoulCar]] = "HP/MP"; + + + foreach it in $items[BittyCar MeatCar,BittyCar SoulCar,BittyCar HotCar] { + if (it.available_amount() > 0) { + available_items.listAppend(it.to_string().replace_string("BittyCar ", "")); + available_descriptions.listAppend(item_descriptions[it]); + } + } + string description = "Reusable once/day for occasional " + available_descriptions.listJoinComponents(", ", "or") + " in combat."; + resource_entries.listAppend(ChecklistEntryMake("__item BittyCar MeatCar", "inventory.php?ftext=bittycar", ChecklistSubentryMake("BittyCar " + available_items.listJoinComponents(", ", "or") + " usable", "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Bittycars resource")); + } + + if (in_run && !__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "mysticality" && !get_property_ascension("lastGoofballBuy") && __quest_state["Level 3"].started && my_path().id != PATH_ZOMBIE_SLAYER && my_path().id != PATH_COMMUNITY_SERVICE) { + resource_entries.listAppend(ChecklistEntryMake("__item bottle of goofballs", "tavern.php?place=susguy", ChecklistSubentryMake("Bottle of goofballs obtainable", "", "For the lair stat test.|Costs nothing, but be careful..."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Goofballs resource")); + } + + if ($item[tonic djinn].available_amount() > 0 && in_ronin() && in_run && !get_property_boolean("_tonicDjinn") && my_path().id != PATH_G_LOVER) { + string [int] possibilities; + possibilities.listAppend("~450 meat (Wealth!)"); + if (__misc_state["need to level"]) { + string mainstat_choice; + if (my_primestat() == $stat[muscle]) + mainstat_choice = "Strength!"; + else if (my_primestat() == $stat[mysticality]) + mainstat_choice = "Wisdom!"; + else if (my_primestat() == $stat[moxie]) + mainstat_choice = "Panache!"; + + if (mainstat_choice.length() != 0) + possibilities.listAppend("~60 mainstats (" + mainstat_choice + ")"); + } + + string [int] description; + description.listAppend("Use for " + possibilities.listJoinComponents(", ", "or")); + + resource_entries.listAppend(ChecklistEntryMake("__item tonic djinn", "inventory.php?ftext=tonic+djinn", ChecklistSubentryMake("Tonic djinn", "", description), importance_level_unimportant_item).ChecklistEntrySetIDTag("Tonic djinn resource")); + } + + // Removed an is_unrestricted check; I think this actually is fine, since this checks ownership, and + // you can't own it unless you are in a path where you can use it or the replica. + + if (__iotms_usable[lookupItem("V for Vivala mask")]) { + if (!get_property_boolean("_vmaskBanisherUsed")) { + string url; + string [int] description; + if (__misc_state["free runs usable"]) + description.listAppend("Once/day free run/banisher. (combat skill)"); + else + description.listAppend("Once/day banisher. (combat skill)"); + + if ($item[V for Vivala mask].equipped_amount() == 0) { + if ($item[replica V for Vivala mask].equipped_amount() == 0) { + description.listAppend("Equip V for Vivala mask first."); + url = "inventory.php?ftext=v+for+vivala"; + } + } + string line = "Costs "; + if (my_mp() < 30) + line += HTMLGenerateSpanFont("30 MP", "red"); + else + line += "30 MP"; + description.listAppend(line + "."); + resource_entries.listAppend(ChecklistEntryMake("__item V for Vivala mask", url, ChecklistSubentryMake("Creepy Grin usable", "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Vivala mask banish")); + } + if (get_property_int("_vmaskAdv") < 10) { + string url; + string [int] description; + int critAdvs_remaining = 10 - get_property_int("_vmaskAdv"); + + if ($item[V for Vivala mask].equipped_amount() == 0) { + if ($item[replica V for Vivala mask].equipped_amount() == 0) { + description.listAppend("Equip V for Vivala mask first."); + url = "inventory.php?ftext=v+for+vivala"; + } + } + description.listAppend("Land critical hits for chance of getting adventures."); + description.listAppend("Also a pseudopickpocket."); + resource_entries.listAppend(ChecklistEntryMake("__item V for Vivala mask", url, ChecklistSubentryMake(pluralise(critAdvs_remaining, "V for Vivala mask adventure available", "V for Vivala mask adventures available"), "+critical%", description), importance_level_item).ChecklistEntrySetIDTag("Vivala mask resource")); + } + } + + if ($item[moveable feast].available_amount() > 0 && $item[moveable feast].is_unrestricted() && get_property_int("_feastUsed") < 5) { + string [int] description; + string url = "inventory.php?ftext=moveable+feast"; + int feastings_left = clampi(5 - get_property_int("_feastUsed"), 0, 5); + + description.listAppend("Gives +10 familiar weight for twenty turns to a specific familiar."); + string [int] familiars_used_on = get_property("_feastedFamiliars").split_string_alternate(";"); //separator: ";" + if (in_run && __misc_state["free runs usable"]) { + string [int] familiars_could_imbue_for_del_shannon; + boolean [familiar] familiars_used_on_inverse; + foreach key, f_name in familiars_used_on { + familiar f = f_name.to_familiar(); + if (f != $familiar[none]) + familiars_used_on_inverse[f] = true; + } + foreach f in $familiars[pair of stomping boots,Frumious Bandersnatch] { + if (f.familiar_is_usable() && !(familiars_used_on_inverse contains f)) { + familiars_could_imbue_for_del_shannon.listAppend(f); + } + } + if (familiars_could_imbue_for_del_shannon.count() > 0) { + description.listAppend("Could feed " + familiars_could_imbue_for_del_shannon.listJoinComponents(", ", "or") + " for +2 free runs."); + } + } + + if (familiars_used_on.count() > 0) + description.listAppend("Already used on " + familiars_used_on.listJoinComponents(", ", "and") + "."); + resource_entries.listAppend(ChecklistEntryMake("__item moveable feast", url, ChecklistSubentryMake(pluralise(feastings_left, "moveable feasting", "moveable feastings"), "", description), importance_level_item).ChecklistEntrySetIDTag("Moveable feast resource")); + //_feastedFamiliars + } + + if ($item[cosmic calorie].available_amount() > 0 && in_run) { + string [int][int] table; + table.listAppend(listMake("Cost", "Item", "Effect")); + + string [item] celestial_descriptions; + celestial_descriptions[$item[celestial olive oil]] = "+1 all res"; + celestial_descriptions[$item[celestial carrot juice]] = "+30% item"; + celestial_descriptions[$item[celestial au jus]] = "+5% combat"; + celestial_descriptions[$item[celestial squid ink]] = "-5% combat"; + int [item] calories_required; + calories_required[$item[celestial olive oil]] = 20; + calories_required[$item[celestial carrot juice]] = 30; + calories_required[$item[celestial au jus]] = 50; + calories_required[$item[celestial squid ink]] = 60; + foreach it in $items[celestial olive oil,celestial carrot juice,celestial au jus,celestial squid ink] { + int amount = it.creatable_amount() + it.available_amount(); + + string [int] line; + line = listMake(calories_required[it], it, celestial_descriptions[it]); + if (amount == 0) { + foreach key, s in line { + line[key] = HTMLGenerateSpanFont(s, "grey"); + } + } + table.listAppend(line); + } + string [int] description; + description.listAppend(HTMLGenerateSimpleTableLines(table)); + resource_entries.listAppend(ChecklistEntryMake("__item cosmic calorie", "inventory.php?ftext=cosmic+calorie", ChecklistSubentryMake(pluralise($item[cosmic calorie]), "", description), importance_level_item).ChecklistEntrySetIDTag("Cosmic calorie resource")); + + } + + if ($item[portable cassette player].available_amount() > 0 && (__misc_state["in run"] || $item[portable cassette player].equipped_amount() > 0) && $item[portable cassette player].is_unrestricted()) { + string [int] description; + string url = ""; + int modulus = total_turns_played() % 40; + + string [effect] buff_descriptions; + buff_descriptions[$effect[Dark Orchestral Song]] = "+5 moxie"; + buff_descriptions[$effect[Pet Shop Song]] = "+10% init"; + buff_descriptions[$effect[Dangerous Zone Song]] = "+25% meat"; + buff_descriptions[$effect[Flashy Dance Song]] = "+10% item"; + + effect [int] buffs_activate_at; //NOT a linear list + buffs_activate_at[0] = $effect[Dark Orchestral Song]; + buffs_activate_at[10] = $effect[Pet Shop Song]; + buffs_activate_at[20] = $effect[Dangerous Zone Song]; + buffs_activate_at[30] = $effect[Flashy Dance Song]; + + boolean [effect] buffs_to_display_for_future = $effects[Dangerous Zone Song,Flashy Dance Song]; + + boolean [effect] buffs_to_not_bother_display_current_for = $effects[Dark Orchestral Song,Pet Shop Song]; //+10% init is like +1% chance of extra modern zmobies, which saves an extremely small fraction of a turn. ignore, because cognitive load + you might run better accessories instead, like +ML. plus, you have to use that weird fiddly technique because of +combat + string [int] future_buffs; + foreach mod_value, buff in buffs_activate_at { + string buff_description = buff_descriptions[buff]; + if (modulus >= mod_value && modulus < mod_value + 10) { + if (buffs_to_not_bother_display_current_for contains buff) { + continue; + } + int turns_remaining = 10 - modulus % 10; + string line = buff_description; + if (buff.have_effect() == 0) + line += " obtainable"; + else { + if (turns_remaining < buff.have_effect()) { + turns_remaining = buff.have_effect(); + line += " active"; + } + } + line += " for " + pluralise(turns_remaining, " more turn", " more turns"); + boolean have_other_song_active = false; + effect other_song = $effect[none]; + foreach e in $effects[Dark Orchestral Song,Pet Shop Song,Dangerous Zone Song,Flashy Dance Song] { + if (e != buff && e.have_effect() > 0) { + other_song = e; + have_other_song_active = true; + } + } + if (have_other_song_active) { + line += " after losing current"; + if (!(buffs_to_not_bother_display_current_for contains other_song)) + line += " " + buff_descriptions[other_song]; + line += " song. (unequip cassette for a turn)"; + } else + line += "."; + if (buff.have_effect() == 0 && !have_other_song_active && $item[portable cassette player].equipped_amount() == 0) + line += " (equip player)"; + description.listAppend(line); + continue; + } + if (buffs_to_display_for_future contains buff) { + int turns_until = mod_value - modulus; + if (turns_until < 0) + turns_until += 40; + future_buffs.listAppend(pluralise(turns_until, "more turn", "more turns") + " until " + buff_description); + } + } + if (future_buffs.count() > 0) + description.listAppend(future_buffs.listJoinComponents(", ").capitaliseFirstLetter() + "."); + + //description.listAppend("Modulus " + modulus + "."); + resource_entries.listAppend(ChecklistEntryMake("__item portable cassette player", url, ChecklistSubentryMake("Portable cassette player buffs", "", description), 10).ChecklistEntrySetIDTag("Portable cassette player")); + } + if (can_equip_outfit("Hodgman's Regal Frippery")) { + int underling_summons_remaining = clampi(5 - get_property_int("_hoboUnderlingSummons"), 0, 5); + if (underling_summons_remaining > 0) { + string url; + string [int] description; + description.listAppend("Combat skill while wearing the frippery. For a single fight, adds +100% meat (joke) or +100% item (dance)."); + if (!is_wearing_outfit("Hodgman's Regal Frippery")) { + url = invSearch("hodgman"); + description.listAppend("Equip frippery first."); + } + resource_entries.listAppend(ChecklistEntryMake("__skill Summon hobo underling", url, ChecklistSubentryMake(pluralise(underling_summons_remaining, "hobo underling summon", "hobo underling summons"), "", description), -1).ChecklistEntrySetIDTag("Hodgman regal frippery resource")); + } + } + if (lookupItem("license to chill").available_amount() > 0 && !get_property_boolean("_licenseToChillUsed") && mafiaIsPastRevision(18122)) { + resource_entries.listAppend(ChecklistEntryMake("__item License to Chill", "inventory.php?ftext=license+to+chill", ChecklistSubentryMake("License to Chill", "", "+5 adventures, extend effects by one turn, HP/MP restore, statgain."), 10).ChecklistEntrySetIDTag("License to chill")); + + } + if (lookupItem("etched hourglass").available_amount() > 0 && !get_property_boolean("_etchedHourglassUsed")) { + resource_entries.listAppend(ChecklistEntryMake("__item etched hourglass", "inventory.php?ftext=etched+hourglass", ChecklistSubentryMake("Etched Hourglass", "", "+5 adventures."), 10).ChecklistEntrySetIDTag("Etched hourglass resource")); + + } + if ($item[mafia middle finger ring].available_amount() > 0 && !get_property_boolean("_mafiaMiddleFingerRingUsed")) { + resource_entries.listAppend(ChecklistEntryMake("__item mafia middle finger ring", ($item[mafia middle finger ring].equipped_amount() == 0 ? $item[mafia middle finger ring].invSearch() : ""), ChecklistSubentryMake("Mafia middle finger ring banish/free run", "", "Once/day, 60 turn duration." + ($item[mafia middle finger ring].equipped_amount() == 0 ? " Equip first." : "")), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Mafia middle finger ring banish")); + + } + + if (get_property_int("_glitchMonsterFights") == 0 && lookupItem("[glitch season reward name]").item_amount() > 0) { + string [int] description; + int glitch_amount = lookupItem("[glitch season reward name]").item_amount(); + int glitch_monster_powah = 5 * glitch_amount * get_property_int("glitchItemImplementationCount"); + + description.listAppend("Has " + (glitch_monster_powah > 0 ? glitch_monster_powah : 1) + " HP/ATK/DEF. Gives " + (glitch_monster_powah > 0 ? glitch_monster_powah.to_string() : "no") + " HP/MP/meat."); //Has 0 defense if at 1 HP/ATK, but who cares... + + description.listAppend("Try to eat one (with chat macro) to fight it (not consumed)."); + + if (glitch_amount >= 2) + description.listAppend("Closet " + (glitch_amount > 2 ? "some" : "one") + " of them to decrease its power (...and reward)."); + + int glitch_in_closet = (get_property_boolean("autoSatisfyWithCloset") ? lookupItem("[glitch season reward name]").closet_amount() : 0); + if (glitch_in_closet >= 1) + description.listAppend("Uncloset " + (glitch_in_closet > 1 ? "some" : "one") + " to " + (glitch_amount > 1 ? "increase" : "multiply") + " its power and reward."); + + resource_entries.listAppend(ChecklistEntryMake("__item [glitch season reward name]", "inventory.php?ftext=%5Bglitch+season+reward+name%5D", ChecklistSubentryMake("[glitch season reward name] free fight", "", description), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Glitch reward free fight")); + } +} + + +void SCouncilGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__misc_state["in run"]) + return; + if (my_path().id == PATH_COMMUNITY_SERVICE) + return; + boolean council_probably_wants_to_speak_to_you = false; + string [int] reasons; + boolean [string] seen_quest_name; + foreach quest_name in __quest_state + { + QuestState state = __quest_state[quest_name]; + if (state.quest_name == "Island War Quest" && my_path().id == PATH_EXPLOSION) continue; + if (state.startable && !state.in_progress && !state.finished && state.council_quest) + { + if (seen_quest_name[state.quest_name]) + continue; + seen_quest_name[state.quest_name] = true; + reasons.listAppend(state.quest_name); + council_probably_wants_to_speak_to_you = true; + } + } + if (!council_probably_wants_to_speak_to_you) + return; + + string [int] description; + + description.listAppend("Start the " + reasons.listJoinComponents(", ", "and") + "."); + + if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues") && !have_outfit_components("Filthy Hippy Disguise") && __quest_state["Level 12"].startable && !__quest_state["Level 12"].in_progress && !__quest_state["Level 12"].finished && my_path().id != PATH_EXPLOSIONS) + description.listAppend(HTMLGenerateSpanFont("May want to wait", "red") + " until you've acquired a filthy hippy disguise for acquiring a war outfit?"); + if (my_path().id == PATH_EXPLOSIONS) + description.listAppend("You might need to visit your quest log afterwards, to update mafia's tracking."); + task_entries.listAppend(ChecklistEntryMake("council", "place.php?whichplace=town", ChecklistSubentryMake("Visit the Council of Loathing", "", description)).ChecklistEntrySetIDTag("Council visit")); +} + +static +{ + //NOTE: this array does not support non-tradeable, quest, or non-discardable items. It could, but then I'd have to filter those out later, and I'm not sure how fast get_related is. + int [item][item] __inverse_pulverisation; + + void initialisePulverisations() + { + foreach smashing_item in $items[] + { + if (!smashing_item.tradeable || smashing_item.quest || !smashing_item.discardable) + continue; + if (smashing_item.to_slot() == $slot[none]) + continue; + int [item] pulverisations = smashing_item.get_related("pulverize"); + if (pulverisations.count() == 0) + continue; + foreach smash_result, value in pulverisations + { + __inverse_pulverisation[smash_result][smashing_item] = value; + } + } + } + + initialisePulverisations(); +} + +record SmashableItem +{ + item it; + float products_found; +}; + +SmashableItem SmashableItemMake(item it, float products_found) +{ + SmashableItem result; + result.it = it; + result.products_found = products_found; + return result; +} + +void listAppend(SmashableItem [int] list, SmashableItem entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + + +void pulveriseAlterOutputList(string [int] output_list) +{ + //Alter lines so items aren't split up by word wrap: + int number_seen = 0; + foreach key in output_list + { + string line = output_list[key]; + + if (number_seen < output_list.count() - 1) //comma needs to be part of the group + line += ","; + line = HTMLGenerateDivOfClass(line, "r_word_wrap_group"); + + output_list[key] = line; + number_seen += 1; + } +} + +string [int] pulveriseGenerateOutputListForProducts(boolean [item] products_wanted, boolean [item] blacklist) +{ + int [item] smashables_found; + foreach product in products_wanted + { + foreach smashable in __inverse_pulverisation[product] + { + if (smashable.available_amount() == 0) + continue; + if (blacklist[smashable]) + continue; + int value = __inverse_pulverisation[product][smashable]; + smashables_found[smashable] += value; + } + } + + + SmashableItem [int] available_smashed_items; + + foreach smashable, product_count in smashables_found + { + float average_products_acquired = product_count.to_float() / 1000000.0; + available_smashed_items.listAppend(SmashableItemMake(smashable, average_products_acquired)); + } + + sort available_smashed_items by -(value.products_found * value.it.available_amount()); + + string [int] result; + foreach key in available_smashed_items + { + SmashableItem smashable_item = available_smashed_items[key]; + string line; + + line = smashable_item.it; + + result.listAppend(line); + } + + + + pulveriseAlterOutputList(result); + return result; +} + +void pulveriseAppendOutputListForProducts(string [int] description, string category, boolean [item] products_wanted, boolean [item] blacklist) +{ + string [int] output_list = pulveriseGenerateOutputListForProducts(products_wanted, blacklist); + + if (output_list.count() > 0) + { + description.listAppend(HTMLGenerateSpanOfClass(category.capitaliseFirstLetter() + ": ", "r_bold") + output_list.listJoinComponents(" ", "and") + "."); + } +} + +void SPulveriseGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!$skill[pulverize].skill_is_usable()) + return; + if (!in_ronin()) //list is far too long with your main inventory, and you can buy wads at this point + return; + + + /* + Smashable item types: + BRICKO brick + candycaine powder + chunk of depleted Grimacite + cold cluster + cold nuggets + cold powder + cold wad + corrupted stardust + effluvious emerald + epic wad + glacial sapphire + handful of Smithereens + hot cluster + hot nuggets + hot powder + hot wad + sea salt crystal + sleaze cluster + sleaze nuggets + sleaze powder + sleaze wad + spooky cluster + spooky nuggets + spooky powder + spooky wad + steamy ruby + stench cluster + stench nuggets + stench powder + stench wad + sugar shard + tawdry amethyst + twinkly nuggets + twinkly powder + twinkly wad + ultimate wad + unearthly onyx + useless powder + wad of Crovacite + */ + + + boolean [item] blacklist; + blacklist.listAppendList($items[fireman's helmet,fire axe,enchanted fire extinguisher,fire hose,rainbow pearl earring,rainbow pearl necklace,rainbow pearl ring,steaming evil,ring of detect boring doors,giant discarded torn-up glove,giant discarded plastic fork,giant discarded bottlecap,toy ray gun,toy space helmet,toy jet pack,MagiMechTech NanoMechaMech,astronaut pants,ancient hot dog wrapper,bram's choker]); + + if (!__quest_state["Level 12"].finished) + blacklist.listAppendList($items[reinforced beaded headband,bullet-proof corduroys,round purple sunglasses,beer helmet,distressed denim pants,bejeweled pledge pin]); + if (!__quest_state["Level 11 Hidden City"].state_boolean["Hospital finished"]) + blacklist.listAppendList($items[head mirror,surgical apron,bloodied surgical dungarees,surgical mask,half-size scalpel]); + + string [int] details; + + //not relevant for adventures anymore: + /*if (availableSpleen() > 0 && my_path().id != PATH_SLOW_AND_STEADY) + { + pulveriseAppendOutputListForProducts(details, "spleen wads", $items[cold wad,hot wad,sleaze wad,spooky wad,stench wad,twinkly wad], blacklist); + }*/ + + /*if (__misc_state["mysticality guild store available"] && $skill[Transcendental Noodlecraft].skill_is_usable() && $skill[The Way of Sauce].skill_is_usable()) //can make hi mein? + { + pulveriseAppendOutputListForProducts(details, "hi mein elemental nuggets", $items[cold nuggets,hot nuggets,sleaze nuggets,spooky nuggets,stench nuggets], blacklist); + }*/ + + + pulveriseAppendOutputListForProducts(details, "handful of smithereens", $items[handful of smithereens], blacklist); + + //Elemental powder, for +1 resistances? + //Elemental nuggets, for +3 tower test? (very marginal) + + if (details.count() > 0) + { + string title; + title = "Pulverisable equipment"; + string url = "craft.php?mode=smith"; + if ($item[tenderizing hammer].available_amount() == 0) + { + url = "shop.php?whichshop=meatsmith"; + details.listAppend("Acquire a tenderizing hammer."); + } + resource_entries.listAppend(ChecklistEntryMake("__skill pulverize", url, ChecklistSubentryMake(title, "", details), 10).ChecklistEntrySetIDTag("Pulverize suggestions")); + } +} + + +void SAftercoreThingsToDoGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //To implement: + //The Sea - rescuing mom, √temple boss if they're missing anything, that one skater quest, whatever else is there + //The suburbs of dis? Is this detectable? + //Farming four shore inc. trip scrip for ascension. + //√Space elves. + //telescope upgrades - telescopeUpgrades (needs basement level check) + //dungeons? slime tube, hobopolis, dreadsylvania, library, items and skills and such + //hobo codes? (no support) + //demon names + //el vibrato island - familiar, mostly, plus items? (bad moon check) + //agua de vida memories quest? + //artist quest? + //going postal quest + //bounty hunting + //starting SBB quests / UMD in inventory to use + //examine http://kol.coldfront.net/thekolwiki/index.php/Quest_Spoilers + //jung jar items + //dwarven factory + + Record AftercoreOption + { + string header; + string url; + string [int] description; + }; + AftercoreOption AftercoreOptionMake(string header, string url, string [int] description) + { + AftercoreOption task; + task.header = header; + task.url = url; + task.description = description; + return task; + } + void listAppend(AftercoreOption [int] list, AftercoreOption entry) + { + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; + } + + + AftercoreOption [int] options; + + if (knoll_available() && !QuestState("questM03Bugbear").started) + { + options.listAppend(AftercoreOptionMake("Felonia quest", "place.php?whichplace=knoll_friendly", listMake("speak to Mayor Zapruder", "rewards once/ascension mushroom fermenting solution"))); + } + + if (!QuestState("questG04Nemesis").started) + { + string [int] things_gives; + things_gives.listAppend("instant karma"); + if (my_class() == $class[disco bandit]) + things_gives.listAppend("rave skills"); + options.listAppend(AftercoreOptionMake("Nemesis quest", "guild.php", listMake("Rewards " + things_gives.listJoinComponents(", ", "and")))); + } + + if (!QuestState("questF04Elves").started && $effect[transpondent].have_effect() == 0) + { + string url; + string first_task; + if ($item[transporter transponder].available_amount() > 0) + { + url = "inventory.php?ftext=transporter+transponder"; + first_task = "use transporter transponder"; + } + else + { + url = "mall.php"; + first_task = "buy and use transporter transponder"; + } + options.listAppend(AftercoreOptionMake("Repair the Elves' Shield Generator", url, listMake(first_task, "rewards 200 lunar isotopes, and space store access"))); + } + + + if (false) //FIXME disabled for now - we don't have suggestions for every path, and this may be too much information to list? need to decide + { + //Grimstone: + string [item] grimstone_paths; + grimstone_paths[$item[silver cow creamer]] = "stepmother"; + grimstone_paths[$item[wolf whistle]] = "wolf"; + grimstone_paths[$item[witch's bra]] = "witch"; + if (__campground[$item[spinning wheel]] == 0) + grimstone_paths[$item[spinning wheel]] = "gnome"; + grimstone_paths[$item[hare pin]] = "hare"; + + string [int] relevant_grimstone_paths; + item [int] relevant_rewards; + foreach it in grimstone_paths + { + if (haveAtLeastXOfItemEverywhere(it, 1)) + continue; + relevant_grimstone_paths.listAppend(grimstone_paths[it]); + relevant_rewards.listAppend(it); + } + if (relevant_grimstone_paths.count() > 0) + { + string path_string = "path available"; + if (relevant_grimstone_paths.count() > 1) + path_string = "paths available"; + + options.listAppend(AftercoreOptionMake("grimstone mask quests", "", listMake(relevant_grimstone_paths.listJoinComponents(", ", "and") + " " + path_string, "Rewards " + relevant_rewards.listJoinComponents(", ", "or")))); + } + } + + if (get_property("merkinQuestPath") == "none" || get_property("merkinQuestPath").length() == 0) + { + //Do they need to complete that quest? Let's find out. + item [class][int] class_temple_items; + boolean [item] loathing_craftable_items = $items[belt of loathing,goggles of loathing,jeans of loathing,scepter of loathing,stick-knife of loathing,treads of loathing]; + class_temple_items[$class[seal clubber]] = listMake($item[Cold Stone of Hatred], $item[Ass-Stompers of Violence]); + class_temple_items[$class[turtle tamer]] = listMake($item[Girdle of Hatred], $item[Brand of Violence]); + class_temple_items[$class[pastamancer]] = listMake($item[Staff of Simmering Hatred], $item[Novelty Belt Buckle of Violence]); + class_temple_items[$class[sauceror]] = listMake($item[Pantaloons of Hatred], $item[Lens of Violence]); + class_temple_items[$class[disco bandit]] = listMake($item[Fuzzy Slippers of Hatred], $item[Pigsticker of Violence]); + class_temple_items[$class[accordion thief]] = listMake($item[Lens of Hatred], $item[Jodhpurs of Violence]); + + //For our class, determine what items we're missing: + item [int] our_class_items = class_temple_items[my_class()]; + int [item] total_amount_of_item_wanted; + boolean [item] want_item_for_crafting_loathing; + foreach key, it in our_class_items + { + total_amount_of_item_wanted[it] = 1; + } + foreach loathing_piece in loathing_craftable_items + { + if (haveAtLeastXOfItemEverywhere(loathing_piece, 1)) + continue; + int [item] components = loathing_piece.get_ingredients_fast(); + foreach component in components + { + if (total_amount_of_item_wanted contains component) //if this component is part of our class components + { + total_amount_of_item_wanted[component] += 1; + want_item_for_crafting_loathing[component] = true; + } + } + } + string [int] description_items; + foreach it, amount in total_amount_of_item_wanted + { + int missing = amount - it.item_amount_almost_everywhere(); + if (missing <= 0) + continue; + string line = "a " + it; + if (it.to_string().contains_text("Violence")) + line += " (gladiator path)"; + else + line += " (scholar path)"; + if (want_item_for_crafting_loathing[it]) + { + line += " for loathing gear piece"; + if (missing >= 2) + line += "/to own"; + } + description_items.listAppend(line); + } + if (description_items.count() > 0) + options.listAppend(AftercoreOptionMake("mer-kin temple in the sea", "", listMake("can find " + description_items.listJoinComponents(", ", "or")))); + } + if (__misc_state["stench airport available"] && !get_property_ascension("lastWartDinseyDefeated")) + { + item dinsey_item; + if (my_class() == $class[seal clubber]) + dinsey_item = $item[Dinsey's oculus]; + else if (my_class() == $class[turtle tamer]) + dinsey_item = $item[Dinsey's radar dish]; + else if (my_class() == $class[pastamancer]) + dinsey_item = $item[Dinsey's pizza cutter]; + else if (my_class() == $class[sauceror]) + dinsey_item = $item[Dinsey's brain]; + else if (my_class() == $class[disco bandit]) + dinsey_item = $item[Dinsey's pants]; + else if (my_class() == $class[accordion thief]) + dinsey_item = $item[Dinsey's glove]; + + if (dinsey_item != $item[none] && !haveAtLeastXOfItemEverywhere(dinsey_item, 1)) + { + location [item] keycards; + + keycards[$item[keycard α]] = $location[Barf Mountain]; + keycards[$item[keycard β]] = $location[Pirates of the Garbage Barges]; + keycards[$item[keycard γ]] = $location[The Toxic Teacups]; + keycards[$item[keycard δ]] = $location[Uncle Gator's Country Fun-Time Liquid Waste Sluice]; + location [int] missing_locations; + item [int] missing_keycards; + foreach it, l in keycards + { + if (it.available_amount() == 0) + { + missing_keycards.listAppend(it); + missing_locations.listAppend(l); + } + + } + if (missing_keycards.count() > 0) + { + options.listAppend(AftercoreOptionMake("defeat Wart Dinsey", "", listMake("Find keycards in " + missing_locations.listJoinComponents(", ", "and")))); + } + } + } + + if (options.count() > 0) + { + string [int] description; + string url = ""; + foreach key, option in options + { + option.header = option.header.capitaliseFirstLetter(); + foreach key in option.description + { + option.description[key] = option.description[key].capitaliseFirstLetter() + "."; + } + if (url.length() == 0) + url = option.url; + description.listAppend(option.header + HTMLGenerateIndentedText(option.description.listJoinComponents("
"))); + } + optional_task_entries.listAppend(ChecklistEntryMake("__effect confused", url, ChecklistSubentryMake("Try an optional quest", "", description), 8).ChecklistEntrySetIDTag("Aftercore task suggestions")); + } +} + +void SAftercoreGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__misc_state["in aftercore"]) + return; + //Campground items: + if (__campground[$item[clockwork maid]] == 0) + { + string url = "mall.php?pudnuggler=%22clockwork+maid"; + optional_task_entries.listAppend(ChecklistEntryMake("__item sprocket", url, ChecklistSubentryMake("Install a clockwork maid", "", listMake("+8 adventures/day.", "Buy from mall."))).ChecklistEntrySetIDTag("Aftercore task clockwork maid")); + } + if (__campground[$item[pagoda plans]] == 0 && $location[Pandamonium Slums].locationAvailable()) + { + string url; + string [int] details; + details.listAppend("+3 adventures/day."); + + if ($item[hey deze nuts].item_amount() == 0) + { + if ($item[hey deze map].item_amount() == 0) + { + url = "pandamonium.php"; + details.listAppend("Adventure in Pandamonium Slums for Hey Deze Map. (25% superlikely)"); + } + else + { + string [int] things_to_do; + string [int] things_to_buy; + if ($item[heavy metal sonata].item_amount() == 0) + things_to_buy.listAppend("heavy metal sonata"); + if ($item[heavy metal thunderrr guitarrr].item_amount() == 0) + things_to_buy.listAppend("heavy metal thunderrr guitarrr"); + if ($item[guitar pick].item_amount() == 0) + things_to_buy.listAppend("guitar pick"); + if (things_to_buy.count() > 0) + things_to_do.listAppend("buy " + things_to_buy.listJoinComponents(", ", "and") + " in mall, "); + things_to_do.listAppend("use hey deze map"); + details.listAppend(things_to_do.listJoinComponents("", "then").capitaliseFirstLetter() + "."); + } + } + if ($item[pagoda plans].item_amount() == 0) + { + if ($item[Elf Farm Raffle ticket].item_amount() == 0) + { + details.listAppend("Buy a Elf Farm Raffle ticket from the mall."); + } + else + { + if (url.length() == 0) + url = "inventory.php?which=3"; + if (in_bad_moon()) //Does bad moon aftercore require a clover? + { + details.listAppend("Use Elf Farm Raffle ticket."); + } + else + { + details.listAppend("Acquire ten-leaf clover, then use Elf Farm Raffle ticket."); + } + } + } + if ($item[ketchup hound].item_amount() == 0) + { + if (url.length() == 0) + url = "mall.php"; + details.listAppend("Buy a ketchup hound from the mall."); + } + if ($item[ketchup hound].item_amount() > 0 && $item[hey deze nuts].item_amount() > 0 && $item[pagoda plans].item_amount() > 0) + { + if (url.length() == 0) + url = "inventory.php?ftext=ketchup+hound"; + details.listAppend("Use a ketchup hound to install pagoda."); + } + optional_task_entries.listAppend(ChecklistEntryMake("__item pagoda plans", url, ChecklistSubentryMake("Install a pagoda", "", details)).ChecklistEntrySetIDTag("Aftercore task pagoda")); + } + + if (knoll_available() && !have_mushroom_plot() && get_property("plantingScript") != "") + { + //They can plant a mushroom plot, and they have a planting script. But they haven't yet, so let's suggest it: + optional_task_entries.listAppend(ChecklistEntryMake("__item knob mushroom", "knoll_mushrooms.php", ChecklistSubentryMake("Plant a mushroom plot", "", "Degrassi Knoll")).ChecklistEntrySetIDTag("Aftercore task mushroom plot")); + } + + + SAftercoreThingsToDoGenerateTasks(task_entries, optional_task_entries, future_task_entries); +} + +//Lock Picking +RegisterTaskGenerationFunction("LockPickingGenerateTasks"); +void LockPickingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (get_property_boolean("lockPicked") == true || !lookupSkill("Lock Picking").have_skill()) + return; + { + string [int] description; + string main_title = "Pick a lock!"; + description.listAppend("Grab your mainstat key, probably."); + task_entries.listAppend(ChecklistEntryMake("__skill lock picking", "skillz.php", ChecklistSubentryMake(main_title, "", description), -11)); + } +} + +void SDailyDungeonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) { + return; + } + + if (__last_adventure_location == $location[The Daily Dungeon]) + { + if ($item[ring of detect boring doors].equipped_amount() == 0 && $item[ring of detect boring doors].available_amount() > 0 && !get_property_boolean("dailyDungeonDone") && get_property_int("_lastDailyDungeonRoom") < 10) + { + task_entries.listAppend(ChecklistEntryMake("__item ring of detect boring doors", "inventory.php?ftext=ring+of+detect+boring+doors", ChecklistSubentryMake("Wear ring of detect boring doors", "", "Speeds up daily dungeon"), -11).ChecklistEntrySetIDTag("Daily dungeon detect boring door reminder")); + } + if (familiar_is_usable($familiar[gelatinous cubeling]) && ($item[pick-o-matic lockpicks].available_amount() == 0 || $item[eleven-foot pole].available_amount() == 0 || $item[Ring of Detect Boring Doors].available_amount() == 0)) //have familiar, but not the drops + { + task_entries.listAppend(ChecklistEntryMake("__familiar gelatinous cubeling", "", ChecklistSubentryMake("Use a gelatinous cubeling first", "", "You're adventuring in the daily dungeon without cubeling drops."), -11).ChecklistEntrySetIDTag("Daily dungeon gelatinous cubeling drops reminder")); + } + } + + + boolean need_to_do_daily_dungeon = false; + + if (__misc_state_int["fat loot tokens needed"] > 0) + need_to_do_daily_dungeon = true; + + string [int] daily_dungeon_aftercore_items_wanted; + + if (__misc_state["in aftercore"]) + { + int tokens_needed = 0; + if (!__misc_state["familiars temporarily missing"]) + { + if (!have_familiar_replacement($familiar[gelatinous cubeling]) && $item[dried gelatinous cube].available_amount() == 0) + { + daily_dungeon_aftercore_items_wanted.listAppend("gelatinous cubeling"); + tokens_needed += 27; + } + } + if (!__misc_state["skills temporarily missing"]) + { + if (!$skill[singer's faithful ocelot].skill_is_usable() && $item[Spellbook: Singer's Faithful Ocelot].available_amount() == 0) + { + daily_dungeon_aftercore_items_wanted.listAppend("Singer's faithful ocelot"); + tokens_needed += 15; + } + if (!$skill[Drescher's Annoying Noise].skill_is_usable() && $item[Spellbook: Drescher's Annoying Noise].available_amount() == 0) + { + daily_dungeon_aftercore_items_wanted.listAppend("Drescher's Annoying Noise"); + tokens_needed += 15; + } + if (!$skill[Walberg's Dim Bulb].skill_is_usable() && $item[Spellbook: Walberg's Dim Bulb].available_amount() == 0) + { + daily_dungeon_aftercore_items_wanted.listAppend("Walberg's Dim Bulb"); + tokens_needed += 15; + } + } + if (tokens_needed > $item[fat loot token].available_amount()) + { + need_to_do_daily_dungeon = true; + __misc_state_int["fat loot tokens needed"] += tokens_needed - $item[fat loot token].available_amount(); + } + } + //When we're down to two potential skeleton keys, mention they shouldn't use them in the door. + int skeleton_key_amount = $item[skeleton key].available_amount() + $item[skeleton key].creatable_amount(); + boolean avoid_using_skeleton_key = ($item[Platinum Yendorian Express Card].available_amount() == 0 && $item[pick-o-matic lockpicks].available_amount() == 0 && (skeleton_key_amount) <= 2 && skeleton_key_amount > 0 && !__quest_state["Level 13"].state_boolean["Past keys"] && in_ronin()); + + boolean delay_daily_dungeon = false; + string delay_daily_dungeon_reason = ""; + if (need_to_do_daily_dungeon) + { + if (familiar_is_usable($familiar[gelatinous cubeling])) + { + item [int] missing_items; + string gelatinousCubelingProgress = get_property("cubelingProgress"); + int priority = CHECKLIST_DEFAULT_IMPORTANCE; + + missing_items = $items[eleven-foot pole,ring of detect boring doors,pick-o-matic lockpicks].items_missing(); + if (missing_items.count() > 0) + { + delay_daily_dungeon = true; + delay_daily_dungeon_reason = "Bring along the gelatinous cubeling first"; + ChecklistSubentry subentry; + + string url = ""; + if (my_familiar() != $familiar[gelatinous cubeling]) + url = "familiar.php"; + + // Cubeling progress added to the tile + int progress = get_property_int("cubelingProgress"); + subentry.header = (12 - progress).pluralise("Gelatinous Cubeling kill", "Gelatinous Cubeling kills") + " remaining"; + + subentry.entries.listAppend("Acquire " + missing_items.listJoinComponents(", ", "and") + " to speed up the daily dungeon."); + + if (missing_items.count() == 1 && missing_items[0] == $item[pick-o-matic lockpicks] && skeleton_key_amount > 1) + { + subentry.entries.listAppend("Or ignore this and use the skeleton keys. (slightly risky)"); + priority = 8; + } + + optional_task_entries.listAppend(ChecklistEntryMake("__familiar gelatinous cubeling", url, subentry, priority).ChecklistEntrySetIDTag("Daily dungeon gelatinous cubeling reminder")); + } + } + else + { + //No gelatinous cubeling. + //But! We can acquire a skeleton key in-run. + //So suggest doing that: + boolean can_make_skeleton_key = ($items[loose teeth,skeleton bone].items_missing().count() == 0); + + if (!avoid_using_skeleton_key && ($item[pick-o-matic lockpicks].available_amount() == 0 && $item[Platinum Yendorian Express Card].available_amount() == 0 && $item[skeleton key].available_amount() == 0 && (!__quest_state["Level 7"].state_boolean["nook finished"] || can_make_skeleton_key))) //they don't have lockpicks or a key, and they can reasonably acquire a key + { + delay_daily_dungeon = true; + if (can_make_skeleton_key) + delay_daily_dungeon_reason = "Make a skeleton key first. (you have the ingredients)"; + else + { + delay_daily_dungeon_reason = "Acquire a skeleton key first. (from defiled nook)"; + if (!in_bad_moon() && my_path().id != PATH_OXYGENARIAN) //FIXME state track this elsewhere + delay_daily_dungeon_reason += "|Unless you can't reach that by the end of today."; + } + + + if (can_make_skeleton_key) + { + ChecklistEntry cl = ChecklistEntryMake("__item skeleton key", "", ChecklistSubentryMake("Make a skeleton key", "", listMake("You have the ingredients.", "Speeds up the daily dungeon."))); + cl.tags.id = "Daily dungeon skeleton key reminder"; + if (__last_adventure_location == $location[The Daily Dungeon]) + { + cl.importance_level = -11; + task_entries.listAppend(cl); + } + else + optional_task_entries.listAppend(cl); + } + } + } + } + + + //Pop up a warning: + if (__last_adventure_location == $location[the daily dungeon] && avoid_using_skeleton_key && $item[skeleton key].available_amount() > 0) + { + task_entries.listAppend(ChecklistEntryMake("__item skeleton key", "", ChecklistSubentryMake("Avoid using the skeleton key in the daily dungeon", "", listMake("Running low, will need one for the tower.")), -11).ChecklistEntrySetIDTag("Daily dungeon skeleton key avoid")); + } + + if (get_property_int("_lastDailyDungeonRoom") > 0) + need_to_do_daily_dungeon = true; + if (need_to_do_daily_dungeon && !get_property_boolean("dailyDungeonDone")) + { + if (delay_daily_dungeon) + { + future_task_entries.listAppend(ChecklistEntryMake("daily dungeon", "da.php", ChecklistSubentryMake("Daily Dungeon", "", delay_daily_dungeon_reason), $locations[the daily dungeon]).ChecklistEntrySetIDTag("Daily dungeon later")); + } + else + { + string url = "da.php"; + string [int] description; + string l; + + if (__misc_state_int["fat loot tokens needed"] > 0) + l = pluralise(__misc_state_int["fat loot tokens needed"], "token", "tokens") + " needed."; + + if (daily_dungeon_aftercore_items_wanted.count() > 0) + { + if (l != "") + l += "|"; + l += "Missing " + daily_dungeon_aftercore_items_wanted.listJoinComponents(", ", "and") + ". Possibly buy "; + if (daily_dungeon_aftercore_items_wanted.count() > 1) + l += "them"; + else + l += "it"; + l += " in the mall?"; + } + if (l != "") + description.listAppend(l); + if (!__misc_state["in aftercore"]) + { + string submessage = ""; + if (familiar_is_usable($familiar[gelatinous cubeling])) + submessage = ""; + if (__misc_state["zap wand available"] && __misc_state_int["DD Tokens and keys available"] > 0) + submessage = "Or zap for it"; + if (submessage != "") + description.listAppend(submessage); + } + + if (!in_ronin() && !have_familiar_replacement($familiar[gelatinous cubeling])) + { + string [int] shopping_list; + foreach it in $items[eleven-foot pole,ring of detect boring doors,pick-o-matic lockpicks] + { + if (it.available_amount() > 0) + continue; + if (it == $item[pick-o-matic lockpicks] && $item[skeleton key].available_amount() > 0) + continue; + shopping_list.listAppend(it); + } + if (shopping_list.count() > 0) + description.listAppend("Buy " + shopping_list.listJoinComponents(", ", "and") + " from mall."); + } + + int rooms_left = MAX(0, 15 - get_property_int("_lastDailyDungeonRoom")); + boolean need_ring = true; + if (get_property_int("_lastDailyDungeonRoom") > 10) + { + need_ring = false; + } + if ($item[ring of detect boring doors].available_amount() > 0 && need_ring) + { + if ($item[ring of detect boring doors].equipped_amount() == 0) + { + url = "inventory.php?ftext=ring+of+detect+boring+doors"; + description.listAppend("Wear the ring of detect boring doors."); + } + else + description.listAppend("Keep the ring of detect boring doors equipped."); + } + + + if (rooms_left < 15) + description.listAppend(pluraliseWordy(rooms_left, "room", "rooms").capitaliseFirstLetter() + " left."); + + if (avoid_using_skeleton_key && $item[skeleton key].available_amount() > 0) + description.listAppend(HTMLGenerateSpanOfClass("Avoid using your skeleton key, you don't have many left.", "r_bold")); + + optional_task_entries.listAppend(ChecklistEntryMake("daily dungeon", url, ChecklistSubentryMake("Daily Dungeon", "", description), $locations[the daily dungeon]).ChecklistEntrySetIDTag("Daily dungeon today")); + } + } + +} + +void SDailyDungeonGenerateMissingItems(ChecklistEntry [int] items_needed_entries) +{ + string url = "da.php"; + if (my_path().id == PATH_KINGDOM_OF_EXPLOATHING) + url = "shop.php?whichshop=exploathing"; + + string from_daily_dungeon_string = "From daily dungeon"; + if ($item[fat loot token].available_amount() > 0) + from_daily_dungeon_string += "|" + pluralise($item[fat loot token]) + " available"; + + if ($item[sneaky pete\'s key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["Sneaky Pete\'s key used"]) { + string [int] options; + options.listAppend(from_daily_dungeon_string); + if (__misc_state_int["pulls available"] > 0 && __misc_state["can eat just about anything"] && $item[sneaky pete's key lime pie].item_is_usable()) + options.listAppend("From key lime pie"); + items_needed_entries.listAppend(ChecklistEntryMake("__item Sneaky Pete\'s key", url, ChecklistSubentryMake("Sneaky Pete\'s key", "", options)).ChecklistEntrySetIDTag("Daily dungeon key sneaky_pete")); + } + if ($item[jarlsberg\'s key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["Jarlsberg\'s key used"]) { + string [int] options; + options.listAppend(from_daily_dungeon_string); + if (__misc_state_int["pulls available"] > 0 && __misc_state["can eat just about anything"] && $item[jarlsberg's key lime pie].item_is_usable()) + options.listAppend("From key lime pie"); + items_needed_entries.listAppend(ChecklistEntryMake("__item jarlsberg's key", url, ChecklistSubentryMake("Jarlsberg's key", "", options)).ChecklistEntrySetIDTag("Daily dungeon key jarlsberg")); + } + if ($item[Boris\'s key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["Boris\'s key used"]) { + string [int] options; + options.listAppend(from_daily_dungeon_string); + if (__misc_state_int["pulls available"] > 0 && __misc_state["can eat just about anything"] && $item[boris's key lime pie].item_is_usable()) + options.listAppend("From key lime pie"); + items_needed_entries.listAppend(ChecklistEntryMake("__item Boris's key", url, ChecklistSubentryMake("Boris's key", "", options)).ChecklistEntrySetIDTag("Daily dungeon key boris")); + } +} + +boolean [string] getHolidaysForDate(string realworld_date, int game_day) +{ + boolean [string] holidays; + + if (realworld_date == "0202") + holidays["Groundhog Day"] = true; + //april fools + else if (realworld_date == "0401") + holidays["April Fool's Day"] = true; + //Talk Like a Pirate Day - september 19th + else if (realworld_date == "0919") + holidays["Talk Like a Pirate Day"] = true; + else if (realworld_date == "1031") + holidays["Halloween"] = true; + else if (realworld_date == "0214") + holidays["Valentine's Day"] = true; + else if (realworld_date == "0525") + holidays["Towel Day"] = true; + else if (realworld_date == "0704") + holidays["Dependence Day"] = true; + + //Crimbo + if (now_to_string("M").to_int_silent() == 12) + holidays["Crimbo"] = true; + + //Friday the 13th + if (format_today_to_string("EEE d") == "Fri 13") + holidays["Friday the 13th"] = true; + + + + //Festival of Jarlsberg - acquire the party hat? - Jarlsuary 1 + if (game_day == 0) + holidays["Festival of Jarlsberg"] = true; + //Valentine's Day! - Frankuary 4 + else if (game_day == 11) + holidays["Valentine's Day"] = true; + //St. Sneaky Pete's Day - Starch 3 + else if (game_day == 18) + holidays["St. Sneaky Pete's Day"] = true; + //Oyster Egg Day - April 2 + else if (game_day == 25) + holidays["Oyster Egg Day"] = true; + //El Dia de Los Muertos Borrachos? just wandering monsters... - Martinus 2 + else if (game_day == 33) + holidays["El Dia de Los Muertos Borrachos"] = true; + //Generic Summer Holiday - Bill 3 + else if (game_day == 42) + holidays["Generic Summer Holiday"] = true; + //Dependence Day - Bor 4 + else if (game_day == 51) + holidays["Dependence Day"] = true; + //Arrrbor Day - Petember 4 + else if (game_day == 59) + holidays["Arrrbor Day"] = true; + //Labór Day - Carlvember 6 + else if (game_day == 69) + holidays["Labór Day"] = true; + //Halloween / halloween tomorrow, save adventures? - Porktober 8 + else if (game_day == 79) + holidays["Halloween"] = true; + //feast of boris...? - Boozember 7 + else if (game_day == 86) + holidays["Feast of Boris"] = true; + //Yuletide? - Dougtember 4 + else if (game_day == 91) + holidays["Yuletide"] = true; + + + return holidays; +} + +boolean [string] getHolidaysToday() +{ + boolean [string] holidays = getHolidaysForDate(format_today_to_string("MMdd"), gameday_to_int()); //FIXME Y10K error + if (holiday() != "") + holidays[holiday()] = true; + return holidays; +} + +boolean [string] getHolidaysTomorrow() +{ + //FIXME support next real-world day + return getHolidaysForDate("", ((gameday_to_int() + 1) % 96)); +} + + + + +location [int] generatePossibleLocationsToBurnDelay() +{ + location [int] possible_locations; + foreach l in __place_delays + { + if (l == $location[the hidden park] && __dense_liana_machete_items.available_amount() > 0) continue; + if (l == $location[the oasis] && $effect[ultrahydrated].have_effect() == 0) continue; + if (l == $location[the hidden apartment building] && get_property_int("hiddenApartmentProgress") >= 7) continue; + if (l == $location[the hidden office building] && get_property_int("hiddenOfficeProgress") >= 7) continue; + if ($locations[the spooky forest,the outskirts of cobb's knob] contains l && (my_path().id == PATH_COMMUNITY_SERVICE || __misc_state["in CS aftercore"] || my_path().id == PATH_GREY_GOO)) continue; + + if (l.delayRemainingInLocation() > 0 && l.locationAvailable()) + possible_locations.listAppend(l); + } + return possible_locations; +} +void SCountersInit() +{ + CountersInit(); +} + +string [int] SCountersGenerateDescriptionForRainMonster() +{ + string [int] description; + + string last_terrain = __last_adventure_location.environment; + + string [int] waterbending_skills_can_cast; + + if ($effect[Personal Thundercloud].have_effect() == 0 && $skill[Thundercloud].skill_is_usable()) + waterbending_skills_can_cast.listAppend("Thundercloud"); + + if ($effect[The Rain In Loathing].have_effect() == 0 && $skill[Rainy Day].skill_is_usable()) + waterbending_skills_can_cast.listAppend("Rainy Day"); + + int water_level_modifier = numeric_modifier("water level"); + + string [string][int] monster_for_terrain_depth; + int [string] base_depth_for_terrain; + + foreach terrain in $strings[underground,indoor,outdoor] + { + monster_for_terrain_depth[terrain][1] = "giant isopod"; + monster_for_terrain_depth[terrain][2] = "gourmet gourami"; + monster_for_terrain_depth[terrain][3] = "freshwater bonefish"; + monster_for_terrain_depth[terrain][4] = "alley catfish"; + monster_for_terrain_depth[terrain][5] = "piranhadon"; + } + base_depth_for_terrain["underground"] = 5; + base_depth_for_terrain["indoor"] = 3; + base_depth_for_terrain["outdoor"] = 1; + monster_for_terrain_depth["underground"][6] = "giant tardigrade"; + monster_for_terrain_depth["indoor"][6] = "aquaconda"; + monster_for_terrain_depth["outdoor"][6] = "storm cow"; + + string [string] monster_descriptions; + monster_descriptions["giant isopod"] = "fishbone"; + monster_descriptions["freshwater bonefish"] = "2x fishbone"; + monster_descriptions["piranhadon"] = "3x fishbone"; + monster_descriptions["gourmet gourami"] = "+init potion"; + monster_descriptions["alley catfish"] = "-washaway potion"; + + //init potion + //-washaway potion + // + + monster_descriptions["giant tardigrade"] = "thunder skill"; + monster_descriptions["aquaconda"] = "rain skill"; + monster_descriptions["storm cow"] = "lightning skill"; + + if (__iotms_usable[$item[Little Geneticist DNA-Splicing Lab]] && mafiaIsPastRevision(13918) && !get_property_boolean("_dnaHybrid") && $effect[Human-Fish Hybrid].have_effect() == 0 && !__misc_state["familiars temporarily blocked"]) + { + //FIXME all once spaded + //NOT giant isopod + //gourmet gourami? + //freshwater bonefish + //alley catfish + //piranhadon + foreach s in $strings[gourmet gourami,freshwater bonefish,alley catfish,piranhadon] + { + monster_descriptions[s] = monster_descriptions[s] + " (fish DNA)"; + } + } + + + if (my_mp() > 50) + { + monster_descriptions["storm cow"] += HTMLGenerateSpanFont(", burn MP to 50 to survive", "red"); + } + + boolean have_usable_last_terrain = (last_terrain == "outdoor" || last_terrain == "indoor" || last_terrain == "underground"); + foreach terrain in $strings[outdoor,indoor,underground] + { + int depth_min = base_depth_for_terrain[terrain] + water_level_modifier; + int depth_max = depth_min + 1; + + depth_min = clampi(depth_min, 1, 6); + depth_max = clampi(depth_max, 1, 6); + + string [int] terrain_monsters; + string line = monster_for_terrain_depth[terrain][depth_min]; + //if (monster_descriptions contains line) + //line += " (" + monster_descriptions[line] + ")"; + if (monster_descriptions contains line) + line = monster_descriptions[line]; + if (last_terrain == terrain && (__last_adventure_location.recommended_stat < 40 || depth_min == depth_max)) + line = HTMLGenerateSpanOfClass(line, "r_bold"); + terrain_monsters.listAppend(line); + + if (depth_min != depth_max) + { + line = monster_for_terrain_depth[terrain][depth_max]; + //if (monster_descriptions contains line) + //line += " (" + monster_descriptions[line] + ")"; + if (monster_descriptions contains line) + line = monster_descriptions[line]; + if (last_terrain == terrain && __last_adventure_location.recommended_stat >= 40) + line = HTMLGenerateSpanOfClass(line, "r_bold"); + terrain_monsters.listAppend(line); + } + + line = terrain.capitaliseFirstLetter() + ": "; + if (!have_usable_last_terrain || last_terrain == terrain) + line = HTMLGenerateSpanOfClass(line, "r_bold"); + line += terrain_monsters.listJoinComponents(", ", "or"); + //if (last_terrain == terrain) + //line = HTMLGenerateSpanOfClass(line, "r_bold"); + description.listAppend(line); + } + + if (waterbending_skills_can_cast.count() > 0) + description.listAppend("Can cast " + waterbending_skills_can_cast.listJoinComponents(", ", "and") + " for deeper water."); + + + return description; +} + +void SCountersGenerateEntry(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, boolean from_task) +{ + string [string] window_image_names; + window_image_names["Nemesis Assassin"] = "__familiar Penguin Goodfella"; //technically not always a penguin, but.. + window_image_names["Bee"] = "__effect Float Like a Butterfly, Smell Like a Bee"; //bzzz! + window_image_names["Holiday Monster"] = "__familiar hand turkey"; + if (getHolidaysToday()["El Dia De Los Muertos Borrachos"]) + window_image_names["Holiday Monster"] = "__item corpse island iced tea"; + window_image_names["Rain Monster"] = "__familiar personal raincloud"; + window_image_names["WoL Monster"] = "__effect Cowrruption"; + window_image_names["Digitize Monster"] = "__item source essence"; + window_image_names["Romantic Monster"] = "__familiar " + __misc_state_string["obtuse angel name"]; + window_image_names["Enamorang Monster"] = "__item lov enamorang"; + window_image_names["portscan.edu"] = "__item gyroscope"; + //window_image_names["Event Monster"] = ""; //no idea + + + + boolean [string] counter_blacklist = $strings[Semi-rare]; //Romantic Monster, + boolean [string] non_range_whitelist = $strings[Digitize Monster,Enamorang Monster,portscan.edu]; + + string [int] all_counter_names = CounterGetAllNames(true); + + foreach key in all_counter_names + { + string window_name = all_counter_names[key]; + if (window_name == "") + continue; + if (counter_blacklist contains window_name) + continue; + + Counter c = CounterLookup(window_name, ErrorMake(), true); + if (!c.CounterIsRange() && !(non_range_whitelist contains window_name)) + continue; + boolean counter_is_range = c.CounterIsRange(); + Vec2i turn_range = c.CounterGetWindowRange(); + int next_exact_turn = c.CounterGetNextExactTurn(); + + if (counter_is_range && !(turn_range.x <= 10 && from_task) && !(turn_range.x > 10 && !from_task) && window_name != "Romantic Monster") + continue; + + //print_html("c = " + c.to_json()); + boolean very_important = false; + if (turn_range.x <= 0 && counter_is_range) + very_important = true; + if (!counter_is_range && next_exact_turn <= 3) //warn three turns ahead + very_important = true; + + + ChecklistSubentry subentry; + string url; + string window_display_name = window_name; + + monster fighting_monster; + if (window_name == "Digitize Monster") + { + fighting_monster = get_property_monster("_sourceTerminalDigitizeMonster"); + string monster_name = fighting_monster.to_lower_case(); + if (monster_name == "") + window_display_name = "Digitised monster"; + else + window_display_name = "Digitised " + monster_name; + } + if (window_name == "Enamorang Monster") + { + fighting_monster = get_property_monster("enamorangMonster"); + string monster_name = fighting_monster.to_lower_case(); + if (monster_name == "") + window_display_name = "Boomerang'd monster"; + else + window_display_name = "Boomerang'd " + monster_name; + } + if (window_name == "Romantic Monster") + { + fighting_monster = get_property_monster("romanticTarget"); + window_display_name = "Arrowed " + __misc_state_string["Romantic Monster Name"].to_lower_case() + " (" + get_property_int("_romanticFightsLeft") + " left)"; + } + if (window_name == "Nemesis Assassin" && __quest_state["Nemesis"].mafia_internal_step >= 26) + { + //someone reported they saw this window after going past the relevant quest step; safety ignore + continue; + } + if (window_name == "WoL Monster" && my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) + continue; + subentry.header = window_display_name; + + + if (!counter_is_range) + { + if (next_exact_turn <= 0) + subentry.header += HTMLGenerateSpanFont(" now", "red"); + else + subentry.header += " after " + pluralise(next_exact_turn, "More Turn", "more turns"); + } + else if (turn_range.y <= 0) + subentry.header += " now or soon"; + else if (turn_range.x <= 0) + subentry.header += " between now and " + turn_range.y + " turns."; + else + subentry.header += " in [" + turn_range.x + " to " + turn_range.y + "] turns."; + + + if (window_name == "Digitize Monster") + { + //Display next window: + int next_window_count = get_property_int("_sourceTerminalDigitizeMonsterCount") + 1; + //Vec2i next_window_range = Vec2iMake(15 + 10 * next_window_count, 25 + 10 * next_window_count); + int next_turn_count = next_window_count * 10 + 10; + //subentry.entries.listAppend("Next window will be [" + next_window_range.x + " to " + next_window_range.y + "] turns."); + subentry.entries.listAppend("Next gap will be " + next_turn_count + " turns."); + + //calculate the limit: + boolean [string] chips = getInstalledSourceTerminalSingleChips(); + int digitisations = get_property_int("_sourceTerminalDigitizeUses"); + int digitisation_limit = 1; + if (chips["TRAM"]) + digitisation_limit += 1; + if (chips["TRIGRAM"]) + digitisation_limit += 1; + int digitisations_left = clampi(digitisation_limit - digitisations, 0, 3); + if (get_property_int("_sourceTerminalDigitizeMonsterCount") >= 2 && digitisations < digitisation_limit) + subentry.entries.listAppend("Could re-digitise to reset the window."); + } + if (window_name == "Rain Monster" && my_path() == $path[Heavy Rains]) + { + // Adding a note here -- there was a bug report that multiple people hit + // this counter outside of heavy rains. I have no idea what was going + // wrong here; feels like a mafia pref issue of something? Dunno. + + // Still adding a big note so that it's easier to find this file if + // this recurs for a user. + + subentry.entries = SCountersGenerateDescriptionForRainMonster(); + } + if (fighting_monster != $monster[none]) + { + CopiedMonstersGenerateDescriptionForMonster(fighting_monster, subentry.entries, (turn_range.x <= 0), false); + } + if (c.waiting_for_adventure_php) + subentry.entries.listAppend("Need to adventure in adventure.php to start counting."); + + if (turn_range.x <= 0) // && counter_is_range || (!counter_is_range && next_exact_turn <= 0)) + { + if (my_path().id != PATH_COMMUNITY_SERVICE && __misc_state["in run"]) + { + if (window_name == "portscan.edu" && $skill[macrometeorite].skill_is_usable() && get_property_int("_macrometeoriteUses") < 10 && !__quest_state["Level 12"].finished && !__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) + { + subentry.entries.listAppend("Adventure in sonofa beach, macrometeorite the government agent to gain a LFM."); + url = $location[sonofa beach].getClickableURLForLocation(); + } + location [int] possible_locations = generatePossibleLocationsToBurnDelay(); + if (possible_locations.count() > 0) + { + subentry.entries.listAppend("Adventure in " + possible_locations.listJoinComponents(", ", "or") + " to burn delay."); + if (url == "") + url = possible_locations[0].getClickableURLForLocation(); + } + } + /*if (get_property_boolean("dailyDungeonDone")) + { + url = "da.php"; + subentry.entries.listAppend("Could check for free in the daily dungeon."); + } + else if (get_property_int("hiddenApartmentProgress") >= 1 && get_property_int("hiddenBowlingAlleyProgress") >= 1 && get_property_int("hiddenHospitalProgress") >= 1 && get_property_int("hiddenOfficeProgress") >= 1) //we could support suggesting each shrine individually, but effort + { + url = $location[the hidden park].getClickableURLForLocation(); + subentry.entries.listAppend("Could check for free in one of the shrines."); + }*/ + } + + string image_name = "__item Pokëmann figurine: Frank"; //default - some person + if (window_image_names contains window_name) + image_name = window_image_names[window_name]; + + int importance = 10; + if (very_important) + importance = -11; + ChecklistEntry entry = ChecklistEntryMake(image_name, url, subentry, importance); + entry.tags.id = window_name + " counter"; + + if (very_important) + task_entries.listAppend(entry); + else + optional_task_entries.listAppend(entry); + + } +} + +void SCountersGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (true) + { + //dance card: + int turns_until_dance_card = CounterLookup("Dance Card").CounterGetNextExactTurn(); + + if (turns_until_dance_card >= 0) + { + string stats = "Gives ~" + __misc_state_float["dance card average stats"].round() + " "; + if (my_primestat() == $stat[moxie]) + stats += "mainstat"; + else + stats += "moxie"; + stats += "."; + if (turns_until_dance_card == 0) + { + task_entries.listAppend(ChecklistEntryMake("__item dance card", $location[the haunted ballroom].getClickableURLForLocation(), ChecklistSubentryMake("Dance card up now.", "", "Adventure in haunted ballroom. " + stats), -11).ChecklistEntrySetIDTag("Counter").ChecklistEntrySetIDTag("Dance card counter now")); + } + else + { + optional_task_entries.listAppend(ChecklistEntryMake("__item dance card", "", ChecklistSubentryMake("Dance card up after " + pluralise(turns_until_dance_card, "adventure", "adventures") + ".", "", "Haunted ballroom. " + stats)).ChecklistEntrySetIDTag("Dance card counter soon")); + } + } + } + + SCountersGenerateEntry(task_entries, optional_task_entries, true); +} + +void SCountersGenerateResource(ChecklistEntry [int] resource_entries) +{ + SCountersGenerateEntry(resource_entries, resource_entries, false); +} + +Record BountyFileEntry +{ + string plural; + string difficulty; + string image; + int amount_needed; + monster bounty_monster; +}; + + +location [int] locationsForMonster(monster m) +{ + //hacky, slow, sorry + location [int] result; + if (m == $monster[none]) + return result; + foreach l in $locations[] + { + monster [int] location_monsters = l.get_monsters(); + foreach key in location_monsters + { + if (location_monsters[key] == m) + result.listAppend(l); + } + } + + return result; +} + +ChecklistSubentry SBHHGenerateHunt(string bounty_item_name, int amount_found, int amount_needed, monster target_monster, location [int] relevant_locations, StringHandle url) +{ + //FIXME update to use new bounty API once 16.3 is out for a sufficient time + ChecklistSubentry subentry; + + subentry.header = "Bounty hunt for " + bounty_item_name.HTMLEscapeString(); + + + + + //Look up monster location: + location [int] monster_locations = locationsForMonster(target_monster); + + relevant_locations.listAppendList(monster_locations); + + + boolean [location] skippable_ncs_locations = $locations[the stately pleasure dome, the poop deck, the spooky forest,The Haunted Gallery,tower ruins,the castle in the clouds in the sky (top floor), the castle in the clouds in the sky (ground floor), the castle in the clouds in the sky (basement), mt. molehill, the jungles of ancient loathing]; + + boolean [location] want_nc_locations = $locations[the penultimate fantasy airship]; + + string turns_remaining_string = ""; + + boolean need_plus_combat = false; + int plus_combat_needed = 25; + boolean need_minus_combat = false; + + + location [int] target_locations; + if (amount_needed != 0 && target_monster != $monster[none] && monster_locations.count() > 0) + { + float min_turns_remaining = -1.0; // Infinity + foreach key in monster_locations + { + location l = monster_locations[key]; + boolean noncombats_skippable = (skippable_ncs_locations contains l); + boolean noncombats_wanted = (want_nc_locations contains l); + float [monster] appearance_rates = l.appearance_rates_adjusted(); + int number_remaining = amount_needed - amount_found; + + + if (number_remaining == 0) + { + if (url.s.length() == 0) + url.s = "place.php?whichplace=forestvillage"; + subentry.header = "Return to the bounty hunter hunter"; + return subentry; + } + string clickable_url = getClickableURLForLocation(l); + if (clickable_url != "" && (url.s.length() == 0 || url.s == "place.php?whichplace=forestvillage")) //if it's that URL, then it's back to the BHH - we'd rather override that with a bounty + url.s = clickable_url; + + float bounty_appearance_rate = appearance_rates[target_monster] / 100.0; + if (bounty_appearance_rate < 0.0) { // is banished, for instance + bounty_appearance_rate = 0.0; + } + + float base_combat_rate = 0.0; + foreach mon, appearance_rate in appearance_rates { + if (mon != $monster[none] && appearance_rate >= 0) { + base_combat_rate += appearance_rate; + } + } + if (noncombats_skippable) + { + //Recorrect for NC: + if (base_combat_rate != 0.0) + bounty_appearance_rate /= (base_combat_rate / 100.0); + } + else if (noncombats_wanted) + { + //Recorrect for NC: + float nc_rate = (100.0 - base_combat_rate) / 100.0; + bounty_appearance_rate += nc_rate; + } + + // always show at least one location if possible, even if there is no chance to encounter the monster (e.g. it is banished) + float turns_remaining = -1.0; + if (bounty_appearance_rate != 0.0) + { + turns_remaining = number_remaining.to_float() / bounty_appearance_rate; + } + + if (min_turns_remaining == -1.0 || (turns_remaining != -1.0 && turns_remaining <= min_turns_remaining)) + { + if (turns_remaining != min_turns_remaining) + target_locations.listClear(); + target_locations.listAppend(l); + + min_turns_remaining = turns_remaining; + if (turns_remaining != -1.0) turns_remaining_string = " ~" + pluralise(round(turns_remaining), "turn remains", "turns remain") + "."; + } + + // Using a fancy function to get the combat percentage, it already accounts for combat modifiers + int combat_rate = l.combat_percent; + + if (noncombats_wanted && combat_rate != 0.0) + need_minus_combat = true; + else if (!noncombats_skippable && combat_rate < 100.0) + { + need_plus_combat = true; + plus_combat_needed = 100.0 - combat_rate; + } + } + } + + + if (need_plus_combat) + subentry.modifiers.listAppend("+" + plus_combat_needed + "% combat"); + if (need_minus_combat) + subentry.modifiers.listAppend("-combat"); + + if (target_monster != $monster[none]) + { + string monster_text = target_monster; + if (last_monster() == target_monster) + monster_text = HTMLGenerateSpanOfClass(monster_text, "r_bold"); + subentry.entries.listAppend("From " + monster_text + " in " + target_locations.listJoinComponents(", ", "or") + "."); + subentry.modifiers.listAppend("olfact " + target_monster); + subentry.modifiers.listAppend("banish"); + } + + + if (amount_needed == 0) + { + subentry.entries.listAppend(amount_found + " found." + turns_remaining_string); + } + else + { + int amount_remaining = amount_needed - amount_found; + subentry.entries.listAppend(amount_remaining.int_to_wordy().capitaliseFirstLetter() + " left." + turns_remaining_string); + //subentry.entries.listAppend(amount_found + " out of " + amount_needed + " found." + turns_remaining_string); + } + + item [string] bounty_item_to_unlock; + + bounty_item_to_unlock["glittery skate key"] = $item[tiny bottle of absinthe]; + bounty_item_to_unlock["pile of country guano"] = $item[astral mushroom]; + if (!get_property_boolean("_psychoJarUsed")) + { + bounty_item_to_unlock["greasy string"] = $item[jar of psychoses (The Meatsmith)]; + bounty_item_to_unlock["pixellated ashes"] = $item[jar of psychoses (The Crackpot Mystic)]; + bounty_item_to_unlock["unlucky claw"] = $item[jar of psychoses (The Suspicious-Looking Guy)]; + } + bounty_item_to_unlock["pop art banana peel"] = $item[llama lama gong]; + bounty_item_to_unlock["wig powder"] = $item["DRINK ME" potion]; + bounty_item_to_unlock["grizzled stubble"] = $item[transporter transponder]; + bounty_item_to_unlock["hickory daiquiri"] = $item[devilish folio]; + + if (bounty_item_to_unlock contains bounty_item_name) + subentry.entries.listAppend("Accessed with " + bounty_item_to_unlock[bounty_item_name] + "."); + + + if ((bounty_item_name == "half-empty bottle of eyedrops" || bounty_item_name == "broken plunger handle") && knoll_available()) + { + url.s = "place.php?whichplace=forestvillage"; + subentry.entries.listClear(); + subentry.modifiers.listClear(); + subentry.entries.listAppend("Unable to complete this bounty under knoll sign."); + subentry.header = "Cancel bounty hunt for " + bounty_item_name.HTMLEscapeString(); + } + + if (bounty_item_name == "greasy string") + subentry.entries.listAppend("Run away from non-salaminders to complete this bounty in a day."); + + if (bounty_item_name == "burned-out arcanodiode") + { + if (monster_level_adjustment() < 20) + subentry.entries.listAppend(HTMLGenerateSpanFont("Run +20 ML to find more MechaMechs.", "red")); + } + + return subentry; +} + +void SBountyHunterHunterGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //Preliminary support, this may break. + //currentEasyBountyItem, currentHardBountyItem, currentSpecialBountyItem + + //FIXME add suggesting taking bounties if we can detect if they have a bounty available + ChecklistSubentry [int] subentries; + string [int] bounty_property_names = split_string_alternate("currentEasyBountyItem,currentHardBountyItem,currentSpecialBountyItem", ","); + string [string] bounty_properties; + boolean on_bounty = false; + + foreach key in bounty_property_names + { + string property_name = bounty_property_names[key]; + string property_value = get_property(property_name); + if (property_value.length() == 0) + continue; + bounty_properties[property_name] = property_value; + on_bounty = true; + } + + StringHandle url_handle; + + + if (!on_bounty) + return; + + location [int] relevant_locations; + foreach bounty_name in bounty_properties + { + string property_value = bounty_properties[bounty_name]; + + //Parse: + //Format is bounty_item:number_found + string [int] split = split_string_alternate(property_value, ":"); + if (split.count() != 2) + continue; + string bounty_item_name = split[0]; + int amount_found = split[1].to_int_silent(); + + if (bounty_item_name.length() == 0 || bounty_item_name == "null") //unknown + bounty_item_name = "unknown"; + + bounty bounty_data = to_bounty(bounty_item_name); + + int amount_needed = bounty_data.number; + monster target_monster = bounty_data.monster; + + subentries.listAppend(SBHHGenerateHunt(bounty_item_name, amount_found, amount_needed, target_monster, relevant_locations, url_handle)); + + } + + boolean [location] highlight_locations = listInvert(relevant_locations); + if (subentries.count() > 0) + { + optional_task_entries.listAppend(ChecklistEntryMake("__item bounty-hunting helmet", url_handle.s, subentries, highlight_locations).ChecklistEntrySetIDTag("Bounty hunter hunter")); + } +} + +void SOldLevel9GenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($location[The Valley of Rof L'm Fao].turnsAttemptedInLocation() == 0) + return; + //if (__misc_state["in run"]) + //return; + QuestState state; + QuestStateParseMafiaQuestProperty(state, "questM15Lol", false); //don't issue a quest log load for this, no information gained + if (!state.in_progress) + return; + + string url = "place.php?whichplace=mountains"; + + string [int] description; + + if ($item[64735 scroll].item_amount() > 0) + { + description.listAppend("Use the 64735 scroll."); + url = "inventory.php?ftext=64735+scroll"; + } + else + { + description.listAppend("Make the 64735 scroll using the rampaging adding machine."); + + item [int] components_testing; + if ($item[64067 scroll].item_amount() == 0) + { + components_testing.listAppend($item[30669 scroll]); + components_testing.listAppend($item[33398 scroll]); + } + if ($item[668 scroll].item_amount() == 0) + { + components_testing.listAppend($item[334 scroll]); + components_testing.listAppend($item[334 scroll]); + } + string [int] components_needed; + int [item] amount_used; + foreach key in components_testing + { + item it = components_testing[key]; + if (it.item_amount() - amount_used[it] <= 0) + { + components_needed.listAppend(it.to_string()); + } + else + amount_used[it] += 1; + } + if (components_needed.count() > 0) + description.listAppend("Need " + components_needed.listJoinComponents(", ", "and") + "."); + + //suggest faxing? + if (__misc_state["fax equivalent accessible"]) + description.listAppend("Possibly fax the rampaging adding machine (with all scroll components) for one-turn quest."); + description.listAppend("Find rampaging adding machine, feed it 334 + 334, 30669 + 33398, 64067 + 668."); + description.listAppend("31337 scroll is 30669 + 668. (334 + 334)"); + } + ChecklistSubentry [int] subentries; + subentries.listAppend(ChecklistSubentryMake("A Quest, LOL", "", description)); + optional_task_entries.listAppend(ChecklistEntryMake("__item 64735 scroll", url, subentries, 10, $locations[the valley of rof l'm fao]).ChecklistEntrySetIDTag("Valley rof l'm fao quest")); +} + + +string [int] SFaxGeneratePotentialFaxes(boolean suggest_less_powerful_faxes, boolean [monster] blocked_monsters) +{ + string [int] potential_faxes; + + record potential_fax { + monster target; + string reason; + // Faxes that will be useful, but not yet for some reason (i.e. quest not started). + boolean unready; + string unready_reason; + }; + + void add_fax(potential_fax it) + { + if (blocked_monsters[it.target]) { + return; + } + + string line = it.target.to_string().capitalisefirstletter() + " " + it.reason; + if (it.unready) + { + if (it.unready_reason != "") + { + line += " (" + it.unready_reason + ")"; + } + line = HTMLGenerateSpanFont(line, "gray"); + } + potential_faxes.listAppend(line); + } + + boolean can_arrow = false; + if (get_property_int("_badlyRomanticArrows") == 0 && (familiar_is_usable($familiar[obtuse angel]) || familiar_is_usable($familiar[reanimated reanimator]))) + can_arrow = true; + + if (my_path().id == PATH_G_LOVER) can_arrow = false; // cannot use arrow skills/fams in g-lover + + if (get_auto_attack() != 0) + { + potential_faxes.listAppend("Auto attack is on, disable it?"); + } + + if (__misc_state["in run"]) + { + //sleepy mariachi + if (familiar_is_usable($familiar[fancypants scarecrow]) || familiar_is_usable($familiar[mad hatrack])) + { + if ($item[spangly mariachi pants].available_amount() == 0 && in_hardcore() && $item[li'l ninja costume].available_amount() == 0) + { + string fax = ""; + fax += ChecklistGenerateModifierSpan("yellow ray"); + + if (familiar_is_usable($familiar[fancypants scarecrow])) + { + fax += "Makes scarecrow into superfairy"; + if (my_primestat() == $stat[moxie] && __misc_state["need to level"]) + { + fax += " and +3 mainstat/turn hat"; + } + } + else if (familiar_is_usable($familiar[mad hatrack])) + fax += "Makes hatrack into superfairy"; + fax += "."; + + add_fax(new potential_fax($monster[sleepy mariachi], HTMLGenerateIndentedText(fax))); + } + } + + //ninja snowman assassin (copy only) + if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && !blocked_monsters[$monster[ninja snowman assassin]]) + { + int equipment_missing_count = $items[ninja carabiner,ninja crampons,ninja rope].items_missing().count(); + if (equipment_missing_count > 0) + { + string fax = ""; + string modifier_text = "+150% init or more"; + if (equipment_missing_count == 3) + modifier_text += ", two copies"; + if (equipment_missing_count == 2) + modifier_text += ", one copy"; + fax += ChecklistGenerateModifierSpan(modifier_text); + if (equipment_missing_count == 3) + fax += "Copy twice for recreational mountain climbing.
"; + else if (equipment_missing_count == 2) + fax += "Copy once for recreational mountain climbing.
"; + fax += generateNinjaSafetyGuide(false); + if ($familiar[obtuse angel].familiar_is_usable() && $familiar[reanimated reanimator].familiar_is_usable()) + fax += "
Make sure to copy with angel, not the reanimator."; + + add_fax(new potential_fax($monster[ninja snowman assassin], HTMLGenerateIndentedText(fax))); + } + } + + int missing_ore = MAX(0, 3 - __quest_state["Level 8"].state_string["ore needed"].to_item().available_amount()); + if (!__quest_state["Level 8"].state_boolean["Past mine"] && missing_ore > 0)// && !$skill[unaccompanied miner].skill_is_usable()) + { + string line = ""; + line += ChecklistGenerateModifierSpan("+150% item or ideally YR"); + line += "Mining ores. Try to copy a few times."; + if (__misc_state_string["obtuse angel name"] != "") + { + string arrow_text = " (arrow?)"; + if (get_property_int("_badlyRomanticArrows") > 0) + arrow_text = HTMLGenerateSpanFont(arrow_text, "gray"); + line += arrow_text; + } + add_fax(new potential_fax($monster[mountain man], HTMLGenerateIndentedText(line))); + } + + + if (!(__quest_state["Level 12"].finished || __quest_state["Level 12"].state_boolean["Lighthouse Finished"] || $item[barrel of gunpowder].available_amount() == 5)) + { + string line = "(lighthouse quest"; + if ($item[barrel of gunpowder].available_amount() < 4) + { + line += "; copy"; + if (can_arrow) + line += "/arrow"; + } + line += ")"; + add_fax(new potential_fax($monster[Lobsterfrogman], line)); + } + + //orcish frat boy spy / war hippy + if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues") && !__quest_state["Level 12"].finished) + potential_faxes.listAppend("Bailey's Beetle (YR) / Hippy spy (30% drop) / Orcish frat boy spy (30% drop) - war outfit"); + + if (!__misc_state["can eat just about anything"]) //can't eat, can't fortune cookie + { + //Suggest kge, miner, baabaaburan: + if (!dispensary_available() && !have_outfit_components("Knob Goblin Elite Guard Uniform")) + { + add_fax(new potential_fax($monster[Knob Goblin Elite Guard Captain], "- ???")); + } + if (!__quest_state["Level 8"].state_boolean["Past mine"] && !have_outfit_components("Mining Gear") && __misc_state["can equip just about any weapon"]) + { + add_fax(new potential_fax($monster[7-Foot Dwarf Foreman], "- Mining gear for level 8 quest. Need YR or +234% items.")); + } + if (!locationAvailable($location[the hidden park]) && $item[stone wool].available_amount() < ($item[the nostril of the serpent].available_amount() == 0 && !get_property_ascension("lastTempleButtonsUnlock") ? 2 : 1)) + { + add_fax(new potential_fax($monster[Baa'baa'bu'ran], "- Stone wool for hidden city unlock. Need +100% items (or as much as you can get for extra wool)")); + } + } + + if (!__misc_state["can reasonably reach -25% combat"] && in_hardcore() && $item[Bram's choker].available_amount() == 0 && combat_rate_modifier() > -25.0 && !(__quest_state["Level 13"].in_progress || (__quest_state["Level 13"].finished && my_path().id != PATH_BUGBEAR_INVASION))) + { + string line = "- drops a -5% combat accessory."; + if (my_basestat($stat[mysticality]) < 50) + line += " (requires 50 myst)"; + add_fax(new potential_fax($monster[Bram the Stoker], line)); + } + + if (!in_hardcore() && $item[richard's star key].available_amount() + $item[richard's star key].creatable_amount() == 0 && !__quest_state["Level 13"].state_boolean["Richard's star key used"] && !($item[star].available_amount() >= 8 && $item[line].available_amount() >= 7)) + { + string copy_type = "arrow"; + if (my_path().id == PATH_HEAVY_RAINS) //arrows mean washaway in flooded areas + copy_type = "copy"; + add_fax(new potential_fax($monster[skinflute], "- +234% item, fight 4 times (" + copy_type + ") to skip HITS with pulls.")); + } + + if (suggest_less_powerful_faxes) + { + //giant swarm of ghuol whelps + if (__quest_state["Level 7"].state_boolean["cranny needs speed tricks"] && !blocked_monsters[$monster[giant swarm of ghuol whelps]]) + { + potential_fax fax = new potential_fax($monster[giant swarm of ghuol whelps], "- +ML - with a copy possibly"); + if (!__quest_state["Level 7"].started) + { + fax.unready = true; + fax.unready_reason = "wait until quest started"; + } + add_fax(fax); + } + //modern zmobie + if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"] && !blocked_monsters[$monster[modern zmobie]]) + { + potential_fax fax = new potential_fax($monster[modern zmobie], "- +ML - with a copy possibly"); + if (!__quest_state["Level 7"].started) + { + fax.unready = true; + fax.unready_reason = "wait until quest started"; + } + add_fax(fax); + } + + //screambat for sonar replacement + if ((3 - __quest_state["Level 4"].state_int["areas unlocked"]) > $item[sonar-in-a-biscuit].available_amount()) + { + potential_fax fax = new potential_fax($monster[screambat], "- unlocks a single bat lair area"); + if (!__quest_state["Level 4"].in_progress) + { + fax.unready = true; + fax.unready_reason = "quest not started"; + } + add_fax(fax); + } + //monstrous boiler + if (__quest_state["Level 11 Manor"].mafia_internal_step < 4 && $item[wine bomb].available_amount() == 0) + { + add_fax(new potential_fax($monster[monstrous boiler], "- charge up unstable fulminate.", $item[unstable fulminate].available_amount() == 0)); + } + if (true) //not sure about this + { + //marginal stuff: + //whitesnake, white lion + if (in_hardcore() && $items[wet stunt nut stew,mega gem].available_amount() == 0 && !__quest_state["Level 11 Palindome"].finished) + { + string [int] stew_source_monsters; + if ($item[bird rib].available_amount() == 0) + { + stew_source_monsters.listAppend("whitesnake"); + } + if ($item[lion oil].available_amount() == 0) + { + stew_source_monsters.listAppend("white lion"); + } + if (stew_source_monsters.count() > 0) + { + string description = stew_source_monsters.listJoinComponents("/").capitaliseFirstLetter() + " - run +300% item/food drops for wet stunt nut stew components. (marginal?)"; + + potential_faxes.listAppend(description); + } + } + } + //blur + if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && $item[drum machine].available_amount() == 0 && !__quest_state["Level 11 Desert"].state_boolean["Wormridden"] && in_hardcore()) + { + add_fax(new potential_fax($monster[blur], "- +234% item " + (item_drop_modifier() >= 234 ? "(have) " : "(don't have) ") + "for drum machine for possible desert exploration route.")); + } + + if (in_hardcore() && knoll_available() && __quest_state["Level 11 Hidden City"].state_boolean["need machete for liana"] && $item[forest tears].available_amount() == 0) + { + add_fax(new potential_fax($monster[forest spirit], "- +234% item - forest tears can meatsmith into a muculent machete for dense liana" + (($familiar[intergnat].familiar_is_usable() && my_level() <= 11) ? " (or use intergnat summon)" : ""))); + } + //green ops + //baa'baa'bu'ran + //grungy pirate - for guitar (need 400% item/YR) + //harem girl + + //FIXME rest + //f'c'le - cleanly pirate/curmudgeonly pirate/that other pirate (and insults) + //KGE + + //dairy goat? mostly for early milk of magnesium (stunt runs) + //possessed wine rack / cabinet + //pygmy shaman / accountant - if you absolutely have to + //barret / aerith for equipment + //racecar bob to olfact + + //brainsweeper for chef-in-the-box / bartender-in-the-box? + //gremlins? + + //FIXME handsome mariachi/etc? + } + } + else + { + //aftercore: + //potential_faxes.listAppend("Adventurer Echo - event chroner"); + add_fax(new potential_fax($monster[Clod Hopper], "(YR/+item) - floaty sand")); + add_fax(new potential_fax($monster[swarm of fudgewasps], "- fudge")); + } + + return potential_faxes; +} + +string [int] SFaxGeneratePotentialFaxes(boolean suggest_less_powerful_faxes) +{ + boolean [monster] blank; + return SFaxGeneratePotentialFaxes(suggest_less_powerful_faxes, blank); +} + +void SFaxGenerateEntry(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries) +{ + if (my_path().id == PATH_G_LOVER) return; // cannot use fax machine in g-lover + + string url = "clan_viplounge.php?action=faxmachine"; + + if (get_auto_attack() != 0) + { + url = "account.php?tab=combat"; + } + + if (__misc_state["fax available"] && $item[photocopied monster].available_amount() == 0) + optional_task_entries.listAppend(ChecklistEntryMake("fax machine", url, ChecklistSubentryMake("Fax", "", listJoinComponents(SFaxGeneratePotentialFaxes(true), "|
"))).ChecklistEntrySetIDTag("VIP fax machine suggestions")); + if ($skill[Rain Man].skill_is_usable() && my_rain() >= 50) + { + ChecklistEntry entry = ChecklistEntryMake("__skill rain man", "skills.php", ChecklistSubentryMake("Rain man copy", "50 rain drops", listJoinComponents(SFaxGeneratePotentialFaxes(true), "
"))); + entry.tags.id = "Heavy rains path rain man skill"; + + if (my_rain() > 93) + { + entry.importance_level = -10; + task_entries.listAppend(entry); + } + else + optional_task_entries.listAppend(entry); + } +} + +void SFaxGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (__misc_state["in aftercore"]) + SFaxGenerateEntry(resource_entries, resource_entries); +} + + +void SFaxGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__misc_state["in aftercore"]) + SFaxGenerateEntry(task_entries, optional_task_entries); +} + + +void SDungeonsOfDoomGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //Let's see... + //Normally, we assume the best path is to fax a quantum mechanic (in HC) or pull a large box (in SC) + //However, that won't work for paths without a fax machine, or for people without a VIP key, or for people who desire to open the dungeons of doom regardless. + //So, we suggest it in those cases. + //We also want to work in aftercore - if they haven't unlocked the DOD yet and they've started, give suggestions. + + //lastPlusSignUnlock is set by the oracle, not reading the book. + string title = "Dungeons of Doom"; + string image_name = "Dungeons of Doom"; + string [int] description; + string [int] modifiers; + string url = "da.php"; + + boolean should_output = true; + + int turns_attempted = $location[The Enormous Greater-Than Sign].turnsAttemptedInLocation() + $location[the dungeons of doom].turnsAttemptedInLocation(); + + if (my_basestat(my_primestat()) < 45) //not yet + return; + if (turns_attempted == 0) //no, they haven't started yet + return; + + if (get_property_ascension("lastPlusSignUnlock")) + { + should_output = false; + //Dungeons of doom unlocked. + if ($item[plus sign].available_amount() > 0) + { + should_output = true; + //Read plus sign: + title = "Read plus sign"; + image_name = "__item plus sign"; + url = "inventory.php?ftext=plus+sign"; + } + } + else + { + boolean adventuring_in_sign = true; + string [int] tasks; + if (my_meat() < 1000) + tasks.listAppend("acquire 1000 meat"); + if ($item[plus sign].available_amount() == 0) + tasks.listAppend("acquire plus sign from non-combat"); + else if ($effect[Teleportitis].have_effect() == 0) + tasks.listAppend("acquire teleportitis from non-combat or uppercase Q hitting you"); + else + { + adventuring_in_sign = false; + tasks.listAppend("find the oracle, pay for major consultation"); + } + + title = "Unlock dungeons of doom"; + if (adventuring_in_sign) + { + modifiers.listAppend("-combat"); + description.listAppend("Run -combat in the enormous greater-than sign."); + + } + description.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + } + + if (should_output) + optional_task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(title, modifiers, description), $locations[the enormous greater-than sign,the dungeons of doom]).ChecklistEntrySetIDTag("Dungeon of doom")); +} +void SOlfactionGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // I am keeping the recommender logic here because I like (most) of these suggestions. However, + // taking out the actual creating-the-tile shit until we refactor to the new olfaction limit + // and turn this into a resource thing rather than a highlighted task. + + if (!$skill[Transcendent Olfaction].skill_is_usable()) + return; + + //Add in some basic reminders to remove olfaction if adventuring in certain areas. + monster olfacted_monster = get_property_monster("olfactedMonster"); + if (olfacted_monster == $monster[none] || __last_adventure_location == $location[none]) + return; + + monster [location] location_wanted_monster; + + if (__misc_state["in run"]) + { + if ($item[talisman o' namsilat].available_amount() == 0 && !__quest_state["Level 11 Palindome"].finished) + location_wanted_monster[$location[belowdecks]] = $monster[gaudy pirate]; + if (!__quest_state["Level 8"].state_boolean["Past mine"]) + location_wanted_monster[$location[the goatlet]] = $monster[dairy goat]; + if (!__quest_state["Level 7"].state_boolean["niche finished"]) + location_wanted_monster[$location[the defiled niche]] = $monster[dirty old lihc]; + + if (!__quest_state["Azazel"].finished) + { + location_wanted_monster[$location[infernal rackets backstage]] = $monster[serialbus]; + location_wanted_monster[$location[the laugh floor]] = $monster[CH Imp]; + } + //Deliberately ignored - the quiet healer. (she's used to it) It's possible they may want to olfact the burly sidekick instead, and there's plenty of time in that area. + + if (!__quest_state["Level 11 Hidden City"].finished) + { + if (!__quest_state["Level 11 Hidden City"].state_boolean["Apartment finished"] && $effect[thrice-cursed].have_effect() == 0) + location_wanted_monster[$location[the hidden apartment building]] = $monster[pygmy shaman]; + + if (!__quest_state["Level 11 Hidden City"].state_boolean["Hospital finished"] && $items[surgical apron,bloodied surgical dungarees,surgical mask,head mirror,half-size scalpel].items_missing().count() > 0) + location_wanted_monster[$location[the hidden hospital]] = $monster[pygmy witch surgeon]; + + + if (!__quest_state["Level 11 Hidden City"].state_boolean["Office finished"] && $item[McClusky file (page 5)].available_amount() == 0 && $item[McClusky file (complete)].available_amount() == 0) + location_wanted_monster[$location[the hidden office building]] = $monster[pygmy witch accountant]; + + if (!__quest_state["Level 11 Hidden City"].state_boolean["Bowling alley finished"]) + location_wanted_monster[$location[the hidden bowling alley]] = $monster[pygmy bowler]; + } + if (!have_outfit_components("Knob Goblin Harem Girl Disguise")) + location_wanted_monster[$location[cobb's knob harem]] = $monster[Knob Goblin Harem Girl]; + //if (in_hardcore()) + //location_wanted_monster[$location[The Dark Neck of the Woods]] = $monster[Hellion]; + if ($skill[summon smithsness].skill_is_usable() && $item[dirty hobo gloves].available_amount() == 0 && $item[hand in glove].available_amount() == 0 && __misc_state["need to level"]) + { + location_wanted_monster[$location[The Sleazy Back Alley]] = $monster[drunken half-orc hobo]; + location_wanted_monster[$location[The Haunted Pantry]] = $monster[drunken half-orc hobo]; + } + location_wanted_monster[$location[fear man's level]] = $monster[morbid skull]; + + // RIP to my boy, the blooper + // if ($item[digital key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["digital key used"] && $item[white pixel].available_amount() + $item[white pixel].creatable_amount() < 27) + // location_wanted_monster[$location[8-bit realm]] = $monster[Blooper]; + + + if (!__quest_state["Level 11 Pyramid"].finished && olfacted_monster != $monster[tomb servant]) + location_wanted_monster[$location[the middle chamber]] = $monster[tomb rat]; + } + + if (!($monsters[ferocious roc,giant man-eating shark,Bristled Man-O-War,The Cray-Kin,Deadly Hydra] contains olfacted_monster)) + location_wanted_monster[$location[the old man's bathtime adventures]] = $monster[none]; + + + foreach l in location_wanted_monster + { + monster m = location_wanted_monster[l]; + if (l == $location[none]) + continue; + if (__last_adventure_location != l) + continue; + if (m == olfacted_monster) + continue; + + boolean all_other_monsters_banished = true; + foreach key, m2 in l.get_monsters() + { + if (m == m2) + continue; + if (!m2.is_banished()) + { + all_other_monsters_banished = false; + break; + } + } + if (all_other_monsters_banished) + continue; + + string [int] description; + + string line; + + if (m != $monster[none]) + line += "To olfact " + m.HTMLEscapeString() + " instead of " + olfacted_monster.HTMLEscapeString() + ".|"; + else + line += "To olfact in " + l + ".|"; + + if (in_ronin()) + line += $item[soft green echo eyedrop antidote].pluralise() + " available."; + + description.listAppend(line); + + + // Old suggestion recommendation; removing this bit because it isn't needed or necessary. We need to factor this + // as a "top" recommendation thing, with the relevant idea from your most recent zone and a few other ideas + // alongside the # of olfactions remaining. + + // task_entries.listAppend(ChecklistEntryMake("__item " + $item[soft green echo eyedrop antidote], "inventory.php?ftext=soft+green+echo+eyedrop+antidote", ChecklistSubentryMake("Remove " + $effect[on the trail], "", description), -11).ChecklistEntrySetIDTag("Olfaction better suggestion")); //TODO could differentiate by suggestion + + break; + } + +} + + +void SHolidayGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + boolean [string] todays_holidays = getHolidaysToday(); + boolean [string] all_tomorrows_parties = getHolidaysTomorrow(); + + if (todays_holidays["Halloween"]) + { + if (__misc_state["in run"]) + { + string [int] description; + description.listAppend("Free stats/items from monsters on the first block."); + if (knoll_available() && !have_outfit_components("Filthy Hippy Disguise")) + { + item [int] missing_components = missing_outfit_components("Bugbear Costume"); + if (missing_components.count() > 0) + description.listAppend("If you need an outfit, buy a " + missing_components.listJoinComponents(", ", "and") + " from the knoll."); + } + optional_task_entries.listAppend(ChecklistEntryMake("__item plastic pumpkin bucket", "place.php?whichplace=town&action=town_trickortreat", ChecklistSubentryMake("Trick or treat for one block", "+" + my_primestat().to_lower_case(), description), $locations[trick-or-treating]).ChecklistEntrySetIDTag("Holiday halloween in-run")); + } + else + { + string [int] description; + description.listAppend("Wear an outfit, go from house to house."); + description.listAppend("Remember you can trick-or-treat while drunk."); + optional_task_entries.listAppend(ChecklistEntryMake("__item plastic pumpkin bucket", "place.php?whichplace=town&action=town_trickortreat", ChecklistSubentryMake("Trick or treat", "", description), $locations[trick-or-treating]).ChecklistEntrySetIDTag("Holiday halloween aftercore")); + } + } + if (all_tomorrows_parties["Halloween"] && !__misc_state["in run"]) + optional_task_entries.listAppend(ChecklistEntryMake("__item plastic pumpkin bucket", "", ChecklistSubentryMake("Save turns for Halloween tomorrow", "", ""), 8).ChecklistEntrySetIDTag("Holiday halloween soon reminder")); + + if (todays_holidays["Arrrbor Day"]) + { + string [int] description; + boolean [item] outfit_pieces_needed; + foreach it in $items[crotchety pants,Saccharine Maple pendant,willowy bonnet] + { + if (!it.haveAtLeastXOfItemEverywhere(1)) + outfit_pieces_needed[it] = true; + } + //FIXME detect collecting reward? + if ($items[bag of Crotchety Pine saplings,bag of Saccharine Maple saplings,bag of Laughing Willow saplings].available_amount() == 0) + { + description.listAppend("Choose a sapling type."); + string [int] suggestions; + if (outfit_pieces_needed[$item[crotchety pants]]) + suggestions.listAppend("Crotchety Pine"); + if (outfit_pieces_needed[$item[Saccharine Maple pendant]]) + suggestions.listAppend("Saccharine Maple"); + if (outfit_pieces_needed[$item[willowy bonnet]]) + suggestions.listAppend("Laughing Willow"); + if (suggestions.count() > 0) + description.listAppend("Could try " + suggestions.listJoinComponents(", ", "or") + " for the reward item" + (suggestions.count() > 1 ? "s" : "") + "."); + } + else + { + item [int] bag_types; + boolean have_a_bag_equipped = false; + int saplings_planted = get_property_int('_saplingsPlanted'); + + foreach it in $items[bag of Crotchety Pine saplings,bag of Saccharine Maple saplings,bag of Laughing Willow saplings] + { + if (it.available_amount() > 0) + bag_types.listAppend(it); + if (it.equipped_amount() > 0) + have_a_bag_equipped = true; + } + + int saplings_needed = 2; + if (outfit_pieces_needed.count() > 0) + saplings_needed = 100; + + int saplings_left = saplings_needed - saplings_planted; + + if (saplings_left <= 0) + return; // All done for today + + if (!have_a_bag_equipped) + { + description.listAppend("Equip your " + bag_types.listJoinComponents(", ", "or") + "."); + } + else if (outfit_pieces_needed.count() > 0) + { + description.listAppend(`Adventure for {pluralise(saplings_left,"more turn","more turns")} to collect the outfit piece next holiday.`); + } + else + { + description.listAppend(`Adventure for {pluralise(saplings_left,"more turn","more turns")} to collect the potion reward next holiday.`); + } + } + optional_task_entries.listAppend(ChecklistEntryMake("__item spooky sapling", "place.php?whichplace=woods", ChecklistSubentryMake("Plant trees", "", description), 8, $locations[The Arrrboretum]).ChecklistEntrySetIDTag("Holiday arrrbor day")); + } +} + +void SRemindersGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + + if ($effect[Straight-Edgy].have_effect() > 0 && inebriety_limit() > 0 && availableDrunkenness() >= 0) { + int straight_edgy_adventures = 4.5 * (availableDrunkenness() + 1); + string header = "Stop drinking"; + if (my_inebriety() == 0) + header = "Don't drink anything"; + string [int] description; + description.listAppend("Will give " + straight_edgy_adventures + " adventures next time you log in since next rollover."); + if (__misc_state_int["adventures after rollover"] + straight_edgy_adventures > 190) //add some leeway for those who didn't know about it + description.listAppend("Is added " + "after".HTMLGenerateSpanOfClass("r_bold") + " the 200 cap."); + if ($familiar[Stooper].familiar_is_usable()) { + string line; + if (my_familiar() == $familiar[Stooper]) + line = "Keep the Stooper equipped to get the most out of this."; + else + line = "Equip the Stooper for additional adventures."; + description.listAppend(line); + } + + task_entries.listAppend(ChecklistEntryMake("__effect straight-edgy", "", ChecklistSubentryMake(header, "", description), -11).ChecklistEntrySetIDTag("Straight-edgy reminder")); + } + + if ($effect[beaten up].have_effect() > 0) + { + string [int] methods; + string url; + if ($skill[tongue of the walrus].skill_is_usable()) + { + methods.listAppend("Cast Tongue of the Walrus."); + url = "skills.php"; + } + else if (__misc_state["VIP available"] && __misc_state_int["hot tub soaks remaining"] > 0) + { + methods.listAppend("Soak in VIP hot tub."); + url = "clan_viplounge.php"; + } + else if ($skill[Shake it off].skill_is_usable()) + { + methods.listAppend("Cast shake it off."); + url = "skills.php"; + } + else if (__misc_state_int["free rests remaining"] > 0) + { + methods.listAppend("Free rest at " + __misc_state_string["resting description"] + "."); + url = __misc_state_string["resting url"]; + } + + foreach it in $items[tiny house,space tours tripple,personal massager,forest tears,csa all-purpose soap] + { + if (it.available_amount() > 0 && methods.count() == 0) + { + url = "inventory.php?which=1"; //may not be correct in all cases + methods.listAppend("Use " + it + "."); + break; + } + } + + boolean [location] ignoring_locations; + ignoring_locations[$location[The Crimbonium Mine]] = true; + + if (methods.count() > 0 && $effect[thrice-cursed].have_effect() == 0 && !((ignoring_locations contains __last_adventure_location) && __last_adventure_location != $location[none])) + task_entries.listAppend(ChecklistEntryMake("__effect beaten up", url, ChecklistSubentryMake("Remove beaten up", "", methods), -11).ChecklistEntrySetIDTag("Beaten up reminder")); + } + + if (true) + { + //Don't get poisoned. + effect [int] poison_effects; + poison_effects.listAppend($effect[Hardly poisoned at all]); + //if (!hippy_stone_broken()) //FIXME remove next PVP season + poison_effects.listAppend($effect[A Little Bit Poisoned]); + poison_effects.listAppend($effect[Somewhat Poisoned]); + poison_effects.listAppend($effect[Really Quite Poisoned]); + poison_effects.listAppend($effect[Majorly Poisoned]); + poison_effects.listAppend($effect[Toad In The Hole]); + + effect have_poison = $effect[none]; + foreach key in poison_effects + { + effect e = poison_effects[key]; + if (e.have_effect() > 0) + { + have_poison = e; + break; + } + } + if (have_poison != $effect[none] && my_path().id != PATH_G_LOVER) + { + string url = ""; + string [int] methods; + + /*if ($skill[disco nap].skill_is_usable() && $skill[adventurer of leisure].skill_is_usable()) + { + url = "skills.php"; + methods.listAppend("Cast Disco Nap."); + } + else*/ + if (true) + { + url = "shop.php?whichshop=doc"; + methods.listAppend("Use Doc Galaktik's anti-anti-antidote."); + if ($item[anti-anti-antidote].available_amount() > 0) + url = "inventory.php?ftext=anti-anti-antidote"; + } + + task_entries.listAppend(ChecklistEntryMake("__effect " + have_poison, url, ChecklistSubentryMake("Remove " + have_poison, "", methods), -11).ChecklistEntrySetIDTag("Poisoned reminder")); + } + } + if ($effect[teleportitis].have_effect() > 0) + { + string url = "inventory.php"; + string method = "Use a soft green echo eyedrop antidote."; + if ($item[soft green echo eyedrop antidote].available_amount()<1) + method = "Acquire & use a soft green echo eyedrop antidote."; + task_entries.listAppend(ChecklistEntryMake("__effect teleportitis", url, ChecklistSubentryMake("Remove Teleportitis", "", method), -11).ChecklistEntrySetIDTag("Teleportitis reminder")); + } + if ($effect[feeling lost].have_effect() > 0) + { + string url = "inventory.php"; + string method = "Use a soft green echo eyedrop antidote."; + if ($item[soft green echo eyedrop antidote].available_amount()<1) + method = "Acquire & use a soft green echo eyedrop antidote."; + task_entries.listAppend(ChecklistEntryMake("__effect Feeling Lost", url, ChecklistSubentryMake("Remove Feeling Lost", "", method), -11).ChecklistEntrySetIDTag("Feeling Lost reminder")); + } + if ($effect[Cunctatitis].have_effect() > 0 && $skill[disco nap].skill_is_usable() && $skill[adventurer of leisure].skill_is_usable()) + { + string url = "skills.php"; + string method = "Cast disco nap."; + task_entries.listAppend(ChecklistEntryMake("__effect Cunctatitis", url, ChecklistSubentryMake("Remove Cunctatitis", "", method), -11).ChecklistEntrySetIDTag("Cunctatitis reminder")); + } + + if ($effect[Down the Rabbit Hole].have_effect() > 0 && __last_adventure_location == $location[The Red Queen's Garden] && (!in_ronin() || $item["DRINK ME" potion].available_amount() > 0) && get_property_int("pendingMapReflections") <= 0) + { + string url = "mall.php"; + + if ($item["DRINK ME" potion].available_amount() > 0) + url = "inventory.php?ftext=drink+me"; + + task_entries.listAppend(ChecklistEntryMake("__item "DRINK ME" potion", url, ChecklistSubentryMake("Drink " + $item["DRINK ME" potion], "+madness", "Otherwise, no reflections of a map will drop."), -11).ChecklistEntrySetIDTag("Rabbit hole map reflections reminder")); + } + + if ($effect[Merry Smithsness].have_effect() == 0 && (!in_ronin() || $item[flaskfull of hollow].available_amount() > 0) && $items[Meat Tenderizer is Murder,Ouija Board\, Ouija Board,Hand that Rocks the Ladle,Saucepanic,Frankly Mr. Shank,Shakespeare's Sister's Accordion,Sheila Take a Crossbow,A Light that Never Goes Out,Half a Purse,loose purse strings,Hand in Glove].equipped_amount() > 0 && $item[flaskfull of hollow].item_is_usable()) + { + //They (can) have a flaskfull of hollow and have a smithsness item equipped, but no merry smithsness. + //So, suggest a high-priority task. + //I suppose in theory they could be saving the flaskfull of hollow for later, for +item? In that case, we would be annoying them. They can closet the flask, but that isn't perfect... + //Still, I feel as though having this reminder is better than not having it. + + //Four items are not on the list due to their marginal bonus: Hairpiece On Fire (+maximum MP), Vicar's Tutu (+maximum HP), Staff of the Headmaster's Victuals (+spell damage), Work is a Four Letter Sword (+weapon damage) + string url = "mall.php"; + + if ($item[flaskfull of hollow].available_amount() > 0) + url = "inventory.php?ftext=flaskfull+of+hollow"; + + task_entries.listAppend(ChecklistEntryMake("__item flaskfull of hollow", url, ChecklistSubentryMake("Drink " + $item[flaskfull of hollow], "", "Gives +25 smithsness"), -11).ChecklistEntrySetIDTag("Smithsness flaskfull of hollow reminder")); + } + + if ($effect[QWOPped Up].have_effect() > 0 && ((__misc_state["VIP available"] && __misc_state_int["hot tub soaks remaining"] > 0) || $skill[Shake It Off].skill_is_usable())) //only suggest if they have hot tub access; other route is a SGEEA, too valuable + { + string [int] description; + string url = ""; + if ($skill[Shake It Off].skill_is_usable()) + { + url = "skills.php"; + description.listAppend("Shake it off."); + } + else + { + url = "clan_viplounge.php"; + description.listAppend("Use hot tub."); + } + + task_entries.listAppend(ChecklistEntryMake("__effect qwopped up", url, ChecklistSubentryMake("Remove QWOPped up effect", "", description), -11).ChecklistEntrySetIDTag("QWOPped up reminder")); + } + + boolean [monster] awkwards; + awkwards[$monster[Dr. Awkward]] = true; + awkwards[$monster[Dr. Aquard]] = true; + + if ((awkwards contains get_property_monster("lastEncounter")) && $item[mega gem].equipped_amount() > 0 && ($items[2268, Staff of Ed\, almost].available_amount() > 0 || $item[2325].available_amount() > 0)) + { + //Just defeated Dr. Awkward. + //This will disappear once they adventure somewhere else. + string [int] description; + + description.listAppend("It's not useful now, wear a better accessory?"); + if ($item[talisman o' namsilat].equipped_amount() > 0) + description.listAppend("Possibly the talisman as well."); + + task_entries.listAppend(ChecklistEntryMake("__item mega gem", "inventory.php?which=2", ChecklistSubentryMake("Possibly unequip the Mega Gem", "", description), -11).ChecklistEntrySetIDTag("Mega gem off reminder")); + } + + if (__misc_state["need to level"]) + { + ChecklistEntry stat_items; + stat_items.image_lookup_name = ""; + stat_items.url = "inventory.php?which=3"; + stat_items.tags.id = "Powerleveling general reminders"; + stat_items.importance_level = 0; + + effect [item] item_effects; + string [item] item_descriptions; + + if ($effect[Purple Tongue].have_effect() == 0 && $effect[Green Tongue].have_effect() == 0 && $effect[Red Tongue].have_effect() == 0 && $effect[Blue Tongue].have_effect() == 0 && $effect[Black Tongue].have_effect() == 0) + { + item_descriptions[$item[orange snowcone]] = "+1.5 mainstat/fight (20 turns)"; + item_effects[$item[orange snowcone]] = $effect[Orange Tongue]; + } + + if (in_ronin()) + { + item_descriptions[$item[Effermint™ tablets]] = "+1.5 mainstat/fight (10 turns)"; + } + + if (__misc_state["need to level moxie"]) + { + item_descriptions[$item[Ye Olde Bawdy Limerick]] = "+2 moxie stats/fight (20 turns)"; + item_effects[$item[Ye Olde Bawdy Limerick]] = $effect[From Nantucket]; + + + item_descriptions[$item[resolution: be sexier]] = "+2 moxie stats/fight (20 turns)"; + item_effects[$item[resolution: be sexier]] = $effect[Irresistible Resolve]; + + //Always better used for +init, since the tower tests came into existence? + /*if (in_ronin() && !in_bad_moon() && my_primestat() == $stat[moxie]) //better used for +init otherwise + { + item_descriptions[$item[old bronzer]] = "+2 moxie stats/fight (25 turns)"; + item_effects[$item[old bronzer]] = $effect[Sepia Tan]; + }*/ + } + + if (__misc_state["need to level muscle"]) + { + item_descriptions[$item[Squat-Thrust Magazine]] = "+3 muscle stats/fight (20 turns)"; + item_effects[$item[Squat-Thrust Magazine]] = $effect[Squatting and Thrusting]; + + + item_descriptions[$item[resolution: be stronger]] = "+2 muscle stats/fight (20 turns)"; + item_effects[$item[resolution: be stronger]] = $effect[Strong Resolve]; + + + /*if (in_ronin() && !in_bad_moon()) + { + item_descriptions[$item[old eyebrow pencil]] = "+2 muscle stats/fight (25 turns)"; + item_effects[$item[old eyebrow pencil]] = $effect[Browbeaten]; + }*/ + } + if (__misc_state["need to level mysticality"]) + { + item_descriptions[$item[O'RLY Manual]] = "+4 mysticality stats/fight (20 turns)"; + item_effects[$item[O'RLY Manual]] = $effect[You Read The Manual]; + + + item_descriptions[$item[resolution: be smarter]] = "+2 mysticality stats/fight (20 turns)"; + item_effects[$item[resolution: be smarter]] = $effect[Brilliant Resolve]; + + + /*if (in_ronin() && !in_bad_moon()) + { + item_descriptions[$item[old rosewater cream]] = "+2 mysticality stats/fight (25 turns)"; + item_effects[$item[old rosewater cream]] = $effect[Rosewater Mark]; + }*/ + } + + if (my_level() >= 11) + { + item_descriptions[$item[BitterSweetTarts]] = "+5.5 " + my_primestat().to_lower_case() + " stats/fight (10 turns)"; + item_effects[$item[BitterSweetTarts]] = $effect[Full of Wist]; + } + + item [int] relevant_items; + string [int] relevant_descriptions; + foreach it in item_descriptions + { + if (it.item_amount() == 0) + continue; + if (!it.item_is_usable()) continue; + effect e = item_effects[it]; + if (e == $effect[none]) + e = it.to_effect(); + if (!e.effect_is_usable()) continue; + if (e.have_effect() > 0) + continue; + if (stat_items.image_lookup_name.length() == 0) + stat_items.image_lookup_name = "__item " + it; + //stat_items.subentries.listAppend(ChecklistSubentryMake("Use " + it, "", item_descriptions[it])); + relevant_items.listAppend(it); + relevant_descriptions.listAppend(item_descriptions[it]); + } + + ChecklistSubentry subentry; + if (relevant_items.count() > 0) + { + subentry.header = "Use " + relevant_items.listJoinComponents(", ", "and"); + subentry.entries.listAppend(relevant_descriptions.listJoinComponents(", ", "and")); + } + + + if (subentry.header != "") + stat_items.subentries.listAppend(subentry); + if (stat_items.subentries.count() > 0) + { + optional_task_entries.listAppend(stat_items); + } + } + + if ($item[evil eye].available_amount() > 0 && __quest_state["Level 7"].state_int["nook evilness"] > 25 && my_path().id != PATH_G_LOVER) + { + task_entries.listAppend(ChecklistEntryMake("__item " + $item[evil eye], "inventory.php?ftext=evil+eye", ChecklistSubentryMake("Use " + $item[evil eye], "", "Three cyrpt nook beeps."), -11).ChecklistEntrySetIDTag("Evil eye reminder")); + } + + if ($familiars[mini-hipster, artistic goth kid] contains my_familiar() && __misc_state["need to level"] && __misc_state_int["hipster fights available"] > 0 && !__misc_state["single familiar run"]) + { + task_entries.listAppend(ChecklistEntryMake("__familiar " + my_familiar(), "", ChecklistSubentryMake("Buff " + my_primestat(), "", "Extra stats from " + my_familiar() + " fights."), -11).ChecklistEntrySetIDTag("Hipster-like familiar scaling fight reminder")); + } + + boolean have_blacklight_bulb = (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && get_property("peteMotorbikeHeadlight") == "Blacklight Bulb"); + boolean have_alternate_uv_source = false; + if (have_blacklight_bulb) + have_alternate_uv_source = true; + if (my_path().id == PATH_LICENSE_TO_ADVENTURE && get_property_boolean("bondDesert")) + have_alternate_uv_source = true; + if (my_familiar() == lookupFamiliar("Melodramedary")) + have_alternate_uv_source = true; + if (__last_adventure_location == $location[the arid\, extra-dry desert] && !__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && __misc_state["in run"] && !have_alternate_uv_source && __quest_state["Level 11 Desert"].state_int["Desert Exploration"] < 99) + { + boolean have_uv_compass_equipped = __quest_state["Level 11 Desert"].state_boolean["Have UV-Compass eqipped"]; + + if (!have_uv_compass_equipped) + { + string title; + item compass_item = $item[UV-resistant compass]; + if ($item[ornate dowsing rod].available_amount() > 0) + compass_item = $item[ornate dowsing rod]; + + title = "Equip " + compass_item; + if (compass_item.available_amount() == 0) + title = "Find and equip " + compass_item; + task_entries.listAppend(ChecklistEntryMake("__item " + compass_item, "", ChecklistSubentryMake(title, "", "Explore more efficiently."), -11).ChecklistEntrySetIDTag("Desert UV-compass reminder")); + } + + } + if ($item[bottle of blank-out].available_amount() > 0 && $item[glob of blank-out].available_amount() == 0 && __misc_state["in run"] && __misc_state["free runs usable"] && !get_property_boolean("_blankoutUsed") && in_ronin()) + { + task_entries.listAppend(ChecklistEntryMake("__item " + $item[bottle of blank-out], "inventory.php?ftext=bottle+of+blank-out", ChecklistSubentryMake("Use " + $item[bottle of blank-out], "", "Acquire glob to run away with."), -11).ChecklistEntrySetIDTag("Blank-out bottle reminder")); + + } + if (__last_adventure_location == $location[the haunted ballroom] && $item[dance card].available_amount() > 0 && __misc_state["need to level"] && my_primestat() == $stat[moxie] && CounterLookup("Dance Card").CounterGetNextExactTurn() == -1) + { + string [int] description; + description.listAppend("Gives ~" + __misc_state_float["dance card average stats"].round() + " mainstat in four turns."); + if ($item[dance card].available_amount() > 1) + description.listAppend("Have " + $item[dance card].pluraliseWordy() + "."); + task_entries.listAppend(ChecklistEntryMake("__item " + $item[dance card], "inventory.php?ftext=dance+card", ChecklistSubentryMake("Use " + $item[dance card], "", description), -11).ChecklistEntrySetIDTag("Powerleveling dance card reminder")); + } + if (!__quest_state["Level 11 Hidden City"].finished && (__quest_state["Level 11 Hidden City"].state_boolean["Apartment finished"] || get_property_int("hiddenApartmentProgress") >= 7) && $effect[thrice-cursed].have_effect() > 0 && my_path().id != PATH_G_LOVER) + { + string curse_removal_method; + string url; + + if (__misc_state["VIP available"] && __misc_state_int["hot tub soaks remaining"] > 0) + { + curse_removal_method = "Relax in hot tub."; + url = "clan_viplounge.php"; + } + if ($skill[Shake It Off].skill_is_usable()) + { + curse_removal_method = "Cast shake it off."; + url = "skills.php"; + } + + if (curse_removal_method != "") + { + task_entries.listAppend(ChecklistEntryMake("__effect thrice-cursed", url, ChecklistSubentryMake("Remove Thrice-Cursed", "", curse_removal_method), -11).ChecklistEntrySetIDTag("Thrice-cursed reminder")); + } + } + + if (my_path().id == PATH_HEAVY_RAINS && my_familiar() != $familiar[none] && $slot[familiar].equipped_item() == $item[none]) + { + boolean [familiar] safely_underwater_familiars = $familiars[black cat,Barrrnacle,Emo Squid,Cuddlefish,Imitation Crab,Magic Dragonfish,Midget Clownfish,Rock Lobster,Urchin Urchin,Grouper Groupie,Squamous Gibberer,Dancing Frog,Adorable Space Buddy]; //cat can swim! + + if (!(safely_underwater_familiars contains my_familiar())) + { + //mafia has code to do this, but it doesn't always work - had it not equip on the blackbird once, another time after the L13 entryway + //plus they have to buy one anyways + string url = "familiar.php"; + string [int] description; + description.listAppend("Otherwise it'll (probably) be blocked."); + if ($item[miniature life preserver].available_amount() == 0) + { + description.listAppend("Buy from the general store."); + url = "shop.php?whichshop=generalstore"; + } + + task_entries.listAppend(ChecklistEntryMake("__item miniature life preserver", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Equip miniature life preserver", "red"), "", description), -11).ChecklistEntrySetIDTag("Heavy rains path life preserver reminder")); + } + } + + if (__last_adventure_location == $location[a maze of sewer tunnels] && $item[hobo code binder].equipped_amount() == 0 && haveAtLeastXOfItemEverywhere($item[hobo code binder], 1)) + { + task_entries.listAppend(ChecklistEntryMake("__item hobo code binder", "inventory.php?ftext=hobo+code+binder", ChecklistSubentryMake(HTMLGenerateSpanFont("Equip hobo code binder", "red"), "", "Speeds up sewer tunnel exploration."), -11).ChecklistEntrySetIDTag("Sewer maze hobo binder reminder")); + } + +} + + + +Record Banish +{ + monster banished_monster; + string banish_source; + int turn_banished; + int banish_turn_length; + string custom_reset_conditions; +}; + +// Added due to reasons, those reasons being "now you can banish phyla" +Record BanishedPhylum +{ + phylum banished_phylum; + string banish_source; + int turn_banished; + int banish_turn_length; + string custom_reset_conditions; +}; + +void listAppend(Banish [int] list, Banish entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +// It is annoying that I have to re-add this for the new record lol +void listAppend(BanishedPhylum [int] list, BanishedPhylum entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +int BanishTurnsLeft(Banish b) +{ + if (b.banish_turn_length == -1) + return 2147483647; + + // Some sources depend on effect or a state that is running out, and so the stated length should be returned directly + string banish_source = b.banish_source.to_lower_case(); + if (banish_source == "roar like a lion") return b.banish_turn_length; + + return b.turn_banished + b.banish_turn_length - my_turncount(); +} + +static +{ + int [string] __banish_source_length; + //FIXME request this be exposed in ASH? + //all of these must be lowercase. because. + __banish_source_length["banishing shout"] = -1; + __banish_source_length["batter up!"] = -1; + __banish_source_length["chatterboxing"] = 20; + __banish_source_length["classy monkey"] = 20; + __banish_source_length["cocktail napkin"] = 20; + __banish_source_length["crystal skull"] = 20; + __banish_source_length["deathchucks"] = -1; + __banish_source_length["dirty stinkbomb"] = -1; + __banish_source_length["divine champagne popper"] = 5; + __banish_source_length["harold's bell"] = 20; + __banish_source_length["howl of the alpha"] = -1; + __banish_source_length["ice house"] = -1; + __banish_source_length["louder than bomb"] = 20; + __banish_source_length["nanorhino"] = -1; + __banish_source_length["pantsgiving"] = 30; + __banish_source_length["peel out"] = -1; + __banish_source_length["pulled indigo taffy"] = 40; + __banish_source_length["smoke grenade"] = 20; + __banish_source_length["spooky music box mechanism"] = -1; + __banish_source_length["staff of the standalone cheese"] = -1; + __banish_source_length["stinky cheese eye"] = 10; + __banish_source_length["thunder clap"] = 40; + __banish_source_length["v for vivala mask"] = 10; + __banish_source_length["replica v for vivala mask"] = 10; + __banish_source_length["walk away from explosion"] = 30; + __banish_source_length["tennis ball"] = 30; + __banish_source_length["curse of vacation"] = -1; + __banish_source_length["ice hotel bell"] = -1; + __banish_source_length["bundle of "fragrant" herbs"] = -1; + __banish_source_length["snokebomb"] = 30; + __banish_source_length["beancannon"] = -1; + __banish_source_length["licorice rope"] = -1; + __banish_source_length["kgb tranquilizer dart"] = 20; + __banish_source_length["breathe out"] = 20; // is it listed as hot jelly, breathe out or space jellyfish ? + __banish_source_length["daily affirmation: be a mind master"] = 80; // how long does it last, exactly? is it still unknown? + __banish_source_length["spring-loaded front bumper"] = 30; + __banish_source_length["mafia middle finger ring"] = 60; + __banish_source_length["throw latte on opponent"] = 30; + __banish_source_length["tryptophan dart"] = -1; + __banish_source_length["baleful howl"] = -1; + __banish_source_length["reflex hammer"] = 30; + __banish_source_length["saber force"] = 30; + __banish_source_length["human musk"] = -1; + __banish_source_length["ultra smash"] = -1; // is it the right name? + __banish_source_length["b. l. a. r. t. spray (wide)"] = -1; + __banish_source_length["system sweep"] = -1; + __banish_source_length["feel hatred"] = 50; + __banish_source_length["show your boring familiar pictures"] = 100; + __banish_source_length["bowl a curveball"] = 5; + __banish_source_length["patriotic screech"] = 100; + __banish_source_length["roar like a lion"] = 30; // not sure it is needed; it should generally be not more than 30 + __banish_source_length["monkey slap"] = 1234567; // this, for some reason, was not properly respecting the reset condition. so imma just do this to hopefully solve it. + __banish_source_length["spring kick"] = -1; + + int [string] __banish_simultaneous_limit; + __banish_simultaneous_limit["beancannon"] = 5; + __banish_simultaneous_limit["banishing shout"] = 3; + __banish_simultaneous_limit["howl of the alpha"] = 3; + __banish_simultaneous_limit["staff of the standalone cheese"] = 5; +} + +Banish [int] __banishes_active_cache; +string __banishes_active_cache_cached_monsters_string; + +Banish [int] BanishesActive() +{ + //banishedMonsters(user, now 'a.m.c. gremlin:ice house:2890', default ) + + string banished_monsters_string = get_property("banishedMonsters"); + + if (banished_monsters_string == __banishes_active_cache_cached_monsters_string && __banishes_active_cache_cached_monsters_string != "") + return __banishes_active_cache; + + __banishes_active_cache_cached_monsters_string = ""; //invalidate the cache + + Banish [int] result; + + string [int] banished_monsters_string_split = banished_monsters_string.split_string(":"); + + foreach key, s in banished_monsters_string_split { + if (s.length() == 0) + continue; + if (key % 3 != 0) + continue; + //string [int] entry = s.split_string(":"); + + //if (entry.count() != 3) + //continue; + if (!(banished_monsters_string_split contains (key + 1)) || !(banished_monsters_string_split contains (key + 2))) + continue; + + Banish b; + b.banished_monster = banished_monsters_string_split[key + 0].to_monster(); + b.banish_source = banished_monsters_string_split[key + 1]; + b.turn_banished = banished_monsters_string_split[key + 2].to_int(); + b.banish_turn_length = 0; + + string banish_source = b.banish_source.to_lower_case(); + if (__banish_source_length contains banish_source) + b.banish_turn_length = __banish_source_length[banish_source]; + if (banish_source == "bowl a curveball") b.banish_turn_length = get_property_int("cosmicBowlingBallReturnCombats"); + if (banish_source == "roar like a lion") b.banish_turn_length = have_effect($effect[Hear Me Roar]); + if (banish_source == "batter up!" || banish_source == "deathchucks" || banish_source == "dirty stinkbomb" || banish_source == "nanorhino" || banish_source == "spooky music box mechanism" || banish_source == "ice hotel bell" || banish_source == "beancannon" || banish_source == "monkey slap") + b.custom_reset_conditions = "rollover"; + if (banish_source == "ice house" && (!$item[ice house].is_unrestricted() || in_bad_moon())) //not relevant + continue; + result.listAppend(b); + } + + __banishes_active_cache_cached_monsters_string = banished_monsters_string; + __banishes_active_cache = result; + + return result; +} + + +Banish [int] BanishesActiveInLocation(location l) +{ + boolean [monster] location_monsters; + foreach key, m in l.get_monsters() + location_monsters[m] = true; + Banish [int] banishes_active = BanishesActive(); + Banish [int] result; + foreach key, b in banishes_active { + if (location_monsters contains b.banished_monster) + result.listAppend(b); + } + return result; +} + +int BanishShortestBanishForLocation(location l) +{ + Banish [int] active_banishes = BanishesActiveInLocation(l); + int minimum = 2147483647; + foreach key, b in active_banishes { + minimum = MIN(minimum, b.BanishTurnsLeft()); + } + return minimum; +} + +Banish BanishForMonster(monster m) +{ + foreach key, b in BanishesActive() { + if (b.banished_monster == m) + return b; + } + Banish blank; + return blank; +} + +string BanishSourceForMonster(monster m) +{ + return BanishForMonster(m).banish_source; +} + +int [string] activeBanishNameCountsForLocation(location l) +{ + Banish [int] banishes_active = BanishesActive(); + + string [monster] names; + foreach key, banish in banishes_active { + if (banish.banished_monster.is_banished()) { //zuko wrote this code + names[banish.banished_monster] = banish.banish_source; + } + } + + int [string] banish_name_counts; + foreach key, m in l.get_monsters() { + if (names contains m) + banish_name_counts[names[m]] += 1; + if (my_path().id == PATH_ONE_CRAZY_RANDOM_SUMMER) { + foreach m2 in names { + if (m2.to_string().to_lower_case().contains_text(m.to_string().to_lower_case())) //FIXME complete hack, wrong, substrings, 1337, etc + banish_name_counts[names[m2]] += 1; + } + } + } + return banish_name_counts; +} + +boolean [string] activeBanishNamesForLocation(location l) +{ + boolean [string] result; + + foreach banish_name, count in l.activeBanishNameCountsForLocation() + result[banish_name] = (count > 0); + return result; +} + +Banish BanishByName(string name) +{ + foreach key, banish in BanishesActive() { + if (banish.banish_source == name) + return banish; + } + Banish blank; + return blank; +} + +int BanishLength(string banish_name) +{ + int length = __banish_source_length[banish_name.to_lower_case()]; + if (length < 0) + length = 2147483647; + return length; +} + +boolean BanishIsActive(string name) +{ + foreach key, banish in BanishesActive() { + if (banish.banish_source == name) + return true; + } + return false; +} + +void SEventsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + return; +} + +void SCrimbo2015GenerateResource(ChecklistEntry [int] resource_entries) +{ + string year_and_month = format_today_to_string("yyyyMM"); + if (year_and_month != "201512") + return; + if (mafiaIsPastRevision(16544) && !in_ronin()) + { + int herb_uses_left = clampi(10 - get_property_int("_fragrantHerbsUsed"), 0, 10); + if ($item[bundle of "fragrant" herbs].available_amount() > 0 && herb_uses_left > 0) + { + string [int] description; + description.listAppend("Free run/banish three monsters at once."); + monster [int] banished_monsters; + foreach key, b in BanishesActive() + { + if (b.banish_source == "bundle of "fragrant" herbs") + { + banished_monsters.listAppend(b.banished_monster); + } + } + if (banished_monsters.count() > 0) + description.listAppend("Have " + banished_monsters.listJoinComponents(", ", "and") + " banished."); + resource_entries.listAppend(ChecklistEntryMake("__item bundle of "fragrant" herbs", "", ChecklistSubentryMake(pluralise(herb_uses_left, "fragrant herb banish", "fragrant herb banishes"), "", description), 3).ChecklistEntrySetIDTag("Crimbo 2015 flagrant herbs")); + } + int stockpile_uses_left = clampi(10 - get_property_int("_nuclearStockpileUsed"), 0, 10); + if ($item[nuclear stockpile].available_amount() > 0 && stockpile_uses_left > 0) + { + string [int] description; + description.listAppend("Does not cost a turn."); + resource_entries.listAppend(ChecklistEntryMake("__item nuclear stockpile", "", ChecklistSubentryMake(pluralise(stockpile_uses_left, "nuclear stockpile instakill", "nuclear stockpile instakills"), "", description), 3).ChecklistEntrySetIDTag("Crimbo 2015 nuclear stockpile")); + } + } +} + +void SEventsGenerateResource(ChecklistEntry [int] resource_entries) +{ + SCrimbo2015GenerateResource(resource_entries); +} +Record SealSummon +{ + monster summoned_monster; + item figurine; + boolean can_buy_in_store_or_hermit; + int seal_clubber_candles_required; + int imbued_seal_blubber_candles_required; //0 or 1 + int minimum_level; + item item_dropped; + item equipment_dropped; + string item_dropped_description; +}; + +SealSummon SealSummonMake(monster summoned_monster, item figurine, boolean can_buy_in_store_or_hermit, int seal_clubber_candles_required, int imbued_seal_blubber_candles_required, int minimum_level, item item_dropped, string item_dropped_description, item equipment_dropped) +{ + SealSummon summon; + summon.summoned_monster = summoned_monster; + summon.figurine = figurine; + summon.can_buy_in_store_or_hermit = can_buy_in_store_or_hermit; + summon.seal_clubber_candles_required = seal_clubber_candles_required; + summon.imbued_seal_blubber_candles_required = imbued_seal_blubber_candles_required; + summon.minimum_level = minimum_level; + summon.item_dropped = item_dropped; + summon.equipment_dropped = equipment_dropped; + summon.item_dropped_description = item_dropped_description; + + return summon; +} + +void listAppend(SealSummon [int] list, SealSummon entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void SSealClubberInfernalSealsGenerateResource(ChecklistEntry [int] resource_entries) +{ + string [int] description; + int seal_summon_limit = 5; + if ($item[Claw of the Infernal Seal].available_amount() > 0) + { + seal_summon_limit = 10; + if ($item[Claw of the Infernal Seal].item_amount() + $item[Claw of the Infernal Seal].equipped_amount() == 0 && $item[Claw of the Infernal Seal].storage_amount() > 0) + description.listAppend("Pull the Claw of the Infernal Seal from hangk's."); + } + int seals_summoned = get_property_int("_sealsSummoned"); + int summons_remaining = MAX(seal_summon_limit - seals_summoned, 0); + if (summons_remaining == 0) + return; + + //Seal summons: + //FIXME suggest they equip a club (support swords with iron palms) + + if (!$slot[weapon].equipped_item().weapon_is_club()) + { + description.listAppend("Equip a club" + ($effect[Iron Palms].have_effect() > 0 ? " or sword" : "") + " first."); + } + + + //initialise all the seals: + SealSummon [int] seal_summons; + //seal_summons.listAppend(SealSummonMake($monster[SUMMONED_MONSTER], $item[FIGURINE], CAN_BUY_IN_STORE_OR_HERMIT, SEAL_CLUBBER_CANDLES_REQUIRED, IMBUED_SEAL_BLUBBER_CANDLES_REQUIRED, MINIMUM_LEVEL, $item[ITEM_DROPPED], "ITEM_DROPPED_DESCRIPTION")); + seal_summons.listAppend(SealSummonMake($monster[broodling seal], $item[figurine of a cute baby seal], true, 5, 0, 5, $item[severed flipper], "low-level club", $item[none])); + + seal_summons.listAppend(SealSummonMake($monster[Centurion of Sparky], $item[figurine of an armored seal], true, 10, 0, 9, $item[ingot of seal-iron], ($items[ingot of seal-iron,bad-ass club,creepy-ass club,evil-ass club,frigid-ass club,hot-ass club,nasty-ass club].available_amount() == 0 ? "+10ML craftable club" : ""), $item[none])); + + seal_summons.listAppend(SealSummonMake($monster[hermetic seal], $item[figurine of an ancient seal], true, 3, 0, 6, $item[powdered sealbone], "imbued candle source", $item[none])); + + seal_summons.listAppend(SealSummonMake($monster[Spawn of Wally], $item[figurine of a wretched-looking seal], true, 1, 0, 1, $item[tainted seal's blood], "minor potion", $item[none])); + + seal_summons.listAppend(SealSummonMake($monster[heat seal], $item[figurine of a charred seal], false, 0, 1, 6, $item[sizzling seal fat], "+init, +hot damage potion", $item[Abyssal ember])); + + seal_summons.listAppend(SealSummonMake($monster[navy seal], $item[figurine of a cold seal], false, 0, 1, 6, $item[frost-rimed seal hide], "+cold damage, +HP potion", $item[frozen seal spine])); + + seal_summons.listAppend(SealSummonMake($monster[Servant of Grodstank], $item[figurine of a stinking seal], false, 0, 1, 6, $item[fustulent seal grulch], "+20 ML, +stench damage potion", $item[infernal toilet brush])); + + seal_summons.listAppend(SealSummonMake($monster[shadow of Black Bubbles], $item[figurine of a shadowy seal], false, 0, 1, 6, $item[scrap of shadow], "+spooky damage potion", $item[shadowy seal eye])); + + seal_summons.listAppend(SealSummonMake($monster[watertight seal], $item[figurine of a sleek seal], false, 0, 1, 12, $item[hyperinflated seal lung], "underwater breathing potion", $item[none])); + + seal_summons.listAppend(SealSummonMake($monster[wet seal], $item[figurine of a slippery seal], false, 0, 1, 6, $item[seal lube], "+sleaze damage, +moxie potion", $item[mannequin leg])); + + seal_summons.listAppend(SealSummonMake($monster[none], $item[depleted uranium seal figurine], false, 0, 1, 0, $item[none], "random", $item[none])); + + //description left blank, due to possible revamp? + string url = ""; + if (guild_store_available()) + url = "shop.php?whichshop=guildstore3"; + + boolean want_output_ml = __misc_state["need to level"]; + + + string [int][int] options; + + if (true) + { + string [int] option; + option.listAppend("figurine"); + option.listAppend("candles"); + if (want_output_ml) + option.listAppend("ML"); + option.listAppend("drops"); + foreach key, s in option + { + option[key] = HTMLGenerateSpanOfClass(s, "r_bold"); + } + options.listAppend(option); + } + + if ($item[powdered sealbone].available_amount() > 0 && $item[imbued seal-blubber candle].available_amount() == 0) + { + description.listAppend("Can make an imbued seal-blubber candle."); + } + + foreach key, summon in seal_summons + { + if (summon.minimum_level > my_level()) + continue; + if (!summon.can_buy_in_store_or_hermit && summon.figurine.available_amount() == 0) + continue; + string figurine_name_simple = summon.figurine.to_string().replace_string("figurine of an ", "").replace_string("figurine of a ", ""); + + string candles_required = summon.seal_clubber_candles_required; + if ($item[seal-blubber candle].available_amount() < summon.seal_clubber_candles_required) + candles_required = HTMLGenerateSpanFont(candles_required, "grey"); + if (summon.imbued_seal_blubber_candles_required > 0) + { + candles_required = "imbued"; + } + string ml_description; + if (summon.summoned_monster != $monster[none]) + { + ml_description = summon.summoned_monster.base_attack; + } + + string item_description = summon.item_dropped_description; + + string [int] option; + option.listAppend(figurine_name_simple); + option.listAppend(candles_required); + if (want_output_ml) + option.listAppend(ml_description); + option.listAppend(item_description); + if (summon.imbued_seal_blubber_candles_required > 0 && $items[imbued seal-blubber candle,powdered sealbone].available_amount() == 0) + { + foreach key, s in option + { + option[key] = HTMLGenerateSpanFont(s, "grey"); + } + } + options.listAppend(option); + } + description.listPrepend(HTMLGenerateSimpleTableLines(options)); + + resource_entries.listAppend(ChecklistEntryMake("__item figurine of an ancient seal", url, ChecklistSubentryMake(pluralise(summons_remaining, "seal summon", "seal summons"), "", description), 10).ChecklistEntrySetIDTag("Seal clubber summon resource")); + + resource_entries.listAppend(ChecklistEntryMake("__item figurine of an ancient seal", url, ChecklistSubentryMake(pluralise(summons_remaining, "seal summon", "seal summons"), "", "See dedicated tile."), 10).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Seal clubber summon free fight")); //add an anchor to the dedicated tile?? +} + +void SSealClubberGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_class() != $class[seal clubber]) + return; + + SSealClubberInfernalSealsGenerateResource(resource_entries); +} + +void STurtleTamerGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_class() != $class[turtle tamer]) + return; + + if (__misc_state["in run"] && guild_store_available() && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST && $effect[Eau de Tortue].have_effect() == 0 && my_meat() >= 200) + { + optional_task_entries.listAppend(ChecklistEntryMake("__item helmet turtle", "shop.php?whichshop=guildstore3", ChecklistSubentryMake("Buy and use turtle pheromones", "", "Lets you encounter more turtles.")).ChecklistEntrySetIDTag("Turtle tamer pheromones")); + } +} + +void SDiscoBanditGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_class() != $class[disco bandit]) + return; + if ($skill[Break It On Down].have_skill() && $skill[Run Like the Wind].have_skill() && $skill[Pop and Lock It].have_skill()) + { + int steals_done = get_property_int("_raveStealCount"); + int steals_remaining = clampi(30 - steals_done, 0, 30); + if (steals_done > 0 && steals_remaining > 0) + { + string [int] description; + description.listAppend("Knocks loose a pickpocketable item."); + //raveCombo5 is rave steal + //FIXME list combo order + string rave_combo_number_5 = get_property("raveCombo5"); + if (rave_combo_number_5 != "") + { + string [int] skill_order = rave_combo_number_5.split_string(","); + description.listAppend(skill_order.listJoinComponents(__html_right_arrow_character).capitaliseFirstLetter() + "."); + } + resource_entries.listAppend(ChecklistEntryMake("__skill Disco Dance 3: Back in the Habit", "", ChecklistSubentryMake(pluralise(steals_remaining, "Rave Steal", "Rave Steals"), "", description), 8).ChecklistEntrySetIDTag("Disco bandit rave steal")); + } + } +} + +void SPastamancerGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_class() != $class[pastamancer]) + return; + if (__quest_state["Nemesis"].finished && !$skill[Canticle of Carboloading].have_skill()) + { + if ($item[black hymnal].available_amount() == 0) + { + optional_task_entries.listAppend(ChecklistEntryMake("__skill Canticle of Carboloading", "volcanoisland.php", ChecklistSubentryMake("Collect the black hymnal from the Nemesis Temple", "", "Unlocks Carboloading.")).ChecklistEntrySetIDTag("Nemesis quest pastamancer black hymnal get")); + } + else + { + optional_task_entries.listAppend(ChecklistEntryMake("__skill Canticle of Carboloading", "inventory.php?ftext=black+hymnal", ChecklistSubentryMake("Use the black hymnal", "", "Unlocks Carboloading.")).ChecklistEntrySetIDTag("Nemesis quest pastamancer black hymnal use")); + } + } +} + +void SClassesGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + STurtleTamerGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SPastamancerGenerateTasks(task_entries, optional_task_entries, future_task_entries); +} + +void SClassesGenerateResource(ChecklistEntry [int] resource_entries) +{ + SSealClubberGenerateResource(resource_entries); + SDiscoBanditGenerateResource(resource_entries); +} + + +string [int] SEquipmentGenerateXiblaxianHoloWristPuterDescription() +{ + string [int] description; + string [int][int] table; + table.listAppend(listMake("Outdoor", "polymer")); + table.listAppend(listMake("Indoor", "circuitry")); + table.listAppend(listMake("Underground", "alloy")); + table.listAppend(listMake("Underwater", "polymer")); + //this is kind of a hack: + int index_to_bold = -1; + if (__last_adventure_location.environment == "outdoor") + index_to_bold = 0; + else if (__last_adventure_location.environment == "indoor") + index_to_bold = 1; + else if (__last_adventure_location.environment == "underground") + index_to_bold = 2; + if (__last_adventure_location.environment == "underwater") + index_to_bold = 3; + + if (index_to_bold != -1) + { + foreach key, v in table[index_to_bold] + table[index_to_bold][key] = HTMLGenerateSpanOfClass(v, "r_bold"); + } + description.listAppend(HTMLGenerateSimpleTableLines(table)); + + if (!get_property_boolean("_holoWristCrystal")) + description.listAppend("Can acquire a crystal by mining. (once/day)"); + + string [int] items_owned; + foreach it in $items[Xiblaxian alloy,Xiblaxian circuitry,Xiblaxian polymer,Xiblaxian crystal] + { + if (it.available_amount() > 0) + items_owned.listAppend(it.available_amount() + " " + it); + } + + description.listAppend("Own " + items_owned.listJoinComponents(", ", "and") + "."); + return description; +} + +void SEquipmentGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[Xiblaxian holo-wrist-puter].equipped_amount() > 0) + { + int turns_left = XiblaxianHoloWristPuterTurnsUntilNextItem(); + if (turns_left == 1 || turns_left == 0) + { + string [int] description = SEquipmentGenerateXiblaxianHoloWristPuterDescription(); + task_entries.listAppend(ChecklistEntryMake("__item Xiblaxian holo-wrist-puter", "", ChecklistSubentryMake("Xiblaxian item next combat", "", description), -11).ChecklistEntrySetIDTag("Xiblaxian wrist now")); + } + } +} + +void SEquipmentGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[Xiblaxian holo-wrist-puter].equipped_amount() > 0) + { + int turns_left = XiblaxianHoloWristPuterTurnsUntilNextItem(); + if (turns_left != -1 || true) + { + string [int] description = SEquipmentGenerateXiblaxianHoloWristPuterDescription(); + //description.listAppend("_holoWristDrops = " + get_property_int("_holoWristDrops")); + //description.listAppend("_holoWristProgress = " + get_property_int("_holoWristProgress")); + + string header = turns_left + " combats to Xiblaxian item"; + if (turns_left <= 1) + header = "Xiblaxian next turn"; + resource_entries.listAppend(ChecklistEntryMake("__item Xiblaxian holo-wrist-puter", "", ChecklistSubentryMake(header, "", description), 8).ChecklistEntrySetIDTag("Xiblaxian wrist reminder")); + } + } +} + +static +{ + int [string] __moon_sign_id_lookup; + void initialiseMoonSignIDLookup() + { + __moon_sign_id_lookup[""] = 0; + __moon_sign_id_lookup["None"] = 0; + __moon_sign_id_lookup["Mongoose"] = 1; + __moon_sign_id_lookup["Wallaby"] = 2; + __moon_sign_id_lookup["Vole"] = 3; + __moon_sign_id_lookup["Platypus"] = 4; + __moon_sign_id_lookup["Opossum"] = 5; + __moon_sign_id_lookup["Marmot"] = 6; + __moon_sign_id_lookup["Wombat"] = 7; + __moon_sign_id_lookup["Blender"] = 8; + __moon_sign_id_lookup["Packrat"] = 9; + __moon_sign_id_lookup["Bad Moon"] = 10; //confirmed + } + initialiseMoonSignIDLookup(); +} + +Record NumberologyCacheState +{ + int b; + int c; + int [int] input_to_outputs; + int [int] input_deltas; +}; + +NumberologyCacheState NumberologyCacheStateMake() +{ + NumberologyCacheState r; + r.b = -1; + r.c = -1; + return r; +} + +static +{ + NumberologyCacheState __numberology_cache = NumberologyCacheStateMake(); +} + +void calculateNumberologyInputValuesForOutputs(boolean [int] desired_digits_in, int [int] digit_inputs_to_outputs_out, int [int] digit_inputs_to_deltas_out) +{ + if (!(__moon_sign_id_lookup contains my_sign())) //not computable + return; + + boolean [int] desired_digits_left; + foreach digit in desired_digits_in + { + desired_digits_left[digit] = true; + digit_inputs_to_deltas_out[digit] = 99; + } + int mood_sign_id = __moon_sign_id_lookup[my_sign()]; + + int b = my_spleen_use() + my_level(); + int c = (my_ascensions() + mood_sign_id) * b + my_adventures(); + + if (__numberology_cache.b == b && __numberology_cache.c == c) + { + //Cache lookup: + foreach digit in desired_digits_in + { + if (__numberology_cache.input_to_outputs contains digit) + { + digit_inputs_to_outputs_out[digit] = __numberology_cache.input_to_outputs[digit]; + remove desired_digits_left[digit]; + } + else if (__numberology_cache.input_deltas contains digit) + { + digit_inputs_to_deltas_out[digit] = __numberology_cache.input_deltas[digit]; + remove desired_digits_left[digit]; + } + } + } + if (desired_digits_left.count() == 0) + return; + + int last_x = -1; + //Brute force method: + for x from 0 to 99 + { + int v = x * b + c; + int last_two_digits = v % 100; + if (desired_digits_left contains last_two_digits) + { + remove desired_digits_left[last_two_digits]; + remove digit_inputs_to_deltas_out[last_two_digits]; + digit_inputs_to_outputs_out[last_two_digits] = x; + if (desired_digits_left.count() == 0) + { + last_x = x; + break; + } + } + foreach digit in desired_digits_left + { + int delta = digit - last_two_digits; + if (delta <= 0) + digit_inputs_to_deltas_out[digit] = min(digit_inputs_to_deltas_out[digit], -delta); + else + { + delta = digit - (last_two_digits + 100); + if (delta <= 0) + digit_inputs_to_deltas_out[digit] = min(digit_inputs_to_deltas_out[digit], -delta); + } + } + } + + //Save cache: + if (__numberology_cache.b != b || __numberology_cache.c != c) + __numberology_cache = NumberologyCacheStateMake(); + __numberology_cache.b = b; + __numberology_cache.c = c; + foreach input, output in digit_inputs_to_outputs_out + __numberology_cache.input_to_outputs[input] = output; + foreach input, delta in digit_inputs_to_deltas_out + __numberology_cache.input_deltas[input] = delta; +} + + +void SCalculateUniverseGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!$skill[Calculate the Universe].skill_is_usable()) + return; + int uses_remaining = 1; + if (get_property_boolean("_universeCalculated") && !mafiaIsPastRevision(17039)) + return; + if (mafiaIsPastRevision(17039)) + { + int universe_calculated = get_property_int("_universeCalculated"); + int limit = 1; + + // As of August 2022, within run, you only get access to 3 calculates per day. This cuts the tile off in-run while letting + // it remain active out-of-run. + int skill_number = __misc_state["in run"] ? min(get_property_int("skillLevel144"),3) : get_property_int("skillLevel144"); + limit = max(skill_number, limit); + if (universe_calculated >= limit) + return; + uses_remaining = limit - universe_calculated; + } + + string [int] description; + + string [int] useful_digits_and_their_reasons; + if (__setting_enable_outputting_all_numberology_options) + { + for digit from 0 to 99 + { + if (!($ints[24,25,26,28,29,31,32,39,41,42,46,52,53,54,55,56,59,60,61,62,64,65,67,72,73,74,76,79,80,81,82,84,85,86,91,92,94,95,96] contains digit)) //Try Again + useful_digits_and_their_reasons[digit] = ""; + } + } + //Set up useful digits: + if (my_path().id != PATH_SLOW_AND_STEADY) + useful_digits_and_their_reasons[69] = "+3 adventures"; + if (hippy_stone_broken()) + useful_digits_and_their_reasons[37] = "+3 fights"; + if (__misc_state["in run"]) + { + if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues") && !__quest_state["Level 12"].finished) + useful_digits_and_their_reasons[51] = "War frat orc to YR"; + useful_digits_and_their_reasons[14] = "1400 meat (autosell 14 moxie weeds)"; + + int ice_cubes_needing_creation = $item[perfect ice cube].available_amount(); + if ($skill[Perfect Freeze].skill_is_usable() && !get_property_boolean("_perfectFreezeUsed")) + ice_cubes_needing_creation += 1; + if (ice_cubes_needing_creation > 0 && $items[bottle of rum,bottle of vodka,boxed wine,bottle of gin,bottle of whiskey,bottle of tequila].available_amount() < ice_cubes_needing_creation && __misc_state["can drink just about anything"]) + { + //FIXME 18, 44, 75, and 99 are all valid for this - pick whichever we can summon now? + useful_digits_and_their_reasons[99] = "base booze for perfect ice cube"; + } + if (__quest_state["Level 5"].mafia_internal_step < 3 && $item[Knob Goblin Perfume].available_amount() == 0 && $effect[Knob Goblin Perfume].have_effect() == 0 && in_ronin()) //have_outfit_components("Knob Goblin Harem Girl Disguise") + { + useful_digits_and_their_reasons[9] = "knob goblin perfume for boss fight"; + } + if ($item[Vegetable of Jarlsberg].available_amount() > 0) + useful_digits_and_their_reasons[16] = "magicalness-in-a-can for Jarlsberg's vegetable soup"; + } + if (my_level() < 13) + { + //making a guess here - 89 is 89 mainstat with bonus experience percent (seems logical with the limited data we have) + float mainstat_gained = 89.0 * (1.0 + numeric_modifier(my_primestat() + " experience percent") / 100.0); + useful_digits_and_their_reasons[89] = roundForOutput(mainstat_gained, 0) + " mainstats"; + } + + //useful_digits_and_their_reasons[44] = "is very bad to steal jobu's rum"; + + //Run complicated calculation code: + boolean [int] desired_digits; + foreach digit in useful_digits_and_their_reasons + desired_digits[digit] = true; + int [int] digit_inputs_to_outputs; + int [int] digit_inputs_to_deltas; + calculateNumberologyInputValuesForOutputs(desired_digits, digit_inputs_to_outputs, digit_inputs_to_deltas); + + string [int][int] table; + table.listAppend(listMake(HTMLGenerateSpanOfClass("Enter", "r_bold"), HTMLGenerateSpanOfClass("For", "r_bold"))); + string [int][int] mappings; + + foreach digit, reason in useful_digits_and_their_reasons + { + string what_to_do; + if (digit_inputs_to_outputs contains digit) + { + if (__setting_enable_outputting_all_numberology_options) + mappings.listAppend(listMake(digit_inputs_to_outputs[digit].to_string(), digit.to_string())); + //mappings.listAppend(digit_inputs_to_outputs[digit] + " -> " + digit); + what_to_do = digit_inputs_to_outputs[digit].to_string();// + HTMLGenerateSpanFont(" (" + digit + ")", "gray", "0.9em"); + } + else if (digit_inputs_to_deltas contains digit) + { + what_to_do = "Wait " + digit_inputs_to_deltas[digit] + " adv"; + } + else + what_to_do = "Unknown result to end in " + digit; + if (reason != "") + { + //table.listAppend(listMake(what_to_do, reason)); + table.listAppend(listMake(what_to_do, reason + HTMLGenerateSpanFont(" (" + digit + ")", "gray", "0.9em"))); + } + } + + string table_description; + if (table.count() > 0) + table_description += "|*" + HTMLGenerateSimpleTableLines(table); + if (mappings.count() > 0) + { + //FIXME full description? + string [int][int] mappings_final; + //Compress mappings: + mappings_final[0] = listMakeBlankString(); + foreach key in mappings + { + string [int] mapping = mappings[key]; + string [int] line = listMake(" ", mapping[0], __html_right_arrow_character, mapping[1]); + + if (mappings_final[mappings_final.count() - 1].count() >= 12) + mappings_final.listAppend(listMakeBlankString()); + mappings_final[mappings_final.count() - 1].listAppendList(line); + } + + + buffer tooltip_text; + tooltip_text.append(HTMLGenerateTagWrap("div", "Values to input for " + __html_right_arrow_character + " output", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); + tooltip_text.append(HTMLGenerateSimpleTableLines(mappings_final)); + + string line = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class") + "Full table", "r_tooltip_outer_class"); + //we can't do full-width table entries because of colspan and display:table, so mimic it: + //description.listAppend(line); + //table.listAppend(listMake(line)); + if (table_description != "") + table_description += "
"; + table_description += line; + } + if (table_description != "") + description.listAppend("Cast skill, enter the right number: (this changes)" + table_description); + else + description.listAppend("Cast skill, enter the right number."); + + /*if (table.count() > 1) + description.listAppend("Cast skill, enter the right number: (this changes, and is still being spaded)|*" + HTMLGenerateSimpleTableLines(table)); + else + description.listAppend("Cast skill, enter the right number.");*/ + string title = "Calculate the Universe"; + if (uses_remaining > 1) + title = pluralise(uses_remaining, "Calculate the Universe", "Calculate the Universes"); + resource_entries.listAppend(ChecklistEntryMake("__skill Calculate the Universe", "skillz.php", ChecklistSubentryMake(title, "", description), 0).ChecklistEntrySetIDTag("Calculate universe resource")); +} + + +void SPVPGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!hippy_stone_broken()) + return; + if (pvp_attacks_left() > 0 && today_is_pvp_season_end()) + { + optional_task_entries.listAppend(ChecklistEntryMake("__effect Swordholder", "peevpee.php?place=fight", ChecklistSubentryMake("Run all of your fights", "", listMake("Season ends today.", "Make sure to get the seasonal item if you haven't, as well."))).ChecklistEntrySetIDTag("PVP season end")); + } + + int [string] mini_names = current_pvp_stances(); + + ChecklistEntry entry; + + + string [int] attacking_description; + string [int] attacking_modifiers; + + string [int] overall_modifiers; + string [int] overall_description; + foreach mini in mini_names + { + string [int] modifiers; + string [int] description; + if (mini == "Maul Power") + { + if ($skill[Kung Fu Hustler].have_skill() && $effect[Kung Fu Fighting].have_effect() == 0) + attacking_description.listPrepend("run a combat without a weapon first"); + attacking_modifiers.listAppend("weapon damage"); + continue; + } + else if (mini == "15 Minutes of Fame" || mini == "Beary Famous" || mini == "Upward Mobility Contest" || mini == "Optimal PvP") + { + //attacking_description.listAppend("hit for fame"); + attacking_description.listAppend("maximise fightgen and hit for fame"); + continue; + } + else if (mini == "80 Days and Counting") + { + description.listAppend("Drink Around the Worlds."); + if (have_outfit_components("Hodgman's Regal Frippery")) + { + if (get_property_int("_hoboUnderlingSummons") < 5) + description.listAppend("Equip Hodgman's Regal Frippery, summon hobo underling, ask for a drink."); + } + else if (QuestState("questL12War").mafia_internal_step == 2) + { + description.listAppend("Finish the war."); + } + else if ($item[Spanish fly trap].available_amount() == 0) + { + modifiers.listAppend("-combat"); + if ($location[The Orcish Frat House].noncombat_queue.contains_text("I Just Wanna Fly") || $location[The Orcish Frat House (Bombed Back to the Stone Age)].noncombat_queue.contains_text("Me Just Want Fly")) + { + description.listAppend("Run -combat in The Obligatory Pirate's Cove, acquire Spanish fly trap."); + } + else + description.listAppend("Adventure in the Orcish Frat House until you meet the I Just Wanna Fly adventure.|Then run -combat in The Obligatory Pirate's Cove, acquire Spanish fly trap."); + } + else + { + string [int] tasks; + if ($item[Spanish fly trap].equipped_amount() == 0) + { + tasks.listAppend("equip Spanish fly trap"); + } + modifiers.listAppend("+item"); + tasks.listAppend("adventure in the Hippy Camp, collecting spanish flies");// + (my_level() >= 9 ? " (+combat)" : "")); + if ($item[Spanish fly].available_amount() >= 5) + tasks.listAppend("turn in " + pluralise($item[Spanish fly]) + " in the orcish frat house (-combat)"); + description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + } + } + else if (mini == "Totally Optimal") + { + if (__quest_state["Level 11 Ron"].state_int["protestors remaining"] > 0) + description.listAppend("Fight zeppelin protestors, and don't try to speed them up."); + else + description.listAppend("Ascend to fight more Zeppelin Protestors."); + } + else if (mini == "Optimal Drinking") + { + if (inebriety_limit() == 0) + description.listAppend("Ascend a path you can drink on."); + else + description.listAppend("When drinking, prefer drinks that have effects."); + } + else if (mini == "Familiar Rotation") + { + if (in_ronin()) + description.listAppend("Pick a different familiar than your last ascensions this season."); + else + description.listAppend("Ascend to rotate your familiar."); + } + else if (mini == "Foreigner Reference") + { + description.listAppend("Drink ice-cold Sir Schlitzs or ice-cold Willers." + (in_ronin() ? "|The Orcish Frat House has them. Run +400% item" + (my_level() >= 9 ? " and +15% combat." : "") : "")); + } + else if (mini == "Best Served Repeatedly") + { + description.listAppend("Attack the same target repeatedly. Ideally, lose."); + } + else if (mini == "Burrowing Deep" || mini == "Obviously Optimal") + { + if (__misc_state_int["Basement Floor"] > 400) + { + description.listAppend("Ascend to basement more."); + } + else if (__misc_state_int["Basement Floor"] <= 1) //this test could be better + { + description.listAppend("Unlock Fernswarthy's basement via your guild."); + } + else + { + int floors_remaining = 200 - __misc_state_int["Basement Floor"]; + if (floors_remaining < 0) + floors_remaining = 400 - __misc_state_int["Basement Floor"]; + description.listAppend("Collect a Pan-Dimensional Gargle Blaster from Fernswarthy's basement. " + pluraliseWordy(floors_remaining, "floor", "floors") + " to go."); + } + } + else if (mini == "Frostily Ephemeral" || mini == "Newest Born" || mini == "SELECT asc_time FROM zzz_players WHERE player_id=%playerid%" || mini == "Optimal Ascension") + { + description.listAppend("Ascend to reset timer."); + } + else if (mini == "Karrrmic Battle" || mini == "Karmic Battle") + { + description.listAppend("Ascend to gain more karma."); + } + else if (mini == "Back to Square One") + { + description.listAppend("Ascend."); + } + else if (mini == "Baker's Dozen") + { + description.listAppend("Adventure as often as possible in Madness Bakery."); + } + else if (mini == "Fahrenheit 451") + { + attacking_modifiers.listAppend("hot damage"); + attacking_modifiers.listAppend("hot spell damage"); + continue; + } + else if (mini == "I Like Pi") + { + description.listAppend("Eat key lime pies."); + } + else if (mini == "HTTP 301 Moved Permanently") + { + description.listAppend("Adventure in as many different locations as you can."); + } + else if (mini == "Quality Assurance") + { + description.listAppend("Defeat bug-phylum monsters."); + } + else if (mini == "Free.Willy.1993.1080p.BRRip.x265.torrent") + { + description.listAppend("Fight dolphins.|Farm sand dollars, turn them into dolphin whistles, and use them."); + } + else if (mini == "Installation Wizard") + { + modifiers.listAppend("+item"); + if (!canadia_available()) + { + description.listAppend("Farm dilapidated wizard hats from copied swamp owls.|Or ascend canadia moon sign."); + } + else + { + description.listAppend("Farm dilapidated wizard hats from swamp owls in The Weird Swamp Village."); + } + } + else if (mini == "Illegal Operation") + { + description.listAppend("Buy goofballs from the suspicious-looking guy. If they're too expensive, ascend to reset the price."); + } + else if (mini == "Fotoshop.CS11.Keygen.exe [legit]") + { + description.listAppend("Eat digital key lime pies."); + } + else if (mini == "Most Murderous" || mini == "Icy Revenge") + { + //FIXME list + description.listAppend("Defeat once/ascension bosses."); + } + else if (mini == "Grave Robbery" || mini == "Bear Hunter") + { + if ($item[wand of nagamar].available_amount() > 0) + description.listAppend("Ascend."); + else + description.listAppend("Avoid making the wand of nagamar, lose to the naughty sorceress (3), and look for the wand in the very unquiet garves"); + } + else if (mini == "Basket Reaver") + { + if (my_level() < 11) + { + description.listAppend("Level up."); + } + else + { + modifiers.listAppend("+5% combat"); + modifiers.listAppend("olfact black widow"); + modifiers.listAppend("+item"); + description.listAppend("Run +item% and farm black widows in the black forest."); + } + } + else if (mini == "Rule 42") + { + if ($location[the Haunted Bathroom].noncombat_queue.contains_text("Off the Rack")) //not perfect + continue; + modifiers.listAppend("-combat"); + if ($location[the Haunted Bathroom].locationAvailable()) + description.listAppend("Collect a towel in the Haunted Bathroom."); + else + description.listAppend("Unlock the Haunted Bathroom in Spookyraven Manor."); + } + else if (mini == "Tea for 2, 3, 4 or More") + { + boolean [item] tea = $items[Corpse Island iced tea,cup of lukewarm tea,cup of "tea",hippy herbal tea,Ice Island Long Tea,New Zealand iced tea]; + //description.listAppend("Drink tea.|" + ); + + string tooltip_text = tea.listInvert().listJoinComponents(", ", "or").capitaliseFirstLetter() + "."; + tooltip_text += "
Cheapest is cup of lukewarm tea.
Hippy herbal tea is guano coffee cup (bat guano, batrat, batrat burrow) + herbs (hippy store)."; + + string title = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class") + "Drink tea.", "r_tooltip_outer_class"); + description.listAppend(title); + } + else if (mini == "Scurvy Challenge") + { + boolean [item] fruit = $items[grapefruit,kumquat,lemon,lime,orange,pixel lemon,sea tangelo,tangerine,vinegar-soaked lemon slice]; + //description.listAppend("Drink tea.|" + ); + + string tooltip_text = fruit.listInvert().listJoinComponents(", ", "or").capitaliseFirstLetter() + "."; + tooltip_text += "
Check the hippy store, on the island."; + + string title = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class") + "Eat fruit.", "r_tooltip_outer_class"); + description.listAppend(title); + } + else if (mini == "Raw Carnivorery") + { + //FIXME This could be dynamic, I bet the game is dynamic. + boolean [item] meat = $items[beefy fish meat, glistening fish meat, slick fish meat, "meat" stick, raw mincemeat, alien meat, dead meat bun, consummate meatloaf, VYKEA meatballs]; + + string [int] entries; + foreach it in meat + { + string entry = it; + if (entries.count() == 0) entry = entry.capitaliseFirstLetter(); + if (it.fullness == 1) + entry = HTMLGenerateSpanOfClass(entry, "r_bold"); + entries.listAppend(entry); + } + + string tooltip_text = entries.listJoinComponents(", ", "or") + "."; + + string title = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class") + "Eat meat.", "r_tooltip_outer_class"); + description.listAppend(title); + } + else if (mini == "That Britney Spears Number") + { + string [int] tasks; + if ($item[wooden stakes].available_amount() == 0) + { + description.listAppend("Adventure in the Spooky Forest, collect wooden stakes from the noncombat."); + description.listAppend("Follow the old road " + __html_right_arrow_character + " Knock on the cottage door."); + modifiers.listAppend("-combat"); + } + else + { + if ($item[wooden stakes].equipped_amount() == 0) + { + tasks.listAppend("equip wooden stakes"); + } + modifiers.listAppend("olfact spooky vampire"); + tasks.listAppend("fight vampires in the Spooky Forest"); + description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + } + } + else if (mini == "The Purity is Right" || mini == "Polar Envy" || mini == "Purity") + { + attacking_description.listAppend("run zero effects"); + continue; + } + else if (mini == "Purrrity") + { + attacking_description.listAppend("run zero effects with R in their name"); + continue; + } + else if (mini == "The Optimal Stat") + { + attacking_modifiers.listAppend("+item drop"); + continue; + } + else if (mini == "A Nice Cold One" || mini == "Thirrrsty forrr Booze") + { + attacking_modifiers.listAppend("+booze drop"); + continue; + } + else if (mini == "Smellin' Like a Stinkin' Rose") + { + attacking_modifiers.listAppend("-combat"); + continue; + } + else if (mini == "Ready to Melt") + { + attacking_modifiers.listAppend("hot damage"); + attacking_modifiers.listAppend("hot spell damage"); + continue; + } + else if (mini == "Zero Tolerance") + { + description.listAppend("Don't drink booze."); + } + else if (mini == "Visiting the Cousins" || mini == "Visiting The Co@^&$`~") + { + if (knoll_available()) + description.listAppend("Adventure in the bugbear pens."); + else + description.listAppend("Ascend knoll moon sign."); + } + else if (mini == "Craft Brew is Optimal") + { + if (gnomads_available()) + description.listAppend("Drink from the Gnomish Microbrewery."); + else + description.listAppend("Ascend Gnomish moon sign."); + } + else if (mini == "Who Runs Bordertown?") + { + if (gnomads_available()) + description.listAppend("Adventure in the Thugnderdome."); + else + description.listAppend("Ascend Gnomish moon sign."); + } + else if (mini == "Pirate Wars!") + { + description.listAppend("Fight pirates, but not too many; the count resets every day."); + } + else if (mini == "Bilge Hunter") + { + description.listAppend("Run +300 ML and +combat, and fight drunken rat kings in the Typical Tavern basement."); + modifiers.listAppend("+300 ML"); + modifiers.listAppend("+combat"); + } + else if (mini == "Death to Ninja!") + { + string [int] tasks; + if (!is_wearing_outfit("Swashbuckling Getup")) + tasks.listAppend("equip swashbuckling getup"); + tasks.listAppend("fight ninja"); + description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + } + else if (mini == "Swimming with the Fishes") + { + description.listAppend("Spend turns underwater."); + } + else if (mini == "(Fur) Shirts and Skins") + { + description.listAppend("Collect furs and skins from monsters. (+item)|The icy peak? Olfact yeti."); + } + else if (mini == "With Your Bare Hands") + { + description.listAppend("Fight beast-type monsters without a weapon equipped.|The icy peak (olfact yeti) or the dire warren?"); + } + else if (mini == "Northern Digestion" || mini == "Frozen Dinners") + { + if (canadia_available()) + { + if (availableFullness() > 0) + description.listAppend("Eat in Chez Snoteé."); + } + else + description.listAppend("Ascend canadia moon sign."); + } + else if (mini == "ERR_VOLUME_FULL") + { + description.listAppend("Don't eat anything."); + } + else if (mini == "Really Bloody") + { + if (inebriety_limit() == 0) + description.listAppend("Ascend to drink Bloody Mary."); + else + description.listAppend("Drink Bloody Mary."); + } + else if (mini == "System Clock Reset: It's 2006 again!") + { + if (inebriety_limit() == 0) + description.listAppend("Ascend to drink White Canadians."); + else + description.listAppend("Drink White Canadians."); + } + else if (mini == "Liver of the Damned") + { + if (inebriety_limit() == 0) + description.listAppend("Ascend to drink cursed bottles of rum."); + else + description.listAppend("Drink cursed bottles of rum."); + description.listAppend("Run -combat at the Poop Deck, set an open course to 1,1, open the cursed chests."); + modifiers.listAppend("-combat"); + } + else if (mini == "Beast Master") + { + attacking_modifiers.listAppend("familiar weight"); + continue; + } + else if (mini == "Letter of the Moment") + { + attacking_modifiers.listAppend("letter of the moment"); + continue; + } + else if (mini == "ASCII-7 of the moment") + { + attacking_modifiers.listAppend("letter a in equipment"); + continue; + } + else if (mini == "Barely Dressed") + { + attacking_description.listAppend("do not equip equipment"); + continue; + } + else if (mini == "DEFACE") + { + attacking_description.listAppend("wear equipment with A/B/C/D/E/F/numbers in them"); + continue; + } + else if (mini == "Dressed to the 9s") + { + attacking_description.listAppend("wear equipment with numbers in them"); + continue; + } + else if (mini == "Optimal Dresser") + { + attacking_description.listAppend("wear low-power shirt/hat/pants"); + continue; + } + else if (mini == "Dressed in Rrrags" || mini == "Outfit Compression") + { + attacking_description.listAppend("wear short-named equipment"); + continue; + } + else if (mini == "Hibernation Ready" || mini == "All Bundled Up") + { + attacking_modifiers.listAppend("cold resistance"); + continue; + } + else if (mini == "Loot Hunter" || mini == "The Optimal Stat") + { + attacking_modifiers.listAppend("+item"); + continue; + } + else if (mini == "Safari Chic") + { + attacking_modifiers.listAppend("equipment autosell value"); + continue; + } + else if (mini == "Checking It Twice") + { + attacking_description.listAppend("target players you haven't fought twice"); + continue; + } + else if (mini == "Ice Hunter") + { + description.listAppend("Fight ice skates. Either fax/wish/copy them, or olfact them in the The Skate Park underwater."); + } + else if (mini == "Bear Hugs All Around" || mini == "Sharing the Love (to stay warm)" || mini == "Fair Game") + { + description.listAppend("Maximise fightgen, attack as many unique opponents as possible."); + } + else if (mini == "Most Things Eaten") + { + string line = "Eat as many one-fullness foods as possible."; + if (__campground[$item[portable mayo clinic]] > 0 && availableDrunkenness() > 0) + line += "|Also use mayodiol."; + description.listAppend(line); + } + else if (mini == "Beta Tester" || mini == "Optimal War") + { + if (__quest_state["Level 12"].finished) + { + description.listAppend("Ascend to fight in war."); + } + else if (!__quest_state["Level 12"].started) + { + description.listAppend("Start the war."); + } + else + { + description.listAppend("Finish the war for the frat side, with five sidequests completed. (iron beta of industry reward)"); + } + } + else if (mini == "Snow Patrol") + { + if (__quest_state["Level 12"].finished) + { + description.listAppend("Ascend to fight in war."); + } + else if (!__quest_state["Level 12"].started) + { + description.listAppend("Start the war."); + } + else + { + modifiers.listAppend("+4 cold res"); + string line = "Fight on the battlefield"; + if (numeric_modifier("cold resistance") < 4) + line += HTMLGenerateSpanFont(" with +4 cold resistance", "red"); + line += "."; + description.listAppend(line); + } + } + else + { + if (my_id() == 1557284) + description.listAppend(HTMLGenerateSpanFont("Unhandled mini \"" + mini + "\".", "red")); + else + continue; + } + overall_modifiers.listAppendList(modifiers); + if (description.count() > 0) + overall_description.listAppend(description.listJoinComponents("|*")); + //entry.subentries.listAppend(ChecklistSubentryMake(mini, modifiers, description)); + } + if (overall_description.count() > 0) + { + entry.subentries.listAppend(ChecklistSubentryMake("Work on PVP minis", overall_modifiers, overall_description)); + } + if (attacking_modifiers.count() > 0) + attacking_description.listAppend("maximise " + attacking_modifiers.listJoinComponents(" / ")); + if (attacking_description.count() > 0) + { + entry.subentries.listAppend(ChecklistSubentryMake("When attacking", attacking_modifiers, attacking_description.listJoinComponents(", ", "and ").capitaliseFirstLetter() + ".")); + } + + if (entry.subentries.count() > 0) + { + entry.image_lookup_name = "__effect Swordholder"; + entry.url = "peevpee.php"; + entry.tags.id = "PVP suggestions"; + entry.importance_level = 6; + optional_task_entries.listAppend(entry); + } +} + +//demonSummoned +RegisterResourceGenerationFunction("SDemonSummonGenerateResource"); +void SDemonSummonGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!QuestState("questL11Manor").finished || my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO) + return; + if (get_property_boolean("demonSummoned")) + return; + //thin black candle >= 3 + //scroll of ancient forbidden unspeakable evil + //FIXME suggest running intergnat? + + if ($item[thin black candle].available_amount() >= 3 && $item[scroll of ancient forbidden unspeakable evil].available_amount() + $item[scroll of ancient forbidden unspeakable evil].creatable_amount() > 0) + { + string [int] description; + string url = "place.php?whichplace=manor4&action=manor4_chamber"; + + if ($item[thin black candle].item_amount() < 3 && $item[thin black candle].available_amount() >= 3) + { + description.listAppend("Pull 3 thin black candles."); + url = ""; + } + if ($item[scroll of ancient forbidden unspeakable evil].available_amount() == 0 && $item[scroll of ancient forbidden unspeakable evil].creatable_amount() > 0) + { + description.listAppend("Create a scroll of ancient forbidden unspeakable evil."); + url = ""; + } + + string [int][int] john; + //Prenatural greed. + string [string] demons; + demons["demonName2"] = "+100% meat"; + if ($familiar[intergnat].familiar_is_usable() && in_ronin()) + { + if (!get_property("demonName12").contains_text("Neil")) //FIXME what if neil is on their friends list? + { + description.listAppend("Could run intergnat for demon name."); + } + else + { + if (my_level() == 11) + { + if (__dense_liana_machete_items.available_amount() == 0) + demons["demonName12"] += "Antique machete, tomb ratchet, and cigarette lighter."; + else + demons["demonName12"] += "Tomb ratchet, and cigarette lighter."; + } + else if (my_level() == 12) + { + if ($items[richard's star key,star chart].available_amount() == 0) + demons["demonName12"] += "Star chart."; + } + else if (my_level() == 13) + demons["demonName12"] += "+50% init buff."; + else + demons["demonName12"] += "1000 meat."; + if (demons["demonName12"] != "") + demons["demonName12"] += "|"; + demons["demonName12"] += "+10% item, +20% meat, +50% init, +spell/weapon damage buff."; + if (my_familiar() != $familiar[intergnat]) + demons["demonName12"] += "|Make sure to switch to your intergnat familiar before summoning."; + } + } + //Intergnat. + + foreach property, description in demons + { + string property_value = get_property(property); + if (property_value == "") + continue; + john.listAppend(listMake(property_value, description)); + } + + if (john.count() > 0) + description.listAppend(HTMLGenerateSimpleTableLines(john)); + + resource_entries.listAppend(ChecklistEntryMake("__item thin black candle", url, ChecklistSubentryMake("Demon summonable", "", description), 7).ChecklistEntrySetIDTag("Manor demon summoning")); + } +} +RegisterTaskGenerationFunction("SAreaUnlocksGenerateTasks"); +void SAreaUnlocksGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__misc_state["desert beach available"] && __misc_state["in run"] && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_SEA) + { + string url; + ChecklistSubentry subentry; + boolean optional = false; + subentry.header = "Unlock desert beach"; + boolean [location] relevant_locations; + if (my_path().id == PATH_COMMUNITY_SERVICE) + { + subentry.header = "Optionally unlock desert beach"; + subentry.entries.listAppend("Not needed to finish path."); + optional = true; + } + if (my_path().id == PATH_NUCLEAR_AUTUMN) + { + subentry.entries.listAppend("Wait until level eleven, which will unlock it autumn-atically."); + } + else if (!knoll_available()) + { + relevant_locations[$location[the degrassi knoll garage]] = true; + string meatcar_line = "Build a bitchin' meatcar."; + if ($item[bitchin' meatcar].creatable_amount() > 0) + meatcar_line += "|*You have all the parts, build it!"; + else + { + item [int] missing_parts_list = missingComponentsToMakeItem($item[bitchin' meatcar]); + boolean [item] missing_parts = missing_parts_list.listInvert(); + + //Tires - 100% drop - Gnollish Tirejuggler in The Degrassi Knoll Garage + //empty meat tank, cog, spring, sprocket - Gnollish toolbox - Gnollish Gearhead in The Degrassi Knoll Garage + // + string [int] meatcar_modifiers; + if (missing_parts[$item[empty meat tank]] || missing_parts[$item[cog]] || missing_parts[$item[spring]] || missing_parts[$item[sprocket]]) + { + meatcar_modifiers.listAppend("+34% item"); + meatcar_modifiers.listAppend("olfact gnollish gearhead"); + } + + + meatcar_modifiers.listAppend("banish guard bugbear"); + + if (meatcar_modifiers.count() > 0) + meatcar_line += "|*" + ChecklistGenerateModifierSpan(meatcar_modifiers); + + meatcar_line += "|*Parts needed: " + missing_parts_list.listJoinComponents(", ", "and") + "."; + if (missing_parts[$item[tires]] || missing_parts[$item[empty meat tank]] || missing_parts[$item[cog]] || missing_parts[$item[spring]] || missing_parts[$item[sprocket]]) + meatcar_line += " (found in the degrassi knoll garage?)"; + } + subentry.entries.listAppend(meatcar_line); + + if (my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) + subentry.entries.listAppend("Or buy a desert bus pass. (5000 meat)"); + if ($item[pumpkin].available_amount() > 0) + subentry.entries.listAppend("Or build a pumpkin carriage."); + if ($items[can of Brütalbräu,can of Drooling Monk,can of Impetuous Scofflaw,fancy tin beer can].available_amount() > 0) + subentry.entries.listAppend("Or build a tin lizzie."); + url = "place.php?whichplace=knoll_hostile"; + } + else + { + url = "shop.php?whichshop=gnoll"; + int meatcar_price = $item[spring].npc_price() + $item[sprocket].npc_price() + $item[cog].npc_price() + $item[empty meat tank].npc_price() + 100 + $item[tires].npc_price() + $item[sweet rims].npc_price() + $item[spring].npc_price(); + subentry.entries.listAppend("Build a bitchin' meatcar. (" + meatcar_price + " meat)"); + } + + ChecklistEntry entry = ChecklistEntryMake("__item bitchin' meatcar", url, subentry, relevant_locations); + entry.tags.id = "Area unlock desert beach"; + if (optional) + optional_task_entries.listAppend(entry); + else + task_entries.listAppend(entry); + } + else if (!__misc_state["mysterious island available"] && __misc_state["in run"]) + { + ChecklistSubentry subentry; + subentry.header = "Unlock mysterious island"; + if (my_path().id == PATH_SEA) return; + if (my_path().id == PATH_COMMUNITY_SERVICE) + { + subentry.header += "?"; + subentry.entries.listAppend("Or not...?"); + } + + string url; + boolean suggest_hippy_alternative = false; + if (my_path().id == PATH_NUCLEAR_AUTUMN) + { + suggest_hippy_alternative = true; + } + + + if (!(my_path().id == PATH_NUCLEAR_AUTUMN && in_hardcore())) + { + if (__misc_state["desert beach available"]) + url = "place.php?whichplace=desertbeach"; + int scrip_number = $item[Shore Inc. Ship Trip Scrip].available_amount(); + int trips_needed = MAX(0, 3 - scrip_number); + + if ($item[dinghy plans].available_amount() > 0) + { + if ($item[dingy planks].available_amount() > 0) + { + url = "inventory.php?ftext=dinghy+plans"; + subentry.entries.listAppend("Use dinghy plans."); + } + else + { + if (my_path().id == PATH_NUCLEAR_AUTUMN) + { + subentry.entries.listAppend("Pull dingy planks, then build dinghy dinghy."); + } + else + { + url = "shop.php?whichshop=generalstore"; + subentry.entries.listAppend("Buy dingy planks, then build dinghy dinghy."); + } + } + + } + else if (trips_needed > 0) + { + int trip_adventure_cost = 3; + int trip_meat_cost = 500; + if (my_path().id == PATH_WAY_OF_THE_SURPRISING_FIST) + { + trip_adventure_cost = 5; + trip_meat_cost = 5; + } + string line_string = "Shore, " + (trip_adventure_cost * trips_needed) + " adventures"; + if (!__misc_state["desert beach available"]) + line_string += ", once the desert beach is unlocked"; + line_string += "."; + int meat_needed = trip_meat_cost * trips_needed; + if (my_meat() < meat_needed) + line_string += "|Need " + meat_needed + " meat for vacations, have " + my_meat() + "."; + subentry.entries.listAppend(line_string); + if ($item[skeleton].available_amount() > 0) + subentry.entries.listAppend("Skeletal skiff?"); + } + else + { + url = "shop.php?whichshop=shore"; + subentry.entries.listAppend("Redeem scrip at shore for dinghy plans."); + } + } + if (suggest_hippy_alternative) + { + string line_string = "Or try"; + if (my_path().id == PATH_NUCLEAR_AUTUMN && in_hardcore()) + line_string = "Try"; + line_string += " the hippy quest in the woods"; + if (my_basestat(my_primestat()) < 25) + line_string += ", once your mainstat reaches 25"; + else if (url == "") + url = "place.php?whichplace=woods"; + line_string += "."; + if (my_path().id == PATH_LOW_KEY_SUMMER) + line_string += " (need to go there anyway)"; + else if (my_path().id != PATH_NUCLEAR_AUTUMN) + line_string += " (probably slower?)"; + subentry.entries.listAppend(line_string); + } + if (my_path().id == PATH_NUCLEAR_AUTUMN && ($familiar[ms. puck man].familiar_is_usable() || $familiar[puck man].familiar_is_usable())) + { + string line = "Or build a yellow submarine."; + string [int] missing_components = $item[yellow submarine].missingComponentsToMakeItemInHumanReadableFormat(); + if (missing_components.count() > 0) + line += " Need " + missing_components.listJoinComponents(", ", "and") + "."; + subentry.entries.listAppend(line); + } + + if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && get_property("peteMotorbikeGasTank").length() == 0) + subentry.entries.listAppend("Possibly upgrade your motorcycle's gas tank. (extra-buoyant)"); + + + ChecklistEntry entry = ChecklistEntryMake("__item dingy dinghy", url, subentry, $locations[the shore\, inc. travel agency]); + entry.tags.id = "Area unlock mysterious island"; + if (my_path().id == PATH_COMMUNITY_SERVICE) + optional_task_entries.listAppend(entry); + else + task_entries.listAppend(entry); + + } +} + +RegisterTaskGenerationFunction("SPowerlevelGenerateTasks"); +void SPowerlevelGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (__misc_state["need to level"] && my_path().id != PATH_EXPLOSION) + { + string url = ""; + int mcd_max_limit = 10; + boolean have_mcd = false; + if (canadia_available() || knoll_available() || gnomads_available() && __misc_state["desert beach available"] || in_bad_moon()) + have_mcd = true; + if (canadia_available()) + { + mcd_max_limit = 11; + url = "place.php?whichplace=canadia&action=lc_mcd"; + } + else if (knoll_available()) + { + if ($item[detuned radio].available_amount() > 0) + url = "inventory.php?ftext=detuned+radio"; + else + url = "shop.php?whichshop=gnoll"; + } + else if (gnomads_available()) + url = "gnomes.php?place=machine"; + //FIXME URLs for the other ones + if (current_mcd() < mcd_max_limit && have_mcd && monster_level_adjustment() < 150 && !in_bad_moon() && !(my_path().id == PATH_G_LOVER && knoll_available())) + { + optional_task_entries.listAppend(ChecklistEntryMake("__item detuned radio", url, ChecklistSubentryMake("Set monster control device to " + mcd_max_limit, "", roundForOutput(mcd_max_limit * __misc_state_float["ML to mainstat multiplier"], 2) + " mainstats/turn")).ChecklistEntrySetIDTag("Powerlevel MCD ML")); + } + } + + if (__misc_state["need to level"] && my_path().id != PATH_COMMUNITY_SERVICE) + { + ChecklistSubentry subentry; + + int main_substats = my_basestat(my_primesubstat()); + int substats_remaining = substatsForLevel(my_level() + 1) - main_substats; + + subentry.header = "Level to " + (my_level() + 1); + + subentry.entries.listAppend("Gain " + pluralise(substats_remaining, "substat", "substats") + "."); + + string url = ""; + + boolean spooky_airport_unlocked = __misc_state["spooky airport available"]; + boolean stench_airport_unlocked = __misc_state["stench airport available"]; + + if (__misc_state["Chateau Mantegna available"] && __misc_state_int["free rests remaining"] > 0) + url = "place.php?whichplace=chateau"; + else if (stench_airport_unlocked && monster_level_adjustment() >= 150) + url = $location[Uncle Gator's Country Fun-Time Liquid Waste Sluice].getClickableURLForLocation(); + else if (spooky_airport_unlocked && ($effect[jungle juiced].have_effect() > 0 || ($item[jungle juice].available_amount() > 0 && availableDrunkenness() > 0 && __misc_state["can drink just about anything"]))) + url = $location[the deep dark jungle].getClickableURLForLocation(); + else if (__misc_state["Chateau Mantegna available"]) + url = "place.php?whichplace=chateau"; + else if (__misc_state["sleaze airport available"]) + url = $location[sloppy seconds diner].getClickableURLForLocation(); + else if (spooky_airport_unlocked) + url = $location[the deep dark jungle].getClickableURLForLocation(); + else if ($item[GameInformPowerDailyPro walkthru].available_amount() > 0) + url = $location[[DungeonFAQ - Level 1]].getClickableURLForLocation(); + else if (my_primestat() == $stat[muscle] && $location[the haunted billiards room].locationAvailable()) + url = $location[the haunted gallery].getClickableURLForLocation(); + else if (my_primestat() == $stat[mysticality] && $location[the haunted bedroom].locationAvailable()) + url = $location[the haunted bathroom].getClickableURLForLocation(); + else if (my_primestat() == $stat[moxie] && $location[the haunted bedroom].locationAvailable()) + url = $location[the haunted ballroom].getClickableURLForLocation(); + + + //133.33333333333333 meat per stat + int maximum_allowed_to_donate = 10000 * my_level(); + int cost_to_donate_for_level = ceil(substats_remaining.to_float() / 1.5) * 200.0; + int min_cost_to_donate_for_level = ceil(substats_remaining.to_float() / 2.0) * 200.0; + if (min_cost_to_donate_for_level <= my_meat() && min_cost_to_donate_for_level <= maximum_allowed_to_donate) + { + string statue_name = ""; + if (my_primestat() == $stat[muscle] && $item[boris's key].available_amount() > 0) + { + statue_name = "Boris"; + if (cost_to_donate_for_level < 2000 || cost_to_donate_for_level < my_meat() * 0.2) + url = "da.php?place=gate1"; + } + else if (my_primestat() == $stat[mysticality] && $item[jarlsberg's key].available_amount() > 0 && my_path().id != PATH_AVATAR_OF_JARLSBERG) + { + statue_name = "Jarlsberg"; + if (cost_to_donate_for_level < 2000 || cost_to_donate_for_level < my_meat() * 0.2) + url = "da.php?place=gate2"; + } + else if (my_primestat() == $stat[moxie] && $item[sneaky pete's key].available_amount() > 0 && my_path().id != PATH_AVATAR_OF_SNEAKY_PETE) + { + statue_name = "Sneaky Pete"; + if (cost_to_donate_for_level < 2000 || cost_to_donate_for_level < my_meat() * 0.2) + url = "da.php?place=gate3"; + } + + if (statue_name != "" && !(!in_ronin() && cost_to_donate_for_level > 20000)) + { + buffer line = "Possibly donate ".to_buffer(); + if (cost_to_donate_for_level == min_cost_to_donate_for_level) + line.append(cost_to_donate_for_level); + else + { + line.append(min_cost_to_donate_for_level); + line.append(" to "); + line.append(cost_to_donate_for_level); + } + line.append(" meat to the statue of "); + line.append(statue_name); + line.append("."); + subentry.entries.listAppend(line); + + } + } + + + + string image_name = "player character"; + + if (false) + { + //vertically less imposing: + //disabled for now - player avatars look better. well, sneaky pete's avatar looks better... + image_name = "mini-adventurer blank female"; + + string [class] class_images; + class_images[$class[seal clubber]] = "mini-adventurer seal clubber female"; + class_images[$class[turtle tamer]] = "mini-adventurer turtle tamer female"; + class_images[$class[pastamancer]] = "mini-adventurer pastamancer female"; + class_images[$class[sauceror]] = "mini-adventurer sauceror female"; + class_images[$class[disco bandit]] = "mini-adventurer disco bandit female"; + class_images[$class[accordion thief]] = "mini-adventurer accordion thief female"; + + if (class_images contains my_class()) + image_name = class_images[my_class()]; + } + + + task_entries.listAppend(ChecklistEntryMake(image_name, url, subentry, 11).ChecklistEntrySetIDTag("Powerlevel suggestions")); + } +} + +//FIXME this should be customizable. But an interface for that would be tricky... + +record PlantSuggestion +{ + location loc; + string plant_name; + string details; + + boolean no_stat_remove; //for +ML plants mainly +}; + +PlantSuggestion PlantSuggestionMake(location loc, string plant_name, string details) +{ + PlantSuggestion result; + result.loc = loc; + result.plant_name = plant_name; + result.details = details; + return result; +} + + +void listAppend(PlantSuggestion [int] list, PlantSuggestion entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + + +PlantSuggestion [int] __plants_suggested_locations; + +record Plant +{ + string name; + string image_lookup_name; //auto-generated + string zone_effect; + string terrain; + boolean territorial; +}; + +Plant PlantMake(string name, string zone_effect, string terrain, boolean territorial) +{ + Plant result; + result.name = name; + result.image_lookup_name = "Plant " + name; + result.zone_effect = zone_effect; + result.terrain = terrain; + result.territorial = territorial; + return result; +} +Plant [string] __plant_properties; +string [int] __plant_output_order; //MUST contain all plants + + +void finaliseSetUpFloristState() +{ + if (!__iotms_usable[$item[Order of the Green Thumb Order Form]]) + return; + + //Set up suggestions: + //We can have this as either plants keeping track of a bunch of locations, or locations keeping track of a bunch of plants. + //Keeping it the same as get_florist_plants makes it mentally easier to track, I guess. + + + __plant_properties["Rabid Dogwood"] = PlantMake("Rabid Dogwood", "+30 ML", "outdoor", true); + __plant_properties["Rutabeggar"] = PlantMake("Rutabeggar", "+25% item", "outdoor", true); + __plant_properties["Rad-ish Radish"] = PlantMake("Rad-ish Radish", "+5 moxie stats/fight", "outdoor", true); + + __plant_properties["War Lily"] = PlantMake("War Lily", "+30 ML", "indoor", true); + __plant_properties["Stealing Magnolia"] = PlantMake("Stealing Magnolia", "+25% item", "indoor", true); + __plant_properties["Canned Spinach"] = PlantMake("Canned Spinach", "+5 muscle stats/fight", "indoor", true); + + __plant_properties["Blustery Puffball"] = PlantMake("Blustery Puffball", "+30 ML", "underground", true); + __plant_properties["Horn of Plenty"] = PlantMake("Horn of Plenty", "+25% item", "underground", true); + __plant_properties["Wizard's Wig"] = PlantMake("Wizard's Wig", "+5 myst stats/fight", "underground", true); + __plant_properties["Shuffle Truffle"] = PlantMake("Shuffle Truffle", "+25% init", "underground", false); + + + __plant_output_order = split_string("Rabid Dogwood,Rutabeggar,Rad-ish Radish,Artichoker,Smoke-ra,Skunk Cabbage,Deadly Cinnamon,Celery Stalker,Lettuce Spray,Seltzer Watercress,War Lily,Stealing Magnolia,Canned Spinach,Impatiens,Spider Plant,Red Fern,BamBOO!,Arctic Moss,Aloe Guv'nor,Pitcher Plant,Blustery Puffball,Horn of Plenty,Wizard's Wig,Shuffle Truffle,Dis Lichen,Loose Morels,Foul Toadstool,Chillterelle,Portlybella,Max Headshroom,Spankton,Kelptomaniac,Crookweed,Electric Eelgrass,Duckweed,Orca Orchid,Sargassum,Sub-Sea Rose,Snori,Up Sea Daisy", ","); + + //Go through all potentials: + boolean [string] plants_used; + if (true) + { + string [int] internal_plants_used = split_string_alternate(get_property("_floristPlantsUsed"), ","); + foreach key in internal_plants_used + plants_used[internal_plants_used[key]] = true; + } + //Shuffle Truffle - underground, init: + if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"]) + { + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the defiled alcove], "Shuffle Truffle", "+2.5% modern zmobie")); + } + //Horn of Plenty - underground, +item: + if (__quest_state["Level 7"].state_boolean["nook needs speed tricks"] && $location[the defiled nook].item_drop_modifier_for_location() < 400.0) + { + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the defiled nook], "Horn of Plenty", "Evil eye, 20% drop.")); + } + if (!__quest_state["Level 11"].finished && $location[the middle chamber].item_drop_modifier_for_location() < 400.0) + { + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the middle chamber], "Horn of Plenty", "Tomb ratchets, 20% drop.")); + } + if (__quest_state["Level 4"].state_int["areas unlocked"] + $item[sonar-in-a-biscuit].available_amount() < 3) + { + string description = "Sonars-in-a-biscuit, 15% drop."; + if (!__quest_state["Level 7"].state_boolean["nook finished"]) //FIXME test if that plant is planted already + description += " Or ignore in favor of the defiled nook?"; + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the batrat and ratbat burrow], "Horn of Plenty", description)); + } + //Intentionally ignored: +item plants in the orchard. Normally you'd plant in the upper chamber instead, since both of these quests often happen on the same day? And there's three zones to plant in - way too complicated. + if (!__quest_state["Level 12"].finished && __misc_state["need to level"] && __quest_state["Level 12"].state_int["frat boys left on battlefield"] != 0 && __quest_state["Level 12"].state_int["hippies left on battlefield"] != 0) + { + location battlefield_zone = $location[the battlefield (hippy uniform)]; + if (__quest_state["Level 12"].state_int["frat boys left on battlefield"] > __quest_state["Level 12"].state_int["hippies left on battlefield"]) + battlefield_zone = $location[the battlefield (frat uniform)]; + if (my_primestat() == $stat[moxie]) + __plants_suggested_locations.listAppend(PlantSuggestionMake(battlefield_zone, "Rad-ish Radish", "")); + else + __plants_suggested_locations.listAppend(PlantSuggestionMake(battlefield_zone, "Rabid Dogwood", "")); + } + if (__misc_state["need to level mysticality"]) + { + //Wizard's Wig - underground, +5 myst stats/fight: + //in SC, can reach level 7 first, so ignore this one: + //if (!__quest_state["Level 4"].finished) + //__plants_suggested_locations.listAppend(PlantSuggestionMake($location[The Boss Bat's Lair], "Wizard's Wig", "")); + if (!__quest_state["Level 7"].state_boolean["niche finished"]) + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[The Defiled Niche], "Wizard's Wig", "")); + } + //Blustery Puffball - underground, +ML: + if (__quest_state["Level 7"].state_int["cranny evilness"] > 25 + 3) + { + PlantSuggestion ps = PlantSuggestionMake($location[the defiled cranny], "Blustery Puffball", "More beeps from swarm of ghuol whelps."); + ps.no_stat_remove = true; + __plants_suggested_locations.listAppend(ps); + } + //Canned Spinach - indoor, +5 muscle stats/fight: + if (my_primestat() == $stat[muscle] && __misc_state["need to level"]) + { + //castle? + if ($item[Spookyraven gallery key].available_amount() > 0 && !__misc_state["Stat gain from NCs reduced"]) + { + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the haunted gallery], "Canned Spinach", "While powerlevelling.")); + } + } + + //Stealing Magnolia - indoor, +item: + //War Lily - indoor, +ML: + if (__misc_state["need to level"]) + { + if ((my_path().id != PATH_PICKY || my_primestat() == $stat[moxie]) && $location[The Castle in the Clouds in the Sky (Ground Floor)].turnsAttemptedInLocation() < 11) //nightmare in picky + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[The castle in the clouds in the sky (ground floor)], "War Lily", "")); + //Haunted bedroom? + } + //Rad-ish Radish - outdoor, +5 moxie stats/fight: + if (__misc_state["need to level moxie"]) + { + //you wouldn't plant +30ML at airship - because oil peak may need it today. FIXME suggest if oil peak done/planted? HCO I guess? I dunno + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[The Spooky Forest], "Rad-ish Radish", "")); + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[The Penultimate Fantasy Airship], "Rad-ish Radish", "")); + } + //Rutabeggar - outdoor, +item: + if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0) + { + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[a-boo peak], "Rutabeggar", "A-boo clue, 15% drop.")); + } + + //Rabid Dogwood - outdoor, +ML: + if (__quest_state["Level 9"].state_float["oil peak pressure"] > 0 && monster_level_adjustment() < 100) + { + PlantSuggestion ps = PlantSuggestionMake($location[oil peak], "Rabid Dogwood", ""); + ps.no_stat_remove = true; + __plants_suggested_locations.listAppend(ps); + } + if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && __misc_state["need to level"]) //you spend a lot of turns in the desert + __plants_suggested_locations.listAppend(PlantSuggestionMake($location[the arid, extra-dry desert], "Rabid Dogwood", "")); + + //Now, go through results, and remove all plants that are already in that location: + + string [location][int] current_plants = get_florist_plants(); + boolean [location][string] current_plants_used; //inverse of current_plants, used for quick searching + foreach l in current_plants + { + foreach key in current_plants[l] + { + string plant = current_plants[l][key]; + current_plants_used[l][plant] = true; + } + } + + int [int] keys_removing; + foreach key in __plants_suggested_locations + { + PlantSuggestion suggestion = __plants_suggested_locations[key]; + + boolean should_remove = false; + if (current_plants_used[suggestion.loc][suggestion.plant_name] || plants_used[suggestion.plant_name]) + { + should_remove = true; + } + else + { + if (suggestion.plant_name == "Rad-ish Radish" || suggestion.plant_name == "Canned Spinach" || suggestion.plant_name == "Wizard's Wig") //+stat plants + { + boolean area_has_ml_plant = false; + if (current_plants_used[suggestion.loc]["Rabid Dogwood"]) + area_has_ml_plant = true; + if (current_plants_used[suggestion.loc]["War Lily"]) + area_has_ml_plant = true; + if (current_plants_used[suggestion.loc]["Blustery Puffball"]) + area_has_ml_plant = true; + if (area_has_ml_plant) + should_remove = true; + } + + //opposite: + if (suggestion.plant_name == "Rabid Dogwood" || suggestion.plant_name == "War Lily" || suggestion.plant_name == "Blustery Puffball") + { + boolean area_has_stat_plant = false; + if (current_plants_used[suggestion.loc]["Rad-ish Radish"]) + area_has_stat_plant = true; + if (current_plants_used[suggestion.loc]["Canned Spinach"]) + area_has_stat_plant = true; + if (current_plants_used[suggestion.loc]["Wizard's Wig"]) + area_has_stat_plant = true; + if (area_has_stat_plant && !suggestion.no_stat_remove) + should_remove = true; + } + + } + + if (should_remove) + keys_removing.listAppend(key); + } + foreach key in keys_removing + { + remove __plants_suggested_locations[keys_removing[key]]; + } +} + +void generateFloristFriar(Checklist [int] checklists) +{ + if (!__iotms_usable[$item[Order of the Green Thumb Order Form]]) + return; + if (!__misc_state["in run"]) //currently, these suggestions are in-run only + return; + ChecklistEntry [int] florist_entries; + + ChecklistSubentry [int] subentries; + foreach key in __plant_output_order + { + string plant_name = __plant_output_order[key]; + if (!(__plant_properties contains plant_name)) + continue; + Plant plant = __plant_properties[plant_name]; + + ChecklistSubentry subentry; + subentry.header = plant_name + ", " + plant.terrain; + subentry.modifiers.listAppend(plant.zone_effect); + + //See if we suggested this plant anywhere: + foreach key in __plants_suggested_locations + { + PlantSuggestion suggestion = __plants_suggested_locations[key]; + if (suggestion.plant_name == plant_name) + { + //we did + string suggestion_text = suggestion.loc; + if (suggestion.details != "") + suggestion_text += " (" + suggestion.details + ")"; + if (!locationAvailable(suggestion.loc)) + subentry.entries.listAppend(HTMLGenerateSpanOfClass(suggestion_text, "r_future_option")); + else + subentry.entries.listAppend(suggestion_text); + } + } + + string image_name = plant.image_lookup_name; + if (subentry.entries.count() > 0) + { + subentries.listAppend(subentry); + } + } + if (subentries.count() > 0) + { + florist_entries.listAppend(ChecklistEntryMake("plant up sea daisy", "place.php?whichplace=forestvillage&action=fv_friar", subentries).ChecklistEntrySetIDTag("Florist friar plant reminder")); + } + + checklists.listAppend(ChecklistMake("Florist Friar", florist_entries)); +} + +//Does not return colour formatting for elemental damage; will need to add that yourself. +string getPlantDescription(string plant_name) +{ + switch (plant_name) + { + case "Rabid Dogwood": + case "War Lily": + case "Blustery Puffball": + return "+30 ML"; + case "Rutabeggar": + case "Stealing Magnolia": + case "Horn of Plenty": + return "+25% item"; + case "Aloe Guv'nor": + return "HP regen"; + case "Artichoker": + return "delevel"; + case "Canned Spinach": + return "5 muscle/fight"; + case "Crookweed": + return "+60% meat"; + case "Dis Lichen": + return "delevel"; + case "Duckweed": + return "hiding"; + case "Electric Eelgrass": + return "block"; + case "Impatiens": + return "+25% init"; + case "Kelptomaniac": + return "+40% item"; + case "Lettuce Spray": + return "HP regen"; + case "Max Headshroom": + return "MP regen"; + case "Orca Orchid": + return "attack"; + case "Pitcher Plant": + return "MP regen"; + case "Portlybella": + return "HP regen"; + case "Rad-ish Radish": + return "5 moxie/fight"; + case "Red Fern": + return "delevel"; + case "Seltzer Watercress": + return "MP regen"; + case "Shuffle Truffle": + return "+25% init"; + case "Smoke-ra": + return "block"; + case "Snori": + return "HP/MP regen"; + case "Spankton": + return "delevel"; + case "Spider Plant": + return "poison"; + case "Up Sea Daisy": + return "30 stats/fight"; + case "Wizard's Wig": + return "5 myst/fight"; + case "Arctic Moss": + case "Sub-Sea Rose": + case "Chillterelle": + return "cold attack"; + case "Celery Stalker": + case "BamBOO!": + return "spooky attack"; + case "Deadly Cinnamon": + return "hot attack"; + case "Loose Morels": + return "sleaze attack"; + case "Sargassum": + case "Skunk Cabbage": + case "Foul Toadstool": + return "stench attack"; + } + return ""; +} + + +RegisterTaskGenerationFunction("SFloristGenerateTasks"); +void SFloristGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //Friar: + if (__iotms_usable[$item[Order of the Green Thumb Order Form]]) + { + string image_name = "sunflower face"; + ChecklistSubentry subentry; + subentry.header = "Plant florist plants in " + __last_adventure_location; + + PlantSuggestion [int] area_relevant_suggestions; + foreach key, suggestion in __plants_suggested_locations + { + + if (suggestion.loc != __last_adventure_location) + continue; + + area_relevant_suggestions.listAppend(suggestion); + } + + boolean single_mode_only = false; + if (area_relevant_suggestions.count() == 1) + { + single_mode_only = true; + PlantSuggestion suggestion = area_relevant_suggestions[0]; + string plant_name = suggestion.plant_name.capitaliseFirstLetter(); + + subentry.header = "Plant " + plant_name + " in " + __last_adventure_location; + } + + foreach key, suggestion in area_relevant_suggestions + { + string plant_name = suggestion.plant_name.capitaliseFirstLetter(); + Plant plant = __plant_properties[plant_name]; + + string line; + + if (single_mode_only) + { + line = plant.zone_effect + ", " + plant.terrain; + if (plant.territorial) + line = line + ", territorial"; + + if (suggestion.details != "") + line += "|*" + suggestion.details; + } + else + { + line = plant_name + " (" + plant.zone_effect + ", " + plant.terrain; + if (plant.territorial) + line = line + ", territorial"; + + line += ")"; + if (suggestion.details != "") + line += "|*" + suggestion.details; + } + + if (plant_name == "War Lily" || plant_name == "Rabid Dogwood" || plant_name == "Blustery Puffball") + { + if (monster_level_adjustment() + 30 > 150) + { + //subentry.header = "Optionally plant florist plants in " + __last_adventure_location; + image_name = "__item pirate fledges"; + + subentry.header += "?"; + line += "|" + HTMLGenerateSpanFont("Very dangerous", "red") + ", monsters "; + if (monster_level_adjustment() > 150) + line += "are"; + else + line += "will be"; + line += " stagger immune."; + } + } + + subentry.entries.listAppend(line); + } + if (subentry.entries.count() > 0) + task_entries.listAppend(ChecklistEntryMake(image_name, "place.php?whichplace=forestvillage&action=fv_friar", subentry, -11).ChecklistEntrySetIDTag("Florist friar plant suggestions")); + } +} + + +RegisterTaskGenerationFunction("SMiscTasksGenerateTasks"); +void SMiscTasksGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //From tasks.ash. May be able to split off some of these into their own files: + if (__misc_state["yellow ray available"] && __misc_state["in run"]) //not-in-run version in Familiars.ash (???) + { + string [int] potential_targets; + + if (!have_outfit_components("Filthy Hippy Disguise") && !(get_property("sidequestOrchardCompleted") == "hippy" || get_property("sidequestOrchardCompleted") == "fratboy")) + potential_targets.listAppend("Mysterious Island Hippy for outfit. (allows hippy store access; free redorant for +combat)"); + if (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues")) + potential_targets.listAppend("Hippy/frat war outfit?"); + //fax targets? + if (__misc_state["fax available"] || $skill[Rain Man].skill_is_usable()) + { + potential_targets.listAppend("Anything on the fax list."); + } + + if (!__quest_state["Level 10"].finished && $item[mohawk wig].available_amount() == 0 && (!lookupSkill("Comprehensive Cartography").skill_is_usable() || $item[model airship].available_amount() == 0) ) + potential_targets.listAppend("Burly Sidekick (Mohawk wig) - speed up top floor of castle."); + if (!__quest_state["Level 12"].state_boolean["Orchard Finished"]) + potential_targets.listAppend("Filthworms."); + + if (__quest_state["Boss Bat"].state_int["areas unlocked"] + $item[sonar-in-a-biscuit].available_amount() <3) + { + if ($item[enchanted bean].available_amount() == 0 && !__misc_state["beanstalk grown"]) + potential_targets.listAppend("Beanbat. (enchanted bean, sonar-in-a-biscuit)"); + else + potential_targets.listAppend("A bat. (sonar-in-a-biscuit)"); + } + + if (__misc_state["stench airport available"] && $item[filthy child leash].available_amount() == 0 && !__misc_state["familiars temporarily blocked"] && $items[ittah bittah hookah,astral pet sweater,snow suit,lead necklace].available_amount() == 0 && in_ronin() && my_path().id != PATH_HEAVY_RAINS && my_path().id != PATH_GELATINOUS_NOOB && my_path().id != PATH_G_LOVER) + { + potential_targets.listAppend("Horrible tourist family (barf mountain) - +5 familiar weight leash."); + } + + + if (item_drop_modifier_ignoring_plants() < 234.0 && !__misc_state["in aftercore"]) + potential_targets.listAppend("Anything with 30% drop if you can't 234%. (dwarf foreman, bob racecar, drum machines, etc)"); + + + if (__misc_state_string["yellow ray source"] == "Unleash Cowrruption" && $effect[Cowrruption].have_effect() == 0) + { + potential_targets.listAppend(HTMLGenerateSpanFont("Acquire cowrruption first.", "red")); + } + + optional_task_entries.listAppend(ChecklistEntryMake(__misc_state_string["yellow ray image name"], "", ChecklistSubentryMake("Fire yellow ray", "", potential_targets), 5).ChecklistEntrySetIDTag("Yellow ray suggestions")); + } + + if (__misc_state["in run"] && !have_mushroom_plot() && knoll_available() && __misc_state["can eat just about anything"] && fullness_limit() >= 4 && $item[spooky mushroom].available_amount() == 0 && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST && my_meat() >= 5000 && my_path().id != PATH_SLOW_AND_STEADY && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) + { + string [int] description; + description.listAppend("For spooky mushrooms, to cook a grue egg omelette. (epic food)|Will " + ((my_meat() < 5000) ? "need" : "cost") + " 5k meat. Plant a spooky spore."); + optional_task_entries.listAppend(ChecklistEntryMake("__item spooky mushroom", "knoll_mushrooms.php", ChecklistSubentryMake("Possibly plant a mushroom plot", "", description), 5).ChecklistEntrySetIDTag("Mushroom plot plant")); + + } + + if (!have_outfit_components("Filthy Hippy Disguise") && __misc_state["mysterious island available"] && __misc_state["in run"] && !__quest_state["Level 12"].finished && !__quest_state["Level 12"].state_boolean["War started"] && !have_outfit_components("Frat Warrior Fatigues") && my_path().id != PATH_EXPLOSION) + { + item [int] missing_pieces = missing_outfit_components("Filthy Hippy Disguise"); + + string [int] description; + string [int] modifiers; + boolean should_be_future_task = false; + + description.listAppend("Missing " + missing_pieces.listJoinComponents(", ", "and") + "."); + string next_line_intro = ""; + if (!__misc_state["yellow ray almost certainly impossible"]) + { + description.listAppend("Yellow-ray a hippy in the hippy camp if you can."); + next_line_intro = "Otherwise, "; + } + else if (my_level() < 9) + should_be_future_task = true; + + if (my_level() >= 9) + { + description.listAppend((next_line_intro + "run -combat " + (next_line_intro == "" ? " in the hippy camp" : "there") + ".").capitaliseFirstLetter()); + modifiers.listAppend("-combat"); + } + else + { + description.listAppend((next_line_intro + "wait for level 9 for the non-combats.").capitaliseFirstLetter()); + } + if ($familiar[slimeling].familiar_is_usable()) + modifiers.listAppend("slimeling?"); + + ChecklistEntry entry = ChecklistEntryMake("__item filthy knitted dread sack", "island.php", ChecklistSubentryMake("Acquire a filthy hippy disguise", modifiers, description), $locations[The Hippy Camp]); + entry.tags.id = "Filthy hippy disguise acquire"; + if (should_be_future_task) + future_task_entries.listAppend(entry); + else + optional_task_entries.listAppend(entry); + } + + if (__misc_state["in run"] && (inebriety_limit() == 0 || my_path().id == PATH_SLOW_AND_STEADY) && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) + { + string url = ""; + string [int] modifiers; + if (__misc_state["have hipster"] && get_property_int("_hipsterAdv") < 7) + { + modifiers.listAppend(__misc_state_string["hipster name"]); + } + string [int] description = listMake("At the end of the day, enter a combat, but don't finish it. Rollover will end it for you.", "This gives an extra chance to look for a non-combat."); + if (__quest_state["Level 3"].in_progress) + { + description.listAppend("Try using it to explore the typical tavern."); + url = "cellar.php"; + } + optional_task_entries.listAppend(ChecklistEntryMake("__item dead guy's watch", url, ChecklistSubentryMake("Use rollover runaway", modifiers, description), 8).ChecklistEntrySetIDTag("Rollover runaway suggestions")); + } + + //I'm not sure if you ever need a frat boy ensemble in-run, even if you're doing the hippy side on the war? If you need war hippy fatigues, the faster (?) way is acquire hippy outfit -> frat warrior fatigues -> start the war / use desert adventure for hippy fatigues. But if they're sure... + if (!have_outfit_components("Frat boy ensemble") && __misc_state["mysterious island available"] && __misc_state["in run"] && !__quest_state["Level 12"].finished && !__quest_state["Level 12"].started && $location[The Orcish Frat House].turnsAttemptedInLocation() >= 3 && ($location[The Orcish Frat House].combatTurnsAttemptedInLocation() > 0 || $location[The Orcish Frat House].noncombat_queue.contains_text("Sing This Explosion to Me") || $location[The Orcish Frat House].noncombat_queue.contains_text("Sing This Explosion to Me") || $location[The Orcish Frat House].noncombat_queue.contains_text("Murder by Death") || $location[The Orcish Frat House].noncombat_queue.contains_text("I Just Wanna Fly") || $location[The Orcish Frat House].noncombat_queue.contains_text("From Stoked to Smoked") || $location[The Orcish Frat House].noncombat_queue.contains_text("Purple Hazers"))) + { + //they don't have a frat boy ensemble, but they adventured in the pre-war frat house + //I'm assuming this means they want the outfit, for whatever reason. So, suggest it, until the level 12 starts: + item [int] missing_pieces = missing_outfit_components("Frat boy ensemble"); + + string [int] description; + string [int] modifiers; + description.listAppend("Missing " + missing_pieces.listJoinComponents(", ", "and") + "."); + if (my_level() >= 9) + { + modifiers.listAppend("-combat"); + description.listAppend("Run -combat."); + } + else + description.listAppend("Possibly wait until level 9, to unlock NCs in the area."); + optional_task_entries.listAppend(ChecklistEntryMake("__item orcish frat-paddle", "island.php", ChecklistSubentryMake("Acquire a frat boy ensemble?", modifiers, description), $locations[The Orcish Frat House]).ChecklistEntrySetIDTag("Frat boy ensemble acquire")); + } + + if ($item[strange leaflet].available_amount() > 0 && __misc_state["in run"] && !get_property_boolean("leafletCompleted")) + { + boolean leaflet_quest_probably_finished = false; + + if ($item[giant pinky ring].available_amount() > 0) //invalid in casual, but eh + leaflet_quest_probably_finished = true; + if ($item[Frobozz Real-Estate Company Instant House (TM)].available_amount() > 0 || __campground[$item[Frobozz Real-Estate Company Instant House (TM)]] > 0) + leaflet_quest_probably_finished = true; + + if (!leaflet_quest_probably_finished) + { + string [int] description; + boolean future_task = false; + description.listAppend("Quests Menu" + __html_right_arrow_character + "Leaflet (With Stats)"); + + if (__misc_state["need to level"]) + { + item relevant_lamp; + effect relevant_lamp_effect; + if (my_primestat() == $stat[muscle]) + { + relevant_lamp = $item[red LavaCo Lamp™]; + relevant_lamp_effect = $effect[Red Menace]; + } + else if (my_primestat() == $stat[mysticality]) + { + relevant_lamp = $item[blue LavaCo Lamp™]; + relevant_lamp_effect = $effect[Blue Eyed Devil]; + } + else if (my_primestat() == $stat[moxie]) + { + relevant_lamp = $item[green LavaCo Lamp™]; + relevant_lamp_effect = $effect[Green Peace]; + } + if (relevant_lamp != $item[none] && relevant_lamp_effect != $effect[none] && relevant_lamp.available_amount() > 0 && relevant_lamp_effect.have_effect() == 0) + { + future_task = true; + description.listAppend("Possibly wait until tomorrow. The " + relevant_lamp + " bonus will give extra stats."); + } + else if (relevant_lamp_effect.have_effect() > 0) + description.listAppend("Soon, before the lava lamp effect runs out."); + + item [int] items_equipping = generateEquipmentToEquipForExtraExperienceOnStat(my_primestat()); + if (items_equipping.count() > 0) + description.listAppend("Could equip " + items_equipping.listJoinComponents(", ", "or") + " for more stats."); + } + + ChecklistEntry entry = ChecklistEntryMake("__item strange leaflet", "", ChecklistSubentryMake("Strange leaflet quest", "", description)); + entry.tags.id = "Strange leaflet"; + if (future_task) + future_task_entries.listAppend(entry); + else + optional_task_entries.listAppend(entry); + } + } + + + + + + boolean have_spaghetti_breakfast = (($skill[spaghetti breakfast].skill_is_usable() && !get_property_boolean("_spaghettiBreakfast")) || $item[spaghetti breakfast].available_amount() > 0); + if (__misc_state["in run"] && __misc_state["can eat just about anything"] && !get_property_boolean("_spaghettiBreakfastEaten") && my_fullness() == 0 && have_spaghetti_breakfast && my_path().id != PATH_SLOW_AND_STEADY) + { + + string [int] adventure_gain; + adventure_gain[1] = "1"; + adventure_gain[2] = "1-2"; + adventure_gain[3] = "2"; + adventure_gain[4] = "2-3"; + adventure_gain[5] = "3"; + adventure_gain[6] = "3-4"; + adventure_gain[7] = "4"; + adventure_gain[8] = "4-5"; + adventure_gain[9] = "5"; + adventure_gain[10] = "5-6"; + adventure_gain[11] = "6"; + + string adventures_gained = adventure_gain[MAX(1, MIN(11, my_level()))]; + + string level_string = ""; + if (my_level() < 11) + level_string = " Gain levels for more."; + string url = "inventory.php?which=1"; + string [int] description; + description.listAppend("Inedible if you eat anything else.|" + adventures_gained + " adventures/fullness." + level_string); + if ($item[spaghetti breakfast].available_amount() == 0) + { + description.listAppend("Obtained by casting spaghetti breakfast."); + url = "skills.php"; + } + optional_task_entries.listAppend(ChecklistEntryMake("__item spaghetti breakfast", url, ChecklistSubentryMake("Eat " + $item[spaghetti breakfast] + " first", "", description), 8).ChecklistEntrySetIDTag("Spaghetti breakfast resource")); + } + + if (my_path().id != PATH_ACTUALLY_ED_THE_UNDYING && my_path().id != PATH_NUCLEAR_AUTUMN) + { + item upgraded_dwelling = $item[none]; + if ($item[Frobozz Real-Estate Company Instant House (TM)].available_amount() > 0 && (__campground[$item[big rock]] > 0 || __campground[$item[Newbiesport™ tent]] > 0 || __campground[$item[cottage]] > 0) && my_path().id != PATH_G_LOVER && my_path().id != PATH_BEES_HATE_YOU) + { + upgraded_dwelling = $item[Frobozz Real-Estate Company Instant House (TM)]; + } + else if ($item[Newbiesport™ tent].available_amount() > 0 && __campground[$item[big rock]] > 0 && my_path().id != PATH_G_LOVER) + { + upgraded_dwelling = $item[Newbiesport™ tent]; + } + if (upgraded_dwelling != $item[none]) + { + string [int] reasons; + reasons.listAppend("rollover"); + + if (__misc_state_int["total free rests possible"] > 0) + reasons.listAppend("free rests"); + + string description = "Better HP/MP restoration via " + reasons.listJoinComponents(", ", "and") + "."; + optional_task_entries.listAppend(ChecklistEntryMake("__item " + upgraded_dwelling, upgraded_dwelling.invSearch(), ChecklistSubentryMake("Use " + upgraded_dwelling, "", description), 8).ChecklistEntrySetIDTag("Campground dwelling uprgade")); + + } + } + + if (__misc_state["in run"] && $item[dry cleaning receipt].available_amount() > 0) + { + item receipt_item = $item[none]; + if (my_primestat() == $stat[muscle]) + receipt_item = $item[power sock]; + else if (my_primestat() == $stat[mysticality]) + receipt_item = $item[wool sock]; + else if (my_primestat() == $stat[moxie]) + receipt_item = $item[moustache sock]; + if (receipt_item != $item[none] && receipt_item.available_amount() == 0) + { + optional_task_entries.listAppend(ChecklistEntryMake("__item " + $item[dry cleaning receipt], "inventory.php?ftext=dry+cleaning+receipt", ChecklistSubentryMake("Use " + $item[dry cleaning receipt], "", "For " + receipt_item + " accessory."), 8).ChecklistEntrySetIDTag("Dry cleaning receipt resource")); + } + } +} + + +static +{ + boolean [item] __simple_candy = $items[1702, 1962, 4341, 913, 1652, 2942, 3455, 3449, 3454, 3453, 3452, 3451, 4152, 1501, 5455, 5478, 5476, 5477, 1344, 5188, 4340, 1161, 912, 4342, 5454, 2941, 1346, 4192, 1494, 5456, 617, 3496, 2734, 933, 908, 3450, 1783, 2088, 2576, 907, 1767, 906, 911, 540, 263, 909, 905, 5180, 2309, 300, 2307, 298, 1163, 2306, 299, 2305, 297, 2304, 2308, 5892, 6792, 5435, 7677, 7785]; + boolean [item] __complex_candy = lookupItems("5495,5496,5494,5458,5421,4851,2197,1382,4334,4333,5424,3269,5422,921,5425,5423,3091,2955,5416,5419,5418,5417,5420,5381,5319,5400,4330,4332,5406,5405,4818,5402,5318,5384,4331,5320,5382,5398,5401,5397,5317,5385,5321,5383,3290,3760,2193,5413,5459,5483,3584,5395,5396,5482,4256,5484,2943,4329,3054,4758,4163,4466,4464,4465,4462,4467,4463,4623,5157,4395,4394,4393,4518,5189,4151,5023,3428,3423,3424,5457,3425,5480,5474,5479,5473,5481,5475,4164,3631,4853,5414,5415,3046,5345,1345,5103,2220,4746,4389,3125,4744,4273,3422,1999,3426,4181,4180,4176,4183,4179,4191,4182,4178,4745,5526,6835,6852,6833,6834,6836,7499,7915,8257,7914,6837,8151,3124,8149,8154,7919,6840,5736,6831,7917,8150,6404,6841,6904,6903,7918,7710,6399,9146,8537,6405,6843,7474,6172,9252,5913];"); +} + + + +int synthesis_price(item it) +{ + if (!it.tradeable) + return 999999999; + int price = it.historical_price(); + if (price <= 0) + return 999999999; + return price; +} + +Record CandyCombination +{ + item candy_1; + item candy_2; +}; + +CandyCombination CandyCombinationMake(item candy_1, item candy_2) +{ + CandyCombination cc; + cc.candy_1 = candy_1; + cc.candy_2 = candy_2; + return cc; +} + +static +{ + CandyCombination [int][int][int] __candy_combination_cache; +} + +CandyCombination [int] calculateSweetSynthesisCandyCombinations(int tier, int subid) +{ + if (__candy_combination_cache[tier][subid].count() > 0) + return __candy_combination_cache[tier][subid]; + + CandyCombination [int] result; + boolean [item] candy_1; + boolean [item] candy_2; + + if (tier == 1) + { + candy_1 = __simple_candy; + candy_2 = __simple_candy; + } + else if (tier == 2) + { + candy_1 = __simple_candy; + candy_2 = __complex_candy; + } + else if (tier == 3) + { + candy_1 = __complex_candy; + candy_2 = __complex_candy; + } + foreach item_1 in candy_1 + { + int item_1_id = item_1.to_int(); + + foreach item_2 in candy_2 + { + int item_2_id = item_2.to_int(); + if ((item_1_id + item_2_id) % 5 != (subid - 1)) + continue; + result[result.count()] = CandyCombinationMake(item_1, item_2); + } + } + sort result by (value.candy_1.synthesis_price() + value.candy_2.synthesis_price()); + __candy_combination_cache[tier][subid] = result; + return result; +} + +static +{ + string [effect] __sweet_synthesis_buff_descriptions; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Hot]] = "+9 hot res"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Cold]] = "+9 cold res"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Pungent]] = "+9 stench res"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Scary]] = "+9 spooky res"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Greasy]] = "+9 sleaze res"; + + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Strong]] = "+300% muscle"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Smart]] = "+300% myst"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Cool]] = "+300% moxie"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Hardy]] = "+300% max HP"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Energy]] = "+300% max MP"; + + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Greed]] = "+300% meat"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Collection]] = "+150% item"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Movement]] = "+50% muscle gain"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Learning]] = "+50% myst gain"; + __sweet_synthesis_buff_descriptions[$effect[Synthesis: Style]] = "+50% moxie gain"; + + int [effect] __sweet_synthesis_buff_tiers; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Hot]] = 1; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Cold]] = 1; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Pungent]] = 1; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Scary]] = 1; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Greasy]] = 1; + + __sweet_synthesis_buff_tiers[$effect[Synthesis: Strong]] = 2; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Smart]] = 2; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Cool]] = 2; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Hardy]] = 2; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Energy]] = 2; + + __sweet_synthesis_buff_tiers[$effect[Synthesis: Greed]] = 3; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Collection]] = 3; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Movement]] = 3; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Learning]] = 3; + __sweet_synthesis_buff_tiers[$effect[Synthesis: Style]] = 3; + + int [effect] __sweet_synthesis_buff_subid; + __sweet_synthesis_buff_subid[$effect[Synthesis: Hot]] = 1; + __sweet_synthesis_buff_subid[$effect[Synthesis: Cold]] = 2; + __sweet_synthesis_buff_subid[$effect[Synthesis: Pungent]] = 3; + __sweet_synthesis_buff_subid[$effect[Synthesis: Scary]] = 4; + __sweet_synthesis_buff_subid[$effect[Synthesis: Greasy]] = 5; + + __sweet_synthesis_buff_subid[$effect[Synthesis: Strong]] = 1; + __sweet_synthesis_buff_subid[$effect[Synthesis: Smart]] = 2; + __sweet_synthesis_buff_subid[$effect[Synthesis: Cool]] = 3; + __sweet_synthesis_buff_subid[$effect[Synthesis: Hardy]] = 4; + __sweet_synthesis_buff_subid[$effect[Synthesis: Energy]] = 5; + + __sweet_synthesis_buff_subid[$effect[Synthesis: Greed]] = 1; + __sweet_synthesis_buff_subid[$effect[Synthesis: Collection]] = 2; + __sweet_synthesis_buff_subid[$effect[Synthesis: Movement]] = 3; + __sweet_synthesis_buff_subid[$effect[Synthesis: Learning]] = 4; + __sweet_synthesis_buff_subid[$effect[Synthesis: Style]] = 5; + + effect [int] __sweet_synthesis_buff_output_order; + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Greed]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Collection]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Movement]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Learning]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Style]); + + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Strong]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Smart]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Cool]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Hardy]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Energy]); + + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Hot]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Cold]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Pungent]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Scary]); + __sweet_synthesis_buff_output_order.listAppend($effect[Synthesis: Greasy]); +} + +RegisterResourceGenerationFunction("SSweetSynthesisGenerateResource"); +void SSweetSynthesisGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!$skill[Sweet Synthesis].skill_is_usable()) + return; + if (availableSpleen() == 0) + return; + + //Calculate potential combinations from inventory, if we're in-run. + //If we're in aftercore, suggest a cheap candy for each buff. Breath mints are forever, right? + + + //We only display a handful of combinations in-run, because honestly there's no room. + int setting_maximum_display_limit = 2; + + + string [int][int] table; + //table.listAppend(listMake(HTMLGenerateSpanOfClass("Effect", "r_bold"), HTMLGenerateSpanOfClass("Candies", "r_bold"))); + + int approximate_line_count = 0; + string [int] table_lines; + foreach key, e in __sweet_synthesis_buff_output_order + { + if (e == $effect[none]) + continue; + CandyCombination [int] combinations = calculateSweetSynthesisCandyCombinations(__sweet_synthesis_buff_tiers[e], __sweet_synthesis_buff_subid[e]); + + + //If we're in aftercore, show the cheapest combination. + //If we're in ronin, show all combinations we have components for. + CandyCombination [int] final_combinations; + //final_combinations = combinations; + if (in_ronin()) + { + //All we have enough for: + //int [int][item] combinations_seen; + + + /*item [int][int] second_stage_combinations; + //Sort on smaller list: + //Note that combinations is, like, 4426, 4371, 4450, 4465, 4489, 1919, 1952, 1913, 1890, 1862, 813, 790, 805, 832, and 856. + foreach key in combinations + { + item item_1 = combinations[key][0]; + + if (item_1.available_amount() + item_1.closet_amount() == 0) + continue; + item item_2 = combinations[key][1]; + if (item_2.available_amount() + item_2.closet_amount() == 0) + continue; + //if (!(item_1.available_amount() + item_1.closet_amount() > 0 && item_2.available_amount() + item_2.closet_amount() > 0 && !(item_1 == item_2 && item_1.available_amount() < 2))) + if (item_1 == item_2 && item_1.available_amount() + item_1.closet_amount() < 2) + continue; + second_stage_combinations.listAppend(combinations[key]); + } + sort second_stage_combinations by (value[0].synthesis_price() + value[1].synthesis_price()); //fast reject - we'll stop running once we reach the display limit + */ + boolean [string] combinations_seen_json; + foreach key, cc in combinations + { + if (final_combinations.count() >= setting_maximum_display_limit + 1) + break; + //So, using item_amount() is three times faster than available_amount(), even though it ignores a bunch of stuff. Which is a difference of 0.3 seconds vs 0.1 seconds. + if (cc.candy_1.item_amount() + cc.candy_1.closet_amount() == 0) + continue; + if (cc.candy_2.item_amount() + cc.candy_2.closet_amount() == 0) + continue; + if (cc.candy_1 == cc.candy_2 && cc.candy_1.item_amount() + cc.candy_1.closet_amount() < 2) + continue; + + //if (!(item_1.available_amount() + item_1.closet_amount() > 0 && item_2.available_amount() + item_2.closet_amount() > 0 && !(item_1 == item_2 && item_1.available_amount() < 2))) + //continue; + int [item] combination_presence; + combination_presence[cc.candy_1] += 1; + combination_presence[cc.candy_2] += 1; + //Use a JSON to discover if we've seen this combination before. Seems to be the fastest way to check if we've seen a map before? + //It shouldn't be too slow... right? Right? + string presence_json = combination_presence.to_json(); + boolean already_seen = (combinations_seen_json contains presence_json); + //Have we seen this particular combination yet? + //Lovely slow O(N^2) algorithm: + /*foreach key in combinations_seen + { + boolean identical = true; + foreach it, amount in combinations_seen[key] + { + if (combination_presence[it] != amount) + { + identical = false; + break; + } + } + if (identical) + { + already_seen = true; + break; + } + }*/ + if (already_seen) + { + continue; + } + + + final_combinations[final_combinations.count()] = cc; + //combinations_seen[combinations_seen.count()] = combination_presence; + combinations_seen_json[presence_json] = true; + } + } + else + { + //Find cheapest: + //This is already pre-sorted. + final_combinations[final_combinations.count()] = combinations[0]; + } + if (final_combinations.count() > 0) + { + buffer line; + foreach key in final_combinations + { + if (key >= setting_maximum_display_limit) //unrealistic to show that many + { + line.append("
[...]"); + break; + } + approximate_line_count += 1; + if (line.length() != 0) + line.append("
"); + line.append(final_combinations[key].candy_1); + line.append(" + "); + line.append(final_combinations[key].candy_2); + } + table_lines.listAppend(HTMLGenerateSpanOfClass(__sweet_synthesis_buff_descriptions[e], "r_bold") + "
" + HTMLGenerateSpanOfStyle(line, "font-size:0.8em;color:#333333")); + //table.listAppend(listMake(__sweet_synthesis_buff_descriptions[e], line)); + } + } + + if (table_lines.count() == 0) + return; + + string [int] building_line; + foreach key in table_lines + { + building_line.listAppend(table_lines[key]); + if (key % 2 == 1) + { + table.listAppend(building_line); + building_line = listMakeBlankString(); + } + } + if (building_line.count() > 0) + table.listAppend(building_line); + int estimated_margin = approximate_line_count * 1.2; + + ChecklistSubentry subentry = ChecklistSubentryMake("Sweet Synthesis Buff", "30 turns", "Costs one spleen and two candies."); + //ChecklistSubentry subentry = ChecklistSubentryMake("Sweet Synthesis Buff", "30 turns", HTMLGenerateSpanOfClass(HTMLGenerateTagWrap("span", table.HTMLGenerateSimpleTableLines(false), mapMake("class", "r_tooltip_inner_class r_tooltip_inner_class_margin", "style", "margin-top:-" + estimated_margin + "em;margin-left:-5em;")) + "Costs one spleen and two candies.", "r_tooltip_outer_class")); + ChecklistEntry entry = ChecklistEntryMake("__skill Sweet Synthesis", "runskillz.php?action=Skillz&whichskill=166&targetplayer=" + my_id() + "&pwd=" + my_hash() + "&quantity=1", subentry, 10); + entry.tags.id = "Sweet synthesis skill"; + entry.subentries_on_mouse_over.listAppend(ChecklistSubentryMake("Sweet Synthesis Buff", "30 turns", table.HTMLGenerateSimpleTableLines(false))); + + resource_entries.listAppend(entry); +} + +RegisterTaskGenerationFunction("SBuffUpkeepGenerateTasks"); +void SBuffUpkeepGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //Least-effort (basically a copy-paste from my ascension script), needs examining: + if (!__misc_state["in run"]) + return; + if (my_meat() < 1000) return; //save + skill [int] skills_want_running; + int [skill] minimum_meat_for_skill; + + skills_want_running.listAppend($skill[iron palm technique]); + + if (in_bad_moon() && my_mp() >= 1) + { + if (my_class() == $class[disco bandit]) + skills_want_running.listAppend($skill[disco aerobics]); + } + if (!__misc_state["familiars temporarily blocked"] && my_familiar() != $familiar[none]) + { + skills_want_running.listAppend($skill[leash of linguini]); + skills_want_running.listAppend($skill[empathy of the newt]); + } + if (get_property("peteMotorbikeMuffler").length() == 0) + skills_want_running.listAppend($skill[rev engine]); + if (my_primestat() == $stat[mysticality] && my_hp() < 500) + { + if ($item[turtle totem].available_amount() > 0) + { + skills_want_running.listAppend($skill[reptilian fortitude]); + skills_want_running.listAppend($skill[astral shell]); + skills_want_running.listAppend($skill[ghostly shell]); + } + } + boolean have_facial_expression = false; + foreach s in $skills[Arched Eyebrow of the Archmage,Disco Leer,Disco Smirk,Icy Glare,Knowing Smile,Patient Smile,Scowl of the Auk,Snarl of the Timberwolf,Stiff Upper Lip,Suspicious Gaze,Wizard Squint,Wry Smile] + { + if (s == $skill[suspicious gaze] && get_property_int("cyrptAlcoveEvilness") <= 26 && QuestState("questL07Cyrptic").started) //only need suspicious gaze there + continue; + if (s.to_effect().have_effect() > 0) + have_facial_expression = true; + } + if (lookupSkill("Inscrutable Gaze").to_effect().have_effect() > 0) + have_facial_expression = true; + + if (__misc_state["need to level"] && !have_facial_expression) + { + if (my_primestat() == $stat[mysticality]) + skills_want_running.listAppend($skill[Wry Smile]); + else if (my_primestat() == $stat[moxie]) + skills_want_running.listAppend($skill[knowing smile]); + else if (my_primestat() == $stat[muscle]) + skills_want_running.listAppend($skill[Patient Smile]); + } + + //UNDYING! + if (my_level() >= 3) + skills_want_running.listAppend($skill[Purr of the Feline]); + skills_want_running.listAppend($skill[Prayer of Seshat]); + if (__misc_state["need to level"]) + skills_want_running.listAppend($skill[Blessing of Serqet]); + skills_want_running.listAppend($skill[Hide of Sobek]); + if (!in_hardcore()) + skills_want_running.listAppend($skill[Bounty of Renenutet]); + skills_want_running.listAppend($skill[Power of Heka]); + skills_want_running.listAppend($skill[Wisdom of Thoth]); + if (my_primestat() == $stat[mysticality] && my_level() < 13) + skills_want_running.listAppend(lookupSkill("Inscrutable Gaze")); + + + + minimum_meat_for_skill[$skill[The Magical Mojomuscular Melody]] = 100; + minimum_meat_for_skill[$skill[blessing of serqet]] = 500; + minimum_meat_for_skill[$skill[Prayer of Seshat]] = 500; + minimum_meat_for_skill[$skill[Power of Heka]] = 500; + minimum_meat_for_skill[$skill[Purr of the Feline]] = 500; + minimum_meat_for_skill[$skill[leash of linguini]] = 2000; + minimum_meat_for_skill[$skill[empathy of the newt]] = 3000; + foreach s in $skills[ur-kel's aria of annoyance,drescher's annoying noise,pride of the puffin] + minimum_meat_for_skill[s] = 2000; + + + skill [int] final_skills; + foreach key, s in skills_want_running + { + if (!s.skill_is_usable() || !s.is_unrestricted()) + continue; + effect e = s.to_effect(); + if (e == $effect[none]) + continue; + if (e.have_effect() > 1) + continue; + if (my_maxmp() < s.mp_cost()) + continue; + final_skills.listAppend(s); + } + if (final_skills.count() > 0) + { + optional_task_entries.listAppend(ChecklistEntryMake("__skill " + final_skills[0], "skillz.php", ChecklistSubentryMake("Upkeep buffs", "", "Cast " + final_skills.listJoinComponents(", ", "and") + ".")).ChecklistEntrySetIDTag("Buff upkeep suggestions")); + } +} + + +void SLevel13DoorGenerateMissingItems(ChecklistEntry [int] tower_door_entries) +{ + if (__quest_state["Level 13"].state_boolean["past keys"]) return; + + if ($item[skeleton key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["skeleton key used"]) { + string line = "loose teeth (" + ($item[loose teeth].available_amount() == 0 ? "need" : "have") + ")"; + line += " + skeleton bone (" + ($item[skeleton bone].available_amount() == 0 ? "need" : "have") + ")"; + tower_door_entries.listAppend(ChecklistEntryMake("__item skeleton key", $location[the defiled nook].getClickableURLForLocation(), ChecklistSubentryMake("Skeleton key", "", line)).ChecklistEntrySetIDTag("Council L13 tower door skeleton key")); + } + + Q8bitRealmGenerateMissingItems(tower_door_entries); + + SDailyDungeonGenerateMissingItems(tower_door_entries); + + QHitsGenerateMissingItems(tower_door_entries); +} + +RegisterTaskGenerationFunction("SMonorailStationGenerateTasks"); +void SMonorailStationGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (in_bad_moon()) return; // No Breakfast Counter in Bad Moon + + if (__misc_state["can eat just about anything"] && get_property("muffinOnOrder") == "earthenware muffin tin") + task_entries.listAppend(ChecklistEntryMake("__item earthenware muffin tin", "place.php?whichplace=monorail&action=monorail_downtown", ChecklistSubentryMake("Get your muffin tin back", "", "Vist the monorail's breakfast counter"), -11).ChecklistEntrySetIDTag("Monorail get muffin tin")); + + if (get_property_boolean("_muffinOrderedToday") || get_property("muffinOnOrder") == "earthenware muffin tin") + return; + + item order = get_property("muffinOnOrder").lookupItem(); + if (order != $item[none]) { + task_entries.listAppend(ChecklistEntryMake("__item " + order.to_string(), "place.php?whichplace=monorail&action=monorail_downtown", ChecklistSubentryMake("Go grab your " + order.to_string()), -11).ChecklistEntrySetIDTag("Monorail muffin resource")); + } + else if (lookupItem("earthenware muffin tin").available_amount() > 0 && __misc_state["in run"]) { + optional_task_entries.listAppend(ChecklistEntryMake("__item earthenware muffin tin", "place.php?whichplace=monorail", ChecklistSubentryMake("Order a new muffin"), 5).ChecklistEntrySetIDTag("Monorail muffin resource")); + } +} +// STEPS TO HAVE NC FORCERS IN TILES +// This will require quite a few things. In order: +// - we will need to have a way for tourguide to tell that you have an NC forcer up for supernag +// - we will need to have a tile that shows good NCs to force +// - we will need to append NC forcers available to this + +// SYNTAX FOR NEW NC FORCERS +// In order to centralize, all NC forcers that were old were placed in this file. They utilize a +// new record type that should make it mildly easier to loop through the lot. + + record SneakSource { + string sourceName; + string url; + string imageLookupName; + boolean sneakCondition; + int sneakCount; + string tileDescription; + }; + +RegisterResourceGenerationFunction("SocialDistanceGenerator"); +void SocialDistanceGenerator(ChecklistEntry [int] resource_entries) +{ + // Saving some useful variables for use in the calculations. + int spleenRemaining = spleen_limit() - my_spleen_use(); + int stomachLeft = availableFullness(); + + SneakSource getSneakisol() { + SneakSource final; + + final.sourceName = "sneakisol"; + final.url = "main.php?eowkeeper=1"; + final.imageLookupName = "__item Eight Days a Week Pill Keeper"; + + // see # of free pillkeeepers remaining + int freeSneakLeft = get_property_boolean("_freePillKeeperUsed") ? 0 : 1; + + // calculate possible spleen-based sneaks + int spleenSneaks = floor(spleenRemaining / 3); + + // usable if we have pill keeper plus free sneaks or spleen sneaks available + final.sneakCondition = __iotms_usable[lookupItem("Eight Days a Week Pill Keeper")] && (freeSneakLeft + spleenSneaks > 0); + + // never noticed I didn't explicitly say this was pillkeeper in the tile lol + final.sneakCount = freeSneakLeft + spleenSneaks; + final.tileDescription = get_property_boolean("_freePillKeeperUsed") ? "" : `1x PillKeeper free sneak, `; + final.tileDescription = final.tileDescription + `{spleenSneaks}x sneaks for 3 spleen each`; + return final; + } + + SneakSource getStenchJellies() { + SneakSource final; + + final.sourceName = "stench jelly"; + final.url = ""; + final.imageLookupName = "__familiar space jellyfish"; + + // You can get more than 3 in a run, but 3 is a good fairway estimate. + int likelyJellies = 3; + + // Check if the familiar is usable & you have jellies in your inventory + boolean canUseJellyfish = $familiar[space jellyfish].familiar_is_usable(); + int jellyCount = $item[stench jelly].available_amount(); + int toastCount = $item[toast with stench jelly].available_amount(); + + // Check that you don't have full organs + int numberOfJelliesConsumable = min(stomachLeft + spleenRemaining, jellyCount + toastCount); + + // Compare current extractions to the likelyJellies variable + int currentExtractions = get_property_int("_spaceJellyfishDrops"); + int plausibleJellies = max(currentExtractions - likelyJellies, numberOfJelliesConsumable); + + // This is an or because it's possible to pull a stench jelly + final.sneakCondition = canUseJellyfish || plausibleJellies > 0; + + // Use plauisible jellies here, to make sure it's added if it's possible + final.sneakCount = plausibleJellies; + final.tileDescription = `{plausibleJellies}x stench jellies (have {clampi(toastCount,0,15)} on toast, {clampi(jellyCount,0,15)} as jelly)`; + return final; + } + + SneakSource getSpikos() { + SneakSource final; + + final.sourceName = 'spikolodon spikes'; + final.url = 'inventory.php?action=jparka'; + final.imageLookupName = "__item jurassic parka"; + + int spikosLeft = clampi(5 - get_property_int("_spikolodonSpikeUses"), 0, 5); + + final.sneakCondition = __iotms_usable[$item[Jurassic Parka]]; + final.sneakCount = spikosLeft; + final.tileDescription = `{spikosLeft}x spikolodon spikes left`; + return final; + + } + + SneakSource getClaras() { + SneakSource final; + + final.sourceName = `clara's bell`; + final.url = ''; + final.imageLookupName = "__item clara's bell"; + + final.sneakCondition = $item[clara's bell].available_amount() > 0 && !get_property_boolean("_claraBellUsed"); + final.sneakCount = get_property_boolean("_claraBellUsed") ? 0 : 1; + final.tileDescription = `{final.sneakCount}x clara's bell charge left`; + + return final; + } + + SneakSource getCinchos() { + SneakSource final; + + final.sourceName = `fiesta exits`; + final.url = ''; + final.imageLookupName = "__skill Cincho: Fiesta Exit"; + final.sneakCondition = __iotms_usable[$item[Cincho de Mayo]]; + + // _cinchUsed is a weird preference that actually means distance from 100% you are at in your current cinch. + + int freeRests = __misc_state_int["total free rests possible"]; + int cinchoRests = get_property_int('_cinchoRests'); + int cinchUsed = get_property_int('_cinchUsed'); + + // Resting when Cincho is full might burn some of the Cincho rests + int freeRestsRemaining = __misc_state_int["free rests remaining"]; + freeRests = min(freeRests, cinchoRests + freeRestsRemaining); + + // Calculating total available cinch + + int [int] cinchLevels = listMake(30,30,30,30,30,25,20,15,10,5); + + // Since the pref is weird, this tells you your current total cinch + int totalCinch = 100 - cinchUsed; + int rest = cinchoRests; + + // This while loop expands your possible cinch starting at rests you haven't used. + while (rest < freeRests) + { + int cinchAmount = rest >= count(cinchLevels) ? 5 : cinchLevels[rest]; + totalCinch += cinchAmount; + rest += 1; + } + + int possibleFiestaExits = floor(totalCinch/60); + + final.sneakCount = possibleFiestaExits; + final.tileDescription = `{possibleFiestaExits}x fiesta exits, with {totalCinch % 60} leftover cinch`; + return final; + } + + // Having generated these, we now get to generate a tile that combines them. + + SneakSource [string] sneakSources; + + sneakSources["cinco"] = getCinchos(); + sneakSources["spiko"] = getSpikos(); + sneakSources["jello"] = getStenchJellies(); + sneakSources["pillo"] = getSneakisol(); + sneakSources["claro"] = getClaras(); + + // Making it use the order we want; almost most recent to oldest, but pills on the bottom. + string [int] sneakOrder = listMake("cinco","spiko","jello","claro","pillo"); + + ChecklistEntry entry; + + entry.url = ""; + entry.image_lookup_name = "__effect Feeling Sneaky"; + entry.tags.id = "Sneak sources available"; + entry.importance_level = -2; + + string [int] description; + int totalSneaks = 0; + + string line = HTMLGenerateSpanOfClass("Force an NC with sneaky tricks!", "r_bold r_element_stench_desaturated"); + + foreach it, sneakType in sneakOrder + { + SneakSource sneaker = sneakSources[sneakType]; + if (sneaker.sneakCount > 0 && sneaker.sneakCondition) { + totalSneaks += sneaker.sneakCount; + entry.url = sneaker.url; + + line += "|*"+sneaker.tileDescription; + } + + } + + if (totalSneaks == 0) return; + + // Append all the lines to a description + description.listAppend(line); + + // Store the base description within the mouseover subentries + entry.subentries_on_mouse_over.listAppend(ChecklistSubentryMake(pluralise(totalSneaks, "sneak usable", "sneaks usable"), "", description)); + + // Add a description that falls away when you hoverover + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(totalSneaks, "sneak usable", "sneaks usable"), "", description)); + + // OK, now we're going to make a big table with the NC recommendations. Yeesh. + // This tile is complicated, dude! First, start by initializing variables. + // Ezan's table creators are formatted as string[int][int], where the first + // is the row and the second is the column... I think? + + int totalNCsRemaining = 0; + string [int][int] table; + + // In the synth tile, Ezan populates table_lines and builds out from there. I + // am doing the same because I don't fully understand the syntax. + string [int] tableLines; + + // This is a function that generates the right format for the table. Basically, + // it ingests the table title + a separated list of all sneak opportunities in + // that summarized title. + string populateSneakTable(string title, string [int] desc) { + string finalDesc = ""; + + // If nothing got added, just add an "all done!" to make the user feel better + if (desc.count() == 0) finalDesc = "All done!"; + + // Have to add line breaks here. + foreach k, d in desc { + finalDesc += d+"
"; + } + + // Finally, generate a little sub-tile that looks like this: + + // NAME OF SNEAKS + // 1 sneaksource + // 1 sneaksource + + // Where the name is bold and the sneaksources are tiny. In some future world, + // it might be nice to have coloring that grays those that are not available + // yet, but that is too much for this first implementation. + return HTMLGenerateSpanOfClass(title, "r_bold") + "
" + HTMLGenerateSpanOfStyle(finalDesc, "font-size:0.8em"); + } + + // We aren't going to do a loop here; we're just going to populate table_lines + // semi-manually, using logic that is roughly correct in each case. + + // START = DELAY SNEAKS + // 1x hidden apartment + // 1x hidden office + + // Initialize your string-int array of the sneaks. + string [int] sneakDelay; + + // You want to use prefs when possible to isolate that the user can use that sneak, then append to sneakDelay + if (get_property_int("hiddenApartmentProgress") < 7) sneakDelay.listAppend("1 hidden apartment"); + if (get_property_int("hiddenOfficeProgress") < 7) sneakDelay.listAppend("1 hidden office"); + + // Populate the sneaky table. + tableLines[1] = populateSneakTable("Delay Zones", sneakDelay); + + // Add the detected NCs to your total NCs remaining. + totalNCsRemaining += sneakDelay.count(); + + // NEXT = 95% COMBAT SNEAKS + // 12x friars NCs (-1 w/ carto) + // 1x castle basement + // 1x castle top + + string [int] sneak95; + + // Ripping some code from the friars tile to count NCs encountered. First, names of the relevant NCs. + boolean [string] necks_known_ncs = $strings[How Do We Do It? Quaint and Curious Volume!,Strike One!,Olive My Love To You\, Oh.,Dodecahedrariffic!]; + boolean [string] heart_known_ncs = $strings[Moon Over the Dark Heart,Running the Lode,I\, Martin,Imp Be Nimble\, Imp Be Quick]; + boolean [string] elbow_known_ncs = $strings[Deep Imp Act,Imp Art\, Some Wisdom,A Secret\, But Not the Secret You're Looking For,Butter Knife? I'll Take the Knife]; + + // Then, a tiny function to count the NCs found by zone for friars. + int countFriarNCs(boolean [string] known_ncs, location place) { + int ncs_found = 0; + + if (known_ncs.count() > 0) { + string [int] location_ncs = place.locationSeenNoncombats(); + + foreach key, s in location_ncs + { + if (known_ncs contains s) ncs_found += 1; + } + } + + return ncs_found; + + } + + // You can remove one from the needed NCs if they have carto in their run. + int cartoAdjustment = lookupSkill("Comprehensive Cartography").have_skill() ? 1 : 0; + + // Right now I think the raw logic off; I noted in the discord that we are having some small issues with + // it showing extra NCs in a few places. Not really sure what's up with that? An easy fix is to + // just set all of these to 0 in the event that questL06Friar = 'finished' -- I've implemented + // this fix, but I do think it's worth solving this at some point. + + int questPropMin = get_property('questL06Friar') == 'finished' ? 0 : 4; + + int necksNCsLeft = min(4 - countFriarNCs(necks_known_ncs, $location[The Dark Neck of the Woods]) - cartoAdjustment, questPropMin); + int heartNCsLeft = min(4 - countFriarNCs(heart_known_ncs, $location[The Dark Heart of the Woods]), questPropMin); + int elbowNCsLeft = min(4 - countFriarNCs(elbow_known_ncs, $location[The Dark Elbow of the Woods]), questPropMin); + + // Also correcting total NCs left here; we are using a "count" for this, and thus we only get 1 + // out of however many NCs actually are left in these zones, because it just counts the elements + // in the list rather than the # prepending the element in the list. + if (necksNCsLeft > 0) { + sneak95.listAppend(`{necksNCsLeft} Dark Neck`); + totalNCsRemaining += necksNCsLeft-1; + } + if (heartNCsLeft > 0) { + sneak95.listAppend(`{heartNCsLeft} Dark Heart`); + totalNCsRemaining += heartNCsLeft-1; + } + if (elbowNCsLeft > 0) { + sneak95.listAppend(`{elbowNCsLeft} Dark Elbow`); + totalNCsRemaining += elbowNCsLeft-1; + } + + // If the pref is any of these, you can still sneak the basement. + boolean [string] canSneakBasement = $strings[unstarted,started,step1,step2,step3,step4,step5,step6,step7]; + + if (canSneakBasement contains get_property("questL10Garbage")) sneak95.listAppend("1 castle basement"); + + // If the quest is unfinished, you can sneak the top floor. + if (get_property("questL10Garbage")!= "finished") sneak95.listAppend("1 castle top floor"); + + tableLines[2] = populateSneakTable("95% Combat", sneak95); + + totalNCsRemaining += sneak95.count(); + + // NEXT = 90% COMBAT SNEAKS + // 1x spookyraven bedroom + // 1x spookyraven bathroom + + string [int] sneak90; + + // I don't really think I need to import this but I'm tired and copy/pasting logic from the spookyraven tile seems fine. + QuestState dance_quest_state; + QuestStateParseMafiaQuestProperty(dance_quest_state, "questM21Dance"); + if ($item[Lady Spookyraven's powder puff].available_amount() == 0 && dance_quest_state.mafia_internal_step < 4) sneak90.listAppend("1 spookyraven bathroom"); + if ($item[Lady Spookyraven's dancing shoes].available_amount() == 0 && dance_quest_state.mafia_internal_step < 4) sneak90.listAppend("1 spookyraven gallery"); + + tableLines[3] = populateSneakTable("90% Combat", sneak90); + + totalNCsRemaining += sneak90.count(); + + // Here is how Ezan built the lines into a table. It's kind of cute. First, make a placeholder "builder" line. + string [int] building_line; + foreach key in tableLines + { + // For each key, you append it to the empty building lines. + building_line.listAppend(tableLines[key]); + + // However, if the key is even, you append to the table. This works, because you are appending a two-element + // item into the table, so it creates a string [int] that creates a row in the table. + if (key % 2 == 1) + { + table.listAppend(building_line); + + // Then, you clear out the building line, to reset the next table row + building_line = listMakeBlankString(); + } + } + // Then, at the end, you append the remainder to the table. + if (building_line.count() > 0) + table.listAppend(building_line); + + // Having done this, you now append the NCs remaining subentry to the end of the core entry, with an on_mouse_over bit as well. + + // However, I am going to be lazy, and not append either of these in the event the user is in CS/GG. + if (my_path().id != PATH_COMMUNITY_SERVICE && my_path().id != PATH_GREY_GOO) { + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(totalNCsRemaining, "NC remaining","NCs remaining"), "", HTMLGenerateSpanOfClass("Mouse over for the best sneaks!", "r_bold r_element_spooky_desaturated"))); + entry.subentries_on_mouse_over.listAppend(ChecklistSubentryMake(pluralise(totalNCsRemaining, "NC remaining","NCs remaining"), "", table.HTMLGenerateSimpleTableLines(false))); + } + + if (entry.subentries.count() > 0) resource_entries.listAppend(entry); + +} + +RegisterTaskGenerationFunction("SneakActiveTask"); +void SneakActiveTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // Use the new preference to tell if there's an NC forcer active + if (!get_property_boolean("noncombatForcerActive")) return; + + // If you are forcing an NC, build the reminder + ChecklistEntry entry; + + entry.url = ""; + entry.image_lookup_name = "__effect Feeling Sneaky"; + entry.tags.id = "Active sneak reminder"; + entry.importance_level = -11; + + entry.subentries.listAppend(ChecklistSubentryMake("Noncombat up next","","You're feeling sneaky; a noncombat will occur in the next zone where an NC is available. Don't waste it!")); + + task_entries.listAppend(entry); +} +// Setting a static converter of phyla to monsters for (mostly bad) reasons. + +static +{ + string [phylum] __phylum_to_monster; + // This is my best attempt to associate a funny monster with each phylum. Some are better than others. + __phylum_to_monster[$phylum[beast]] = "__monster "+$monster[fluffy bunny].to_string().to_lower_case(); + __phylum_to_monster[$phylum[bug]] = "__monster "+$monster[Spant soldier].to_string().to_lower_case(); + __phylum_to_monster[$phylum[constellation]] = "__monster "+$monster[Astrologer of Shub-Jigguwatt].to_string().to_lower_case(); + __phylum_to_monster[$phylum[construct]] = "__monster "+$monster[Luggage-Handling Trainbot].to_string().to_lower_case(); + __phylum_to_monster[$phylum[demon]] = "__monster "+$monster[W imp].to_string().to_lower_case(); + __phylum_to_monster[$phylum[dude]] = "__monster "+$monster[dirty thieving brigand].to_string().to_lower_case(); + __phylum_to_monster[$phylum[elemental]] = "__monster "+$monster[BASIC Elemental].to_string().to_lower_case(); + __phylum_to_monster[$phylum[elf]] = "__monster "+$monster[wire-crossin' elf].to_string().to_lower_case(); + __phylum_to_monster[$phylum[fish]] = "__monster "+$monster[sea cowboy].to_string().to_lower_case(); + __phylum_to_monster[$phylum[goblin]] = "__monster "+$monster[Knob Goblin Very Mad Scientist].to_string().to_lower_case(); + __phylum_to_monster[$phylum[hippy]] = "__monster "+$monster[Neil].to_string().to_lower_case(); + __phylum_to_monster[$phylum[humanoid]] = "__monster "+$monster[yeti].to_string().to_lower_case(); + __phylum_to_monster[$phylum[horror]] = "__monster "+$monster[Guy Made Of Bees].to_string().to_lower_case(); + __phylum_to_monster[$phylum[mer-kin]] = "__monster "+$monster[Ringogeorge, the Bladeswitcher].to_string().to_lower_case(); + __phylum_to_monster[$phylum[orc]] = "__monster "+$monster[Danglin' Chad].to_string().to_lower_case(); + __phylum_to_monster[$phylum[penguin]] = "__monster "+$monster[Mob Penguin Arsonist].to_string().to_lower_case(); + __phylum_to_monster[$phylum[pirate]] = "__monster "+$monster[grungy pirate].to_string().to_lower_case(); + __phylum_to_monster[$phylum[plant]] = "__monster "+$monster[man-eating plant].to_string().to_lower_case(); + __phylum_to_monster[$phylum[slime]] = "__monster "+$monster[fan slime].to_string().to_lower_case(); + __phylum_to_monster[$phylum[undead]] = "__monster "+$monster[the ghost of Phil Bunion].to_string().to_lower_case(); + __phylum_to_monster[$phylum[weird]] = "__monster "+$monster[loaf of Bread of Wonder].to_string().to_lower_case(); +} + +// In order to make the for loop a bit nicer, generate the string in a helper function. +string DescribeThisBanish(Banish b) { + + string banishedMon = b.banished_monster.to_string(); + string source = b.banish_source; + int banishTurn = b.turn_banished; + int banishLength = b.banish_turn_length; + string banishLengthString = ""; + + int turnsOfBanishLeft = BanishTurnsLeft(b); + + if (source == "Bowl a Curveball") { + turnsOfBanishLeft = get_property_int("cosmicBowlingBallReturnCombats"); + } + + if (source == "Roar like a Lion") { + turnsOfBanishLeft = have_effect($effect[Hear Me Roar]); + } + + if (turnsOfBanishLeft <= 0) { + return ""; + } + + if (turnsOfBanishLeft >= 300) banishLengthString = " until rollover."; + if (turnsOfBanishLeft <= 300) banishLengthString = ` for {pluralise(turnsOfBanishLeft,"more turn","more turns")}.`; + if (source == "ice house") banishLengthString = " forever."; + + string textReturn = ""+banishedMon+", via "+source+banishLengthString+"
|*"; + + return textReturn; + +} + +// Due to the world being the way it is, need to enumerate this twice to handle both record types. +string DescribeThisBanish(BanishedPhylum b) { + + string banishedPhy = b.banished_phylum.to_string().to_upper_case(); + string source = b.banish_source; + int banishTurn = b.turn_banished; + int banishLength = b.banish_turn_length; + string banishLengthString = ""; + + + if (b.custom_reset_conditions == "rollover") { + banishLength = 1234567; + } + + int turnsSinceBanish = my_turncount() - banishTurn; + int turnsOfBanishLeft = banishLength - turnsSinceBanish; + + if (turnsOfBanishLeft < 0) { + return ""; + } + + if (turnsOfBanishLeft >= 300) banishLengthString = " until rollover."; + if (turnsOfBanishLeft <= 300) banishLengthString = ` for {pluralise(turnsOfBanishLeft,"more turn","more turns")}!`; + + // If a new source is introduced, just add "by "+source" as in the above monster example. + + string textReturn = "The entire "+banishedPhy+" phylum is banished"+banishLengthString; + + return textReturn; + +} + +// I think there are better ways to do this. However, I am tired. So, I'm instead doing... whatever the fuck this is, I guess. +RegisterResourceGenerationFunction("ActiveBanishesList"); +void ActiveBanishesList(ChecklistEntry [int] resource_entries) +{ + // Read in the banisher preferences + string banishedMonstersUnparsed = get_property("banishedMonsters"); + string banishedPhylumUnparsed = get_property("banishedPhyla"); + + Banish [int] monsterResult = BanishesActive(); + BanishedPhylum [int] phylaResult; + + // Save the banished monsters to compare later for snapper/eagle checks, with snapper phylum. + monster [int] banishedMonsterList; + phylum snapperPhylum = get_property("redSnapperPhylum").to_phylum(); + + // Banishes are in the format "thing:source:###" where # is turncount of banished. This splits it. + string [int] banishedMonstersParsed = banishedMonstersUnparsed.split_string(":"); + string [int] banishedPhylumParsed = banishedPhylumUnparsed.split_string(":"); + + // ... then this reads it. + foreach key, banish in monsterResult { + // Add the banished monster to the banishedMonsterList + banishedMonsterList.listAppend(banish.banished_monster); + } + + // Now that you've addressed "normal" banishes, address the phylum banish. + + foreach key, parsedString in banishedPhylumParsed { + if (parsedString.length() == 0) + continue; // This bypasses if there is no result + if (key % 3 != 0) + continue; // This bypasses when you aren't at a divisible-by-three key. + + BanishedPhylum b; + b.banished_phylum = banishedPhylumParsed[key + 0].to_phylum(); + b.banish_source = banishedPhylumParsed[key + 1]; + b.turn_banished = banishedPhylumParsed[key + 2].to_int(); + b.banish_turn_length = 0; + if (__banish_source_length contains b.banish_source.to_lower_case()) + b.banish_turn_length = __banish_source_length[b.banish_source.to_lower_case()]; + + phylaResult.listAppend(b); + } + + // Now, make a resource entry for this whole thing + ChecklistSubentry [int] subentries; + string name; + string description; + string monsterIcon; + string phylaSubtitle; + string monsterSubtitle; + string monsterSymbol; // 🠞 for normal monster, 🞮 for un-banished monster + string banishDescribed; + phylum phylumBanished = $phylum[none]; + int monsterCount = 0; + + if (phylaResult.count() > 0) { + name = "Current Phyla Banished"; + + int screechCharge = get_property_int("screechCombats"); + if (screechCharge == 0) phylaSubtitle = "can clear with your patriotic eagle"; + if (screechCharge > 0) phylaSubtitle = `spend {pluralise(screechCharge,"turn/run","turns/runs")} with your eagle to cast screech again`; + + foreach key, banish in phylaResult { + banishDescribed = DescribeThisBanish(banish); + if (banishDescribed != "") { + description += "|*"+banishDescribed+"
|*"; + monsterIcon = __phylum_to_monster[banish.banished_phylum]; + phylumBanished = banish.banished_phylum; + } + } + subentries.listAppend(ChecklistSubentryMake(name,phylaSubtitle,description)); + } + + if (monsterResult.length() > 0) { + description = ""; + monsterSubtitle = ""; + + // If your snapper is active, show the snapper phylum. + phylum snapperTarget = my_familiar() == lookupFamiliar("Red Nosed Snapper") ? get_property("redSnapperPhylum").to_phylum() : $phylum[none]; + + if (snapperTarget != $phylum[none]) { + monsterSubtitle = `your snapper is un-banishing {snapperTarget.to_string()} targets, marked with 🞮`; + } + + foreach key, banish in monsterResult { + banishDescribed = DescribeThisBanish(banish); + monsterSymbol = "🠞 "; + if (banishDescribed != "") { + // add an icon for snapper unbanishing the monster + if (banish.banished_monster.phylum == snapperTarget) { + monsterSymbol = `🞮 `; + } + description += "|*"+monsterSymbol+banishDescribed; + monsterIcon = "__monster "+banish.banished_monster.to_string().to_lower_case(); + monsterCount += 1; + } + } + name = `{pluralise(monsterCount,"monster banished", "monsters banished")}`; + subentries.listAppend(ChecklistSubentryMake(name,monsterSubtitle,description)); + + } + + if (subentries.count() > 0) { + + // Want this atop resources for testing. Also, maybe just want it there period? + int priority = -69; + ChecklistEntry entry = ChecklistEntryMake(monsterIcon, "", subentries, priority); + entry.tags.id = "Active banishes"; + resource_entries.listAppend(entry); + } +} + + +void SetsInit() +{ + SCountersInit(); + QHitsInit(); +} + + +void SetsGenerateResources(ChecklistEntry [int] resource_entries) +{ + SFamiliarsGenerateResource(resource_entries); + SSkillsGenerateResource(resource_entries); + SMiscItemsGenerateResource(resource_entries); + SCopiedMonstersGenerateResource(resource_entries); + SPulveriseGenerateResource(resource_entries); + SCountersGenerateResource(resource_entries); + SFaxGenerateResource(resource_entries); + SClassesGenerateResource(resource_entries); + SEquipmentGenerateResource(resource_entries); + SCalculateUniverseGenerateResource(resource_entries); + SEventsGenerateResource(resource_entries); +} + +void SetsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + SFamiliarsGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SDispensaryGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SCouncilGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SCopiedMonstersGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SAftercoreGenerateTasks(task_entries, optional_task_entries, future_task_entries); + QHitsGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SDailyDungeonGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SCountersGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SBountyHunterHunterGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SOldLevel9GenerateTasks(task_entries, optional_task_entries, future_task_entries); + SFaxGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SDungeonsOfDoomGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SOlfactionGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SHolidayGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SRemindersGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SEventsGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SClassesGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SEquipmentGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SMiscItemsGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SPVPGenerateTasks(task_entries, optional_task_entries, future_task_entries); +} + +boolean [item] __pulls_reasonable_to_buy_in_run; + +int pullable_amount(item it, int maximum_total_wanted) +{ + boolean buyable_in_run = false; + if (__pulls_reasonable_to_buy_in_run contains it) + buyable_in_run = true; + if (it.tradeable && it.historical_price() > 0 && it.historical_price() < 75000) + buyable_in_run = true; + if (maximum_total_wanted == 0) + maximum_total_wanted = __misc_state_int["pulls available"] + it.available_amount(); + if (__misc_state["Example mode"]) //simulate pulls + { + if (buyable_in_run) + return min(__misc_state_int["pulls available"], maximum_total_wanted); + else + return min(__misc_state_int["pulls available"], min(storage_amount(it) + it.available_amount(), maximum_total_wanted)); + } + + int amount = storage_amount(it); + if (buyable_in_run) + amount = 20; + int total_amount = amount + it.available_amount(); + + if (total_amount > maximum_total_wanted) + { + amount = maximum_total_wanted - it.available_amount(); + } + + // Code by MadCarew to limit your pull # to just 1, not > 1. + if (in_ronin() && amount > 0 ) + { + // Hooray for removing already-pulled stuff! + string ronin_storage_pulls = get_property("_roninStoragePulls"); + string[int] already_pulled = split_string(ronin_storage_pulls, ","); + int requested_item = it.to_int(); + + boolean already_pulled_this_item = false; + foreach key in already_pulled { + if (already_pulled[key] == requested_item) already_pulled_this_item = true; + } + amount = already_pulled_this_item ? 0 : 1; + } + + return min(__misc_state_int["pulls available"], amount); +} + +int pullable_amount(item it) +{ + return pullable_amount(it, 0); +} + + +//generic pull item +record GPItem +{ + //Either item OR alternate_name + item it; + string alternate_name; + string alternate_image_name; + + string reason; + int max_wanted; +}; + +GPItem GPItemMake(item it, string reason, int max_wanted) +{ + GPItem result; + result.it = it; + result.reason = reason; + result.max_wanted = max_wanted; + return result; +} + +GPItem GPItemMake(item it, string reason) +{ + return GPItemMake(it, reason, 1); +} + +GPItem GPItemMake(string alternate_name, string alternate_image_name, string reason) +{ + GPItem result; + result.alternate_name = alternate_name; + result.alternate_image_name = alternate_image_name; + result.reason = reason; + result.max_wanted = 1; + return result; +} + +void listAppend(GPItem [int] list, GPItem entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + + +void generatePullList(Checklist [int] checklists) +{ + // Start out pull list generation with some general bookkeeping + ChecklistEntry [int] pulls_entries; + + // Return in the event that the user has no pulls available + int pulls_available = __misc_state_int["pulls available"]; + if (pulls_available <= 0) + return; + if (pulls_available > 0) + pulls_entries.listAppend(ChecklistEntryMake("special subheader", "", ChecklistSubentryMake(pluralise(pulls_available, "pull", "pulls") + " remaining")).ChecklistEntrySetIDTag("Pulls special subheader")); + + // Establish your base lists & variables + item [int] pullable_list_item; + int [int] pullable_list_max_wanted; + string [int] pullable_list_reason; + GPItem [int] pullable_item_list; + boolean combat_items_usable = true; + boolean combat_skills_usable = true; + + // Set a single path-related variable + if (my_path().id == PATH_POCKET_FAMILIARS) + combat_items_usable = false; + combat_skills_usable = false; + + // ===================================================================== + // ------ SECTION #1: 3+ TURNS ----------------------------------------- + // ===================================================================== + + // Pulls in this category are highly valuable turnsave pulls that can + // either bypass certain quests entirely or save entire chunks of + // quests. Everything here is stupid valuable. Ordering is: + // 1. Free kills + // 2. Free runs + // 3. Copiers + // 4. Quest-y pulls + + boolean canUseHeavySpleeners = availableSpleen() >= 2 && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_COMMUNITY_SERVICE; + + // Breathitin is virtually always good. Absurdly nice pull. + if (canUseHeavySpleeners) + pullable_item_list.listAppend(GPItemMake($item[Breathitin™], "5 outdoor free kills for 2 spleen", 7)); + + // Bat-oomerang is a great freekill pull + if (combat_items_usable && $item[replica bat-oomerang].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[replica bat-oomerang], "3 daily free kills", 1)); + + // Carnivorous Potted Plant is frustrating when you have lots of offhands, but it's + // unambiguously good... so long as you have enough combats left. Going to say + // that after 250 turns spent, it's unlikely you want this. + pullable_item_list.listAppend(GPItemMake($item[carnivorous potted plant], "offhand; +25 ML, 4% chance of turning any given combat free", 1)); + + // Part of me kind of wants to make one pull tile that concatenates the 3 battery + // types, but this is good enough. + + if (combat_skills_usable) { + pullable_item_list.listAppend(GPItemMake($item[battery (car)], "1 yellow ray + freekill|30 turns of 100% item/meat", 2)); + pullable_item_list.listAppend(GPItemMake($item[battery (lantern)], "1 yellow ray + freekill|30 turns of 100% item", 2)); + pullable_item_list.listAppend(GPItemMake($item[battery (9-volt)], "1 yellow ray + freekill", 2)); + } + + boolean freeRunFamiliarUsable = familiar_is_usable($familiar[pair of stomping boots]) || ($skill[the ode to booze].skill_is_usable() && familiar_is_usable($familiar[Frumious Bandersnatch])); + + // This is a catch-all for familiar weight pulls, which are only useful if the user can use boots/bander + if (!__misc_state["familiars temporarily blocked"] && $familiar[pair of stomping boots].is_unrestricted() && freeRunFamiliarUsable) { + + // Sort of a pain, but if they have it, it's a nice +4 runs... + if ($item[snow suit].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[snow suit], "+20 familiar weight for a while, +4 free runs (boots/bander)", 1)); + + // If they've got a free-run fam, this is a dope pull + if ($item[repaid diaper].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[repaid diaper], "+3 free runs (boots/bander)", 1)); + + // If they've got a free-run fam, this is a dope pull + if ($item[silver face paint].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[silver face paint], "+4 free runs (boots/bander)|only lasts 1 turn; extend w/ wool or PYEC?", 1)); + } + + // Generic free-run based pulls + if (__misc_state["free runs usable"]) { + + // GAP & navel are still good pulls, even now! Priority is GAP > navel > parasol, if you own all. + int storagePants = pullable_amount($item[greatest american pants]); + int storageNavel = pullable_amount($item[navel ring of navel gazing]); + int totalGAPandNavel = $items[greatest american pants, navel ring of navel gazing].available_amount(); + + if (storagePants > 0) { + pullable_item_list.listAppend(GPItemMake($item[greatest american pants], "3+ free runaways|item, mox, DA buff", 1)); + } + else if (storageNavel > 0) { + pullable_item_list.listAppend(GPItemMake($item[navel ring of navel gazing], "3+ free runaways|easier fights", 1)); + } + else if (storagePants + storageNavel + totalGAPandNavel == 0) { + pullable_item_list.listAppend(GPItemMake($item[peppermint parasol], "3+ free runaways", 1)); + } + + if (!get_property_boolean("_blankoutUsed") && $item[bottle of blank-out].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[bottle of blank-out], "5 free runaways|flee your problems", 1)); + + } + + // Rain-Doh & Spooky Putty; 5 copies is roughly 3+ turns in value, even without going in delay. + if ($item[empty rain-doh can].available_amount() == 0 && $item[can of rain-doh].available_amount() == 0 && $item[can of rain-doh].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[can of rain-doh], "5 copies/day|everything really", 1)); + + if ($items[empty rain-doh can,can of rain-doh,spooky putty monster].available_amount() == 0 && $item[spooky putty sheet].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[spooky putty sheet], "5 copies/day", 1)); + + // Extro: the modern stuffer/blaster lol. + if (canUseHeavySpleeners) pullable_item_list.listAppend(GPItemMake($item[Extrovermectin™], "3 copies (as wanderers) for 2 spleen", 7)); + + // Stuffers and blasters are still good, though blaster is strictly inferior to a breath + if (availableSpleen() >= 2 && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_COMMUNITY_SERVICE) + { + pullable_item_list.listAppend(GPItemMake($item[turkey blaster], "Burns five turns of delay in last adventured area. Costs spleen, limited uses/day.", MIN(3 - get_property_int("_turkeyBlastersUsed"), MIN(availableSpleen() / 2, 3)))); + + if (!__quest_state["Level 12"].finished && __quest_state["Level 12"].state_int["frat boys left on battlefield"] >= 936 && __quest_state["Level 12"].state_int["hippies left on battlefield"] >= 936) + { + pullable_item_list.listAppend(GPItemMake($item[stuffing fluffer], "Saves eight turns if you use two at the start of fighting in the war.", 2)); + } + } + + // Homebodyl is a pretty good pull if the user doesn't have free crafts. + boolean hasAnyFreeCrafts = false; + + if ($item[recording of Inigo's Incantation of Inspiration].available_amount() > 0) { + hasAnyFreeCrafts = true; + } + else if ($item[cuppa Craft tea].available_amount() > 0) { + hasAnyFreeCrafts = true; + } + else if ($skill[rapid prototyping].skill_is_usable()) { + hasAnyFreeCrafts = true; + } + else if (lookupSkill("Expert Corner-Cutter").skill_is_usable()) { + hasAnyFreeCrafts = true; + } + else if (get_property_int("homebodylCharges") > 0 || $item[Homebodyl™].available_amount() > 0) { + hasAnyFreeCrafts = true; + } + + if (!hasAnyFreeCrafts) + pullable_item_list.listAppend(GPItemMake($item[Homebodyl™], "11 free crafts for 2 spleen", 1)); + + // Hero key generators save 3+ turns apiece, but if you have a zap wand, you should pull accessories instead + if (__misc_state_int["fat loot tokens needed"] > 0) { + + string [int] hero_key_selections; // general summary hero selection variable + string [int] which_pies; // if it's pie time + string [int] which_accessories; // if it's wand time + string line; + string description; + + // If they have an easy way to get a wand (or have a wand, or are in shrunken adv) suggest hero accessories instead of pies + if (my_path() == $path[A Shrunken Adventurer am I] || __iotms_usable[lookupItem("diabolic pizza cube")] || __misc_state["zap wand owned"]) { + if ($items[boris's key,boris's key lime pie].available_amount() == 0) which_accessories.listAppend("Boris' Ring"); + if ($items[jarlsberg's key,jarlsberg's key lime pie].available_amount() == 0) which_accessories.listAppend("Jarlsberg's Earring"); + if ($items[sneaky pete's key,sneaky pete's key lime pie].available_amount() == 0) which_accessories.listAppend("Sneaky Pete's Breath Spray"); + if (which_accessories.count() > 0) + line += which_accessories.listJoinComponents(", ")+" ... get a wand and zap them!"; + hero_key_selections.listAppend(line); + + // If they're pulling accessories, should also probably pull PYEC + pullable_item_list.listAppend(GPItemMake($item[Platinum Yendorian Express Card], "recharge your zap wand, extend some effects")); + } + else if (__misc_state["can eat just about anything"] && availableFullness() > 0) + { + if ($items[boris's key,boris's key lime pie].available_amount() == 0 && $item[boris's key lime pie].item_is_usable()) + which_pies.listAppend("Boris"); + if ($items[jarlsberg's key,jarlsberg's key lime pie].available_amount() == 0 && $item[jarlsberg's key lime pie].item_is_usable()) + which_pies.listAppend("Jarlsberg"); + if ($items[sneaky pete's key,sneaky pete's key lime pie].available_amount() == 0 && $item[sneaky pete's key lime pie].item_is_usable()) + which_pies.listAppend("Sneaky Pete"); + if (which_pies.count() > 0) + line += which_pies.listJoinComponents("/") + "'s "; + line += "key lime pie"; + if (which_pies.count() > 1) + line += "s"; + hero_key_selections.listAppend(line); + + } + + if (hero_key_selections.count() > 0) { + description = hero_key_selections.listJoinComponents(", "); + pullable_item_list.listAppend(GPItemMake("Hero Key Generators", "Boris's key", description)); + } + } + + // Being able to skip HITS entirely is pretty strong, much like Whitey's skip. + int starChartsNeeded = MAX(1 - $item[star chart].available_amount(), 0); + int starsNeeded = MAX(8 - $item[star].available_amount(), 0); + int linesNeeded = MAX(7 - $item[line].available_amount(), 0); + + boolean haveStarKey = __quest_state["Level 13"].state_boolean["Richard\'s star key used"] || $item[richard\'s star key].available_amount() > 0; + + if (!haveStarKey) { + // First, if they don't have a star chart, recommend a chart or a greasy desk bell. + if (starChartsNeeded > 0) { + if ($item[greasy desk bell].is_unrestricted()) { + pullable_item_list.listAppend(GPItemMake($item[greasy desk bell], "get a star chart + 2 stars & 2 lines|free (but difficult) fight", 1)); + } + else { + pullable_item_list.listAppend(GPItemMake($item[star chart], "for Richard's Star Key", 1)); + } + } + + // Next, suggest star pops + if (__misc_state["can eat just about anything"] && my_path() != $path[A Shrunken Adventurer am I]) { + if (availableFullness() > 0 ) { + string starPopDesc = "3-4 stars & lines"; + if (starsNeeded < 4 && linesNeeded < 4) starPopDesc += ", will finish your key"; + if (starsNeeded > 3 && linesNeeded > 3) starPopDesc += ", of the "+starsNeeded+" stars & "+linesNeeded+" lines you still need"; + pullable_item_list.listAppend(GPItemMake($item[star pop], starPopDesc)); + } + + // Next, suggest star KLPs; if we've already suggested star pops, don't suggest KLPs, as they're strictly worse + if (availableFullness() > 3 && !$item[star pop].is_unrestricted()) { + string starKLPDesc = "2-4 stars & lines"; + if (starsNeeded < 3 && linesNeeded < 3) starKLPDesc += ", will finish your key"; + if (starsNeeded > 2 && linesNeeded > 2) starKLPDesc += ", of the "+starsNeeded+" stars & "+linesNeeded+" lines you still need"; + pullable_item_list.listAppend(GPItemMake($item[star key lime pie], starKLPDesc)); + } + } + } + + + // Wet stew is just an eternally great pull, Whitey's sucks + if (!__quest_state["Level 11 Palindome"].finished && $item[mega gem].available_amount() == 0 && ($item[wet stew].available_amount() + $item[wet stunt nut stew].available_amount() + $item[wet stew].creatable_amount() == 0) && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) + pullable_item_list.listAppend(GPItemMake($item[wet stew], "make into wet stunt nut stew|skip whitey's grove", 1)); + + // While a machete is quest-relevant, it's a 4-7 turn pull; that's absurd value. + if (!__quest_state["Level 11 Hidden City"].finished && !__quest_state["Level 11"].finished && (get_property_int("hiddenApartmentProgress") < 1 || get_property_int("hiddenBowlingAlleyProgress") < 1 || get_property_int("hiddenHospitalProgress") < 1 || get_property_int("hiddenOfficeProgress") < 1) && __misc_state["can equip just about any weapon"] && my_path().id != PATH_POCKET_FAMILIARS) + { + boolean have_machete = false; + foreach it in __dense_liana_machete_items + { + if (it.available_amount() > 0 && it.is_unrestricted()) + have_machete = true; + } + if (!have_machete) + { + if (my_basestat($stat[muscle]) < 62 && $item[machetito].is_unrestricted()) + { + //machetito + pullable_item_list.listAppend(GPItemMake($item[machetito], "Machete for dense liana", 1)); + } + else if ($item[muculent machete].is_unrestricted() && my_path().id != PATH_G_LOVER) //my_basestat($stat[muscle]) < 62 && + { + //muculent machete, also gives +5% meat, op ti mal + pullable_item_list.listAppend(GPItemMake($item[muculent machete], "Machete for dense liana", 1)); + } + else + { + //antique machete + pullable_item_list.listAppend(GPItemMake($item[antique machete], "Machete for dense liana", 1)); + } + } + } + + // As with machete, these are just flat-out great pulls, quest relevant or not + // 2025 UPDATE: ... or, well, they were. lol. + // if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && !have_outfit_components("eXtreme Cold-Weather Gear")) + // { + // item [int] missing_ninja_components = items_missing($items[ninja carabiner, ninja crampons, ninja rope]); + // if (missing_ninja_components.count() > 0) + // { + // string description = missing_ninja_components.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; + + // if (numeric_modifier("cold resistance") < 5.0) + // description += "|Will require five " + HTMLGenerateSpanOfClass("cold", "r_element_cold") + " resist to use properly."; + // pullable_item_list.listAppend(GPItemMake("Ninja peak climbing", "__item " + missing_ninja_components[0], description)); + // } + // } + + // Literally just 3 straight turnsave to pull scrips if you need em, lol + string [int] scrip_reasons; + int scrip_needed = 0; + if (!__misc_state["mysterious island available"] && $item[dinghy plans].available_amount() == 0) + { + scrip_needed += 3; + scrip_reasons.listAppend("mysterious island"); + } + if ($item[uv-resistant compass].available_amount() == 0 && $item[ornate dowsing rod].available_amount() == 0 && __misc_state["can equip just about any weapon"] && !__quest_state["Level 11 Desert"].state_boolean["Desert Explored"]) + { + scrip_needed += 1; + scrip_reasons.listAppend($item[uv-resistant compass].to_string()); + } + if (scrip_needed > 0 && my_path().id != PATH_COMMUNITY_SERVICE && my_path().id != PATH_EXPLOSIONS) + { + pullable_item_list.listAppend(GPItemMake($item[Shore Inc. Ship Trip Scrip], "Saves three turns each. (One per day?)|" + scrip_reasons.listJoinComponents(", ", "and").capitaliseFirstLetter() + ".", scrip_needed)); + } + + // Zepp mob, if done via faceroll, is 40+ turns. This stuff is massive value in ignoring that. + if (my_path().id != PATH_SEA && __quest_state["Level 11 Ron"].mafia_internal_step <= 2 && __quest_state["Level 11 Ron"].state_int["protestors remaining"] > 1) + { + item [int] missing_freebird_components = items_missing( __misc_state["Torso aware"] ? $items[lynyrdskin cap,lynyrdskin tunic,lynyrdskin breeches,lynyrd musk] : $items[lynyrdskin cap,lynyrdskin breeches,lynyrd musk] ); + + // In softcore, you are -almost- always going to prefer sleaze route in modern standard. + // However, for the sake of completionism, I will do a short and sweet sleaze calc; if + // the user is over the line of 262 sleaze, they should just pull a dang lewd deck. + + int projectedSleaze = 31; // assuming war outfit + kicks + ghost of a necklace + + if (__iotms_usable[$item[Jurassic Parka]]) projectedSleaze += 40; + if (__iotms_usable[$item[June Cleaver]]) projectedSleaze += 50; + if (__iotms_usable[$item[tiny stillsuit]]) projectedSleaze += 40; + if (__iotms_usable[$item[cursed monkey's paw]]) projectedSleaze += 200; + if (__iotms_usable[$item[designer sweatpants]]) projectedSleaze += 120; + + if (missing_freebird_components.count() > 0 && projectedSleaze < 262) + { + string description = missing_freebird_components.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; + if (__misc_state["Torso aware"]) + { + if ($strings[Wombat,Blender,Packrat] contains my_sign() && my_path().id != PATH_ZOMBIE_SLAYER) // gnome trainer may be available + description += "|Plus five clovers. Skips protestors in five turns? Or become torso aware and pull the tunic first."; + else + description += "|Plus five clovers. Skips the entire Zeppelin Mob in five turns?"; + } + else + description += "|Plus four clovers. Skips the entire Zeppelin Mob in ~four turns?"; + pullable_item_list.listAppend(GPItemMake("Weird copperhead NC strategy", "__item " + missing_freebird_components[0], description)); + } + + if (my_path().id != PATH_GELATINOUS_NOOB && projectedSleaze > 100) + pullable_item_list.listAppend(GPItemMake($item[deck of lewd playing cards], "+138 sleaze damage equip for Zeppelin Mob", 1)); + + } + + // Gravy Boat used to be an unreasonable pull, but in 37 evil per zone era, this is a good one now + if (__quest_state["Level 7"].in_progress) + { + pullable_item_list.listAppend(GPItemMake($item[gravy boat], "Wear to save 3-4 turns in the cyrpt.")); + + } + + // ===================================================================== + // ------ SECTION #2: 1-2 TURNS ---------------------------------------- + // ===================================================================== + + // Not as valuable as the section #1 pulls, but better than average. In + // general, these pulls should be considered above quest misses and + // are less related to explicit in-run findings. + + // Generic free-run based pulls, but these are less valuable than those in section #1 + if (__misc_state["free runs usable"]) + { + // Middle finger ring is straight up good! + if (my_path().id != PATH_ZOMBIE_SLAYER && combat_skills_usable) // can't use due to MP cost in zombie slayer + pullable_item_list.listAppend(GPItemMake($item[mafia middle finger ring], "1 free 80-turn banish, per day", 1)); + + // I did not realize vivala mask gave a 10-turn banish until Legacy of Loathing. I was unfamiliar with its game. + if ($item[v for vivala mask].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[v for vivala mask], "1 free 10-turn banish, per day", 1)); + } + + // Generic free-kill based pulls, but less valuable than tier 1 pulls + int pills_pullable = clampi(20 - get_property_int("_powerPillUses"), 0, 20); + if (pills_pullable > 0 && ($familiar[ms. puck man].have_familiar() || $familiar[puck man].have_familiar())) + { + pullable_item_list.listAppend(GPItemMake($item[power pill], "1 free kill, with your puck", pills_pullable)); + } + + if (combat_items_usable) { + // Shadow bricks are pretty much fine as a pull; certainly better than writs/GSBs + pullable_item_list.listAppend(GPItemMake($item[shadow brick], "1 free kill", 13)); + + // Powdered Madness is expensive but fine + pullable_item_list.listAppend(GPItemMake($item[powdered madness], "1 free kill",5)); + + // Groveling Gravel is worse, but it's... fine + pullable_item_list.listAppend(GPItemMake($item[groveling gravel], "1 free kill|destroys item drops, buyer beware!",5)); + } + + // NC forcers are great! Clara's is nice because it's 2 in a 2-day run. + if ($item[Clara's Bell].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[Clara's Bell], "Forces a non-combat, once/day.", 1)); + + // ... but one stench jelly is also fine! + if (availableSpleen() > 0 && $item[stench jelly].item_is_usable() && my_path().id != PATH_LIVE_ASCEND_REPEAT) + pullable_item_list.listAppend(GPItemMake($item[stench jelly], "Skips ahead to an NC, saves 2-3 turns each.", 20)); + + // Quest-y pull; just save searching for an NC, like an NC forcer, but also save the turn spent! + if (my_path().id != PATH_SEA && !get_property_ascension("lastTempleUnlock") && $item[spooky-gro fertilizer].item_amount() == 0 && $item[spooky-gro fertilizer].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[spooky-gro fertilizer], "Saves 2-ish turns while unlocking temple.")); + + if (my_path().id != PATH_COMMUNITY_SERVICE && $item[11-leaf clover].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[11-leaf clover], "Various turn saving applications|Zeppelin Mob, Wand of Nagamar, etc.")); + + // If you can't hit 25% combat, all of these are actually pretty dope... + if (!__misc_state["can reasonably reach -25% combat"]) + { + if ((my_primestat() == $stat[moxie] || my_basestat($stat[moxie]) >= 35) && $item[iFlail].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[iFlail], "-combat, +11 ML, +5 familiar weight")); + if (__misc_state["Torso aware"] && $item[xiblaxian stealth vest].item_is_usable()) //FIXME exclusiveness with camouflage T-shirt. probably should pull camou if we're over muscle stat, otherwise stealth vest, or whichever we have + pullable_item_list.listAppend(GPItemMake($item[xiblaxian stealth vest], "-combat shirt")); + if ($item[duonoculars].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[duonoculars], "-combat, +5 ML")); + if ($item[ring of conflict].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[ring of conflict], "-combat")); + if (($item[red shoe].can_equip() || my_path().id == PATH_GELATINOUS_NOOB) && $item[red shoe].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[red shoe], "-combat")); + } + + // ... but even if you CAN hit 25% combat, invisibility tonic is actually pretty great + if (my_path().id != PATH_LIVE_ASCEND_REPEAT) { + pullable_item_list.listAppend(GPItemMake($item[patent invisibility tonic], "30 turns of -15% combat|If you route 30 turns of NC hunting together, this is solid value")); + } + + // If they have grey goose, they should (perhaps) consider pulling some of the familiar XP gear + if ($familiar[grey goose].familiar_is_usable() && my_path() != $path[Legacy of Loathing]) { + int extraVestXP = $item[tiny stillsuit].available_amount() > 0 ? 1 : 2; + pullable_item_list.listAppend(GPItemMake($item[grey down vest], "Equip for +"+extraVestXP+" goose XP over your next best option")); + + if ($item[teacher's pen].available_amount() < 3) { + pullable_item_list.listAppend(GPItemMake($item[teacher's pen], "Equip for +2 goose XP per fight")); + } + + } + + // Speaking of goose, Claw of the Infernal Seal is a nice pull for 5 free-ish fights + if (my_class() == $class[seal clubber] && $item[Claw of the Infernal Seal].available_amount() == 0) { + pullable_item_list.listAppend(GPItemMake($item[Claw of the Infernal Seal], "Fight 5 more free seals per day|Familiar turns, XP, and other fight-advanced goodies")); + } + + // Sure, why not; pocket wishes are fine + if ($item[pocket wish].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[pocket wish], "Save turns with meat/item wishes, monster summons, and more", 20)); + + // If nuns is still needed, recommend pulling an inhaler. + if (!__quest_state["Level 12"].state_boolean["Nuns Finished"] && my_path().id != PATH_2CRS) { + pullable_item_list.listAppend(GPItemMake($item[Mick's IcyVapoHotness Inhaler], "10 turns of +200% meat|Worth anywhere from 1-3 turns on the nuns war sidequest")); + } + + // One copy is kind of marginal but it's fine to include right at the end. + if ($familiar[Intergnat].familiar_is_usable() && $item[infinite BACON machine].item_is_usable()) + { + pullable_item_list.listAppend(GPItemMake($item[infinite BACON machine], "One copy/day with ~seven turns of your intergnat.", 1)); + } + + // Speaking of one copy, fine, we'll suggest a 4-d camera + if (combat_items_usable) { + pullable_item_list.listAppend(GPItemMake($item[4-d camera], "Use in a fight to copy a monster", 1)); + } + + // ===================================================================== + // ------ SECTION #3: QUEST MISSES ------------------------------------- + // ===================================================================== + + // Most pulls in here can be (relatively) painlessly routed into your + // run. However, if you don't have them, they're good pulls, just not + // universally valuable like the 1/2 tier pulls. A few of these end + // up being better than pulls above if you miss them, too. + + // I have not included the following 3 pulls because although they sort + // of belong, the logic is complex enough that I didn't want to hassle + + // - QUEST MISS: tangle of rat tails + // - QUEST MISS: sonar-in-a-biscuit + // - QUEST MISS: disposable instant camera + + if (__quest_state["Level 10"].mafia_internal_step >= 8) + { + if (__quest_state["Level 10"].mafia_internal_step == 8 && $item[amulet of extreme plot significance].available_amount() == 0) + { + pullable_item_list.listAppend(GPItemMake($item[amulet of extreme plot significance], "Speeds up castle basement.", 1)); + } + if (!__quest_state["Level 10"].finished && $item[mohawk wig].available_amount() == 0 && (!lookupSkill("Comprehensive Cartography").skill_is_usable() || $item[model airship].available_amount() == 0)) + { + pullable_item_list.listAppend(GPItemMake($item[mohawk wig], "Speeds up top floor of castle.", 1)); + } + } + + if (!__quest_state["Level 9"].state_boolean["bridge complete"]) + { + int boxes_needed = MIN(__quest_state["Level 9"].state_int["bridge fasteners needed"], __quest_state["Level 9"].state_int["bridge lumber needed"]) / 5; + + boxes_needed = MIN(6, boxes_needed); //bridge! farming? + + if (__iotms_usable[lookupItem("model train set")]) boxes_needed = 0; // you REALLY do not need to pull this if you have a train lol + + if (boxes_needed > 0 && $item[smut orc keepsake box].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[smut orc keepsake box], "Skip a few turns in building your smut orc bridge.", boxes_needed)); + } + + if (__quest_state["Level 9"].state_int["peak tests remaining"] > 0) + { + int trimmers_needed = clampi(__quest_state["Level 9"].state_int["peak tests remaining"], 0, 4); + if (trimmers_needed > 0) + pullable_item_list.listAppend(GPItemMake($item[rusty hedge trimmers], "Speed up twin peak, burn delay.|Saves ~2 turns each", trimmers_needed)); + } + + if (__quest_state["Level 11"].mafia_internal_step < 2) + pullable_item_list.listAppend(GPItemMake($item[blackberry galoshes], "Speed up Black Forest by 2-3 turns", 1)); + + //OUTFITS: √War outfit + if (!__quest_state["Level 12"].finished && (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues"))) + { + item [int] missing_hippy_components = missing_outfit_components("War Hippy Fatigues"); + item [int] missing_frat_components = missing_outfit_components("Frat Warrior Fatigues"); + pullable_item_list.listAppend(GPItemMake("Island War Outfit", "__item round purple sunglasses", "Hippy: " + missing_hippy_components.listJoinComponents(", ", "and") + ".|Frat boy: " + missing_frat_components.listJoinComponents(", ", "and") + ".")); + } + + // These are technically 1 turn if you're using clovers, less if you use other resource uses. + if (!__quest_state["Level 8"].state_boolean["Past mine"] && __quest_state["Level 8"].state_string["ore needed"] != "" && !$skill[unaccompanied miner].skill_is_usable()) + { + item ore_needed = __quest_state["Level 8"].state_string["ore needed"].to_item(); + + // Adding a trainset switch here, as you can just get this with trainset if you have it + if (ore_needed != $item[none] && ore_needed.available_amount() < 3 && !__iotms_usable[lookupItem("model train set")]) + { + pullable_item_list.listAppend(GPItemMake(ore_needed, "Level 8 quest.", 3)); + } + } + + if (!have_outfit_components("Knob Goblin Elite Guard Uniform") && !__quest_state["Level 5"].finished) + { + item [int] missing_outfit_components = missing_outfit_components("Knob Goblin Harem Girl Disguise"); + + string entry = missing_outfit_components.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; + entry += " Level 5 quest."; + if (missing_outfit_components.count() > 0) + pullable_item_list.listAppend(GPItemMake("Knob Goblin Harem Girl Disguise", "__item " + missing_outfit_components[0], entry)); + } + + + if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && __quest_state["Level 11 Desert"].state_int["Desert Exploration"] < 95) + { + if (!__quest_state["Level 11 Desert"].state_boolean["Wormridden"] && $item[drum machine].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[drum machine], "30% desert exploration with pages.", 1)); + if (!__quest_state["Level 11 Desert"].state_boolean["Killing Jar Given"] && $location[the haunted bedroom].locationAvailable()) + pullable_item_list.listAppend(GPItemMake($item[killing jar], "15% desert exploration.", 1)); + if (!__quest_state["Level 11 Desert"].state_boolean["Black Paint Given"] && my_path().id == PATH_NUCLEAR_AUTUMN) + pullable_item_list.listAppend(GPItemMake($item[can of black paint], "15% desert exploration.", 1)); + + // Adding milestone, as it's valuable enough to warrant a mention. + pullable_item_list.listAppend(GPItemMake($item[milestone], "5% desert exploration; can use as many as you get!", 10)); + } + + if (!__quest_state["Level 10"].state_boolean["beanstalk grown"] && $item[enchanted bean].available_amount() == 0) { + pullable_item_list.listAppend(GPItemMake($item[enchanted bean], "Grow it in the Nearby Plains for the Level 10 quest", 1)); + } + + int hospital_progress = get_property_int("hiddenHospitalProgress"); + + if (hospital_progress < 7) { + item [int] missingSurgeonComponents; + if (__misc_state["Torso aware"]) + missingSurgeonComponents = items_missing($items[bloodied surgical dungarees,surgical mask,head mirror,half-size scalpel,surgical apron]); + if (!__misc_state["Torso aware"]) + missingSurgeonComponents = items_missing($items[bloodied surgical dungarees,surgical mask,head mirror,half-size scalpel]); + + if (missingSurgeonComponents.count() > 0) + { + string description = "Still need: " + missingSurgeonComponents.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."; + pullable_item_list.listAppend(GPItemMake("Surgeon disguise for the Hidden Hospital", "__item " + missingSurgeonComponents[0], description)); + } + + } + + boolean hiddenTavernUnlocked = get_property_ascension("hiddenTavernUnlock"); + + if ($item[book of matches].available_amount() == 0 && !hiddenTavernUnlocked) { + pullable_item_list.listAppend(GPItemMake($item[book of matches], "Unlock Cursed Punch & Bowl of Scorpions for Hidden City turnsaving", 1)); + } + + // Can pull a bowling ball, I guess. + int bowling_progress = get_property_int("hiddenBowlingAlleyProgress"); + int numberOfRollsLeft = 6 - bowling_progress; + int bowlingBallsNeeded = numberOfRollsLeft - $item[bowling ball].available_amount_including_closet(); + int bowlingBallsInInventory = $item[bowling ball].available_amount(); + + if (bowling_progress < 7 && bowlingBallsNeeded > 0) { + pullable_item_list.listAppend(GPItemMake($item[bowling ball], "Could pull a bowling ball for the Hidden Bowling Alley", bowlingBallsNeeded)); + } + + if ($item[electric boning knife].available_amount() == 0 && __quest_state["Level 13"].state_boolean["wall of bones will need to be defeated"] && my_path().id != PATH_POCKET_FAMILIARS) { + if (!$skill[garbage nova].skill_is_usable() && !in_bad_moon() && !__quest_state["Level 13"].state_boolean["past tower level 2"] && $location[the castle in the clouds in the sky (top floor)].locationAvailable()) { + pullable_item_list.listAppend(GPItemMake("Can pull a clusterbomb to crumble the wall of bones", "__ item sleaze clusterbomb", "Unbelievably expensive pull that will save you a few turns if you cannot towerkill the wall of bones")); + } + } + + + // ===================================================================== + // ------ SECTION #4: LEVELING ----------------------------------------- + // ===================================================================== + + // Pulls in this category aren't really measured by turn-value; they're + // measured by how many stats they give the user. Ergo, in cases where + // it's possible, try to include the # of expected stats in the desc + + if (__misc_state["need to level"]) + { + // Best stat pull is the glitch, so put it at the top. But only show it at a critical mass of implementations. + int glitchMonsterStats = MAX(10, 5 * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0 ) * get_property_int("glitchItemImplementationCount") / 4); + + // Below this, you might as well just pull sprout or whatever. + if (glitchMonsterStats > 400) { + string glitchDesc = "Difficult free fight, but massive meat/stat gains!"; + + // Display meat if it actually matters + if (my_meat() < 7500) glitchDesc += "|Will gain "+get_property_int("glitchItemImplementationCount")*5+" meat from your glitch."; + + glitchDesc += "|Will gain "+glitchMonsterStats+" stats from your glitch."; + + if (__iotms_usable[$item[emotion chip]] && clampi(3 - get_property_int("_feelPrideUsed"), 0, 3) > 0) glitchDesc += "|Consider using Feel Pride to get 3x that total of stats."; + + pullable_item_list.listAppend(GPItemMake(lookupItem("[glitch season reward name]"), glitchDesc)); + } + + if (my_primestat() == $stat[muscle]) + { + if ($item[fake washboard].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[fake washboard], "+25% to mainstat gain, offhand.")); + if ($item[red LavaCo Lamp™].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[red LavaCo Lamp™], "+5 adventures, 50 turns of +50% mainstat gain after rollover.")); + } + else if (my_primestat() == $stat[mysticality]) + { + if ($item[basaltamander buckler].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[basaltamander buckler], "+25% to mainstat gain, offhand.")); + if ($item[blue LavaCo Lamp™].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[blue LavaCo Lamp™], "+5 adventures, 50 turns of +50% mainstat gain after rollover.")); + if (my_path().id == PATH_THE_SOURCE) + { + int amount = 3; + if ($item[battle broom].available_amount() > 0) + amount = 2; + pullable_item_list.listAppend(GPItemMake($item[wal-mart nametag], "+4 mainstat/fight", amount)); + } + } + else if (my_primestat() == $stat[moxie]) + { + if ($item[backwoods banjo].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[backwoods banjo], "+20% to mainstat gain, 2h weapon.")); + if ($item[green LavaCo Lamp™].item_is_usable()) + pullable_item_list.listAppend(GPItemMake($item[green LavaCo Lamp™], "+5 adventures, 50 turns of +50% mainstat gain after rollover.")); + if (my_path().id == PATH_THE_SOURCE) + pullable_item_list.listAppend(GPItemMake($item[wal-mart overalls], "+4 mainstat/fight")); + } + + // If the user can use a red rocket, and user doesn't have a cleaver, suggest pulling a guilty sprout + if (__misc_state["in run"] && __misc_state["can eat just about anything"] && available_amount($item[Clan VIP Lounge key]) > 0 && get_property("_fireworksShop").to_boolean() && my_path().id != PATH_G_LOVER) { + if (!__iotms_usable[$item[June Cleaver]]) { + int sproutStats = MAX(0, 4 * 225 * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0)); + pullable_item_list.listAppend(GPItemMake($item[guilty sprout],"Food; gain "+sproutStats+" stats with a red-rocketed sprout!")); + } + } + + // Vamp stats are pretty stupid but they're plausible I guess. + int vampingStats = MIN(500, 4 * my_basestat(my_primestat())) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); + pullable_item_list.listAppend(GPItemMake($item[plastic vampire fangs], "Gain"+vampingStats+" mainstat, once/day; costs a turn!", 1)); + } + + + // ===================================================================== + // ------ SECTION #5: PATH-SPECIFIC ------------------------------------ + // ===================================================================== + + // Pulls in this category are path-specific pulls that are useful in a + // particular challenge path context and not particularly useful in + // other situations. + + if (my_path() == $path[A Shrunken Adventurer am I]) + pullable_item_list.listAppend(GPItemMake("Flat +100 stat potion", "__item bottle of pirate juice", "The tower stat test is really, really tough in this path!|Once at the tower, pull a bottle of pirate juice for moxie, teeny-tiny magic scroll for myst, or a bottle of rhinoceros hormones for muscle.")); + + if (my_path().id == PATH_COMMUNITY_SERVICE) + pullable_item_list.listAppend(GPItemMake($item[pocket wish], "Saves turns on everything in Community Service.", 20)); + + if (my_path().id == PATH_HEAVY_RAINS) + pullable_item_list.listAppend(GPItemMake($item[fishbone catcher's mitt], "offhand, less items washing away", 1)); + + // ===================================================================== + // ------ SECTION #6: TURNBLOAT ---------------------------------------- + // ===================================================================== + + // Pulls in this category are only really worth it if they help you make + // daycount. You probably ignore it in most unrestricted contexts, but + // instead of flat ignoring it I think you just throw these at the + // absolute bottom of the list. + + // Turnbloat does not work in slow and steady, unless you are sweaty bill + if (my_path().id != PATH_SLOW_AND_STEADY) + { + // PANTSGIVING: banishes aren't really turnsaving anymore, you'd only pull it for unrestricted bloat. + pullable_item_list.listAppend(GPItemMake($item[pantsgiving], "5x non-free banishes|+2 stats/fight|+15% items|2 extra fullness (realistically)", 1)); + + // General food/drink constructors + if (__misc_state["can eat just about anything"] && availableFullness() > 0) + { + string [int] food_selections; + + if (availableFullness() >= 5 && my_path() != $path[A Shrunken Adventurer am I]) + { + if (my_level() >= 13 && my_path().id != PATH_G_LOVER) + food_selections.listAppend("hi meins"); + else if ($item[moon pie].is_unrestricted() && $item[moon pie].item_is_usable()) + food_selections.listAppend("moon pies"); + if ($item[fleetwood mac 'n' cheese].item_is_usable()) + food_selections.listAppend("fleetwood mac 'n' cheese" + (my_level() < 8 ? " (level 8)" : "")); + if ($item[karma shawarma].is_unrestricted() && $item[karma shawarma].item_is_usable()) + food_selections.listAppend("karma shawarma? (expensive" + (my_level() < 7 ? ", level 7" : "") + ")"); + } + + // adding the legendary cookbookbat foods; technically, if they have a bander, DDoL is + // also 3 turnsave via freeruns, but that's kind of annoying logic... + if ($item[Deep Dish of Legend].item_is_usable() && storage_amount($item[Deep Dish of Legend]) > 0) + food_selections.listAppend("Deep Dish of Legend" + (my_level() < 5 ? " (level 5)" : "")); + if ($item[Calzone of Legend].item_is_usable() && storage_amount($item[Calzone of Legend]) > 0) + food_selections.listAppend("Calzone of Legend" + (my_level() < 5 ? " (level 5)" : "")); + if ($item[Pizza of Legend].item_is_usable() && storage_amount($item[Pizza of Legend]) > 0) + food_selections.listAppend("Pizza of Legend" + (my_level() < 5 ? " (level 5)" : "")); + + string description; + if (food_selections.count() > 0) + description = food_selections.listJoinComponents(", ") + ", etc."; + pullable_item_list.listAppend(GPItemMake("Food", "Deep Dish of Legend", description)); + } + if (__misc_state["can drink just about anything"] && availableDrunkenness() >= 0 && inebriety_limit() >= 5) + { + string [int] drink_selections; + if ($item[wrecked generator].is_unrestricted() && $item[wrecked generator].item_is_usable()) + drink_selections.listAppend("wrecked generators"); + if ($item[Ice Island Long Tea].is_unrestricted() && $item[Ice Island Long Tea].item_is_usable()) + drink_selections.listAppend("Ice Island Long Tea"); + if ($item[Boris's beer].is_unrestricted() && $item[Boris's beer].item_is_usable()) + drink_selections.listAppend("Boris's beer"); + if ($item[vintage smart drink].is_unrestricted() && $item[vintage smart drink].item_is_usable()) + drink_selections.listAppend("vintage smart drink"); + + string description; + if (drink_selections.count() > 0) + description = drink_selections.listJoinComponents(", ") + ", etc."; + + pullable_item_list.listAppend(GPItemMake("Drink", "gibson", description)); + } + + if ($skill[ancestral recall].have_skill() && my_adventures() < 10) + { + int casts = get_property_int("_ancestralRecallCasts"); + if (casts < 10) + pullable_item_list.listAppend(GPItemMake($item[blue mana], "+3 adventures each.", clampi(10 - casts, 0, 10))); + } + + //unify these... later... + foreach it in $items[License to Chill,etched hourglass] + pullable_item_list.listAppend(GPItemMake(it, "slotless turn generation", 1)); + + boolean canEquipThumbRing = my_basestat($stat[muscle]) > 39; + pullable_item_list.listAppend(GPItemMake($item[mafia thumb ring], "turn generation accessory"+(canEquipThumbRing ? "" : " (need 40 muscle to equip!)"), 1)); + } + + // ===================================================================== + // ------ SECTION #7: MARGINAL GRAVEYARD ------------------------------- + // ===================================================================== + + // Pulls in this category are pretty bad. Most of them are leftover from + // old metas where the were mildly useful. Commenting them out... for + // now, mostly because there's possibly some future use case I'm not + // seeing and it's largely good stuff to at least remember that we + // once considered a good pull. + + // ... however, pre-commenting-out, I will include one meat-generating + // item at the end of the recommendations. It doesn't save turns, + // really, but it's certainly comfortable! + + if (my_meat() < 5000) + { + item meatyItem = $item[gold wedding ring]; + if (storage_amount($item[facsimile dictionary]) > 0) meatyItem = $item[facsimile dictionary]; + pullable_item_list.listAppend(GPItemMake(meatyItem, "Autosells for "+autosell_price(meatyItem)+" meat.|Likely non-optimal.", 1)); + } + + // At best, folder holder represents a minor leveling boost and +/- combat. Better than red shoe, but not dramatically... + // if (true) + // { + // string line = "So many things!"; + // if ($item[over-the-shoulder folder holder].storage_amount() > 0 && $item[over-the-shoulder folder holder].item_is_usable()) + // { + // string [int] description; + // string [item] folder_descriptions; + + // folder_descriptions[$item[folder (red)]] = "+20 muscle"; + // folder_descriptions[$item[folder (blue)]] = "+20 myst"; + // folder_descriptions[$item[folder (green)]] = "+20 moxie"; + // folder_descriptions[$item[folder (magenta)]] = "+15 muscle +15 myst"; + // folder_descriptions[$item[folder (cyan)]] = "+15 myst +15 moxie"; + // folder_descriptions[$item[folder (yellow)]] = "+15 muscle +15 moxie"; + // folder_descriptions[$item[folder (smiley face)]] = "+2 muscle stat/fight"; + // folder_descriptions[$item[folder (wizard)]] = "+2 myst stat/fight"; + // folder_descriptions[$item[folder (space skeleton)]] = "+2 moxie stat/fight"; + // folder_descriptions[$item[folder (D-Team)]] = "+1 stat/fight"; + // folder_descriptions[$item[folder (Ex-Files)]] = "+5% combat"; + // folder_descriptions[$item[folder (skull and crossbones)]] = "-5% combat"; + // folder_descriptions[$item[folder (Knight Writer)]] = "+40% init"; + // folder_descriptions[$item[folder (Jackass Plumber)]] = "+25 ML"; + // folder_descriptions[$item[folder (holographic fractal)]] = "+4 all res"; + // folder_descriptions[$item[folder (barbarian)]] = "stinging damage"; + // folder_descriptions[$item[folder (rainbow unicorn)]] = "prismatic stinging damage"; + // folder_descriptions[$item[folder (Seawolf)]] = "-pressure penalty"; + // folder_descriptions[$item[folder (dancing dolphins)]] = "+50% item (underwater)"; + // folder_descriptions[$item[folder (catfish)]] = "+15 familiar weight (underwater)"; + // folder_descriptions[$item[folder (tranquil landscape)]] = "15 DR / 15 HP & MP regen"; + // folder_descriptions[$item[folder (owl)]] = "+500% item (dreadsylvania)"; + // folder_descriptions[$item[folder (Stinky Trash Kid)]] = "passive stench damage"; + // folder_descriptions[$item[folder (sports car)]] = "+5 adv"; + // folder_descriptions[$item[folder (sportsballs)]] = "+5 PVP fights"; + // folder_descriptions[$item[folder (heavy metal)]] = "+5 familiar weight"; + // folder_descriptions[$item[folder (Yedi)]] = "+50% spell damage"; + // folder_descriptions[$item[folder (KOLHS)]] = "+50% item (KOLHS)"; + + // foreach s in $slots[folder1,folder2,folder3] + // { + // item folder = s.equipped_item(); + // if (folder == $item[none]) continue; + + // if (folder_descriptions contains folder) + // description.listAppend(folder_descriptions[folder]); + // } + // if (description.count() > 0) + // line = description.listJoinComponents(" / "); + // } + // pullable_item_list.listAppend(GPItemMake($item[over-the-shoulder folder holder], line, 1)); + // } + + // As with folder holder, this just isn't really a great pull anymore. Minor back slot is just not useful at all. + + // if (!__misc_state["familiars temporarily blocked"] && ($item[protonic accelerator pack].available_amount() == 0 || $familiar[machine elf].familiar_is_usable())) //if you have a machine elf, it might be worth pulling a bjorn with a protonic pack anyways + // { + // if ($item[Buddy Bjorn].storage_amount() > 0) + // pullable_item_list.listAppend(GPItemMake($item[Buddy Bjorn], "+10ML/+lots MP hat|or +item/+init/+meat/etc", 1)); + // else if ($item[buddy bjorn].available_amount() == 0) + // pullable_item_list.listAppend(GPItemMake($item[crown of thrones], "+10ML/+lots MP hat|or +item/+init/+meat/etc", 1)); + // } + + // At best, this is +5 fam weight; not worth a pull at all. + // if ($item[operation patriot shield].item_is_usable()) + // pullable_item_list.listAppend(GPItemMake($item[operation patriot shield], "+america", 1)); + // pullable_item_list.listAppend(GPItemMake($item[the crown of ed the undying], "Various in-run modifiers. (init, HP, ML/item/meat/etc)", 1)); + // } + + //pullable_item_list.listAppend(GPItemMake($item[haiku katana], "?", 1)); + // if ($item[bottle-rocket crossbow].item_is_usable()) + // pullable_item_list.listAppend(GPItemMake($item[bottle-rocket crossbow], "?", 1)); + + // This never showed up because it had an added false in the condition. I am commenting it out + // because I don't think anyone in unrestricted would ever want to do this? + + // boolean have_super_fairy = false; + // // Pretty sure I deleted the places that use this, but in case I didn't... + // if ((familiar_is_usable($familiar[fancypants scarecrow]) && $item[spangly mariachi pants].available_amount() > 0) || (familiar_is_usable($familiar[mad hatrack]) && $item[spangly sombrero].available_amount() > 0)) + // have_super_fairy = true; + + // if (!have_super_fairy && my_path().id != PATH_HEAVY_RAINS) + // { + // if (familiar_is_usable($familiar[fancypants scarecrow])) + // pullable_item_list.listAppend(GPItemMake($item[spangly mariachi pants], "2x fairy on fancypants scarecrow", 1)); + // else if (familiar_is_usable($familiar[mad hatrack])) + // pullable_item_list.listAppend(GPItemMake($item[spangly sombrero], "2x fairy on mad hatrack", 1)); + // } + + // These all suck now lol + //pullable_item_list.listAppend(GPItemMake($item[jewel-eyed wizard hat], "a wizard is you!", 1)); + //pullable_item_list.listAppend(GPItemMake($item[origami riding crop], "+5 stats/fight, but only if the monster dies quickly", 1)); //not useful? + //pullable_item_list.listAppend(GPItemMake($item[plastic pumpkin bucket], "don't know", 1)); //not useful? + //pullable_item_list.listAppend(GPItemMake($item[packet of mayfly bait], "why let it go to waste?", 1)); + + // Not good enough to use. The untinkering is cute, might unlock an extra battery YR, but not pull-worthy. + // pullable_item_list.listAppend(GPItemMake($item[loathing legion knife], "?", 1)); + + // No idea why you would want this, honestly. + // if ($item[juju mojo mask].item_is_usable()) + // pullable_item_list.listAppend(GPItemMake($item[juju mojo mask], "?", 1)); + + // Technically this is best in slot at certain times of the month but I don't care enough to include it anymore. + // if ($item[jekyllin hide belt].item_is_usable()) + // pullable_item_list.listAppend(GPItemMake($item[jekyllin hide belt], "+variable% item", 3)); + + // There's probably a (very small) case for still including as BIS +ML, but it's barely better than carn plant. + // if (__misc_state["need to level"]) + // { + // pullable_item_list.listAppend(GPItemMake($item[hockey stick of furious angry rage], "+30ML accessory.", 1)); + // } + + // Not useful enough unfortunately. + // pullable_item_list.listAppend(GPItemMake($item[ice sickle], "+15ML 1h weapon|+item/+meat/+init foldables", 1)); + + // No world where you're wasting a pull on +15% item drop on purpose. + // if ($item[buddy bjorn].available_amount() == 0 && $item[camp scout backpack].item_is_usable()) + // pullable_item_list.listAppend(GPItemMake($item[camp scout backpack], "+15% items on back", 1)); + + // Only really useful in their own paths. + // if ($item[boris's helm].item_is_usable()) pullable_item_list.listAppend(GPItemMake($item[boris's helm], "+15ML/+5 familiar weight/+init/+mp regeneration/+weapon damage", 1)); + // pullable_item_list.listAppend(GPItemMake($item[Jarlsberg's Pan], "Cook up some cool Jarlsberg potions!", 1)); + + // None of these shirts are particularly cool or good. + // if (__misc_state["Torso aware"]) + // { + // pullable_item_list.listAppend(GPItemMake($item[flaming pink shirt], "+15% items on shirt. (marginal)" + (__misc_state["familiars temporarily blocked"] ? "" : "|Or extra experience on familiar. (very marginal)"), 1)); + // if (__misc_state["need to level"] && $item[Sneaky Pete's leather jacket (collar popped)].available_amount() == 0 && $item[Sneaky Pete's leather jacket].available_amount() == 0) + // { + + // if ($item[Sneaky Pete's leather jacket (collar popped)].storage_amount() + $item[Sneaky Pete's leather jacket].storage_amount() > 0 && $item[Sneaky Pete's leather jacket].item_is_usable()) + // { + // if (my_path().id != PATH_AVATAR_OF_SNEAKY_PETE) + // pullable_item_list.listAppend(GPItemMake($item[Sneaky Pete's leather jacket], "+30ML/+meat/+adv/+init/+moxie shirt", 1)); + // } + // else + // if ($item[cane-mail shirt].item_is_usable()) + // pullable_item_list.listAppend(GPItemMake($item[cane-mail shirt], "+20ML shirt", 1)); + // } + // } + + // Only useful in Grey Goo. Not worth a pull. + // if (__misc_state["spooky airport available"] && __misc_state["need to level"] && __misc_state["can drink just about anything"] && $effect[jungle juiced].have_effect() == 0) + // { + // pullable_item_list.listAppend(GPItemMake($item[jungle juice], "Drink that doubles stat-gain in the deep dark jungle.", 1)); + // } + + // lol absolutely not + //pullable_item_list.listAppend(GPItemMake($item[slimy alveolus], "40 turns of +50ML (" + floor(40 * 50 * __misc_state_float["ML to mainstat multiplier"]) +" mainstat total, cave bar levelling)|1 spleen", 3)); //marginal now. low-skill oil peak/cyrpt? + + //FIXME suggest machetito? + //FIXME suggest super marginal stuff in SCO or S&S + //Ideas: Goat cheese, keepsake box, √spooky-gro fertilizer, harem outfit, perfume, rusty hedge trimmers, bowling ball, surgeon gear, tomb ratchets or tangles, all the other pies + //FIXME suggest ore when we don't have access to free mining + + //FIXME add hat/stuffing fluffer/blank-out + + // Ezan had some cruft here for pulling XP% things for chateau rest improved stats. I removed it because it + // didn't even show and isn't relevant to unrestricted anymore, high or low end. Sorry Ezan. + + // It's cute, but not really useful + // if ($item[Mr. Cheeng's spectacles] != $item[none]) + // pullable_item_list.listAppend(GPItemMake($item[Mr. Cheeng's spectacles], "+15% item, +30% spell damage, acquire random potions in-combat.|Not particularly optimal, but fun.")); + + // ======================================================================================================== + // ------ OK COOL ALL THE PULLS ARE DEALT WITH, NOW LET'S CONCAT THE PULL LIST LADS ----------------------- + // ======================================================================================================== + + boolean currently_trendy = (my_path().id == PATH_TRENDY); + foreach key in pullable_item_list + { + GPItem gp_item = pullable_item_list[key]; + string reason = gp_item.reason; + string [int] reason_list = split_string_alternate(reason, "\\|"); + + if (gp_item.alternate_name != "") + { + pulls_entries.listAppend(ChecklistEntryMake(gp_item.alternate_image_name, "storage.php", ChecklistSubentryMake(gp_item.alternate_name, "", reason_list)).ChecklistEntrySetIDTag("Pull suggestions " + gp_item.alternate_name)); + continue; + } + + + item [int] items; + int [item] related_items = get_related(gp_item.it, "fold"); + if (related_items.count() == 0) + items.listAppend(gp_item.it); + else + { + foreach it in related_items + items.listAppend(it); + } + + + int max_wanted = gp_item.max_wanted; + + int found_total; + foreach key, it in items + { + found_total += it.available_amount(); + } + if (found_total >= max_wanted) + continue; + if (my_path().id == PATH_GELATINOUS_NOOB) + { + boolean allowed = false; + boolean [item] whitelist = $items[gravy boat,blackberry galoshes,machetito,muculent machete,antique machete,Mr. Cheeng's spectacles,buddy bjorn,crown of thrones,navel ring of navel gazing,greatest american pants,plastic vampire fangs,the jokester's gun]; + foreach key, it in items + { + if ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3] contains it.to_slot() && !(whitelist contains it) && !it.discardable && !__items_in_outfits[it]) + { + } + else + allowed = true; + } + if (!allowed) + { + //print_html("Rejecting " + items[0]); + continue; + } + } + + foreach key in items + { + item it = items[key]; + if (currently_trendy && !is_trendy(it)) + continue; + if (!is_unrestricted(it)) + continue; + int actual_amount = pullable_amount(it, max_wanted); + if (actual_amount > 0) + { + string url = "storage.php"; + if (it != $item[none]) + { + if (it.fullness > 0 || it.inebriety > 0) + url = "storage.php?which=1"; + if (it.to_slot() != $slot[none]) + url = "storage.php?which=2"; + } + + if (it.storage_amount() == 0 && (__pulls_reasonable_to_buy_in_run contains it) && it != $item[11-leaf clover] && it != $item[none]) + url = "mall.php"; + + string title = pluralise(actual_amount, it); + if (max_wanted == 1) + title = it; + + pulls_entries.listAppend(ChecklistEntryMake(it, url, ChecklistSubentryMake(title, "", reason_list)).ChecklistEntrySetIDTag("Pull suggestions " + it.name)); + break; + } + } + } + + checklists.listAppend(ChecklistMake("Suggested Pulls", pulls_entries)); +} + +void PullsInit() +{ + //Pulls which are reasonable to buy in the mall, then pull: + __pulls_reasonable_to_buy_in_run = $items[peppermint parasol,slimy alveolus,bottle of blank-out,11-leaf clover,ninja rope,ninja crampons,ninja carabiner,clockwork maid,sonar-in-a-biscuit,knob goblin perfume,chrome ore,linoleum ore,asbestos ore,goat cheese,enchanted bean,dusty bottle of Marsala,dusty bottle of Merlot,dusty bottle of Muscat,dusty bottle of Pinot Noir,dusty bottle of Port,dusty bottle of Zinfandel,ketchup hound,lion oil,bird rib,stunt nuts,drum machine,beer helmet,distressed denim pants,bejeweled pledge pin,reinforced beaded headband,bullet-proof corduroys,round purple sunglasses,wand of nagamar,ng,star crossbow,star hat,star staff,star sword,Star key lime pie,Boris's key lime pie,Jarlsberg's key lime pie,Sneaky Pete's key lime pie,tomb ratchet,tangle of rat tails,swashbuckling pants,stuffed shoulder parrot,eyepatch,Knob Goblin harem veil,knob goblin harem pants,knob goblin elite polearm,knob goblin elite pants,knob goblin elite helm,cyclops eyedrops,mick's icyvapohotness inhaler,large box,marzipan skull,jabañero-flavored chewing gum,handsomeness potion,Meleegra™ pills,pickle-flavored chewing gum,lime-and-chile-flavored chewing gum,gremlin juice,wussiness potion,Mick's IcyVapoHotness Rub,super-spiky hair gel,adder bladder,black no. 2,skeleton,rock and roll legend,wet stew,glass of goat's milk,hot wing,frilly skirt,pygmy pygment,wussiness potion,gremlin juice,adder bladder,Angry Farmer candy,thin black candle,super-spiky hair gel,Black No. 2,Mick's IcyVapoHotness Rub,Frigid ninja stars,Spider web,Sonar-in-a-biscuit,Black pepper,Pygmy blowgun,Meat vortex,Chaos butterfly,Photoprotoneutron torpedo,Fancy bath salts,inkwell,Hair spray,disease,bronzed locust,Knob Goblin firecracker,powdered organs,leftovers of indeterminate origin,mariachi G-string,NG,plot hole,baseball,razor-sharp can lid,tropical orchid,stick of dynamite,barbed-wire fence,smut orc keepsake box,spooky-gro fertilizer,machetito,muculent machete,antique machete,rusty hedge trimmers,Ice Island Long Tea,killing jar,can of black paint,gravy boat,ring of conflict,bram's choker,duonoculars]; +} + + +void setUpExampleState() +{ + __misc_state["in run"] = true; + + //Do a default reset of each quest: + + foreach quest_name in __quest_state + { + QuestState state = __quest_state[quest_name]; + QuestStateParseMafiaQuestPropertyValue(state, "started"); + __quest_state[quest_name] = state; + } + + __misc_state_int["pulls available"] = 17; +} + + +//We call this twice - once at the start, once after __quest_state["Level 13"] becomes available. I would just call it once but that could break things? (very old code) +void computeFatLootTokens() +{ + int dd_tokens_and_keys_available = 0; + int tokens_needed = 0; + int keys_missing = 0; + boolean need_boris_key = true; + boolean need_jarlsberg_key = true; + boolean need_sneaky_pete_key = true; + + if ($item[boris\'s key].available_amount() > 0) + need_boris_key = false; + if ($item[jarlsberg\'s key].available_amount() > 0) + need_jarlsberg_key = false; + if ($item[sneaky pete\'s key].available_amount() > 0) + need_sneaky_pete_key = false; + + if (__quest_state["Level 13"].state_boolean["Sneaky Pete's key used"]) + need_sneaky_pete_key = false; + if (__quest_state["Level 13"].state_boolean["Boris's key used"]) + need_boris_key = false; + if (__quest_state["Level 13"].state_boolean["Jarlsberg's key used"]) + need_jarlsberg_key = false; + + if (need_boris_key) + tokens_needed += 1; + if (need_jarlsberg_key) + tokens_needed += 1; + if (need_sneaky_pete_key) + tokens_needed += 1; + + keys_missing = tokens_needed; + tokens_needed -= $item[fat loot token].available_amount(); + tokens_needed = MAX(0, tokens_needed); + + dd_tokens_and_keys_available += $item[fat loot token].available_amount(); + dd_tokens_and_keys_available += $item[boris\'s key].available_amount(); + dd_tokens_and_keys_available += $item[jarlsberg\'s key].available_amount(); + dd_tokens_and_keys_available += $item[sneaky pete\'s key].available_amount(); + + __misc_state_int["fat loot tokens needed"] = MAX(0, tokens_needed); + __misc_state_int["hero keys missing"] = keys_missing; + __misc_state_int["DD Tokens and keys available"] = dd_tokens_and_keys_available; +} + + +void setUpState() +{ + __misc_state.listClear(); + __last_adventure_location = get_property_location("lastAdventure"); + if (__misc_state["Example mode"]) + { + int wanted_index = random_safe($locations[].count()); + int i = 0; + foreach l in $locations[] + { + if (i == wanted_index) + { + __last_adventure_location = l; + break; + } + i += 1; + } + } + if (__setting_debug_mode && __setting_debug_enable_example_mode_in_aftercore && get_property_boolean("kingLiberated")) + { + __misc_state["Example mode"] = true; + } + + __misc_state["in aftercore"] = get_property_boolean("kingLiberated"); + //if (get_property_ascension("lastKingLiberation") && my_ascensions() != 0) + //__misc_state["in aftercore"] = true; + __misc_state["in run"] = !__misc_state["in aftercore"]; + if (__misc_state["Example mode"]) + __misc_state["in run"] = true; + __misc_state["In valhalla"] = (my_class().to_string() == "Astral Spirit"); + + __misc_state["in CS aftercore"] = __misc_state["in aftercore"] && get_property("csServicesPerformed").split_string(",").count() == 11; + + + int adventures_after_rollover = my_adventures() + 40; + if (my_path().id != PATH_SLOW_AND_STEADY) { + adventures_after_rollover += numeric_modifier("adventures"); + adventures_after_rollover += get_property_int("extraRolloverAdventures"); + } + adventures_after_rollover = MAX(adventures_after_rollover, 0); //Who knows? + int adventures_after_rollover_post_cap = MIN(adventures_after_rollover, 200); + __misc_state_int["adventures after rollover"] = adventures_after_rollover_post_cap; + __misc_state_int["adventures lost to rollover"] = adventures_after_rollover - adventures_after_rollover_post_cap; + + if (my_turncount() >= 30 && get_property_int("singleFamiliarRun") != -1) + __misc_state["single familiar run"] = true; + if ($item[Clan VIP Lounge key].available_amount() > 0 && !in_bad_moon() && my_path() != $path[Legacy of Loathing]) + __misc_state["VIP available"] = true; + boolean fax_available = false; + if (__misc_state["VIP available"]) + { + if (!get_property_boolean("_photocopyUsed")) + fax_available = true; + __misc_state["fax accessible"] = true; + } + + if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_TRENDY) + { + __misc_state["fax accessible"] = false; + } + if (!$item[deluxe fax machine].is_unrestricted()) + __misc_state["fax accessible"] = false; + + if (!__misc_state["fax accessible"]) + fax_available = false; + __misc_state["fax available"] = fax_available; + + __misc_state["fax equivalent accessible"] = __misc_state["fax available"]; + if (my_path().id == PATH_HEAVY_RAINS && $skill[rain man].skill_is_usable()) + __misc_state["fax equivalent accessible"] = true; + + if (__misc_state["VIP available"]) + { + int soaks_remaining = MAX(0, 5 - get_property_int("_hotTubSoaks")); + __misc_state_int["hot tub soaks remaining"] = soaks_remaining; + } + + __misc_state["can eat just about anything"] = true; + if (my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_ZOMBIE_SLAYER || fullness_limit() == 0 || my_path().id == PATH_VAMPIRE || my_path().id == PATH_YOU_ROBOT || my_path().id == PATH_GELATINOUS_NOOB) + { + __misc_state["can eat just about anything"] = false; + } + + __misc_state["can drink just about anything"] = true; + if (my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_KOLHS || my_path().id == PATH_LICENSE_TO_ADVENTURE || inebriety_limit() == 0 || my_path().id == PATH_VAMPIRE || my_path().id == PATH_YOU_ROBOT) + { + __misc_state["can drink just about anything"] = false; + } + + + __misc_state["can equip just about any weapon"] = true; + if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_WAY_OF_THE_SURPRISING_FIST) + { + __misc_state["can equip just about any weapon"] = false; + } + + + __misc_state["MMJs buyable"] = false; + if (get_property_ascension("lastGuildStoreOpen")) + { + if (my_class() == $class[pastamancer] || my_class() == $class[sauceror] || (my_class() == $class[accordion thief] && my_level() >= 9)) + __misc_state["MMJs buyable"] = true; + } + + //Check for moxie/mysticality/muscle combat skills: + + foreach s in $skills[] + { + if (!s.combat) + continue; + if (!s.skill_is_usable()) + continue; + if (s.class == $class[accordion thief] || s.class == $class[disco bandit]) + __misc_state["have moxie class combat skill"] = true; + if (s.class == $class[pastamancer] || s.class == $class[sauceror]) + __misc_state["have mysticality class combat skill"] = true; + if (s.class == $class[seal clubber] || s.class == $class[turtle tamer]) + __misc_state["have muscle class combat skill"] = true; + } + + + + boolean yellow_ray_available = false; + string yellow_ray_source = ""; + string yellow_ray_image_name = "__effect everything looks yellow"; + boolean yellow_ray_potentially_available = false; + + if (__iotms_usable[lookupItem("Eight Days a Week Pill Keeper")] && (!get_property_boolean("_freePillKeeperUsed") || spleen_limit() - my_spleen_use() >= 3)) + { //One of the shortest, but also one of the worst, since you activate it BEFORE a fight starts + yellow_ray_available = true; + yellow_ray_source = "pill keeper Explodinall"; + } + foreach source in $items[4766,5229,6673,7013] + { + if (!(source.available_amount() > 0 || (source == $item[4766] && $item[4761].available_amount() > 0))) + continue; + yellow_ray_available = true; + yellow_ray_source = source.to_string(); + yellow_ray_image_name = "__item " + source.to_string(); + } + if ($item[micronova].available_amount() > 0) + { + yellow_ray_available = true; + yellow_ray_source = "micronova"; + yellow_ray_image_name = "__item micronova"; + } + if ($item[viral video].available_amount() > 0) + { + yellow_ray_available = true; + yellow_ray_source = "viral video"; + yellow_ray_image_name = "__item viral video"; + } + + if ($item[mayo lance].available_amount() > 0 && get_property_int("mayoLevel") > 0) + { + yellow_ray_available = true; + yellow_ray_source = "Mayo Lance"; + yellow_ray_image_name = "__item mayo lance"; + } + if ($skill[Unleash Cowrruption].have_skill()) + { + yellow_ray_available = true; + yellow_ray_source = "Unleash Cowrruption"; + yellow_ray_image_name = "__skill Unleash Cowrruption"; + } + if ($familiar[Crimbo Shrub].familiar_is_usable() && get_property("shrubGifts") == "yellow" && !(my_daycount() == 1 && get_property("_shrubDecorated") == "false")) + { + yellow_ray_available = true; + yellow_ray_source = "Crimbo Shrub"; + yellow_ray_image_name = "__item DNOTC Box"; //uncertain + } + if (familiar_is_usable($familiar[nanorhino]) && __misc_state["have moxie class combat skill"] && get_property_int("_nanorhinoCharge") == 100) + { + yellow_ray_available = true; + yellow_ray_source = "Nanorhino"; + yellow_ray_image_name = "nanorhino"; + } + if (lookupItem("unwrapped knock-off retro superhero cape").have() && __iotms_usable[lookupItem("unwrapped knock-off retro superhero cape")]) + { + yellow_ray_available = true; + yellow_ray_source = "Superhero cape skill Unleash the Devil's Kiss"; + yellow_ray_source += get_property("retroCapeSuperhero") != "heck" || get_property("retroCapeWashingInstructions") != "kiss" ? " (Heck General + Kiss me)" : ""; + yellow_ray_source += !lookupItem("unwrapped knock-off retro superhero cape").equipped() ? " (equip first)" : ""; + yellow_ray_image_name = "__item unwrapped knock-off retro superhero cape"; + } + if ($skill[Ball Lightning].skill_is_usable() && my_path().id == PATH_HEAVY_RAINS && my_lightning() >= 5) + { + yellow_ray_available = true; + yellow_ray_source = "Ball Lightning"; + yellow_ray_image_name = "__skill Ball Lightning"; + } + if ($skill[wrath of ra].skill_is_usable() && my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + { + yellow_ray_available = true; + yellow_ray_source = "Wrath of Ra"; + yellow_ray_image_name = "__skill wrath of ra"; + } + if (familiar_is_usable($familiar[he-boulder])) + { + yellow_ray_available = true; + yellow_ray_source = "He-Boulder"; + yellow_ray_image_name = "he-boulder"; + } + if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && $skill[Flash Headlight].skill_is_usable() && get_property("peteMotorbikeHeadlight") == "Ultrabright Yellow Bulb") + { + yellow_ray_available = true; + yellow_ray_source = "Flash Headlight"; + yellow_ray_image_name = "__skill Easy Riding"; + } + if (lookupSkill("disintegrate").have_skill() && my_maxmp() >= 150) + { + yellow_ray_available = true; + yellow_ray_source = "Disintegrate"; + yellow_ray_image_name = "__skill Disintegrate"; + } + + if (yellow_ray_available) + yellow_ray_potentially_available = true; + + if (my_path().id == PATH_KOLHS) + yellow_ray_potentially_available = true; + + + if ($effect[Everything looks yellow].have_effect() > 0) + yellow_ray_available = false; + if (!yellow_ray_available) + yellow_ray_source = ""; + __misc_state["yellow ray available"] = yellow_ray_available; + __misc_state_string["yellow ray source"] = yellow_ray_source; + __misc_state_string["yellow ray image name"] = yellow_ray_image_name; + __misc_state["yellow ray potentially available"] = yellow_ray_potentially_available; + + + if (in_bad_moon() && !__misc_state["yellow ray potentially available"] && !__misc_state["yellow ray available"]) + { + __misc_state["yellow ray almost certainly impossible"] = true; + } + + __misc_state["can cook for free"] = false; + if (__campground[$item[chef-in-the-box]] > 0 || __campground[$item[clockwork chef-in-the-box]] > 0 || $effect[Inigo's Incantation of Inspiration].have_effect() >= 5) + __misc_state["can cook for free"] = true; + + + __misc_state["can bartend for free"] = false; + if (__campground[$item[bartender-in-the-box]] > 0 || __campground[$item[clockwork bartender-in-the-box]] > 0 || $effect[Inigo's Incantation of Inspiration].have_effect() >= 5) + __misc_state["can bartend for free"] = true; + + if ($skill[Rapid Prototyping].skill_is_usable() && get_property_int("_rapidPrototypingUsed") < 5) + { + __misc_state["can cook for free"] = true; + __misc_state["can bartend for free"] = true; + } + if (lookupSkill("Expert Corner-Cutter").skill_is_usable() && get_property_int("_expertCornerCutterUsed") < 5) + { + __misc_state["can cook for free"] = true; + __misc_state["can bartend for free"] = true; + } + + boolean free_runs_usable = true; + if (my_path().id == PATH_BIG || my_path().id == PATH_POCKET_FAMILIARS) //more like "combat items not usable" but + free_runs_usable = false; + __misc_state["free runs usable"] = free_runs_usable; + + boolean blank_outs_usable = true; + if (my_path().id == PATH_AVATAR_OF_JARLSBERG) + blank_outs_usable = false; + if (!free_runs_usable) + blank_outs_usable = false; + __misc_state["blank outs usable"] = free_runs_usable; + + // TODO: reconfig this whole state thing re: free runs. + boolean free_runs_available = false; + if (familiar_is_usable($familiar[pair of stomping boots]) || ($skill[the ode to booze].skill_is_usable() && familiar_is_usable($familiar[Frumious Bandersnatch]))) + free_runs_available = true; + if ($item[goto].available_amount() > 0 || $item[tattered scrap of paper].available_amount() > 0) + free_runs_available = true; + if ($item[greatest american pants].available_amount() > 0 || $item[navel ring of navel gazing].available_amount() > 0 || $item[peppermint parasol].available_amount() > 0) + free_runs_available = true; + if ($item[divine champagne popper].available_amount() > 0 || 2371.to_item().available_amount() > 0 || 7014.to_item().available_amount() > 0 || $item[handful of Smithereens].available_amount() > 0) + free_runs_available = true; + if ($item[V for Vivala mask].available_amount() > 0 && !get_property_boolean("_vmaskBanisherUsed")) + free_runs_available = true; + if ($item[replica V for Vivala mask].available_amount() > 0 && !get_property_boolean("_vmaskBanisherUsed")) + free_runs_available = true; + if (blank_outs_usable) + { + if ($item[bottle of Blank-Out].available_amount() > 0 || get_property_int("blankOutUsed") > 0) + free_runs_available = true; + } + if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE && $skill[Peel Out].skill_is_usable()) + { + + int total_free_peel_outs_available = 10; + if (get_property("peteMotorbikeTires") == "Racing Slicks") + total_free_peel_outs_available += 20; + int free_peel_outs_available = MAX(0, total_free_peel_outs_available - get_property_int("_petePeeledOut")); + if (free_peel_outs_available > 0) + free_runs_available = true; + } + if (my_path().id == PATH_HEAVY_RAINS && $skill[Lightning Strike].skill_is_usable()) + free_runs_available = true; + if (!free_runs_usable) + free_runs_available = false; + __misc_state["free runs available"] = free_runs_available; + + + string olfacted_monster = ""; + boolean some_olfact_available = false; + boolean some_reusable_olfact_available = false; + if ($skill[Transcendent Olfaction].skill_is_usable()) + { + some_olfact_available = true; + some_reusable_olfact_available = true; + olfacted_monster = get_property("olfactedMonster"); + } + if ($familiar[nosy nose].familiar_is_usable()) //weakened, but still relevant + { + some_olfact_available = true; + } + if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + { + some_olfact_available = true; + some_reusable_olfact_available = true; + } + __misc_state["have olfaction equivalent"] = some_olfact_available; + __misc_state_string["olfaction equivalent monster"] = olfacted_monster; + __misc_state["have reusable olfaction equivalent"] = some_reusable_olfact_available; + + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING || my_path().id == PATH_NUCLEAR_AUTUMN) + __misc_state["campground unavailable"] = true; + + boolean skills_temporarily_missing = false; + boolean familiars_temporarily_blocked = false; + boolean familiars_temporarily_missing = false; + if (in_bad_moon()) + { + skills_temporarily_missing = true; + familiars_temporarily_missing = true; + } + if (my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING || my_path().id == PATH_VAMPIRE) + { + skills_temporarily_missing = true; + familiars_temporarily_missing = true; + familiars_temporarily_blocked = true; + } + if (my_path().id == PATH_ZOMBIE_SLAYER) + { + skills_temporarily_missing = true; + } + if (my_path().id == PATH_CLASS_ACT || my_path().id == PATH_CLASS_ACT_2) + { + //not sure how mafia interprets "have_skill" under class act + skills_temporarily_missing = true; + } + if (my_path().id == PATH_TRENDY) + { + //not sure if this is correct + //skills_temporarily_missing = true; + //familiars_temporarily_missing = true; + } + if (my_path().id == PATH_AVATAR_OF_WEST_OF_LOATHING || my_path().id == PATH_NUCLEAR_AUTUMN || my_path().id == PATH_GELATINOUS_NOOB || my_path().id == PATH_G_LOVER) + { + skills_temporarily_missing = true; + } + if (my_path().id == PATH_LICENSE_TO_ADVENTURE || my_path().id == PATH_POCKET_FAMILIARS) + familiars_temporarily_blocked = true; + __misc_state["skills temporarily missing"] = skills_temporarily_missing; + __misc_state["familiars temporarily missing"] = familiars_temporarily_missing; + __misc_state["familiars temporarily blocked"] = familiars_temporarily_blocked; + + + __misc_state["AT skills available"] = true; + if (my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_ZOMBIE_SLAYER || ((my_path().id == PATH_CLASS_ACT || my_path().id == PATH_CLASS_ACT_2) && my_class() != $class[accordion thief])) + __misc_state["AT skills available"] = false; + + + __misc_state_float["Non-combat statgain multiplier"] = 1.0; + __misc_state_float["ML to mainstat multiplier"] = 1.0 / (2.0 * 3.0); + /*if (my_path().id == PATH_CLASS_ACT_2) + { + __misc_state_float["ML to mainstat multiplier"] = 1.0 / (2.0 * 2.0); + }*/ + if (false) + { + //this does not seem to be the case? FIXME spade please + __misc_state_float["Non-combat statgain multiplier"] = 0.5; + __misc_state["Stat gain from NCs reduced"] = false; + } + + int pulls_available = 0; + pulls_available = pulls_remaining(); + if (__setting_debug_mode && in_ronin()) + pulls_available = MAX(pulls_available, 4); + __misc_state_int["pulls available"] = pulls_available; + + //Calculate free rests available: + int rests_used = get_property_int("timesRested"); + int total_rests_available = total_free_rests(); + + __misc_state_int["total free rests possible"] = total_rests_available; + __misc_state_int["free rests remaining"] = MAX(total_rests_available - rests_used, 0); + + + //monster.monster_initiative() is usually what you need, but just in case: + __misc_state_float["init ML penalty"] = monsterExtraInitForML(monster_level_adjustment_ignoring_plants()); + + // Make a state variable re: zap wand ownership + __misc_state["zap wand owned"] = false; + + item zap_wand_owned; + + if (true) { + zap_wand_owned = $item[none]; + foreach wand in $items[aluminum wand,ebony wand,hexagonal wand,marble wand,pine wand] { + if (wand.available_amount() > 0) { + zap_wand_owned = wand; + break; + } + } + } + + if (zap_wand_owned != $item[none]) __misc_state["zap wand owned"] = true; + + int ngs_needed = 0; + + //stats: + + if (my_level() < 13 && !__misc_state["in aftercore"]) + { + __misc_state["need to level"] = true; + } + __misc_state["need to level muscle"] = false; + __misc_state["need to level mysticality"] = false; + __misc_state["need to level moxie"] = false; + + if (__misc_state["in run"]) + { + //62 muscle for antique machete/hidden hospital + //70 moxie, 70 mysticality for war outfits + if (my_primestat() == $stat[muscle] && __misc_state["need to level"]) + __misc_state["need to level muscle"] = true; + if (my_primestat() == $stat[mysticality] && __misc_state["need to level"]) + __misc_state["need to level mysticality"] = true; + if (my_primestat() == $stat[moxie] && __misc_state["need to level"]) + __misc_state["need to level moxie"] = true; + + if (my_basestat($stat[muscle]) < 62) + __misc_state["need to level muscle"] = true; + if (my_basestat($stat[mysticality]) < 70) + __misc_state["need to level mysticality"] = true; + if (my_basestat($stat[moxie]) < 70) + __misc_state["need to level moxie"] = true; + } + + //wand + + boolean wand_of_nagamar_needed = true; + if (my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_BUGBEAR_INVASION || my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_KOLHS || my_path().id == PATH_HEAVY_RAINS || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING || my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_THE_SOURCE || my_path().id == PATH_LICENSE_TO_ADVENTURE || my_path().id == PATH_POCKET_FAMILIARS || my_path().id == PATH_VAMPIRE || my_path().id == PATH_GREY_GOO || my_path().id == PATH_YOU_ROBOT || my_path().id == PATH_FALL_OF_THE_DINOSAURS || my_path().id == PATH_AVATAR_OF_SHADOWS_OVER_LOATHING || my_path().id == PATH_WEREPROFESSOR) + wand_of_nagamar_needed = false; + + int ruby_w_needed = 1; + int metallic_a_needed = 1; + int lowercase_n_needed = 1; + int heavy_d_needed = 1; + int [string] letters_needed; + letters_needed["w"] = 1; + letters_needed["a"] = 1; + letters_needed["n"] = 1; + letters_needed["d"] = 1; + letters_needed["g"] = 0; + + int [string] letters_available; + letters_available["w"] = $item[ruby w].available_amount() + $item[wa].available_amount(); + letters_available["a"] = $item[metallic a].available_amount() + $item[wa].available_amount(); + letters_available["n"] = $item[lowercase n].available_amount() + $item[nd].available_amount() + $item[ng].available_amount(); + letters_available["d"] = $item[heavy d].available_amount() + $item[nd].available_amount(); + letters_needed["n"] += ngs_needed; + letters_needed["g"] += ngs_needed; + + if ($item[wand of nagamar].available_amount() > 0) + wand_of_nagamar_needed = false; + + if (my_path().id == PATH_SEA) wand_of_nagamar_needed = false; + + if (!wand_of_nagamar_needed) + { + letters_needed["w"] -= 1; + letters_needed["a"] -= 1; + letters_needed["n"] -= 1; + letters_needed["d"] -= 1; + } + + letters_needed["w"] = MAX(0, letters_needed["w"] - letters_available["w"]); + letters_needed["a"] = MAX(0, letters_needed["a"] - letters_available["a"]); + letters_needed["n"] = MAX(0, letters_needed["n"] - letters_available["n"]); + letters_needed["d"] = MAX(0, letters_needed["d"] - letters_available["d"]); + + __misc_state["wand of nagamar needed"] = wand_of_nagamar_needed; + __misc_state_int["ruby w needed"] = letters_needed["w"]; + __misc_state_int["metallic a needed"] = letters_needed["a"]; + __misc_state_int["lowercase n needed"] = letters_needed["n"]; + __misc_state_int["lowercase n available"] = letters_available["n"]; + __misc_state_int["heavy d needed"] = letters_needed["d"]; + __misc_state_int["original g needed"] = letters_needed["g"]; + + + computeFatLootTokens(); + + boolean mysterious_island_unlocked = false; + if ($items[dingy dinghy, skeletal skiff].available_amount() > 0) //junk junk requires completing the quest first + mysterious_island_unlocked = true; + + if (get_property("peteMotorbikeGasTank") == "Extra-Buoyant Tank") + mysterious_island_unlocked = true; + if (get_property_ascension("lastIslandUnlock")) + mysterious_island_unlocked = true; + if (my_path().id == PATH_EXPLOSION) + mysterious_island_unlocked = true; //kinda + + __misc_state["mysterious island available"] = mysterious_island_unlocked; + + __misc_state["desert beach available"] = false; + if (get_property("peteMotorbikeGasTank") == "Large Capacity Tank") + __misc_state["desert beach available"] = true; + if (get_property_ascension("lastDesertUnlock")) + __misc_state["desert beach available"] = true; + if ($location[south of the border].locationAvailable()) + __misc_state["desert beach available"] = true; + if ($locations[The Shore\, Inc. Travel Agency,the arid\, extra-dry desert,the oasis, south of the border].turnsAttemptedInLocation() > 0) //weird issues with detecting the beach. check if we've ever adventured there as a back-up + __misc_state["desert beach available"] = true; + if (my_path().id == PATH_EXPLOSION) + __misc_state["desert beach available"] = true; + + string ballroom_song = ""; + if (get_property_ascension("lastQuartetAscension")) + { + //1 and 3 are a guess + if (get_property("lastQuartetRequest") == "1") + { + ballroom_song = "+ML"; + } + else if (get_property("lastQuartetRequest") == "2") + { + ballroom_song = "-combat"; + } + else if (get_property("lastQuartetRequest") == "3") + { + ballroom_song = "+item"; + } + } + __misc_state_string["ballroom song"] = ballroom_song; + + __misc_state["Torso aware"] = false; + if ($skill[12].skill_is_usable() || $skill[Best Dressed].skill_is_usable()) // Torso Aware(g)ness + __misc_state["Torso aware"] = true; + + int hipster_fights_used = get_property_int("_hipsterAdv"); + if (hipster_fights_used < 0) hipster_fights_used = 0; + if (hipster_fights_used > 7) hipster_fights_used = 7; + + if (familiar_is_usable($familiar[artistic goth kid])) //goth kid has crayon shavings, which help survivability, though it has that weirdness with early runaways (have to defeat a monster first) + { + __misc_state_string["hipster name"] = "goth kid"; + __misc_state_int["hipster fights available"] = 7 - hipster_fights_used; + __misc_state["have hipster"] = true; + } + else if (familiar_is_usable($familiar[Mini-Hipster])) + { + __misc_state_string["hipster name"] = "hipster"; + __misc_state_int["hipster fights available"] = 7 - hipster_fights_used; + __misc_state["have hipster"] = true; + } + __misc_state_string["obtuse angel name"] = ""; + if (familiar_is_usable($familiar[reanimated reanimator])) + __misc_state_string["obtuse angel name"] = "Reanimated Reanimator"; + else if (familiar_is_usable($familiar[obtuse angel])) + __misc_state_string["obtuse angel name"] = "Obtuse Angel"; + + if (get_property_ascension("lastPlusSignUnlock")) + __misc_state["dungeons of doom unlocked"] = true; + else + __misc_state["dungeons of doom unlocked"] = false; + + __misc_state["can use clovers"] = true; + if (in_bad_moon() && $item[11-leaf clover].available_amount() == 0) + __misc_state["can use clovers"] = false; + + + __misc_state["bookshelf accessible"] = true; + if (my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) + __misc_state["bookshelf accessible"] = false; + + + __misc_state["can pickpocket"] = false; + if (my_class() == $class[disco bandit] || my_class() == $class[accordion thief] || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || $item[tiny black hole].equipped_amount() > 0 || $effect[Form of...Bird!].have_effect() > 0) + __misc_state["can pickpocket"] = true; + + if (CounterLookup("Romantic Monster").CounterExists() || get_property_int("_romanticFightsLeft") > 0) + __misc_state_string["Romantic Monster Name"] = get_property("romanticTarget").HTMLEscapeString(); + + //Moxie Experience Percent + float dance_card_average_stat_gain = MIN(2.25 * my_basestat($stat[moxie]), 300.0) * __misc_state_float["Non-combat statgain multiplier"] * (1.0 + numeric_modifier("Moxie Experience Percent") / 100.0); + __misc_state_float["dance card average stats"] = dance_card_average_stat_gain; + + //don't know if there's any way to query this information directly, so indirectly calculate it from scaling monsters in the area: + __misc_state_int["Basement Floor"] = MAX(1, round(powf(MAX(0.0, ($monster[Ghost of Fernswarthy's Grandfather].raw_defense - monster_level_adjustment()).to_float() / 2.0), 5.0 / 7.0))); + + if (true) + { + //calculate if we need -combat sources: + int minus_combat_source_count = 0; + int minus_combat_from_accessories = 0; + + foreach it in __minus_combat_equipment + { + if (!(it.can_equip() && it.available_amount() > 0)) + continue; + if (it == $item[none]) + continue; + if (it == $item[over-the-shoulder folder holder]) + { + } + int value = -it.numeric_modifier("combat rate"); + if ($slots[acc1,acc2,acc3] contains it.to_slot()) + minus_combat_from_accessories += value; + else + minus_combat_source_count += value; + } + if ($item[over-the-shoulder folder holder].available_amount() > 0) + { + //check if we have the -combat folder: + boolean [item] equipped_folders; + foreach s in $slots[folder1,folder2,folder3,folder4,folder5] + { + equipped_folders[s.equipped_item()] = true; + } + if (!(equipped_folders contains $item[folder (Ex-Files)])) + { + if (equipped_folders contains $item[folder (skull and crossbones)]) + { + minus_combat_from_accessories += 5; + } + } + } + + minus_combat_source_count += MIN(3 * 5, minus_combat_from_accessories); //three at most + + if ($skill[smooth movement].skill_is_usable()) + minus_combat_source_count += 5; + if ($skill[the sonata of sneakiness].skill_is_usable()) + minus_combat_source_count += 5; + if ($items[crown of thrones,buddy bjorn].available_amount() > 0 && $familiar[grimstone golem].have_familiar() && !__misc_state["familiars temporarily blocked"]) + minus_combat_source_count += 5; + if (my_path().id == PATH_AVATAR_OF_BORIS && $skill[song of solitude].skill_is_usable()) + minus_combat_source_count += 5 * 4; + if (my_path().id == PATH_ZOMBIE_SLAYER && $skill[disquiet riot].skill_is_usable()) + minus_combat_source_count += 5 * 4; + if (my_path().id == PATH_AVATAR_OF_JARLSBERG && $skill[chocolatesphere].skill_is_usable()) + minus_combat_source_count += 5 * 3; + if (__iotms_usable[lookupItem("Asdon Martin keyfob")]) + minus_combat_source_count += 10; + if (my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) + { + if ($skill[Brood].skill_is_usable()) + minus_combat_source_count += 5 * 2; + if (get_property("peteMotorbikeMuffler") == "Extra-Quiet Muffler" && $skill[Rev Engine].skill_is_usable()) + minus_combat_source_count += 5 * 3; + } + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + { + if ($skill[Shelter of Shed].have_skill()) + minus_combat_source_count += 5 * 4; + } + if (minus_combat_source_count >= 25) + __misc_state["can reasonably reach -25% combat"] = true; + } + if (my_path().id == PATH_LIVE_ASCEND_REPEAT) + __misc_state["can reasonably reach -25% combat"] = true; + + if (!in_bad_moon() && $item[hand turkey outline].is_unrestricted()) + { + foreach s in $strings[spooky,sleaze,hot,cold,stench] + { + if (get_property_boolean(s + "AirportAlways") || get_property_boolean("_" + s + "AirportToday")) + __misc_state[s + " airport available"] = true; + } + } + + if (get_property_boolean("chateauAvailable") && !in_bad_moon() && $item[Chateau Mantegna room key].is_unrestricted()) { + __misc_state["Chateau Mantegna available"] = true; + __misc_state_string["resting url Chateau Mantegna"] = "place.php?whichplace=chateau"; + } + + // you can also use the chateau in LoL, if you have it + if (get_property_boolean("chateauAvailable") && my_path() == $path[Legacy of Loathing]) { + __misc_state["Chateau Mantegna available"] = true; + __misc_state_string["resting url Chateau Mantegna"] = "place.php?whichplace=chateau"; + } + + if (get_property_boolean("getawayCampsiteUnlocked") && !in_bad_moon() && $item[Distant Woods Getaway Brochure].is_unrestricted()) { + __misc_state["Getaway Campsite available"] = true; + __misc_state_string["resting url Getaway Campsite"] = "place.php?whichplace=campaway"; + } + + + __misc_state_string["resting url campsite"] = "campground.php"; + + + //Calculate how much HP/MP will be gained if resting at your campground + float resting_hp_percent = numeric_modifier("resting hp percent") / 100.0; + float resting_mp_percent = numeric_modifier("resting mp percent") / 100.0; + + //FIXME trace down every rest effect and make this more accurate, instead of an initial guess. + + //If grimace or ronald is full, they double the gains of everything else. + //This is reported as a modifier of +100% - so with pagoda, that's +200% HP + //But, it's actually +300%, or 400% total. I could be wrong about this - my knowledge of rest mechanics is limited. + //So, we'll explicitly check for grimace or ronald being full, then recalculate. Not great, but should work okay? + //This is probably inaccurate in a great number of cases, due to the complication of resting. + + float overall_multiplier_hp = 1.0; + float overall_multiplier_mp = 1.0; + float bonus_resting_hp = numeric_modifier("bonus resting hp"); + float after_bonus_resting_hp = 0.0; + int grimace_light = moon_phase() / 2; + int ronald_light = moon_phase() % 8; + if (grimace_light == 4) { + resting_hp_percent -= 1.0; + overall_multiplier_hp += 1.0; + } + if (ronald_light == 4) { + resting_mp_percent -= 1.0; + overall_multiplier_mp += 1.0; + } + + if ($effect[L'instinct Félin].have_effect() > 0) { //not currently tracked by mafia. Seems to triple HP/MP gains. + overall_multiplier_hp *= 3.0; + overall_multiplier_mp *= 3.0; + } + + if (__campground contains $item[gauze hammock]) { + //Gauze hammock appears to be a flat addition applied after everything else, including grimace, pagoda, and l'instinct. + //It shows up it bonus resting hp - we'll remove that, and add it back at the end. + bonus_resting_hp -= 60.0; + after_bonus_resting_hp += 60.0; + } + + __misc_state_int["rest hp restore"] = after_bonus_resting_hp + overall_multiplier_hp * (numeric_modifier("base resting hp") * (1.0 + resting_hp_percent) + bonus_resting_hp); + __misc_state_int["rest mp restore"] = overall_multiplier_mp * (numeric_modifier("base resting mp") * (1.0 + resting_mp_percent) + numeric_modifier("bonus resting mp")); + + + if (__misc_state["Chateau Mantegna available"] && get_property_boolean("restUsingChateau")) { + __misc_state_string["resting url"] = __misc_state_string["resting url Chateau Mantegna"]; + __misc_state_string["resting description"] = "Chateau Mantegna"; + __misc_state["recommend resting at campsite"] = false; + } else if (__misc_state["Getaway Campsite available"] && get_property_boolean("restUsingCampAwayTent")) { + __misc_state_string["resting url"] = __misc_state_string["resting url Getaway Campsite"]; + __misc_state_string["resting description"] = "Getaway Campsite"; + __misc_state["recommend resting at campsite"] = false; + } else { + __misc_state_string["resting url"] = __misc_state_string["resting url campsite"]; + __misc_state_string["resting description"] = "your campsite"; + __misc_state["recommend resting at campsite"] = true; + } + + if (!__misc_state["recommend resting at campsite"]) { //chance of redemption + boolean still_have_reason_to_rest_at_campsite = __resting_bonuses.count() > 0 || __misc_state_int["rest hp restore"] > 250 || __misc_state_int["rest mp restore"] > 125; + __misc_state["recommend resting at campsite"] = still_have_reason_to_rest_at_campsite; + } + + + + if ($classes[seal clubber,turtle tamer] contains my_class()) + __misc_state["guild open"] = QuestState("questG09Muscle").finished; + else if ($classes[pastamancer,sauceror] contains my_class()) + __misc_state["guild open"] = QuestState("questG07Myst").finished; + else if ($classes[disco bandit,accordion thief] contains my_class()) + __misc_state["guild open"] = QuestState("questG08Moxie").finished; + if (guild_store_available()) + __misc_state["guild open"] = true; + + + __misc_state["muscle guild store available"] = false; + __misc_state["mysticality guild store available"] = false; + __misc_state["moxie guild store available"] = false; + if (guild_store_available()) + { + if ($classes[seal clubber, turtle tamer] contains my_class()) + __misc_state["muscle guild store available"] = true; + if ($classes[pastamancer, sauceror] contains my_class()) + __misc_state["mysticality guild store available"] = true; + if ($classes[disco bandit,accordion thief] contains my_class()) + __misc_state["moxie guild store available"] = true; + + if (my_class() == $class[accordion thief] && my_level() >= 9) + { + __misc_state["muscle guild store available"] = true; + __misc_state["mysticality guild store available"] = true; + } + } + + __misc_state["can purchase magical mystery juice"] = __misc_state["mysticality guild store available"]; + __misc_state["have some reasonable way of restoring MP"] = false; + + if (__misc_state["can purchase magical mystery juice"] || black_market_available() || dispensary_available() || true) + __misc_state["have some reasonable way of restoring MP"] = true; + + if (my_path().id == PATH_ONE_CRAZY_RANDOM_SUMMER) + __misc_state["monsters can be nearly impossible to kill"] = true; + + int tonic_price = $item[Doc Galaktik's Invigorating Tonic].npc_price(); + if (tonic_price == 0) + tonic_price = 90; //wrong, but w/e + __misc_state_float["meat per MP"] = tonic_price.to_float() / 10.0; + + float soda_cost = -1.0; + if (black_market_available()) + soda_cost = $item[black cherry soda].npc_price(); + else if (dispensary_available()) + soda_cost = $item[knob goblin seltzer].npc_price(); + else if (!in_ronin()) //can't buy from NPC, so have to use mall price: + soda_cost = 100; //$item[knob goblin seltzer].mall_price(); //don't issue a mall search, we don't need it + + if (soda_cost > 0.0) + { + __misc_state_float["meat per MP"] = MIN(__misc_state_float["meat per MP"], soda_cost / 10.0); + } + + if (__misc_state["can purchase magical mystery juice"]) + { + float juice_cost = $item[magical mystery juice].npc_price(); + float mp_restored = 5.0 + my_level().to_float() * 1.5; + + if (juice_cost > 0.0) + __misc_state_float["meat per MP"] = MIN(__misc_state_float["meat per MP"], juice_cost / mp_restored); + } + + //FIXME all avatar paths: + if (my_path().id == PATH_GELATINOUS_NOOB || my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_AVATAR_OF_BORIS || my_path().id == PATH_AVATAR_OF_JARLSBERG || my_path().id == PATH_KOLHS || my_path().id == PATH_CLASS_ACT_2 || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING || my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_THE_SOURCE || my_path().id == PATH_EXPLOSIONS) + __misc_state["sea access blocked"] = true; + +} + + +void setUpQuestStateViaMafia() +{ + QuestsInit(); + SetsInit(); + + foreach key, function_name in __init_functions + call function_name(); + + //Opening guild quest + if (true) + { + //??? + QuestState state; + state.startable = true; + } +} + + +void finaliseSetUpState() +{ + //done after quest parsing + + if (__misc_state["Example mode"]) + { + __misc_state["need to level"] = true; + if (my_primestat() == $stat[muscle]) + __misc_state["need to level muscle"] = true; + if (my_primestat() == $stat[mysticality]) + __misc_state["need to level mysticality"] = true; + if (my_primestat() == $stat[moxie]) + __misc_state["need to level moxie"] = true; + } + + if (__misc_state_int["pulls available"] > 0) + { + PullsInit(); + } + computeFatLootTokens(); + + finaliseSetUpFloristState(); +} + +void setUpQuestState() +{ + if (__misc_state["In valhalla"]) + return; + setUpQuestStateViaMafia(); +} + + +void generateMissingItems(Checklist [int] checklists) +{ + ChecklistEntry [int] items_needed_entries; + + if (!__misc_state["in run"]) + return; + if (my_path().id == PATH_COMMUNITY_SERVICE) + return; + + //thought about using getClickableURLForLocationIfAvailable for these, but our location detection is very poor, and there are corner cases regardless + + if (__misc_state["wand of nagamar needed"]) { + ChecklistSubentry [int] subentries; + + subentries.listAppend(ChecklistSubentryMake("Wand of Nagamar", "", "")); + + Record WandComponentSource { + item component; + int drop_rate; + monster monster_dropped_from; + location location_dropped_from; + }; + void listAppend(WandComponentSource [int] list, WandComponentSource entry) { + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; + } + + WandComponentSource [int] component_sources; + + if (__misc_state_int["ruby w needed"] > 0) { + WandComponentSource source; + source.component = $item[ruby w]; + source.drop_rate = 30; + source.monster_dropped_from = $monster[W imp]; + if (__quest_state["Level 6"].finished) + source.location_dropped_from = $location[Pandamonium Slums]; + else + source.location_dropped_from = $location[the dark neck of the woods]; + component_sources.listAppend(source); + } + + if (__misc_state_int["metallic a needed"] > 0) { + WandComponentSource source; + source.component = $item[metallic a]; + source.drop_rate = 30; + source.monster_dropped_from = $monster[MagiMechTech MechaMech]; + source.location_dropped_from = $location[The Penultimate Fantasy Airship]; + component_sources.listAppend(source); + } + + if (__misc_state_int["lowercase n needed"] > 0 && __misc_state_int["lowercase n available"] == 0) { + WandComponentSource source; + source.component = $item[lowercase n]; + source.drop_rate = 30; + source.monster_dropped_from = $monster[XXX pr0n]; + source.location_dropped_from = $location[The Valley of Rof L\'m Fao]; + component_sources.listAppend(source); + } + + if (__misc_state_int["heavy d needed"] > 0) { + WandComponentSource source; + source.component = $item[heavy d]; + source.drop_rate = 40; + source.monster_dropped_from = $monster[Alphabet Giant]; + source.location_dropped_from = $location[The Castle in the Clouds in the Sky (Basement)]; + component_sources.listAppend(source); + } + + foreach key, source in component_sources { + if (source.component.available_amount() > 0) + continue; + string modifier_text = ""; + if (!in_bad_moon()) + modifier_text = "Clover or "; + if (source.drop_rate > 0 && source.drop_rate < 100) { + int drop_rate_inverse = ceil(100.0 / source.drop_rate.to_float() * 100.0 - 100.0); + modifier_text += "+" + drop_rate_inverse + "% item"; + } + + string [int] description; + if (!in_bad_moon()) + description.listAppend("Clover the castle basement."); + description.listAppend(source.monster_dropped_from + " - " + source.location_dropped_from + " - " + source.drop_rate + "% drop"); + subentries.listAppend(ChecklistSubentryMake(source.component, modifier_text, description)); + } + + if (subentries.count() == 1) + subentries[0].entries.listAppend("Can create it."); + else if (!__misc_state["can use clovers"]) + subentries[0].entries.listAppend("Either meatpaste together, or find after losing to the naughty sorceress. (" + (in_bad_moon() ? "probably faster" : "usually slower") + ")"); + + ChecklistEntry entry = ChecklistEntryMake("__item wand of nagamar", $location[the castle in the clouds in the sky (basement)].getClickableURLForLocation(), subentries); + entry.tags.id = "Wand of Nagamar reminder"; + entry.should_indent_after_first_subentry = true; + + items_needed_entries.listAppend(entry); + } + + if (my_path().id != PATH_LOW_KEY_SUMMER) //keys are in their own section in this path + SLevel13DoorGenerateMissingItems(items_needed_entries); + + if ($item[lord spookyraven\'s spectacles].available_amount() == 0 && __quest_state["Level 11 Manor"].state_boolean["Can use fast route"] && !__quest_state["Level 11 Manor"].finished) + items_needed_entries.listAppend(ChecklistEntryMake("__item lord spookyraven's spectacles", $location[the haunted bedroom].getClickableURLForLocation(), ChecklistSubentryMake("Lord Spookyraven's spectacles", "", "Found in Haunted Bedroom")).ChecklistEntrySetIDTag("Lord spookyraven spectacles reminder")); + + if ($item[enchanted bean].available_amount() == 0 && !__quest_state["Level 10"].state_boolean["beanstalk grown"]) { + items_needed_entries.listAppend(ChecklistEntryMake("__item enchanted bean", $location[The Beanbat Chamber].getClickableURLForLocation(), ChecklistSubentryMake("Enchanted bean", "", "Found in the beanbat chamber.")).ChecklistEntrySetIDTag("Enchanted bean reminder")); + } + + if (__quest_state["Level 13"].state_boolean["shadow will need to be defeated"]) { + //Let's see + //5 gauze garters + filthy poultices + //Or... + //red pixel potion (not worth farming, but if they have it...) + //red potion + //extra-strength red potion (they might find it) + + } + if (__quest_state["Level 11 Palindome"].state_boolean["Need instant camera"]) { + item camera = 7266.to_item(); + if (camera != $item[none]) { + if (my_path().id != PATH_SEA) items_needed_entries.listAppend(ChecklistEntryMake("__item " + camera, $location[the haunted bedroom].getClickableURLForLocation(), ChecklistSubentryMake("Disposable instant camera", "", "Found in the Haunted Bedroom.")).ChecklistEntrySetIDTag("Instant camera reminder")); + } + } + + if ($item[electric boning knife].available_amount() == 0 && __quest_state["Level 13"].state_boolean["wall of bones will need to be defeated"] && my_path().id != PATH_POCKET_FAMILIARS) { + string [int] description; + description.listAppend("Found from an NC on the ground floor of the castle in the clouds in the sky."); + boolean can_towerkill = false; + if ($skill[garbage nova].skill_is_usable()) { + description.listAppend("Ignore this, you can towerkill with Garbage Nova."); + can_towerkill = true; + } else if (!in_bad_moon()) + description.listAppend("Or towerkill."); + if (!can_towerkill && !__quest_state["Level 13"].state_boolean["past tower level 2"] && $location[the castle in the clouds in the sky (top floor)].locationAvailable()) + description.listAppend("Don't collect this right now; wait until you're at the wall of bones.|(probability of appearing increases)"); + items_needed_entries.listAppend(ChecklistEntryMake("__item electric boning knife", $location[the castle in the clouds in the sky (ground floor)].getClickableURLForLocation(), ChecklistSubentryMake("Electric boning knife", "-combat", description)).ChecklistEntrySetIDTag("Electric boning knife reminder")); + } + if ($item[beehive].available_amount() == 0 && __quest_state["Level 13"].state_boolean["wall of skin will need to be defeated"] && my_path().id != PATH_POCKET_FAMILIARS) { + string [int] description; + + description.listAppend("Found from an NC in the black forest."); + + if (get_property_int("blackForestProgress") >= 1) + description.listAppend(listMake("Head toward the blackberry patch", "Head toward the buzzing sound", "Keep going", "Almost... there...").listJoinComponents(__html_right_arrow_character)); + else + description.listAppend("Not available yet."); + if (!in_bad_moon()) + description.listAppend("Or towerkill."); + + items_needed_entries.listAppend(ChecklistEntryMake("__item beehive", $location[the black forest].getClickableURLForLocation(), ChecklistSubentryMake("Beehive", "-combat", description)).ChecklistEntrySetIDTag("Beehive reminder")); + } + + if (!__quest_state["Level 13"].state_boolean["past races"]) { + ChecklistSubentry subentry = ChecklistSubentryMake("Sources", "", "For the lair races."); + string [int] sources; + if (!__quest_state["Level 13"].state_boolean["Init race completed"]) { + subentry.modifiers.listAppend("+init"); + sources.listAppend("init"); + //subentries.listAppend(ChecklistSubentryMake("+init sources", "+init", "For the lair races.")); + } + if (!__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "") { + // + subentry.modifiers.listAppend("+" + __quest_state["Level 13"].state_string["Stat race type"]); + sources.listAppend(__quest_state["Level 13"].state_string["Stat race type"]); + } + if (!__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && __quest_state["Level 13"].state_string["Elemental damage race type"] != "") { + // + string type = __quest_state["Level 13"].state_string["Elemental damage race type"]; + string type_class = "r_element_" + type + "_desaturated"; + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+" + type + " damage", type_class)); + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+" + type + " spell damage", type_class)); + sources.listAppend(type); + } + string [int] relevant_elements; + foreach s in $strings[nsChallenge3,nsChallenge4,nsChallenge5] { + element e = get_property_element(s); + if (e == $element[none]) continue; + if (numeric_modifier(e + " resistance") >= 7) + continue; + string type_class = "r_element_" + e; + string type_class_desaturated = "r_element_" + e + "_desaturated"; + relevant_elements.listAppend(HTMLGenerateSpanOfClass("+" + e, type_class) + " resistance"); + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("+" + e, type_class_desaturated) + " res"); + } + if (relevant_elements.count() > 0) + subentry.entries.listAppend(relevant_elements.listJoinComponents(", ", "and").capitaliseFirstLetter() + " for the hedge maze."); + + subentry.header = sources.listJoinComponents(", ", "and").capitaliseFirstLetter() + " sources"; + if (subentry.modifiers.count() > 0) + items_needed_entries.listAppend(ChecklistEntryMake("__item vial of patchouli oil", "", subentry).ChecklistEntrySetIDTag("NS lair pre-door challenges reminder")); + } + + checklists.listAppend(ChecklistMake("Required Items", items_needed_entries)); +} + + +void generateTasks(Checklist [int] checklists) +{ + ChecklistEntry [int] task_entries; + + ChecklistEntry [int] optional_task_entries; + + ChecklistEntry [int] future_task_entries; + + QuestsGenerateTasks(task_entries, optional_task_entries, future_task_entries); + SetsGenerateTasks(task_entries, optional_task_entries, future_task_entries); + + checklists.listAppend(ChecklistMake("Tasks", task_entries)); + checklists.listAppend(ChecklistMake("Optional Tasks", optional_task_entries)); + checklists.listAppend(ChecklistMake("Future Tasks", future_task_entries)); +} +/* +Random notes: +-Having both a torch and mining helmet equipped will drop items from both, but not sure if at the same time. + +Relevant URLs: +http://forums.kingdomofloathing.com/vb/showthread.php?p=4721915#post4721915 +http://forums.kingdomofloathing.com/vb/showthread.php?p=4713383#post4713383 +http://forums.kingdomofloathing.com/vb/showthread.php?p=4717434#post4717434 +http://forums.kingdomofloathing.com/vb/showthread.php?p=4730373#post4730373 +http://forums.kingdomofloathing.com/vb/showpost.php?p=4749602&postcount=19 +*/ + +//should we record spelunkyUpgrades here? may not use them +Record SpelunkingStatus +{ + boolean [location] areas_unlocked; + boolean altar_unlocked; + boolean noncombat_due_next_adventure; + boolean sticky_bombs_unlocked; + int turns_left; + int gold; + int bombs; + int ropes; + int keys; + int sacrifices; + string buddy; +}; + +location SpelunkingLookupLocationStatusName(string entry) +{ + if (entry == "Burial Ground") + return $location[The Ancient Burial Ground]; + if (entry == "LOLmec's Lair") + return $location[LOLmec's Lair]; + if (entry == "Hell") + return $location[Hell]; + if (entry == "Yomama's Throne") + return $location[Yomama's Throne]; + return ("The " + entry).to_location(); +} + +SpelunkingStatus SpelunkingParseStatus() +{ + //spelunkyStatus(user, now 'Turns: 3, Gold: 150, Bombs: 2, Ropes: 0, Keys: 0, Buddy: A Helpful Guy, Unlocks: , Jungle, Burial Ground, Spider Hole, Sticky Bombs', default ) + //spelunkyStatus(user, now 'Turns: 10, Gold: 209, Bombs: 6, Ropes: 3, Keys: 0, Buddy: , Unlocks: Jungle, Ice Caves, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit, Snake Pit', default ) + SpelunkingStatus spelunking_status; + spelunking_status.areas_unlocked[$location[The Mines]] = true; + + boolean past_unlocks = false; + string [int] status_split = get_property("spelunkyStatus").split_string(", "); + + spelunking_status.sacrifices = get_property_int("spelunkySacrifices"); + foreach key, entry in status_split + { + if (entry == "Non-combat Due") + { + spelunking_status.noncombat_due_next_adventure = true; + continue; + } + if (entry.stringHasPrefix("Unlocks:")) + { + past_unlocks = true; + entry = entry.replace_string("Unlocks: ", ""); + } + if (past_unlocks) + { + if (entry == "Sticky Bombs") //this is treated as an "Unlocks" + spelunking_status.sticky_bombs_unlocked = true; + else if (entry == "Altar") + spelunking_status.altar_unlocked = true; + else + { + location l = SpelunkingLookupLocationStatusName(entry); + if (l != $location[none]) + spelunking_status.areas_unlocked[l] = true; + } + } + + if (entry.contains_text(": ")) + { + string [int] split_entry = entry.split_string(": "); //hopefully, there isn't one that has a : inside of it... FIXME + if (split_entry.count() < 2) + continue; + string header = split_entry[0]; + if (header == "Turns") + spelunking_status.turns_left = split_entry[1].to_int_silent(); + else if (header == "Gold") + spelunking_status.gold = split_entry[1].to_int_silent(); + else if (header == "Bombs") + spelunking_status.bombs = split_entry[1].to_int_silent(); + else if (header == "Ropes") + spelunking_status.ropes = split_entry[1].to_int_silent(); + else if (header == "Keys") + spelunking_status.keys = split_entry[1].to_int_silent(); + else if (header == "Buddy") + spelunking_status.buddy = split_entry[1].replace_string("A ", ""); + else + { + if (__setting_debug_mode) + { + print_html("Unknown entry type \"" + entry + "\""); + } + } + } + } + return spelunking_status; +} + +void SpelunkingGenerateNCInformation(SpelunkingStatus spelunking_status, ChecklistEntry [int] task_entries, ChecklistEntry [int] future_task_entries) +{ + + ChecklistEntry entry; + entry.image_lookup_name = "__item sunken chest"; + entry.tags.id = "Spelunky mode general NC info"; + entry.should_indent_after_first_subentry = true; + + string first_entry_title = ""; + boolean very_important = false; + if (spelunking_status.noncombat_due_next_adventure) + { + very_important = true; + first_entry_title = "Non-combat next adventure"; + entry.url = "place.php?whichplace=spelunky"; + } + else + { + int turns_left = clampi(3 - get_property_int("spelunkyWinCount"), 0, 3); + first_entry_title = "Non-combat after " + pluraliseWordy(turns_left, "combat", "combats"); + } + int phase = get_property_int("spelunkyNextNoncombat"); + entry.subentries.listAppend(ChecklistSubentryMake(first_entry_title, "", "Next phase is " + phase.int_to_wordy() + ".")); + + + location [int] shopping_areas; + location [int] crate_areas; + location [int] tombstone_areas; + + location [int] evaluation_order; + evaluation_order.listAppend($location[The Snake Pit]); + evaluation_order.listAppend($location[The Mines]); + evaluation_order.listAppend($location[The Spider Hole]); + evaluation_order.listAppend($location[The Ancient Burial Ground]); + evaluation_order.listAppend($location[The Jungle]); + evaluation_order.listAppend($location[The Beehive]); + evaluation_order.listAppend($location[the crashed u. f. o.]); + evaluation_order.listAppend($location[The Ice Caves]); + evaluation_order.listAppend($location[The City of Goooold]); + evaluation_order.listAppend($location[The Temple Ruins]); + + //FIXME Some of these gold listings are inaccurate, I think. + foreach key, l in evaluation_order + { + if (!spelunking_status.areas_unlocked[l]) + continue; + string [int] description; + if (l == $location[the mines]) + { + if (phase == 1) + { + description.listAppend("20 gold."); + if ($item[pot].available_amount() == 0) + description.listAppend("A pot. (deals 20 damage, gives 10 gold once when thrown)"); + } + else if (phase == 2) + { + shopping_areas.listAppend(l); + continue; + } + else if (phase == 3) + { + // + if (!spelunking_status.areas_unlocked[$location[the snake pit]] && spelunking_status.bombs > 0 && !spelunking_status.areas_unlocked[$location[the spider hole]]) + { + description.listAppend("Unlock the Snake Pit, at the cost of a bomb.|Blocks out the Spider Hole."); + } + if (!spelunking_status.areas_unlocked[$location[the spider hole]] && spelunking_status.bombs > 0 && !spelunking_status.areas_unlocked[$location[the snake pit]]) + { + description.listAppend("Unlock the Spider Hole, at the cost of a rope.|Leads to sticky bombs. Blocks out the Snake Pit."); + } + + string [int] damage_avoidance; + if ($item[trusty whip].available_amount() > 0) + { + string line = "take 0 or 5 damage"; + if ($item[trusty whip].equipped_amount() == 0) + line += " (equip whip first)"; + damage_avoidance.listAppend(line); + } + if ($slot[off-hand].equipped_item() != $item[none]) + damage_avoidance.listAppend("sacrifice an off-hand"); + + if (damage_avoidance.count() == 0) + damage_avoidance.listAppend("take 10 damage"); + description.listAppend(damage_avoidance.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); + } + } + else if (l == $location[the jungle]) + { + if (phase == 1) + { + shopping_areas.listAppend(l); + continue; + } + else if (phase == 2) + { + tombstone_areas.listAppend(l); + continue; + } + else if (phase == 3) + { + if (!spelunking_status.areas_unlocked[$location[The Beehive]] && spelunking_status.bombs > 0 && !spelunking_status.areas_unlocked[$location[The Ancient Burial Ground]]) + { + string line = "Unlock the Beehive, at the cost of a bomb"; + if (!spelunking_status.sticky_bombs_unlocked) + line += " and 15 damage"; + + line += ".|Blocks out the Ancient Burial Ground."; + description.listAppend(line); + } + if (!spelunking_status.areas_unlocked[$location[The Ancient Burial Ground]] && spelunking_status.ropes > 0 && !spelunking_status.areas_unlocked[$location[The Beehive]]) + { + string line = "Unlock the Ancient Burial Ground, at the cost of a rope"; + if ($item[yellow cape].available_amount() == 0 && $item[jetpack].available_amount() == 0) + line += " and 15 damage"; + line += "."; + + if ($item[yellow cape].equipped_amount() == 0 && $item[jetpack].equipped_amount() == 0) + { + if ($item[jetpack].available_amount() > 0) + line += " (equip jetpack first)"; + else if ($item[yellow cape].available_amount() > 0) + line += " (equip yellow cape first)"; + } + line += "|Useful for a different-phase Clown Crown. Blocks out the Beehive."; + description.listAppend(line); + } + + if ($item[spring boots].available_amount() > 0) + { + string line = "Nothing."; + if ($item[spring boots].equipped_amount() == 0) + line += " (equip spring boots first)"; + description.listAppend(line); + } + else + description.listAppend("Take 30 damage."); + } + } + else if (l == $location[The Ice Caves]) + { + if (phase == 1) + { + shopping_areas.listAppend(l); + continue; + } + else if (phase == 2) + { + string line = "+50-60 gold"; + if ($item[cursed coffee cup].available_amount() > 0) + { + line += ", restore 30 HP."; + if ($item[cursed coffee cup].equipped_amount() == 0) + line += " (equip cursed coffee cup first)"; + } + else + line += "."; + description.listAppend(line); + + if ($item[torch].available_amount() > 0) + { + line = ""; + if (spelunking_status.buddy.length() == 0) + line = "Gain a spelunking buddy."; + else + line = "Gain 60-70 gold."; + + if ($item[torch].equipped_amount() == 0) + line += " (equip a torch first)"; + description.listAppend(line); + } + } + else if (phase == 3) + { + if (!spelunking_status.altar_unlocked) + { + description.listAppend("Unlock the Altar, take 10 damage.|Blocks out U.F.O."); + } + if (!spelunking_status.areas_unlocked[$location[The Crashed U. F. O.]] && spelunking_status.ropes >= 3 && !spelunking_status.altar_unlocked) + description.listAppend("Unlock the Crashed U. F. O., at the cost of three ropes.|Blocks out altar."); + description.listAppend("Take 30 damage."); + } + } + else if (l == $location[The Temple Ruins]) + { + if (phase == 1) + { + crate_areas.listAppend(l); + continue; + } + else if (phase == 2) + { + if (spelunking_status.buddy == "Resourceful Kid") + { + description.listAppend("+250 gold."); + } + else if ($item[jetpack].available_amount() > 0) + { + string line = "+250 gold."; + if ($item[jetpack].equipped_amount() == 0 && !($item[spring boots].equipped_amount() > 0 && $item[yellow cape].equipped_amount() > 0)) + line += " (equip jetpack first)"; + description.listAppend(line); + } + else if ($items[spring boots,yellow cape].items_missing().count() == 0) + { + string line = "+250 gold."; + string [int] items_to_equip; + foreach it in $items[spring boots,yellow cape] + { + if (it.equipped_amount() == 0) + items_to_equip.listAppend(it); + } + if (items_to_equip.count() > 0) + line += " (equip " + items_to_equip.listJoinComponents(", ", "and") + " first)"; + description.listAppend(line); + + } + else + { + description.listAppend("+250 gold, lose all HP."); + } + } + else if (phase == 3) + { + if (spelunking_status.keys > 0 && !spelunking_status.areas_unlocked[$location[The City of Goooold]]) + { + description.listAppend("Unlock The City of Goooold, at the cost of one key."); + } + else + description.listAppend("Take 40 damage."); + } + } + else if ($locations[the snake pit,the beehive,the crashed u. f. o.] contains l) + { + crate_areas.listAppend(l); + continue; + } + else if (l == $location[The Spider Hole]) + { + boolean no_period = false; + string line = "15-20 gold"; + if ($item[cursed coffee cup].available_amount() > 0) + { + //line += " and " + (MIN(my_maxhp() - my_hp(), 30)) + " HP."; + line += " and restore 30 HP."; //consistency + if ($item[cursed coffee cup].equipped_amount() == 0) + { + line += " (equip the cursed coffee cup first)"; + no_period = true; + } + } + if (!no_period) + line += "."; + description.listAppend(line); + + if ($item[sturdy machete].available_amount() > 0) + { + if (spelunking_status.buddy.length() == 0) + line = "A buddy."; + else + line = "30?-40 gold."; //???? + if ($item[sturdy machete].equipped_amount() == 0) + line += " (equip a sturdy machete first)"; + description.listAppend(line); + } + if ($item[torch].available_amount() > 0) + { + line = "30-50 gold."; + if ($item[torch].equipped_amount() == 0) + line += " (equip a torch first)"; + description.listAppend(line); + } + } + else if (l == $location[The Ancient Burial Ground]) + { + tombstone_areas.listAppend(l); + continue; + } + else if (l == $location[The City of Goooold]) + { + if (spelunking_status.keys > 0) + description.listAppend("+150 gold, at the cost of a key."); + if (spelunking_status.bombs > 0) + description.listAppend("+80-100 gold, at the cost of a bomb."); + description.listAppend("+60 gold, but take 20 damage."); + } + entry.subentries.listAppend(ChecklistSubentryMake(l, "", description)); + } + if (shopping_areas.count() > 0) + { + string [int] description; + description.listAppend("Shopkeeper."); + + string [int] possible_inventory; + possible_inventory.listAppend("bombs"); + possible_inventory.listAppend("ropes"); + possible_inventory.listAppend("a key"); + foreach it in $items[spelunking fedora,boomerang,sturdy machete,heavy pickaxe,spiked boots,spring boots,mining helmet,X-ray goggles,yellow cape,shotgun,jetpack] + { + if (it.available_amount() == 0) + possible_inventory.listAppend(it); + } + description.listAppend("Could have " + possible_inventory.listJoinComponents(", ", "or") + "."); + entry.subentries.listAppend(ChecklistSubentryMake(shopping_areas.listJoinComponents(", ", "or"), "", description)); + } + if (crate_areas.count() > 0) + { + string [int] drops; + drops.listAppend("3 ropes"); + drops.listAppend("3 bombs"); + foreach it in $items[heavy pickaxe,jetpack,sturdy machete,spring boots] + { + //seen crate give duplicate spring boots before + drops.listAppend(it); + } + entry.subentries.listAppend(ChecklistSubentryMake(crate_areas.listJoinComponents(", ", "or"), "", "Crate. Gives " + drops.listJoinComponents(", ", "or") + ".")); + //Usually drops ropes/bombs? + } + if (tombstone_areas.count() > 0) + { + string [int] description; + + description.listAppend("20-30? gold or a skeleton buddy."); //highest seen for me is 27 + + if ($item[heavy pickaxe].available_amount() > 0 && $item[Shotgun].available_amount() == 0) + { + string line = "Shotgun"; + if ($item[heavy pickaxe].equipped_amount() == 0) + line += " (equip heavy pickaxe first)"; + line += "."; + description.listAppend(line); + } + + if ($item[x-ray goggles].available_amount() > 0 && $item[The Clown Crown].available_amount() == 0) + { + string line = "The Clown Crown"; + if ($item[x-ray goggles].equipped_amount() == 0) + line += " (equip x-ray goggles first)"; + line += "."; + description.listAppend(line); + } + entry.subentries.listAppend(ChecklistSubentryMake(tombstone_areas.listJoinComponents(", ", "or"), "", description)); + } + + + if (very_important) + { + task_entries.listAppend(entry); + string secondary_description = "Scroll up for full description."; + ChecklistEntry pop_up_reminder_entry = ChecklistEntryMake(entry.image_lookup_name, "", ChecklistSubentryMake(entry.subentries[0].header, "", secondary_description), -11); + pop_up_reminder_entry.tags.id = entry.tags.id + " popup"; + pop_up_reminder_entry.only_show_as_extra_important_pop_up = true; + pop_up_reminder_entry.container_div_attributes["onclick"] = "navbarClick(0, 'Tasks_checklist_container')"; + pop_up_reminder_entry.container_div_attributes["class"] = "r_clickable"; + + task_entries.listAppend(pop_up_reminder_entry); + } + else + future_task_entries.listAppend(entry); +} + +string [item] SpelunkingGenerateEquipmentDescriptions(SpelunkingStatus spelunking_status) +{ + string [item] equipment_descriptions; + + equipment_descriptions[$item[trusty whip]] = "3-6 damage."; + equipment_descriptions[$item[sturdy machete]] = "3-6 damage, +5 weapon damage."; + equipment_descriptions[$item[shotgun]] = "6-12 damage, +10 ranged damage."; + equipment_descriptions[$item[boomerang]] = "3-6 damage, delevels."; + equipment_descriptions[$item[plasma rifle]] = "9-18 damage, +20 ranged damage."; + + equipment_descriptions[$item[Bananubis's Staff]] = "3-6 damage, -6 gold drops, raises a skeleton buddy"; + if (spelunking_status.buddy != "") + equipment_descriptions[$item[Bananubis's Staff]] += " later"; + equipment_descriptions[$item[Bananubis's Staff]] += "."; + if (spelunking_status.buddy.length() == 0) + { + if (spelunking_status.sacrifices < 3 && !spelunking_status.areas_unlocked[$location[the crashed u. f. o.]]) + equipment_descriptions[$item[Bananubis's Staff]] += "|Use this now if you want a buddy to sacrifice."; + else + equipment_descriptions[$item[Bananubis's Staff]] += "|Use this now if you want a skeleton buddy. (for +stat sacrificing or Yomama)"; + } + + equipment_descriptions[$item[crumbling skull]] = "Can throw for 20 damage.|Afterward, can find another."; + equipment_descriptions[$item[8042]] = "Can throw for 30 damage.|Afterward, can find another."; + equipment_descriptions[$item[pot]] = "2 DR, can throw for 20 damage/10 gold."; + equipment_descriptions[$item[heavy pickaxe]] = "+5 all attributes"; + equipment_descriptions[$item[torch]] = "Deals 8-10 damage first round of combat.|Finds random bombs/ropes/gold.|Can be thrown for 100 damage.|Can be thrown at Yomama for recurring damage."; + equipment_descriptions[$item[The Joke Book of the Dead]] = "-6 gold drops, +5 weapon damage, 5 DR."; + equipment_descriptions[$item[cursed coffee cup]] = "-2 gold drops, restores HP after combat."; + + equipment_descriptions[$item[spelunking fedora]] = "+5 stats."; + equipment_descriptions[$item[mining helmet]] = "2 DR, finds random ropes/bombs/gold."; + equipment_descriptions[$item[X-ray goggles]] = "-5 moxie, +5 gold drops."; + equipment_descriptions[$item[The Clown Crown]] = "-6 gold drops."; + + //Note: Both the yellow cape and jetpack affect both boots. How to? + item [int] boots_available; + foreach it in $items[spring boots,spiked boots] + { + if (it.available_amount() > 0) + boots_available.listAppend(it); + } + + equipment_descriptions[$item[yellow cape]] = "+5 moxie"; + if (boots_available.count() > 0) + equipment_descriptions[$item[yellow cape]] += ", improves " + boots_available.listJoinComponents(", ", "and"); + equipment_descriptions[$item[yellow cape]] += "."; + + equipment_descriptions[$item[jetpack]] = "+10 moxie"; + if (boots_available.count() > 0) + equipment_descriptions[$item[jetpack]] += ", improves " + boots_available.listJoinComponents(", ", "and"); + equipment_descriptions[$item[jetpack]] += "."; + + equipment_descriptions[$item[spring boots]] = "Avoids enemy attacks."; + equipment_descriptions[$item[spiked boots]] = "Deals "; + if ($item[jetpack].equipped_amount() > 0) + equipment_descriptions[$item[spiked boots]] += "14-15"; + else if ($item[yellow cape].equipped_amount() > 0) + equipment_descriptions[$item[spiked boots]] += "8-10"; + else + equipment_descriptions[$item[spiked boots]] += "4-5"; + equipment_descriptions[$item[spiked boots]] += " damage first round of combat."; + if ($item[jetpack].available_amount() > 0) + { + if ($item[jetpack].equipped_amount() == 0) + equipment_descriptions[$item[spiked boots]] += " (equip jetpack for more)"; + } + else if ($item[yellow cape].available_amount() > 0 && $item[yellow cape].equipped_amount() == 0) + equipment_descriptions[$item[spiked boots]] += " (equip yellow cape for more)"; + + return equipment_descriptions; +} + +void SpelunkingGenerateEquipmentEntries(Checklist [int] checklists, SpelunkingStatus spelunking_status) +{ + /*ChecklistEntry [int] equipment_entries; + + if (true) + { + Checklist equipment_checklist; + equipment_checklist = ChecklistMake("Equipment", equipment_entries); + checklists.listAppend(equipment_checklist); + }*/ + + string [item] equipment_descriptions = SpelunkingGenerateEquipmentDescriptions(spelunking_status); + + + item [slot][int] equipment_per_slot; + + foreach it in $items[trusty whip,sturdy machete,shotgun,boomerang,plasma rifle,Bananubis's Staff,crumbling skull,8042,pot,heavy pickaxe,torch,The Joke Book of the Dead,cursed coffee cup,spelunking fedora,mining helmet,X-ray goggles,The Clown Crown,yellow cape,jetpack,spring boots,spiked boots] + { + if (it.available_amount() == 0) + continue; + + if (!(equipment_per_slot contains it.to_slot())) + { + item [int] blank_entries; + equipment_per_slot[it.to_slot()] = blank_entries; + } + equipment_per_slot[it.to_slot()].listAppend(it); + } + + slot [int] slot_evaluation_order; + slot_evaluation_order.listAppend($slot[weapon]); + slot_evaluation_order.listAppend($slot[off-hand]); + slot_evaluation_order.listAppend($slot[hat]); + slot_evaluation_order.listAppend($slot[back]); + slot_evaluation_order.listAppend($slot[acc1]); + foreach s in equipment_per_slot + { + if (!($slots[weapon,off-hand,hat,back,acc1] contains s)) + slot_evaluation_order.listAppend(s); + } + + foreach key, s in slot_evaluation_order + { + if (!(equipment_per_slot contains s)) + continue; + + string slot_name = s.slot_to_plural_string().capitaliseFirstLetter(); + + /*ChecklistEntry entry; + entry.subentries.listAppend(ChecklistSubentryMake(slot_name, "", "")); + entry.should_indent_after_first_subentry = true; + boolean have_something_to_unequip = false;*/ + + ChecklistEntry [int] checklist_entries; + + foreach key2 in equipment_per_slot[s] + { + item it = equipment_per_slot[s][key2]; + string header = it.capitaliseFirstLetter(); + if (it.available_amount() > 1) + header = pluralise(it); + string description; + + description = equipment_descriptions[it]; + + /*if (it.equipped_amount() == 0) + have_something_to_unequip = true; + + if (entry.image_lookup_name.length() == 0) + entry.image_lookup_name = "__item " + it; + + entry.subentries.listAppend(ChecklistSubentryMake(header, "", description));*/ + ChecklistEntry entry = ChecklistEntryMake("__item " + it, "", ChecklistSubentryMake(header, "", description)); + entry.tags.id = "Spelunky mode equipment " + it.name; + if (it.equipped_amount() > 0) + { + entry.should_highlight = true; + if (it.to_slot() != $slot[none]) + entry.url = "place.php?whichplace=spelunky"; + } + else if (it.to_slot() != $slot[none]) + { + //this is an interesting idea, but it violates our rule that clicking guide never modifies significant state + //in other words, guide should feel "safe" to click on + //I mean, you should never feel safe around guide. save yourself! + //But, it seems useful enough to be worth doing... + entry.url = "inv_equip.php?pwd=" + my_hash() + "&which=2&action=equip&whichitem=" + it.to_int(); + //KoLmafia/sideCommand?cmd=uneffect+effect&pwd=hash + //entry.url = "KoLmafia/sideCommand?pwd=" + my_hash() + "&cmd=equip+" + it.replace_string(" ", "+"); + //entry.url = "inventory.php?which=2"; + } + checklist_entries.listAppend(entry); + + } + /*if (have_something_to_unequip) + entry.url = "inventory.php?which=2"; + equipment_entries.listAppend(entry);*/ + + + + if (true) + { + Checklist c; + c = ChecklistMake(slot_name, checklist_entries); + checklists.listAppend(c); + } + } +} + + +void LimitModeSpelunkingGenerateChecklists(Checklist [int] checklists) +{ + if (limit_mode() != "spelunky") + return; + ChecklistEntry [int] task_entries; + ChecklistEntry [int] optional_task_entries; + ChecklistEntry [int] future_task_entries; + ChecklistEntry [int] resource_entries; + + if (true) + { + Checklist task_checklist; + task_checklist = ChecklistMake("Tasks", task_entries); + checklists.listAppend(task_checklist); + + + Checklist optional_task_checklist; + optional_task_checklist = ChecklistMake("Optional Tasks", optional_task_entries); + checklists.listAppend(optional_task_checklist); + + Checklist future_task_checklist; + future_task_checklist = ChecklistMake("Future Tasks", future_task_entries); + checklists.listAppend(future_task_checklist); + + Checklist resources_checklist; + resources_checklist = ChecklistMake("Resources", resource_entries); + checklists.listAppend(resources_checklist); + } + + string spelunking_url = "place.php?whichplace=spelunky"; + + + SpelunkingStatus spelunking_status = SpelunkingParseStatus(); + + + if (spelunking_status.turns_left == 0) + { + string [int] description; + + string [int] accomplishments; + if (spelunking_status.gold > 0) + accomplishments.listAppend("earned " + spelunking_status.gold + " gold"); + if (spelunking_status.sacrifices > 0) + accomplishments.listAppend("sacrificed " + pluraliseWordy(spelunking_status.sacrifices, "noble friend", "noble friends")); //is this really an... accomplishment? + if (accomplishments.count() > 0) + description.listAppend("You " + accomplishments.listJoinComponents(", ", "and") + "."); + + task_entries.listAppend(ChecklistEntryMake("__item spelunking fedora", "place.php?whichplace=spelunky&action=spelunky_quit", ChecklistSubentryMake("Ride off into the sunset", "", description)).ChecklistEntrySetIDTag("Spelunky mode results")); + return; + } + + SpelunkingGenerateNCInformation(spelunking_status, task_entries, future_task_entries); + + + if (my_hp() == 0) + { + task_entries.listAppend(ChecklistEntryMake("__effect beaten up", spelunking_url, ChecklistSubentryMake("Heal", "", "Probably at your tent. (costs a turn)"), -11).ChecklistEntrySetIDTag("Spelunky mode heal")); + } + + if ($item[jetpack].available_amount() > 0 && $item[yellow cape].equipped_amount() > 0 && !spelunking_status.noncombat_due_next_adventure) + { + task_entries.listAppend(ChecklistEntryMake("__item jetpack", "inv_equip.php?pwd=" + my_hash() + "&which=2&action=equip&whichitem=" + $item[jetpack].to_int(), ChecklistSubentryMake("Equip jetpack", "", "More efficient than the yellow cape."), -11).ChecklistEntrySetIDTag("Spelunky mode jetpack")); + } + + if (get_property("spelunkyUpgrades").contains_text("N")) + { + int unlocks_found = 0; + string upgrades_string = get_property("spelunkyUpgrades"); + for i from 0 to upgrades_string.length() - 1 + { + if (upgrades_string.char_at(i) == "Y") + unlocks_found += 1; + } + + int unlocks_remaining = clampi(9 - unlocks_found, 0, 9); + + int after_this_remaining = MAX(0, unlocks_remaining - 1); + + if (after_this_remaining > 0) + future_task_entries.listAppend(ChecklistEntryMake("__item heavy pickaxe", "", ChecklistSubentryMake("Spelunk " + pluraliseWordy(after_this_remaining, "more time", "more times") + " after this", "", "Unlock all the starting bonuses.")).ChecklistEntrySetIDTag("Spelunky mode unlock bonuses")); + } + + if (spelunking_status.altar_unlocked && spelunking_status.buddy != "") + { + string [int] description; + //spelunking_status.sacrifices + if (spelunking_status.buddy == "Resourceful Kid") + description.listAppend("He's just a kid! Don't do it!"); + else if (spelunking_status.buddy == "Helpful Guy") + description.listAppend("But, he's really helpful... a loyal companion at your side! Could you betray him?"); + else if (spelunking_status.buddy == "Skeleton") + { + description.listAppend("A skeleton probably won't mind. They're just magic, right?|Still, it is a betrayal..."); + } + else if (spelunking_status.buddy == "Golden Monkey") + description.listAppend("Animal sacrifice... is it really worth it?"); + else + description.listAppend("But, will you betray your friend?"); + + string [int] results; + + if (spelunking_status.sacrifices == 0) + results.listAppend("cursed coffee cup"); + else if (spelunking_status.sacrifices == 1) + { + item next_item; + if ($item[x-ray goggles].available_amount() == 0) + next_item = $item[x-ray goggles]; + else if ($item[spiked boots].available_amount() == 0) + next_item = $item[spiked boots]; + else if ($item[jetpack].available_amount() == 0) + next_item = $item[jetpack]; + else + next_item = $item[8042]; + results.listAppend(next_item); + } + else if (spelunking_status.sacrifices == 2) + results.listAppend("The Joke Book of the Dead (used for unlocking Hell/fighting ghost)"); + + + if (spelunking_status.sacrifices == 0) + results.listAppend("+10 to all stats"); + else if (spelunking_status.sacrifices == 1) + results.listAppend("+5 to all stats"); + else if (spelunking_status.sacrifices >= 2) + results.listAppend("+1 to all stats"); + + if ($item[cursed coffee cup].available_amount() > 0) + { + string line = "30 HP restoration"; + if ($item[cursed coffee cup].equipped_amount() == 0) + line += " (equip cursed coffee cup first)"; + } + + if ($item[Bananubis's Staff].available_amount() > 0) + description.listAppend("Consider repeatedly summoning/sacrificing skeletons for extra stats. (Bananubis's Staff)"); + + if (results.count() > 0) + description.listAppend("Gives " + results.listJoinComponents(", ", "and") + "."); + + if (spelunking_status.sacrifices < 2) + description.listAppend("Part of unlocking Hell."); //where else would you go? + + if (spelunking_status.sacrifices > 0) + description.listAppend(pluraliseWordy(spelunking_status.sacrifices, "sacrifice", "sacrifices").capitaliseFirstLetter() + " so far."); + optional_task_entries.listAppend(ChecklistEntryMake("__item Cloaca-Cola-issue combat knife", spelunking_url, ChecklistSubentryMake("Possibly sacrifice " + spelunking_status.buddy.to_lower_case() + " at the altar", "", description)).ChecklistEntrySetIDTag("Spelunky mode sacrifice")); + //place.php?whichplace=spelunky&action=spelunky_side6 + } + + + + if ($item[the joke book of the dead].available_amount() > 0) + { + string url; + string [int] description; + string [int] tasks; + description.listAppend("If you haven't already."); + + if ($item[the joke book of the dead].equipped_amount() == 0) + { + tasks.listAppend("after equipping " + $item[the joke book of the dead]); + url = "inventory.php?ftext=joke+book+of+the+dead"; + } + tasks.listAppend("click on the ghost"); + description.listAppend(tasks.listJoinComponents(", ").capitaliseFirstLetter() + "."); + description.listAppend("Gives ten more turns on victory."); + + + string [int] ideas; + foreach it in $items[spring boots,boomerang,spelunking fedora] + { + if (it.equipped_amount() == 0) + ideas.listAppend(it); + } + if (spelunking_status.buddy != "Skeleton") + ideas.listAppend("skeleton"); + ideas.listAppend("ropes"); + + + + description.listAppend("Defeating it involves... " + ideas.listJoinComponents(", ") + "?"); + + optional_task_entries.listAppend(ChecklistEntryMake("__item ghost trap", url, ChecklistSubentryMake("Possibly attack the ghost", "", description)).ChecklistEntrySetIDTag("Spelunky mode ghost fight")); + } + + if (spelunking_status.areas_unlocked[$location[the city of Goooold]] && $item[Bananubis's Staff].available_amount() == 0) + { + string [int] description; + description.listAppend("Part of unlocking Hell, and the staff can give stats via sacrifices."); + if (spelunking_status.sticky_bombs_unlocked) + description.listAppend("Throw two bombs."); + else + { + string [int] tasks; + if ($item[spring boots].available_amount() == 0) + tasks.listAppend("acquire spring boots"); + else if ($item[spring boots].equipped_amount() == 0) + tasks.listAppend("equip spring boots"); + tasks.listAppend("rope until spring boots activate"); + tasks.listAppend("throw a bomb"); + tasks.listAppend("throw a bomb or attack or whatever will kill him"); + description.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "?"); + description.listAppend("Or acquire sticky bombs."); + } + description.listAppend("Appears after defeating five mummies in the area."); + optional_task_entries.listAppend(ChecklistEntryMake("__item Bananubis's Staff", spelunking_url, ChecklistSubentryMake("Defeat Bananubis", "", description)).ChecklistEntrySetIDTag("Spelunky mode defeat Bananubis")); + } + + if (spelunking_status.areas_unlocked[$location[LOLmec's lair]] && !spelunking_status.areas_unlocked[$location[Hell]]) + { + //defeat LOLMec + string [int] description; + description.listAppend("If you haven't already."); + if (spelunking_status.bombs < 10) + description.listAppend("Collect ten bombs first."); + else + { + string line = "Throw ten bombs."; + if (!spelunking_status.sticky_bombs_unlocked && spelunking_status.bombs >= 20) + line += " Or twenty."; + description.listAppend(line); + if (!spelunking_status.sticky_bombs_unlocked) + { + if (!spelunking_status.areas_unlocked[$location[the snake pit]]) + description.listAppend("Possibly acquire sticky bombs from the spider queen."); + + string [int] ideas; + foreach it in $items[spring boots,shotgun,spelunking fedora,8042] + { + if (it.equipped_amount() == 0) + ideas.listAppend(it); + } + if (spelunking_status.buddy != "Skeleton") + ideas.listAppend("skeleton"); + ideas.listAppend("ropes"); + + + + description.listAppend("Umm... " + ideas.listJoinComponents(", ") + "?"); + } + } + optional_task_entries.listAppend(ChecklistEntryMake("__item LOLmec statuette", spelunking_url, ChecklistSubentryMake("Defeat LOLmec", "", description)).ChecklistEntrySetIDTag("Spelunky mode defeat LOLmec")); + } + + if (spelunking_status.areas_unlocked[$location[Yomama's Throne]]) + { + string [int] description; + description.listAppend("If you haven't already."); + description.listAppend("Umm... throw a bomb, throw a torch, stagger with ropes? Spring boots? Fedora?|Or defeat him another way. Skeleton buddy might help."); + optional_task_entries.listAppend(ChecklistEntryMake("__item huge gold coin", spelunking_url, ChecklistSubentryMake("Defeat Yomama", "", description)).ChecklistEntrySetIDTag("Spelunky mode defeat Yomama")); + } + + if (!spelunking_status.areas_unlocked[$location[the temple ruins]]) + { + } + else if (!spelunking_status.areas_unlocked[$location[Hell]] && $items[Bananubis's Staff,The Joke Book of the Dead,The Clown Crown].items_missing().count() == 0) + { + if (spelunking_status.keys == 0) + { + optional_task_entries.listAppend(ChecklistEntryMake("__item Clan VIP Lounge key", "", ChecklistSubentryMake("Acquire a key", "", "For unlocking Hell.")).ChecklistEntrySetIDTag("Spelunky mode unlock hell way 1 step 1")); // This is just a guess, I have very little idea what is going on here + } + else + { + string [int] description; + string [int] tasks; + string url; + url = spelunking_url; + + foreach it in $items[Bananubis's Staff,The Joke Book of the Dead,The Clown Crown] + { + if (it.equipped_amount() == 0) + { + tasks.listAppend("equip " + it); + url = "inventory.php?which=2"; + } + } + tasks.listAppend("click on LOLmec's lair"); + if (tasks.count() > 0) + description.listAppend(tasks.listJoinComponents(", ", "then").capitaliseFirstLetter() + "."); + description.listAppend(HTMLGenerateSpanFont("Only do this if you've defeated LOLmec already.", "red")); + optional_task_entries.listAppend(ChecklistEntryMake("__item Clan VIP Lounge key", url, ChecklistSubentryMake("Unlock Hell", "", description)).ChecklistEntrySetIDTag("Spelunky mode unlock hell way 1 step 2")); + } + } + else if (!spelunking_status.areas_unlocked[$location[Hell]] && !(spelunking_status.areas_unlocked[$location[the crashed u. f. o.]])) + { + string [int] description; + string [int] tasks; + if ($item[Bananubis's Staff].available_amount() == 0) + { + tasks.listAppend("acquire Bananubis's Staff"); + } + if ($item[The Joke Book of the Dead].available_amount() == 0) + { + tasks.listAppend("sacrifice buddies for the Joke Book of the Dead"); + } + if ($item[x-ray goggles].available_amount() == 0) + { + tasks.listAppend("acquire x-ray goggles"); + } + if ($item[The Clown Crown].available_amount() == 0) + { + tasks.listAppend("acquire the Clown Crown from the jungle/burial ground NCs"); + } + if (!spelunking_status.areas_unlocked[$location[LOLmec's lair]]) + tasks.listAppend("unlock LOLmec's lair"); + tasks.listAppend("defeat LOLmec"); + if (spelunking_status.keys == 0) + tasks.listAppend("acquire a key"); + + description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + optional_task_entries.listAppend(ChecklistEntryMake("__item handful of fire", "", ChecklistSubentryMake("Unlock Hell", "", description)).ChecklistEntrySetIDTag("Spelunky mode unlock hell way 2")); + } + + if (true) + { + string [int] description; + if (__setting_debug_mode && false) + { + //spelunkyNextNoncombat,spelunkyWinCount,spelunkyUpgrades,spelunkySacrifices + foreach s in $strings[spelunkyStatus] + { + description.listAppend(s + " = \"" + get_property(s) + "\""); + } + description.listAppend("spelunking_status = " + spelunking_status.to_json()); + } + + string [int] areas_to_adventure_in; + areas_to_adventure_in.listAppend("Mines: if the other areas are too difficult."); + //snake pit - marginal? + if (spelunking_status.areas_unlocked[$location[the spider hole]] && !spelunking_status.sticky_bombs_unlocked) + areas_to_adventure_in.listAppend("The Spider Hole: to unlock sticky bombs."); + //burial ground + if (spelunking_status.areas_unlocked[$location[the jungle]] && $item[torch].available_amount() == 0) + areas_to_adventure_in.listAppend("Jungle: chance a torch from tikimen. Throwing rocks works well here."); + //beehive + //UFO + //ice caves - unlocking temple ruins...? + if (spelunking_status.areas_unlocked[$location[The City of Goooold]] && $item[Bananubis's Staff].available_amount() == 0) + areas_to_adventure_in.listAppend("City of Goooold: defeat boss for Bananubis's staff. Part of unlocking Hell."); + //temple ruins + if (spelunking_status.areas_unlocked[$location[the temple ruins]] && !spelunking_status.areas_unlocked[$location[lolmec's lair]]) + areas_to_adventure_in.listAppend("Temple ruins: unlock LOLmec's lair."); + //lolmec's lair + //yomama's lair + if (spelunking_status.areas_unlocked[$location[hell]] && !spelunking_status.areas_unlocked[$location[yomama's throne]]) + areas_to_adventure_in.listAppend("Hell: unlock Yomama's throne after seven combats won."); + + if (spelunking_status.areas_unlocked[$location[the temple ruins]]) + areas_to_adventure_in.listAppend("Temple ruins: to collect gold."); + else + areas_to_adventure_in.listAppend("Somewhere: to collect gold."); + if (areas_to_adventure_in.count() > 0) + description.listAppend("Adventure in:|*" + areas_to_adventure_in.listJoinComponents("|*
")); + + //description.listAppend("Usual combat strategy:|*Throw a bomb or rope if they're powerful (and you can afford it), then attack. Try to avoid taking damage, or heal it with a cursed coffee cup."); + task_entries.listAppend(ChecklistEntryMake("__item heavy pickaxe", spelunking_url, ChecklistSubentryMake("Spelunk!", "", description)).ChecklistEntrySetIDTag("Spelunky mode general")); + } + + SpelunkingGenerateEquipmentEntries(checklists, spelunking_status); +} + + + +string [int] generateHotDogLine(string hotdog, string description, int fullness) +{ + description += " " + fullness + " full."; + if (availableFullness() < fullness) { + hotdog = HTMLGenerateSpanOfClass(hotdog , "r_future_option"); + description = HTMLGenerateSpanOfClass(description , "r_future_option"); + } + return listMake(hotdog, description); +} + + +void generateDailyResources(Checklist [int] checklists) +{ + ChecklistEntry [int] resource_entries; + + SetsGenerateResources(resource_entries); + QuestsGenerateResources(resource_entries); + + if (!get_property_boolean("_fancyHotDogEaten") && availableFullness() > 0 && __misc_state["VIP available"] && __misc_state["can eat just about anything"] && $item[Clan hot dog stand].is_unrestricted()) { //too expensive to use outside a run? well, more that it's information overload + + string name = "Fancy hot dog edible"; + string [int] description; + string image_name = "basic hot dog"; + + string [int][int] options; + options.listAppend(generateHotDogLine("Optimal Dog", "Get Lucky!", 1)); + + if (__misc_state["in run"]) { + options.listAppend(generateHotDogLine("Ghost Dog", "-combat, 30 turns.", 3)); + options.listAppend(generateHotDogLine("Video Game Hot Dog", "+25% item, +25% meat, pixels, 50 turns.", 3)); + options.listAppend(generateHotDogLine("Junkyard dog", "+combat, 30 turns.", 3)); + if (!__quest_state["Level 8"].finished || __quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0) + options.listAppend(generateHotDogLine("Devil dog", "+3 cold/spooky res, 30 turns.", 3)); + if (!__quest_state["Level 9"].state_boolean["Peak Stench Completed"]) + options.listAppend(generateHotDogLine("Chilly dog", "+10ML and +3 stench/sleaze res, 30 turns.", 3)); + if (my_primestat() == $stat[muscle]) + options.listAppend(generateHotDogLine("Savage macho dog", "+50% muscle, 50 turns.", 2)); + if (my_primestat() == $stat[mysticality]) + options.listAppend(generateHotDogLine("One with everything", "+50% mysticality, 50 turns.", 2)); + if (my_primestat() == $stat[moxie]) + options.listAppend(generateHotDogLine("Sly Dog", "+50% moxie, 50 turns.", 2)); + if (__misc_state["Chateau Mantegna available"] && !$skill[Dog Tired].have_skill()) + options.listAppend(generateHotDogLine("Sleeping dog", "5 free rests/day (stats at chateau or cinch rests)", 2)); + } + + description.listAppend(HTMLGenerateSimpleTableLines(options)); + resource_entries.listAppend(ChecklistEntryMake(image_name, "clan_viplounge.php?action=hotdogstand", ChecklistSubentryMake(name, "", description), 5).ChecklistEntrySetIDTag("VIP hot dog stand")); + } + + + if (!get_property_boolean("_olympicSwimmingPoolItemFound") && __misc_state["VIP available"] && $item[Olympic-sized Clan crate].is_unrestricted()) + resource_entries.listAppend(ChecklistEntryMake("__item inflatable duck", "", ChecklistSubentryMake("Dive for swimming pool item", "", "\"swim item\" in GCLI"), 5).ChecklistEntrySetIDTag("VIP swimming pool item")); + if (!get_property_boolean("_olympicSwimmingPool") && __misc_state["VIP available"] && $item[Olympic-sized Clan crate].is_unrestricted()) + resource_entries.listAppend(ChecklistEntryMake("__item inflatable duck", "clan_viplounge.php?action=swimmingpool", ChecklistSubentryMake("Swim in VIP pool", "50 turns", listMake("+20 ML, +30% init", "Or -combat")), 5).ChecklistEntrySetIDTag("VIP swimming pool buff")); + if (!get_property_boolean("_aprilShower") && __misc_state["VIP available"] && $item[Clan shower].is_unrestricted()) { + string [int] description; + if (__misc_state["need to level"]) + description.listAppend("+mainstat gains. (50 turns)"); + + string [int] reasons; + if ($item[double-ice cap].available_amount() == 0) + reasons.listAppend("nice hat"); + if ($familiar[fancypants scarecrow].familiar_is_usable() && $item[double-ice britches].available_amount() == 0) + reasons.listAppend("scarecrow pants"); + //if (!__quest_state["Level 13"].state_boolean["past tower monsters"]) //don't think this is true + //reasons.listAppend("situational tower killing"); + + if (reasons.count() > 0) + description.listAppend("Double-ice. (" + reasons.listJoinComponents(", ", "and") + ")"); + else + description.listAppend("Double-ice."); + + resource_entries.listAppend(ChecklistEntryMake("__item shard of double-ice", "clan_viplounge.php?action=shower", ChecklistSubentryMake("Take a shower", description), 5).ChecklistEntrySetIDTag("VIP april shower")); + } + if (__misc_state["VIP available"] && get_property_int("_poolGames") <3 && $item[Clan pool table].is_unrestricted()) { + int games_available = 3 - get_property_int("_poolGames"); + string [int] description; + if (__misc_state["familiars temporarily blocked"]) + description.listAppend("+50% weapon damage. (aggressively)"); + else + description.listAppend("+5 familiar weight, +50% weapon damage. (aggressively)"); + description.listAppend("Or +50% spell damage, +10 MP regeneration. (strategically)"); + description.listAppend("Or +10% item, +50% init. (stylishly)"); + resource_entries.listAppend(ChecklistEntryMake("__item pool cue", "clan_viplounge.php?action=pooltable", ChecklistSubentryMake(pluralise(games_available, "pool table game", "pool table games"), "10 turns", description), 5).ChecklistEntrySetIDTag("VIP table pool resource")); + } + if (__quest_state["Level 6"].finished && !get_property_boolean("friarsBlessingReceived") && my_path().id != PATH_COMMUNITY_SERVICE && !__misc_state["in CS aftercore"]) { + string [int] description; + if (!__misc_state["familiars temporarily blocked"]) { + description.listAppend("+Familiar experience."); + description.listAppend("Or +30% food drop."); + } + else + description.listAppend("+30% food drop."); + description.listAppend("Or +30% booze drop."); + boolean should_output = true; + if (!__misc_state["in run"]) { + should_output = false; + } + if (!should_output && familiar_weight(my_familiar()) < 20 && my_familiar() != $familiar[none]) { + description.listClear(); + description.listAppend("+Familiar experience."); + should_output = true; + } + if (should_output) + resource_entries.listAppend(ChecklistEntryMake("Monk", "friars.php", ChecklistSubentryMake("Forest Friars buff", "20 turns", description), 10).ChecklistEntrySetIDTag("Friars blessing resource")); + } + + + + + + + if (!get_property_boolean("_madTeaParty") && __misc_state["VIP available"] && $item[Clan looking glass].is_unrestricted() && $item["DRINK ME" potion].item_is_usable()){ + string [int] description; + string line = "Various effects."; + if (__misc_state["in run"] && my_path().id != PATH_ZOMBIE_SLAYER && $item[pail].available_amount() > 0) { + line = "+20ML"; + line += "|Or various effects."; + } + description.listAppend(line); + resource_entries.listAppend(ChecklistEntryMake("__item insane tophat", "", ChecklistSubentryMake("Mad tea party", "30 turns", description), 5).ChecklistEntrySetIDTag("Rabbit hole tea party resource")); + } + + if (true) { + string image_name = "__item hell ramen"; + ChecklistSubentry [int] subentries; + int importance = 11; + if (availableFullness() > 0) { + string [int] description; + if ($effect[Got Milk].have_effect() > 0) + description.listAppend(pluralise($effect[Got Milk]) + " available (woah)."); + if (!get_property_boolean("_milkOfMagnesiumUsed") && lookupItem("milk of magnesium").available_amount() > 0) + description.listAppend("Use Milk of Magnesium for +5 adv."); + if ($effect[barrel of laughs].have_effect() >= 5) { + int turns = $effect[barrel of laughs].have_effect(); + description.listAppend(pluralise($effect[barrel of laughs]) + " available" + (turns % 5 > 0 ? " (" + (turns - turns % 5) + ")" : "") + "."); + } + subentries.listAppend(ChecklistSubentryMake(availableFullness() + " fullness", "", description)); + } + if (inebriety_limit() > 0) { + boolean stooper_is_equipped = my_familiar() == $familiar[Stooper]; + boolean could_equip_stooper = $familiar[Stooper].familiar_is_usable() && !stooper_is_equipped; + string title = ""; + string [int] description; + if (availableDrunkenness() >= 0) { + boolean shotglass_drink_available = !get_property_boolean("_mimeArmyShotglassUsed") && lookupItem("mime army shotglass").is_unrestricted() && lookupItem("mime army shotglass").available_amount() > 0; + if (subentries.count() == 0) + image_name = "__item gibson"; + if ($effect[ode to booze].have_effect() > 0) + description.listAppend(pluralise($effect[ode to booze]) + " available."); + if ($effect[salty mouth].have_effect() > 0) + description.listAppend(pluralise($effect[salty mouth]) + " available. Drink beer for +5 adv!"); + if ($effect[beer barrel polka].have_effect() >= 5) { + int turns = $effect[beer barrel polka].have_effect(); + description.listAppend(pluralise($effect[beer barrel polka]) + " available" + (turns % 5 > 0 ? " (" + (turns - turns % 5) + ")" : "") + "."); + } + + if (availableDrunkenness() > 0) + title = availableDrunkenness() + " drunkenness" + (could_equip_stooper ? " + Stooper" : ""); + else { + title = "Can overdrink"; + if (could_equip_stooper) + description.listAppend("Could equip Stooper for +1 drunkenness."); + } + if (shotglass_drink_available) + description.listAppend("1 free 1-drunkenness booze available."); + subentries.listAppend(ChecklistSubentryMake(title, "", description)); + } else if (availableDrunkenness() == -1 && could_equip_stooper) { + importance = -11; + title = HTMLGenerateSpanFont("Equip the Stooper", "red"); + image_name = "__familiar stooper"; + description.listAppend("Can keep adventuring/overdrink further as long as it's equipped."); + subentries.listAppend(ChecklistSubentryMake(title, "", description)); + } + } + if (availableSpleen() > 0) { + if (subentries.count() == 0) + image_name = "__item agua de vida"; + subentries.listAppend(ChecklistSubentryMake(availableSpleen() + " spleen", "", "")); + } + if (subentries.count() == 0) { + image_name = "__skill stomach of steel"; + subentries.listAppend(ChecklistSubentryMake("No organ space available")); + } + + int adventures_lost_due_to_cap = __misc_state_int["adventures lost to rollover"]; + int gain_from_rollover = __misc_state_int["adventures after rollover"] + adventures_lost_due_to_cap - my_adventures(); + + string [int] rollover_description; + rollover_description.listAppend("Will gain " + gain_from_rollover + " adventures if rollover happens now" + (adventures_lost_due_to_cap == 0 ? "" : ", wasting " + adventures_lost_due_to_cap) + "."); + + subentries[subentries.count() - 1].entries.listAppendList(rollover_description); + + resource_entries.listAppend(ChecklistEntryMake(image_name, "inventory.php?which=1", subentries, importance).ChecklistEntrySetIDTag("Organs consumption consumables")); + } + + if (__quest_state["Level 13"].state_boolean["king waiting to be freed"]) { + string [int] description; + description.listAppend("Contains one (1) monarch."); + description.listAppend(pluralise(my_ascensions(), "king", "kings") + " freed." + (my_ascensions() > 250 ? " Collect them all!" : "")); + string image_name; + image_name = "__effect sleepy"; + resource_entries.listAppend(ChecklistEntryMake(image_name, "place.php?whichplace=nstower", ChecklistSubentryMake("1 Prism", "", description), 10).ChecklistEntrySetIDTag("This is his home now")); + } + + if ((get_property("sidequestOrchardCompleted") == "hippy" || get_property("sidequestOrchardCompleted") == "fratboy") && !get_property_boolean("_hippyMeatCollected") && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) { + resource_entries.listAppend(ChecklistEntryMake("__item herbs", "island.php", ChecklistSubentryMake("Meat from the hippy store", "", "~4500 free meat."), 8).ChecklistEntrySetIDTag("Island orchard meat cut")); //FIXME consider shop.php?whichshop=hippy + } + if ((get_property("sidequestArenaCompleted") == "hippy" || get_property("sidequestArenaCompleted") == "fratboy") && !get_property_boolean("concertVisited")) { + string [int] description; + if (get_property("sidequestArenaCompleted") == "hippy") { + if (!__misc_state["familiars temporarily blocked"]) + description.listAppend("+5 familiar weight."); + description.listAppend("Or +20% item."); + if (__misc_state["need to level"]) + description.listAppend("Or +5 stats/fight."); + } else if (get_property("sidequestArenaCompleted") == "fratboy") { + description.listAppend("+40% meat."); + description.listAppend("+50% init."); + description.listAppend("+10% all attributes."); + } + + string url = "bigisland.php?place=concert"; + if (__quest_state["Level 12"].finished) + url = "postwarisland.php?place=concert"; + resource_entries.listAppend(ChecklistEntryMake("__item the legendary beat", url, ChecklistSubentryMake("Arena concert", "20 turns", description), 5).ChecklistEntrySetIDTag("Island arena daily buff")); + } + + if (skill_is_usable($skill[Unaccompanied Miner])) { + int free_digs_available = 5 - get_property_int("_unaccompaniedMinerUsed"); + if (free_digs_available > 0) { + string [int] description; + string url; + + if (__misc_state["hot airport available"]) { + //volcano mining + string [int] unmet_requirements; + int heat_resistance = numeric_modifier("Hot Resistance"); + + if (lookupItem("High-temperature mining drill").equipped_amount() == 0) { + if (lookupItem("High-temperature mining drill").available_amount() > 0) { + unmet_requirements.listAppend("to equip high-temperature mining drill"); + if (url == "") url = "inventory.php?ftext=high-temperature+mining+drill"; + } else { + unmet_requirements.listAppend("to acquire a high-temperature mining drill"); + if (url == "") url = "inventory.php?ftext=broken+high-temperature+mining+drill"; // won't bother looking at if they have the broken drill, they can figure it out + } + } + + if (heat_resistance < 15) + unmet_requirements.listAppend("15 hot resist (have " + heat_resistance + ")"); + + if (url == "") url = "mining.php?mine=6"; + + description.listAppend("Can mine in the velvet/gold mine" + (unmet_requirements.count() > 0 ? " (Need " + listJoinComponents(unmet_requirements, ", ", "and") + ")" : "" ) + "."); + } + + if (get_property_boolean("mapToAnemoneMinePurchased")) { //name is misleading; they are set to true even if this is the zone you automatically get access to based on your class + if (lookupItem("Mer-kin digpick").equipped_amount() > 0) { + if (url == "") url = "mining.php?mine=3"; + description.listAppend("Anemone Mine (free even without fishy)."); + } else if (lookupItem("Mer-kin digpick").available_amount() > 0) { + description.listAppend("Equip a Mer-kin digpick to mine in Anemone Mine (won't need fishy)."); + if (url == "") url = "inventory.php?ftext=Mer-kin+digpick"; + } else { + description.listAppend("Buy and equip a Mer-kin digpick from the mall to mine in Anemone Mine."); + if (url == "") url = "mall.php?justitems=0&pudnuggler=%22Mer-kin+digpick%22"; + } + } else if (!get_property_boolean("bigBrotherRescued")) { + if (!(__misc_state["in run"] && get_property("questS02Monkees") == "unstarted")) + description.listAppend("Could progress sea quest" + (my_primestat() != $stat[muscle] ? " (+ pay 50 sand dollars)" : "") + " to unlock Anemone Mine."); + } else { + if (my_primestat() == $stat[muscle]) { + description.listAppend("Talk to little brother to unlock Anemone Mine."); + if (url == "") url = "seafloor.php"; + } else { + description.listAppend("Unlock Anemone Mine by buying the map from big brother (50 sand dollars, have " + $item[sand dollar].available_amount() + ")."); + if (url == "") url = "seafloor.php"; + } + } + + + string [int] available_basic_mines_message; + string available_basic_mines_url; + + if (get_property("questL08Trapper") != "unstarted") { // is it the only way/a sure way to know? + available_basic_mines_message.listAppend("Itznotyerzitz Mine"); + if (get_property("questL08Trapper") == "started") { + available_basic_mines_message.listAppend(" (Talk to Trapper first)"); + if (url == "") url = "place.php?whichplace=mclargehuge"; + } + if (available_basic_mines_url == "") available_basic_mines_url = "mining.php?mine=1"; + } + if (lookupItem("Cobb's Knob lab key").available_amount() > 0) { + available_basic_mines_message.listAppend("The Knob Shaft (last resort)"); + if (available_basic_mines_url == "") available_basic_mines_url = "mining.php?mine=2"; + } + + if (available_basic_mines_message.count() > 0) { // Have access to either, or both + string help_message; + if (lookupEffect("Earthen Fist").have_effect() == 0 && !is_wearing_outfit("Mining Gear") && !is_wearing_outfit("Dwarvish War Uniform")) { + if (lookupSkill("Worldpunch").have_skill()) { + help_message += " (cast Worldpunch)"; // this is from an avatar path, so you'll never get both Unaccompanied miner AND worldpunch, right? Eh, whatever, you can still get the fist effect from hookah-like... + if (url == "") url = "skillz.php"; + } else if (can_equip_outfit("Mining Gear")) { + help_message += " (equip mining gear)"; + if (url == "") url = "inventory.php?which=2"; + } else if (can_equip_outfit("Dwarvish War Uniform")) { + help_message += " (equip Dwarvish War Uniform)"; + if (url == "") url = "inventory.php?which=2"; + } else + help_message += " (need proper equipment)"; + } else + if (url == "") url = available_basic_mines_url; + + description.listAppend("Can mine in " + listJoinComponents(available_basic_mines_message, " ", "or") + "." + HTMLGenerateIndentedText(help_message)); + } + + + resource_entries.listAppend(ChecklistEntryMake("__item 7-Foot Dwarven mattock", url, ChecklistSubentryMake( free_digs_available + " free minings", "", description), 5).ChecklistEntrySetIDTag("Unaccompanied miner resource")); + } + } + + //Not sure how I feel about this. It's kind of extraneous? + if (get_property_int("telescopeUpgrades") > 0 && !get_property_boolean("telescopeLookedHigh") && __misc_state["in run"] && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING && !in_bad_moon() && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_G_LOVER && my_path().id != PATH_WEREPROFESSOR) { + string [int] description; + int percentage = 5 * get_property_int("telescopeUpgrades"); + description.listAppend("+" + (percentage == 25 ? "35% or +25" : percentage) + "% to all attributes. (10 turns)"); + resource_entries.listAppend(ChecklistEntryMake("__effect Starry-Eyed", "campground.php?action=telescope", ChecklistSubentryMake("Telescope buff", "", description), 10).ChecklistEntrySetIDTag("Telescope buff resource")); + } + + + if (__misc_state_int["free rests remaining"] > 0) { + ChecklistEntry entry; + entry.image_lookup_name = "__effect sleepy"; + entry.tags.id = "Campground free rests resource"; + entry.importance_level = 10; + + //Build the entries in an order dependant on user preferences + boolean go_chateau = get_property_boolean("restUsingChateau"); + boolean go_away = get_property_boolean("restUsingCampAwayTent"); + string [int] order; + order [go_chateau ? 0 : 1] = "Chateau Mantegna"; + order [go_chateau ? 1 : 0] = go_away ? "Getaway Campsite" : "Your Campsite"; + order [2] = go_away ? "Your Campsite" : "Getaway Campsite"; + + + string [int] url; + ChecklistSubentry [int] subentries_handle; + string [int] description; + + foreach i, loc in order { + ChecklistSubentry subentry; + switch { + case loc == "Chateau Mantegna" && __misc_state["Chateau Mantegna available"]: + subentry.header = "At your Chateau Mantegna:"; + url.listAppend(__misc_state_string["resting url Chateau Mantegna"]); + + stat nightstand_stat = $stat[none]; + int [item] chateau = get_chateau(); + + if (chateau[$item[electric muscle stimulator]] > 0) + nightstand_stat = $stat[muscle]; + else if (chateau[$item[foreign language tapes]] > 0) + nightstand_stat = $stat[mysticality]; + else if (chateau[$item[bowl of potpourri]] > 0) + nightstand_stat = $stat[moxie]; + + string nightstand_message; + if (nightstand_stat != $stat[none] && my_path().id != PATH_THE_SOURCE) { + float experience_multiplier = (100 + numeric_modifier(nightstand_stat + " Experience Percent")) / 100; + int nightstand_statgain = clampi(12 * my_level(), 0, 100) * experience_multiplier; + nightstand_message = ", " + nightstand_statgain + " " + nightstand_stat + " stats"; + } + + subentry.entries.listAppend("250 HP, 125 MP" + nightstand_message + "."); + + if (my_level() < 9 && my_path().id != PATH_THE_SOURCE) + subentry.entries.listAppend("May want to wait until level 9(?) for more stats from resting."); + + item [int] items_equipping = generateEquipmentToEquipForExtraExperienceOnStat(nightstand_stat); + if (items_equipping.count() > 0 && __misc_state["need to level"]) + subentry.entries.listAppend("Could equip " + items_equipping.listJoinComponents(", ", "or") + " for more stats."); + + subentries_handle.listAppend(subentry); + break; + case loc == "Getaway Campsite" && __misc_state["Getaway Campsite available"]: + subentry.header = "At your Getaway Campsite:"; + url.listAppend(__misc_state_string["resting url Getaway Campsite"]); + + int tent_decoration = get_property_int("campAwayDecoration"); + effect tent_decoration_effect = $effect[none]; //Not actually used... + string tent_decoration_stat; + + switch (tent_decoration) { + case 1: + tent_decoration_effect = $effect[Muscular Intentions]; + tent_decoration_stat = "muscle"; + break; + case 2: + tent_decoration_effect = $effect[Mystical Intentions]; + tent_decoration_stat = "myst"; + break; + case 3: + tent_decoration_effect = $effect[Moxious Intentions]; + tent_decoration_stat = "moxie"; + break; + } + + subentry.entries.listAppend("250 HP, 125 MP, removes negative effects."); + + if (tent_decoration != 0) + subentry.entries.listAppend("Gives 20 turns of +3 " + tent_decoration_stat + " stats/fight."); + + subentries_handle.listAppend(subentry); + break; + case loc == "Your Campsite" && __misc_state["recommend resting at campsite"]: + subentry.header = "At your Campsite:"; + url.listAppend(__misc_state_string["resting url campsite"]); + + subentry.entries.listAppend(__misc_state_int["rest hp restore"] + " HP, " + __misc_state_int["rest mp restore"] + " MP."); + if ($item[pantsgiving].available_amount() > 0) { + if ($item[pantsgiving].equipped_amount() == 0) + subentry.entries.listAppend("Wear pantsgiving for extra HP/MP."); + if (availableFullness() > 0) + subentry.entries.listAppend("Eat more for +" + (availableFullness() * 5) + " extra HP/MP."); + } + + if (__resting_bonuses.count() > 0) { + boolean saw_a_limit; + string [int] bonus_messages; + foreach source, bonus in __resting_bonuses { + string message; + + if (source == $item[Confusing LED clock] && my_adventures() < 5) + continue; //won't activate + + if (bonus.duration > 0) { + if (source == $item[Lucky cat statue]) //SETS the remaining duration of that effect to 5 adv + message += pluralise(bonus.duration - bonus.given_effect.have_effect(), "turn", "turns") + " of "; + else if (bonus.tasteful && bonus.given_effect.have_effect() > 1) + continue; //won't activate + else + message += bonus.duration.pluralise("turn", "turns") + " of "; + } + + message += bonus.given_effect == $effect[none] ? bonus.header : bonus.given_effect + " (" + bonus.header + ")"; + + if (bonus.limit > 0) { + saw_a_limit = true; + message += ", " + bonus.limit + (bonus.limit > 1 ? "x" : "") + "/day"; + } + + //if (bonus.tasteful) //player should already be well aware of this; not relevant + // message += ", breaks after 3-5 uses"; + + message += "."; + + bonus_messages.listAppend(message); + } + + if (saw_a_limit) //tell the player that the tiles don't mean that the buffs are still obtainable today; we can't know if they reached the limits + subentry.modifiers.listAppend("Can't tell if you got them, sorry..."); + + if (bonus_messages.count() > 1) + subentry.entries.listAppend("Will give:" + HTMLGenerateIndentedText(bonus_messages.listJoinComponents("
"))); + else if (bonus_messages.count() == 1) + subentry.entries.listAppend("Will give " + bonus_messages[0]); + } + + subentries_handle.listAppend(subentry); + break; + } + } + + entry.url = url [0]; + + if (subentries_handle.count() > 1) { + entry.should_indent_after_first_subentry = true; //that feature is awesome! + entry.subentries = subentries_handle; + entry.subentries.listPrepend(ChecklistSubentryMake(pluralise(__misc_state_int["free rests remaining"], "free rest", "free rests"))); //entire entry acts as a "title" + } else if (subentries_handle.count() == 1) + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(__misc_state_int["free rests remaining"], "free rest", "free rests"), "", subentries_handle[0].entries)); + + resource_entries.listAppend(entry); + } + + if (__quest_state["Sea Monkees"].finished && !get_property_boolean("_momFoodReceived")) { + //FIXME Detect if they can breathe underwater, to go meet her + string [int] description; + + if (__misc_state["in run"]) { //who knows... + string [int] elemental_buffs; + elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Hot Sweat", "r_element_hot")); + elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Cold Sweat", "r_element_cold")); + elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Rank Sweat", "r_element_stench")); + elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Black Sweat", "r_element_spooky")); + elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Flop Sweat", "r_element_sleaze")); + + description.listAppend("" + elemental_buffs.listJoinComponents(" / ") + ": +7 X resistance."); + } + + description.listAppend("Mark of Candy Cain: +20% critical & spell critical hit."); + description.listAppend("Cereal Killer: +200 stats/fight."); + + resource_entries.listAppend(ChecklistEntryMake("Mom Monkey Castle Window", "monkeycastle.php?who=4", ChecklistSubentryMake('Have Mom "make breakfast"', "50 turns", description), 5).ChecklistEntrySetIDTag("Mom sea monkey resource")); + } + + if (true) { + //FIXME Detect if they can breathe underwater + string [string] dailySkateParkBuffs; + + switch (__quest_state["Sea Monkees"].state_string["skate park status"]) { + case "ice": + if (!get_property_boolean("_skateBuff1")) + dailySkateParkBuffs["Lutz, the Ice Skate"] = "Fishy"; + break; + case "roller": + if (!get_property_boolean("_skateBuff2")) + dailySkateParkBuffs["Comet, the Roller Skate"] = "-30% pressure penalty"; + break; + case "peace": + if (!get_property_boolean("_skateBuff3")) + dailySkateParkBuffs["The Bandshell"] = "+1 sand dollar/underwater combat"; + if (!get_property_boolean("_skateBuff4")) + dailySkateParkBuffs["A Merry-Go Round"] = "+25% underwater item"; + if (!get_property_boolean("_skateBuff5")) + dailySkateParkBuffs["The Eclectic Eels"] = "+10 underwater familiar weight"; + break; + } + + if (dailySkateParkBuffs.count() > 0) { + ChecklistEntry entry; + entry.image_lookup_name = "Skate Park"; + entry.url = "sea_skatepark.php"; + entry.tags.id = "Sea skate park buff resource"; + entry.importance_level = 5; + + if (dailySkateParkBuffs.count() > 1) { + entry.subentries.listAppend(ChecklistSubentryMake("Daily Skate Park buffs (30 turns each)")); + entry.should_indent_after_first_subentry = true; //to make it clear(er) that they are not mutually exclusive + foreach whoYouGonnaCall, buff in dailySkateParkBuffs { + entry.subentries.listAppend(ChecklistSubentryMake(whoYouGonnaCall, "", buff)); + } + } else { + foreach whoYouGonnaCall, buff in dailySkateParkBuffs //We know there's only 1 key, but I think it's the only way to get it? + entry.subentries.listAppend(ChecklistSubentryMake("Daily Skate Park buff (30 turns)", "", HTMLGenerateSpanOfClass(whoYouGonnaCall, "r_bold") + ": " + buff)); + } + + resource_entries.listAppend(entry); + } + } + + if (my_path().id != PATH_BEES_HATE_YOU && !get_property_boolean("guyMadeOfBeesDefeated") && get_property_int("guyMadeOfBeesCount") > 0 && (__misc_state["in aftercore"] || !__quest_state["Level 12"].state_boolean["Arena Finished"])) { + //Not really worthwhile? But I suppose we can track it if they've started it, and are either in aftercore or haven't flyered yet. + //For flyering, it's 20 turns at -25%, 25 turns at -15%. 33 turns at -5%. Not worthwhile? + int summon_count = get_property_int("guyMadeOfBeesCount"); + + string [int] description; + string times = ""; + if (summon_count == 4) + times = "One More Time."; + else + times = int_to_wordy(5 - summon_count) + " times."; + description.listAppend("Speak his name " + times); + if ($item[antique hand mirror].available_amount() == 0) + description.listAppend("Need antique hand mirror to win. Or towerkill."); + resource_entries.listAppend(ChecklistEntryMake("__item guy made of bee pollen", $location[the haunted bathroom].getClickableURLForLocation(), ChecklistSubentryMake("The Guy Made Of Bees", "", description), 10).ChecklistEntrySetIDTag("Guy made of bees")); + } + + if (stills_available() > 0) { + string [int] description; + string [int] mixables; + if (__misc_state["can drink just about anything"] && my_path().id != PATH_SLOW_AND_STEADY) { + mixables.listAppend("neuromancer-level drinks"); + } + mixables.listAppend("~40MP from tonic water"); + + description.listAppend(mixables.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); + + resource_entries.listAppend(ChecklistEntryMake("Superhuman Cocktailcrafting", "shop.php?whichshop=still", ChecklistSubentryMake(pluralise(stills_available(), "still use", "still uses"), "", description), 10).ChecklistEntrySetIDTag("Nash crosby still resource")); + } + + if (__last_adventure_location == $location[The Red Queen\'s Garden]) { + string will_need_effect = ""; + if ($effect[down the rabbit hole].have_effect() == 0) + will_need_effect = "|Will need to use "DRINK ME" potion first."; + if (get_property_int("pendingMapReflections") > 0) + resource_entries.listAppend(ChecklistEntryMake("__item reflection of a map", "place.php?whichplace=rabbithole", ChecklistSubentryMake(pluralise(get_property_int("pendingMapReflections"), "pending reflection of a map", "pending reflections of a map"), "+900% item", "Adventure in the Red Queen's garden to acquire." + will_need_effect), 0).ChecklistEntrySetIDTag("Rabbit hole map reflections future")); + if ($items[reflection of a map].available_amount() > 0) { + resource_entries.listAppend(ChecklistEntryMake("__item reflection of a map", "inventory.php?ftext=reflection+of+a+map", ChecklistSubentryMake(pluralise($item[reflection of a map]), "", "Queen cookies." + will_need_effect), 0).ChecklistEntrySetIDTag("Rabbit hole map reflections resource")); + } + } + + if (__misc_state["VIP available"]) { + if (!get_property_boolean("_lookingGlass") && $item[Clan looking glass].is_unrestricted()) { + resource_entries.listAppend(ChecklistEntryMake("__item "DRINK ME" potion", "clan_viplounge.php?whichfloor=2", ChecklistSubentryMake("A gaze into the looking glass", "", "Acquire a " + $item["DRINK ME" potion] + "."), 10).ChecklistEntrySetIDTag("VIP mirror gaze resource")); + } + //_deluxeKlawSummons? + //_crimboTree? + int soaks_remaining = __misc_state_int["hot tub soaks remaining"]; + if (__misc_state["in run"] && soaks_remaining > 0 && my_path().id != PATH_ACTUALLY_ED_THE_UNDYING && my_path().id != PATH_VAMPIRE) { + string description = "Restore all HP, removes most bad effects."; + resource_entries.listAppend(ChecklistEntryMake("__effect blessing of squirtlcthulli", "clan_viplounge.php", ChecklistSubentryMake(pluralise(soaks_remaining, "hot tub soak", "hot tub soaks"), "", description), 8).ChecklistEntrySetIDTag("VIP hot tub soaks resource")); + } + + + } + //_klawSummons? + + //Skill books we have used, but don't have the skill for? + + //soul sauce tracking? + + if ($item[can of rain-doh].available_amount() > 0 && $item[empty rain-doh can].available_amount() == 0 && __misc_state["in run"]) { + resource_entries.listAppend(ChecklistEntryMake("__item can of rain-doh", "inventory.php?ftext=can+of+rain-doh", ChecklistSubentryMake("Can of Rain-Doh", "", "Open it!"), 0).ChecklistEntrySetIDTag("Can of rain-doh resource")); + } + + + + if (get_property_int("goldenMrAccessories") > 0) { + //FIXME inline with hugs + int total_casts_available = get_property_int("goldenMrAccessories") * 5; + int casts_used = get_property_int("_smilesOfMrA"); + + int casts_remaining = total_casts_available - casts_used; + + if (casts_remaining > 0) { + string image_name = "__item Golden Mr. Accessory"; + if (my_id() == 1043600) + image_name = "__item defective Golden Mr. Accessory"; //does not technically give out sunshine, but... + resource_entries.listAppend(ChecklistEntryMake(image_name, "skills.php", ChecklistSubentryMake(pluralise(casts_remaining, "smile of the Mr. Accessory", "smiles of the Mr. Accessory"), "", "Give away sunshine."), 8).ChecklistEntrySetIDTag("Smile of Mr A heart")); + } + } + + if ( __iotms_usable[$item[Chateau Mantegna room key]] && !get_property_boolean("_chateauDeskHarvested")) { + string image_name = "__item fancy calligraphy pen"; + resource_entries.listAppend(ChecklistEntryMake(image_name, "place.php?whichplace=chateau", ChecklistSubentryMake("Chateau desk openable", "", "Daily collectable."), 8).ChecklistEntrySetIDTag("Chateau Mantegna desk resource")); + } + + if (!get_property_boolean("_lyleFavored") && my_path().id != PATH_G_LOVER) { + string image_name = "__effect favored by lyle"; + string description = $effect[Favored by Lyle].have_effect() > 0 ? "Increases duration of Favored by Lyle." : "+10% all attributes."; + resource_entries.listAppend(ChecklistEntryMake(image_name, "place.php?whichplace=monorail", ChecklistSubentryMake("Visit Lyle", "10 turns", description), 10).ChecklistEntrySetIDTag("Lyle favored resource")); + } + + checklists.listAppend(ChecklistMake("Resources", resource_entries)); +} + +void generateStrategy(Checklist [int] checklists) +{ + ChecklistEntry [int] entries; + + if (!__misc_state["in run"]) + return; + + + //What familiar to run. spleen items + //Turn generation. + //How to handle combat. + //How to restore HP. + //Where to get MP...? + + + checklists.listAppend(ChecklistMake("Strategy", entries)); +} +void generateRandomMessageLocation(string [int] random_messages) +{ + if (__last_adventure_location == $location[none]) + return; + string message = ""; + switch (__last_adventure_location) + { + case $location[the penultimate fantasy airship]: + message = "insert disc 2 to continue"; break; + case $location[a-boo peak]: + message = "allons-y!"; break; + case $location[twin peak]: + message = "fire walk with me"; break; + case $location[The Arrrboretum]: + message = "save the planet"; break; + case $location[the red queen's garden]: + message = "curiouser and curiouser"; break; + case $location[A Massive Ziggurat]: + message = "1.21 ziggurats"; break; + case $location[McMillicancuddy's Barn]: + message = "dooks"; break; + case $location[The Roman Forum]: + message = "they go the house"; break; + case $location[the battlefield (hippy uniform)]: + message = "love and war"; break; + case $location[the middle chamber]: + message = "pyramid laundry machine"; break; + case $location[the arid, extra-dry desert]: + message = "can't remember your name"; break; + case $location[outside the club]: + message = "around the world around the world around the world around the world"; break; + case $location[the hidden temple]: + message = "beware of temple guards"; break; + case $location[sonar]: + message = "one ping only"; break; + case $location[galley]: + message = "hungry?"; break; + case $location[science lab]: + message = "poetry in motion"; break; + case $location[fear man's level]: + case $location[doubt man's level]: + case $location[regret man's level]: + case $location[anger man's level]: + message = "this isn't me"; break; + case $location[domed city of ronaldus]: + case $location[domed city of grimacia]: + case $location[hamburglaris shield generator]: + message = "spaaaace!"; break; + case $location[The Mansion of Dr. Weirdeaux]: + case $location[The Deep Dark Jungle]: + case $location[The Secret Government Laboratory]: + message = "they know where you live, " + get_property("System.user.name").to_lower_case(); break; + case $location[The castle in the clouds in the sky (ground floor)]: + case $location[The castle in the clouds in the sky (basement)]: + case $location[The castle in the clouds in the sky (top floor)]: + if (my_class() == $class[disco bandit]) + message = "making castles of your disco"; + break; + case $location[The Prince's Restroom]: + case $location[The Prince's Dance Floor]: + case $location[The Prince's Kitchen]: + case $location[The Prince's Balcony]: + case $location[The Prince's Lounge]: + case $location[The Prince's Canapes table]: + message = "social sabotage"; break; + case $location[anemone mine (mining)]: + case $location[itznotyerzitz mine (in disguise)]: + case $location[the knob shaft (mining)]: + case $location[The Crimbonium Mine]: + case $location[The Velvet / Gold Mine (Mining)]: + message = "street sneaky pete don't you call me cause I can't go"; break; + case lookupLocation("Through the Spacegate"): + message = "oh look! rocks!"; + case $location[hell]: + message = "that's a clean burning hell, I'll tell you what"; break; + case $location[The Neverending Party]: + message = "duffo was lit"; break; + } + if (message != "") + random_messages.listAppend(message); +} + + +void generateRandomMessageFamiliar(string [int] random_messages) +{ + string lowercase_player_name = my_name().to_lower_case().HTMLEscapeString(); + if (my_familiar() == $familiar[none]) + return; + string message = ""; + switch (my_familiar()) + { + case $familiar[none]: + message = "even introverts need friends"; break; + case $familiar[crimbo shrub]: + if (format_today_to_string("MM") == "07") + message = "crimbo in july"; break; + case $familiar[black cat]: + message = "aww, cute kitty!"; break; + case $familiar[temporal riftlet]: + message = "master of time and space"; break; + case $familiar[Frumious Bandersnatch]: + message = "frabjous"; break; + case $familiar[Pair of Stomping Boots]: + if (__misc_state["free runs usable"]) + message = "running away again?"; + break; + case $familiar[baby sandworm]: + message = "the waters of life"; break; + case $familiar[baby bugged bugbear]: + message = "expected }, found }̋̑̀̆͊̑̔͏̱̩̠̰ ̣̻͊ͅf̝͎̰̥̙ͣͦͥ̎,̜̘̖ͭ͋ ̲͉̮̭̪̣͌͋ͤ̉͗ͪ̄̕;̹̼̋̈͛͊ ̧͔̥̤「͙̺̻͖̯͛̀̓̏͑̀l͍̍̍̍͑i̖̖͙͂ͪͮ̍ ̓͑̉̀̆҉̠̜͚̜̹1̶͔̩̬̦̦͍ͥ7͛҉̬̯͇̻͖͉1̆̑̂͒̓」̧̼̜̹̘͕͆̾́͆͐ͯͧ"; //causes severe rendering slowdown; working as intended + break; + case $familiar[mechanical songbird]: + message = "a little glowing friend"; break; + case $familiar[nanorhino]: + message = "write every day"; break; + case $familiar[rogue program]: + message = "ascends for the users"; break; + case $familiar[O.A.F.]: + message = "helping"; break; + case $familiar[Bank Piggy]: + case $familiar[Egg Benedict]: + case $familiar[Floating Eye]: + case $familiar[Money-Making Goblin]: + case $familiar[Oyster Bunny]: + case $familiar[Plastic Grocery Bag]: + case $familiar[Snowhitman]: + case $familiar[Vampire Bat]: + case $familiar[Worm Doctor]: + message = "hacker, or a QT, who could know"; break; + case $familiar[adorable space buddy]: + message = "far beyond the stars"; break; + case $familiar[happy medium]: + message = "karma slave"; //what mistakes could I have made? + break; + case $familiar[wild hare]: + message = "or you wouldn't have come here"; //you must be mad + break; + case $familiar[artistic goth kid]: + message = "life is pain, " + lowercase_player_name; break; + case $familiar[angry jung man]: + message = "personal trauma"; break; + case $familiar[unconscious collective]: + message = "zzz"; break; + case $familiar[dataspider]: + message = "spiders are your friends"; break; + case $familiar[stocking mimic]: + message = "delicious candy"; break; + case $familiar[cocoabo]: + message = "flightless bird"; break; + case $familiar[whirling maple leaf]: + message = "canadian pride"; break; + case $familiar[Hippo Ballerina]: + message = "spin spin spin"; break; + case $familiar[Mutant Cactus Bud]: + message = "always watching"; break; + case $familiar[ghuol whelp]: + message = "¯\\_(ツ)_/¯"; //¯\_(ツ)_/¯ + break; + case $familiar[bulky buddy box]: + message = "♥︎"; //♥︎ + break; + case $familiar[emo squid]: + message = "sob"; break; + case $familiar[fancypants scarecrow]: + message = "the best in terms of pants"; break; + case $familiar[jumpsuited hound dog]: + message = "a little less conversation"; break; + case $familiar[Gluttonous Green Ghost]: + message = "I think he can hear you, " + lowercase_player_name; break; + case $familiar[hand turkey]: + message = "a rare bird"; break; + case $familiar[reanimated reanimator]: + message = "weird science"; break; + case $familiar[Twitching Space Critter]: + message = "right right right right down right agh"; break; + case $familiar[slimeling]: + message = "lost mother"; break; + case $familiar[Puck Man]: + case $familiar[Ms. Puck Man]: + message = "ᗧ • • • • • • • • •"; break; + case $familiar[Lil' Barrel Mimic]: + message = ":D"; break; + case $familiar[pet rock]: + message = "what if the rock's eyebrow froze that way. would anyone notice?"; break; + case $familiar[space jellyfish]: + message = "deer force"; + if (__quest_state["Level 13"].state_boolean["king waiting to be freed"]) + { + int obtained = 0; + int obtainable = 0; + foreach it in $items[] + { + if (it.quest) continue; //these disappear + if (it.item_amount_almost_everywhere() > 0) + obtained += 1; + obtainable += 1; + } + float rate = to_float(obtained) / to_float(obtainable); + random_messages.listClear(); + message = "SEE YOU NEXT MISSION
your rate for collecting items is " + to_int(rate * 100) + "%"; + } + else if (my_level() == 1 || my_turncount() <= 2) + { + random_messages.listClear(); + message = "the last jellyfish is in captivity
the kingdom is at peace"; + } + + break; + case $familiar[bad vibe]: + message = "it's all your fault"; break; + case $familiar[pocket professor]: + message = "when your professor's in your pocket, you can profess anytime"; break; + case $familiar[god lobster]: + message = "god save the lobster"; break; + case $familiar[cat burglar]: + message = "cat got your tongue?"; break; + case $familiar[elf operative]: + message = "your mission, if you choose to accept it, is to use a better familiar"; break; + case $familiar[red-nosed snapper]: + message = "dude, where's my fish"; break; + case $familiar[melodramedary]: + message = "schlurrrrrk!"; break; + case $familiar[vampire vintner]: + message = "he doesn't drink... wine"; break; + case $familiar[grey goose]: + message = "gooso is lit"; break; + case $familiar[patriotic eagle]: + message = "proud to be a loather"; break; + } + if (message != "") + random_messages.listAppend(message); +} + +string generateRandomMessage() +{ + string [int] random_messages; + int current_hour = now_to_string("HH").to_int_silent(); + int current_minute = now_to_string("mm").to_int_silent(); + int minute_of_day = current_hour * 60 + current_minute; + + if (!playerIsLoggedIn()) + return "the kingdom awaits"; + + if (__misc_state["In valhalla"]) + return "rebirth"; + + if (__misc_state["in run"]) + { + if (my_turncount() > 1000 && !in_bad_moon()) + random_messages.listAppend("so many turns"); + + if (false) + random_messages.listAppend("you are ascending perfectly, excellent work!"); + else if (my_daycount() >= 365) + random_messages.listAppend("no king, forever"); + else if (my_daycount() >= 11) + random_messages.listAppend("does the king even exist...?"); + else if (my_turncount() > 400 && my_daycount() == 1) + random_messages.listAppend("you are ascending too... wait, what?"); + else if (gameday_to_int() == 7) + random_messages.listAppend("you are ascending at a reasonable pace, could do better"); + else + random_messages.listAppend("you are ascending too slowly, ascend faster!"); + + string what_does_the_spreadsheet_say = "saves a turn"; + if (my_path().id == PATH_ONE_CRAZY_RANDOM_SUMMER) + what_does_the_spreadsheet_say = "gives +fun"; + if ($item[optimal spreadsheet].equipped_amount() > 0) + random_messages.listAppend("every spreadsheet you wear " + what_does_the_spreadsheet_say); //sure, why not? + else + random_messages.listAppend("every spreadsheet you make " + what_does_the_spreadsheet_say); + } + + string [string] holiday_messages; + holiday_messages["Groundhog Day"] = "it's cold out there every day"; + holiday_messages["Crimbo"] = "merry crimbo"; + if ($item[tommy gun].equipped_amount() > 0) //I believe ya, but my tommy gun don't! + holiday_messages["Crimbo"] = "merry crimbo, ya filthy animal"; + holiday_messages["April Fool's Day"] = "you are ascending too quickly, ascend slower!"; + holiday_messages["Valentine's Day"] = HTMLGenerateSpanFont("♥︎", "pink", "3.0em"); + holiday_messages["Towel Day"] = "don't panic"; + + boolean [string] holidays_today = getHolidaysToday(); + foreach holiday in holidays_today + { + if (holiday_messages contains holiday) + { + random_messages.listAppend(holiday_messages[holiday]); + } + } + + if ($item[The One Mood Ring].equipped_amount() > 0 || $item[mood ring].equipped_amount() > 0) + { + string [int] moods = split_string("grateful,awake,accomplished,disappointed,enraged,tired,exhausted,amused,crushed,peaceful,energetic,listless,hyper,jubilant,hungry,sad,bewildered,alone,quixotic,recumbent,bored,excited,relaxed,lonely,curious,guilty,jealous,cheerful,depressed,stressed,infuriated,pleased,crappy,aggravated,okay,rejuvenated,apathetic,bittersweet,optimistic,exanimate,complacent,devious,rejected,blissful,discontent,sympathetic,mellow,refreshed,ecstatic,lazy,morose,dark,mischievous,bouncy,thankful,melancholy,content,drained,numb,uncomfortable,indifferent,groggy,calm,irate,determined,giggly,good,confused,anxious,relieved,mad,accepted,happy,angry,lethargic,shocked,indescribable,satisfied,gloomy,irritated,pessimistic,rushed,frustrated,surprised,annoyed,sleepy,touched,enthralled,cynical,envious,hopeful,ashamed,chipper,loved,giddy,restless", ","); + string mood_today = moods[gameday_to_int()]; + if (mood_today != "") + random_messages.listAppend(mood_today); + } + + if (__misc_state["in run"]) + { + random_messages.listAppend("optimal power, make up!"); + random_messages.listAppend("the faster your runs, the longer they take"); + } + + generateRandomMessageLocation(random_messages); + + //random_messages.listAppend(HTMLGenerateTagWrap("a", "if you're feeling stressed, play alice's army", generateMainLinkMap("aagame.php"))); + random_messages.listAppend(HTMLGenerateTagWrap("a", "if you're feeling stressed, play witchess", generateMainLinkMap("playwitchess.php?action=another"))); + random_messages.listAppend("consider your mistakes creative spading"); + random_messages.listAppend(HTMLGenerateTagWrap("a", "Found inaccurate/questionable information?
Have a question/suggestion? Click here!", string [string] {"href":"https://github.com/loathers/TourGuide/", "target":"_blank", "class":"r_a_undecorated"})); + + if (hippy_stone_broken()) + random_messages.listAppend(HTMLGenerateTagWrap("a", "it's not easy having yourself a good time", generateMainLinkMap("peevpee.php"))); + + string [item] equipment_messages; + equipment_messages[$item[whatsian ionic pliers]] = "ionic pliers untinker to a screwdriver and a sonar-in-a-biscuit"; + equipment_messages[$item[yearbook club camera]] = "rule of thirds"; + equipment_messages[$item[happiness]] = "bang bang"; + equipment_messages[$item[mysterious silver lapel pin]] = "be seeing you"; + equipment_messages[$item[Moonthril Circlet]] = "moon tiara"; //action! + equipment_messages[$item[numberwang]] = "simply everyone"; + equipment_messages[$item[Mark V Steam-Hat]] = "girl genius"; + equipment_messages[$item[mr. accessory]] = "you can equip mr. accessories?"; + equipment_messages[$item[replica haiku katana]] = "a haiku state of mind"; + equipment_messages[$item[white hat hacker T-shirt]] = "hack the planet"; + equipment_messages[$item[heart necklace]] = "♥︎"; //♥︎ + equipment_messages[$item[fleetwood chain]] = "running in the shadows"; + equipment_messages[$item[liar's pants]] = "never tell the same lie twice"; + equipment_messages[$item[detective skull]] = HTMLGenerateSpanFont("too slow ascend faster", "#ACA200"); //speakeasy password + equipment_messages[$item[gasmask]] = "are you my mummy?"; + equipment_messages[$item[spanish fly trap]] = "around the world around the world around the world around the world"; + equipment_messages[$item[wand of nagamar]] = "levi OH sa"; + if (in_bad_moon() && my_primestat() != $stat[moxie]) + equipment_messages[$item[sneaky pete's breath spray]] = "every class a moxie class"; + foreach it in $items[twisted-up wet towel,sommelier's towel,time bandit time towel] + equipment_messages[it] = "don't panic"; + equipment_messages[$item[pirate fledges]] = " oh, better far to live and die, under the brave black flag I fly! "; + + equipment_messages[$item[guzzlr tablet]] = "looking for booze, eh?"; + equipment_messages[$item[retrospecs]] = "cleesh is love, cleesh is life"; + equipment_messages[$item[tiny stillsuit]] = "it's called fashion sweaty"; + equipment_messages[$item[jurassic parka]] = "so preoccupied with whether you could, never stopped to think if you should"; + equipment_messages[$item[replica jurassic parka]] = "so preoccupied with whether you replica could, never stopped to think if you replica should"; + + foreach it in equipment_messages + { + if (it.equipped_amount() > 0) + { + random_messages.listAppend(equipment_messages[it]); + break; + } + } + + if (my_ascensions() == 0) + random_messages.listAppend("welcome to the kingdom!"); + else if (my_ascensions() == 1) + random_messages.listAppend("run, while you still have the chance!"); + + if (__misc_state["in run"]) + random_messages.listAppend("perfect runs are overrated"); + random_messages.listAppend("math is your helpful friend"); + + if (get_property_int("_pantsgivingCount") >= 5500) + { + random_messages.listAppend("Could not connect to secondary database server:2003 - Can't connect to MySQL server on '10.0.0.51' (99)"); + } + + if ((gameday_to_int() & 31) == 0) + random_messages.listAppend("seek the alchemist"); //a young lady's illustrated ascension guide + + string [effect] effect_messages; + + effect_messages[$effect[consumed by anger]] = "don't ascend angry"; + effect_messages[$effect[consumed by regret]] = "wasted potential"; + effect_messages[$effect[All Revved Up]] = "vroom"; + if (my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) + effect_messages[$effect[Expert Timing]] = "martial arts and crafts"; + effect_messages[$effect[apathy]] = ""; // + effect_messages[$effect[silent running]] = "an awful lot of running"; + effect_messages[$effect[Neuromancy]] = "the silver paths"; + effect_messages[$effect[Teleportitis]] = "everywhere and nowhere"; + effect_messages[$effect[Form of...Bird!]] = "fiddle fiddle fiddle"; + effect_messages[$effect[superstar]] = "★"; + effect_messages[$effect[hopped up on goofballs]] = "a massive drug deficiency"; + foreach s in $strings[Warlock\, Warstock\, and Warbarrel,Barrel of Laughs,Barrel Chested,Pork Barrel,Double-Barreled,Beer Barrel Polka] + effect_messages[s.to_effect()] = "just let me throw a barrel at it"; + effect_messages[$effect[Meteor Showered]] = "すきだ"; + foreach e in effect_messages + { + if (e.have_effect() > 0 && e != $effect[none]) + { + random_messages.listAppend(effect_messages[e]); + break; + } + } + + + if (__misc_state["single familiar run"]) + random_messages.listAppend("together forever"); + + random_messages.listAppend("click click click"); + + switch (my_path().id) + { + case PATH_OXYGENARIAN: + random_messages.listAppend("the slow path"); break; + case PATH_BEES_HATE_YOU: + random_messages.listAppend("bzzzzzz"); break; + case PATH_WAY_OF_THE_SURPRISING_FIST: + random_messages.listAppend("martial arts and crafts"); break; + case PATH_TRENDY: + random_messages.listAppend("played out"); break; + case PATH_AVATAR_OF_BORIS: + random_messages.listAppend("testosterone poisoning"); break; + case PATH_BUGBEAR_INVASION: + random_messages.listAppend("bugbears!"); break; + case PATH_ZOMBIE_SLAYER: + random_messages.listAppend("consumerism metaphor"); break; + case PATH_CLASS_ACT: + random_messages.listAppend("try the sequel"); break; + case PATH_AVATAR_OF_JARLSBERG: + random_messages.listAppend("nerd"); break; + case PATH_BIG: + random_messages.listAppend("everything's so tiny..."); break; + case PATH_KOLHS: + random_messages.listAppend("did you study?"); break; + case PATH_CLASS_ACT_2: + random_messages.listAppend("lonely guild trainer"); break; + case PATH_AVATAR_OF_SNEAKY_PETE: + random_messages.listAppend("sunglasses at night"); break; + case PATH_SLOW_AND_STEADY: + if (!in_hardcore()) + random_messages.listAppend("infinite pulls"); + else + random_messages.listAppend("skip a day if you like"); + break; + case PATH_HEAVY_RAINS: + random_messages.listAppend("survive"); break; + case PATH_PICKY: + if ($skill[cannelloni cannon].skill_is_usable() && !$skill[cannelloni cocoon].skill_is_usable()) //such an easy mistake... + random_messages.listAppend("cannelloni confusion"); + else + random_messages.listAppend("combinatorial ascension"); + break; + case PATH_STANDARD: + random_messages.listAppend("no past no path"); break; + case PATH_ACTUALLY_ED_THE_UNDYING: + random_messages.listAppend("UNDYING!"); break; + case PATH_ONE_CRAZY_RANDOM_SUMMER: + random_messages.listAppend("dance the mersenne twist"); break; + case PATH_COMMUNITY_SERVICE: + random_messages.listAppend("make the world a better place"); break; + case PATH_AVATAR_OF_WEST_OF_LOATHING: + random_messages.listAppend("draw"); break; + case PATH_THE_SOURCE: + if (my_daycount() % 2 == 0) + random_messages.listAppend("don't think you aren't. know you aren't."); + else + random_messages.listAppend("it is not the spoon that ascends, it is only yourself"); + break; + case PATH_NUCLEAR_AUTUMN: + random_messages.listAppend("I do want to set the world on " + HTMLGenerateSpanFont("fire", "red")); + break; + case PATH_GELATINOUS_NOOB: + random_messages.listAppend("you jelly?"); + break; + case PATH_LICENSE_TO_ADVENTURE: + random_messages.listAppend("FOR YOUR EYES ONLY"); + break; + case PATH_LIVE_ASCEND_REPEAT: + random_messages.listAppend("a single perfect day"); + break; + case PATH_POCKET_FAMILIARS: + random_messages.listAppend("adorable slaves"); + break; + case PATH_G_LOVER: + random_messages.listAppend("get going, guuuurl"); + break; + case PATH_DEMIGUISE: + random_messages.listAppend("who are you?"); break; + case PATH_VAMPIRE: + random_messages.listAppend("die monster! you don't belong in this world!"); break; + case PATH_2CRS: + random_messages.listAppend("what happened to my inventory?"); break; + case PATH_EXPLOSIONS: + random_messages.listAppend("kaboooooom"); break; + /*case PATH_CLASS_ACT_3: + random_messages.listAppend("buttons for the people"); break; + case PATH_AVATAR_OF_THE_NAUGHTY_SORCERESS: + random_messages.listAppend("go forth to your lair! have some tea"); break;*/ + } + + if (in_ronin() && my_adventures() <= 3) + random_messages.listAppend("always tomorrow"); + + random_messages.listAppend("I don't know either, sorry"); + + string lowercase_player_name = my_name().to_lower_case().HTMLEscapeString(); + + random_messages.listAppend(HTMLGenerateTagWrap("a", "check the wiki", mapMake("class", "r_a_undecorated", "href", "http://kol.coldfront.net/thekolwiki/index.php/Main_Page", "target", "_blank"))); + random_messages.listAppend("the RNG is only trying to " + ((random(100) == 0) ? "hurt" : "help")); + if (__misc_state["in run"]) + { + int choice = gameday_to_int() & 3; + + if (choice == 0) + random_messages.listAppend("speed ascension is all I have left, " + lowercase_player_name); + else if (choice == 1) + random_messages.listAppend("let the turns go"); + else if (choice == 2) + random_messages.listAppend("mostly made up"); + else if (choice == 3) + random_messages.listAppend("kingdom of self loathing"); + if (my_ascensions() >= 1000) + random_messages.listAppend("dedicated"); + } + + if (item_drop_modifier() <= -100.0) + random_messages.listAppend("let go of your material posessions"); + if ($item[puppet strings].item_amount() > 0 && my_id() != 1557284) + { + //full puppet string support: + string chosen_message; + switch (gameday_to_int() % 13) + { + case 0: chosen_message = "%playername% is easily the most great person ever! three cheers for %playername%!"; break; + case 1: chosen_message = "%playername% is my hero! don't you all agree?"; break; + case 2: chosen_message = "%playername% is such a sexy beast!"; break; + case 3: chosen_message = "%playername% is super-attractive and studly! don't you all agree?"; break; + case 4: chosen_message = "%playername% is super-attractive and studly! just saying that name makes me feel all tingly inside!"; break; + case 5: chosen_message = "who do I think is the best KoLer? obviously\, it's %playername%! how about a round of applause?"; break; + case 6: chosen_message = "I wish I was as good-looking as %playername%. hip hip hooray!"; break; + case 7: chosen_message = "I'm %playername%'s biggest fan! let's hear it for %playername%!"; break; + case 8: chosen_message = "I've never met anyone as attractive as %playername%! how about a round of applause?"; break; + case 9: chosen_message = "I've never met anyone as studly as %playername%! all the rest of us are totally lame in comparison!"; break; + case 10: chosen_message = "is anyone as fabulous as %playername%? I don't think so! just saying that name makes me feel all tingly inside!"; break; + case 11: chosen_message = "is anyone as intelligent as %playername%? I don't think so! hooray for %playername%!"; break; + default: chosen_message = "%playername% is totally awesome! hooray for %playername%!"; break; + } + chosen_message = chosen_message.replace_string("%playername%", lowercase_player_name); + random_messages.listAppend(chosen_message); + //random_messages.listAppend(lowercase_player_name + " is totally awesome! hooray for " + lowercase_player_name + "!"); + } + + if (__quest_state["Level 12"].in_progress && __quest_state["Level 12"].state_int["hippies left on battlefield"] < 1000 && __quest_state["Level 12"].state_int["frat boys left on battlefield"] < 1000) + random_messages.listAppend("playing sides"); + + if (__iotms_usable[$item[Order of the Green Thumb Order Form]]) + random_messages.listAppend(HTMLGenerateTagWrap("a", "the forgotten friar cries himself to sleep", generateMainLinkMap("place.php?whichplace=forestvillage&action=fv_friar"))); + + if (!__misc_state["skills temporarily missing"] && !$skill[Transcendent Olfaction].skill_is_usable()) + { + random_messages.listAppend(HTMLGenerateTagWrap("a", "visit the bounty hunter hunter sometime", generateMainLinkMap("bounty.php"))); + } + if (__misc_state["in aftercore"]) + random_messages.listAppend(HTMLGenerateTagWrap("a", "ascension is waiting for you", generateMainLinkMap("place.php?whichplace=nstower"))); + + if (my_adventures() == 0) + random_messages.listAppend("nowhere left to go"); + + if (__quest_state["Level 11"].in_progress) + random_messages.listAppend("try not to lose your sanity"); + if (__quest_state["Level 13"].in_progress) + { + if (my_daycount() == 1) + random_messages.listAppend("all the world's work in a day"); + else + random_messages.listAppend("it'll be all over soon"); + } + + if (hippy_stone_broken() && pvp_attacks_left() > 0) + random_messages.listAppend(HTMLGenerateTagWrap("a", "aggressive friendship", generateMainLinkMap("peevpee.php"))); + + + if (get_property_boolean("_warbearGyrocopterUsed")) + random_messages.listAppend("[gyroseaten] => 109"); + + //random_messages.listAppend(HTMLGenerateTagWrap("a", "♫", mapMake("class", "r_a_undecorated", "href", "http://www.kingdomofloathing.com/radio.php", "target", "_blank"))); + + if (__misc_state_int["free rests remaining"] > 0) + random_messages.listAppend(HTMLGenerateTagWrap("a", "dream your life away", generateMainLinkMap(__misc_state_string["resting url"]))); + + if (get_property_int("cinderellaScore") >= 32) + random_messages.listAppend("mother knows best"); + + if ($location[the shore\, inc. travel agency].turnsAttemptedInLocation() >= 11) + { + if (hippy_stone_broken()) + random_messages.listAppend("beware of shorebots"); + else + random_messages.listAppend("under a distant shore you will find your answers"); + } + + if (current_hour >= 2 && current_hour <= 3) + random_messages.listAppend("up late?"); + else if (current_hour >= 4 && current_hour <= 5) + random_messages.listAppend("zzz..."); + else if (current_hour == 6) + random_messages.listAppend("the dawn is your enemy"); + + random_messages.listAppend("take chances, be courageous, go exploring!"); + switch (my_class()) + { + case $class[disco bandit]: + random_messages.listAppend("making discos of your castles"); break; + case $class[seal clubber]: + random_messages.listAppend("I ♣︎ seals"); break; + case $class[turtle tamer]: + random_messages.listAppend("friends everywhere you go"); break; + case $class[sauceror]: + random_messages.listAppend("journey of the sauceror"); break; + case $class[Snake Oiler]: + random_messages.listAppend("ten points to slytherin"); break; + } + + if (numeric_modifier("hot damage") <= 0.0 && gameday_to_int() % 4 == 0) + random_messages.listAppend("have you tried " + HTMLGenerateSpanFont("fire", "red")); + + + if (__misc_state["Chateau Mantegna available"] && get_property_monster("chateauMonster").phylum == $phylum[fish] && !get_property_boolean("_chateauMonsterFought")) + { + random_messages.listAppend(HTMLGenerateTagWrap("a", "personal aquarium", generateMainLinkMap("place.php?whichplace=chateau"))); //WhiteWizard42: feeeeesh. feesh in the waaaall + } + generateRandomMessageFamiliar(random_messages); + + if (last_monster().phylum == $phylum[penguin]) + { + random_messages.listClear(); //sufficiently rare + random_messages.listAppend("dood"); + } + + string [monster] monster_messages; + string [monster] beaten_up_monster_messages; + //TODO add a message for the procrastination giant + foreach m in $monsters[The Temporal Bandit,crazy bastard,Knott Slanding,hockey elemental,Hypnotist of Hey Deze,infinite meat bug,QuickBASIC Elemental,The Master of Thieves,Baiowulf,Count Bakula,The Nuge] //Pooltergeist (Ultra-Rare)? + monster_messages[m] = "an ultra rare! congratulations!"; + monster_messages[$monster[The Master of Thieves]] = "don't @ me"; + monster_messages[$monster[Dad Sea Monkee]] = "is always was always" + HTMLGenerateSpanFont(" is always was always", "#444444") + HTMLGenerateSpanFont(" is always was always", "#888888") + HTMLGenerateSpanFont(" is always was always", "#BBBBBB"); + + foreach m in $monsters[Ed the Undying (1),Ed the Undying (2),Ed the Undying (3),Ed the Undying (4),Ed the Undying (5),Ed the Undying (6),Ed the Undying (7)] + monster_messages[m] = "UNDYING!"; + foreach m in $monsters[Naughty Sorceress, Naughty Sorceress (2), Naughty Sorceress (3)] + { + if (holidays_today["Valentine's Day"]) + monster_messages[m] = "please be mine, sorceress"; + else + monster_messages[m] = "she isn't all that bad"; + } + foreach m in $monsters[Shub-Jigguwatt\, Elder God of Violence,Yog-Urt\, Elder Goddess of Hatred] + monster_messages[m] = "strange aeons"; + monster_messages[$monster[daft punk]] = "can you feel it?"; + monster_messages[$monster[ghastly organist]] = "phantom of the opera"; + monster_messages[$monster[The Man]] = "let the workers unite"; + monster_messages[$monster[The Big Wisniewski]] = "far out"; + monster_messages[$monster[Quiet Healer]] = "..."; + monster_messages[$monster[menacing thug]] = "watch your back"; + monster_messages[$monster[sea cowboy]] = "pardon me"; + monster_messages[$monster[topiary golem]] = "almost ther... wait, golems?"; + monster_messages[$monster[The Server]] = "console cowboy"; + monster_messages[$monster[Fickle Finger of F8]] = "f/8 and be there"; + monster_messages[$monster[malevolent crop circle]] = "I want to believe"; + monster_messages[$monster[Enraged Cow]] = "moo"; + if ($item[bottle of blank-out].is_unrestricted()) + monster_messages[$monster[Claybender Sorcerer Ghost]] = "accio blank-out"; + else + monster_messages[$monster[Claybender Sorcerer Ghost]] = "leaderboardus totalus"; + monster_messages[$monster[Whatsian Commando Ghost]] = "captain jack hotness"; + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + monster_messages[$monster[Whatsian Commando Ghost]] = "are you my mummy?"; + monster_messages[$monster[Space Tourist Explorer Ghost]] = "oh my"; + monster_messages[$monster[Battlie Knight Ghost]] = "boring conversation anyway"; + monster_messages[$monster[oil slick]] = "run more ML!"; + monster_messages[$monster[Space Marine]] = "as if it were from an old dream"; + monster_messages[$monster[Regret Man]] = "wasted potential"; + monster_messages[$monster[Principal Mooney]] = "life moves pretty fast"; + if (my_turncount() < 11) + monster_messages[$monster[family of kobolds]] = "in a hurry?"; + monster_messages[$monster[Black Crayon Spiraling Shape]] = "be what you're like"; + monster_messages[$monster[best-selling novelist]] = "fiction to escape reality"; + monster_messages[$monster[7-Foot Dwarf Replicant]] = "it's too bad she won't live
but then again, who does?"; + monster_messages[$monster[The Avatar of Jarlsberg]] = "smoked cheese"; + monster_messages[$monster[giant sandworm]] = "walk without rhythm"; + monster_messages[$monster[bookbat]] = "tattered scrap of dignity"; + monster_messages[$monster[Urge to Stare at Your Hands]] = ".⃝.⃝"; //.⃝.⃝ + if (my_path().id == PATH_HEAVY_RAINS) + monster_messages[$monster[pygmy bowler]] = "right into the gutter"; //come back! + monster_messages[$monster[Ron "The Weasel" Copperhead]] = "RONALD WEASLEY! HOW DARE YOU STEAL THAT ZEPPELIN
" + ChecklistGenerateModifierSpan("your father's now facing an inquiry at work and it's entirely YOUR FAULT"); + monster_messages[$monster[Mr. Loathing]] = HTMLGenerateTagWrap("a", "ruuun! go! get to the towah!", generateMainLinkMap("place.php?whichplace=nstower")); + if (my_hp() < my_maxhp()) + monster_messages[$monster[Smooth Criminal]] = "you've been hit by
you've been struck by
a smooth criminal"; + monster_messages[$monster[demonic icebox]] = "zuul"; + monster_messages[$monster[angry mushroom guy]] = "touch fizzy, get dizzy"; + beaten_up_monster_messages[$monster[storm cow]] = "
^__^            
(oo)\\_______
(__)\\ )\\/\\
||----w |
|| ||
"; + monster_messages[$monster[The Barrelmech of Diogenes]] = "just let me throw a barrel at it"; + //beaten_up_monster_messages[$monster[Lavalos]] = HTMLGenerateTagWrap("span", "but... the future refused to change", mapMake("onclick", "var l = new Audio('" + __lavalos_sound_data + "'); l.play();", "class", "r_clickable")); //copyright, etc + beaten_up_monster_messages[$monster[Lavalos]] = "but... the future refused to change"; + if ($item[protonic accelerator pack].equipped_amount() > 0 && last_monster().monsterIsGhost()) + beaten_up_monster_messages[last_monster()] = "venkman makes it look easy"; + if ($effect[beaten up].have_effect() > 0 && $items[rainbow pearl earring,rainbow pearl necklace,rainbow pearl ring,vampire pearl earring,vampire pearl ring,vampire pearl necklace,freshwater pearl necklace,pearl diver's ring,pearl diver's necklace,pearl necklace].equipped_amount() > 0) + beaten_up_monster_messages[last_monster()] = "WHY WON'T YOU LET ME DO THIS FOR YOU, ROSE?"; + if (last_monster().phylum == $phylum[demon]) + beaten_up_monster_messages[last_monster()] = "he made the devil so much stronger than a man!"; + if (current_hour >= 5 && current_hour <= 11) + monster_messages[$monster[Lavalos]] = "good morning, " + lowercase_player_name + "!"; + else + monster_messages[$monster[Lavalos]] = "all life begins with nu and ends with nu"; + monster_messages[$monster[sk8 gnome]] = "he was a sk8r gnome she said see u l8r gnome"; + monster_messages[$monster[The Inquisitor]] = "nothing is up"; + monster_messages[$monster[Doc Clock]] = "your defeat will happen at " + (current_hour > 12 ? current_hour - 12 : current_hour) + ":" + current_minute + " precisely"; // + (current_hour >= 12 ? " PM" : " AM") + monster_messages[lookupMonster("God Lobster")] = "what a grand and intoxicating innocence"; //how can you kill a god? equip the heart of the volcano? + monster_messages[lookupMonster("cockroach")] = "are bug exterminators professional assassins?"; + monster_messages[lookupMonster("Mountain Man")] = "it's ok, TPTB don't like mining either"; + monster_messages[lookupMonster("Smut Orc Pervert")] = "remember, gooso is lit"; + monster_messages[lookupMonster("void slab")] = "return the slab, or suffer my curse"; + monster_messages[lookupMonster("Astrologer of Shub-Jigguwatt")] = "gettin' jiggu watt it"; + monster_messages[lookupMonster("party skelteon")] = "when it's time to party we will party hard"; + + string day_cycle; + if (current_hour >= 5 && current_hour <= 11) + day_cycle = "morning"; + else if (current_hour >= 12 && current_hour <= 16) + day_cycle = "afternoon"; + else if (current_hour >= 17 && current_hour <= 20) + day_cycle = "evening"; + else + day_cycle = "night"; + monster_messages[$monster[Travoltron]] = now_to_string("EEEE").to_lower_case() + " " + day_cycle + " fever"; + + if (my_daycount() == 2 && (my_adventures() == 0 || availableDrunkenness() < 0) && availableFullness() == 0 && availableDrunkenness() <= 0 && my_path().id != PATH_OXYGENARIAN && __quest_state["Level 12"].started && !__quest_state["Level 13"].state_boolean["king waiting to be freed"] && my_path().id != PATH_NUCLEAR_AUTUMN && my_path().id != PATH_SLOW_AND_STEADY && !__quest_state["Level 13"].finished) + { + //detect failed two-day runs, and provide psychological support: + random_messages.listClear(); + if (__quest_state["Level 13"].started) + random_messages.listAppend("ever so close"); + else + random_messages.listAppend("three days is fine"); + } + + boolean already_output_relevant_beaten_up_effect = false; + if ((my_hp() == 0 || $effect[beaten up].have_effect() > 0) && beaten_up_monster_messages contains last_monster() && last_monster() != $monster[none]) + { + random_messages.listClear(); + random_messages.listAppend(beaten_up_monster_messages[last_monster()]); + already_output_relevant_beaten_up_effect = true; + } + else if (monster_messages contains last_monster() && last_monster() != $monster[none]) + { + random_messages.listClear(); + random_messages.listAppend(monster_messages[last_monster()]); + } + + + if (__quest_state["Level 13"].state_boolean["king waiting to be freed"]) + { + if (my_path().id == PATH_ONE_CRAZY_RANDOM_SUMMER) + { + random_messages.listClear(); + random_messages.listAppend(HTMLGenerateTagWrap("a", "roll the dice", generateMainLinkMap("place.php?whichplace=nstower"))); + } + } + + if (__misc_state_int["Basement Floor"] == 500) + { + random_messages.listClear(); + random_messages.listAppend(HTMLGenerateTagWrap("a", "open it!", generateMainLinkMap("basement.php"))); + } + + string [string] encounter_messages; + boolean encounter_override = false; + encounter_messages["It's Always Swordfish"] = "one two three four five"; + encounter_messages["Meet Frank"] = "don't trust the skull"; + encounter_messages["The Mirror in the Tower has the View that is True"] = "shatter the false reality"; + encounter_messages["A Tombstone"] = "peperony and chease"; + encounter_messages["Witchess Puzzles"] = "this etch a sketch is hard"; + encounter_messages["Rubbed it the Right Way"] = "desire incarnate"; + if (my_class() == $class[turtle tamer]) + { + //The Horror... needs disambiguation + foreach s in $strings[Nantucket Snapper,Blue Monday,Capital!,Training Day,Boxed In,Duel Nature,Slow Food,A Rolling Turtle Gathers No Moss,Slow Road to Hell,C'mere\, Little Fella,The Real Victims,Like That Time in Tortuga,Cleansing your Palette,Harem Scarum,Turtle in peril,No Man\, No Hole,Slow and Steady Wins the Brawl,Stormy Weather,Turtles of the Universe,O Turtle Were Art Thou,Allow 6-8 Weeks For Delivery,Kick the Can,Turtles All The Way Around,More eXtreme Than Usual,Jewel in the Rough,The worst kind of drowning] + encounter_messages[s] = "friend!"; + } + if (encounter_messages contains get_property("lastEncounter")) + { + random_messages.listClear(); + random_messages.listAppend(encounter_messages[get_property("lastEncounter")]); + encounter_override = true; + } + + if (__quest_state["Level 12"].in_progress && __quest_state["Level 12"].state_int["hippies left on battlefield"] == 1 && __quest_state["Level 12"].state_int["frat boys left on battlefield"] == 1) + { + random_messages.listClear(); + random_messages.listAppend("wossname is waiting"); + } + + if (my_familiar() == $familiar[Helix Fossil]) + { + buffer generated; + + + string [int] commands; + + string property_value = get_property("__voices"); + + if (property_value.length() > 1) //remove sentinel + { + if (property_value.char_at(property_value.length() - 1) == "|") + property_value = property_value.substring(0, property_value.length() - 1); + } + + commands = property_value.split_string_alternate(","); + + for i from 0 to 0 + { + string word; + int r = random(100); + if (r < 15) + word = "⬆"; //⬆︎ + else if (r < 30) + word = "⬇"; //⬇︎ + else if (r < 45) + word = "➡"; //➡ + else if (r < 60) + word = "⬅"; //⬅︎ + else if (r < 75) + word = "A";// Ⓐ = Ⓐ + else if (r < 95) + word = "B"; //Ⓑ = Ⓑ + else + word = "start"; + + + + commands.listAppend(word); + } + while (commands.count() > 6) + remove commands[commands.listKeyForIndex(0)]; + set_property("__voices", commands.listJoinComponents(", ") + "|"); //we add an ending sentinel because set_property() will remove ";" if it's at the end of the string. set_property() is not guaranteed to keep data integrity + + random_messages.listClear(); + + string message = commands.listJoinComponents(" "); + message = HTMLGenerateTagWrap("span", message, mapMake("onclick", "updatePageAndFireTimer()", "class", "r_clickable")); + + random_messages.listAppend(message); + } + + + + foreach s in $strings[rainDohMonster,spookyPuttyMonster,cameraMonster,photocopyMonster,envyfishMonster,iceSculptureMonster,crudeMonster,crappyCameraMonster,romanticTarget,chateauMonster] + { + if (get_property_monster(s) == $monster[Quiet Healer]) + { + random_messages.listClear(); + random_messages.listAppend("you can't bring her back"); + break; + } + } + if (false)//mmg_my_bets().count() > 0) + { + random_messages.listClear(); + random_messages.listAppend("win some, lose some"); + } + if ($effect[beaten up].have_effect() > 0 && limit_mode().length() == 0 && !already_output_relevant_beaten_up_effect) + { + random_messages.listClear(); + + + switch (my_path().id) + { + case PATH_BEES_HATE_YOU: + random_messages.listAppend("BZZZZZZ"); break; + case PATH_ONE_CRAZY_RANDOM_SUMMER: + random_messages.listAppend("tick, tock"); break; + case PATH_ACTUALLY_ED_THE_UNDYING: + random_messages.listAppend("DYING!"); break; + case PATH_COMMUNITY_SERVICE: + random_messages.listAppend("no good deed goes unpunished"); break; + case PATH_AVATAR_OF_WEST_OF_LOATHING: + random_messages.listAppend("shucks"); break; + case PATH_LIVE_ASCEND_REPEAT: + random_messages.listAppend("I got you babe"); break; + case PATH_LICENSE_TO_ADVENTURE: + random_messages.listAppend("you only live twice"); break; + case PATH_THE_SOURCE: + random_messages.listAppend("not like this"); break; + case PATH_POCKET_FAMILIARS: + random_messages.listAppend(lowercase_player_name + "! now is not the time to use that!"); break; + case PATH_G_LOVER: + random_messages.listAppend("the Gs will continue until morale improves"); break; + case 46: // Fall of the Dinosaurs + random_messages.listAppend("watch out for velociraptors"); break; + default: + random_messages.listAppend("ow"); break; + } + } + if (my_turncount() <= 0) + { + random_messages.listClear(); + if (my_path().id == PATH_LIVE_ASCEND_REPEAT) + random_messages.listAppend("I got you babe"); + else if (my_path().id == PATH_POCKET_FAMILIARS) + random_messages.listAppend("pika pika!"); + else + random_messages.listAppend("find yourself
starting back"); + } + if (limit_mode() == "Spelunky" && !encounter_override) + { + random_messages.listClear(); + + if (get_property("lastEncounter") == "Spelunkrifice" && get_property("spelunkyStatus").contains_text("Buddy: ")) + { + if (get_property("spelunkingStatus").contains_text("Resourceful Kid")) + random_messages.listAppend("he's only a child!"); + else + random_messages.listAppend("et tu, " + lowercase_player_name + "?"); + } + else + random_messages.listAppend("ascend? yes! play? no!"); + } + if (limit_mode() == "batman" && !encounter_override) + { + random_messages.listClear(); + random_messages.listAppend("a superstitious, cowardly lot"); + } + + // Adding a few Legacy of Loathing replica messages + + if (my_path() == $path[Legacy of Loathing]) + { + random_messages.listAppend("make sure you get your hand turkey"); + random_messages.listAppend("hot legacy summer"); + random_messages.listAppend("living like the richy-rich"); + random_messages.listAppend("it's one banana, " + lowercase_player_name + ". what could it cost, replica ten bucks?"); + random_messages.listAppend("replicas are like any other machine -- they're either a benefit or a hazard"); + random_messages.listAppend("claimin' respect, just to get a rep... lica"); + } + + // There's no way I could determine for mafia to tell that you -just- cast Feel Disappointed. + // Therefore, for this silly set of disappointment messages, they only show in the pool if + // you've cast it exactly two times. This is silly, but I think it's fine. + + if (get_property("_feelDisappointedUsed") == 2) + { + random_messages.listAppend("zapdos ran away! aww..."); + random_messages.listAppend("mentally simulate a 1-day HC Grey You ascension"); + random_messages.listAppend("manifesting a 40 turn friars"); + random_messages.listAppend("agriculture will become impossible in our lifetime"); + random_messages.listAppend("we will never get the cruelest moth"); + random_messages.listAppend("gaze upon this display case and despair"); + random_messages.listAppend(HTMLGenerateTagWrap("a", "gaze upon this display case and despair", generateMainLinkMap("displaycollection.php?who=252058"))); + random_messages.listAppend("home depot is out of 12-foot skeletons"); + random_messages.listAppend("imagine being a Sacramento Kings fan, tho"); + random_messages.listAppend("are you SURE you took the crystal ball off?"); + random_messages.listAppend("does king ralph really care about us?"); + } + + if (format_today_to_string("yyyyMMdd") == "20151021") //october 21st, 2015 + { + //kept active for any time travelers + random_messages.listClear(); + if (get_property("System.user.country.format") == "US") + random_messages.listAppend("88 MPH
hey, you did it!"); + else + random_messages.listAppend("142 km/h
hey, you did it!"); + } + + + //Choose: + if (random_messages.count() == 0) + return "lack of cleverness"; + string chosen_message = ""; + //Base message off of the minute, so it doesn't cycle when the page reloads often: + chosen_message = random_messages[minute_of_day % random_messages.count()]; + + return chosen_message; +} + + +void generateImageTest(Checklist [int] checklists) +{ + ChecklistEntry [int] image_test_entries; + KOLImagesInit(); + foreach i in __kol_images + { + KOLImage image = __kol_images[i]; + image_test_entries.listAppend(ChecklistEntryMake(i, "", ChecklistSubentryMake(i))); + + } + checklists.listAppend(ChecklistMake("All images", image_test_entries)); +} + +void generateStateTest(Checklist [int] checklists) +{ + ChecklistEntry [int] misc_state_entries; + ChecklistEntry [int] quest_state_entries; + + + string [int] state_description; + string [int] string_description; + string [int] int_description; + foreach key in __misc_state + { + state_description.listAppend(key + " = " + __misc_state[key]); + } + foreach key in __misc_state_string + { + string_description.listAppend(key + " = \"" + __misc_state_string[key] + "\""); + } + foreach key in __misc_state_int + { + int_description.listAppend(key + " = " + __misc_state_int[key]); + } + + misc_state_entries.listAppend(ChecklistEntryMake("__item milky potion", "", ChecklistSubentryMake("Boolean", "", state_description.listJoinComponents("|")))); + misc_state_entries.listAppend(ChecklistEntryMake("__item ghost thread", "", ChecklistSubentryMake("String", "", string_description.listJoinComponents("|")))); + misc_state_entries.listAppend(ChecklistEntryMake("__item handful of numbers", "", ChecklistSubentryMake("Int", "", int_description.listJoinComponents("|")))); + + boolean [string] names_already_seen; + + foreach key in __quest_state + { + if (names_already_seen[key]) + continue; + names_already_seen[key] = true; + + QuestState quest_state = __quest_state[key]; + + string [int] full_name_list; + full_name_list.listAppend(key); + + //Look for others: + foreach key2 in __quest_state + { + if (key == key2) + continue; + QuestState quest_state_2 = __quest_state[key2]; + + if (QuestStateEquals(quest_state, quest_state_2)) + { + full_name_list.listAppend(key2); + names_already_seen[key2] = true; + } + } + + ChecklistSubentry subentry; + + subentry.header = listJoinComponents(full_name_list, " / " ); + if (quest_state.quest_name != "") + subentry.entries.listAppend("Internal name: " + quest_state.quest_name); + + subentry.entries.listAppend("Startable: " + quest_state.startable); + subentry.entries.listAppend("Started: " + quest_state.started); + subentry.entries.listAppend("In progress: " + quest_state.in_progress); + subentry.entries.listAppend("Finished: " + quest_state.finished); + subentry.entries.listAppend("Mafia's internal step: " + quest_state.mafia_internal_step); + + foreach key2 in quest_state.state_boolean + { + subentry.entries.listAppend(key2 + ": " + quest_state.state_boolean[key2]); + } + foreach key2 in quest_state.state_string + { + subentry.entries.listAppend(key2 + ": \"" + quest_state.state_string[key2] + "\""); + } + foreach key2 in quest_state.state_int + { + subentry.entries.listAppend(key2 + ": " + quest_state.state_int[key2]); + } + + quest_state_entries.listAppend(ChecklistEntryMake(quest_state.image_name, "", subentry)); + } + + + checklists.listAppend(ChecklistMake("Misc. States", misc_state_entries)); + checklists.listAppend(ChecklistMake("Quest States", quest_state_entries)); +} + +void generateCounterTest(Checklist [int] checklists) +{ + ChecklistEntry [int] checklist_entries; + + ChecklistEntry main_entry; + main_entry.image_lookup_name = "__item sinister ancient tablet"; + + string [int] counter_names = CounterGetAllNames(); + + if (counter_names.count() == 0) + return; + + foreach key in counter_names + { + string counter_name = counter_names[key]; + Counter c = CounterLookup(counter_name); + + string [int] description; + description.listAppend(c.CounterDescription()); + + main_entry.subentries.listAppend(ChecklistSubentryMake(c.name, "", description)); + } + + checklist_entries.listAppend(main_entry); + + + checklists.listAppend(ChecklistMake("Counters", checklist_entries)); +} + +buffer generateMajorMinorText(string [string][int] entries) +{ + buffer description; + foreach zone in entries + { + if (description.length() > 0) + description.append("|"); + description.append(zone); + description.append(":|*"); + description.append(entries[zone].listJoinComponents("|*")); + } + return description; +} + +void generateSelfDataTest(Checklist [int] checklists) +{ + ChecklistEntry [int] checklist_entries; + //Show missing locations in locationAvailable and missing locations from clickables. + + string [string][int] missing_available_locations; + string [string][int] missing_location_links_description; + + foreach l in $locations[] + { + Error unable_to_find_location; + l.locationAvailable(unable_to_find_location); + + if (unable_to_find_location.was_error) + { + if (!(missing_available_locations contains l.zone)) + missing_available_locations[l.zone] = listMakeBlankString(); + missing_available_locations[l.zone].listAppend(l.to_string()); + } + + Error unable_to_find_clickable; + l.getClickableURLForLocation(unable_to_find_clickable); + if (unable_to_find_clickable.was_error) + { + if (!(missing_location_links_description contains l.zone)) + missing_location_links_description[l.zone] = listMakeBlankString(); + missing_location_links_description[l.zone].listAppend("lookup_map[\"" + l.to_string() + "\"] = \"REPLACEME\";"); + } + } + if (missing_available_locations.count() > 0) + { + buffer description = generateMajorMinorText(missing_available_locations); + checklist_entries.listAppend(ChecklistEntryMake("__item cobb's knob map", "", ChecklistSubentryMake("Missing locationAvailable() locations", "", description))); + } + + + if (missing_location_links_description.count() > 0) + { + buffer description = generateMajorMinorText(missing_location_links_description); + checklist_entries.listAppend(ChecklistEntryMake("__item reflection of a map", "", ChecklistSubentryMake("Missing getClickableURLForLocation() locations", "", description))); + } + checklists.listAppend(ChecklistMake("Self data tests", checklist_entries)); +} + + +void generateBanishTest(Checklist [int] checklists) +{ + ChecklistEntry [int] checklist_entries; + + string [int][int] banish_table; + banish_table.listAppend(listMake("Monster", "Source", "On turn", "Turn length", "Reset conditions")); + foreach key, b in BanishesActive() + { + banish_table.listAppend(listMake(b.banished_monster, b.banish_source, b.turn_banished, b.banish_turn_length, b.custom_reset_conditions)); + } + if (banish_table.count() > 1) + { + checklist_entries.listAppend(ChecklistEntryMake("__item ice house", "", ChecklistSubentryMake("Banishes", "", HTMLGenerateSimpleTableLines(banish_table)))); + } + + checklists.listAppend(ChecklistMake("Banishes", checklist_entries)); +} + +void generateAllTests(Checklist [int] checklists) +{ + generateImageTest(checklists); + generateStateTest(checklists); + generateCounterTest(checklists); + generateBanishTest(checklists); + generateSelfDataTest(checklists); +} + + + +/*zone values: +Bat-Cavern +Somewhere in Gotpork City +Center Park (Low Crime) +Slums (Moderate Crime) +Industrial District (High Crime) +Downtown +*/ +//Bat-Investigation Progress appears to be the amount of progress you advance per fight, which upgrades with upgrades. +Record BatState +{ + string zone; + int funds_available; + int time_left; + + string [string] stats; + boolean [string] upgrades; + /*int hp; + int max_hp; + int hp_regen;*/ + //FIXME more +}; + +BatState __batstate; + +BatState BatStateMake() +{ + BatState state; + //Parse: + state.zone = get_property("batmanZone"); + state.funds_available = get_property_int("batmanFundsAvailable"); + state.time_left = get_property_int("batmanTimeLeft"); + //FIXME upgrades + + foreach key, s in get_property("batmanStats").split_string_alternate(";") + { + string [int] attribution = s.split_string_alternate("="); + if (attribution.count() != 2) + continue; + state.stats[attribution[0]] = attribution[1]; + } + foreach key, s in get_property("batmanUpgrades").split_string_alternate(";") + state.upgrades[s] = true; + __batstate = state; + return state; +} + + +static +{ + location [monster] __batfellow_bosses_to_locations; + + void initialiseBatfellowBosses() + { + __batfellow_bosses_to_locations[$monster[Kudzu]] = $location[Gotpork Conservatory of Flowers]; + __batfellow_bosses_to_locations[$monster[Mansquito]] = $location[Gotpork Municipal Reservoir]; + __batfellow_bosses_to_locations[$monster[Miss Graves]] = $location[Gotpork Gardens Cemetery]; + + __batfellow_bosses_to_locations[$monster[The Plumber]] = $location[Gotpork City Sewers]; + __batfellow_bosses_to_locations[$monster[The Author]] = $location[Porkham Asylum]; + __batfellow_bosses_to_locations[$monster[The Mad Libber]] = $location[The Old Gotpork Library]; + + __batfellow_bosses_to_locations[$monster[Doc Clock]] = $location[Gotpork Clock, Inc.]; + __batfellow_bosses_to_locations[$monster[Mr. Burns]] = $location[Gotpork Foundry]; + __batfellow_bosses_to_locations[$monster[The Inquisitor]] = $location[Trivial Pursuits, LLC]; + } + initialiseBatfellowBosses(); + +} + + +Record BatfellowBossArea +{ + location area; + string short_name; + string image_name; + string zone; + monster boss; + string [int] strategies; + int [item] nc_twenty_five_progress_requirements; + int [item] nc_fifty_progress_requirements; + int [item] nc_reward_items; +}; + +BatfellowBossArea BatfellowBossAreaMake() +{ + BatfellowBossArea area; + return area; +} + +static +{ + BatfellowBossArea [location] __batfellow_bosses; + void initialiseBatfellowBossAreas() + { + BatfellowBossArea area = BatfellowBossAreaMake(); + area.area = $location[Gotpork Conservatory of Flowers]; + area.short_name = "Conservatory"; + area.image_name = "sunflower face"; + area.zone = "Center Park (Low Crime)"; + area.boss = $monster[Kudzu]; + area.nc_twenty_five_progress_requirements[$item[glob of Bat-Glue]] = 1; + area.nc_fifty_progress_requirements[$item[fingerprint dusting kit]] = 3; + area.nc_reward_items[$item[dangerous chemicals]] = 5; + __batfellow_bosses[area.area] = area; + + area = BatfellowBossAreaMake(); + area.area = $location[Gotpork Municipal Reservoir]; + area.short_name = "Reservoir"; + area.image_name = "__item personal raindrop"; //"__item ketchup hound"; + area.zone = "Center Park (Low Crime)"; + area.boss = $monster[Mansquito]; + area.nc_twenty_five_progress_requirements[$item[Bat-Aid™ bandage]] = 1; + area.nc_fifty_progress_requirements[$item[ultracoagulator]] = 3; + area.nc_reward_items[$item[kidnapped orphan]] = 5; + __batfellow_bosses[area.area] = area; + + area = BatfellowBossAreaMake(); + area.area = $location[Gotpork Gardens Cemetery]; + area.short_name = "Cemetery"; + area.image_name = "__item grave robbing shovel"; + area.zone = "Center Park (Low Crime)"; + area.boss = $monster[Miss Graves]; + area.nc_twenty_five_progress_requirements[$item[bat-bearing]] = 1; + area.nc_fifty_progress_requirements[$item[exploding kickball]] = 3; + area.nc_reward_items[$item[incriminating evidence]] = 5; + __batfellow_bosses[area.area] = area; + + + area = BatfellowBossAreaMake(); + area.area = $location[Porkham Asylum]; + area.short_name = "Asylum"; + area.image_name = "__item jet bennie marble"; + area.zone = "Slums (Moderate Crime)"; + area.boss = $monster[The Author]; + area.nc_twenty_five_progress_requirements[$item[bat-o-mite]] = 1; + area.nc_reward_items[$item[high-grade metal]] = 6; + __batfellow_bosses[area.area] = area; + + area = BatfellowBossAreaMake(); + area.area = $location[Gotpork City Sewers]; + area.short_name = "Sewers"; + area.image_name = "__item helmet turtle"; + area.zone = "Slums (Moderate Crime)"; + area.boss = $monster[The Plumber]; + area.nc_twenty_five_progress_requirements[$item[bat-oomerang]] = 1; + area.nc_reward_items[$item[high-grade explosives]] = 6; + __batfellow_bosses[area.area] = area; + + area = BatfellowBossAreaMake(); + area.area = $location[The Old Gotpork Library]; + area.short_name = "Library"; + area.image_name = "__item very overdue library book"; + area.zone = "Slums (Moderate Crime)"; + area.boss = $monster[The Mad Libber]; + area.nc_twenty_five_progress_requirements[$item[bat-jute]] = 1; + area.nc_reward_items[$item[high-tensile-strength fibers]] = 6; + __batfellow_bosses[area.area] = area; + + + area = BatfellowBossAreaMake(); + area.area = $location[Gotpork Clock, Inc.]; + area.short_name = "Clock"; + area.image_name = "__item borrowed time"; + area.zone = "Industrial District (High Crime)"; + area.boss = $monster[Doc Clock]; + area.nc_twenty_five_progress_requirements[$item[exploding kickball]] = 1; + area.nc_reward_items[$item[kidnapped orphan]] = 6; + area.nc_reward_items[$item[high-grade explosives]] = 6; + area.strategies.listAppend("Bat-oomerang the time bandits, to prevent them from stealing time?"); + area.strategies.listAppend("Gain resources from the NC?"); + __batfellow_bosses[area.area] = area; + + area = BatfellowBossAreaMake(); + area.area = $location[Gotpork Foundry]; + area.short_name = "Foundry"; + area.image_name = "__item handful of fire"; + area.zone = "Industrial District (High Crime)"; + area.boss = $monster[Mr. Burns]; + area.nc_twenty_five_progress_requirements[$item[ultracoagulator]] = 1; + area.nc_reward_items[$item[dangerous chemicals]] = 6; + area.nc_reward_items[$item[high-grade metal]] = 6; + area.strategies.listAppend("Gain resources from the NC?"); + __batfellow_bosses[area.area] = area; + + area = BatfellowBossAreaMake(); + area.area = $location[Trivial Pursuits, LLC]; + area.short_name = "Trivial Company"; + area.image_name = "__item Trivial Avocations Card: What?"; + area.zone = "Industrial District (High Crime)"; + area.boss = $monster[The Inquisitor]; + area.nc_twenty_five_progress_requirements[$item[fingerprint dusting kit]] = 1; + area.nc_reward_items[$item[incriminating evidence]] = 6; + area.nc_reward_items[$item[high-tensile-strength fibers]] = 6; + area.strategies.listAppend("Gain resources from the NC?"); + __batfellow_bosses[area.area] = area; + } + initialiseBatfellowBossAreas(); +} + + + +void LimitModeBatfellowGenerateResources(ChecklistEntry [int] resource_entries, BatState state) +{ + if (__setting_debug_mode) + { + string [int] description; + foreach s in $strings[batmanBonusInitialFunds,batmanFundsAvailable,batmanStats,batmanTimeLeft,batmanUpgrades,batmanZone] + { + description.listAppend(s + " = " + get_property(s)); + } + description.listAppend("Dwayne Manor"); + resource_entries.listAppend(ChecklistEntryMake("__item batarang", "", ChecklistSubentryMake("Bat-Properties", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode debug properties")); + + resource_entries.listAppend(ChecklistEntryMake("__item batarang", "", ChecklistSubentryMake("Bat-State", "", state.to_json()), 8).ChecklistEntrySetIDTag("Batfellow mode debug state")); + } + + string [item] item_descriptions; + item_descriptions[$item[bat-oomerang]] = "Deals 20 damage, disarms foes, speeds up sewers."; + item_descriptions[$item[bat-jute]] = "Against a monster with ten or less HP, defeats foe and increases progress that fight.|Speeds up the library."; + item_descriptions[$item[bat-o-mite]] = "Instakill, speeds up asylum."; + + item_descriptions[$item[incriminating evidence]] = "Trade for armour upgrades and progress increasers.";//, which also help with the trivia company and the conservatory."; + item_descriptions[$item[dangerous chemicals]] = "Trade for health upgrades and HP restorers.";//, which also help with the foundry and the reservoir."; + item_descriptions[$item[kidnapped orphan]] = "Trade for attack upgrades and free instakills.";//, which also help with the clock factory and cemetary."; + + + item_descriptions[$item[high-grade metal]] = "make bat-oomeranges (damages)"; + item_descriptions[$item[high-tensile-strength fibers]] = "makes bat-jutes (damages)"; + item_descriptions[$item[high-grade explosives]] = "makes bat-o-mites (kills?)"; + + item_descriptions[$item[experimental gene therapy]] = ""; + item_descriptions[$item[ultracoagulator]] = "restores all HP, speeds up foundry and reservoir"; + item_descriptions[$item[self-defense training]] = ""; + item_descriptions[$item[fingerprint dusting kit]] = "4% progress/fight, speeds up trivia company and conservatory"; + item_descriptions[$item[confidence-building hug]] = ""; + item_descriptions[$item[exploding kickball]] = "skips monster to advance the NC, speeds up clock factory and cemetary"; + item_descriptions[$item[glob of Bat-Glue]] = "stuns for multiple rounds, speeds up conservatory"; + item_descriptions[$item[Bat-Aid™ bandage]] = "restores 20 HP, speeds up reservoir"; + item_descriptions[$item[bat-bearing]] = "stuns foes, deals 15 damage, speeds up cemetary"; + + item [int][int] item_groupings; + item_groupings.listAppend(listMake($item[bat-oomerang], $item[bat-jute], $item[bat-o-mite])); + item_groupings.listAppend(listMake($item[incriminating evidence], $item[dangerous chemicals], $item[kidnapped orphan])); + item_groupings.listAppend(listMake($item[high-grade metal], $item[high-tensile-strength fibers], $item[high-grade explosives])); + + foreach it in item_descriptions + item_groupings.listAppend(listMake(it)); + + /*foreach it in $items[] + { + if (it.available_amount() > 0) + item_groupings.listAppend(listMake(it)); + }*/ + boolean [item] seen_items; + foreach key in item_groupings + { + ChecklistEntry entry; + entry.tags.id = "Batfellow mode item grouping " + key; + foreach key2, it in item_groupings[key] + { + if (seen_items[it]) + continue; + if (it.available_amount() > 0) + { + seen_items[it] = true; + string description = item_descriptions[it]; + if (item_descriptions contains it && description == "") //deliberately ignore, for the three upgrade items + continue; + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", description)); + if (entry.image_lookup_name == "") + entry.image_lookup_name = "__item " + it; + //resource_entries.listAppend(ChecklistEntryMake("__item " + it, "", ChecklistSubentryMake(pluralise(it), "", description), 8)); + } + } + if (entry.subentries.count() > 0) + resource_entries.listAppend(entry); + } +} + + +void LimitModeBatfellowGeneralGenerateTasks(ChecklistEntry [int] task_entries, BatState state) +{ + if (true) + { + string [int] description; + if (state.zone != "Downtown") + { + if (my_hp() == 0) + description.listAppend("Go downtown, visit the hospital?"); + } + else if (my_hp() != my_maxhp()) + description.listAppend("Visit the hospital?"); + if (description.count() > 0) + task_entries.listAppend(ChecklistEntryMake("__item bubblegum heart", "main.php", ChecklistSubentryMake("Heal", "", description), -11).ChecklistEntrySetIDTag("Batfellow mode heal")); + } +} + +void LimitModeBatfellowBossesGenerateTasks(ChecklistEntry [int] task_entries, BatState state) +{ + foreach l, area in __batfellow_bosses + { + if (area.zone != state.zone) + continue; + + int area_progress = -1; + int progress_remaining = clampi(100 - area_progress, 0, 100); + + + string [int] description; + if (progress_remaining > 0) + { + if (area_progress == -1) + description.listAppend("?% progress remaining."); + else + description.listAppend(progress_remaining + "% progress remaining."); + + if (progress_remaining > 10) + { + //description.listAppend("area = " + area.to_json()); + boolean has_fifty_progress = false; + boolean meets_fifty_progress = false; + if (area.nc_fifty_progress_requirements.count() > 0) + { + has_fifty_progress = true; + meets_fifty_progress = true; + foreach it, amount in area.nc_fifty_progress_requirements + { + if (it.available_amount() < amount) + { + meets_fifty_progress = false; + int remaining = MAX(0, amount - it.available_amount()); + description.listAppend("Avoid until you have " + remaining.int_to_wordy() + " more " + (remaining > 1 ? it.plural : it) + ".|(50% progress in NC)"); + } + } + } + if (area.nc_twenty_five_progress_requirements.count() > 0 && !(has_fifty_progress && meets_fifty_progress)) + { + foreach it, amount in area.nc_twenty_five_progress_requirements + { + if (it.available_amount() < amount) + { + int remaining = MAX(0, amount - it.available_amount()); + string line = "Avoid until you have "; + if (has_fifty_progress && !meets_fifty_progress) + line = "Or until you have "; + line += remaining.int_to_wordy() + " more " + (remaining > 1 ? it.plural : it) + ".|(25% progress in NC)"; + description.listAppend(line); + } + } + } + if (area.strategies.count() > 0) + description.listAppend(area.strategies.listJoinComponents("|")); + if (area.nc_reward_items.count() > 0) + { + string [int] rewards; + foreach it, amount in area.nc_reward_items + { + rewards.listAppend(pluralise(amount, it)); + } + description.listAppend("NC reward option gives " + rewards.listJoinComponents(", ", "and") + "."); + } + } + task_entries.listAppend(ChecklistEntryMake(area.image_name, "main.php", ChecklistSubentryMake("Fight in the " + area.short_name, "", description), 8).ChecklistEntrySetIDTag("Batfellow mode progress " + area.short_name)); + } + else + { + task_entries.listAppend(ChecklistEntryMake("__monster " + area.boss, "main.php", ChecklistSubentryMake("Defeat " + area.boss, "", ""), 8).ChecklistEntrySetIDTag("Batfellow mode fight " + area.boss)); + } + } +} + +void LimitModeBatfellowJokesterGenerateTasks(ChecklistEntry [int] task_entries, BatState state) +{ + return; +} + +void LimitModeBatfellowBatCavernGenerateTaskResources(ChecklistEntry [int] task_entries, ChecklistEntry [int] resource_entries, BatState state) +{ + boolean found_tasks = false; + if (state.funds_available > 0) + { + string [string][string] suggested_upgrades; + suggested_upgrades["Suit"] = mapMake(); + suggested_upgrades["Sedan"] = mapMake(); + suggested_upgrades["Cavern"] = mapMake(); + //orphans,evidence,chemicals bat-sedan + //lower combat time + //two that decrease searching + //glue, bearings, bat-aids after every third combat + //orphan/chemical upgrades, but not evidence upgrades? + suggested_upgrades["Suit"]["Improved Cowl Optics"] = "find things?"; + suggested_upgrades["Suit"]["Utility Belt First Aid Kit"] = "bandages every third combat"; + suggested_upgrades["Suit"]["Extra-Swishy Cloak"] = "prevents first hit in combat"; + suggested_upgrades["Suit"]["Hardened Knuckles"] = "double punch damage"; + suggested_upgrades["Suit"]["Steel-Toed Bat-Boots"] = "double kick damage"; + + suggested_upgrades["Sedan"]["Rocket Booster"] = "faster travel time"; + suggested_upgrades["Sedan"]["Street Sweeper"] = "gather evidence while driving"; + suggested_upgrades["Sedan"]["Advanced Air Filter"] = "gather dangerous chemicals while driving"; + suggested_upgrades["Sedan"]["Orphan Scoop"] = "gather orphans while driving"; + suggested_upgrades["Sedan"]["Spotlight"] = "faster progress"; + suggested_upgrades["Sedan"]["Loose Bearings"] = "bearings every third combat"; + + + suggested_upgrades["Cavern"]["Surveillance Network"] = "faster progress"; + suggested_upgrades["Cavern"]["Glue Factory"] = "glue every third combat"; + suggested_upgrades["Cavern"]["Improved 3-D Bat-Printer"] = "cheaper bat-materials"; + suggested_upgrades["Cavern"]["Really Long Winch"] = "instant travel back home"; + suggested_upgrades["Cavern"]["Blueprints Database"] = "faster progress?"; + suggested_upgrades["Cavern"]["Transfusion Satellite"] = "restores 5 hp/fight"; + + + string [int] description; + foreach type in $strings[Suit,Sedan,Cavern] + { + string [int] type_upgrades; + foreach upgrade_name, upgrade_decription in suggested_upgrades[type] + { + if (state.upgrades contains upgrade_name) + continue; + type_upgrades.listAppend(HTMLGenerateSpanOfClass(upgrade_name, "r_bold") + ": " + upgrade_decription); + } + if (type_upgrades.count() == 0) continue; + description.listAppend(HTMLGenerateSpanOfClass(type, "r_bold") + ":|*" + type_upgrades.listJoinComponents("|*")); + } + string url; + if (state.zone == "Bat-Cavern") + url = "place.php?whichplace=batman_cave&action=batman_cave_rnd"; + else + description.listAppend("Travel to the Bat-Cavern first."); + ChecklistEntry entry = ChecklistEntryMake("__item fat stacks of cash", url, ChecklistSubentryMake(pluralise(state.funds_available, "Bat-Research", "Bat-Researches"), "", description), 8); + entry.tags.id = "Batfellow mode bat-research"; + if (state.zone != "Bat-Cavern") + resource_entries.listAppend(entry); + else + { + task_entries.listAppend(entry); + found_tasks = true; + } + } + if (state.zone == "Bat-Cavern" && $items[high-grade metal,high-tensile-strength fibers,high-grade explosives].available_amount() > 0) + { + item [item] fabricator_conversions; + fabricator_conversions[$item[high-grade metal]] = $item[bat-oomerang]; + fabricator_conversions[$item[high-tensile-strength fibers]] = $item[bat-jute]; + fabricator_conversions[$item[high-grade explosives]] = $item[bat-o-mite]; + int cost_per_conversion = 3; + if (state.upgrades["Improved 3-D Bat-Printer"]) + cost_per_conversion = 2; + string [int] craftables; + foreach source, destination in fabricator_conversions + { + int amount_craftable = source.available_amount() / cost_per_conversion; + if (amount_craftable > 0) + { + craftables.listAppend(pluralise(amount_craftable, destination)); + } + } + + string [int] description; + if (craftables.count() > 0) + description.listAppend("Can make " + craftables.listJoinComponents(", ", "and") + "."); + if (description.count() > 0) + { + task_entries.listAppend(ChecklistEntryMake("__item high-grade explosives", "shop.php?whichshop=batman_cave", ChecklistSubentryMake("Bat-Fabricate", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode bat-fabricate")); + found_tasks = true; + } + } + if (!found_tasks && state.zone == "Bat-Cavern") + { + string [int] description; + task_entries.listAppend(ChecklistEntryMake("__item bitchin' meatcar", "place.php?whichplace=batman_cave&action=batman_cave_car", ChecklistSubentryMake("Travel somewhere", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode leave cavern")); + } +} +void LimitModeBatfellowDowntownGenerateTasks(ChecklistEntry [int] task_entries, BatState state) +{ + if (state.zone != "Downtown") + return; + item evidence = $item[incriminating evidence]; + item chemicals = $item[dangerous chemicals]; + item orphans = $item[kidnapped orphan]; + boolean found_tasks = false; + if (orphans.available_amount() > 0) + { + string [int] description; + string [int] options; + int hug_price = 3 + 3 * $item[confidence-building hug].available_amount(); + if (hug_price <= orphans.available_amount()) + options.listAppend("+1 damage upgrades"); + options.listAppend("freekill kickballs"); + description.listAppend(options.listJoinComponents(" / ").capitaliseFirstLetter() + "."); + task_entries.listAppend(ChecklistEntryMake("__item kidnapped orphan", "shop.php?whichshop=batman_orphanage", ChecklistSubentryMake("Turn in orphans", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode orphans")); + found_tasks = true; + } + if (chemicals.available_amount() > 0) + { + string [int] description; + string [int] options; + int hug_price = 3 + 3 * $item[experimental gene therapy].available_amount(); + if (hug_price <= chemicals.available_amount()) + options.listAppend("+10 HP upgrades"); + options.listAppend("HP-restoring ultracoagulators"); + description.listAppend(options.listJoinComponents(" / ").capitaliseFirstLetter() + "."); + task_entries.listAppend(ChecklistEntryMake("__item " + chemicals, "shop.php?whichshop=batman_chemicorp", ChecklistSubentryMake("Turn in chemicals", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode chemicals")); + found_tasks = true; + } + if (evidence.available_amount() > 0) + { + string [int] description; + string [int] options; + int hug_price = 3 + 3 * $item[self-defense training].available_amount(); + if (hug_price <= evidence.available_amount()) + options.listAppend("+armour upgrades"); + options.listAppend("progress-increasing fingerprint dusting kits"); + description.listAppend(options.listJoinComponents(" / ").capitaliseFirstLetter() + "."); + task_entries.listAppend(ChecklistEntryMake("__item " + evidence, "shop.php?whichshop=batman_pd", ChecklistSubentryMake("Turn in evidence", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode evidence")); + found_tasks = true; + } + if (!found_tasks && my_hp() == my_maxhp()) + { + string [int] description; + task_entries.listAppend(ChecklistEntryMake("__item bitchin' meatcar", "place.php?whichplace=batman_downtown&action=batman_downtown_car", ChecklistSubentryMake("Travel somewhere", "", description), 8).ChecklistEntrySetIDTag("Batfellow mode leave downtown")); + } +} + +void LimitModeBatfellowGenerateChecklists(Checklist [int] checklists) +{ + if (limit_mode() != "batman") + return; + + ChecklistEntry [int] task_entries; + ChecklistEntry [int] optional_task_entries; + ChecklistEntry [int] future_task_entries; + ChecklistEntry [int] resource_entries; + + if (true) + { + Checklist task_checklist; + task_checklist = ChecklistMake("Bat-Tasks", task_entries); + checklists.listAppend(task_checklist); + + + Checklist optional_task_checklist; + optional_task_checklist = ChecklistMake("Optional Bat-Tasks", optional_task_entries); + checklists.listAppend(optional_task_checklist); + + Checklist future_task_checklist; + future_task_checklist = ChecklistMake("Future Bat-Tasks", future_task_entries); + checklists.listAppend(future_task_checklist); + + Checklist resources_checklist; + resources_checklist = ChecklistMake("Bat-Resources", resource_entries); + checklists.listAppend(resources_checklist); + } + + BatState bat_state = BatStateMake(); + + + //task_entries.listAppend(ChecklistEntryMake("__item batarang", "", ChecklistSubentryMake("Stop the Jokester", "", "Better living through violence?"), 8)); + + LimitModeBatfellowGenerateResources(resource_entries, bat_state); + LimitModeBatfellowGeneralGenerateTasks(task_entries, bat_state); + + LimitModeBatfellowBossesGenerateTasks(task_entries, bat_state); + + LimitModeBatfellowJokesterGenerateTasks(task_entries, bat_state); + + LimitModeBatfellowBatCavernGenerateTaskResources(task_entries, resource_entries, bat_state); + LimitModeBatfellowDowntownGenerateTasks(task_entries, bat_state); +} + +RegisterResourceGenerationFunction("BatfellowGenerateResource"); +void BatfellowGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[replica bat-oomerang].available_amount() > 0 && mafiaIsPastRevision(16927)) + { + int remaining = clampi(3 - get_property_int("_usedReplicaBatoomerang"), 0, 3); + if (remaining > 0) + resource_entries.listAppend(ChecklistEntryMake("__item replica bat-oomerang", "", ChecklistSubentryMake(pluralise(remaining, "replica bat-oomerang use", "replica bat-oomerang uses"), "", "Free instakill."), 5).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Batfellow bat-oomerang free kill i'm jealous")); + } + if ($item[The Jokester's Gun].available_amount() > 0 && mafiaIsPastRevision(16986) && !get_property_boolean("_firedJokestersGun")) + { + int importance = 0; + string [int] description; + description.listAppend("Free instakill."); + if ($item[The Jokester's Gun].equipped_amount() == 0) + { + string line = "Equip it"; + if (!$item[The Jokester's Gun].can_equip()) + { + line += ", once you can. (need 50 moxie)"; + importance = 8; + } + else + line += " first."; + description.listAppend(line); + } + else + description.listAppend("Fire the Jokester's Gun skill in combat."); + resource_entries.listAppend(ChecklistEntryMake("__item The Jokester's Gun", "", ChecklistSubentryMake("The Jokester's Gun firing", "", description), importance).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Batfellow jokester gun free kill")); + } +} + + +void generateMisc(Checklist [int] checklists) +{ + if (__quest_state["Level 13"].state_boolean["king waiting to be freed"]) + { + ChecklistEntry [int] unimportant_task_entries; + string [int] king_messages; + king_messages.listAppend("You know, whenever."); + king_messages.listAppend("Or become the new naughty sorceress?"); + unimportant_task_entries.listAppend(ChecklistEntryMake("king imprismed", "place.php?whichplace=nstower", ChecklistSubentryMake("Free the King", "", king_messages)).ChecklistEntrySetIDTag("He's still trapped, just saying")); + + checklists.listAppend(ChecklistMake("Unimportant Tasks", unimportant_task_entries)); + } + + if (availableDrunkenness() < 0 && ($item[drunkula\'s wineglass].equipped_amount() == 0 || my_adventures() == 0)) + { + //They are drunk, so tasks are not as relevant. Re-arrange everything: + string url; + + //Give them something to mindlessly click on: + //url = "bet.php"; + if ($coinmaster[Game Shoppe].is_accessible()) + url = "aagame.php"; + + + Checklist task_entries = lookupChecklist(checklists, "Tasks"); + + lookupChecklist(checklists, "Future Tasks").entries.listAppendList(lookupChecklist(checklists, "Tasks").entries); + lookupChecklist(checklists, "Future Tasks").entries.listAppendList(lookupChecklist(checklists, "Optional Tasks").entries); + lookupChecklist(checklists, "Future Unimportant Tasks").entries.listAppendList(lookupChecklist(checklists, "Unimportant Tasks").entries); + + lookupChecklist(checklists, "Tasks").entries.listClear(); + lookupChecklist(checklists, "Optional Tasks").entries.listClear(); + lookupChecklist(checklists, "Unimportant Tasks").entries.listClear(); + + //Remove extra-important popups, because they will not work anymore: + Checklist future_checklist = lookupChecklist(checklists, "Future Tasks"); + foreach key, c in future_checklist.entries + { + if (c.only_show_as_extra_important_pop_up) + remove future_checklist.entries[key]; + } + + string [int] description; + string line = "You're drunk."; + if (__last_adventure_location == $location[Drunken Stupor]) + url = "campground.php"; + + if (hippy_stone_broken() && pvp_attacks_left() > 0) + url = "peevpee.php"; + + description.listAppend(line); + if ($item[drunkula\'s wineglass].available_amount() > 0 && $item[drunkula\'s wineglass].can_equip() && my_adventures() > 0) + { + description.listAppend("Or equip your wineglass."); + } + + int pvp_fights_gained = numeric_modifier("pvp fights").to_int() + 10; + int pvp_fights_after_rollover_before_caps = pvp_attacks_left() + pvp_fights_gained; + int pvp_fights_after_rollover = MIN(pvp_fights_after_rollover_before_caps, 100); + if (today_is_pvp_season_end()) + pvp_fights_after_rollover = 0; + + int adventures_after_rollover = __misc_state_int["adventures after rollover"]; + + string [int] all_tomorrows_parties; + all_tomorrows_parties.listAppend(pluralise(adventures_after_rollover, "adventure", "adventures")); //it should be impossible to have under twenty adventures after rollover, but why should that stop us from checking the singular case? + if (hippy_stone_broken() && pvp_fights_after_rollover > 0) + all_tomorrows_parties.listAppend(pluralise(pvp_fights_after_rollover, "fight", "fights")); + + description.listAppend("Will start with " + all_tomorrows_parties.listJoinComponents(", ", "and") + " tomorrow."); + + int rollover_adventures_from_equipment = 0; + foreach s in $slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3,familiar] + rollover_adventures_from_equipment += s.equipped_item().numeric_modifier("adventures").to_int_silent(); + + //detect if they're going to lose some turns, be nice: + int adventures_lost = __misc_state_int["adventures lost to rollover"]; + if (rollover_adventures_from_equipment == 0.0 && adventures_lost == 0 && my_path().id != PATH_SLOW_AND_STEADY) + { + description.listAppend("Possibly wear +adventures gear."); + } + if (adventures_lost > 0) + { + string [int] leisure_activities; + leisure_activities.listAppend("work out in the gym"); + leisure_activities.listAppend("craft"); + if ($item[game grid ticket].is_unrestricted()) + leisure_activities.listAppend("play arcade games"); + description.listAppend("You'll miss out on " + pluraliseWordy(adventures_lost, "adventure", "adventures") + ". Alas.|Could " + leisure_activities.listJoinComponents(", ", "or") + "."); + } + + if (hippy_stone_broken()) + { + int pvp_fights_lost = pvp_fights_after_rollover_before_caps - pvp_fights_after_rollover;//MAX(0, pvp_fights_after_rollover_before_caps - 100); + if (pvp_fights_lost > 0 && pvp_attacks_left() > 0) + { + description.listAppend("Fight " + pluralise(MIN(pvp_attacks_left(), pvp_fights_lost), "time", "times") + " to avoid losing fights to rollover."); + } + } + + //this could be better (i.e. checking against current shirt and looking in inventory, etc.) + if (my_path().id != PATH_SLOW_AND_STEADY) + { + if ($item[Sneaky Pete's leather jacket (collar popped)].equipped_amount() > 0 && adventures_lost <= 0) + description.listAppend("Could unpop your collar. (+4 adventures)"); + if ($item[Sneaky Pete's leather jacket].equipped_amount() > 0 && hippy_stone_broken()) + description.listAppend("Could pop your collar. (+4 fights)"); + if (in_ronin() && $item[resolution: be more adventurous].available_amount() > 0 && get_property_int("_resolutionAdv") < 5) + { + description.listAppend("Use resolution: be more adventurous."); + } + } + if (in_ronin() && pulls_remaining() > 0) + { + description.listAppend("Don't forget your " + pluraliseWordy(pulls_remaining(), "pull", "pulls") + "."); + } + //FIXME resolution be more adventurous goes here + + task_entries.entries.listAppend(ChecklistEntryMake("__item counterclockwise watch", url, ChecklistSubentryMake("Wait for rollover", "", description), -11).ChecklistEntrySetIDTag("Game unplayable")); + if (stills_available() > 0 && __misc_state["in run"]) + { + string url = "shop.php?whichshop=still"; + if ($item[soda water].available_amount() == 0) + url = "shop.php?whichshop=generalstore"; + task_entries.entries.listAppend(ChecklistEntryMake("__item tonic water", url, ChecklistSubentryMake("Make " + pluralise(stills_available(), $item[tonic water]), "", listMake("Tonic water is a ~40MP restore, improved from soda water.", "Or improve drinks.")), -11).ChecklistEntrySetIDTag("End of day nash crosby still")); + } + } +} + + +void generateChecklists(Checklist [int] ordered_output_checklists) +{ + setUpState(); + setUpQuestState(); + + if (__misc_state["Example mode"]) + setUpExampleState(); + + finaliseSetUpState(); + + Checklist [int] checklists; + + ChecklistCollection checklist_collection; + + if (limit_mode() == "spelunky") + { + LimitModeSpelunkingGenerateChecklists(checklists); + } + else if (limit_mode() == "batman") + { + LimitModeBatfellowGenerateChecklists(checklists); + } + else if (!playerIsLoggedIn() && !__misc_state["Example mode"]) + { + Checklist task_entries = lookupChecklist(checklists, "Tasks"); + + string image_name; + image_name = "disco bandit"; + task_entries.entries.listAppend(ChecklistEntryMake(image_name, "", ChecklistSubentryMake("Log in", "+internet", "An Adventurer is You!"), -11).ChecklistEntrySetIDTag("Not logged in")); + } + else if (__misc_state["In valhalla"] && !__misc_state["Example mode"]) + { + //Valhalla: + Checklist task_entries = lookupChecklist(checklists, "Tasks"); + task_entries.entries.listAppend(ChecklistEntryMake("astral spirit", "", ChecklistSubentryMake("Start a new life", "", listMake("Perm skills.", "Buy consumables.", "Bring along a pet."))).ChecklistEntrySetIDTag("Astral spirit")); + } + else + { + generateDailyResources(checklists); + + generateTasks(checklists); + if (__misc_state["Example mode"] || !__misc_state["in aftercore"]) + { + generateMissingItems(checklists); + generatePullList(checklists); + } + if (__setting_debug_show_all_internal_states && __setting_debug_mode) + { + generateAllTests(checklists); + } + generateFloristFriar(checklists); + + + generateStrategy(checklists); + + foreach key, checklist_generation_function_name in __checklist_generation_function_names + { + call checklist_generation_function_name(checklist_collection); + } + + foreach checklist_name in __specific_checklist_1_generation_function_names + { + ChecklistEntry [int] checklist_entries = checklist_collection.lookup(checklist_name).entries; + foreach key, function_name in __specific_checklist_1_generation_function_names[checklist_name] + { + call function_name(checklist_entries); + } + } + foreach key, request in __specific_checklist_generation_requests + { + int argument_count = request.checklist_names.count(); + string function_name = request.function_name; + //"call request.function_name()" will not work + if (argument_count == 3) + { + call function_name(checklist_collection.lookup(request.checklist_names[0]).entries, checklist_collection.lookup(request.checklist_names[1]).entries, checklist_collection.lookup(request.checklist_names[2]).entries); + } + else if (argument_count == 2) + { + call function_name(checklist_collection.lookup(request.checklist_names[0]).entries, checklist_collection.lookup(request.checklist_names[1]).entries); + } + else if (argument_count == 1) + { + call function_name(checklist_collection.lookup(request.checklist_names[0]).entries); + } + } + } + + + //Convert checklist_collection to checklists: + checklists = ChecklistCollectionMergeWithLinearList(checklist_collection, checklists); + + generateMisc(checklists); //Last, due to drunkenness re-arranging + + //Remove checklists that have no entries: + int [int] keys_to_remove; + foreach key in checklists + { + Checklist cl = checklists[key]; + if (cl.entries.count() == 0) + keys_to_remove.listAppend(key); + } + listRemoveKeys(checklists, keys_to_remove); + listClear(keys_to_remove); + + //Go through desired output order: + string [int] setting_desired_output_order = split_string_alternate("Tasks,Keys,Optional Tasks,Unimportant Tasks,Future Tasks,Resources,Future Unimportant Tasks,Required Items,Suggested Pulls,Florist Friar,Strategy", ","); + foreach key in setting_desired_output_order { + string title = setting_desired_output_order[key]; + //Find title in checklists: + foreach key2 in checklists { + Checklist cl = checklists[key2]; + if (cl.title == title) { + ordered_output_checklists.listAppend(cl); + keys_to_remove.listAppend(key2); + break; + } + } + } + listRemoveKeys(checklists, keys_to_remove); + listClear(keys_to_remove); + + //Add remainder: + foreach key in checklists { + Checklist cl = checklists[key]; + ordered_output_checklists.listAppend(cl); + } +} + +/** +Adds the checklists to the DOM. +@param ordered_output_checklists Checklists to output. +*/ +void outputChecklists(Checklist [int] ordered_output_checklists) { + Checklist extra_important_tasks; + + // Checklists: + foreach i, cl in ordered_output_checklists { + // Check for Pin + if (__show_importance_bar && cl.title == "Tasks") { + foreach key, entry in cl.entries { + if (entry.importance_level <= -11) { + extra_important_tasks.entries.listAppend(entry); + if (entry.only_show_as_extra_important_pop_up) { + remove cl.entries[key]; + } + } + } + } + + // Output + PageWrite(ChecklistGenerate(cl)); + } + + if (__show_importance_bar && extra_important_tasks.entries.count() > 0) { + extra_important_tasks.title = "Tasks"; + extra_important_tasks.disable_generating_id = true; + PageWrite(HTMLGenerateTagPrefix("div", mapMake("id", "importance_bar", "style", "z-index:3;position:fixed; top:0;width:100%;max-width:" + __setting_horizontal_width + "px;visibility:hidden;"))); + PageWrite(ChecklistGenerate(extra_important_tasks, false)); + + string background = "background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAUCAYAAABMDlehAAAAb0lEQVR42gFkAJv/AFFRUf8AVlZW+ABcXFzvAGRjY+QAa2xr2AB1dHXLAH5+fr0AiIiIrgCTk5KfAJ2dnZAAqKiofwCzs7JwAL69vmAAyMjIUQDS0tJBANzb3DMA5eXlJwDt7e0bAPT09BAA+vr6B861MNMaArkVAAAAAElFTkSuQmCC);background-repeat:repeat-x;"; //use this gradient image, because alpha gradients are not consistent across browsers (compare black to white, 100% to zero opacity, on safari versus firefox) + + PageWrite(HTMLGenerateTagWrap("div", "", mapMake("id", "importance_bar_gradient", "style", "height:20px;transition:opacity 0.25s;opacity:0;" + background))); + PageWrite(HTMLGenerateTagSuffix("div")); + } +} + + + +Record BadMoonAdventure +{ + int encounter_id; + string category; + string description; + string conditions_to_finish; + boolean has_additional_requirements_not_yet_met; + location [int] locations; +}; + +BadMoonAdventure BadMoonAdventureMake(int encounter_id, location [int] locations, string category, string description, string conditions_to_finish, boolean has_additional_requirements_not_yet_met) +{ + BadMoonAdventure adventure; + adventure.encounter_id = encounter_id; + adventure.category = category; + adventure.description = description; + adventure.conditions_to_finish = conditions_to_finish; + adventure.has_additional_requirements_not_yet_met = has_additional_requirements_not_yet_met; + adventure.locations = locations; + return adventure; +} + +BadMoonAdventure BadMoonAdventureMake(int encounter_id, location l, string category, string description, string conditions_to_finish, boolean has_additional_requirements_not_yet_met) +{ + location [int] locations; + locations.listAppend(l); + return BadMoonAdventureMake(encounter_id, locations, category, description, conditions_to_finish, has_additional_requirements_not_yet_met); +} + +void listAppend(BadMoonAdventure [int] list, BadMoonAdventure entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + + +/* +Categories: +DAMAGE1 +DAMAGE2 +ELEMENTALDAMAGE1 - +10 elemental damage, -2 DR +ELEMENTALDAMAGE2 - +20 elemental damage, - ~2 HP/round +DAMAGE_REDUCTION - +DR, -8 weapon damage +Familiar Hatchlings - +ITEM_DROP +ITEMS +meat +MEAT_DROP +RESIST1 +RESIST2 +SKILLS +STAT1 - +20 one stat, -5 two other stats +STAT2 - +40 one stat, -50% familiar weight +STAT3 - +50% one stat, -50% other stat +*/ +static +{ + BadMoonAdventure [int] __static_bad_moon_adventures; + BadMoonAdventure [location] __static_bad_moon_adventures_by_location; + void initialiseStaticBadMoonAdventures() + { + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(2, $location[The Haunted Pantry], "STAT1", "+20 myst, -5 muscle/moxie", "", false)); //FIXME is there a conditional on this? + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(3, $location[The Sleazy Back Alley], "STAT1", "+20 moxie, -5 myst/muscle", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(4, $location[Cobb's Knob Treasury], "STAT2", "+40 muscle, -50% familiar weight", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(5, $location[Cobb's Knob Kitchens], "STAT2", "+40 myst, -50% familiar weight", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(6, $location[Cobb's Knob Harem], "STAT2", "+40 moxie, -50% familiar weight", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(7, $location[The Orcish Frat House], "STAT3", "+50% muscle, -50% myst", "", false)); + // __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(8, $location[Frat House In Disguise], "STAT3", "+50% muscle, -50% moxie", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(8, fratHouseInDisguise(), "STAT3", "+50% muscle, -50% moxie", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(9, $location[The Hippy Camp], "STAT3", "+50% myst, -50% moxie", "", false)); + // __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(10, $location[Hippy Camp In Disguise], "STAT3", "+50% myst, -50% muscle", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(10, hippyCampInDisguise(), "STAT3", "+50% myst, -50% muscle", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(11, $location[The Obligatory Pirate's Cove], "STAT3", "+50% moxie, -50% muscle", "", false)); + //12 is gone? was: The Obligatory Pirate's Cove (In Disguise) //retired + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(15, $location[The Haunted Kitchen], "ELEMENTALDAMAGE1", "+10 " + HTMLGenerateElementSpanDesaturated($element[hot]) + " damage, -2 DR", "", false)); + //__static_bad_moon_adventures.listAppend(BadMoonAdventureMake(17, $location[The Haunted Library], "ELEMENTALDAMAGE1", "+10 " + HTMLGenerateElementSpanDesaturated($element[spooky]) + " damage, -2 DR", "", false)); //retired + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(18, $location[Guano Junction], "ELEMENTALDAMAGE1", "+10 " + HTMLGenerateElementSpanDesaturated($element[stench]) + " damage, -2 DR", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(20, $location[The Icy Peak], "ELEMENTALDAMAGE2", "+20 " + HTMLGenerateElementSpanDesaturated($element[cold]) + " damage, ~2 HP lost/round", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(28, $location[Tower Ruins], "RESIST1", "+2 " + HTMLGenerateElementSpanDesaturated($element[spooky], "res") + ", 2x damage from stench/hot", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(32, $location[Cobb's Knob Laboratory], "ITEM_DROP", "+50% item, -5 stats/fight", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(33, $location[The Haunted Bathroom], "ITEM_DROP", "+100% item, -20 all stats", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(34, $location[The Unquiet Garves], "MEAT_DROP", "+50% meat, -50% init", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(35, $location[The VERY Unquiet Garves], "MEAT_DROP", "+200% meat, -50% item", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(38, $location[the spooky forest], "meat", "1000 meat", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(41, $location[south of the border], "meat", "4000 meat, beaten up", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(43, $location[Noob Cave], "Familiar Hatchlings", "Black cat hatchling, 14 drunkenness", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(46, $location[A Barroom Brawl], "Familiar Hatchlings", "Leprechaun hatchling, one drunkenness", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(47, $location[The Hidden Temple], "ITEMS", "Loaded dice", "", false)); + __static_bad_moon_adventures.listAppend(BadMoonAdventureMake(48, $location[The Haunted Conservatory], "Familiar Hatchlings", "Potato sprout", "", false)); + } + initialiseStaticBadMoonAdventures(); +} + +//FIXME make this work in scripts that aren't guide +//We should probably have an "invalidate caches" message that happens whenever state may have changed. +//Maybe a global variable in the library that's incremented by one, and caches check themselves against that. +//Querying that variable would be through a function, so it automatically increments by one if the turncount changes. + +BadMoonAdventure [int] __all_bad_moon_adventures_cache; +int __all_bad_moon_adventures_cache_on_turn = -1; +BadMoonAdventure [int] AllBadMoonAdventures() +{ + if (__all_bad_moon_adventures_cache.count() > 0 && __all_bad_moon_adventures_cache_on_turn == my_turncount()) + return __all_bad_moon_adventures_cache; + BadMoonAdventure [int] adventures; + + foreach key, adventure in __static_bad_moon_adventures + { + adventures.listAppend(adventure); + } + + adventures.listAppend(BadMoonAdventureMake(39, $location[the degrassi knoll garage], "meat", "2000 meat, -myst debuff", "finish meatcar guild quest", !QuestState("questG01Meatcar").finished)); + adventures.listAppend(BadMoonAdventureMake(40, $location[the bat hole entrance], "meat", "3000 meat, -moxie debuff", "open boss bat's lair", __quest_state["Level 4"].state_int["areas unlocked"] < 3)); + + adventures.listAppend(BadMoonAdventureMake(1, $location[the Outskirts of Cobb's Knob], "STAT1", "+20 muscle, -5 myst/moxie", "find encryption key", $item[knob goblin encryption key].available_amount() == 0 && !$location[cobb's knob kitchens].locationAvailable())); + //adventures.listAppend(BadMoonAdventureMake(13, $location[The Haunted Billiards Room], "DAMAGE1", "+10 damage, -2 DR", "open the Haunted Library", !$location[the haunted library].locationAvailable())); //retired + //adventures.listAppend(BadMoonAdventureMake(14, $location[The Goatlet], "ELEMENTALDAMAGE1", "+10 " + HTMLGenerateElementSpanDesaturated($element[cold]) + " damage, -2 DR", "unlock the eXtreme Slope", !$location[the extreme slope].locationAvailable())); //retired + adventures.listAppend(BadMoonAdventureMake(16, $location[Pandamonium Slums], "ELEMENTALDAMAGE1", "+10 " + HTMLGenerateElementSpanDesaturated($element[sleaze]) + " damage, -2 DR", "get Steel Margarita", !QuestState("questM10Azazel").finished)); + //adventures.listAppend(BadMoonAdventureMake(19, $location[The Castle in the Clouds in the Sky (somewhere)], "DAMAGE2", "+20 melee damage, ~2 HP lost/round", "completed trash quest", REPLACEMEB)); //retired + //adventures.listAppend(BadMoonAdventureMake(21, $location[Oasis], "ELEMENTALDAMAGE2", "+20 " + HTMLGenerateElementSpanDesaturated($element[hot]) + " damage, ~2 HP lost/round", "find worm-riding hooks", REPLACEMEB)); //seems retired + adventures.listAppend(BadMoonAdventureMake(22, $location[The Hole in the Sky], "ELEMENTALDAMAGE2", "+20 " + HTMLGenerateElementSpanDesaturated($element[sleaze]) + " damage, ~2 HP lost/round", "make Richard's star key", $item[richard's star key].available_amount() == 0)); + //adventures.listAppend(BadMoonAdventureMake(23, $location[The Haunted Ballroom], "ELEMENTALDAMAGE2", "+20 " + HTMLGenerateElementSpanDesaturated($element[spooky]) + " damage, ~2 HP lost/round", "open Spookyraven basement", !$location[the haunted wine cellar].locationAvailable())); //retired + //adventures.listAppend(BadMoonAdventureMake(24, $location[The Black Forest], "ELEMENTALDAMAGE2", "+20 " + HTMLGenerateElementSpanDesaturated($element[stench]) + " damage, ~2 HP lost/round", "open black market", !black_market_available())); //retired + adventures.listAppend(BadMoonAdventureMake(25, $location[Inside the Palindome], "RESIST1", "+2 " + HTMLGenerateElementSpanDesaturated($element[cold], "res") + ", 2x damage from hot/spooky", "defeat Dr. Awkward", !QuestState("questL11Palindome").finished)); + //adventures.listAppend(BadMoonAdventureMake(26, $location[REPLACEME], "RESIST1", "+2 " + HTMLGenerateElementSpanDesaturated($element[hot], "res") + ", 2x damage from stench/sleaze", "REASONWHYNOTREPLACEME", REPLACEMEB)); //Pot-Unlucky - UNKNOWN //retired + adventures.listAppend(BadMoonAdventureMake(27, $location[The Valley of Rof L'm Fao], "RESIST1", "+2 " + HTMLGenerateElementSpanDesaturated($element[sleaze], "res") + ", 2x damage from cold/spooky", "acquire facsimile dictionary", $item[facsimile dictionary].available_amount() == 0)); + //adventures.listAppend(BadMoonAdventureMake(29, $location[The Arid, Extra-Dry Desert], "RESIST1", "+2 " + HTMLGenerateElementSpanDesaturated($element[stench], "res") + ", 2x damage from cold/sleaze", "need to have ultrahydrated", $effect[ultrahydrated].have_effect() > 0)); //retired + adventures.listAppend(BadMoonAdventureMake(30, $location[the Beanbat Chamber], "RESIST2", "+1 all res, -10% stats", "plant beanstalk", !__quest_state["Level 10"].state_boolean["beanstalk grown"])); + //adventures.listAppend(BadMoonAdventureMake(31, $location[The Haunted Wine Cellar], "RESIST2", "+2 all res, -20% stats", "defeat Lord Spookyraven", !__quest_state["Level 11 Manor"].finished)); //retired + adventures.listAppend(BadMoonAdventureMake(36, $location[8-bit realm], "DAMAGE_REDUCTION", "+4 DR, -8 damage", "acquire digital key", $item[digital key].available_amount() == 0)); + adventures.listAppend(BadMoonAdventureMake(37, $location[The Penultimate Fantasy Airship], "DAMAGE_REDUCTION", "+8 DR, -8 damage", "unlock castle", $item[s.o.c.k.].available_amount() == 0)); + QuestState white_citadel_quest = QuestState("questG02Whitecastle"); + adventures.listAppend(BadMoonAdventureMake(42, $location[whitey's grove], "meat", "5000 meat, -20% stats debuff", "finish white citadel quest? (this needs spading)", !(!white_citadel_quest.started || white_citadel_quest.finished))); + //adventures.listAppend(BadMoonAdventureMake(45, $location[The Arid, Extra-Dry Desert], "ITEMS", "anticheese", "need to not have ultrahydrated", $effect[ultrahydrated].have_effect() == 0)); //is this still here? //retired + + adventures.listAppend(BadMoonAdventureMake(44, $location[the spooky forest], "SKILLS", "torso awareness, -50% muscle debuff", "unlock hidden temple", !get_property_ascension("lastTempleUnlock"))); + + __all_bad_moon_adventures_cache = adventures; + __all_bad_moon_adventures_cache_on_turn = my_turncount(); + + return adventures; +} +BadMoonAdventure [string][int] AllBadMoonAdventuresByCategory() +{ + BadMoonAdventure [string][int] result; + foreach key, adventure in AllBadMoonAdventures() + { + if (!(result contains adventure.category)) + { + BadMoonAdventure [int] blank; + result[adventure.category] = blank; + } + result[adventure.category].listAppend(adventure); + } + return result; +} + +BadMoonAdventure [int] BadMoonAdventuresForLocation(location l) +{ + BadMoonAdventure [int] result; + foreach key, adventure in AllBadMoonAdventures() + { + foreach key, l2 in adventure.locations + { + if (l == l2) + { + result.listAppend(adventure); + break; + } + } + } + return result; +} + +RegisterTaskGenerationFunction("PathBadMoonGenerateTasks"); +void PathBadMoonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!in_bad_moon()) + return; + if (my_turncount() == 0 && !haveSeenBadMoonEncounter(43) && $item[black kitten].available_amount() == 0 && !$familiar[black cat].have_familiar()) + { + string [int] description; + description.listAppend("For a black cat run. So cute!"); + description.listAppend("Adventure in the noob cave " + HTMLGenerateSpanFont("once", "red") + "."); + description.listAppend(HTMLGenerateSpanFont("Will cost 14 drunkenness.", "red")); + optional_task_entries.listAppend(ChecklistEntryMake("__familiar black cat", "", ChecklistSubentryMake("Possibly adopt a black kitten", "", description)).ChecklistEntrySetIDTag("Bad moon path black cat familiar masochist oh god no why")); + } + + //Finding familiars - +item, +meat, +stats + + if (my_familiar() != $familiar[black cat]) + { + if (!$familiar[blood-faced volleyball].have_familiar() && !$familiar[smiling rat].have_familiar()) + { + string [int] description; + string url; + + string [int] tasks; + if ($item[blood-faced volleyball].available_amount() > 0) + { + tasks.listAppend("use blood-faced volleyball"); + url = "inventory.php?ftext=blood-faced+volleyball"; + } + else + { + int trinkets_needed = 0; + if ($item[volleyball].available_amount() == 0) + { + string line = "collect a volleyball"; + if ($effect[bloody hand].have_effect() == 0 && $item[seal tooth].available_amount() == 0) + { + line += " and seal tooth"; + trinkets_needed += 1; + } + line += " from the hermit"; + tasks.listAppend(line); + url = "hermit.php"; + trinkets_needed += 1; + } + if ($effect[bloody hand].have_effect() == 0) + { + if ($item[seal tooth].available_amount() == 0 && $item[volleyball].available_amount() > 0) + { + tasks.listAppend("collect a seal tooth from the hermit"); + url = "hermit.php"; + trinkets_needed += 1; + } + tasks.listAppend("use seal tooth to acquire a bloody hand (ow!)"); + if (url != "" && $item[seal tooth].available_amount() > 0) + url = "inventory.php?ftext=seal+tooth"; + } + int trinkets_missing = MAX(0, trinkets_needed - $items[worthless trinket,worthless gewgaw,worthless knick-knack].available_amount()); + if (trinkets_missing > 0) + { + tasks.listPrepend("collect " + pluralise(trinkets_missing, $item[worthless trinket]) + " (use chewing gum)"); + if ($item[chewing gum on a string].available_amount() == 0) + url = "shop.php?whichshop=generalstore"; + else + url = "inventory.php?ftext=chewing+gum+on+a+string"; + if ($item[hermit permit].available_amount() == 0) + { + tasks.listPrepend("buy hermit permit"); + url = "shop.php?whichshop=generalstore"; + } + } + + tasks.listAppend("use volleyball"); + if (url != "" && $item[volleyball].available_amount() > 0 && $effect[bloody hand].have_effect() > 0) + url = "inventory.php?ftext=volleyball"; + + tasks.listAppend("use blood-faced volleyball"); + } + description.listAppend(tasks.listJoinComponents(", ").capitaliseFirstLetter() + "."); + optional_task_entries.listAppend(ChecklistEntryMake("__familiar blood-faced volleyball", url, ChecklistSubentryMake("Adopt a blood-faced volleyball", "", description)).ChecklistEntrySetIDTag("Bad moon path volleyball familiar")); + } + if (!$familiar[Leprechaun].have_familiar()) + { + string [int] description; + string url; + if ($item[leprechaun hatchling].available_amount() > 0) + { + description.listAppend("Use a leprechaun hatchling."); + url = "inventory.php?ftext=leprechaun+hatchling"; + } + else if (!haveSeenBadMoonEncounter(46) && $location[a barroom brawl].locationAvailable()) + { + description.listAppend("Find in a barroom brawl."); + url = $location[a barroom brawl].getClickableURLForLocation(); + } + if (description.count() > 0) + optional_task_entries.listAppend(ChecklistEntryMake("__familiar Leprechaun", url, ChecklistSubentryMake("Adopt a leprechaun", "", description), $locations[a barroom brawl]).ChecklistEntrySetIDTag("Bad moon path leprechaun familiar")); + } + if (!$familiar[baby gravy fairy].have_familiar()) + { + string [int] description; + string [int] modifiers; + string url; + + if ($item[pregnant mushroom].available_amount() > 0) + { + description.listAppend("Use a pregnant mushroom."); + url = "inventory.php?ftext=pregnant+mushroom"; + } + else if ($item[pregnant mushroom].creatable_amount() > 0) + { + description.listAppend("Create and use a pregnant mushroom."); + url = "craft.php?mode=cook"; + } + else + { + boolean need_minus_combat = false; + if ($item[fairy gravy boat].available_amount() == 0) + { + need_minus_combat = true; + description.listAppend("Adventure in the Haiku Dungeon for a fairy gravy boat.|Second choice in the NC."); + url = $location[the haiku dungeon].getClickableURLForLocation(); + } + if ($item[Knob mushroom].available_amount() == 0) + { + need_minus_combat = true; + description.listAppend("Find a knob mushroom somewhere.|Probably the haiku dungeon. First choice in the NC.|The cobb's knob kitchens are also an option. (?)"); + url = $location[the haiku dungeon].getClickableURLForLocation(); + } + if (need_minus_combat) + modifiers.listAppend("-combat"); + } + + optional_task_entries.listAppend(ChecklistEntryMake("__familiar baby gravy fairy", url, ChecklistSubentryMake("Adopt a baby gravy fairy", modifiers, description)).ChecklistEntrySetIDTag("Bad moon path fairy familiar")); + } + if (!$familiar[cocoabo].have_familiar() && $item[cocoa egg].available_amount() + $item[cocoa egg].creatable_amount() > 0) + { + //thanks harumph + string [int] description; + string url; + if ($item[cocoa egg].available_amount() == 0) + { + description.listAppend("Cook two cocoa eggshell fragments together twice, then cook two large cocoa eggshell fragments together.|Then use the cocoa egg."); + url = "craft.php?mode=cook"; + } + else + { + description.listAppend("Use a cocoa egg."); + url = "inventory.php?ftext=cocoa+egg"; + } + optional_task_entries.listAppend(ChecklistEntryMake("__familiar cocoabo", url, ChecklistSubentryMake("Adopt a cocoabo", "", description)).ChecklistEntrySetIDTag("Bad moon path cocoabo familiar")); + + } + } + //FIXME do we want the init semi-rare potion? it's only +100%... but, that might save a lot of turns? +} + +RegisterResourceGenerationFunction("PathBadMoonGenerateResource"); +void PathBadMoonGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!in_bad_moon()) + return; + + if (in_bad_moon() && !get_property_boolean("styxPixieVisited")) + { + string [int] description; + description.listAppend("Rubdown: +25% muscle, +5 DR, +10 damage."); + description.listAppend("Mind: +25% mysticality, +10-15 mp regen, +15 spell damage."); + description.listAppend("Colonge: +20% items, +25% moxie, +40% meat."); + resource_entries.listAppend(ChecklistEntryMake("__effect Hella Smooth", "heydeze.php?place=styx", ChecklistSubentryMake("Styx pixie buff", "", description), 10).ChecklistEntrySetIDTag("Bad moon path styx pixie resource")); + } + + if ($item[ghost key].available_amount() > 0 && __misc_state["in run"]) + { + string url = ""; + if ($location[the haunted bedroom].locationAvailable()) + url = $location[the haunted bedroom].getClickableURLForLocation(); + + string [int] description; + + if (__misc_state["need to level"]) + { + string target_nightstand = ""; + if (my_primestat() == $stat[muscle]) + target_nightstand = "simple"; + else if (my_primestat() == $stat[mysticality]) + target_nightstand = "ornate"; + else if (my_primestat() == $stat[moxie]) + target_nightstand = "rustic"; + description.listAppend("? mainstat from a " + target_nightstand + " nightstand."); //wiki says 200, but I saw 87 at level nine in bad moon + } + description.listAppend("1000 meat from a mahogany nightstand."); + resource_entries.listAppend(ChecklistEntryMake("__item ghost key", url, ChecklistSubentryMake(pluralise($item[ghost key]), "", description), 10).ChecklistEntrySetIDTag("Bad moon path ghost key resource")); + + } +} + +void PathBadMoonGenerateCategoryChecklistEntry(BadMoonAdventure [string][int] adventures_by_category, ChecklistEntry [int] bad_moon_adventures_entries, string [int] categories, string image_name, string header, string [int] initial_d_escription) +{ + string [int][int] description_active; + string [int][int] description_inactive; + + string url; + boolean [location] relevant_locations; + foreach key1, category in categories + { + foreach key2, adventure in adventures_by_category[category] + { + if (haveSeenBadMoonEncounter(adventure.encounter_id)) + continue; + + string [int] line; + line.listAppend(adventure.locations.listJoinComponents(" / ")); + + string line2 = adventure.description; + + + boolean greyed_out = false; + if (adventure.has_additional_requirements_not_yet_met) + { + line2 += ".|Need to " + adventure.conditions_to_finish + "."; + //line = HTMLGenerateSpanFont(line, "grey"); + greyed_out = true; + } + else + line2 += "."; + line.listAppend(line2); + + if (!greyed_out) + { + boolean have_open_location = false; + foreach key, l in adventure.locations + { + if (l.locationAvailable()) + { + if (url == "") + url = l.getClickableURLForLocation(); + have_open_location = true; + } + /*if (__setting_debug_mode) + { + Error unable_to_find_location; + l.locationAvailable(unable_to_find_location); + if (unable_to_find_location.was_error) + print_html("\"" + l + "\" unknown to locationAvailable"); + + }*/ + } + if (!have_open_location) + { + //line = HTMLGenerateSpanFont(line, "grey"); + greyed_out = true; + } + } + + if (greyed_out) + { + foreach key, value in line + { + line[key] = HTMLGenerateSpanFont(value, "grey"); + } + description_inactive.listAppend(line); + } + else + { + foreach key, l in adventure.locations + relevant_locations[l] = true; + description_active.listAppend(line); + } + } + } + string [int] description; + + description.listAppendList(initial_d_escription); //deja vu! + foreach key in description_inactive + { + description_active.listAppend(description_inactive[key]); + } + if (description_active.count() + description.count() > 0) + { + description.listAppend(HTMLGenerateSimpleTableLines(description_active)); + bad_moon_adventures_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(header, "", description), relevant_locations).ChecklistEntrySetIDTag("Bad moon path " + header + " special advs")); + } +} + +void PathBadMoonGenerateCategoryChecklistEntry(BadMoonAdventure [string][int] adventures_by_category, ChecklistEntry [int] bad_moon_adventures_entries, string [int] categories, string image_name, string header) +{ + PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, categories, image_name, header, listMakeBlankString()); +} + +RegisterChecklistGenerationFunction("PathBadMoonGenerateChecklists"); +void PathBadMoonGenerateChecklists(ChecklistCollection checklist_collection) +{ + if (!in_bad_moon()) + return; + + ChecklistEntry [int] bad_moon_adventures_entries = checklist_collection.lookup("Bad Moon Adventures").entries; + + + //badMoonEncounter01 to badMoonEncounter48 + //umm... that's a lot... + //each area has up to one encounter, but many areas may have the same encounter (frat house/hippy camp) + + /* + They're all classified under different areas, though. + + Things to mention: + √lots of meat, -something + √+X% item, -something + √+X% meat, -something + √+2 elemental resistance, 2x damage from two other elements + √+resistance all elements, all attributes -% + √+20 mainstat, -5 other stats + √+40 mainstat, -50% familiar weight (black cat!) + √items, -something (√black kitten and terrarium, √torso awareness, anticheese (irrelevant), √leprechaun, loaded dice (irrelevant), √potato sprout (irrelevant?) + + Maybe: + √+50% stat, -50% other stat + √+20 elemental damage, -~2 damage/round (g-g-g-ghosts!) + √+10 elemental damage, -2 DR (g-g-g-ghosts!) + + ???: + +DR, -8 weapon damage + */ + + BadMoonAdventure [string][int] adventures_by_category = AllBadMoonAdventuresByCategory(); + + PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("meat"), "__item dense meat stack", "Meat"); + if (my_familiar() != $familiar[black cat]) + PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("Familiar hatchlings"), "__item Familiar-Gro™ Terrarium", "Familiar hatchlings"); + PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("ITEM_DROP"), "__item Mr. Cheeng's spectacles", "Item buffs"); + PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("MEAT_DROP"), "__item old leather wallet", "Meat buffs"); + + string [int] elemental_damage_ordering = listMake("ELEMENTALDAMAGE1", "ELEMENTALDAMAGE2"); + if (my_level() >= 10) + elemental_damage_ordering = listMake("ELEMENTALDAMAGE2", "ELEMENTALDAMAGE1"); //don't encourage the +20 buffs until later + PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("RESIST1", "RESIST2"), "__item yak anorak", "Elemental resist buffs"); + PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, listMake("STAT2", "STAT1", "STAT3"), "__effect Phorcefullness", "Stat buffs"); + PathBadMoonGenerateCategoryChecklistEntry(adventures_by_category, bad_moon_adventures_entries, elemental_damage_ordering, "__item oversized snowflake", "Elemental damage buffs", listMake("For defeating ghosts.")); + + if (!$skill[12].have_skill() && !haveSeenBadMoonEncounter(44) && $location[the hidden temple].locationAvailable()) // Torso Aware(g)ness + { + string [int] description; + description.listAppend("Spooky forest."); + + if ($item[grue egg omelette].available_amount() == 0 && $item[spooky mushroom].available_amount() == 0 && ($item[strange leaflet].available_amount() == 0 || $item[grue egg].available_amount() == 0)) + { + description.listAppend("Farm a spooky mushroom (for grue omelette) while you're there: " + listMake("Explore the stream", "March to the marsh").listJoinComponents(__html_right_arrow_character)); + } + else + description.listAppend("Farm spices (for spicy burritos) while you're there: " + listMake("Brave the dark thicket", "Follow the even darker path", "Take the scorched path", "Investigate the moist crater").listJoinComponents(__html_right_arrow_character)); + + bad_moon_adventures_entries.listAppend(ChecklistEntryMake("__item "Humorous" T-shirt", $location[the spooky forest].getClickableURLForLocation(), ChecklistSubentryMake("Torso Awareness", "", description), $locations[the spooky forest]).ChecklistEntrySetIDTag("Bad moon path torso awareness")); + } + + /* + FIXME + "Tower Ruins" unknown to locationAvailable + "The Orcish Frat House" unknown to locationAvailable + "Frat House (Frat Disguise)" unknown to locationAvailable + "The Hippy Camp" unknown to locationAvailable + "Hippy Camp (Hippy Disguise)" unknown to locationAvailable + */ +} + + +Record LBPItemInformation +{ + string image_url; + boolean should_display_drop_current; + string item_drop_current_information; + string item_name; + boolean should_display_drop_base; + string item_drop_base_information; + string [int] tags; + boolean greyed_out; +}; + +void listAppend(LBPItemInformation [int] list, LBPItemInformation entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +buffer createItemInformationTableMethod2(int columns, LBPItemInformation [int] items_presenting, boolean want_item_minimal_display, string table_class, string table_style) +{ + buffer output_buffer; + + string [string] table_map; + table_map = mapMake("style", "display:table;"); + if (table_style != "") + table_map["style"] += table_style; + if (table_class != "") + table_map["class"] = table_class; + output_buffer.append(HTMLGenerateTagPrefix("div", table_map)); + + + foreach key, info in items_presenting + { + if (key % columns == 0) + { + if (key != 0) + { + output_buffer.append(""); + } + output_buffer.append(HTMLGenerateTagPrefix("div", mapMake("style", "display:table-row;"))); + } + int image_size = 30; + if (want_item_minimal_display) + image_size = 15; + + //hack? + float percentage = 33; + if (columns == 2) + percentage = 50; + if (columns == 1) + percentage = 100; + + + int [int] image_sizes; + string [int] image_classes; + + image_classes.listAppend("r_only_display_if_not_tiny"); // r_only_display_if_not_small"); + image_sizes.listAppend(image_size); + + //image_classes.listAppend("r_only_display_if_small"); + //image_sizes.listAppend(MIN(image_size, 20)); + + string image_url = info.image_url; + if (image_url.length() == 0) + { + image_url = "images/itemimages/confused.gif"; + } + + foreach key in image_sizes + { + int using_size = image_sizes[key]; + string image_class = image_classes[key]; + output_buffer.append(HTMLGenerateTagPrefix("div", mapMake("style", "display:table-cell;max-width:" + using_size + ";max-height:" + using_size + ";min-width:" + using_size + ";min-height:" + using_size + ";padding-left:3px;padding-right:3px;vertical-align:middle;", "class", image_class))); + + //Generate image: + string [string] image_map = mapMake("src", image_url, "width", using_size, "height", using_size); + + image_map["style"] += "display:block;"; //removes implicit pixels around image + if (info.greyed_out) + image_map["style"] += "opacity:0.5;"; + image_map["alt"] = info.item_name; + output_buffer.append(HTMLGenerateTagPrefix("img", image_map)); + output_buffer.append(""); + } + + + string main_tag_style = "display:table-cell;width:" + percentage + "%;vertical-align:middle;"; + if (info.greyed_out) + main_tag_style += "color:gray;"; + if (want_item_minimal_display) + main_tag_style += "font-size:0.9em;"; + output_buffer.append(HTMLGenerateTagPrefix("div", mapMake("style", main_tag_style))); + if (want_item_minimal_display) + output_buffer.append(HTMLGenerateTagPrefix("span", mapMake("class", "r_location_bar_background_blur_small"))); + else + output_buffer.append(HTMLGenerateTagPrefix("span", mapMake("class", "r_location_bar_background_blur"))); + + if (info.should_display_drop_current) + { + output_buffer.append(info.item_drop_current_information); + output_buffer.append(" "); + } + output_buffer.append(info.item_name); + output_buffer.append(""); + + string [int] secondary_line; + if (info.should_display_drop_base) + secondary_line.listAppend(info.item_drop_base_information); + if (info.tags.count() > 0) + secondary_line.listAppendList(info.tags); + + if (secondary_line.count() > 0) + { + string [string] tag_map = mapMake("class", "r_cl_modifier_inline"); + if (info.greyed_out) + tag_map["style"] += "color:gray;"; + string wrap_type = "span"; //"div"; + if (want_item_minimal_display) + wrap_type = "span"; + else + tag_map["style"] += "display:block;"; + + output_buffer.append(HTMLGenerateTagPrefix(wrap_type, tag_map)); + if (!want_item_minimal_display) + output_buffer.append(HTMLGenerateTagPrefix("span", mapMake("class", "r_location_bar_background_blur"))); + if (want_item_minimal_display) + output_buffer.append(" ("); + output_buffer.append(secondary_line.listJoinComponents(", ")); + if (want_item_minimal_display) + output_buffer.append(")"); + if (!want_item_minimal_display) + output_buffer.append(""); + output_buffer.append(HTMLGenerateTagSuffix(wrap_type)); + } + + output_buffer.append(""); + } + output_buffer.append(""); //row + output_buffer.append(""); //table + return output_buffer; +} + + +buffer generateItemInformationMethod2(location l, monster m, boolean try_for_minimal_display, boolean [monster] monsters_to_display_items_minimally) +{ + int number_of_slimeling_eligible_items = 0; + foreach key, r in m.item_drops_array() + { + if ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3] contains r.drop.to_slot()) + number_of_slimeling_eligible_items += 1; + } + + + LBPItemInformation [int] items_presenting; + + foreach key, r in m.item_drops_array() + { + item it = r.drop; + int base_drop_rate = r.rate; + + + + int adjusted_base_drop_rate = base_drop_rate; + boolean drop_rate_is_actually_zero = false; + boolean drop_rate_is_guess = false; + + //r-type? + boolean item_is_conditional = r.type.contains_text("c"); + boolean item_is_stealable_accordion = r.type.contains_text("a"); + boolean item_is_pickpockable_only = r.type.contains_text("p"); + boolean item_cannot_be_pickpocketed = r.type.contains_text("n"); //FIXME use this for anything? + boolean item_rate_is_fixed = r.type.contains_text("f"); + boolean item_is_avatar_potion = r.drop.item_type() == "avatar potion"; //r.drop.to_effect().string_modifier("Avatar") != ""; + boolean grey_out_item = false; + if (item_is_stealable_accordion && my_class() != $class[accordion thief]) + { + grey_out_item = true; + adjusted_base_drop_rate = 0; + drop_rate_is_actually_zero = true; + } + if (item_is_pickpockable_only && !__misc_state["can pickpocket"]) + { + grey_out_item = true; + adjusted_base_drop_rate = 0; + drop_rate_is_actually_zero = true; + } + if (it == $item[reflection of a map] && get_property_int("pendingMapReflections") == 0) + { + grey_out_item = true; + adjusted_base_drop_rate = 0; + drop_rate_is_actually_zero = true; + } + if (($items[folder (red),folder (blue),folder (green),folder (magenta),folder (cyan),folder (yellow),folder (smiley face),folder (wizard),folder (space skeleton),folder (D-Team),folder (Ex-Files),folder (skull and crossbones),folder (Knight Writer),folder (Jackass Plumber),folder (holographic fractal),folder (barbarian),folder (rainbow unicorn),folder (Seawolf),folder (dancing dolphins),folder (catfish),folder (tranquil landscape),folder (owl),folder (Stinky Trash Kid),folder (sports car),folder (sportsballs),folder (heavy metal),folder (Yedi),folder (KOLHS)] contains it)) + { + if (base_drop_rate <= 0) + { + base_drop_rate = 5; //assumed + adjusted_base_drop_rate = base_drop_rate; //assumed + drop_rate_is_guess = true; + } + if ($item[over-the-shoulder folder holder].equipped_amount() == 0) + { + grey_out_item = true; + adjusted_base_drop_rate = 0; + drop_rate_is_actually_zero = true; + drop_rate_is_guess = false; + } + } + + string [int] item_drop_modifiers_to_display; + boolean yes_it_is_actually_zero = false; + if (adjusted_base_drop_rate > 0 && adjusted_base_drop_rate < 100) + { + + float effective_drop_rate = adjusted_base_drop_rate; + float item_modifier = l.item_drop_modifier_for_location(); + Error error; + // if (it.fullness > 0 || (__items_that_craft_food contains it)) // Switching to use mixable/cookable + if (it.fullness > 0 || it.cookable) + { + // need exception for chateau de vinegar; booze drop only impacts it + if (it != $item[bottle of chateau de vinegar]) { + item_modifier += numeric_modifier("Food Drop"); + item_drop_modifiers_to_display.listAppend("+food"); + } + } + if (it.inebriety > 0 || it.mixable || it == $item[bottle of chateau de vinegar]) + { + item_modifier += numeric_modifier("Booze Drop"); + item_drop_modifiers_to_display.listAppend("+booze"); + } + if (it.to_slot() == $slot[hat]) + { + item_modifier += numeric_modifier("Hat Drop"); + item_drop_modifiers_to_display.listAppend("+hat"); + } + if (it.to_slot() == $slot[weapon]) + { + item_modifier += numeric_modifier("Weapon Drop"); + item_drop_modifiers_to_display.listAppend("+weapon"); + } + if (it.to_slot() == $slot[off-hand]) + { + item_modifier += numeric_modifier("Offhand Drop"); + item_drop_modifiers_to_display.listAppend("+offhand"); + } + if (it.to_slot() == $slot[shirt]) + { + item_modifier += numeric_modifier("Shirt Drop"); + item_drop_modifiers_to_display.listAppend("+shirt"); + } + if (it.to_slot() == $slot[pants]) + { + item_modifier += numeric_modifier("Pants Drop"); + item_drop_modifiers_to_display.listAppend("+pants"); + } + if ($slots[acc1,acc2,acc3] contains it.to_slot()) + { + item_modifier += numeric_modifier("Accessory Drop"); + item_drop_modifiers_to_display.listAppend("+accessory"); + } + if (it.candy) + { + item_modifier += numeric_modifier("Candy Drop"); + item_drop_modifiers_to_display.listAppend("+candy"); + } + if ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3] contains it.to_slot()) //assuming familiar equipment isn't "gear" + { + item_modifier += numeric_modifier("Gear Drop"); + item_drop_modifiers_to_display.listAppend("+gear"); + } + if (it == $item[black picnic basket] && $skill[Bear Essence].have_skill()) + { + item_modifier += 20.0 * MAX(1, get_property_int("skillLevel134")); + } + if (l.environment == "underwater") //FIXME underwater drops are complicated and I'd have to look deeply into this to verify + { + //item_modifier -= l.pressurePenaltyForLocation(error); //pressure is actually already included in item_drop_modifier_for_location() + } + if (item_is_pickpockable_only) + { + if (__misc_state["can pickpocket"]) + item_modifier = numeric_modifier("pickpocket chance"); + else + item_modifier = 0.0; + } + if (item_rate_is_fixed) + item_modifier = 0.0; + if ($locations[sweet-ade lake,Eager Rice Burrows,Gumdrop Forest] contains l) + { + item_modifier = 0.0; + if (it.candy) + item_modifier += numeric_modifier("Candy Drop"); + } + //FIXME pickpocketting...? + //FIXME black cat + + if (my_path().id == PATH_LIVE_ASCEND_REPEAT && !item_rate_is_fixed && !item_is_pickpockable_only && !item_is_avatar_potion && effective_drop_rate > 0.0) + { + //It's either 0.0 or not. + float needed_rate = 1.0 / (2.0 * effective_drop_rate / 100.0); + //print_html("needed_rate = " + needed_rate + " effective_drop_rate = " + effective_drop_rate); + if (1.0 + item_modifier / 100.0 >= needed_rate) + effective_drop_rate = 100.0; + else + { + effective_drop_rate = 0.0; + } + yes_it_is_actually_zero = true; + } + else + effective_drop_rate *= 1.0 + item_modifier / 100.0; + if (my_path().id == PATH_HEAVY_RAINS) + { + effective_drop_rate = clampf(floor(effective_drop_rate), 0.0, 100.0); + float washaway_rate = l.washaway_rate_of_location(); + effective_drop_rate *= (1.0 - washaway_rate); + } + if (my_familiar() == $familiar[slimeling] && ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3] contains it.to_slot()) && effective_drop_rate < 100.0) + { + effective_drop_rate = clampf(floor(effective_drop_rate), 0.0, 100.0); + //number_of_slimeling_eligible_items + float slimeling_chance = 0.0; + if (number_of_slimeling_eligible_items > 0) + slimeling_chance = 1.0 / number_of_slimeling_eligible_items.to_float(); + + int effective_familiar_weight = my_familiar().familiar_weight() + numeric_modifier("familiar weight"); + int familiar_weight_from_familiar_equipment = $slot[familiar].equipped_item().numeric_modifier("familiar weight"); //need to cancel it out + + float slimeling_base_drop_rate = my_familiar().numeric_modifier("item drop", effective_familiar_weight - familiar_weight_from_familiar_equipment, $slot[familiar].equipped_item()); + if ($slot[familiar].equipped_item() == $item[undissolvable contact lenses]) + slimeling_base_drop_rate += 25.0; + + slimeling_chance *= adjusted_base_drop_rate.to_float() * (1.0 + slimeling_base_drop_rate / 100.0); + effective_drop_rate += (100.0 - effective_drop_rate) * (slimeling_chance / 100.0); + } + //not a quest item, ??? + //if (my_familiar() == $familiar[black cat]) + + effective_drop_rate = clampf(floor(effective_drop_rate), 0.0, 100.0); + adjusted_base_drop_rate = effective_drop_rate; + + if (error.was_error) + adjusted_base_drop_rate = -1; + } + + + + //FIXME implement this + LBPItemInformation info; + + info.image_url = "images/itemimages/" + it.smallimage; + if (it.smallimage.contains_text("/")) + info.image_url = "images/" + it.smallimage; + + if (!grey_out_item) + { + if (adjusted_base_drop_rate <= 0 && !yes_it_is_actually_zero) + { + info.should_display_drop_current = true; + info.item_drop_current_information = "?%"; + } + else if (adjusted_base_drop_rate < 100 || base_drop_rate < 100) + { + info.should_display_drop_current = true; + if (drop_rate_is_guess || l.environment == "underwater") + info.item_drop_current_information = adjusted_base_drop_rate + "?%"; + else + info.item_drop_current_information = adjusted_base_drop_rate + "%"; + } + } + info.item_name = it; + if (it.available_amount() == 0) + info.item_name = "" + info.item_name + ""; + + if (base_drop_rate != adjusted_base_drop_rate && base_drop_rate > 0 && base_drop_rate < 100 && !grey_out_item) + { + info.should_display_drop_base = true; + if (drop_rate_is_guess) + info.item_drop_base_information = base_drop_rate + "?%"; + else + info.item_drop_base_information = base_drop_rate + "%"; + } + if (item_drop_modifiers_to_display.count() > 0) + { + if (info.item_drop_base_information != "") + info.item_drop_base_information += ", "; + info.item_drop_base_information += item_drop_modifiers_to_display.listJoinComponents(", ") + " drop"; + } + if (item_is_conditional) + info.tags.listAppend("conditional"); + if (item_is_pickpockable_only) + info.tags.listAppend("pickpocket"); + if (item_rate_is_fixed) + info.tags.listAppend("unaffected by +item"); + if (item_is_avatar_potion) + info.tags.listAppend("avatar"); + info.greyed_out = grey_out_item; + + items_presenting.listAppend(info); + } + + + int columns = 3; + if (items_presenting.count() % 2 == 0 && items_presenting.count() % 3 != 0 && items_presenting.count() < 8) + columns = 2; + if (items_presenting.count() < columns) + columns = 1; + + boolean want_item_minimal_display = false; + if (try_for_minimal_display || monsters_to_display_items_minimally[m] || monsters_to_display_items_minimally.count() > 2) + want_item_minimal_display = true; + + boolean display_alternate_for_smaller_sizes = (columns == 3); + + buffer output_buffer; + output_buffer.append(HTMLGenerateTagPrefix("div", mapMake("style", "padding-left:" + (__setting_indention_width_in_em * 0.5) + "em;"))); + string table_class = ""; + if (display_alternate_for_smaller_sizes) + table_class = "r_only_display_if_not_tiny r_only_display_if_not_small"; + + output_buffer.append(createItemInformationTableMethod2(columns, items_presenting, want_item_minimal_display, table_class, "")); + + if (display_alternate_for_smaller_sizes) + { + int maximum_columns = 2; + if (items_presenting.count() >= 7 || monsters_to_display_items_minimally.count() >= 5) //hippy camp + maximum_columns = 3; + output_buffer.append(createItemInformationTableMethod2(MIN(columns, maximum_columns), items_presenting, want_item_minimal_display, "r_only_display_if_not_large r_only_display_if_not_medium", "")); //font-size:0.95em; + } + output_buffer.append(""); //container + + return output_buffer; +} + +string generateLocationBarModifierEntries(string [int] entries_in) +{ + if (entries_in.count() == 1) + return entries_in.listJoinComponents(", "); + + //Returns entries using a minimum-width algorithm designed to use two lines. + + string [int] entries = entries_in; + if (!entries.listKeysMeetStrictRequirements()) //insure we can test [key + 1] and such + entries = entries.listCopyStrictRequirements(); + + int [int] entries_length; + foreach key in entries + { + entries_length[key] = entries[key].HTMLStripTags().length(); + } + + int calculating_sum = 0; + + int smallest_length = 0; + int smallest_length_index = -1; + foreach key in entries + { + if (key == entries.count() - 1) + continue; + + calculating_sum += entries_length[key]; + //If we split at the end of this entry, what will be our length? + int line_1_length = calculating_sum; + int line_2_length = 0; + foreach key2 in entries + { + if (key2 <= key) + continue; + line_2_length += entries_length[key2]; + } + int line_length = MAX(line_1_length, line_2_length); + + if (smallest_length_index == -1) + { + smallest_length = line_length; + smallest_length_index = key; + } + else + { + if (smallest_length >= line_length) + { + smallest_length_index = key; + smallest_length = line_length; + } + } + } + //Split after smallest_length: + buffer result; + foreach key in entries + { + result.append(entries[key]); + boolean should_br = false; + if (key == smallest_length_index) + should_br = true; + if (key != entries.count() - 1) + { + if (should_br) + result.append(","); + else + result.append(", "); + } + if (should_br) + result.append("
"); + + } + return result; +} + + +buffer generateLocationBarTable(string [int] table_entries, string [int] table_entry_urls, string [int] table_entry_styles, string [int] table_entry_classes, float [int] table_entry_width_weight, float [int] table_entry_fixed_width_percentage, string base_url) +{ + buffer bar; + + + int [int] table_entry_widths; + if (__setting_location_bar_fixed_layout) + { + float reserved_percentage = 0.0; + foreach key, v in table_entry_fixed_width_percentage + reserved_percentage += v; + reserved_percentage = clampf(reserved_percentage, 0.0, 1.0); + + + int [int] table_entry_character_length; + foreach key in table_entries + { + if (table_entry_fixed_width_percentage contains key) + continue; + //Complicated: + string entry = table_entries[key]; + string [int] lines = entry.split_string("
"); + int max_length = 0; + foreach key2 in lines + { + //Remove HTML: + string l = HTMLStripTags(lines[key2]); + max_length = MAX(max_length, l.length()); + } + if (table_entry_width_weight contains key) + max_length = round(max_length.to_float() * table_entry_width_weight[key]); + table_entry_character_length[key] = max_length; + } + int total_character_count = listSum(table_entry_character_length); + int [int] proportional_character_lengths; + foreach key in table_entry_character_length + { + if (table_entry_fixed_width_percentage contains key) + continue; + int v = table_entry_character_length[key]; + if (total_character_count != 0 && __setting_location_bar_limit_max_width) + { + if (v.to_float() / total_character_count.to_float() >= __setting_location_bar_max_width_per_entry) + { + v = floor(total_character_count.to_float() * __setting_location_bar_max_width_per_entry); + } + } + proportional_character_lengths[key] = v; + } + + float remaining_percentage = 100.0 * (1.0 - reserved_percentage); + + int proportional_total = listSum(proportional_character_lengths); + foreach key in table_entry_fixed_width_percentage + { + table_entry_widths[key] = clampf(table_entry_fixed_width_percentage[key], 0.0, 1.0) * 100.0; + } + foreach key in proportional_character_lengths + { + if (table_entry_fixed_width_percentage contains key) + continue; + int v = proportional_character_lengths[key]; + int width = 25; + if (proportional_character_lengths.count() > 0) + width = floor(remaining_percentage / proportional_character_lengths.count().to_float()); //backup + if (proportional_total != 0) + { + width = v.to_float() / proportional_total.to_float() * remaining_percentage; + } + table_entry_widths[key] = width; + } + } + + if (table_entry_widths.listSum() > 100) + { + //Safety backup. Renormalize: + int current_sum = table_entry_widths.listSum(); + foreach key in table_entry_widths + { + if (current_sum != 0) //not strictly necessary, will always be true (as the code currently is) + table_entry_widths[key] = floor(table_entry_widths[key].to_float() / current_sum.to_float() * 100.0); + } + } + + + if (true) + { + buffer table_style; + table_style.append("display:table;width:100%;height:100%;text-align:center;"); + if (__setting_location_bar_fixed_layout) + table_style.append("table-layout:fixed;"); + bar.append(HTMLGenerateTagPrefix("div", mapMake("style", table_style))); // + } + + foreach key in table_entries + { + string s = table_entries[key]; + string entry_url = base_url; + if (table_entry_urls contains key) + entry_url = table_entry_urls[key]; + + string [string] map; + + if (entry_url != "") + map = generateMainLinkMap(entry_url); + map["class"] += " r_location_bar_table_entry"; + if (table_entry_classes contains key) + map["class"] += " " + table_entry_classes[key]; + if (table_entry_styles contains key) + map["style"] += table_entry_styles[key]; + + if (table_entry_widths contains key) + map["style"] += "width:" + table_entry_widths[key] + "%;"; + + if (entry_url.length() != 0) + bar.append(HTMLGenerateTagPrefix("a", map)); + else + bar.append(HTMLGenerateTagPrefix("div", map)); + + if (table_entry_classes contains key) + bar.append(s); + else + bar.append(HTMLGenerateTagWrap("div", s, mapMake("class", "r_cl_modifier_inline", "style", "color:black;"))); //r_cl_modifier_inline needs its own div due to CSS class order precedence + if (entry_url.length() != 0) + { + bar.append(""); + } + else + bar.append(""); + } + + + bar.append(HTMLGenerateTagSuffix("div")); + + + + return bar; +} + + +static +{ + boolean __manuel_available = false; + boolean __did_check_manuel_available = false; +} + +buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_location_name_is_centre_aligned) +{ + buffer buf; + if (!__setting_enable_location_popup_box) + return buf; + location l = __last_adventure_location; + if (!__setting_location_bar_uses_last_location && !get_property_boolean("_relay_guide_setting_ignore_next_adventure_for_location_bar") && get_property_location("nextAdventure") != $location[none]) + l = get_property_location("nextAdventure"); + + string transition_time = "0.5s"; + buf.append(HTMLGenerateTagWrap("div", "", mapMake("id", "r_location_popup_blackout", "style", "position:fixed;z-index:6;width:100%;height:100%;background:rgba(0,0,0,0.5);opacity:0;pointer-events:none;visibility:hidden;"))); + + + buf.append(HTMLGenerateTagPrefix("div", mapMake("id", "r_location_popup_box", "style", "height:auto;transition:bottom " + transition_time + ";z-index:6;opacity:0;pointer-events:none;bottom:-10000px", "class", "r_bottom_outer_container"))); + buf.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_bottom_inner_container", "style", "background:white;height:auto;"))); + + float [monster] appearance_rates_adjusted = l.appearance_rates_adjusted(false).appearance_rates_cancel_nc(); + float [monster] appearance_rates_next_turn = l.appearance_rates_adjusted(true).appearance_rates_cancel_nc(); + + string [monster] monsters_that_we_cannot_encounter; + if ($effect[Ancient Annoying Serpent Poison].have_effect() == 0) + { + foreach m in $monsters[The Frattlesnake,Batsnake,Frozen Solid Snake,Burning Snake of Fire,The Snake With Like Ten Heads,Snakeleton] + { + monsters_that_we_cannot_encounter[m] = "not on copperhead quest"; + } + } + if (l == $location[the boss bat's lair]) + { + if (l.delayRemainingInLocation() > 0) + { + monsters_that_we_cannot_encounter[$monster[Boss Bat]] = "on delay"; + } + } + else if (l == $location[the defiled niche]) + { + int evilness = __quest_state["Level 7"].state_int["niche evilness"]; + if (evilness > 13) + { + monsters_that_we_cannot_encounter[$monster[gargantulihc]] = "evilness too high"; + } + else if (evilness > 0) + { + monsters_that_we_cannot_encounter[$monster[senile lihc]] = "boss up"; + monsters_that_we_cannot_encounter[$monster[slick lihc]] = "boss up"; + monsters_that_we_cannot_encounter[$monster[dirty old lihc]] = "boss up"; + } + } + else if (l == $location[the defiled cranny]) + { + int evilness = __quest_state["Level 7"].state_int["cranny evilness"]; + if (evilness > 13) + { + monsters_that_we_cannot_encounter[$monster[huge ghuol]] = "evilness too high"; + } + else if (evilness > 0) + { + foreach m in $monsters[gluttonous ghuol,gaunt ghuol,swarm of ghuol whelps,big swarm of ghuol whelps,giant swarm of ghuol whelps] + monsters_that_we_cannot_encounter[m] = "boss up"; + } + } + else if (l == $location[the defiled nook]) + { + int evilness = __quest_state["Level 7"].state_int["nook evilness"]; + if (evilness > 13) + { + monsters_that_we_cannot_encounter[$monster[giant skeelton]] = "evilness too high"; + } + else if (evilness > 0) + { + foreach m in $monsters[spiny skelelton,toothy sklelton,party skelteon] + monsters_that_we_cannot_encounter[m] = "boss up"; + } + } + else if (l == $location[the defiled alcove]) + { + int evilness = __quest_state["Level 7"].state_int["alcove evilness"]; + if (evilness > 13) + { + monsters_that_we_cannot_encounter[$monster[conjoined zmombie]] = "evilness too high"; + } + else if (evilness > 0) + { + foreach m in $monsters[grave rober zmobie,corpulent zobmie,modern zmobie] + monsters_that_we_cannot_encounter[m] = "boss up"; + } + } + else if (l == $location[oil peak]) + { + int oil_ml = $location[oil peak].monster_level_adjustment_for_location(); + monster correct_monster = $monster[oil slick]; + if (oil_ml < 20) + correct_monster = $monster[oil slick]; + else if (oil_ml < 50) + correct_monster = $monster[oil tycoon]; + else if (oil_ml < 100) + correct_monster = $monster[oil baron]; + else if (oil_ml >= 100) + correct_monster = $monster[oil cartel]; + foreach m in $monsters[oil slick,oil tycoon,oil baron,oil cartel] + { + if (m != correct_monster) + monsters_that_we_cannot_encounter[m] = "ML based"; + } + } + + boolean banishes_are_possible = true; + if ($locations[the secret government laboratory,sloppy seconds diner] contains l) + banishes_are_possible = false; + if (my_path().id == PATH_LIVE_ASCEND_REPEAT) + banishes_are_possible = false; + + foreach m in appearance_rates_next_turn + { + if (monsters_that_we_cannot_encounter contains m) + remove appearance_rates_next_turn[m]; + } + + monster [int] monster_display_order; + boolean rates_are_equal = true; + boolean next_rates_are_equal = true; + float last_rate = -1.0; + float last_next_rate = -1.0; + foreach m in appearance_rates_adjusted + { + if (m == $monster[none]) + continue; + float rate = appearance_rates_adjusted[m]; + float next_rate = appearance_rates_next_turn[m]; + if (rate <= 0.0 && l == $location[Investigating a Plaintive Telegram]) + continue; + monster_display_order.listAppend(m); + if (rate > 0.0) + { + if (last_rate == -1.0) + last_rate = rate; + else if (fabs(last_rate - rate) > 0.01) + { + rates_are_equal = false; + } + } + + if (next_rate > 0.0) + { + if (last_next_rate == -1.0) + last_next_rate = next_rate; + else if (fabs(last_next_rate - next_rate) > 0.01) + { + next_rates_are_equal = false; + } + } + } + + boolean [monster] possible_alien_monsters; + if (!(appearance_rates_adjusted contains last_monster())) //wandering monsters, etc + { + possible_alien_monsters[last_monster()] = true; + monster_display_order.listAppend(last_monster()); + } + + int minimal_cutoff_monster_count = 10; + boolean try_for_minimal_display = false; + if (monster_display_order.count() > minimal_cutoff_monster_count) + try_for_minimal_display = true; + + if (next_rates_are_equal) + { + //equality + sort monster_display_order by -appearance_rates_next_turn[value]; + sort monster_display_order by -appearance_rates_adjusted[value] - (possible_alien_monsters[value] ? -100.0 : 0); + } + else + { + sort monster_display_order by -appearance_rates_adjusted[value] - (possible_alien_monsters[value] ? -100.0 : 0); + sort monster_display_order by -appearance_rates_next_turn[value] - (possible_alien_monsters[value] ? -100.0 : 0); + } + int entries_displayed = 0; + int monsters_displayed = 0; + + boolean can_display_as_2x = true; + boolean spelunking = limit_mode() == "spelunky"; + + /*if (false) //trying with it off - it feels better to use layout more effectively, rather than try to line up everything. example area: domed city of grimacia + { + foreach key, m in monster_display_order + { + int item_count_displaying = m.item_drops_array().count(); + if (item_count_displaying <= 1) + { + } + else if (item_count_displaying == 2 || (item_count_displaying % 2 == 0 && item_count_displaying % 3 != 0)) + { + } + else + can_display_as_2x = false; + } + }*/ + + boolean [monster] monsters_to_display_items_minimally; + int item_minimal_display_limit = 6; + foreach key, m in monster_display_order + { + //pooltergeist has lots of items, but they're very short named + int total_string_length = 0; + foreach key, r in m.item_drops_array() + { + total_string_length += r.drop.to_string().length(); + } + if (m.item_drops_array().count() > item_minimal_display_limit && total_string_length >= 100) + monsters_to_display_items_minimally[m] = true; + } + foreach key, m in monster_display_order + { + string [int] fl_entries; + string [int] fl_entry_urls; + string [int] fl_entry_styles; + string [int] fl_entry_classes; + float [int] fl_entry_width_weight; + float [int] fl_entry_fixed_width_percentage; + + string monster_image_url = "images/adventureimages/" + m.image; + if (m.image.contains_text("/")) + monster_image_url = "images/" + m.image; + if (m.image == "toxbeast1.gif") + monster_image_url = "images/adventureimages/toxbeast3.gif"; + if (m.image.length() == 0) + monster_image_url = ""; + ServerImageStats monster_image_stats = ServerImageStatsOfImageURL(monster_image_url); + float rate = appearance_rates_adjusted[m]; + float next_rate = appearance_rates_next_turn[m]; + if (entries_displayed > 0) + buf.append(HTMLGenerateTagPrefix("hr", mapMake("style", "margin:0px;"))); + entries_displayed += 1; + monsters_displayed += 1; + + boolean avoid_outputting_conditional = false; + boolean monster_cannot_be_encountered = false; + string reason_monster_cannot_be_encountered = ""; + if (rate == -3.0 && banishes_are_possible) //-3.0 => is (properly) banished + { + monster_cannot_be_encountered = true; + reason_monster_cannot_be_encountered = "banished"; + } + else if (monsters_that_we_cannot_encounter contains m) + { + monster_cannot_be_encountered = true; + reason_monster_cannot_be_encountered = monsters_that_we_cannot_encounter[m]; + } + else if (appearance_rates_adjusted[$monster[none]] >= 100.0 && !(possible_alien_monsters contains m)) + { + monster_cannot_be_encountered = true; + reason_monster_cannot_be_encountered = "no combats"; + avoid_outputting_conditional = true; + } + if (true) + { + //string style = "width:100%;display:table;padding:0.25em;z-index:8;position:relative;overflow:hidden;"; + string style = "width:100%;padding-bottom:0.1em;z-index:8;position:relative;overflow:hidden;"; + if (try_for_minimal_display) + style += "padding-top:0.1em;"; + if (monster_cannot_be_encountered) + style += "color:grey;"; + if (monster_image_stats.height > 100 && false) //those tall monsters like to impress + style += "min-height:100px;"; + buf.append(HTMLGenerateTagPrefix("div", mapMake("style", style))); + } + if (!monster_image_url.contains_text("nopic.gif") && monster_image_url != "") + { + //FIXME centre image if it's small? maybe a table? more tables! + boolean from_bottom_instead = false; + //if ($strings[images/adventureimages/lower_b.gif,images/adventureimages/lower_k.gif,images/adventureimages/lower_h.gif,images/adventureimages/upper_q.gif,images/adventureimages/aswarm.gif,images/adventureimages/lowerm.gif,images/adventureimages/dad_machine.gif] contains monster_image_url && monster_image_stats.maximum_y_coordinate != -1 && monster_image_stats.height != -1) //dungeons of doom, dad sea monkee + //from_bottom_instead = true; + + + float max_height = 100; + //monster_image_stats.height + //make max_height adjust: + float effective_height = monster_image_stats.maximum_y_coordinate - monster_image_stats.minimum_y_coordinate + 1; + float height_fraction = 1.0; + if (monster_image_stats.height > 0) + height_fraction = effective_height / monster_image_stats.height.to_float(); + + if (height_fraction > 0) + max_height = 100.0 / height_fraction; + + string image_style = "position:absolute;right:0px;top:0px;max-height:" + max_height.ceil() + "px;z-index:-3;"; + if (monster_cannot_be_encountered) + image_style += "opacity:0.1;"; + else if (last_monster() == m) + image_style += "opacity:0.5;"; //1.0 + else if (m.attributes.contains_text("ULTRARARE")) + image_style += "opacity:0.1;"; + else + image_style += "opacity:0.2;"; //0.5 + if (from_bottom_instead && false) //disabled, no longer works + { + float location_of_first_bottom_pixel = monster_image_stats.maximum_y_coordinate; + float margin_bottom = monster_image_stats.height - location_of_first_bottom_pixel; + if (monster_image_stats.height != 100) + { + //correct margin, as we scale images down to 100 + float ratio = monster_image_stats.height.to_float() / 100.0; + if (ratio != 0.0) + margin_bottom /= ratio; + } + image_style += "bottom:0px;"; + image_style += "margin-bottom:-" + ceil(margin_bottom) + "px;"; + + } + else + { + float location_of_first_top_pixel = MAX(0, monster_image_stats.minimum_y_coordinate); + if (monster_image_stats.height != 100 && false) //FIXME ??? + { + //correct margin, as we scale images down to 100 + float ratio = monster_image_stats.height.to_float() / 100.0; + if (ratio != 0.0) + location_of_first_top_pixel /= ratio; + } + if (location_of_first_top_pixel > 0) + image_style += "margin-top:-" + location_of_first_top_pixel + "px;"; + } + buf.append(HTMLGenerateTagPrefix("img", mapMake("src", monster_image_url, "style", image_style, "alt", m))); + } + + if (true) + { + string style; + float width_weight = 1.4; + if (monster_cannot_be_encountered) + { + style += "text-decoration:line-through;"; + //width_weight = 1.0; + } + else + style = "font-size:1.2em;"; + style += "text-align:left;padding-top:2px;"; + + fl_entries.listAppend(m.capitaliseFirstLetter()); + fl_entry_classes[fl_entries.count() - 1] = "r_bold r_location_bar_ellipsis_entry"; + fl_entry_styles[fl_entries.count() - 1] = style; + fl_entry_width_weight[fl_entries.count() - 1] = width_weight; + } + + // ----------- NEW BIT FROM SCOTCH ABOUT BOFA ------------- + if (true) + { + if ($skill[just the facts].have_skill()) { + string bofaText; + string bofaEffect = m.fact_type(); + string factAppend; + + // TODO: Bunch of stuff, this is a first implementation. Goals: + // - Try to figure out a nicer way to format this. + // - Filter out the "junk" BOFA results. + if (bofaEffect == "item") factAppend = HTMLGenerateSpanFont(m.item_fact().name,"red"); + if (bofaEffect == "effect") factAppend = HTMLGenerateSpanFont(`{m.effect_fact().name} ({m.numeric_fact()})`,"blue"); + bofaText = `{factAppend}`; + + // I tried to put this a few places. First I tried in the stats + // sidebar, then I tried under the name, then I tried as an + // appended item. I ended up preferring having it generate in + // visibly in large zones with cutoff entries. I am pretty sure + // the "best" solution is a more elegant way to add it to the + // item list, but this initial implementation is good enough for + // now, I think. + + fl_entries.listAppend(bofaText); + fl_entry_styles[fl_entries.count() - 1] = "text-align:left;font-size:0.8em"; + } + } + + //FIXME handle canceling NC + buffer rate_buffer; + if (m.attributes.contains_text("ULTRARARE")) + rate_buffer.append("ultra rare "); + else if (m.boss) + rate_buffer.append("boss "); + else if (rate > 0 && !monster_cannot_be_encountered) + { + if (!rates_are_equal) + { + rate_buffer.append(rate.roundForOutput(0)); + rate_buffer.append("%"); + } + if (next_rate != rate && next_rate > 0 && !next_rates_are_equal) + { + if (rates_are_equal) + rate_buffer.append("equal %"); + rate_buffer.append("
next "); + + rate_buffer.append(next_rate.roundForOutput(0)); + rate_buffer.append("%"); + } + } + else if (rate <= 0 && !(m.is_banished() && banishes_are_possible)) + { + if (possible_alien_monsters contains m) + rate_buffer.append("elsewhere"); + else if (!avoid_outputting_conditional) + rate_buffer.append("conditional"); + } + //seen values for rate: + //0.0 for bosses + //-1.0 for ultra-rares + //-3.0 for (properly) banished + if (m.is_banished() && banishes_are_possible) + { + Banish banish_information = m.BanishForMonster(); + if (rate == -3.0) + { + rate_buffer.append("banished"); + if (banish_information.banish_source != "") + { + rate_buffer.append(" by "); + rate_buffer.append(banish_information.banish_source); + } + if (banish_information.custom_reset_conditions != "") + { + rate_buffer.append(" until "); + rate_buffer.append(banish_information.custom_reset_conditions); + } + else if (banish_information.banish_turn_length == -1) + rate_buffer.append(" forever"); + else if (banish_information.banish_turn_length > 0) + { + int turns_left = banish_information.BanishTurnsLeft(); + rate_buffer.append(" for "); + rate_buffer.append(pluralise(turns_left, "more turn", "more turns")); + } + } + else if (rate > 0.0) + { + //monster was banished, but they are olfacting it (only base copies of the monsters are removed by banishes) + if (!rates_are_equal || !next_rates_are_equal) + rate_buffer.append("
"); + rate_buffer.append("banished"); + if (banish_information.banish_source != "") + { + rate_buffer.append(" by "); + rate_buffer.append(banish_information.banish_source); + } + //want to avoid cluttering, so don't show until when + rate_buffer.append("
"); + rate_buffer.append("brought back by copies".HTMLGenerateSpanOfClass("r_element_important")); + + } + rate_buffer.append(" "); + } + + if (rate_buffer.length() > 0) + { + fl_entries.listAppend(rate_buffer); + } + if (monster_cannot_be_encountered && reason_monster_cannot_be_encountered != "banished") + { + fl_entries.listAppend(reason_monster_cannot_be_encountered); + } + + + + + + + int item_count_displaying = m.item_drops_array().count(); + if (item_count_displaying > 0 && try_for_minimal_display && !monster_cannot_be_encountered) + { + fl_entries.listAppend(pluralise(item_count_displaying, "item", "items")); + } + + + if (!monster_cannot_be_encountered) + { + string [int] stats_l1; + string [int] stats_l2; + //if (m.base_hp > 0) + //stats_l1.listAppend(m.base_hp + " HP"); + if (m.phylum != $phylum[none] && !spelunking) + { + string line; + if ($monsters[broodling seal] contains m) + line = "cute
"; + line += m.phylum; + if (true && m.attack_element != $element[none]) + line = HTMLGenerateSpanOfClass(line, "r_element_" + m.attack_element + "_desaturated"); + stats_l1.listAppend(line); + } + /*if (m.attack_element != $element[none] && false) + { + stats_l2.listAppend(HTMLGenerateSpanOfClass(m.attack_element, "r_element_" + m.attack_element + "_desaturated")); + }*/ + if (m.max_meat > 0) + { + float average_meat = (m.min_meat + m.max_meat) * 0.5; + Error error; + // float pressure_penalty = l.environment == "underwater" ? -l.pressurePenaltyForLocation(error) : 0.0; //already accounted for in meat_drop_modifier() + average_meat *= 1.0 + meat_drop_modifier() / 100.0; + if (average_meat >= 25) //ignore really low amounts + { + if (error.was_error) + stats_l1.listAppend("? meat"); + else + stats_l1.listAppend(average_meat.round() + " meat"); + } + } + if (m.base_attack > 0) + stats_l2.listAppend(m.base_attack + " ML"); + if (spelunking) + stats_l2.listAppend(m.base_hp + " HP"); + if ($skill[Extract Oil].have_skill()) + { + string oil_type = lookupAWOLOilForMonster(m); + if (oil_type != "") + stats_l2.listAppend(oil_type); + } + //if (m.raw_defense > 0) + //stats_l2.listAppend(m.raw_defense + " def"); + if (false) + { + //disabled - monster_factoids_available constantly reissues server requets if we don't have a factoid on a monster + if (!__did_check_manuel_available) + { + //so, if the manuel isn't available, we incur a quest log load every time. so don't do that. + __manuel_available = $monster[spooky vampire].monster_factoids_available(false) > 0; + __did_check_manuel_available = true; + } + if (__manuel_available) + { + int factoids_left = 3 - monster_factoids_available(m, false); + if (m.attributes.contains_text("ULTRARARE") || m.attributes.contains_text("NOMANUEL")) //ULTRARARE test may be superfluous + factoids_left = 0; + if (factoids_left > 0) + stats_l2.listAppend(factoids_left + " more fact" + (factoids_left > 1 ? "s" : "")); + } + } + + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + { + int ka_dropped = m.ka_dropped(); + if (ka_dropped > 0) + stats_l1.listAppend(ka_dropped + " ka"); + } + + if (m.expected_damage() > 1 && (m.expected_damage() >= my_hp().to_float() * 0.5 || ($monsters[spider gremlin,batwinged gremlin,erudite gremlin,vegetable gremlin] contains m)) || spelunking) + { + string damage_text = m.expected_damage() + " dmg"; + if (m.expected_damage() >= 0.75 * my_hp()) + damage_text = HTMLGenerateSpanOfClass(damage_text, "r_element_hot_desaturated"); //"#FC686F", ""); + stats_l2.listAppend(damage_text); + } + + if (stats_l2.count() == 0 && stats_l1.count() == 2) //rebalance hack + { + stats_l2.listPrepend(stats_l1[1]); + remove stats_l1[1]; + } + if (stats_l2.count() == 1 && stats_l1.count() == 3) //rebalance hack + { + stats_l2.listPrepend(stats_l1[2]); + remove stats_l1[2]; + } + + if (stats_l1.count() + stats_l2.count() > 0) + { + string line = stats_l1.listJoinComponents(" / "); + if (stats_l2.count() > 0) + { + if (stats_l1.count() > 0) + line += "
"; + line += stats_l2.listJoinComponents(" / "); + } + fl_entries.listAppend(line); + fl_entry_styles[fl_entries.count() - 1] = "text-align:right;"; + fl_entry_width_weight[fl_entries.count() - 1] = 1.4; + } + } + + //add background blur: + if (true) + { + foreach key, entry in fl_entries + { + entry = HTMLGenerateSpanOfClass(entry, "r_location_bar_background_blur"); + fl_entries[key] = entry; + } + } + if (!(m.is_banished() && banishes_are_possible)) + { + if (fl_entries.count() == 2) + fl_entry_fixed_width_percentage[0] = 0.60; + else if (fl_entries.count() == 3) + { + fl_entry_fixed_width_percentage[0] = 0.50; + fl_entry_fixed_width_percentage[1] = 0.2; + fl_entry_fixed_width_percentage[2] = 0.3; + } + else if (fl_entries.count() == 4) + { + fl_entry_fixed_width_percentage[0] = 0.40; + fl_entry_fixed_width_percentage[1] = 0.2; + fl_entry_fixed_width_percentage[2] = 0.15; + fl_entry_fixed_width_percentage[3] = 0.25; + } + } + //remove fl_entry_fixed_width_percentage[0]; + + buf.append(generateLocationBarTable(fl_entries, fl_entry_urls, fl_entry_styles, fl_entry_classes, fl_entry_width_weight, fl_entry_fixed_width_percentage, "")); + + + if (item_count_displaying > 0 && !try_for_minimal_display && !monster_cannot_be_encountered && true) + { + buf.append(generateItemInformationMethod2(l, m, try_for_minimal_display,monsters_to_display_items_minimally)); + } + + //buf.append(HTMLGenerateTagSuffix("div")); + buf.append(HTMLGenerateTagSuffix("div")); + //break; + } + + if (in_bad_moon()) + { + BadMoonAdventure [int] bad_moon_adventures = BadMoonAdventuresForLocation(l); + + if (bad_moon_adventures.count() > 0) + { + foreach key, adventure in bad_moon_adventures + { + if (haveSeenBadMoonEncounter(adventure.encounter_id)) + continue; + + string [int] fl_entries; + string [int] fl_entry_urls; + string [int] fl_entry_styles; + string [int] fl_entry_classes; + float [int] fl_entry_width_weight; + float [int] fl_entry_fixed_width_percentage; + + + string image_style = "margin-top:1px;"; + if (adventure.has_additional_requirements_not_yet_met) + image_style += "opacity:0.25;"; + fl_entries.listAppend(HTMLGenerateTagPrefix("img", mapMake("src", __bad_moon_small_image_data, "style", image_style))); + fl_entry_styles[fl_entries.count() - 1] = "text-align:right;"; + fl_entry_fixed_width_percentage[fl_entries.count() - 1] = 0.1; + fl_entries.listAppend(adventure.description); + fl_entry_styles[fl_entries.count() - 1] = "text-align:left;"; + if (adventure.has_additional_requirements_not_yet_met) + fl_entries.listAppend("Need to " + adventure.conditions_to_finish); + + + buf.append(HTMLGenerateTagPrefix("hr", mapMake("style", "margin:0px;"))); + buf.append(generateLocationBarTable(fl_entries, fl_entry_urls, fl_entry_styles, fl_entry_classes, fl_entry_width_weight, fl_entry_fixed_width_percentage, "")); + } + } + } + + + if (false) + { + string [int] lines; + string [int] lines_offscreen; + if (false && l.parentdesc != "" && l.parentdesc != "No Category" && l.parentdesc.to_lower_case() != l.to_lower_case()) + lines.listAppend(l.parentdesc); + if (!__misc_state["in run"] && l.turns_spent > 0) + { + lines.listAppend(pluralise(l.turns_spent, "turn spent", "turns spent")); //lines_offscreen + } + if (lines.count() + lines_offscreen.count() > 0) + { + if (entries_displayed >= 1) + buf.append(HTMLGenerateTagPrefix("hr", mapMake("style", "margin:0px;"))); + string div_class = "r_cl_modifier_inline"; + string div_style = "height:1.1em;padding-top:1px;padding-bottom:1px;"; + if (location_bar_location_name_is_centre_aligned) + div_class += " r_centre"; + else + div_style += "padding-left:" + __setting_indention_width + ";"; + buf.append(HTMLGenerateTagPrefix("div", mapMake("class", div_class, "style", div_style))); + buf.append(lines.listJoinComponents(" - ")); + buf.append(""); + if (lines_offscreen.count() > 0) + { + buf.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_cl_modifier_inline", "style", "position:absolute;right:0px;top:0px;"))); + buf.append(lines_offscreen.listJoinComponents(" - ")); + buf.append(""); + } + entries_displayed += 1; + } + } + if (false) + { + string [int] fl_entries; + string [int] fl_entry_urls; + string [int] fl_entry_styles; + string [int] fl_entry_classes; + float [int] fl_entry_width_weight; + float [int] fl_entry_fixed_width_percentage; + + if (false && l.parentdesc != "" && l.parentdesc != "No Category" && l.parentdesc.to_lower_case() != l.to_lower_case()) + fl_entries.listAppend(l.parentdesc); + + /*Error err; + if (!l.locationAvailable(err)) + { + if (!err.was_error) + fl_entries.listAppend("Inaccessible"); //doesn't make any sense unless we add that one feature + }*/ + + if (!__misc_state["in run"] && l.turns_spent > 0) + fl_entries.listAppend(pluralise(l.turns_spent, "turn spent", "turns spent")); + + boolean all_entries_blank = true; + foreach key, entry in fl_entries + { + if (entry != "") + all_entries_blank = false; + } + if (fl_entries.count() > 0 && !all_entries_blank) + { + if (entries_displayed >= 1) + buf.append(HTMLGenerateTagPrefix("hr", mapMake("style", "margin:0px;"))); + /*if (fl_entries.count() == 2) + { + fl_entry_styles[1] += "text-align:right;"; + }*/ + foreach key in fl_entries + fl_entry_styles[key] += "height:1.25em;"; + + fl_entry_styles[0] += "text-align:left;"; + fl_entry_styles[0] += "padding-left:" + __setting_indention_width + ";"; + if (fl_entries.count() > 1) + { + fl_entry_styles[fl_entries.count() - 1] += "text-align:right;"; + fl_entry_styles[fl_entries.count() - 1] += "padding-right:" + __setting_indention_width + ";"; + } + buf.append(generateLocationBarTable(fl_entries, fl_entry_urls, fl_entry_styles, fl_entry_classes, fl_entry_width_weight, fl_entry_fixed_width_percentage, "")); + entries_displayed += 1; + + //output_hr_override = true; + } + + } + + //boolean output_hr_override = false; + + if (entries_displayed == 0) + return "".to_buffer(); + buf.append(HTMLGenerateTagSuffix("div")); + //if (output_hr_override) + //buf.append("
"); + buf.append(HTMLGenerateTagSuffix("div")); + + return buf; +} + + +buffer generateLocationBar(boolean displaying_navbar) +{ + buffer bar; + if (!playerIsLoggedIn()) + return bar; + location l = __last_adventure_location; + if (!__setting_location_bar_uses_last_location && !get_property_boolean("_relay_guide_setting_ignore_next_adventure_for_location_bar") && get_property_location("nextAdventure") != $location[none]) //setting exists for ascension scripts that alter my_location() to a null value/noob cave whenever they're not adventuring somewhere specific, to avoid environment-based effects on modifiers. + l = get_property_location("nextAdventure"); + + if (l == $location[none] || __misc_state["In valhalla"]) + return "".to_buffer(); + + string url = l.getClickableURLForLocation(); + + float [monster] monster_appearance_rates = l.appearance_rates_adjusted(); + + int nc_rate = MAX(0.0, monster_appearance_rates[$monster[none]]); + + float location_base_ml = l.monster_level_adjustment_for_location(); + float location_base_init_penalty = monsterExtraInitForML(location_base_ml); + if (l.locationHasPlant("Impatiens") || l.locationHasPlant("Shuffle Truffle")) + location_base_init_penalty -= 25.0; + + + float average_ml = 0.0; + float max_init = 0.0; + float sample_count = 0.0; + + boolean [location] locations_where_monsters_always_matter = $locations[the haunted bedroom]; + + foreach m in monster_appearance_rates + { + if (monster_appearance_rates[m] <= 0.0 && !(locations_where_monsters_always_matter contains l)) //one-time hack, sure? + continue; + if (m == $monster[none]) + continue; + average_ml += m.raw_attack + location_base_ml; + + if (m.raw_attack == m.base_attack && location_base_ml > 0) //scaling monsters will have equivalent base_attack and raw_attack with ML already applied. + average_ml -= location_base_ml; //this will be slightly incorrect with plants, due to how location ML works, but fixing it is very complicated + + max_init = MAX(max_init, m.raw_initiative + location_base_init_penalty); + sample_count += 1.0; + } + if (sample_count > 0.0) + { + average_ml /= sample_count; + } + + float chance_of_jump = 0.0; + chance_of_jump = clampNormalf(((100.0 - max_init) + initiative_modifier_ignoring_plants()) / 100.0); + + string [int] plant_data; + + if (__iotms_usable[$item[Order of the Green Thumb Order Form]]) + { + string [location, 3] florist_plants = get_florist_plants(); + + if (florist_plants contains l) + { + string [3] area_plants = get_florist_plants()[l]; + + foreach key in area_plants + { + string plant_name = area_plants[key]; + if (plant_name.length() == 0) + continue; + string plant_description = plant_name.getPlantDescription(); + + string class_name = ""; + //Half-saturation of their original colour, to fit in with the modifier look: + if (plant_description == "spooky attack") + class_name = "r_element_spooky_desaturated"; + else if (plant_description == "hot attack") + class_name = "r_element_hot_desaturated"; + else if (plant_description == "sleaze attack") + class_name = "r_element_sleaze_desaturated"; + else if (plant_description == "stench attack") + class_name = "r_element_stench_desaturated"; + else if (plant_description == "cold attack") + class_name = "r_element_cold_desaturated"; + + if (class_name != "") + plant_description = HTMLGenerateSpanOfClass(plant_description, class_name); + + if (plant_description != "") + plant_data.listAppend(plant_description); + else + plant_data.listAppend("Unknown"); + } + } + string environment_display = l.environment.capitaliseFirstLetter(); + if (l.environment == "unknown" || l.environment == "none" || l.environment == "") + environment_display = "Unknown"; + if (plant_data.count() == 0)// && l.environment != "unknown" && l.environment != "none" && l.environment != "") + { + if (l == $location[The Valley of Rof L'm Fao]) + plant_data.listAppend(l.environment.replace_string("o", "0")); + else if (!($locations[The Prince's Restroom,The Prince's Dance Floor,The Prince's Kitchen,The Prince's Balcony,The Prince's Lounge,The Prince's Canapes table,the shore\, inc. travel agency] contains l)) + plant_data.listAppend(environment_display); + } + } + + + /*int [location] pressure_penalties; + pressure_penalties[$location[The Briny Deeps]] = 25; + pressure_penalties[$location[The Brinier Deepers]] = 50; + pressure_penalties[$location[The Briniest Deepests]] = 75; + foreach loc in $locations[An Octopus's Garden,The Wreck of the Edgar Fitzsimmons,Madness Reef,The Mer-Kin Outpost,The Skate Park,The Coral Corral] + pressure_penalties[loc] = 100; + foreach loc in $locations[Mer-kin Colosseum,Mer-kin Library,Mer-kin Gymnasium,Mer-kin Elementary School] + pressure_penalties[loc] = 150; + foreach loc in $locations[The Marinara Trench,Anemone Mine,The Dive Bar,The Caliginous Abyss] + pressure_penalties[loc] = 200;*/ + + + string custom_location_information; + string custom_location_url; + if (l == $location[domed city of ronaldus]) + { + int ronald_phase = moon_phase() % 8; + int ronald_darkness = abs(ronald_phase - 4); + int ronald_light = 4 - ronald_darkness; + if (ronald_light < 2) + custom_location_information = "No aliens"; + else + custom_location_information = (ronald_light * 8) + "% aliens"; + } + else if (l == $location[domed city of grimacia]) + { + int grimace_phase = moon_phase() / 2; + int grimace_darkness = abs(grimace_phase - 4); + int grimace_light = 4 - grimace_darkness; + if (grimace_light < 2) + custom_location_information = "No aliens"; + else + custom_location_information = (grimace_light * 8) + "% aliens"; + } + else if (l == $location[a-boo peak]) + { + if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0) + { + custom_location_information = __quest_state["Level 9"].state_int["a-boo peak hauntedness"] + "% haunted"; + } + } + else if (l == $location[oil peak]) + { + if (__quest_state["Level 9"].state_float["oil peak pressure"] > 0.0) + { + float pressure = __quest_state["Level 9"].state_float["oil peak pressure"]; + float pressure_remaining = pressure / 310.66; + custom_location_information = round(clampNormalf(pressure_remaining) * 100.0) + "% pressure"; + } + } + else if (l == $location[Inside the Palindome]) + { + if (!__quest_state["Level 11 Palindome"].state_boolean["dr. awkward's office unlocked"]) + { + float likelyhood_of_dudes = 0.0; + foreach m in monster_appearance_rates + { + if (monster_appearance_rates[m] <= 0.0) + continue; + if (m == $monster[none]) + continue; + if (m == $monster[Bob Racecar] || m == $monster[Racecar Bob] || m == $monster[Drab Bard]) + likelyhood_of_dudes += monster_appearance_rates[m]; + } + custom_location_information = likelyhood_of_dudes.round() + "% dudes"; + } + } + else if (l == $location[the hidden bowling alley]) + { + int pygmy_banishes_left = clampi(11 - get_property_int("_drunkPygmyBanishes"), 0, 11); + if ($item[bowl of scorpions].item_amount() > 0 && !$monster[drunk pygmy].is_banished() && pygmy_banishes_left > 0) + { + custom_location_information = pluralise(pygmy_banishes_left, "drunk pygmy", "drunk pygmies") + " left"; + } + } + /*else if (l == $location[twin peak]) //disabled, not very useful + { + string [int] entries; + + if (!__quest_state["Level 9"].state_boolean["Peak Stench Completed"]) + entries.listAppend(HTMLGenerateSpanOfClass("room 237", "r_element_stench_desaturated")); + if (!__quest_state["Level 9"].state_boolean["Peak Item Completed"]) + entries.listAppend("pantry"); + if (!__quest_state["Level 9"].state_boolean["Peak Jar Completed"]) + entries.listAppend("music"); + if (!__quest_state["Level 9"].state_boolean["Peak Init Completed"]) + entries.listAppend("you"); + custom_location_information = entries.generateLocationBarModifierEntries(); + }*/ + else if (l == $location[the arid\, extra-dry desert]) + { + if (__quest_state["Level 11 Desert"].state_int["Desert Exploration"] < 100) + { + custom_location_information = __quest_state["Level 11 Desert"].state_int["Desert Exploration"] + "% explored"; + } + } + else if (l == $location[barrrney's barrr]) + { + if (!__quest_state["Pirate Quest"].finished) + { + custom_location_information = pluralise(__quest_state["Pirate Quest"].state_int["insult count"], "insult", "insults"); + } + } + else if ($locations[Dreadsylvanian Woods,Dreadsylvanian Village,Dreadsylvanian Castle,The Slime Tube,A Maze of Sewer Tunnels,Hobopolis Town Square,Burnbarrel Blvd.,Exposure Esplanade,The Heap,The Ancient Hobo Burial Ground,The Purple Light District] contains l) + { + custom_location_information = "Clan logs"; + custom_location_url = "clan_raidlogs.php"; + } + else if (l == $location[the defiled alcove]) + custom_location_information = __quest_state["Level 7"].state_int["alcove evilness"] + " evilness"; + else if (l == $location[the defiled nook]) + custom_location_information = __quest_state["Level 7"].state_int["nook evilness"] + " evilness"; + else if (l == $location[the defiled cranny]) + custom_location_information = __quest_state["Level 7"].state_int["cranny evilness"] + " evilness"; + else if (l == $location[the defiled niche]) + custom_location_information = __quest_state["Level 7"].state_int["niche evilness"] + " evilness"; + else if (l == $location[the battlefield (hippy uniform)]) + custom_location_information = pluralise(__quest_state["Level 12"].state_int["frat boys left on battlefield"], "frat boy", "frat boys"); + else if (l == $location[the battlefield (frat uniform)]) + custom_location_information = pluralise(__quest_state["Level 12"].state_int["hippies left on battlefield"], "hippy", "hippies"); + else if (l.environment == "underwater") + { + Error error; + float pressure_penalty = l.pressurePenaltyForLocation(error); + custom_location_information = pressure_penalty.floor() + "% pressure"; + if (error.was_error) + custom_location_information = "Unknown pressure"; + /*int pressure_penalty = MAX(0, -numeric_modifier("item drop penalty")); + if (l == my_location()) + custom_location_information = pressure_penalty + "% pressure"; + else //numeric_modifier is location sensitive + custom_location_information = "Unknown pressure";*/ + } + else if ($locations[The Prince's Restroom,The Prince's Dance Floor,The Prince's Kitchen,The Prince's Balcony,The Prince's Lounge,The Prince's Canapes table] contains l) + { + int minutes_to_midnight = get_property_int("cinderellaMinutesToMidnight"); + if (minutes_to_midnight > 0) + custom_location_information = pluralise(minutes_to_midnight, "minute", "minutes") + " left"; + } + else if ($locations[Ye Olde Medievale Villagee,Portal to Terrible Parents,Rumpelstiltskin's Workshop] contains l) + { + int turns_left = clampi(30 - get_property_int("rumpelstiltskinTurnsUsed"), 0, 30); + custom_location_information = pluralise(turns_left, "turn", "turns") + " left"; + } + else if (l == $location[fernswarthy's basement]) + { + custom_location_information = "Floor " + __misc_state_int["Basement Floor"]; + } + else if ($locations[Your Bung Chakra,Your Guts Chakra,Your Liver Chakra,Your Nipple Chakra,Your Nose Chakra,Your Hat Chakra,Crimbo's Sack,Crimbo's Boots,Crimbo's Jelly,Crimbo's Reindeer,Crimbo's Beard,Crimbo's Hat] contains l) + { + string [location] property_name_for_location; + property_name_for_location[$location[Your Bung Chakra]] = "crimbo16BungChakraCleanliness"; + property_name_for_location[$location[Your Guts Chakra]] = "crimbo16GutsChakraCleanliness"; + property_name_for_location[$location[Your Liver Chakra]] = "crimbo16LiverChakraCleanliness"; + property_name_for_location[$location[Your Nipple Chakra]] = "crimbo16NippleChakraCleanliness"; + property_name_for_location[$location[Your Nose Chakra]] = "crimbo16NoseChakraCleanliness"; + property_name_for_location[$location[Your Hat Chakra]] = "crimbo16HatChakraCleanliness"; + property_name_for_location[$location[Crimbo's Sack]] = "crimbo16SackChakraCleanliness"; + property_name_for_location[$location[Crimbo's Boots]] = "crimbo16BootsChakraCleanliness"; + property_name_for_location[$location[Crimbo's Jelly]] = "crimbo16JellyChakraCleanliness"; + property_name_for_location[$location[Crimbo's Reindeer]] = "crimbo16ReindeerChakraCleanliness"; + property_name_for_location[$location[Crimbo's Beard]] = "crimbo16BeardChakraCleanliness"; + property_name_for_location[$location[Crimbo's Hat]] = "crimbo16CrimboHatChakraCleanliness"; + + string property_name = property_name_for_location[l]; + if (property_name != "") + { + custom_location_information = get_property_int(property_name) + "% clean"; + } + } + + //else if (pressure_penalties contains l) + //custom_location_information = pressure_penalties[l] + "% pressure"; + + string [int] monster_data; + if (false) + { + boolean even_appearance_rates = true; + float last_seen_rate = -10000.0; + foreach m in monster_appearance_rates + { + if (m == $monster[none]) + continue; + float rate = monster_appearance_rates[m]; + if (rate <= 0.0) + continue; + if (last_seen_rate == -10000.0) + last_seen_rate = rate; + else if (rate != last_seen_rate) + { + even_appearance_rates = false; + break; + } + + } + foreach m in monster_appearance_rates + { + if (m == $monster[none]) + continue; + float rate = monster_appearance_rates[m]; + if (rate <= 0.0) + continue; + if (even_appearance_rates) + monster_data.listAppend(m.to_string()); + else + monster_data.listAppend(m.to_string() + " (" + rate.round() + "%)"); + } + } + + float mpa = -1.0; + boolean should_output_meat_drop = false; + if (false) //disabled for the moment, still thinking about this. is it really that useful...? + { + float base_mpa = 0.0; + float total_appearance = 0.0; + foreach m in monster_appearance_rates + { + if (m == $monster[none]) + continue; + float rate = monster_appearance_rates[m]; + if (rate <= 0.0) + continue; + + float average_meat = (m.min_meat + m.max_meat) * 0.5; + + total_appearance += rate; + base_mpa += average_meat * rate; + } + if (total_appearance != 0.0) + { + base_mpa /= total_appearance; + mpa = base_mpa * (1.0 + meat_drop_modifier() / 100.0); + } + if (numeric_modifier(my_familiar(), "meat drop", familiar_weight(my_familiar()), $slot[familiar].equipped_item()) > 0.0) + should_output_meat_drop = true; + if (l == $location[the themthar hills]) + should_output_meat_drop = true; + } + + string [int] location_data; + string [int] location_urls; + float [int] location_fixed_widths; + + if (true) //__misc_state["in run"]) //useful even in aftercore + { + int area_delay = l.delayRemainingInLocation(); + + int turns_spent = l.turns_spent; + if (area_delay > 0) + location_data.listAppend(pluralise(area_delay, "turn", "turns") + "
delay"); + else if (turns_spent > 0) + location_data.listAppend(pluralise(turns_spent, "turn", "turns")); + } + + //easy list: $locations[Pump Up Muscle,Pump Up Mysticality,Pump Up Moxie,The Shore\, Inc. Travel Agency,Goat Party,Pirate Party,Lemon Party,The Roulette Tables,The Poker Room,Anemone Mine (Mining),The Knob Shaft (Mining),Friar Ceremony Location,Itznotyerzitz Mine (in Disguise),The Prince's Restroom,The Prince's Dance Floor,The Prince's Kitchen,The Prince's Balcony,The Prince's Lounge,The Prince's Canapes table,Portal to Terrible Parents,fernswarthy's basement] + //ashq foreach l in $locations[] if (l.appearance_rates().count() == 1 && l.appearance_rates()[$monster[none]] == 100.0) print(l); + boolean [location] nc_blacklist = {$location[fernswarthy's basement]:true}; + foreach l in $locations[] + if (l.appearance_rates().count() == 1 && l.appearance_rates()[$monster[none]] == 100.0) + nc_blacklist[l] = true; + + if ((my_buffedstat($stat[moxie]) < average_ml || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE) && sample_count > 0 && __misc_state["in run"] && monster_level_adjustment() < 100) + { + //Init: + //We only show this if the monsters out-moxie the player in-run. It feels as though it can easily be information overload otherwise. + if (true) + { + if (chance_of_jump == 0 && false) + location_data.listAppend("No jump"); + else + location_data.listAppend((chance_of_jump * 100.0).round() + "% jump"); + } + else if (true) + { + if (chance_of_jump <= 0.0) + location_data.listAppend(max_init.round() + "% init
" + (chance_of_jump * 100.0).round() + "% jump"); + else + location_data.listAppend((chance_of_jump * 100.0).round() + "% jump"); + } + else if (false) + { + string line; + if (chance_of_jump >= 1.0) + line = "100% jump"; + else + line = max_init.round() + "% init
" + (chance_of_jump * 100.0).round() + "% jump"; + location_data.listAppend(line); + } + else if (chance_of_jump < 1.0) + { + if (false) + location_data.listAppend(max_init.round() + "% init
" + (chance_of_jump * 100.0).round() + "% jump"); + else + location_data.listAppend((chance_of_jump * 100.0).round() + "% jump"); + } + } + if (nc_rate > 0.0 && !(nc_blacklist contains l)) + location_data.listAppend(nc_rate + "% NCs"); + if (custom_location_information != "") + { + location_data.listAppend(custom_location_information); + if (custom_location_url != "") + location_urls[location_data.count() - 1] = custom_location_url; + } + + if (my_path().id == PATH_HEAVY_RAINS) + { + boolean has_items_that_will_wash_away = false; + + foreach key, m in l.get_monsters() + { + foreach it, drop_rate in m.item_drops() + { + if (drop_rate == 0) + continue; + if (drop_rate == 100) + continue; + if (it.quest) + continue; + has_items_that_will_wash_away = true; + break; + } + if (has_items_that_will_wash_away) + break; + } + + if (has_items_that_will_wash_away) + { + //Calculate washaway chance: + boolean unknown_washaway = false; + int current_water_level = l.water_level_of_location(); + + int washaway_chance = current_water_level * 5; + if ($item[fishbone catcher's mitt].equipped_amount() > 0) + washaway_chance -= 15; //GUESS + + if ($effect[Fishy Whiskers].have_effect() > 0) + { + //washaway_chance -= ?; //needs spading + unknown_washaway = true; + } + if (unknown_washaway) + location_data.listAppend("?% wash"); + else + location_data.listAppend(washaway_chance + "% wash"); + } + } + if (mpa != -1.0 && should_output_meat_drop) + { + location_data.listAppend(mpa.round() + " MPA"); + } + if (monster_data.count() > 0) + { + location_data.listAppend(pluralise(monster_data.count(), "monster", "monsters")); + } + if (my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + { + float average_coins_gained = 0.0; + foreach m, rate in monster_appearance_rates + { + if (rate <= 0) continue; + float coin_from_monster = m.ka_dropped(); + //NC should already be included in appearance rates? + average_coins_gained += coin_from_monster * rate / 100.0; + } + if (average_coins_gained <= 0.0) + location_data.listAppend("No ka"); + else + location_data.listAppend(average_coins_gained.roundForOutput(1) + " ka"); + } + + boolean [location] powerleveling_locations = $locations[hamburglaris shield generator,[DungeonFAQ - Level 1],[DungeonFAQ - Level 2],[DungeonFAQ - Level 3]]; + + if (sample_count > 0 && (__misc_state["in run"] || powerleveling_locations contains l || average_ml > my_buffedstat($stat[moxie]))) + { + if (false) + location_data.listAppend(average_ml.round() + " ML
" + (average_ml * __misc_state_float["ML to mainstat multiplier"]).round() + " " + my_primestat().to_lower_case() + "/fight"); + else + location_data.listAppend(average_ml.round() + " ML"); + } + + if (in_bad_moon()) + { + boolean bad_moon_adventure_possible_now = false; + boolean bad_moon_adventure_possible = false; + + BadMoonAdventure [int] bad_moon_adventures = BadMoonAdventuresForLocation(l); + + if (bad_moon_adventures.count() > 0) + { + foreach key, adventure in bad_moon_adventures + { + boolean possible = !haveSeenBadMoonEncounter(adventure.encounter_id); + if (possible) + bad_moon_adventure_possible = possible; + if (!bad_moon_adventure_possible_now) + bad_moon_adventure_possible_now = !adventure.has_additional_requirements_not_yet_met; + } + } + + if (bad_moon_adventure_possible) + { + string style = "margin-top:1px;"; + if (!bad_moon_adventure_possible_now) + style += "opacity:0.25;"; + string image_html = HTMLGenerateTagPrefix("img", mapMake("src", __bad_moon_small_image_data, "style", style)); //"images/itemimages/badmoon.gif" + location_data.listAppend(image_html); + location_fixed_widths[location_data.count() - 1] = 0.15; //won't display otherwise + } + } + + if (plant_data.count() > 0) + { + string line; + + line = plant_data.generateLocationBarModifierEntries(); + + + if (__setting_location_bar_fixed_layout) + line = HTMLGenerateDivOfClass(line, "r_location_bar_ellipsis_entry"); + location_data.listAppend(line); + if (l == __last_adventure_location || true) + location_urls[location_data.count() - 1] = "place.php?whichplace=forestvillage&action=fv_friar"; + } + if (true) + { + //Holding containers: + string style; + if (displaying_navbar) + style += "bottom:" + __setting_navbar_height + ";"; + else + style += "bottom:0px;"; + + string onmouseenter_code; + string onmouseleave_code; + + if (__setting_enable_location_popup_box) + { + onmouseenter_code = "alterLocationPopupBarVisibility(event, true);"; + onmouseleave_code = "alterLocationPopupBarVisibility(event, false);"; + } + + string [string] outer_containiner_map = mapMake("class", "r_bottom_outer_container", "style", style); + bar.append(HTMLGenerateTagPrefix("div", outer_containiner_map)); + + string [string] inner_containiner_map = mapMake("id", "location_bar_inner_container", "class", "r_bottom_inner_container", "style", "background:white;"); + if (onmouseenter_code != "") + inner_containiner_map["onmouseenter"] = onmouseenter_code; + if (onmouseleave_code != "") + inner_containiner_map["onmouseleave"] = onmouseleave_code; + bar.append(HTMLGenerateTagPrefix("div", inner_containiner_map)); + } + + + + + + string [int] table_entries; + string [int] table_entry_urls; + string [int] table_entry_styles; + string [int] table_entry_classes; + float [int] table_entry_width_weight; + float [int] table_entry_fixed_width_percentage; + if (true) + { + buffer style; + if (location_data.count() > 0) + style.append("text-align:left;"); + style.append("padding-left:" + __setting_indention_width + ";"); + //style.append("text-wrap:none;"); + //style.append("overflow:hidden;"); + //style.append("white-space:nowrap;"); + //style.append("text-overflow:clip;"); + + string l_name = l.to_string(); + + if (__setting_location_bar_fixed_layout) + l_name = HTMLGenerateDivOfClass(l_name, "r_location_bar_ellipsis_entry"); + + //table_entries.listAppend(HTMLGenerateTagWrap("div", l_name, mapMake("class", "r_bold", "style", style))); + table_entries.listAppend(l_name); + table_entry_classes[table_entries.count() - 1] = "r_bold"; + table_entry_styles[table_entries.count() - 1] = style; + table_entry_width_weight[table_entries.count() - 1] = 1.05; + } + table_entries.listAppendList(location_data); + foreach key in location_urls + { + table_entry_urls[key + 1] = location_urls[key]; + } + foreach key in location_fixed_widths + { + table_entry_fixed_width_percentage[key + 1] = location_fixed_widths[key]; + } + foreach key in location_data + { + table_entry_width_weight[key + 1] = 0.8; + } + + + + bar.append(generateLocationBarTable(table_entries, table_entry_urls, table_entry_styles, table_entry_classes, table_entry_width_weight, table_entry_fixed_width_percentage, url)); + + + + //bar.append(""); + + + + + bar.append(""); + bar.append(""); + + float bottom_coordinates = __setting_navbar_height_in_em; + if (displaying_navbar) + bottom_coordinates = __setting_navbar_height_in_em * 2.0; + bar.append(generateLocationPopup(bottom_coordinates, (table_entries.count() == 1))); + return bar; +} + +//Support auto-refreshing guide while editing code: +static +{ + string __last_compile_time = ""; + __last_compile_time = now_to_string("kmsS"); +} + +string [string] generateAPIResponse() +{ + //35ms response time measured in-run + string [string] result; + + boolean should_force_reload = false; + + if (should_force_reload) + { + result["need to reload"] = should_force_reload; + return result; + } + + //Unique identifiers to determine whether a reload is necessary: + //All of these will be checked by the javascript. + result["turns played"] = my_turncount(); + result["hp"] = my_hp(); + result["mp"] = my_mp(); + result["+ml"] = monster_level_adjustment(); + result["+init"] = initiative_modifier(); + result["combat rate"] = combat_rate_modifier(); + result["+item"] = item_drop_modifier(); + result["familiar"] = my_familiar().to_int(); + result["adventures remaining"] = my_adventures(); + result["meat available"] = my_meat(); + result["stills available"] = stills_available(); + result["enthroned familiar"] = my_enthroned_familiar(); + result["bjorned familiar"] = my_bjorned_familiar(); + result["pulls remaining"] = pulls_remaining(); + result["location"] = my_location(); + + if (true) + { + int [effect] my_effects = my_effects(); + int total_effect_length = 0; + foreach e in my_effects + total_effect_length += my_effects[e]; + + result["effect count"] = my_effects.count(); + result["total effect length"] = total_effect_length; + } + result["fullness available"] = availableFullness(); + result["drunkenness available"] = availableDrunkenness(); + result["spleen available"] = availableSpleen(); + result["auto attack id"] = get_auto_attack(); //for copied monsters warning, don't want that to be stale + + if (true) + { + result["equipped items"] = equipped_items().to_json(); + } + + if (false) + { + //if we need a clockwork maid? maybe? + result["campground items"] = get_campground().to_json(); + } + if (__iotms_usable[$item[Order of the Green Thumb Order Form]]) + { + int plant_count = 0; + string [location, 3] florist_plants = get_florist_plants(); + foreach l in florist_plants + { + foreach key in florist_plants[l] + { + if (florist_plants[l][key] != "") + plant_count+= 1; + } + } + result["plant count"] = plant_count; + } + + if (true) + { + //Before discovering get_inventory() existed, this was very intensive - 40ms API load versus 25ms, or 28ms versus 16ms; + //With get_inventory(), maybe it won't be a problem? In-run, it's about 0.2ms. + int item_count = 0; + foreach it, amount in get_inventory() + item_count += amount; + result["item count"] = item_count; + } + if (true) + { + //When foldables change, item count does not, so we need to manually watch them: + //FIXME probably spooky putty/etc? + int [int] output; + boolean [item] relevant_items_strings = lookupItemsArray($strings[deceased crimbo tree,broken champagne bottle,tinsel tights,wad of used tape,makeshift garbage shirt]); + foreach it in relevant_items_strings + { + if (it.available_amount() > 0) + output[it.to_int()] = it.available_amount(); + } + + result["relevant items"] = output.to_json(); + } + /*else if (true) + { + //Checking every item is slow. But certain items won't trigger a reload, but need to. So: + boolean [item] relevant_items = $items[photocopied monster,4-d camera,pagoda plans,Elf Farm Raffle ticket,skeleton key,heavy metal thunderrr guitarrr,heavy metal sonata,Hey Deze nuts,rave whistle,damp old boot,map to Professor Jacking's laboratory,world's most unappetizing beverage,squirmy violent party snack,White Citadel Satisfaction Satchel,rusty screwdriver,giant pinky ring,The Lost Pill Bottle,GameInformPowerDailyPro magazine,dungeoneering kit,Knob Goblin encryption key,dinghy plans,Sneaky Pete's key,Jarlsberg's key,Boris's key,fat loot token,bridge,chrome ore,asbestos ore,linoleum ore,csa fire-starting kit,tropical orchid,stick of dynamite,barbed-wire fence,psychoanalytic jar,digital key,Richard's star key,star hat,star crossbow,star staff,star sword,Wand of Nagamar,Azazel's tutu,Azazel's unicorn,Azazel's lollipop,smut orc keepsake box,blessed large box,massive sitar,hammer of smiting,chelonian morningstar,17-alarm saucepan,shagadelic disco banjo,squeezebox of the ages,E.M.U. helmet,E.M.U. harness,E.M.U. joystick,E.M.U. rocket thrusters,E.M.U. unit,wriggling flytrap pellet,Mer-kin trailmap,Mer-kin stashbox,Makeshift yakuza mask,Novelty tattoo sleeves,strange goggles,zaibatsu level 2 card,zaibatsu level 3 card,flickering pixel,jar of oil,bowl of scorpions,molybdenum magnet,steel lasagna,steel margarita,steel-scented air freshener,Grandma's Map,mer-kin healscroll,scented massage oil,soggy used band-aid,extra-strength red potion,red pixel potion,red potion,filthy poultice,gauze garter,green pixel potion,cartoon heart,red plastic oyster egg,Manual of Dexterity,Manual of Labor,Manual of Transmission,wet stunt nut stew,lost key,resolution: be more adventurous,sugar sheet,sack lunch,glob of Blank-Out,gaudy key,plus sign,Newbiesport™ tent,Frobozz Real-Estate Company Instant House (TM),dry cleaning receipt,book of matches,rock band flyers,jam band flyers,disassembled clover,continuum transfunctioner,UV-resistant compass,eyepatch,carton of astral energy drinks,astral hot dog dinner,astral six-pack,gym membership card,tattered scrap of paper,bowling ball, snow boards,reassembled blackbird,reconstituted crow,louder than bomb,odd silver coin,grimstone mask,empty rain-doh can,Lord Spookyraven's spectacles,lump of Brituminous coal,bone rattle,mer-kin knucklebone,spooky glove,steam-powered model rocketship,crappy camera,shaking crappy camera,hedge maze puzzle,ghost of a necklace,telegram from Lady Spookyraven,Lady Spookyraven's finest gown,recipe: mortar-dissolving solution,disposable instant camera,unstable fulminate,thunder thigh,aquaconda brain,lightning milk,White Citadel Satisfaction Satchel,handful of smithereens,Loathing Legion jackhammer,lynyrd skin,red zeppelin ticket,lynyrd snare,glark cable,Fernswarthy's key,bottle of Gü-Gone,BURT,handful of juicy garbage,Jeff Goldblum larva,imbued seal-blubber candle,claw of the infernal seal,junk junk,sea lasso,seal tooth,worthless trinket,worthless gewgaw,worthless knick-knack,gnollish toolbox,poppy,opium grenade,talisman o' namsilat,toxic globule,yellow pixel,greek pasta spoon of peril,hellseal disguise,8042,uncapped red lava bottle,uncapped green lava bottle,uncapped blue lava bottle,capped red lava bottle,capped green lava bottle,capped blue lava bottle,insulated gold wire,little firkin,normal barrel,big tun,weathered barrel,dusty barrel,disintegrating barrel,moist barrel,rotting barrel,mouldering barrel,barnacled barrel,incriminating evidence,dangerous chemicals,kidnapped orphan,bat-oomerang,bat-jute,bat-o-mite,rad,cashew,stuffing fluffer]; + + + int [int] output; + + foreach it in relevant_items + { + if (it.available_amount() > 0) + output[it.to_int()] = it.available_amount(); + } + + boolean [item] relevant_items_strings = lookupItemsArray($strings[cornucopia]); + foreach it in relevant_items_strings + { + if (it.available_amount() > 0) + output[it.to_int()] = it.available_amount(); + } + + result["relevant items"] = output.to_json(); + }*/ + + /*if (true) + { + //Possibly switch to this in 17.7? It's slower by 4ms, but drastically simplifies implementation. + //The other method is 9/10ms. + //16ms: + //result["mafia properties"] = get_all_properties("", false).to_json(); + //13ms: + buffer mafia_properties; + foreach property_name, property_value in get_all_properties("", false) + { + mafia_properties.append(property_value); + } + result["mafia properties"] = mafia_properties.to_string(); + } + else if (true)*/ + if (true) + { + boolean [string] relevant_mafia_properties = $strings[merkinQuestPath,questF01Primordial,questF02Hyboria,questF03Future,questF04Elves,questF05Clancy,questG01Meatcar,questG02Whitecastle,questG03Ego,questG04Nemesis,questG05Dark,questG06Delivery,questI01Scapegoat,questI02Beat,questL02Larva,questL03Rat,questL04Bat,questL05Goblin,questL06Friar,questL07Cyrptic,questL08Trapper,questL09Topping,questL10Garbage,questL11MacGuffin,questL11Manor,questL11Palindome,questL11Pyramid,questL11Worship,questL12War,questL13Final,questM01Untinker,questM02Artist,questM03Bugbear,questM04Galaktic,questM05Toot,questM06Gourd,questM07Hammer,questM08Baker,questM09Rocks,questM10Azazel,questM11Postal,questM12Pirate,questM13Escape,questM14Bounty,questM15Lol,questS01OldGuy,questS02Monkees,sidequestArenaCompleted,sidequestFarmCompleted,sidequestJunkyardCompleted,sidequestLighthouseCompleted,sidequestNunsCompleted,sidequestOrchardCompleted,cyrptAlcoveEvilness,cyrptCrannyEvilness,cyrptNicheEvilness,cyrptNookEvilness,desertExploration,gnasirProgress,relayCounters,timesRested,currentEasyBountyItem,currentHardBountyItem,currentSpecialBountyItem,volcanoMaze1,_lastDailyDungeonRoom,seahorseName,chasmBridgeProgress,_aprilShower,lastAdventure,lastEncounter,_floristPlantsUsed,_fireStartingKitUsed,_psychoJarUsed,hiddenHospitalProgress,hiddenBowlingAlleyProgress,hiddenApartmentProgress,hiddenOfficeProgress,pyramidPosition,parasolUsed,_discoKnife,lastPlusSignUnlock,olfactedMonster,photocopyMonster,lastTempleUnlock,volcanoMaze1,blankOutUsed,peteMotorbikeCowling,peteMotorbikeGasTank,peteMotorbikeHeadlight,peteMotorbikeMuffler,peteMotorbikeSeat,peteMotorbikeTires,_petePeeledOut,_navelRunaways,_peteRiotIncited,_petePartyThrown,hiddenTavernUnlock,_dnaPotionsMade,_psychokineticHugUsed,dnaSyringe,_warbearGyrocopterUsed,questM20Necklace,questM21Dance,grimstoneMaskPath,cinderellaMinutesToMidnight,merkinVocabularyMastery,_pirateBellowUsed,questM21Dance,_defectiveTokenChecked,questG07Myst,questG08Moxie,questESpClipper,questESpGore,questESpJunglePun,questESpFakeMedium,questESlMushStash,questESlAudit,questESlBacteria,questESlCheeseburger,questESlCocktail,questESlSprinkles,questESlSalt,questESlFish,questESlDebt,_pickyTweezersUsed,_bittycar,questESpSerum,questESpOutOfOrder,_shrubDecorated,questESpEVE,questESpSmokes,questG09Muscle,_rapidPrototypingUsed,nsTowerDoorKeysUsed,_chateauDeskHarvested,lastGoofballBuy,nsChallenge1,nsChallenge2,nsContestants1,nsContestants2,nsContestants3,lastDesertUnlock,questM18Swamp,edPiece,warehouseProgress,questEStFishTrash,questEStNastyBears,questEStSocialJusticeI,questEStSocialJusticeII,questEStSuperLuber,questEStZippityDooDah,_summonAnnoyanceUsed,questEStWorkWithFood,questM24Doc,questEStGiveMeFuel,_mayoTankSoaked,_feastUsed,spelunkyNextNoncombat,spelunkySacrifices,spelunkyStatus,spelunkyUpgrades,spelunkyWinCount,_deckCardsDrawn,_glarkCableUses,_banderRunaways,questM25Armorer,pyramidBombUsed,_powerPillUses,nextAdventure,_volcanoItem1,_volcanoItem2,_volcanoItem3,_barrelPrayer,questECoBucket,_machineTunnelsAdv,_snojoFreeFights,snojoSetting,_lastCombatStarted,batmanZone,batmanUpgrades,batmanTimeLeft,batmanStats,questLTTQuestByWire,questM26Oracle,sourceTerminalEducate1,sourceTerminalEducate2,sourceTerminalEnquiry,_sourceTerminalDigitizeUses,_sourceTerminalEnhanceUses,_sourceTerminalExtrudes,_detectiveCasesCompleted,_pottedTeaTreeUsed,lastIslandUnlock,falloutShelterChronoUsed,_timeSpinnerMinutesUsed,_lynyrdSnareUses,_noobSkillCount,_universeCalculated,_horsery,_expertCornerCutterUsed,boomBoxSong,_questPartyFair,_questPartyFairQuest,_neverendingPartyFreeTurns,_latteRefillsUsed,_latteBanishUsed,_latteCopyUsed,_latteDrinkUsed,_kgbTranquilizerDartUses,banishedMonsters,lastLightsOutTurn,lastVoteMonsterTurn,_lastCombatStarted,_sausageFights,_saberMod,_saberForceMonster,_daycareRecruits,_daycareGymScavenges,_campAwayCloudBuffs,_campAwaySmileBuffs,moonTuned,zeppelinProtestors,questL11Ron,questL11Shen,redSnapperPhylum,_canSeekBirds,questGuzzlr,retroCapeSuperhero,retroCapeWashingInstructions,noncombatForcerActive]; + + if (false) + { + //Give full description: + string [string] mafia_properties; + foreach property_name in relevant_mafia_properties + { + mafia_properties[property_name] = get_property(property_name); + } + result["mafia properties"] = mafia_properties.to_json(); + } + else + { + //Give partial description: (equivalent for equivalency testing) + //65% smaller + buffer mafia_properties; + boolean first = true; + foreach property_name in relevant_mafia_properties + { + //This could fail an update if two properties coincidentally update a certain way - i.e. "1" and "21" becoming "12" and "1" both would be "121" - but it's unlikely to happen, and the faster this is, the better. + /*if (first) + first = false; + else + mafia_properties.append(",");*/ + string value = get_property(property_name); + mafia_properties.append(value); + } + result["mafia properties"] = mafia_properties.to_string(); + } + result["logged in"] = playerIsLoggedIn(); + } + if (my_path().id == PATH_AVATAR_OF_WEST_OF_LOATHING || my_path().id == PATH_AVATAR_OF_SNEAKY_PETE || my_path().id == PATH_THE_SOURCE || my_path().id == PATH_GELATINOUS_NOOB) + { + int skill_count = 0; + foreach s in $skills[] + { + if (s.skill_is_usable()) + skill_count += 1; + } + result["skill_count"] = skill_count; + } + else if (true) + { + int relevant_skill_count = 0; + foreach s in $skills[Gothy Handwave] + { + if (s.skill_is_usable()) + relevant_skill_count += 1; + } + result["relevant_skill_count"] = relevant_skill_count; + } + result["last compile time"] = __last_compile_time; + + result["monster_phylum"] = monster_phylum().to_string(); + return result; +} + +buffer generateNavbar(Checklist [int] ordered_output_checklists) +{ + buffer navbar; + navbar.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_bottom_outer_container", "style", "bottom:0px;"))); + navbar.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_bottom_inner_container", "style", "background:" + __setting_navbar_background_colour + ";"))); + + string [int] titles; + foreach key in ordered_output_checklists + titles.listAppend(ordered_output_checklists[key].title); + + if (titles.count() > 0) + { + int [int] each_width; + //Calculate width of each title: + if (__setting_navbar_has_proportional_widths) + { + int total_character_count = 0; + foreach i in titles + { + string title = titles[i]; + int title_length = title.length(); + total_character_count += title_length; + } + if (total_character_count > 0) + { + foreach i in titles + { + string title = titles[i]; + float title_length = title.length(); + + float calculating_value = (100.0 * title_length) / (to_float(total_character_count)); + each_width[i] = floor(calculating_value); + } + } + } + else + { + float remaining_width = 100.0; + int number_done = 0; + foreach i in titles + { + int shared_width = to_int(remaining_width / to_float(titles.count() - number_done)); + each_width[i] = shared_width; + remaining_width -= shared_width; + number_done += 1; + } + } + boolean first = true; + foreach i in titles + { + string title = titles[i]; + + string onclick_javascript = ""; + + //Cancel our usual link: + onclick_javascript += "navbarClick(event,'" + HTMLConvertStringToAnchorID(title + " checklist container") + "')"; + + navbar.append(HTMLGenerateTagPrefix("a", mapMake("class", "r_a_undecorated", "href", "#" + HTMLConvertStringToAnchorID(title), "onclick", onclick_javascript))); + navbar.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_navbar_button_container", "style", "width:" + each_width[i] + "%;"))); + + //Vertical separator: + if (first) + first = false; + else if (!__setting_gray_navbar) + navbar.append(HTMLGenerateDivOfClass("", "r_navbar_line_separator")); + + string text_div = HTMLGenerateDivOfClass(title, "r_navbar_text"); + if (true) + { + //Vertical centring with divs: + //Which is to... tell the browser to act like a table. + //Sorry. + navbar.append(HTMLGenerateTagPrefix("div", mapMake("style", "padding-left:1px;padding-right:1px;margin-left:auto;margin-right:auto;display:table;height:100%;"))); + navbar.append(HTMLGenerateTagWrap("div", text_div, mapMake("style", "display:table-cell;vertical-align:middle;"))); + navbar.append(""); + } + navbar.append(""); + navbar.append(""); + } + } + navbar.append(""); + navbar.append(""); + return navbar; +} + +void setUpCSSStyles() +{ + if (true) //body + { + string body_style, body_medium, body_small, body_tiny; + if (!__setting_use_kol_css) + { + //Base page look: + body_style += "font-family:Arial,Helvetica,sans-serif;background-color:white;color:black;"; + PageAddCSSClass("a:link", "", "color:black;", -10); + PageAddCSSClass("a:visited", "", "color:black;", -10); + PageAddCSSClass("a:active", "", "color:black;", -10); + } + if (__setting_side_negative_space_is_dark) + body_style += "background-color:" + __setting_dark_colour + ";"; + else + body_style += "background-color:#FFFFFF;"; + body_style += "margin:0px;padding:0px;font-size:14px;"; + + if (__setting_ios_appearance) + body_style += "font-family:'Helvetica Neue',Arial, Helvetica, sans-serif;font-weight:lighter;"; + + + body_medium += "font-size:13px;"; + body_small += "font-size:12px;"; + body_tiny += "font-size:12px;"; + + body_style += "--cl_entry_container_padding: 5px;"; + body_medium += "--cl_entry_container_padding: 4px;"; + body_small += "--cl_entry_container_padding: 3px;"; + body_tiny += "--cl_entry_container_padding: 3px;"; + + body_style += "--cl_container_padding:" + __setting_indention_width + ";"; + body_medium += "--cl_container_padding:" + (__setting_indention_width_in_em / 2.0) + "em;"; + body_small += "--cl_container_padding: 0px;"; + body_tiny += "--cl_container_padding: 0px;"; + + body_style += "--image-width:" + __setting_image_width_large + "px;"; + body_medium += "--image-width:" + __setting_image_width_medium + "px;"; + body_small += "--image-width:" + __setting_image_width_small + "px;"; + body_tiny += "--image-width: 0px;"; + + PageAddCSSClass("body", "", body_style, -11); + PageAddCSSClass("body", "", body_medium, -11, __setting_media_query_medium_size); + PageAddCSSClass("body", "", body_small, -11, __setting_media_query_small_size); + PageAddCSSClass("body", "", body_tiny, -11, __setting_media_query_tiny_size); + } + + PageAddCSSClass("", "r_clickable", "cursor:pointer;cursor:hand;"); + PageAddCSSClass("", "r_future_option", "color:" + __setting_unavailable_colour + ";"); + + PageAddCSSClass("a", "r_cl_internal_anchor", "position:absolute;z-index:2;display:inline-block;"); + + PageAddCSSClass("", "r_button", "visibility:hidden;cursor:pointer;color:#7F7F7F;font-size:1.5em;z-index:3;position:absolute;"); //background:" + __setting_page_background_colour + "; + + PageAddCSSClass("div", "r_word_wrap_group", "display:inline-block;"); + + if (true) + { + string hr_definition; + hr_definition = "height: 1px; margin-top: 1px; margin-bottom: 1px; border: 0px; width: 100%;"; + + hr_definition += "background: " + __setting_line_colour + ";"; + PageAddCSSClass("hr", "", hr_definition); + } + + + if (__setting_fill_vertical) + PageAddCSSClass("div", "r_vertical_fill", "bottom:0;left:0;right:0;position:fixed;height:100%;margin-left:auto;margin-right:auto;"); + + if (__setting_show_navbar) + { + PageAddCSSClass("div", "r_navbar_line_separator", "position:absolute;float:left;min-width:1px;min-height:" + __setting_navbar_height + ";background:" + __setting_line_colour + ";"); + PageAddCSSClass("div", "r_navbar_text", "text-align:center;font-weight:bold;font-size:.9em;"); + PageAddCSSClass("div", "r_navbar_button_container", "overflow:hidden;vertical-align:top;display:inline-block;height:" + __setting_navbar_height + ";"); + + if (__setting_gray_navbar) + { + PageAddCSSClass("div", "r_navbar_line_separator", "display:none;"); + PageAddCSSClass("div", "r_navbar_text", "text-align:center;font-size:.9em;font-weight:normal;"); + PageAddCSSClass("div", "r_navbar_button_container", "overflow:hidden;vertical-align:top;display:inline-block;height:" + __setting_navbar_height + ";"); + __setting_navbar_background_colour = __setting_page_background_colour; + } + } + PageAddCSSClass("div", "r_bottom_outer_container", "height:" + __setting_navbar_height + ";position:fixed;z-index:7;width:100%;overflow:hidden;"); + if (true) + { + //Second holding container: + string style = ""; + int width = __setting_horizontal_width; + if (!__setting_fill_vertical) + width -= 2; + + style += "max-width:" + width + "px;margin-left:auto; margin-right:auto;font-size:1em;"; + style += "height:" + __setting_navbar_height + ";"; + if (!__setting_side_negative_space_is_dark && !__setting_fill_vertical) + style += "border-left:1px solid;border-right:1px solid;"; + style += "border-top:1px solid;border-color:" + __setting_line_colour + ";"; + PageAddCSSClass("div", "r_bottom_inner_container", style); + } + //PageAddCSSClass("", "r_location_bar_table_entry", "vertical-align:middle;padding-left:0.5em;display:table-cell;"); + PageAddCSSClass("", "r_location_bar_table_entry", "vertical-align:middle;padding-left:0.5em;padding-right:0.5em;display:table-cell;"); + PageAddCSSClass("", "r_location_bar_ellipsis_entry", "overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;"); + + PageAddCSSClass("", "r_only_display_if_not_large", ""); + PageAddCSSClass("", "r_only_display_if_not_large", "display:none !important;", 0, __setting_media_query_large_size); + + PageAddCSSClass("", "r_only_display_if_not_medium", ""); + PageAddCSSClass("", "r_only_display_if_not_medium", "display:none !important;", 0, __setting_media_query_medium_size); + + PageAddCSSClass("", "r_only_display_if_not_tiny", ""); + PageAddCSSClass("", "r_only_display_if_not_tiny", "display:none !important;", 0, __setting_media_query_tiny_size); + + PageAddCSSClass("", "r_only_display_if_not_small", ""); + PageAddCSSClass("", "r_only_display_if_not_small", "display:none !important;", 0, __setting_media_query_small_size); + + PageAddCSSClass("", "r_only_display_if_small", "display:none !important;", 0, __setting_media_query_large_size); + PageAddCSSClass("", "r_only_display_if_small", "display:none !important;", 0,__setting_media_query_medium_size); + PageAddCSSClass("", "r_only_display_if_small", "", 0, __setting_media_query_small_size); + PageAddCSSClass("", "r_only_display_if_small", "display:none !important;", 0,__setting_media_query_tiny_size); + + PageAddCSSClass("", "r_only_display_if_tiny", "display:none !important;", 0, __setting_media_query_large_size); + PageAddCSSClass("", "r_only_display_if_tiny", "display:none !important;", 0,__setting_media_query_medium_size); + PageAddCSSClass("", "r_only_display_if_tiny", "display:none !important;", 0, __setting_media_query_small_size); + PageAddCSSClass("", "r_only_display_if_tiny", "", 0, __setting_media_query_tiny_size); + + + PageAddCSSClass("", "r_location_bar_background_blur", "background:rgba(255, 255, 255, 0.95);box-shadow:0px 0px 1px 2px rgba(255, 255, 255, 0.95);"); + PageAddCSSClass("", "r_location_bar_background_blur_small", "background:rgba(255, 255, 255, 0.95);box-shadow:0px 0px 0.5px 1px rgba(255, 255, 255, 0.95);"); + + PageAddCSSClass("", "r_tooltip_outer_class", "border-bottom:1px dotted;border-color:" + __setting_line_colour + ";");//"position:relative;"); + PageAddCSSClass("", "r_tooltip_inner_class", "background:white;border-style:solid;border-color:" + __setting_line_colour + ";border-width:1px;padding-left:1em;padding-right:1em;padding-bottom:0.25em;padding-top:0.25em;position:absolute;opacity:0;transition:visibility 0s linear 0.25s, opacity 0.25s linear;visibility:hidden;margin-top:1.5em;z-index:1000"); + PageAddCSSClass("", "r_tooltip_inner_class_margin", "margin-top:-200px;"); + PageAddCSSClass("", "r_tooltip_outer_class:hover .r_tooltip_inner_class", "opacity:1;visibility:visible;transition-delay:0s;"); + //PageAddCSSClass("", "r_tooltip_inner_class_weve_had_one_yes_but_what_about_second_inner_class", "background:white;border-style:solid;border-color:black;border-width:1px;padding:1em;top:1.5em;"); + + PageAddCSSClass("", "r_no_css_transition", "-webkit-transition:none !important;-moz-transition:none !important;-o-transition:none !important;-ms-transition:none !important;transition:none !important;"); + + PageAddCSSClass("img", "", "border:0px;"); +} + + +void contextMenuInit() +{ + PageAddCSSClass("div", "menu", "position:absolute; border:5px double; padding:0px 10px 5px; z-index:4; background:ghostwhite; display:none; flex-direction:column;"); + PageAddCSSClass("div", "ct_menu_choice_group", "display:flex; flex-direction:column; margin-top:5px;"); + PageAddCSSClass("div", "ct_menu_choice", "display:inline-flex; flex-flow:row wrap; justify-content:center; align-items:center;"); + PageAddCSSClass("", "ct_menu_choice_subheader", "width:100%; margin-bottom:5px;"); //text-decoration:underline; ? + PageAddCSSClass("", "ct_menu_choice_label", ""); //width:50%; text-align:right; + PageAddCSSClass("", "ct_menu_choice_setting", "width:auto; overflow:hidden; font-size:1em;"); //width:50%; //for some reason, they don't inherit size, so set it + +} + +buffer generateContextualMenuChoice(string choice_label, string choice_id, string [string] option_values) +{ + buffer choice; + choice.append(HTMLGenerateTagWrap("label", choice_label, string [string] {"class":"ct_menu_choice_label", "for":choice_id})); + + buffer options; + options.append(HTMLGenerateTagWrap("option", "", string [string] {"value":"default", "id":"default_" + choice_id, "style":"display:none;"})); + foreach choice_value, choice_text in option_values + { + options.append(HTMLGenerateTagWrap("option", choice_text, string [string] {"value":choice_value})); + } + + choice.append(HTMLGenerateTagWrap("select", options, string [string] {"id":choice_id, "class":"ct_menu_choice_setting", "onchange":"registerSettingsChange(event)"})); + return HTMLGenerateTagWrap("div", choice, string [string] {"class":"ct_menu_choice"}); +} + +buffer generateContextualMenu() +{ + //Minimization-specific contextual menu + buffer guide_contextual_menu; + + buffer guide_contextual_menu_header; + guide_contextual_menu_header.append(HTMLGenerateTagWrap("div", "", string [string] {"id":"contextual_menu_header_text", "style":"flex-grow:1; font-size:1.07em; font-weight:bold; padding-bottom:5px; word-wrap:anywhere;"})); + guide_contextual_menu_header.append(HTMLGenerateTagWrap("div", "?", string [string] {"id":"settings_help_button", "title":entity_encode('"What is this?"'), "style":"margin-left:-8px; width:1.2em; border:1px solid; border-radius:1em; background-color:lightcyan; cursor:pointer; flex-shrink:0;", "onclick":"alterSettingsHelpDisplay()"})); + + guide_contextual_menu.append(HTMLGenerateTagWrap("div", guide_contextual_menu_header, string [string] {"id":"contextual_menu_header", "style":"display:flex; flex-direction:row-reverse; align-items:center; margin-bottom:5px; border-bottom:2px solid;"})); + //guide_contextual_menu.append(HTMLGenerateTagWrap("span", "", string [string] {"id":"contextual_menu_trace", "style":"margin-bottom:2px;"})); //cur. unused + //guide_contextual_menu.append(HTMLGenerateTagWrap("span", "", string [string] {"id":"contextual_menu_current_node", "style":"margin-bottom:2px;"})); + //guide_contextual_menu.append(HTMLGenerateTagWrap("div", "", string [string] {"id":"contextual_menu_next_nodes", "style":"margin-bottom:2px;"})); //cur. unused + + + if (true) + { + //auto-expansion choices + buffer choice_group; + choice_group.append(HTMLGenerateTagWrap("div", "Auto-expansion", string [string] {"class":"ct_menu_choice_subheader"})); + choice_group.append(generateContextualMenuChoice("At rollover", "rollover_AE", string [string] {"true":"yes","false":"no"})); + choice_group.append(generateContextualMenuChoice("On ascension", "ascension_AE", string [string] {"true":"yes", "false":"no"})); + + guide_contextual_menu.append(HTMLGenerateTagWrap("div", choice_group, string [string] {"class":"ct_menu_choice_group", "id":"auto_expansion_choice_group"})); + } + if (true) + { + //when minimized choices + buffer choice_group; + choice_group.append(HTMLGenerateTagWrap("div", "When minimized", string [string] {"class":"ct_menu_choice_subheader"})); + choice_group.append(generateContextualMenuChoice("Opacity", "opacity", string [string] {"half":"halve opacity","full":"keep full opacity"})); + choice_group.append(generateContextualMenuChoice("Tile image", "image", string [string] {"none":"don't display", "small":"display smallest", "auto":"don't change image size"})); + choice_group.append(generateContextualMenuChoice("Content to show", "collapsing", string [string] {"modifiers":"title", "entries":"title + subtitle", "replace":"replace all with tile ID"})); + guide_contextual_menu.append(HTMLGenerateTagWrap("div", choice_group, string [string] {"class":"ct_menu_choice_group", "id":"auto_expansion_choice_group"})); + } + + if (true) + { + //info + buffer help_text; + help_text.append("- Right-click on the minimize button of a tile to open the settings for that specific tile."); + help_text.append("

- Neither the Minimize nor the Settings feature will work if you don't set your browser to be able to store data."); + help_text.append("
- Everything is saved in LocalStorage. To access it, right-click anywhere => inspect element => Storage => Local Storage (Firefox), or right-click anywhere => inspect => Application => Storage => Local Storage (Edge/Chrome)."); + help_text.append("
- If you're actually relying on this feature, make sure you note its value every once in a while; if there's ever a release that changes their syntax, they'll get erased!."); + help_text.append("
- Deleting your browser's cache will also wipe out everything."); + guide_contextual_menu.append(HTMLGenerateTagWrap("div", help_text, string [string] {"id":"ct_menu_help", "style":"display:none;"})); + } + + //the rest of the computation happens in the .js + return guide_contextual_menu; +} +// Misc +void generateGardenEntry(ChecklistEntry [int] resource_entries, boolean [item] garden_source_items, boolean [item] garden_creatable_items) +{ + ChecklistSubentry [int] subentries; + string image_name = ""; + foreach it in garden_source_items + { + if (it.available_amount() == 0) continue; + if (image_name.length() == 0) + image_name = "__item " + it; + subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", "")); + } + if (subentries.count() > 0) + { + ChecklistSubentry subentry = subentries[subentries.count() - 1]; //hacky + TagGroup tags; + tags.id = "Campground garden possible creations"; //differenciate by "kind of garden" ? + + + int [item] creatable_items = garden_creatable_items.creatable_items(); + string [int] output_list; + foreach it in creatable_items + { + int amount = creatable_items[it]; + + if (it.to_slot() != $slot[none] && it.available_amount() > 0) //already have one + continue; + output_list.listAppend(pluralise(amount, it)); + } + if (output_list.count() > 0) + { + subentry.entries.listAppend("Can create " + output_list.listJoinComponents(", ", "or") + "."); + } + resource_entries.listAppend(ChecklistEntryMake(image_name, "", subentries, 8)); + } +} + + +RegisterResourceGenerationFunction("IOTMGardensGenerateResource"); +void IOTMGardensGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["in run"] || !in_ronin()) + return; + + //Garden items: + if (true) + { + boolean [item] garden_creatable_items; + garden_creatable_items[$item[pumpkin juice]] = true; + if (__misc_state["can eat just about anything"]) + garden_creatable_items[$item[pumpkin pie]] = true; + if (__misc_state["can drink just about anything"]) + garden_creatable_items[$item[pumpkin beer]] = true; + if (__misc_state_string["yellow ray source"] == 4766.to_item().to_string()) + garden_creatable_items[4766.to_item()] = true; + + generateGardenEntry(resource_entries, $items[pumpkin], garden_creatable_items); + } + if (true) + { + boolean [item] garden_creatable_items; + if (__misc_state["can eat just about anything"]) + garden_creatable_items[$item[peppermint patty]] = true; + if (__misc_state["can drink just about anything"]) + garden_creatable_items[$item[peppermint twist]] = true; + if (__misc_state["free runs usable"]) + garden_creatable_items[$item[peppermint parasol]] = true; + garden_creatable_items[$item[peppermint crook]] = true; + generateGardenEntry(resource_entries, $items[peppermint sprout], garden_creatable_items); + } + if (true) + { + boolean [item] garden_creatable_items; + if (__misc_state["can eat just about anything"]) + garden_creatable_items[$item[skeleton quiche]] = true; + if (__misc_state["can drink just about anything"]) + garden_creatable_items[$item[crystal skeleton vodka]] = true; + if (!__misc_state["mysterious island available"]) + garden_creatable_items[$item[skeletal skiff]] = true; + if (hippy_stone_broken()) + garden_creatable_items[$item[auxiliary backbone]] = true; + generateGardenEntry(resource_entries, $items[skeleton], garden_creatable_items); + } + if (true) + { + generateGardenEntry(resource_entries, $items[handful of barley,cluster of hops,fancy beer bottle,fancy beer label], $items[can of Brütalbräu,can of Drooling Monk,can of Impetuous Scofflaw,bottle of old pugilist,bottle of professor beer,bottle of rapier witbier,artisanal homebrew gift package]); + } + if (true) + { + boolean [item] garden_creatable_items; + + foreach it in $items[snow cleats,snow crab,unfinished ice sculpture,snow mobile,ice bucket,bod-ice,snow belt,ice house,ice nine] + garden_creatable_items[it] = true; + + if (!__quest_state["Level 9"].state_boolean["bridge complete"]) + garden_creatable_items[$item[snow boards]] = true; + + if (!__quest_state["Level 4"].finished) + garden_creatable_items[$item[snow shovel]] = true; + + if (__misc_state["can eat just about anything"]) + garden_creatable_items[$item[snow crab]] = true; + if (__misc_state["can drink just about anything"]) + garden_creatable_items[$item[Ice Island Long Tea]] = true; + if (hippy_stone_broken()) + garden_creatable_items[$item[ice nine]] = true; + + + generateGardenEntry(resource_entries, $items[snow berries, ice harvest], garden_creatable_items); + } +} + +RegisterTaskGenerationFunction("IOTMHorseryGenerateTasks"); +void IOTMHorseryGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[lookupItem("Horsery contract")]) return; + if (get_property("_horsery") == "" && my_meat() >= 500) + { + optional_task_entries.listAppend(ChecklistEntryMake("__item magical pony: Spectrum Dash", "place.php?whichplace=town_right&action=town_horsery", ChecklistSubentryMake("Bring along a horse!", "", "Probably the dark horse.")).ChecklistEntrySetIDTag("Horsery get a horse")); + + } +} + +RegisterResourceGenerationFunction("IOTMLibramGenerateResource"); +void IOTMLibramGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (__misc_state["bookshelf accessible"]) { + int libram_mp_cost = nextLibramSummonMPCost(); + + + string [int] librams_usable; + foreach s in __libram_skills { + if (s.skill_is_usable()) + librams_usable.listAppend(s.to_string()); + } + if (libram_mp_cost <= my_maxmp() && librams_usable.count() > 0) { + ChecklistSubentry subentry; + if (librams_usable.count() == 1) + subentry.header = "Libram"; + else + subentry.header = "Librams"; + subentry.header += " summonable"; + subentry.modifiers.listAppend(libram_mp_cost + "MP cost"); + + string [int] readable_list; + foreach key in librams_usable { + string libram_name = librams_usable[key]; + if (libram_name.stringHasPrefix("Summon ")) + libram_name = libram_name.substring(7); + readable_list.listAppend(libram_name); + } + + subentry.entries.listAppend(readable_list.listJoinComponents(", ", "and") + "."); + + if ($skill[summon taffy].skill_is_usable() && get_property_int("_taffyRareSummons") < 4) { + int rare_summons = get_property_int("_taffyRareSummons"); + subentry.entries.listAppend((4 - rare_summons) + " rare taffies still available."); + float chance = powf(0.5, MAX(0, rare_summons + 1)); + subentry.entries.listAppend("Could try to summon a yellow taffy. (" + (chance * 100.0).roundForOutput(1) + "% chance)"); + } + + resource_entries.listAppend(ChecklistEntryMake("__item libram of divine favors", "campground.php?action=bookshelf", subentry, 7).ChecklistEntrySetIDTag("Bookshelf librams resource")); + } + + + if ($skill[summon brickos].skill_is_usable() && __misc_state["in run"]) { + if (get_property_int("_brickoEyeSummons") <3) { + ChecklistSubentry subentry; + subentry.header = (3 - get_property_int("_brickoEyeSummons")) + " BRICKO™ eye bricks obtainable"; + subentry.entries.listAppend("Cast Summon BRICKOs libram. (" + libram_mp_cost + " mp)"); + resource_entries.listAppend(ChecklistEntryMake("__item bricko eye brick", "campground.php?action=bookshelf", subentry, 9).ChecklistEntrySetIDTag("Bookshelf BRICKO libram resource")); + + } + } + } + + if ((__misc_state["in run"] || true) && availableDrunkenness() >= 0) { + boolean [item] all_possible_bricko_fights = $items[bricko eye brick,bricko airship,bricko bat,bricko cathedral,bricko elephant,bricko gargantuchicken,bricko octopus,bricko ooze,bricko oyster,bricko python,bricko turtle,bricko vacuum cleaner]; + + int bricko_potential_fights_available = 0; + foreach it in $items[bricko eye brick,bricko airship,bricko bat,bricko cathedral,bricko elephant,bricko gargantuchicken,bricko octopus,bricko ooze,bricko oyster,bricko python,bricko turtle,bricko vacuum cleaner] { + bricko_potential_fights_available += it.available_amount(); + } + bricko_potential_fights_available = MIN(10 - get_property_int("_brickoFights"), bricko_potential_fights_available); + if (!in_ronin()) + bricko_potential_fights_available = clampi(10 - get_property_int("_brickoFights"), 0, 10); + if (bricko_potential_fights_available > 0) { + ChecklistSubentry subentry; + TagGroup tags; + tags.id = "BRICKO free fight"; + subentry.header = pluralise(bricko_potential_fights_available, "BRICKO™ fight", "BRICKO™ fights") + " ready"; + + + foreach fight in all_possible_bricko_fights { + int number_available = fight.available_amount(); + if (number_available > 0) { + string line = pluralise(number_available, fight); + + if ($items[rock band flyers,jam band flyers].available_amount() > 0 && !__quest_state["Level 12"].state_boolean["Arena Finished"] && __quest_state["Level 12"].in_progress && get_property_int("flyeredML") < 10000) { + monster m = fight.to_string().to_monster(); //is there a better way to look this up? + line += " (" + m.base_initiative + "% init)"; + } + subentry.entries.listAppend(line); + } + } + + item [int] craftable_fights; + string [int] creatable; + foreach fight in all_possible_bricko_fights { + monster m = fight.to_string().to_monster(); //is there a better way to look this up? + int bricks_needed = get_ingredients_fast(fight)[$item[bricko brick]]; + int monster_level = m.raw_attack; + int number_available = creatable_amount(fight); + if (number_available > 0) { + craftable_fights.listAppend(fight); + creatable.listAppend(pluralise(number_available, fight) + " (" + bricks_needed + " bricks, " + monster_level + "ML)"); + } + } + + if (creatable.count() > 0) + subentry.entries.listAppend("Creatable: (" + $item[bricko brick].available_amount() + " bricks available)" + HTMLGenerateIndentedText(creatable)); + + resource_entries.listAppend(ChecklistEntryMake("__item bricko brick", "inventory.php?ftext=bricko", subentry, tags, 7)); + } + } +} + +void smithsnessGenerateCoalSuggestions(string [int] coal_suggestions) +{ + if (!__misc_state["in run"]) + return; + string [item] coal_item_suggestions; + + if (__misc_state["can equip just about any weapon"]) + { + if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) + coal_item_suggestions[$item[half a purse]] = "2x smithsness meat for nuns"; + coal_item_suggestions[$item[A Light that Never Goes Out]] = "2x smithsness +item"; + + + if (my_class() == $class[seal clubber]) + coal_item_suggestions[$item[Meat Tenderizer is Murder]] = "weapon, +2x smithsness muscle %"; + else if (my_class() == $class[turtle tamer]) + coal_item_suggestions[$item[Ouija Board, Ouija Board]] = "weapon, +2x smithsness muscle %"; + else if (my_class() == $class[pastamancer]) + coal_item_suggestions[$item[Hand that Rocks the Ladle]] = "weapon, +2x smithsness mysticality %"; + else if (my_class() == $class[sauceror]) + coal_item_suggestions[$item[Saucepanic]] = "weapon, +myst stats, +2x smithsness mysticality %"; + else if (my_class() == $class[disco bandit]) + coal_item_suggestions[$item[Frankly Mr. Shank]] = "weapon, +2x smithsness moxie %"; + else if (my_class() == $class[accordion thief]) + coal_item_suggestions[$item[Shakespeare's Sister's Accordion]] = "weapon, +2x smithsness moxie %, useful cadenza"; + //not sure I like these suggestions based off of mainstat, but... + else if (my_primestat() == $stat[mysticality]) + coal_item_suggestions[$item[Staff of the Headmaster's Victuals]] = "weapon, +smithsnesss spell damage"; + else if (my_primestat() == $stat[muscle]) + coal_item_suggestions[$item[Work is a Four Letter Sword]] = "weapon, +2x smithsness weapon damage"; + else if (my_primestat() == $stat[moxie]) + coal_item_suggestions[$item[Sheila Take a Crossbow]] = "weapon, +smithsness initiative"; + + string [int] sheila_reasons; + if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"]) + sheila_reasons.listAppend("modern zmobies"); + if (!__quest_state["Level 13"].state_boolean["Init race completed"]) + sheila_reasons.listAppend("lair init race"); + if (sheila_reasons.count() > 0) + coal_item_suggestions[$item[Sheila Take a Crossbow]] = "weapon, +smithsness initiative (useful for " + sheila_reasons.listJoinComponents(", ", "and") + ")"; + + + } + coal_item_suggestions[$item[Hand in Glove]] = "lots of +ML"; + if ($item[dirty hobo gloves].available_amount() == 0) + coal_item_suggestions[$item[Hand in Glove]] += " (need dirty hobo gloves)"; + else + coal_item_suggestions[$item[Hand in Glove]] += " (have dirty hobo gloves)"; + if (knoll_available() || $item[maiden wig].available_amount() > 0) + coal_item_suggestions[$item[Hairpiece On Fire]] = "+4 adventures, +5 smithness hat, +smithsness MP"; + if (knoll_available() || $item[frilly skirt].available_amount() > 0) + { + coal_item_suggestions[$item[Vicar's Tutu]] = "+5 smithsness pants, +smithsness HP"; + + if (hippy_stone_broken()) + coal_item_suggestions[$item[Vicar's Tutu]] = coal_item_suggestions[$item[Vicar's Tutu]] + ", +3 PVP fights"; + } + + if ($skill[pulverize].skill_is_usable()) + coal_suggestions.listAppend("Smash smithed equipment for more smithereens"); + foreach it in coal_item_suggestions + { + int number_wanted_max = 1; + if (it.to_slot() == $slot[weapon] && it.weapon_hands() == 1) + { + if ($skill[double-fisted skull smashing].skill_is_usable() && it.item_type() != "accordion") + number_wanted_max += 1; + if (familiar_is_usable($familiar[disembodied hand])) + number_wanted_max += 1; + } + + if (it.available_amount() >= number_wanted_max) + continue; + string suggestion = coal_item_suggestions[it]; + coal_suggestions.listAppend(it + ": " + suggestion); + } +} + +void smithsnessGenerateSmithereensSuggestions(string [int] smithereen_suggestions) //suggestereens +{ + smithereen_suggestions.listAppend(7014.to_item().to_string() + ": " + (__misc_state["free runs usable"] ? "free run/" : "") + "banish for 20 turns"); + + if (__misc_state["can eat just about anything"] && availableFullness() >= 2 && my_path().id != PATH_SLOW_AND_STEADY) + { + smithereen_suggestions.listAppend("Charming Flan: 2 fullness epic food
Miserable Pie: 2 fullness awesome food, 50 turns of +10 smithsness"); + } + + if (__misc_state["can drink just about anything"] && availableDrunkenness() >= 2 && my_path().id != PATH_SLOW_AND_STEADY) + { + smithereen_suggestions.listAppend("Vulgar Pitcher: 2 drunkenness epic drink
Bigmouth: 2 drunkenness awesome drink, 50 turns of +10 smithsness"); + } + if (!$familiar[he-boulder].familiar_is_usable()) + { + string line = "Golden Light: Yellow ray"; + if ($effect[everything looks yellow].have_effect() > 0) + line = HTMLGenerateSpanFont(line, "gray"); + smithereen_suggestions.listAppend(line); + } + + if (__misc_state["in run"]) + smithereen_suggestions.listAppend("Handsome Devil: single-turn +100% item"); + +} + +RegisterResourceGenerationFunction("IOTMSmithsnessGenerateResource"); +void IOTMSmithsnessGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (__misc_state["in run"] && $item[handful of smithereens].available_amount() > 0 && in_ronin()) + { + string [int] smithereen_suggestions; + smithsnessGenerateSmithereensSuggestions(smithereen_suggestions); + resource_entries.listAppend(ChecklistEntryMake("__item handful of smithereens", "", ChecklistSubentryMake(pluralise($item[handful of smithereens]), "", smithereen_suggestions.listJoinComponents("
")), 10).ChecklistEntrySetIDTag("Smithsness smithereens suggestions")); + } + if (__misc_state["in run"] && $item[lump of Brituminous coal].available_amount() > 0 && in_ronin()) + { + string [int] coal_suggestions; + smithsnessGenerateCoalSuggestions(coal_suggestions); + resource_entries.listAppend(ChecklistEntryMake("__item lump of Brituminous coal", "", ChecklistSubentryMake(pluralise($item[lump of Brituminous coal]), "", coal_suggestions.listJoinComponents("
")), 10).ChecklistEntrySetIDTag("Smithsness brituminous suggestions")); + } + if ($item[flaskfull of hollow].available_amount() > 0 && $effect[Merry Smithsness].have_effect() < 25 && __misc_state["in run"] && my_path().id != PATH_G_LOVER) + { + int turns_left = $effect[Merry Smithsness].have_effect(); + string [int] details; + details.listAppend(pluralise((turns_left + 150 * $item[flaskfull of hollow].available_amount()), "turn", "turns") + " of +25 smithsness"); + if (turns_left > 0) + details.listAppend("Effect will run out in " + pluralise(turns_left, "turn", "turns")); + resource_entries.listAppend(ChecklistEntryMake("__item flaskfull of hollow", "inventory.php?ftext=flaskfull+of+hollow", ChecklistSubentryMake(pluralise($item[flaskfull of hollow]), "", details), 10).ChecklistEntrySetIDTag("Smithsness flaskfull of hollow")); + } +} + + +void SugarGenerateSuggestions(string [int] suggestions) +{ + if (!__misc_state["in run"]) + return; + if ($item[sugar shield].available_amount() == 0 && $item[snow suit].available_amount() == 0) + suggestions.listAppend("Sugar shield: +10 familiar weight equip"); + if ($item[sugar chapeau].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["past tower monsters"]) + suggestions.listAppend("Sugar chapeau: +50% spell damage (tower killing)"); +} + +RegisterResourceGenerationFunction("IOTMSugarGenerateResource"); +void IOTMSugarGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!$item[sugar sheet].is_unrestricted()) + return; + item [int] sugar_crafted_items; + for i from 4178 to 4183 + { + sugar_crafted_items.listAppend(i.to_item()); + } + ChecklistSubentry [int] subentries; + TagGroup tags; + tags.id = "Sugar sheet folding resource"; + + string image_name = ""; + + if ($item[sugar sheet].available_amount() > 0 && __misc_state["in run"] && in_ronin()) + { + string [int] suggestions; + SugarGenerateSuggestions(suggestions); + subentries.listAppend(ChecklistSubentryMake(pluralise($item[sugar sheet]), "", suggestions)); + + image_name = "sugar sheet"; + } + foreach key in sugar_crafted_items + { + item it = sugar_crafted_items[key]; + if (it.available_amount() == 0) + continue; + int counter = get_property_int("sugarCounter" + it.to_int()); + if (counter == 0 && (!__misc_state["in run"] || !in_ronin())) //in aftercore, probably not as relevant + continue; + int combats_left = 31 - counter; + subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", pluralise(combats_left, "combat", "combats") + " left.")); + if (image_name.length() == 0) + image_name = it; + } + if (subentries.count() > 0) + { + resource_entries.listAppend(ChecklistEntryMake(image_name, "", subentries, 10)); + } +} + + +RegisterResourceGenerationFunction("IOTMTomesGenerateResource"); +void IOTMTomesGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (true) + { + ChecklistSubentry [int] subentries; + + int tome_count = 0; + + string [skill] tome_summons_property_names; + tome_summons_property_names[$skill[Summon Smithsness]] = "_smithsnessSummons"; + tome_summons_property_names[$skill[summon clip art]] = "_clipartSummons"; + tome_summons_property_names[$skill[Summon Sugar Sheets]] = "_sugarSummons"; + tome_summons_property_names[$skill[Summon Snowcones]] = "_snowconeSummons"; + tome_summons_property_names[$skill[Summon Stickers]] = "_stickerSummons"; + tome_summons_property_names[$skill[Summon Rad Libs]] = "_radlibSummons"; + + int [skill] summons_available; + foreach s in tome_summons_property_names + { + string property_name = tome_summons_property_names[s]; + int value = 0; + if (s.skill_is_usable()) + { + if (in_ronin()) + value = 3 - get_property_int("tomeSummons"); + else + value = 3 - get_property_int(property_name); + if (value > 0) + { + tome_count += 1; + } + } + summons_available[s] = value; + } + if (tome_count == 0) + return; + + if (in_ronin()) + { + int summons_remaining = 3 - get_property_int("tomeSummons"); + subentries.listAppend(ChecklistSubentryMake(pluralise(summons_remaining, "tome summon", "tome summons") + " remaining", "", "")); + } + + + if (summons_available[$skill[Summon Smithsness]] > 0) + { + string [int] description; + + string [int] flask_suggestions; + + string [int] smithereen_suggestions; + smithsnessGenerateSmithereensSuggestions(smithereen_suggestions); + + + string [int] coal_suggestions; + smithsnessGenerateCoalSuggestions(coal_suggestions); + + if (true) + { + int merry_smithsness_currently_available = $item[flaskfull of hollow].available_amount() * 150 + $effect[merry smithsness].have_effect(); + string building_line = "+25 smithsness (150 turns)"; + if (merry_smithsness_currently_available > 0) + building_line += " (" + merry_smithsness_currently_available + " turns currently available)"; + flask_suggestions.listAppend(building_line); + + } + + + if (__misc_state["in run"]) + { + description.listAppend("1 Flaskfull of Hollow" + HTMLGenerateIndentedText(flask_suggestions.listJoinComponents("
"))); + description.listAppend("1 Lump of Brituminous coal" + HTMLGenerateIndentedText(coal_suggestions.listJoinComponents("
"))); + description.listAppend("1 Handful of Smithereens" + HTMLGenerateIndentedText(smithereen_suggestions.listJoinComponents("
"))); + } + else + description.listAppend("Flaskfull of Hollow, Lump of Brituminous coal, and Handful of Smithereens"); + + + string name = "The Smith's Tome"; + if (!in_ronin()) + name = pluralise(summons_available[$skill[Summon Smithsness]], name + " summon", name + " summons"); + subentries.listAppend(ChecklistSubentryMake(name, "", description)); + + } + if (summons_available[$skill[summon clip art]] > 0) + { + string [int] description; + if (__misc_state["in run"]) + { + if ($item[shining halo].available_amount() == 0 && __misc_state["need to level"]) + description.listAppend("Shining halo: +3 stats/fight when unarmed"); + if ($item[frosty halo].available_amount() == 0 && $item[a light that never goes out].available_amount() == 0) + description.listAppend("Frosty halo: 25% items when unarmed"); + if ($item[furry halo].available_amount() == 0) + { + string line = "Furry halo: +5 familiar weight when unarmed"; + if (__misc_state["free runs available"]) + line += " (1 free run/day)"; + description.listAppend(line); + } + if ($item[time halo].available_amount() == 0 && my_daycount() <3 ) + description.listAppend("Time halo: +5 adventures/day"); + + if ($item[bucket of wine].available_amount() == 0 && __misc_state["can drink just about anything"]) + { + if ($skill[the ode to booze].skill_is_usable()) + description.listAppend("Bucket of wine: 28 adventures nightcap with ode"); + else if (!get_property_ascension("hiddenTavernUnlock") && $item[ye olde meade].available_amount() == 0) //just use fog murderers or meade instead, about the same + description.listAppend("Bucket of wine: 18 adventures nightcap"); + } + + if (__misc_state["can eat just about anything"] && __misc_state["need to level"]) + description.listAppend("Ultrafondue: 3 fullness awesome food, +15ML for 30 adventures"); + if (true) + { + string line = "Crystal skull: banish in high monster count zones"; + if ($skill[Summon Smithsness].skill_is_usable() && !__misc_state["in aftercore"]) + line += "|*Smith's Tome has a better one"; + description.listAppend(line); + } + if ($item[borrowed time].available_amount() == 0 && !get_property_boolean("_borrowedTimeUsed") && my_daycount() > 1) + description.listAppend("Borrowed time: 20 adventures on last day"); + + string [int] familiar_suggestions; + if (familiar_is_usable($familiar[he-boulder]) && $item[quadroculars].available_amount() == 0 && !lookupSkill("Disintegrate").have_skill()) + familiar_suggestions.listAppend("He-Boulder 100-turn YR"); + if (familiar_is_usable($familiar[obtuse angel]) && !familiar_is_usable($familiar[Reanimated Reanimator])) + familiar_suggestions.listAppend("+1 angel copy"); + + if (familiar_suggestions.count() > 0) + description.listAppend("Box of familiar jacks: free familiar equipment (" + listJoinComponents(familiar_suggestions, ", ") + ")"); + else + description.listAppend("Box of familiar jacks: free familiar equipment"); + } + + string name = "Tome of Clip Art"; + if (!in_ronin()) + name = pluralise(summons_available[$skill[Summon Clip Art]], name + " summon", name + " summons"); + subentries.listAppend(ChecklistSubentryMake(name, "", description)); + } + if (summons_available[$skill[Summon Sugar Sheets]] > 0) + { + string [int] description; + + SugarGenerateSuggestions(description); + + string name = "Tome of Sugar Shummoning"; + if (!in_ronin()) + name = pluralise(summons_available[$skill[Summon Sugar Sheets]], name + " summon", name + " summons"); + subentries.listAppend(ChecklistSubentryMake(name, "", description)); + } + if (summons_available[$skill[Summon Snowcones]] > 0) + { + string [int] description; + //FIXME check this + + string name = "Tome of Snowcone Summoning"; + if (!in_ronin()) + name = pluralise(summons_available[$skill[Summon Snowcones]], name + " summon", name + " summons"); + subentries.listAppend(ChecklistSubentryMake(name, "", description)); + } + if (summons_available[$skill[Summon Stickers]] > 0) + { + string [int] description; + //FIXME check this + + string name = "Scratch 'n' Sniff Sticker Tome"; + if (!in_ronin()) + name = pluralise(summons_available[$skill[Summon Stickers]], name + " summon", name + " summons"); + subentries.listAppend(ChecklistSubentryMake(name, "", description)); + } + if (summons_available[$skill[Summon Rad Libs]] > 0) + { + string [int] description; + + //FIXME check this + + string name = "Tome of Rad Libs"; + if (!in_ronin()) + name = pluralise(summons_available[$skill[Summon Rad Libs]], name + " summon", name + " summons"); + subentries.listAppend(ChecklistSubentryMake(name, "", description)); + } + + + ChecklistEntry entry = ChecklistEntryMake("__item tome of clip art", "campground.php?action=bookshelf", subentries); + entry.tags.id = "Tomes summons resource"; + if (in_ronin()) + entry.should_indent_after_first_subentry = true; + resource_entries.listAppend(entry); + } +} + +RegisterResourceGenerationFunction("ReplicaBookshelfGenerateResource"); +void ReplicaBookshelfGenerateResource(ChecklistEntry [int] resource_entries) +{ + // You need separate handling because replica tome/librams work differently. Instead of summon skills, you use + // the replica item and receive your daily guys. This relies on three boolean entries: + // _replicaSnowconeTomeUsed + // _replicaResolutionLibramUsed + // _replicaSmithsTomeUsed + + ChecklistSubentry [int] subentries; + string name; + string description; + string url; + + if (__iotms_usable[lookupItem("Tome of Snowcone Summoning")]) { + if (!get_property_boolean("_replicaSnowconeTomeUsed")) { + name = "Use your replica Tome of Snowcone Summoning"; + description = "SNOWCONES: Potential potions for +5 familiar weight, 50% meat, or 25% items."; + url = "inventory.php?ftext=snowcone+summoning"; + subentries.listAppend(ChecklistSubentryMake(name,"",description)); + } + } + + if (__iotms_usable[lookupItem("Libram of Resolutions")]) { + if (!get_property_boolean("_replicaResolutionLibramUsed")) { + name = "Use your replica Libram of Resolutions"; + description = "RESOLUTIONS: Potential potions for +5 familiar weight, 50% meat, or 25% items."; + url = "inventory.php?ftext=libram+of+resolutions"; + subentries.listAppend(ChecklistSubentryMake(name,"",description)); + } + } + + if (__iotms_usable[lookupItem("Smith's Tome")]) { + if (!get_property_boolean("_replicaSmithsTomeUsed")) { + name = "Use your replica Smith's Tome"; + description = "SMITH'S: 6x free-run banishes, with 3 equips as well"; + url = "inventory.php?ftext=smith's+tome"; + subentries.listAppend(ChecklistSubentryMake(name,"",description)); + } + } + + if (subentries.count() > 0) { + + ChecklistEntry entry = ChecklistEntryMake("__item smith's tome", url, subentries); + entry.tags.id = "Replica bookshelf resource"; + resource_entries.listAppend(entry); + } +} + +// Time-Twitching Tower +static +{ + string [item] __tea_tree_teas; + void initialiseTeaTreeTeas() + { + __tea_tree_teas[$item[cuppa Activi tea]] = "adventures, stats"; + __tea_tree_teas[$item[cuppa Alacri tea]] = "+50% init"; + __tea_tree_teas[$item[cuppa Boo tea]] = "+30 spooky damage"; + __tea_tree_teas[$item[cuppa Chari tea]] = "+50% meat"; + __tea_tree_teas[$item[cuppa Craft tea]] = "crafting"; + __tea_tree_teas[$item[cuppa Cruel tea]] = "+5 fights for spleen"; + __tea_tree_teas[$item[cuppa Dexteri tea]] = "+50 moxie"; + __tea_tree_teas[$item[cuppa Feroci tea]] = "+50 muscle"; + __tea_tree_teas[$item[cuppa Flamibili tea]] = "+30 hot damage"; + __tea_tree_teas[$item[cuppa Flexibili tea]] = "+3 moxie stats/fight"; + __tea_tree_teas[$item[cuppa Frost tea]] = "+3 hot res"; + __tea_tree_teas[$item[cuppa Gill tea]] = "fishy"; + __tea_tree_teas[$item[cuppa Impregnabili tea]] = "30 DR"; + __tea_tree_teas[$item[cuppa Improprie tea]] = "+30 sleaze damage"; + __tea_tree_teas[$item[cuppa Insani tea]] = "+3 OCRS modifiers, teleporting(?)"; + __tea_tree_teas[$item[cuppa Irritabili tea]] = "+combat"; + __tea_tree_teas[$item[cuppa Loyal tea]] = "+5 familiar weight"; + __tea_tree_teas[$item[cuppa Mana tea]] = "+30 max MP, ~4 MP regen"; + __tea_tree_teas[$item[cuppa Mediocri tea]] = "+30 ML"; + __tea_tree_teas[$item[cuppa Monstrosi tea]] = "-30 ML"; + __tea_tree_teas[$item[cuppa Morbidi tea]] = "+3 spooky res"; + __tea_tree_teas[$item[cuppa Nas tea]] = "+30 stench damage"; + __tea_tree_teas[$item[cuppa Net tea]] = "+3 stench res"; + __tea_tree_teas[$item[cuppa Neuroplastici tea]] = "+3 myst stat/fight"; + __tea_tree_teas[$item[cuppa Obscuri tea]] = "-combat"; + __tea_tree_teas[$item[cuppa Physicali tea]] = "+3 muscle stats/fight"; + __tea_tree_teas[$item[cuppa Proprie tea]] = "+3 sleaze res"; + __tea_tree_teas[$item[cuppa Royal tea]] = "+1 royalty"; + __tea_tree_teas[$item[cuppa Serendipi Tea]] = "+25% item"; + __tea_tree_teas[$item[cuppa Sobrie tea]] = "-1 drunkenness"; + __tea_tree_teas[$item[cuppa Toast tea]] = "+3 cold res"; + __tea_tree_teas[$item[cuppa Twen tea]] = "+20 various stats"; + __tea_tree_teas[$item[cuppa Uncertain tea]] = "random effect"; + __tea_tree_teas[$item[cuppa Vitali tea]] = "+30 max HP, ~4 HP regen"; + __tea_tree_teas[$item[Cuppa Voraci tea]] = "+1 stomach capacity today"; + __tea_tree_teas[$item[cuppa Wit tea]] = "+50 myst"; + __tea_tree_teas[$item[cuppa Yet tea]] = "+30 cold damage"; + } + initialiseTeaTreeTeas(); +} + +RegisterResourceGenerationFunction("IOTMTeaTreeGenerateResource"); +void IOTMTeaTreeGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!get_property_boolean("_pottedTeaTreeUsed") && __iotms_usable[$item[potted tea tree]]) + { + string [int] options; + //+50% Combat Initiative? + + string [int][int] tea_options; + + + if (__misc_state["in run"]) + { + tea_options.listAppend(listMake("Irritabili", "+combat (30 turns)")); + tea_options.listAppend(listMake("Obscuri", "-combat (30 turns)")); + tea_options.listAppend(listMake("Serendipi", "+25% item (30 turns)")); + tea_options.listAppend(listMake("Chari", "+50% meat (30 turns)")); + tea_options.listAppend(listMake("Mediocri", "+30 ML")); + if (!__misc_state["familiars temporarily blocked"]) + tea_options.listAppend(listMake("Loyal", "+5 familiar weight")); + tea_options.listAppend(listMake("Craft", "Free crafts")); + if (hippy_stone_broken()) + tea_options.listAppend(listMake("Cruel", "+5 PVP fights, spleen")); + } + if (inebriety_limit() > 0) + tea_options.listAppend(listMake("Sobrie", "-1 drunkenness")); + if (fullness_limit() > 0) + tea_options.listAppend(listMake("Voraci", "+1 fullness capacity today")); + + if (!__misc_state["in run"]) + { + tea_options.listAppend(listMake("Royal", "Mall selling, royal leaderboarding")); + tea_options.listAppend(listMake("Gill", "Fishy (30 turns)")); + } + if (!__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && __quest_state["Level 13"].state_string["Elemental damage race type"] != "") + { + // + element type = __quest_state["Level 13"].state_string["Elemental damage race type"].to_element(); + item [element] element_tea_map; + element_tea_map[$element[sleaze]] = $item[cuppa Improprie Tea]; + element_tea_map[$element[spooky]] = $item[cuppa Boo tea]; + element_tea_map[$element[hot]] = $item[cuppa Flamibili tea]; + element_tea_map[$element[stench]] = $item[cuppa Nas tea]; + element_tea_map[$element[cold]] = $item[cuppa Yet tea]; + + item tea = element_tea_map[type]; + string type_class = "r_element_" + type + "_desaturated"; + if (tea != $item[none] && tea.available_amount() == 0) + tea_options.listAppend(listMake(tea.replace_string(" tea", "").replace_string("cuppa ", "").capitaliseFirstLetter(), HTMLGenerateSpanOfClass(__tea_tree_teas[tea], type_class) + " for lair race.")); + } + + if (tea_options.count() > 0) + options.listAppend(HTMLGenerateSimpleTableLines(tea_options)); + resource_entries.listAppend(ChecklistEntryMake("__item potted tea tree", "campground.php?action=teatree", ChecklistSubentryMake("Tea Tree Tea", "", options), 4).ChecklistEntrySetIDTag("Tea tree daily resource")); + } + + if (__misc_state["in run"] && in_ronin()) + { + string image_name = ""; + string url = ""; + string [int] teas_found; + string [int] reasons_found; + boolean one_tea_gives_effect = false; + foreach tea, treason in __tea_tree_teas + { + if (tea.available_amount() == 0) + continue; + string shortened_tea_name = tea.replace_string("cuppa ", "").replace_string(" tea", ""); + teas_found.listAppend(pluralise(tea.available_amount(), shortened_tea_name, shortened_tea_name)); + + reasons_found.listAppend(treason); + if (image_name == "") + image_name = "__item " + tea; + if (!one_tea_gives_effect && tea.to_effect() != $effect[none]) + one_tea_gives_effect = true; + if (tea.spleen > 0) + { + if (url == "") + url = "inventory.php?which=1"; + } + else + url = "inventory.php?which=3"; + } + if (teas_found.count() > 0) + { + resource_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(teas_found.listJoinComponents(", ", "and").capitaliseFirstLetter() + " tea", "", reasons_found.listJoinComponents(", ", "and").capitaliseFirstLetter() + (one_tea_gives_effect ? " (30 turns)" : "")), 8).ChecklistEntrySetIDTag("Tea tree cuppas resource")); + } + } +} + +// 2009 + +// 2010 +Record COTSuggestion +{ + string reason; + familiar [int] familiars; +}; + + +COTSuggestion COTSuggestionMake(string reason, familiar [int] familiars) +{ + COTSuggestion suggestion; + suggestion.reason = reason; + suggestion.familiars = familiars; + + return suggestion; +} + +COTSuggestion COTSuggestionMake(string reason, familiar f) +{ + familiar [int] familiar_list; + familiar_list.listAppend(f); + return COTSuggestionMake(reason, familiar_list); +} + +COTSuggestion COTSuggestionMake(string reason, boolean [familiar] familiars_in) +{ + familiar [int] familiars_out; + foreach f in familiars_in + familiars_out.listAppend(f); + return COTSuggestionMake(reason, familiars_out); +} + +void listAppend(COTSuggestion [int] list, COTSuggestion entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + + +//Follows in order. If we can't find one in the first set, we check the second, then third, etc. +//This allows for supporting +25% meat, then falling back on +20%, etc. +Record COTSuggestionSet +{ + COTSuggestion [int] suggestions; +}; + +COTSuggestionSet COTSuggestionSetMake(COTSuggestion [int] suggestions) +{ + COTSuggestionSet suggestion_set; + suggestion_set.suggestions = suggestions; + + return suggestion_set; +} + +COTSuggestionSet COTSuggestionSetMake(COTSuggestion suggestion) +{ + COTSuggestionSet suggestion_set; + suggestion_set.suggestions.listAppend(suggestion); + + return suggestion_set; +} + +void listAppend(COTSuggestionSet [int] list, COTSuggestionSet entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + + +void IOTMCOTGenerateSuggestions(string [int] description) +{ + familiar enthroned_familiar = my_enthroned_familiar(); + familiar bjorned_familiar = my_bjorned_familiar(); + //Suggest what it offers: + COTSuggestionSet [int] suggestion_sets; + + boolean have_two_available = false; + if ($item[crown of thrones].available_amount() > 0 && $item[Buddy Bjorn].available_amount() > 0) + have_two_available = true; + + //Relevant: + //+10ML + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+10 ML and +MP regen", $familiar[el vibrato megadrone]))); + //+15% item drops, or +10% + if (true) { + COTSuggestion [int] suggestions; + suggestions.listAppend(COTSuggestionMake("+15% items", $familiars[li'l xenomorph, feral kobold])); + suggestions.listAppend(COTSuggestionMake("+10% items", $familiars[Reassembled Blackbird,Reconstituted Crow,Oily Woim])); + suggestion_sets.listAppend(COTSuggestionSetMake(suggestions)); + } + //+2 moxie/muscle/mysticality stats/fight + if (__misc_state["need to level"]) { + if (my_primestat() == $stat[moxie]) { + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+2 mainstat/fight", $familiars[blood-faced volleyball,jill-o-lantern, nervous tick,mariachi chihuahua, cymbal-playing monkey,hovering skull]))); + } else if (my_primestat() == $stat[mysticality]) { + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+2 mainstat/fight", $familiars[reanimated reanimator,dramatic hedgehog,cheshire bat,pygmy bugbear shaman,hovering sombrero,sugar fruit fairy, uniclops]))); + } else if (my_primestat() == $stat[muscle]) { + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+2 mainstat/fight", $familiars[hunchbacked minion, killer bee, grinning turtle,chauvinist pig, baby mutant rattlesnake]))); + } + } + //+25% / +20% meat from monsters + if (true) { + COTSuggestion [int] suggestions; + suggestions.listAppend(COTSuggestionMake("+25% meat", $familiars[Knob Goblin Organ Grinder,Happy Medium,Hobo Monkey])); + suggestions.listAppend(COTSuggestionMake("+20% meat", $familiars[Dancing Frog,Psychedelic Bear,Hippo Ballerina,Attention-Deficit Demon,Piano Cat,Coffee Pixie,Obtuse Angel,Hand Turkey,Leprechaun,Grouper Groupie,Mutant Cactus Bud,Jitterbug,Casagnova Gnome])); + suggestion_sets.listAppend(COTSuggestionSetMake(suggestions)); + } + //+5 to familiar weight + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+5 familiar weight", $familiars[Gelatinous Cubeling,Pair of Ragged Claws,Spooky Pirate Skeleton,Autonomous Disco Ball,Ghost Pickle on a Stick,Misshapen Animal Skeleton,Animated Macaroni Duck,Penguin Goodfella,Barrrnacle]))); + //+20% to combat init + if (__misc_state["in run"]) + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+20% init", $familiars[Teddy Bear,Emo Squid,Evil Teddy Bear,Syncopated Turtle,Untamed Turtle,Mini-Skulldozer,Cotton Candy Carnie,Origami Towel Crane,Feather Boa Constrictor,Levitating Potato,Temporal Riftlet,Squamous Gibberer,Cuddlefish,Teddy Borg]))); + //+15% to moxie/muscle/mysticality + if (__misc_state["in run"]) { + if (true) { + //Either scaling monster levelling, or the NS + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+15% moxie", $familiars[Ninja Snowflake,Nosy Nose,Clockwork Grapefruit,Sabre-Toothed Lime]))); + } + if (my_primestat() == $stat[mysticality] && __misc_state["need to level"]) { + //Scaling monster levelling + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+15% mysticality", $familiars[Ragamuffin Imp,Inflatable Dodecapede,Scary Death Orb,Snowy Owl,grue]))); + } else if (my_primestat() == $stat[muscle] && __misc_state["need to level"]) { + //Scaling monster levelling + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+15% muscle", $familiars[MagiMechTech MicroMechaMech,Angry Goat,Wereturtle,Stab Bat,Wind-up Chattering Teeth,Imitation Crab]))); + } + } + //+20%/+15%/+10% to spell damage + //Too marginal? + /*if (__misc_state["in run"]) { + COTSuggestion [int] suggestions; + suggestions.listAppend(COTSuggestionMake("+20% spell damage", $familiar[mechanical songbird])); + suggestions.listAppend(COTSuggestionMake("+15% spell damage", $familiars[Magic Dragonfish,Pet Cheezling,Rock Lobster])); + suggestions.listAppend(COTSuggestionMake("+10% spell damage", $familiars[Midget Clownfish,Star Starfish,Baby Yeti,Snow Angel,Wizard Action Figure,Dataspider,Underworld Bonsai,Whirling Maple Leaf,Rogue Program,Howling Balloon Monkey])); + suggestion_sets.listAppend(COTSuggestionSetMake(suggestions)); + }*/ + //hot wings from reanimator + if (true) { + string [int] reanimator_reasons; + + if (__quest_state["Pirate Quest"].state_boolean["need more hot wings"]) + reanimator_reasons.listAppend("hot wings"); + + if (reanimator_reasons.count() > 0) + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake(reanimator_reasons.listJoinComponents(", ").capitaliseFirstLetter(), $familiar[reanimated reanimator]))); + } + if (__misc_state["in run"]) + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("50% block", $familiar[Mariachi Chihuahua]))); + + //knob mushrooms from badger + if (__misc_state["in run"] && __misc_state["can eat just about anything"]) + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("Knob mushrooms", $familiar[astral badger]))); + + boolean need_cold_res = false; + boolean need_all_res = false; + //At a-boo peak, but not finished with it: + if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0 && __quest_state["Level 9"].state_boolean["bridge complete"]) + need_all_res = true; + //Climbing the peak: + if (__quest_state["Level 8"].state_boolean["Past mine"] && !__quest_state["Level 8"].state_boolean["Groar defeated"] && numeric_modifier("cold resistance") < 5.0) + need_cold_res = true; + + if (__misc_state["in run"] && need_cold_res) + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+3 cold res", $familiar[Flaming Face]))); + if (need_cold_res && !$familiar[flaming face].have_familiar_replacement()) + need_all_res = true; + if (__misc_state["in run"] && need_all_res) + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+2 all res", $familiars[Bulky Buddy Box,Exotic Parrot,Holiday Log,Pet Rock,Toothsome Rock]))); + + //if (__misc_state["in run"] && availableSpleen() >= 4) + //suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("Spleen items", $familiar[Grim Brother]))); + + //slightly powerful: + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("+combat", $familiar[Grim Brother]))); + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("-combat", $familiar[Grimstone Golem]))); + + if (get_property_int("_grimstoneMaskDropsCrown") == 0) + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("Grimstone mask", $familiar[Grimstone Golem]))); + if (get_property_int("_grimFairyTaleDropsCrown") < 2 && !(__misc_state["in run"] && spleen_limit() == 0)) + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake(pluraliseWordy(clampi(2 - get_property_int("_grimFairyTaleDropsCrown"), 0, 2), "spleen item", "spleen items").capitaliseFirstLetter(), $familiar[grim Brother]))); + + if ($item[blackberry].available_amount() < 3 && $item[blackberry galoshes].available_amount() == 0 && __quest_state["Level 11"].mafia_internal_step < 2) + suggestion_sets.listAppend(COTSuggestionSetMake(COTSuggestionMake("Blackberries for galoshes", $familiars[reassembled blackbird,reconstituted crow]))); + string [int][int] familiar_options; + foreach key in suggestion_sets { + boolean found_relevant = false; + COTSuggestionSet suggestion_set = suggestion_sets[key]; + foreach key2 in suggestion_set.suggestions { + //Suggest the familiar with the highest weight, under the assumption they're using it more. + COTSuggestion suggestion = suggestion_set.suggestions[key2]; + familiar best_familiar_by_weight = $familiar[none]; + familiar second_best_familiar_by_weight = $familiar[none]; + foreach key3 in suggestion.familiars { + familiar f = suggestion.familiars[key3]; + if (f == $familiar[none]) //didn't find it + continue; + if (f.have_familiar_replacement()) { + if ((best_familiar_by_weight != enthroned_familiar || enthroned_familiar == $familiar[none]) && (best_familiar_by_weight == $familiar[none] || f.familiar_weight() > best_familiar_by_weight.familiar_weight() || f == enthroned_familiar)) { + second_best_familiar_by_weight = best_familiar_by_weight; + best_familiar_by_weight = f; + } else if (second_best_familiar_by_weight == $familiar[none] || f.familiar_weight() > second_best_familiar_by_weight.familiar_weight()) { + if (best_familiar_by_weight != f) + second_best_familiar_by_weight = f; + } + } + } + if (best_familiar_by_weight != $familiar[none]) { + string familiar_string; + + familiar_string = best_familiar_by_weight; + if ((enthroned_familiar == best_familiar_by_weight && enthroned_familiar != $familiar[none]) || (bjorned_familiar == best_familiar_by_weight && bjorned_familiar != $familiar[none])) + familiar_string = HTMLGenerateSpanOfClass(best_familiar_by_weight, "r_bold"); + + if (second_best_familiar_by_weight != $familiar[none] && have_two_available) + familiar_string += "|" + second_best_familiar_by_weight; + familiar_options.listAppend(listMake(suggestion.reason, familiar_string)); + break; + } + } + } + if (familiar_options.count() > 0) + description.listAppend(HTMLGenerateSimpleTableLines(familiar_options)); +} + +RegisterResourceGenerationFunction("IOTMCOTGenerateResource"); +void IOTMCOTGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[crown of thrones].available_amount() == 0 && $item[Buddy Bjorn].available_amount() == 0) + return; + if (__misc_state["familiars temporarily blocked"]) //avatar paths + return; + string [int] description; + + void addFamiliarDropsLine(string fam, string prop, int limit, string dropdesc) { + int currentDrops = get_property_int(prop); + familiar thisFam = fam.to_familiar(); + if ( !thisFam.have_familiar() ) { return; } + string txtclr = ""; + if ( fam.index_of("Stomping") > -1 ) { + txtclr = (get_property_boolean("bootsCharged"))?"blue":"black"; + } + if ( currentDrops == limit ) { txtclr = "gray"; } + + description.listAppend(HTMLGenerateSpanFont(fam+": "+currentDrops + "/"+limit+" "+dropdesc+".", txtclr)); + return; + } + + description.listAppend(HTMLGenerateSpanFont("Crown/Bjorn-specific drops", "purple")); + addFamiliarDropsLine("Garbage Fire", "_garbageFireDropsCrown", 3, "burning newspapers"); + addFamiliarDropsLine("Grim Brother", "_grimFairyTaleDropsCrown", 2, "grim fairy tales"); + addFamiliarDropsLine("Grimstone Golem", "_grimstoneMaskDropsCrown", 1, "grimstone mask"); + addFamiliarDropsLine("Machine Elf", "_abstractionDropsCrown", 25, "abstractions"); + addFamiliarDropsLine("Optimistic Candle", "_optimisticCandleDropsCrown", 3, "globs of melted wax"); + addFamiliarDropsLine("Ms. Puck Man", "_yellowPixelDropsCrown", 25, "yellow pixels"); + addFamiliarDropsLine("Puck Man", "_yellowPixelDropsCrown", 25, "yellow pixels"); + addFamiliarDropsLine("Trick-or-Treating Tot", "_hoardedCandyDropsCrown", 3, "hoarded candy wads"); + + description.listAppend(HTMLGenerateSpanFont("General familiar drops", "purple")); + addFamiliarDropsLine("Adventurous Spelunker", "_spelunkingTalesDrops", 1, "Tales of Spelunking"); + addFamiliarDropsLine("Astral Badger", "_astralDrops", 5, "astral mushrooms"); + addFamiliarDropsLine("Baby Sandworm", "_aguaDrops", 5, "Agua de Vidae"); + addFamiliarDropsLine("Blavious Kloop", "_kloopDrops", 5, "devlish folios"); + addFamiliarDropsLine("Bloovian Groose", "_grooseDrops", 5, "groose grease"); + addFamiliarDropsLine("Cat Burglar", "_catBurglarCharge", 30, "Heist charges"); + #addFamiliarDropsLine("Cookbookbat", "_turkeyBooze", 5, "Turkey booze"); + addFamiliarDropsLine("Fist Turkey", "_turkeyBooze", 5, "Turkey booze"); + addFamiliarDropsLine("Galloping Grill", "_hotAshesDrops", 5, "hot ashes"); + addFamiliarDropsLine("Golden Monkey", "_powderedGoldDrops", 5, "powdered gold"); + addFamiliarDropsLine("Green Pixie", "_absintheDrops", 5, "bottles of absinthe"); + addFamiliarDropsLine("Grim Brother", "_grimFairyTaleDrops", 5, "grim fairy tales"); + addFamiliarDropsLine("Li'l Xenomorph", "_transponderDrops", 5, "transponders"); + addFamiliarDropsLine("Llama Lama", "_gongDrops", 5, "Llama gongs"); + addFamiliarDropsLine("Puck Man", "_powerPillDrops", 11, "power pills"); + addFamiliarDropsLine("Ms. Puck Man", "_powerPillDrops", 11, "power pills"); + addFamiliarDropsLine("Rogue Program", "_tokenDrops", 5, "GG tokens"); + addFamiliarDropsLine("Stomping Boots", "_pasteDrops", 7, "spleen pastes"); + addFamiliarDropsLine("Unconscious Collective", "_dreamJarDrops", 5, "dream jars"); + item crown_item = $item[crown of thrones]; + if (crown_item.equipped_amount() == 0 && $item[Buddy Bjorn].available_amount() > 0) + crown_item = $item[Buddy Bjorn]; + + string image_name = "__item " + crown_item; + familiar enthroned_familiar = my_enthroned_familiar(); + familiar bjorned_familiar = my_bjorned_familiar(); + + if (($item[crown of thrones].equipped_amount() > 0 || $item[Buddy Bjorn].equipped_amount() > 0) || __misc_state["in run"]) { + IOTMCOTGenerateSuggestions(description); + } + + if (enthroned_familiar != $familiar[none]) { + description.listAppend(enthroned_familiar + " enthroned."); + //image_name = "__familiar " + enthroned_familiar.to_string(); + } + if (bjorned_familiar != $familiar[none]) + description.listAppend(bjorned_familiar + " bjorned."); + //FIXME my_bjorned_familiar() when 16.3 + + string url = "familiar.php"; + if ($item[crown of thrones].equipped_amount() == 0 && $item[Buddy Bjorn].equipped_amount() == 0) + url = "inventory.php?which=2"; + + string header = crown_item; + item [int] available_sources; + + if ($item[Buddy Bjorn].available_amount() > 0) + available_sources.listAppend($item[Buddy Bjorn]); + if ($item[crown of thrones].available_amount() > 0) + available_sources.listAppend($item[crown of thrones]); + if (available_sources.count() > 0) + header = available_sources.listJoinComponents(", ", "and"); + + if (description.count() > 0) + resource_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(header, "", description), 8).ChecklistEntrySetIDTag("Crown of Bjorn/Buddy thrones resource")); +} + +// 2011 +RegisterResourceGenerationFunction("IOTMPlasticVampireFangsGenerateResource"); +void IOTMPlasticVampireFangsGenerateResource(ChecklistEntry [int] resource_entries) +{ + // Commenting out since the replica is unrestricted. I think ownership handles this. + + // if (!$item[plastic vampire fangs].is_unrestricted()) + // return; + if ($items[replica plastic vampire fangs, plastic vampire fangs, Interview With You (a Vampire)].available_amount() == 0) + return; + item fang_source = $item[plastic vampire fangs]; + string url = ""; + string separator = " " + __html_right_arrow_character + " "; + + // Detect if your access is through the replica, the book, or the O.G. + + if ($item[replica plastic vampire fangs].available_amount() > 0) { + fang_source = $item[replica plastic vampire fangs]; + url = "place.php?whichplace=town"; + if ($item[plastic vampire fangs].equipped_amount() == 0) { + url = "inventory.php?ftext=plastic+vampire+fangs"; + } + } + + else if ($item[Interview With You (a Vampire)].available_amount() > 0) { + fang_source = $item[Interview With You (a Vampire)]; + url = "inventory.php?ftext=interview+with+you"; + } + + else { + url = "place.php?whichplace=town"; + if ($item[plastic vampire fangs].equipped_amount() == 0) { + url = "inventory.php?ftext=plastic+vampire+fangs"; + } + } + + // Show the Isabella interview option if it is valid for the user. + + if (!get_property_boolean("_interviewIsabella") && __misc_state["in run"] && __misc_state["need to level"]) { + string [int] description; + int stats_gained = MIN(500, 4 * my_basestat(my_primestat())) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); + + description.listAppend(stats_gained + " " + my_primestat().to_lower_case() + " gained, one adventure cost."); + if ($item[Interview With You (a Vampire)].available_amount() > 0) { + description.listAppend("Vamp out via Interview With You (a Vampire)."); + } + else { + description.listAppend("Vamp out in Seaside Town, with fangs equipped."); + } + + if (my_primestat() == $stat[muscle]) + description.listAppend("Visit Isabella's" + separator + "Drain Her."); + else if (my_primestat() == $stat[mysticality]) + description.listAppend("Visit Isabella's" + separator + "Tell Her How You Feel" + separator + "Find Other Prey."); + else if (my_primestat() == $stat[moxie]) + description.listAppend("Visit Isabella's" + separator + "Redirect Your Desire" + separator + "Go to the Bar."); + + + resource_entries.listAppend(ChecklistEntryMake("__item " + fang_source, url, ChecklistSubentryMake("Vampire stats", "", description), 5).ChecklistEntrySetIDTag("Plastic vampire fangs Isabella interview")); + + } + + if (!__misc_state["in run"]) { + string [int] description; + if ($item[Interview With You (a Vampire)].available_amount() > 0) { + description.listAppend("Vamp out via Interview With You (a Vampire)."); + } + else { + description.listAppend("Vamp out in Seaside Town, with fangs equipped."); + } + + int vamp_outs_remaining = 0; + + //Disabled, unless there's something useful about these to be reminded of in aftercore: + /*if (!get_property_boolean("_interviewVlad")) { + description.listAppend("Vlad's Boutique - DR or spell damage or weapon damage buff."); + vamp_outs_remaining += 1; + } + if (!get_property_boolean("_interviewIsabella")) { + description.listAppend("Isabella's - mainstat gain, meat."); + vamp_outs_remaining += 1; + }*/ + if (!get_property_boolean("_interviewMasquerade")) { + string [int] masquerade_description; + if ($item[Sword of the Brouhaha Prince].available_amount() == 0) { + string [int] interview_questions = listMake("Warehouse", "Growl", "The Clash", "Motorcycle", "Lager"); + string [int] nomination = listMake("Malkovich", "Torremolinos", "Brouhaha", "Ventrilo"); + string item_name = "Sword of the Brouhaha Prince"; + masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); + } + if ($item[Chalice of the Malkovich Prince].available_amount() == 0) { + string [int] interview_questions = listMake("Laugh Factory", "Giggle", "Glass breaking", "Wheelbarrow", "Blood"); + string [int] nomination = listMake("Torremolinos", "Ventrilo", "Brouhaha", "Malkovich"); + string item_name = "Chalice of the Malkovich Prince"; + + masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); + } + if ($item[Sceptre of the Torremolinos Prince].available_amount() == 0) { + string [int] interview_questions = listMake("Loft", "Flirty", "Mozart", "Carriage", "Absinthe"); + string [int] nomination = listMake("Malkovich", "Ventrilo", "Torremolinos", "Brouhaha"); + string item_name = "Sceptre of the Torremolinos Prince"; + masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); + } + if ($item[Medallion of the Ventrilo Prince].available_amount() == 0) { + string [int] interview_questions = listMake("Penthouse", "Terse", "No time", "Limo", "Espresso"); + string [int] nomination = listMake("Ventrilo", "Malkovich", "Brouhaha", "Torremolinos"); + string item_name = "Medallion of the Ventrilo Prince"; + masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); + } + if (true) { + string [int] interview_questions = listMake("Warehouse", "Growl", "The Clash", "Motorcycle", "Lager"); + string [int] nomination = listMake("Ventrilo", "Brouhaha", "Torremolinos", "Malkovich"); + string item_name = "Your own black heart (restores 100% HP/MP)"; + masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); + } + if ($item[plastic vampire fangs].available_amount() > 0) { + string [int] interview_questions = listMake("Warehouse", "Growl", "The Clash", "Motorcycle", "Lager"); + string [int] nomination = listMake("Ventrilo", "Malkovich", "Torremolinos", "Brouhaha"); + string item_name = "Interview With You (a Vampire)"; + masquerade_description.listAppend(item_name + "|*Interview: " + interview_questions.listJoinComponents(separator) + "
|*Nomination order: " + nomination.listJoinComponents(separator)); + } + //description.listAppend("The Masquerade." + HTMLGenerateIndentedText(masquerade_description)); + description.listAppendList(masquerade_description); + vamp_outs_remaining += 1; + } + + if (vamp_outs_remaining > 0) { + //resource_entries.listAppend(ChecklistEntryMake("__item " + fang_source, url, ChecklistSubentryMake(pluralise(vamp_outs_remaining, "vamp out", "vamp outs"), "", description), 8)); + resource_entries.listAppend(ChecklistEntryMake("__item " + fang_source, url, ChecklistSubentryMake("Vampire masquerade", "", description), 8).ChecklistEntrySetIDTag("Plastic vampire fangs vamp out resource")); + } + } +} + +// 2013 + + +void IOTMPShadyPastGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + string [int] description; + string [int] modifiers; + + if ($item[White Dragon Fang].available_amount() == 0) + { + boolean can_acquire_taijijian = ($item[strange goggles].available_amount() > 0 || $item[toy taijijian].available_amount() > 0 || !in_ronin()); + if ($item[magical battery].available_amount() > 0 && can_acquire_taijijian) + { + description.listAppend("To make the White Dragon Fang, meatpaste together the toy taijijian with the magical battery."); + } + } + + string last_combat = $location[chinatown tenement].lastCombatInLocation(); + if ($location[chinatown tenement].combat_queue.contains_text("White Bone Demon") && description.count() == 0) //somewhat limited way of detecting that we are finished + return; + if ($item[Test site key].available_amount() > 0) + { + //Last segment: + + int gold_pieces_needed = MAX(0, 30 - $item[gold piece].available_amount()); + if (last_combat == "the server") + { + description.listAppend("Fight the White Bone Demon."); + } + else if (gold_pieces_needed > 0) + { + //at least one gold piece from a desperate gold farmer is under 21.89% drop rate + //needs spading + description.listAppend("Adventure in the chinatown tenement, acquire " + pluralise(gold_pieces_needed, "more gold piece", "more gold pieces") + "."); + modifiers.listAppend("+400%? item"); + + if (__misc_state["have olfaction equivalent"]) + modifiers.listAppend("olfact desperate gold farmer"); + } + else + { + description.listAppend("Adventure in the chinatown tenement, fight the server.|Once the server's panel falls off, use the strange goggles."); + } + } + else if ($item[CEO office card].available_amount() > 0) + { + //Use to see wheels within wheels. + description.listAppend("Use CEO office card."); + } + else if ($items[makeshift yakuza mask,Novelty tattoo sleeves].items_missing().count() == 0) + { + //Visit the first floor. + item [int] equip_items; + foreach it in $items[makeshift yakuza mask,novelty tattoo sleeves] + { + if (it.equipped_amount() == 0) + equip_items.listAppend(it); + } + if (equip_items.count() > 0 && $location[1st floor\, shiawase-mitsuhama building].turnsAttemptedInLocation() == 0) + { + description.listAppend("Equip " + equip_items.listJoinComponents(", ", "and") + "."); + } + else + { + description.listAppend("Adventure on the floors of the Shiawase-Mitsuhama building, acquire and use cards."); + + foreach it in $items[zaibatsu level 2 card, zaibatsu level 3 card] + { + if (it.available_amount() == 0) + continue; + description.listAppend("Use " + it + "."); + } + } + } + else if ($item[strange goggles].available_amount() > 0) + { + //Make yakuza mask. + if ($item[makeshift yakuza mask].available_amount() == 0) + { + string line = "Assemble a makeshift yakuza mask with items from the chinatown shops."; + + item [int] missing_parts_list = missingComponentsToMakeItem($item[makeshift yakuza mask]); + if (missing_parts_list.count() == 0) + line = "Assemble a makeshift yakuza mask.|(rhinoceros horn + rhinoceros horn) + (furry pink pillow + bottle of limeade)"; + else + line += "|Missing " + missing_parts_list.listJoinComponents(", ", "and") + "."; + + description.listAppend(line); + } + if ($item[Novelty tattoo sleeves].available_amount() == 0) + { + description.listAppend("Buy novelty tattoo sleeves from the chinatown shops."); + } + } + else if ($item[zaibatsu lobby card].available_amount() > 0) + { + //Triad factory. + description.listAppend("Adventure in the sewer triad factory, defeat the Sierpinski brothers."); + description.listAppend("Run +item for a possible magical battery."); + modifiers.listAppend("+item"); + } + else + { + //Start of quest. + description.listAppend("Adventure in the Chinatown shops, defeat a yakuza courier."); + } + + + optional_task_entries.listAppend(ChecklistEntryMake("chinatown", "place.php?whichplace=junggate_1", ChecklistSubentryMake("The Suspicious-Looking Guy's Shady Past", modifiers, description),$locations[chinatown shops, chinatown tenement, triad factory,1st floor\, shiawase-mitsuhama building,2nd floor\, shiawase-mitsuhama building,3rd floor\, shiawase-mitsuhama building]).ChecklistEntrySetIDTag("Psychoanalytic jar suspicious-looking guy")); +} + +void IOTMPOldManGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + string [int] description; + string [int] modifiers; + + if ($location[The Old Man's Bathtime Adventures].lastNoncombatInLocation() == "Journey's End") //somewhat limited way of detecting that we are finished + return; + + description.listAppend("Sail the seas. Try to one-hit kill the sea monsters."); + + if ($item[Bloodbath].available_amount() == 0) + description.listAppend("Need to finish the area with 50+ crew to acquire Bloodbath."); + else if ($item[ornamental sextant].available_amount() == 0) + description.listAppend("Need to finish the area with 37+ crew to acquire ornamental sextant."); + else if ($item[miniature deck cannon].available_amount() == 0) + description.listAppend("Need to finish the area with [24 to 36] crew to acquire miniature deck cannon."); + else if ($item[Foam naval trousers].available_amount() == 0) + description.listAppend("Need to finish the area with [24 to 36] crew to acquire Foam naval trousers."); + else if ($item[Foam commodore's hat].available_amount() == 0) + description.listAppend("Need to finish the area with [24 to 36] crew to acquire Foam commodore's hat."); + + description.listAppend("Choose +crew non-combat options, add monsters if you can."); + + + monster olfacted_monster = get_property_monster("olfactedMonster"); + + boolean olfacted_relevant_monster = ($monsters[ferocious roc,giant man-eating shark,Bristled Man-O-War,The Cray-Kin,Deadly Hydra] contains olfacted_monster); + + if (__misc_state["have olfaction equivalent"] && !olfacted_relevant_monster) + { + description.listAppend("Olfact any monster that is not a fearsome giant squid."); + modifiers.listAppend("olfaction"); + } + + if (my_basestat($stat[mysticality]) >= 200) + { + if ($item[Mesmereyes™ contact lenses].equipped_amount() == 0) + { + description.listAppend("Wear " + $item[Mesmereyes™ contact lenses] + "."); + } + } + else + { + if ($item[Attorney's badge].equipped_amount() == 0) + { + description.listAppend("Wear " + $item[Attorney's badge] + "."); + } + description.listAppend("Possibly level mysticality to 200 to wear " + $item[Mesmereyes™ contact lenses] + ", makes this area much easier."); + } + + if ($item[Young Man's Crew Sequester].available_amount() > 0) + description.listAppend("Young Man's Crew Sequester available. (+5 crew)"); + if ($item[Young Man's Cargo Load].available_amount() > 0) + description.listAppend("Young Man's Cargo Load available. (+4 crayons, +16 bubbles)"); + + //very limited potato detection: + if (my_familiar() != $familiar[levitating potato] && !(my_familiar() == $familiar[fancypants scarecrow] && ($slot[familiar].equipped_item() == $item[swashbuckling pants] || $slot[familiar].equipped_item() == $item[spangly mariachi pants])) && !(my_familiar() == $familiar[mad hatrack] && $slot[familiar].equipped_item() == $item[spangly sombrero])) + description.listAppend("Run a potato familiar of some kind."); + + + optional_task_entries.listAppend(ChecklistEntryMake("__item inflatable duck", "", ChecklistSubentryMake("The Old Man's Bathtime Adventure", modifiers, description),$locations[The Old Man's Bathtime Adventures]).ChecklistEntrySetIDTag("Psychoanalytic jar old man")); +} + +void IOTMPMeatGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + string [int] description; + string [int] modifiers; + + if ($location[The Nightmare Meatrealm].lastCombatInLocation() == "The Beefhemoth") //somewhat limited way of detecting that we are finished + return; + + modifiers.listAppend("+meat"); + description.listAppend("Adventure until you find the beefhemoth, defeat him."); + if ($items[the sword in the steak, meatcleaver].available_amount() == 0) + description.listAppend("The Sword in the Steak is from a 0.1% likelyhood non-combat.|To find it, run away from monsters, preferrably with greatest american pants/navel ring of navel gazing."); + if ($item[meatcleaver].available_amount() == 0 && $item[the sword in the steak].available_amount() > 0) + { + if (my_buffedstat($stat[muscle]) < 1000) + description.listAppend("To pull the sword from the steak, buff muscle to 1000."); + else + description.listAppend("Pull the sword from the steak, adventurer."); + } + + + optional_task_entries.listAppend(ChecklistEntryMake("meat", "place.php?whichplace=junggate_6", ChecklistSubentryMake("The Meatsmith's Brainspace", modifiers, description),$locations[The Nightmare Meatrealm]).ChecklistEntrySetIDTag("Psychoanalytic jar meatsmith")); +} + +void IOTMPGourdGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + string [int] description; + string [int] modifiers; + + if ($location[the gourd!].lastCombatInLocation() == "Fnord the Unspeakable") //This should work for termination detection? + return; + + modifiers.listAppend("+item?"); + description.listAppend("Adventure in the gourd."); + if ($item[truthsayer].available_amount() == 0) + { + string [int] components; + boolean [item] items_implicitly_have; + if ($item[loose blade].available_amount() > 0) + { + items_implicitly_have[$item[goblin collarbone]] = true; + items_implicitly_have[$item[sharp tin strip]] = true; + } + if ($item[goblin bone hilt].available_amount() > 0) + { + items_implicitly_have[$item[goblin collarbone]] = true; + items_implicitly_have[$item[wad of spider silk]] = true; + } + if ($item[sticky sword blade].available_amount() > 0) + { + items_implicitly_have[$item[sharp tin strip]] = true; + items_implicitly_have[$item[wad of spider silk]] = true; + } + foreach it in $items[sharp tin strip, wad of spider silk, goblin collarbone] + { + string line = it; + if (it.available_amount() == 0 && !(items_implicitly_have contains it)) + line = HTMLGenerateSpanFont(line, "gray"); + components.listAppend(line); + } + description.listAppend("Truthsayer is (" + components.listJoinComponents(" + ") + "), found from gourd monsters."); + } + + + optional_task_entries.listAppend(ChecklistEntryMake("__item gourd potion", "place.php?whichplace=junggate_2", ChecklistSubentryMake("The Gourd", modifiers, description),$locations[The gourd!]).ChecklistEntrySetIDTag("Psychoanalytic jar gourd")); +} + +void IOTMPCrackpotGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + string [int] description; + string [int] modifiers; + + //Despair, rage, envy. Anger, fear, doubt, regret. + string url = "place.php?whichplace=junggate_3"; + string image_name = "__item red pixel"; + + boolean need_byte_sword = !($item[byte].available_amount() + $item[byte].storage_amount() > 0 || $item[flickering pixel].available_amount() + $item[flickering pixel].storage_amount() >= 8); + + if ($item[flickering pixel].available_amount() == 8) + { + description.listAppend("Use eight flickering pixels to acquire the sword, byte."); + } + + string [int] bosses_remaining; + + if ($location[anger man's level].lastCombatInLocation() != "Anger man") + bosses_remaining.listAppend("anger man"); + if ($location[fear man's level].lastCombatInLocation() != "Fear man") + bosses_remaining.listAppend("fear man"); + if ($location[doubt man's level].lastCombatInLocation() != "Doubt man") + bosses_remaining.listAppend("doubt man"); + if ($location[regret man's level].lastCombatInLocation() != "Regret man") + bosses_remaining.listAppend("regret man"); + + if (bosses_remaining.count() == 0 && description.count() == 0) + return; + + if (__last_adventure_location == $location[anger man's level] && $location[anger man's level].lastCombatInLocation() != "Anger man") + { + description.listAppend("Adventure in anger man's level, defeat the boss."); + string [int] stats_needed_to_complete_zone; + string [int] stats_needed_for_flickering_pixel; + foreach s in $stats[muscle, mysticality, moxie] + { + if (s.my_buffedstat() < 50) + { + stats_needed_to_complete_zone.listAppend(s.to_string().to_lower_case()); + } + if (s.my_buffedstat() < 500) + { + stats_needed_for_flickering_pixel.listAppend(s.to_string().to_lower_case()); + } + } + + float resistance = numeric_modifier("hot resistance"); + int resistance_needed = MAX(0, floor(25 - resistance)); + if (resistance < 25.0 && need_byte_sword) + description.listAppend("Need " + resistance_needed + " more hot resistance for the first flickering pixel."); + + if (stats_needed_to_complete_zone.count() > 0) + description.listAppend("Need 50 " + stats_needed_to_complete_zone.listJoinComponents(", ", "and") + " to pass first test."); + if (stats_needed_for_flickering_pixel.count() > 0 && need_byte_sword) + description.listAppend("Need 500 " + stats_needed_for_flickering_pixel.listJoinComponents(", ", "and") + " for the second flickering pixels."); + + + } + else if (__last_adventure_location == $location[fear man's level] && $location[fear man's level].lastCombatInLocation() != "Fear man") + { + description.listAppend("Adventure in fear man's level, defeat the boss."); + + //50 moxie to complete + //300 moxie for first flickering + //25 spooky res for second flickering + + if (my_buffedstat($stat[moxie]) < 50) + description.listAppend("Need 50 total moxie pass first test."); + + if (my_buffedstat($stat[moxie]) < 300 && need_byte_sword) + description.listAppend("Need 300 total moxie for the first flickering pixel."); + + float resistance = numeric_modifier("spooky resistance"); + int resistance_needed = MAX(0, floor(25 - resistance)); + if (resistance < 25.0 && need_byte_sword) + description.listAppend("Need " + resistance_needed + " more spooky resistance for the second flickering pixel."); + } + else if (__last_adventure_location == $location[doubt man's level] && $location[doubt man's level].lastCombatInLocation() != "Doubt man") + { + description.listAppend("Adventure in doubt man's level, defeat the boss."); + + //weapon damage >= 100 to complete + //HP > 100 to complete + //weapon damage >= 276(?) for first flickering + //HP >= 1000 for second flickering + + int weapon_damage = numeric_modifier("weapon damage").floor(); + if (weapon_damage < 100) + description.listAppend("Need " + (100 - weapon_damage) + " more weapon damage to pass first test."); + if (weapon_damage < 276 && need_byte_sword) + description.listAppend("Need " + (276 - weapon_damage) + "(?) more weapon damage for the first flickering pixel."); + + if (my_hp() < 100) + description.listAppend("Need 100 total HP to pass second test."); + if (my_hp() < 1000 && need_byte_sword) + description.listAppend("Need 1000 total HP for the second flickering pixel."); + } + else if (__last_adventure_location == $location[regret man's level] && $location[regret man's level].lastCombatInLocation() != "Regret man") + { + description.listAppend("Adventure in regret man's level, defeat the boss."); + + //MP >= 100 to complete + //total elemental damage >= 50 to complete + //MP >= 1000 for first flickering + //total elemental damage >= 100 for second flickering + + if (my_mp() < 100) + description.listAppend("Need 100 total MP to pass first test."); + if (my_mp() < 1000 && need_byte_sword) + description.listAppend("Need 1000 total MP for the first flickering pixel."); + //int total_elemental_damage = numeric_modifier("cold damage") + numeric_modifier("hot damage") + numeric_modifier("sleaze damage") + numeric_modifier("spooky damage") + numeric_modifier("stench damage"); + + //FIXME I am not sure if this is correct. How exactly does this test work? + string [int] missing_second_test; + string [int] missing_second_pixel_test; + foreach e in $strings[cold,hot,sleaze,spooky,stench] + { + string element_html_id = "r_element_" + e; + int damage = numeric_modifier(e + " damage").floor(); + if (damage < 50) + missing_second_test.listAppend(HTMLGenerateSpanOfClass((50 - damage) + " more " + e, element_html_id)); + if (damage < 60 && need_byte_sword) + missing_second_pixel_test.listAppend(HTMLGenerateSpanOfClass((60 - damage) + " more " + e, element_html_id)); + + } + if (missing_second_test.count() > 0) + description.listAppend("Need " + missing_second_test.listJoinComponents(", ", "and") + " damage to pass the second test."); + if (missing_second_pixel_test.count() > 0) + description.listAppend("Need " + missing_second_pixel_test.listJoinComponents(", ", "and") + " damage for the second flickering pixel."); + } + + string await = " await."; + if (bosses_remaining.count() == 1) + await = " awaits."; + if (bosses_remaining.count() > 0) + description.listAppend(bosses_remaining.listJoinComponents(", ", "and").capitaliseFirstLetter() + await); + else if ($item[flickering pixel].available_amount() == 8) + { + url = "inventory.php?ftext=flickering+pixel"; + image_name = "__item flickering pixel"; + } + + if (__misc_state["in run"]) + description.listAppend("(this isn't ascension relevant after you've gotten a digital key)"); + + optional_task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake("The Crackpot Mystic's Psychoses", modifiers, description),$locations[anger man's level, fear man's level, doubt man's level, regret man's level]).ChecklistEntrySetIDTag("Psychoanalytic jar crackpot mystic")); +} + + + +void IOTMPJickGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + string [int] description; + string [int] modifiers; + + if ($item[sword of procedural generation].available_amount() > 0) + return; + + description.listAppend("Fight skeletons."); + description.listAppend("Make sure you have a monster manuel first; once this tower is complete, there's no way to get these factoids ever again."); + + //FIXME be more specific + + optional_task_entries.listAppend(ChecklistEntryMake("__item skeleton", "", ChecklistSubentryMake("Jick's Obsessions", modifiers, description),$locations[the tower of procedurally-generated skeletons]).ChecklistEntrySetIDTag("Psychoanalytic jar Jick")); +} + + + +void IOTMPArtistGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + string [int] description; + string [int] modifiers; + + + foreach e in $effects[My Breakfast With Andrea,The Champion's Breakfast,Tiffany's Breakfast,Breakfast Clubbed] + { + if (e.have_effect() > 0) + return; + } + //Let's see. + //The way this quest works is, you find utensils in the kitchen drawer. (or the mall) + //Then, you adventure in the grocery bag, and use a utensil on the monsters. + //The utensil you use on the monster determines breakfast. + + + description.listAppend("Make a breakfast."); + description.listAppend("To do this, you find utensils in the kitchen drawer, and use them, in combat, on the five different foods in the grocery bag.|Which utensil you use on which food helps determine your breakfast."); + + + string [int] missing_utensils; + foreach it in $items[Artist's Butterknife of Regret,Artist's Cookie Cutter of Loneliness,Artist's Crème Brulée Torch of Fury,Artist's Spatula of Despair,Artist's Whisk of Misery] + { + if (it.available_amount() > 0) + continue; + string utensil_readable_name = it.to_string().replace_string("Artist's ", ""); + + missing_utensils.listAppend(utensil_readable_name); + } + + if (missing_utensils.count() > 0) + { + modifiers.listAppend("+300% item"); + description.listAppend("Find utensils in the kitchen drawer, or buy in the mall.|Utensils missing:|*" + missing_utensils.listJoinComponents(", ", "and") + "."); + } + + string [int] breakfasts; + + string breakfast_line; + //Meat & Knife, Bread & Knife, Batter & Spatula, Eggs & Whisk, Potatoes & Knife + breakfast_line += "My Breakfast With Andrea: (+meat)"; + breakfast_line += "|*Meat" + __html_right_arrow_character + "Butterknife"; + breakfast_line += "|*Bread" + __html_right_arrow_character + "Butterknife"; + breakfast_line += "|*Batter" + __html_right_arrow_character + "Spatula"; + breakfast_line += "|*Eggs" + __html_right_arrow_character + "Whisk"; + breakfast_line += "|*Potatoes" + __html_right_arrow_character + "Butterknife"; + breakfasts.listAppend(breakfast_line); breakfast_line = ""; + + //Meat & Cutter, Bread & Torch, Batter & Whisk, Eggs & Torch, Potatoes & Torch + breakfast_line += "
"; + breakfast_line += "The Champion's Breakfast: (+init)"; + breakfast_line += "|*Meat" + __html_right_arrow_character + "Cookie Cutter"; + breakfast_line += "|*Bread" + __html_right_arrow_character + "Crème Brulée Torch"; + breakfast_line += "|*Batter" + __html_right_arrow_character + "Whisk"; + breakfast_line += "|*Eggs" + __html_right_arrow_character + "Crème Brulée Torch"; + breakfast_line += "|*Potatoes" + __html_right_arrow_character + "Crème Brulée Torch"; + breakfasts.listAppend(breakfast_line); breakfast_line = ""; + + //Meat & Spatula, Bread & Cutter, Batter & Cutter, Eggs & Spatula, Potatoes & Whisk + breakfast_line += "
"; + breakfast_line += "Tiffany's Breakfast: (+item)"; + breakfast_line += "|*Meat" + __html_right_arrow_character + "Spatula"; + breakfast_line += "|*Bread" + __html_right_arrow_character + "Cookie Cutter"; + breakfast_line += "|*Batter" + __html_right_arrow_character + "Cookie Cutter"; + breakfast_line += "|*Eggs" + __html_right_arrow_character + "Spatula"; + breakfast_line += "|*Potatoes" + __html_right_arrow_character + "Whisk"; + breakfasts.listAppend(breakfast_line); breakfast_line = ""; + + + //It's actually anything, but let's pick one: + //Meat & Torch, Bread & Whisk, Batter & Knife, Eggs & Cutter, Potatoes & Spatula + breakfast_line += "
"; + breakfast_line += "Breakfast Clubbed: (+ML)"; + breakfast_line += "|*Meat" + __html_right_arrow_character + "Crème Brulée Torch"; + breakfast_line += "|*Bread" + __html_right_arrow_character + "Whisk"; + breakfast_line += "|*Batter" + __html_right_arrow_character + "Butterknife"; + breakfast_line += "|*Eggs" + __html_right_arrow_character + "Cookie Cutter"; + breakfast_line += "|*Potatoes" + __html_right_arrow_character + "Spatula"; + breakfasts.listAppend(breakfast_line); breakfast_line = ""; + + description.listAppend("There are four different breakfasts possible:" + HTMLGenerateIndentedText(breakfasts)); + + if ($item[Ginsu™].available_amount() == 0) + description.listAppend("Making all four breakfasts in the same ascension lets you acquire the sword, " + $item[Ginsu™] + "."); + + optional_task_entries.listAppend(ChecklistEntryMake("__effect My Breakfast With Andrea", "place.php?whichplace=junggate_5", ChecklistSubentryMake("The Pretentious Artist's Obsession", modifiers, description),$locations[a kitchen drawer, a grocery bag]).ChecklistEntrySetIDTag("Psychoanalytic jar pretentious artist")); +} + +RegisterTaskGenerationFunction("IOTMPsychoanalyticGenerateTasks"); +void IOTMPsychoanalyticGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!get_property_boolean("_psychoJarUsed")) + return; + //Can't detect which jar was used, so check where they've been: + if ($locations[chinatown shops, chinatown tenement, triad factory,1st floor\, shiawase-mitsuhama building,2nd floor\, shiawase-mitsuhama building,3rd floor\, shiawase-mitsuhama building] contains __last_adventure_location) + { + //√ + IOTMPShadyPastGenerateTasks(task_entries, optional_task_entries, future_task_entries); + } + if ($locations[The Old Man's Bathtime Adventures] contains __last_adventure_location) + { + //√ + IOTMPOldManGenerateTasks(task_entries, optional_task_entries, future_task_entries); + } + if ($locations[The Nightmare Meatrealm] contains __last_adventure_location) + { + IOTMPMeatGenerateTasks(task_entries, optional_task_entries, future_task_entries); + } + if ($locations[The gourd!] contains __last_adventure_location) + { + IOTMPGourdGenerateTasks(task_entries, optional_task_entries, future_task_entries); + } + if ($locations[anger man's level, fear man's level, doubt man's level, regret man's level] contains __last_adventure_location) + { + //√ + IOTMPCrackpotGenerateTasks(task_entries, optional_task_entries, future_task_entries); + } + if ($locations[the tower of procedurally-generated skeletons] contains __last_adventure_location) + { + IOTMPJickGenerateTasks(task_entries, optional_task_entries, future_task_entries); + } + if ($locations[a kitchen drawer, a grocery bag] contains __last_adventure_location) + { + //√ + IOTMPArtistGenerateTasks(task_entries, optional_task_entries, future_task_entries); + } +} + + +// 2014 +//_dnaPotionsMade - int, count of potions made +//dnaSyringe - int, current phylum of syringe. seems to track if it's become empty? double check +//_dnaHybrid - boolean, true if you're become a human abomination today +//r13912 or higher + + +string [phylum] __dna_phylum_to_description; +string [phylum] __dna_phylum_to_description_colourless; +item [phylum] __dna_phylum_to_item; +effect [phylum] __dna_phylum_to_effect; +phylum [effect] __dna_effect_to_phylum; +string [int] __dna_intrinsic_ideas; + +record DNASuggestion +{ + phylum [int] phylums; + string relevant_effect_description; + string reason; + boolean always_show; +}; + + +DNASuggestion DNASuggestionMake(phylum [int] phylums, string relevant_effect_description, string reason, boolean always_show) +{ + DNASuggestion result; + result.phylums = phylums; + result.relevant_effect_description = relevant_effect_description; + result.reason = reason; + result.always_show = always_show; + return result; +} + +DNASuggestion DNASuggestionMake(phylum p, string relevant_effect_description, string reason) +{ + phylum [int] phylums; + phylums[0] = p; + return DNASuggestionMake(phylums, relevant_effect_description, reason, false); +} + +DNASuggestion DNASuggestionMake(phylum p, string relevant_effect_description, string reason, boolean always_show) +{ + phylum [int] phylums; + phylums[0] = p; + return DNASuggestionMake(phylums, relevant_effect_description, reason, always_show); +} + + +DNASuggestion DNASuggestionMake(boolean [phylum] phylums_in, string relevant_effect_description, string reason) +{ + phylum [int] phylums; + foreach p in phylums_in + { + phylums.listAppend(p); + } + return DNASuggestionMake(phylums, relevant_effect_description, reason, false); +} + +void listAppend(DNASuggestion [int] list, DNASuggestion entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +boolean DNAHavePhylum(phylum p) +{ + if (__dna_phylum_to_effect[p].have_effect() > 0) + return true; + + if (__dna_phylum_to_item[p].available_amount() > 0) + return true; + + return false; +} + +string DNABoldPhylumIfCurrentMonster(phylum p) +{ + if (monster_phylum() == p) + return HTMLGenerateSpanOfClass(p.to_string(), "r_bold"); + else + return p.to_string(); +} + +DNASuggestion [int] __phylum_potion_suggestions; +DNASuggestion [int] __phylum_potion_reminder_suggestions; +effect __current_dna_intrinsic = $effect[none]; + +RegisterInitFunction("IOTMDNAInit"); +void IOTMDNAInit() +{ + if (!__iotms_usable[$item[Little Geneticist DNA-Splicing Lab]]) + return; + + + //this is not a particulary good idea: + __dna_phylum_to_description[$phylum[beast]] = "+30 weapon damage"; + __dna_phylum_to_description[$phylum[bug]] = "+25% init"; + __dna_phylum_to_description[$phylum[constellation]] = "+50% meat"; + __dna_phylum_to_description[$phylum[construct]] = "+5 familiar weight, +50 DA, +5 DR"; + __dna_phylum_to_description[$phylum[dude]] = "+10% item, +10 muscle/mysticality/moxie"; + __dna_phylum_to_description[$phylum[elemental]] = "+3 resistances"; + __dna_phylum_to_description[$phylum[elf]] = "+100% spell damage, +50% candy drops"; + __dna_phylum_to_description[$phylum[fish]] = "+10 familiar weight"; + __dna_phylum_to_description[$phylum[goblin]] = "+20% pickpocket, +50% food drops"; + __dna_phylum_to_description[$phylum[hippy]] = "+1 stat/fight, +20 max MP"; + __dna_phylum_to_description[$phylum[humanoid]] = "+20% meat, +10% muscle/mysticality/moxie"; + __dna_phylum_to_description[$phylum[horror]] = "+10% critical hit, +10% critical spell hit"; + __dna_phylum_to_description[$phylum[mer-kin]] = "+25 ML"; + __dna_phylum_to_description[$phylum[orc]] = "+1 stat/fight, +40 max HP"; + __dna_phylum_to_description[$phylum[penguin]] = "+25% item"; + __dna_phylum_to_description[$phylum[pirate]] = "+50% gear drops, +50% booze drops"; + + + __dna_phylum_to_description_colourless[$phylum[demon]] = "+20 hot damage / hot spell damage"; + __dna_phylum_to_description_colourless[$phylum[hobo]] = "+20 stench damage / stench spell damage"; + __dna_phylum_to_description_colourless[$phylum[plant]] = "+20 cold damage / cold spell damage"; + __dna_phylum_to_description_colourless[$phylum[slime]] = "+20 sleaze damage / sleaze spell damage"; + __dna_phylum_to_description_colourless[$phylum[undead]] = "+20 spooky damage / spooky spell damage"; + + __dna_phylum_to_description[$phylum[demon]] = HTMLGenerateSpanOfClass(__dna_phylum_to_description_colourless[$phylum[demon]], "r_element_hot_desaturated"); + __dna_phylum_to_description[$phylum[hobo]] = HTMLGenerateSpanOfClass(__dna_phylum_to_description_colourless[$phylum[hobo]], "r_element_stench_desaturated"); + __dna_phylum_to_description[$phylum[plant]] = HTMLGenerateSpanOfClass(__dna_phylum_to_description_colourless[$phylum[plant]], "r_element_cold_desaturated"); + __dna_phylum_to_description[$phylum[slime]] = HTMLGenerateSpanOfClass(__dna_phylum_to_description_colourless[$phylum[slime]], "r_element_sleaze_desaturated"); + __dna_phylum_to_description[$phylum[undead]] = HTMLGenerateSpanOfClass(__dna_phylum_to_description_colourless[$phylum[undead]], "r_element_spooky_desaturated"); + + __dna_phylum_to_description[$phylum[weird]] = "+4 stats/fight"; + + foreach p in __dna_phylum_to_description + { + if (__dna_phylum_to_description_colourless contains p) + continue; + __dna_phylum_to_description_colourless[p] = __dna_phylum_to_description[p]; + } + + __dna_phylum_to_item[$phylum[beast]] = $item[Gene Tonic: Beast]; + __dna_phylum_to_item[$phylum[bug]] = $item[Gene Tonic: Insect]; + __dna_phylum_to_item[$phylum[constellation]] = $item[Gene Tonic: Constellation]; + __dna_phylum_to_item[$phylum[construct]] = $item[Gene Tonic: Construct]; + __dna_phylum_to_item[$phylum[demon]] = $item[Gene Tonic: Demon]; + __dna_phylum_to_item[$phylum[dude]] = $item[Gene Tonic: Dude]; + __dna_phylum_to_item[$phylum[elemental]] = $item[Gene Tonic: Elemental]; + __dna_phylum_to_item[$phylum[elf]] = $item[Gene Tonic: Elf]; + __dna_phylum_to_item[$phylum[fish]] = $item[Gene Tonic: Fish]; + __dna_phylum_to_item[$phylum[goblin]] = $item[Gene Tonic: Goblin]; + __dna_phylum_to_item[$phylum[hippy]] = $item[Gene Tonic: Hippy]; + __dna_phylum_to_item[$phylum[hobo]] = $item[Gene Tonic: Hobo]; + __dna_phylum_to_item[$phylum[horror]] = $item[Gene Tonic: Horror]; + __dna_phylum_to_item[$phylum[humanoid]] = $item[Gene Tonic: Humanoid]; + __dna_phylum_to_item[$phylum[mer-kin]] = $item[Gene Tonic: Mer-kin]; + __dna_phylum_to_item[$phylum[orc]] = $item[Gene Tonic: Orc]; + __dna_phylum_to_item[$phylum[penguin]] = $item[Gene Tonic: Penguin]; + __dna_phylum_to_item[$phylum[pirate]] = $item[Gene Tonic: Pirate]; + __dna_phylum_to_item[$phylum[plant]] = $item[Gene Tonic: Plant]; + __dna_phylum_to_item[$phylum[slime]] = $item[Gene Tonic: Slime]; + __dna_phylum_to_item[$phylum[undead]] = $item[Gene Tonic: Undead]; + __dna_phylum_to_item[$phylum[weird]] = $item[Gene Tonic: Weird]; + + __dna_phylum_to_effect[$phylum[beast]] = $effect[Human-Beast Hybrid]; + __dna_phylum_to_effect[$phylum[bug]] = $effect[Human-Insect Hybrid]; + __dna_phylum_to_effect[$phylum[constellation]] = $effect[Human-Constellation Hybrid]; + __dna_phylum_to_effect[$phylum[construct]] = $effect[Human-Machine Hybrid]; + __dna_phylum_to_effect[$phylum[demon]] = $effect[Human-Demon Hybrid]; + __dna_phylum_to_effect[$phylum[dude]] = $effect[Human-Human Hybrid]; + __dna_phylum_to_effect[$phylum[elemental]] = $effect[Human-Elemental Hybrid]; + __dna_phylum_to_effect[$phylum[elf]] = $effect[Human-Elf Hybrid]; + __dna_phylum_to_effect[$phylum[fish]] = $effect[Human-Fish Hybrid]; + __dna_phylum_to_effect[$phylum[goblin]] = $effect[Human-Goblin Hybrid]; + __dna_phylum_to_effect[$phylum[hippy]] = $effect[Human-Hippy Hybrid]; + __dna_phylum_to_effect[$phylum[hobo]] = $effect[Human-Hobo Hybrid]; + __dna_phylum_to_effect[$phylum[horror]] = $effect[Human-Horror Hybrid]; + __dna_phylum_to_effect[$phylum[humanoid]] = $effect[Human-Humanoid Hybrid]; + __dna_phylum_to_effect[$phylum[mer-kin]] = $effect[Human-Mer-kin Hybrid]; + __dna_phylum_to_effect[$phylum[orc]] = $effect[Human-Orc Hybrid]; + __dna_phylum_to_effect[$phylum[penguin]] = $effect[Human-Penguin Hybrid]; + __dna_phylum_to_effect[$phylum[pirate]] = $effect[Human-Pirate Hybrid]; + __dna_phylum_to_effect[$phylum[plant]] = $effect[Human-Plant Hybrid]; + __dna_phylum_to_effect[$phylum[slime]] = $effect[Human-Slime Hybrid]; + __dna_phylum_to_effect[$phylum[undead]] = $effect[Human-Undead Hybrid]; + __dna_phylum_to_effect[$phylum[weird]] = $effect[Human-Weird Thing Hybrid]; + + foreach p in __dna_phylum_to_effect + { + __dna_effect_to_phylum[__dna_phylum_to_effect[p]] = p; + } + + + foreach e in __dna_effect_to_phylum + { + if (e.have_effect() == 2147483647) + { + __current_dna_intrinsic = e; + break; + } + } + + + if (my_path().id == PATH_COMMUNITY_SERVICE) + { + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[fish], "", "+10 familiar weight for statgain, parrot")); + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[elemental], "", "saves three turns on resistance test")); + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[pirate], "", "~3.3 turns saved on item test")); + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[construct], "", "+5 familiar weight")); + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[elf], "", "spell damage test")); + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[beast], "", "marginal?")); + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[dude], "", "marginal?")); + + return; + } + + if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"]) + { + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[bug], "", "speed up defiled alcove")); + __phylum_potion_reminder_suggestions.listAppend(DNASuggestionMake($phylum[bug], "", "speed up defiled alcove")); + } + + if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) + { + //FIXME only suggest constellation if they've not finished HITS? + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylums[constellation,humanoid], "+meat", "nuns")); + __phylum_potion_reminder_suggestions.listAppend(DNASuggestionMake($phylum[constellation], "+meat", "nuns")); + __phylum_potion_reminder_suggestions.listAppend(DNASuggestionMake($phylum[humanoid], "+meat", "nuns")); + + } + if (!__quest_state["Level 3"].finished) + { + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylums[demon,hobo,plant,undead], "+elemental damage", "tavern NC skipping")); + } + if (!__quest_state["Level 12"].finished && (!have_outfit_components("War Hippy Fatigues") && !have_outfit_components("Frat Warrior Fatigues")) && !__misc_state["yellow ray potentially available"]) + { + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[pirate], "+50% gear drop", "war outfit?")); + } + if (__quest_state["Level 11 Palindome"].mafia_internal_step < 5 && $item[mega gem].available_amount() == 0 && in_hardcore() && !($skill[Check Hair].skill_is_usable() && $skill[Natural Dancer].skill_is_usable())) //avatar of sneaky pete usually can cap this easily... usually + { + if ($item[wet stunt nut stew].available_amount() == 0 && !(($item[bird rib].available_amount() > 0 && $item[lion oil].available_amount() > 0 || $item[wet stew].available_amount() > 0))) + { + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[goblin], "+50% food drop", "Wet stunt nut stew components")); + __phylum_potion_reminder_suggestions.listAppend(DNASuggestionMake($phylum[goblin], "+50% food drop", "Wet stunt nut stew components")); //300% drop, very important + } + } + + if (true) + { + string [int] reasons; + if (!__quest_state["Level 8"].finished && numeric_modifier("cold resistance") < 5.0) + reasons.listAppend("icy peak"); + if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0) + reasons.listAppend("a-boo peak"); + + if (reasons.count() > 0) + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[elemental], "+3 all resistance", reasons.listJoinComponents(", ", "and").capitaliseFirstLetter())); + } + + if (__misc_state["in run"]) + { + if (__current_dna_intrinsic != __dna_phylum_to_effect[$phylum[construct]] && !__misc_state["familiars temporarily blocked"]) + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[construct], "+5 familiar weight, DR/DA", "", true)); + if (__current_dna_intrinsic != __dna_phylum_to_effect[$phylum[dude]]) + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[dude], "+10% item", "", true)); + + if (!__quest_state["Level 13"].state_boolean["Elemental damage race completed"]) + { + string element_needed = __quest_state["Level 13"].state_string["Elemental damage race type"]; + DNASuggestion element_suggestion; + string suggestion_effect = "+" + HTMLGenerateSpanOfClass(element_needed, "r_element_" + element_needed + "_desaturated") + " damage/spell damage"; + string suggestion_description = "Lair race"; + if (element_needed == "hot") + element_suggestion = DNASuggestionMake($phylum[demon], suggestion_effect, suggestion_description, true); + else if (element_needed == "cold") + element_suggestion = DNASuggestionMake($phylum[plant], suggestion_effect, suggestion_description, true); + else if (element_needed == "sleaze") + element_suggestion = DNASuggestionMake($phylum[slime], suggestion_effect, suggestion_description, true); + else if (element_needed == "spooky") + element_suggestion = DNASuggestionMake($phylum[undead], suggestion_effect, suggestion_description, true); + else if (element_needed == "stench") + element_suggestion = DNASuggestionMake($phylum[hobo], suggestion_effect, suggestion_description, true); + if (element_suggestion.phylums.count() > 0 && element_needed != "") + { + __phylum_potion_suggestions.listAppend(element_suggestion); + __phylum_potion_reminder_suggestions.listAppend(element_suggestion); + } + } + } + else + { + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[penguin], "", "", true)); + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[fish], "", "", true)); + __phylum_potion_suggestions.listAppend(DNASuggestionMake($phylum[constellation], "", "", true)); + } + + + if (__current_dna_intrinsic == $effect[none]) + { + if (!__misc_state["familiars temporarily blocked"]) + { + if (!__misc_state["in run"] || my_path().id == PATH_HEAVY_RAINS) + __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[fish]) + " (+10 familiar weight)"); + else if ($item[grimstone mask].available_amount() > 0) + { + __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[fish]) + " (+10 familiar weight, via grimstone mask candy witch's lake)"); + __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[construct]) + " (+5 familiar weight)"); + } + else + __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[construct]) + " (+5 familiar weight)"); + } + if (__misc_state["need to level"]) + { + if ($familiar[astral badger].familiar_is_usable() || $item[astral mushroom].available_amount() > 0 || $effect[Half-Astral].have_effect() > 0 || __misc_state_int["pulls available"] > 0) + { + string method = "astral badger"; + if (!$familiar[astral badger].familiar_is_usable() || $item[astral mushroom].available_amount() > 0) + method = "astral mushroom"; + __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[weird]) + " (+4 stats/fight, via " + method + ")"); + } + else if (__misc_state["sleaze airport available"]) + { + __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[weird]) + " (+4 stats/fight, via sloppy seconds diner)"); + } + } + __dna_intrinsic_ideas.listAppend(DNABoldPhylumIfCurrentMonster($phylum[dude]) + " (+10% item)"); + + } +} + +RegisterResourceGenerationFunction("IOTMDNAGenerateResource"); +void IOTMDNAGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (__misc_state["campground unavailable"]) + return; + if (!__iotms_usable[$item[Little Geneticist DNA-Splicing Lab]]) + return; + + //Player has a genetic engineering lab installed. Let's play with our DNA! + + phylum syringe_phylum = getDNASyringePhylum(); + int potions_made = get_property_int("_dnaPotionsMade"); + int potions_left = MAX(0, 3 - potions_made); + boolean became_a_genetic_monstrosity_today = get_property_boolean("_dnaHybrid"); + + + //Some ideas: + //Intrinsics: + //√constructs - +5 familiar weight - also a potion option + //√weird - +4 stats/fight - hard to find without badger + //√dudes - +10% items + + //fish - +10 familiar weight - HCO only? possible with agua de vida, but takes at least two turns? 70% NC base, 2 NCs, need two of an NC. this is versus zero-turn +5 familiar weight... + //mer-kin - +25 ML - fax only. even with sea access, requires wreck access + //orcs/hippies - +1 stat/fight... ??? marginal? + //penguins - +25% item - nowhere to be found in-run before level 11 + + //Potions: + //√bug - +25% init - modern zmobies, potion, if we can find bugs + //√elemental - +3 all res - icy peak, a-boo, stench for twin/bats + //√constellation - +50% meat - nuns, potion + //√humanoid - +20% meat - more nuns? + //√demon - +20 hot damage - skipping tavern NC + //√hobo - +20 stench damage - skipping tavern NCs, but isn't there a better source? (the pool) + //√plant - +20 cold damage - tavern skipping, somewhat silly, song of north exists + //√undead - +20 spooky damage - tavern skipping...? + //pirate - +50% gear drops - not sure. potion? seems like it'd be useful in a handful of places + + + + + + ChecklistSubentry [int] subentries; + TagGroup tags; + tags.id = "DNA lab various resources"; //seems to include a lot, but IDK enough about the lab + + string syringe_description = ""; + boolean syringe_description_output = false; + if (syringe_phylum != $phylum[none]) + { + string line = "Syringe has " + syringe_phylum + "." + " (" + __dna_phylum_to_description_colourless[syringe_phylum] + ")"; + syringe_description = line; + } + + if (potions_left > 0) + { + string [int] description; + + if (syringe_description != "" && !syringe_description_output) + { + description.listAppend(syringe_description); + syringe_description_output = true; + } + + string [int] potion_suggestion_descriptions; + foreach key in __phylum_potion_suggestions + { + DNASuggestion suggestion = __phylum_potion_suggestions[key]; + + phylum [int] needed_phylums; + + foreach key2 in suggestion.phylums + { + phylum p = suggestion.phylums[key2]; + if (!DNAHavePhylum(p) || suggestion.always_show) + { + needed_phylums.listAppend(p); + } + } + + if (needed_phylums.count() > 0) + { + string [int] phylum_descriptions; + string [int] output_effect_description; + + foreach key in needed_phylums + { + phylum p = needed_phylums[key]; + + phylum_descriptions.listAppend(DNABoldPhylumIfCurrentMonster(p)); + + if (suggestion.relevant_effect_description.length() == 0) + output_effect_description.listAppend(__dna_phylum_to_description_colourless[p]); + } + if (suggestion.relevant_effect_description != "") + output_effect_description.listAppend(suggestion.relevant_effect_description); + + string line; + + line = phylum_descriptions.listJoinComponents("/"); + line += ": " + output_effect_description.listJoinComponents("/"); + if (suggestion.reason != "") + line += " - " + suggestion.reason; + + potion_suggestion_descriptions.listAppend(line); + } + } + //HTMLGenerateSimpleTableLines + if (potion_suggestion_descriptions.count() > 0) + description.listAppend("Tonic ideas:|*" + potion_suggestion_descriptions.listJoinComponents("
|*")); + subentries.listAppend(ChecklistSubentryMake(pluralise(potions_left, "gene tonic", "gene tonics") + " creatable", "", description)); + } + if (!became_a_genetic_monstrosity_today) + { + string [int] description; + if (syringe_description != "" && !syringe_description_output) + { + description.listAppend(syringe_description); + syringe_description_output = true; + } + + if (__current_dna_intrinsic != $effect[none] && (__dna_effect_to_phylum contains __current_dna_intrinsic)) + description.listAppend("Currently a " + __dna_effect_to_phylum[__current_dna_intrinsic] + ". (" + __dna_phylum_to_description_colourless[__dna_effect_to_phylum[__current_dna_intrinsic]] + ")"); + + + if (__current_dna_intrinsic == $effect[none]) + { + if (__dna_intrinsic_ideas.count() > 0) + description.listAppend("Could try " + __dna_intrinsic_ideas.listJoinComponents(", ", "or") + "."); + } + + subentries.listAppend(ChecklistSubentryMake("Genetic intrinsic available", "", description)); + } + + int importance = 5; + + if (potions_left == 0 && __current_dna_intrinsic != $effect[none]) //no potions, already a hybrid + importance = 8; + + string image_name = "__effect Human-Human Hybrid"; + + if (__misc_state["in run"]) + { + foreach p in __dna_phylum_to_item + { + item it = __dna_phylum_to_item[p]; + if (it.available_amount() == 0) + continue; + if (subentries.count() == 0) + image_name = "__item Gene Tonic: Constellation"; + subentries.listAppend(ChecklistSubentryMake(it.pluralise(), "", __dna_phylum_to_description_colourless[p])); + + } + } + + if (subentries.count() > 0) + resource_entries.listAppend(ChecklistEntryMake(image_name, "campground.php?action=workshed", subentries, tags, importance)); +} + +RegisterTaskGenerationFunction("IOTMDNAGenerateTasks"); +void IOTMDNAGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (__misc_state["campground unavailable"]) + return; + if (!__iotms_usable[$item[Little Geneticist DNA-Splicing Lab]]) + return; + + //Reminders: + phylum syringe_phylum = getDNASyringePhylum(); + + + if (get_property_int("_dnaPotionsMade") < 3) + { + if (syringe_phylum != $phylum[none] && !DNAHavePhylum(syringe_phylum)) + { + //Make the resulting tonic: + string suggestion_reason; + + string relevant_effect_description; + + + foreach key in __phylum_potion_reminder_suggestions + { + DNASuggestion suggestion = __phylum_potion_reminder_suggestions[key]; + foreach key2 in suggestion.phylums + { + phylum suggestion_phylum = suggestion.phylums[key2]; + if (syringe_phylum == suggestion_phylum) + { + suggestion_reason = suggestion.reason; + relevant_effect_description = suggestion.relevant_effect_description; + } + } + } + + + if (suggestion_reason != "") + { + string description = suggestion_reason.capitaliseFirstLetter() + "."; + task_entries.listAppend(ChecklistEntryMake("__effect Human-Human Hybrid", "campground.php?action=workshed", ChecklistSubentryMake("Make gene tonic for " + syringe_phylum, "", description), -11).ChecklistEntrySetIDTag("DNA lab make DNA potion")); + } + } + + + + if (monster_phylum() != $phylum[none] && monster_phylum() != syringe_phylum && !DNAHavePhylum(monster_phylum())) + { + //Syringe a monster when we find it: + phylum p = monster_phylum(); + + string suggestion_reason; + + string relevant_effect_description; + + + foreach key in __phylum_potion_reminder_suggestions + { + DNASuggestion suggestion = __phylum_potion_reminder_suggestions[key]; + foreach key2 in suggestion.phylums + { + phylum suggestion_phylum = suggestion.phylums[key2]; + if (p == suggestion_phylum) + { + suggestion_reason = suggestion.reason; + relevant_effect_description = suggestion.relevant_effect_description; + } + } + } + + if (suggestion_reason != "") + { + if (relevant_effect_description.length() == 0) + relevant_effect_description = __dna_phylum_to_description[p]; + string description = suggestion_reason.capitaliseFirstLetter() + "."; + description += "|" + monster_phylum().to_string().capitaliseFirstLetter() + " (" + relevant_effect_description + ")"; + task_entries.listAppend(ChecklistEntryMake("__effect Human-Human Hybrid", "", ChecklistSubentryMake("Extract DNA from " + last_monster().to_string().HTMLEscapeString(), "", description), -11).ChecklistEntrySetIDTag("DNA lab use syringe")); + } + } + } + + if (__current_dna_intrinsic == $effect[none] && !get_property_boolean("_dnaHybrid")) + { + string [int] description; + if (__dna_intrinsic_ideas.count() > 0) + description.listAppend("Could try " + __dna_intrinsic_ideas.listJoinComponents(", ", "or") + "."); + optional_task_entries.listAppend(ChecklistEntryMake("__effect Human-Human Hybrid", "campground.php?action=workshed", ChecklistSubentryMake("Hybridize yourself", "", description), 5).ChecklistEntrySetIDTag("DNA lab become hybrid")); + } +} + +void IOTMGrimstoneHareGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + string [int] description; + string [int] modifiers; + + modifiers.listAppend("mysticality"); + modifiers.listAppend("spell damage percent"); + modifiers.listAppend("spell critical percent"); + int time_remaining = $effect[hare-brained].have_effect(); + + //FIXME deal with coldform / hotform / etc + + description.listAppend("Adventure on the deserted stretch of road.|Cast elemental-aligned powerful spells on vehicles.|The more damage, the faster you go."); + + description.listAppend("The speedy/expensive strategy is to nanorhino/ice house/batter up/pantsgiving/crystal skull/etc. banish everything that isn't an ice cream truck, and olfact ice cream trucks.|Then run coldform, buff spell damage, mysticality, and spell damage critical.|Then cast shrap."); + + string [string] elemental_descriptions; + + string [int] missing_hobopolis_spells; + + elemental_descriptions["hot"] = HTMLGenerateSpanOfClass("hot", "r_element_hot"); + elemental_descriptions["cold"] = HTMLGenerateSpanOfClass("cold", "r_element_cold"); + elemental_descriptions["spooky"] = HTMLGenerateSpanOfClass("spooky", "r_element_spooky"); + elemental_descriptions["stench"] = HTMLGenerateSpanOfClass("stench", "r_element_stench"); + elemental_descriptions["sleaze"] = HTMLGenerateSpanOfClass("sleaze", "r_element_sleaze"); + + + boolean have_shrap = $skill[shrap].skill_is_usable(); + + if (have_shrap && $effect[hotform].have_effect() > 0) + elemental_descriptions["hot"] = "Shrap (" + elemental_descriptions["hot"] + ")"; + else if ($skill[volcanometeor showeruption].skill_is_usable()) + elemental_descriptions["hot"] = "Volcanometeor Showeruption (" + elemental_descriptions["hot"] + ")"; + else if ($skill[Awesome Balls of Fire].skill_is_usable()) + elemental_descriptions["hot"] = "Awesome Balls of Fire (" + elemental_descriptions["hot"] + ")"; + else + missing_hobopolis_spells.listAppend("Awesome Balls of Fire"); + + + if (have_shrap && $effect[coldform].have_effect() > 0) + elemental_descriptions["cold"] = "Shrap (" + elemental_descriptions["cold"] + ")"; + else if ($skill[Snowclone].skill_is_usable()) + elemental_descriptions["cold"] = "Snowclone (" + elemental_descriptions["cold"] + ")"; + else + missing_hobopolis_spells.listAppend("Snowclone"); + + if (have_shrap && $effect[spookyform].have_effect() > 0) + elemental_descriptions["spooky"] = "Shrap (" + elemental_descriptions["spooky"] + ")"; + else if ($skill[Raise Backup Dancer].skill_is_usable()) + elemental_descriptions["spooky"] = "Raise Backup Dancer (" + elemental_descriptions["spooky"] + ")"; + else + missing_hobopolis_spells.listAppend("Raise Backup Dancer"); + + if (have_shrap && $effect[stenchform].have_effect() > 0) + elemental_descriptions["stench"] = "Shrap (" + elemental_descriptions["stench"] + ")"; + else if ($skill[Eggsplosion].skill_is_usable()) + elemental_descriptions["stench"] = "Eggsplosion (" + elemental_descriptions["stench"] + ")"; + else + missing_hobopolis_spells.listAppend("Eggsplosion"); + + + if (have_shrap && $effect[sleazeform].have_effect() > 0) + elemental_descriptions["sleaze"] = "Shrap (" + elemental_descriptions["sleaze"] + ")"; + else if ($skill[Grease Lightning].skill_is_usable()) + elemental_descriptions["sleaze"] = "Grease Lightning (" + elemental_descriptions["sleaze"] + ")"; + else + missing_hobopolis_spells.listAppend("Grease Lightning"); + + + + string [int][int] vehicle_descriptions; + if (!$monster[Fire truck].is_banished()) + vehicle_descriptions.listAppend(listMake("Fire truck", elemental_descriptions["hot"])); + if (!$monster[ice cream truck].is_banished()) + vehicle_descriptions.listAppend(listMake("ice cream truck", elemental_descriptions["cold"])); + if (!$monster[monster hearse].is_banished()) + vehicle_descriptions.listAppend(listMake("monster hearse", elemental_descriptions["spooky"])); + if (!$monster[sewer tanker].is_banished()) + vehicle_descriptions.listAppend(listMake("sewer tanker", elemental_descriptions["stench"])); + if (!$monster[sketchy van].is_banished()) + vehicle_descriptions.listAppend(listMake("sketchy van", elemental_descriptions["sleaze"])); + + monster last_encounter = get_property_monster("lastEncounter"); + //string [int] vehicles = split_string_alternate("Fire truck,ice cream truck,monster hearse,sewer tanker,sketchy van", ","); + monster [int] vehicles = {$monster[Fire truck],$monster[ice cream truck],$monster[monster hearse],$monster[sewer tanker],$monster[sketchy van]}; + + foreach key in vehicles + { + monster vehicle = vehicles[key]; + if (vehicle == $monster[none]) + continue; + + if (last_encounter != vehicle) + continue; + + vehicle_descriptions[key][0] = HTMLGenerateSpanOfClass(vehicle_descriptions[key][0], "r_bold"); + vehicle_descriptions[key][1] = HTMLGenerateSpanOfClass(vehicle_descriptions[key][1], "r_bold"); + } + + description.listAppend("Spells to cast: " + HTMLGenerateIndentedText(HTMLGenerateSimpleTableLines(vehicle_descriptions))); + + if (my_familiar() != $familiar[magic dragonfish]) + description.listAppend("Run magic dragonfish familiar."); + else if ($familiar[magic dragonfish].familiar_weight() < 20) + description.listAppend("Gain " + (20 - $familiar[magic dragonfish].familiar_weight()) + " pounds on your magic dragonfish."); + + if (missing_hobopolis_spells.count() > 0) + description.listAppend("Could acquire " + missing_hobopolis_spells.listJoinComponents(", ", "or") + " from the mall."); + + if ($skill[frigidalmatian].skill_is_usable() && $effect[frigidalmatian].have_effect() == 0) + description.listAppend("Could cast frigidalmatian. (expensive)"); + + if (my_basestat($stat[mysticality]) < 400) + description.listAppend("May want to gain " + (400 - my_basestat($stat[mysticality])) + " more mysticality."); + + description.listAppend(pluralise(time_remaining, "turn", "turns") + " remaining in race."); + + + + + //$location[A Deserted Stretch of I-911] + optional_task_entries.listAppend(ChecklistEntryMake("__effect hare-brained", "place.php?whichplace=ioty2014_hare", ChecklistSubentryMake("Hare Race", modifiers, description)).ChecklistEntrySetIDTag("Grimstone mask hare")); +} + +void IOTMGrimstoneStepmotherGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + int minutes_to_midnight = get_property_int("cinderellaMinutesToMidnight"); + if (minutes_to_midnight <= 0) + return; + + //if (__misc_state["in run"] && !($locations[the prince's kitchen,the prince's balcony,the prince's lounge,the prince's canapes table,the prince's restroom,the prince's dance floor] contains __last_adventure_location) && minutes_to_midnight < 30) + //return; + + int score = get_property_int("cinderellaScore"); + string [int] description; + string [int] modifiers; + + + if (minutes_to_midnight > 0) + { + string line; + line = pluralise(minutes_to_midnight, "minute", "minutes") + " to midnight."; + + if (score > 0) + line += " " + pluralise(score, "point", "points") + " earned."; + + description.listAppend(line); + } + + /* + The idea behind this solution is you want to put three items into cindy's purse. + The first two make her ignore her hankerchief and go to the restroom - where the doctored soap gives her puffy eyes - whereupon she returns and confirms the disease rumor. + The third is the mouse, which you confront her about. Then later she'll not have the purse at all and go to the restroom again. + + There are other solutions, but I don't know them. Find them! It's a fun puzzle. + */ + + string [int][int] minute_to_action; + minute_to_action[30] = listMake("Lounge", "Take a cigar from the sideboard"); //I say, old chap + minute_to_action[29] = listMake("Balcony", "Examine the flowers."); //to give to prince + minute_to_action[28] = listMake("Canapés Table", "Give your carnation to the Prince."); //causes sneezing fit at 23, 13, 3 + minute_to_action[27] = listMake("Canapés Table", "Slip something into Cindy's purse while she's distracted", "The cigar."); //Make her leave when sneezing + minute_to_action[26] = listMake("Balcony", "Examine the flowers."); //For doctoring + minute_to_action[25] = listMake("Restroom", "Rub the flower on the soap."); //For 23 sneezing. + minute_to_action[24] = listMake("Lounge", "Start a rumor about Cinderella", "Cinderella has a terrible disease."); //Points! + minute_to_action[23] = listMake("Lounge", "Take the empty cigar box."); //Mouse trap setup. 3 points (from sneezing) + minute_to_action[22] = listMake("Kitchen", "Inspect the kitchen pantry."); //Acquire cinnamon, notice mouse hole. + minute_to_action[21] = listMake("Canapés Table", "Take a piece of cheese."); //Mouse trap setup. + minute_to_action[20] = listMake("Kitchen", "Set a trap for the mouse."); //Set up mouse trap with cigar box and cheese. (if we had room, soap too, but that adds one point and there's no room - used in 31-point solution) + minute_to_action[19] = listMake("Canapés Table", "Slip something into Cindy's purse while she's distracted", "The cinnamon."); //For 13 sneezing fit, makes her ignore hankerchief. + minute_to_action[18] = listMake("Lounge", "Take the whiskey flask."); //To make cindy drunk. 5 points (prince hears rumor) + minute_to_action[17] = listMake("Canapés Table", "Pour some whisky into Cindy's glass."); //Cindy's drunk - used at 16, 6, and extra points from soap. + minute_to_action[16] = listMake("Balcony", "Examine the flowers."); //For stealing a hairpin from baronness. 6 points (16 behavior hits, she's drunk) + minute_to_action[15] = listMake("Balcony", "Speak with the Baroness."); //First step baronness + minute_to_action[14] = listMake("Balcony", "Ask the Baroness what troubles her."); //Makes baronness move to dance floor + minute_to_action[13] = listMake("Dance Floor", "Give your carnation to the Baroness and steal one of her hairpins."); //Now we can steal a hairpin. 11 points (sneezing fit with disease rumor) + minute_to_action[12] = listMake("Restroom", "Look in the medicine cabinet", "Pick the lock", "Take the bottle of syrup of ipecac."); //Which we use to pick the lock of the medicine cabinet, acquiring ipecac. + minute_to_action[11] = listMake("Kitchen", "Dose the tray of cannoli with ipecac."); //Ipecac we use here. + minute_to_action[10] = listMake("Restroom", "Take some soap."); //We'll be throwing it later. + minute_to_action[9] = listMake("Canapés Table", "Offer Cindy your 'customized' cannoli."); //Makes her throw up in eight turns. (no cinnamon) + minute_to_action[8] = listMake("Kitchen", "Take the mouse out of the trap."); //It showed up. Hello mouse. + minute_to_action[7] = listMake("Canapés Table", "Slip something into Cindy's purse while she's distracted", "The mouse."); //Third time. + minute_to_action[6] = listMake("Canapés Table", "Ask Cindy to loan you her handkerchief."); //Hey, is that a mouse in your purse? 13 points. (one from mouse, one from 6 behavior) + minute_to_action[5] = listMake("Dance Floor", "Kick some soap at Cindy."); //She's on the dance floor. Let's make her dance. 15 points. (dance!) + minute_to_action[4] = listMake("Restroom", "Take some soap."); //Dancing supplies. + minute_to_action[3] = listMake("Dance Floor", "Kick some soap at Cindy."); //Dance. 21 points (sneezing, dance!) + minute_to_action[2] = listMake("Restroom", "Take some soap."); //Dancing supplies. + minute_to_action[1] = listMake("Dance Floor", "Kick some soap at Cindy."); //She throws up. Dance. 32 points. (she threw up, dance!) + + if (false) + { + //output full details for reference: + string line; + foreach minute in minute_to_action + { + string description = minute_to_action[minute]; + line = "|" + pluralise(minute, "minute", "minutes") + ":|*" + minute_to_action[minute].listJoinComponents(" > ") + line; + } + description.listAppend(line); + } + //FIXME add the other two trophies? + + + //int [int] needed_points_at_spot_to_be_following_correct_path; //score isn't tracked properly, and anyways there's split score per turn + + /* +√30 take cigar +√29 flower +√28 give flower to prince +√27 give cigar to cindy +√26 flower +√25 doctor soap +√24 spread rumour (disease) +√23 take empty cigar box +√22 inspect kitchen +√21 get cheese +√20 set trap +√19 plant cinnamon in cindy's purse +√18 get whiskey +√17 pour whiskey +√16 flower +√15 ask baronness +√14 ask baronness x2 +√13 steal from baronness +√12 steal ipecac +√11 make cannoli (mouse available) +√10 get soap +√9 give cindy cannoli +√8 get mouse +√7 plant mouse +√6 ask for hankerchief +√5 kick soap +√4 get soap +√3 kick soap +√2 get soap +√1 kick soap + */ + + boolean output_next_step = true; + //if (needed_points_at_spot_to_be_following_correct_path contains minutes_to_midnight && score != needed_points_at_spot_to_be_following_correct_path[minutes_to_midnight]) //they're doing a different route + //output_next_step = false; + + if (minute_to_action contains minutes_to_midnight && output_next_step) + { + description.listAppend("Next step for 32 points:|*" + minute_to_action[minutes_to_midnight].listJoinComponents(__html_right_arrow_character)); + description.listAppend("Though, this is a fun puzzle to solve on your own."); + } + + //FIXME add suggestions for other two trophies (partners in crime, ending party early) + optional_task_entries.listAppend(ChecklistEntryMake("__item long-stemmed rose", "place.php?whichplace=ioty2014_cindy", ChecklistSubentryMake("The Prince's Ball", modifiers, description)).ChecklistEntrySetIDTag("Grimstone mask stepmother")); +} + +void IOTMGrimstoneWolfGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //FIXME I have no idea + return; +} + +void IOTMGrimstoneWitchGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //FIXME I have no idea + return; +} + +void IOTMGrimstoneGnomeGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //FIXME I have no idea + return; +} + +RegisterTaskGenerationFunction("IOTMGrimstoneGenerateTasks"); +void IOTMGrimstoneGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //grimstoneMaskPath + //rumpelstiltskinTurnsUsed gives number of turns used getting materials. rumpelstiltskinKidsRescued gives the number of children rescued. It is likely that there are more messages than are documented on the wiki, so if some are missing and aren't parsed correctly, please put a note in the forum. + //cinderellaMinutesToMidnight gives number of turns remaining. cinderellaScore gives the current score. Also added grimstoneMaskPath which gives the current grimstone content available, "stepmother", "wolf", "witch", "gnome" or "hare". + + string mask_path = get_property("grimstoneMaskPath").to_lower_case(); + + if ($effect[hare-brained].have_effect() > 0) + IOTMGrimstoneHareGenerateTasks(task_entries, optional_task_entries, future_task_entries); + if (mask_path == "stepmother") + IOTMGrimstoneStepmotherGenerateTasks(task_entries, optional_task_entries, future_task_entries); + if (mask_path == "wolf") + IOTMGrimstoneWolfGenerateTasks(task_entries, optional_task_entries, future_task_entries); + if (mask_path == "witch") + IOTMGrimstoneWitchGenerateTasks(task_entries, optional_task_entries, future_task_entries); + if (mask_path == "gnome") + IOTMGrimstoneGnomeGenerateTasks(task_entries, optional_task_entries, future_task_entries); + if (mask_path == "tuxedo") + task_entries.listAppend(ChecklistEntryMake("__item long-stemmed rose", "place.php?whichplace=arcade", ChecklistSubentryMake("Believe in yourself", "", ""), -11).ChecklistEntrySetIDTag("Grimstone mask Sailor Moon reference")); +} + + +RegisterResourceGenerationFunction("IOTMSpeakeasyGenerateResource"); +void IOTMSpeakeasyGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["VIP available"]) + return; + + if (!(__misc_state["can drink just about anything"] && get_property_int("_speakeasyDrinksDrunk") <3 && mafiaIsPastRevision(14155) && availableDrunkenness() >= 0)) + return; + if (!$item[clan speakeasy].is_unrestricted()) + return; + + //speakeasy: + /* + √Lucky lindy - good 1-potency, gives semi-rare. crucial in zombie slayer + Bee's Knees - awesome 2-potency, 25 turns of +100% all stats + √Sockdollager - awesome 2-potency, 25 turns of (+20 all elemental damage, +40 all elemental spell damage, +20 ranged/weapon damage, +50% weapon/spell damage, +50 spell damage + Flivver - 20,000 meat epic 2-potency, restores mana (not useful in-run) + √Hot Socks - awesome 3-potency, 50 turns of (+2 familiar experience, +10 familiar weight, +20 familiar damage) + √Sloppy Jalopy - 100,000 meat awesome 5-potency, gives skill Hollow Leg (+1 liver capacity) for aftercore + Phonus Balonus - +fights/+adventures + Ish Kabibble - +3 all res, +DA/DR + */ + int drinks_remaining = MAX(3 - get_property_int("_speakeasyDrinksDrunk"), 0); + + string [int][int] options; + + options.listAppend(listMake("Drink", "Size", "Description")); + options.listAppend(listMake("Lucky Lindy", "6", "Get Lucky!")); + + //FIXME every drink + //FIXME gray out drinks we can't drink at the moment (drunkenness, meat) + + if ($effect[1701].have_effect() == 0 && !__misc_state["familiars temporarily blocked"] && __misc_state["in run"]) //hip to the jive + { + string [int] description; + description.listAppend("+10 familiar weight"); + if (familiar_weight(my_familiar()) < 20) + description.listAppend("+2 familiar exp/fight"); + options.listAppend(listMake("Hot Socks", "3", description.listJoinComponents("|"))); + } + + if (!__misc_state["in run"] && !$skill[Hollow Leg].skill_is_usable()) + options.listAppend(listMake("Sloppy Jalopy", "5", "+1 liver capacity skill|Very expensive")); + + + string [int] reasons_to_sockdollager; + if (!__quest_state["Level 3"].finished) + { + boolean can_skip_cold = numeric_modifier("Cold Damage") >= 20.0; + boolean can_skip_hot = numeric_modifier("Hot Damage") >= 20.0; + boolean can_skip_spooky = numeric_modifier("Spooky Damage") >= 20.0; + boolean can_skip_stench = numeric_modifier("Stench Damage") >= 20.0; + if (!can_skip_cold || !can_skip_hot || !can_skip_spooky || !can_skip_stench) + reasons_to_sockdollager.listAppend("tavern NC skipping"); + } + + if (!__quest_state["Level 13"].state_boolean["Elemental damage race completed"]) + reasons_to_sockdollager.listAppend("Elemental damage race"); + + if (my_path().id == PATH_HEAVY_RAINS && !__quest_state["Level 13"].finished) + reasons_to_sockdollager.listAppend("fighting rain king"); + + if (reasons_to_sockdollager.count() > 0) + options.listAppend(listMake("Sockdollager", "2", reasons_to_sockdollager.listJoinComponents(", ", "and").capitaliseFirstLetter())); + + if (__misc_state["in run"] && my_meat() >= 20000) + options.listAppend(listMake("Flivver", "2", "Epic-level drunkenness.")); + + if (__misc_state["need to level"]) + { + string drink_name = ""; + + if (my_primestat() == $stat[muscle]) + { + drink_name = "Glass of \"milk\""; + } + else if (my_primestat() == $stat[mysticality]) + { + drink_name = "Cup of \"tea\""; + } + else if (my_primestat() == $stat[moxie]) + { + drink_name = "Thermos of \"whiskey\""; + } + if (drink_name != "") + { + float mainstat_gain = 87.5 * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); + string description = mainstat_gain.roundForOutput(0) + " mainstat"; + //if (my_path().id != PATH_SLOW_AND_STEADY) + //description += ""; + options.listAppend(listMake(drink_name, "1", description)); + } + + } + + if (hippy_stone_broken()) + { + options.listAppend(listMake("Phonus Balonus", "3", "+fights/+adventures")); + } + + if (my_path().id == PATH_NUCLEAR_AUTUMN) + { + foreach key in options + { + if (options[key][1].to_int_silent() > 1) + remove options[key]; + } + } + + string [int] description; + if (options.count() > 1) + description.listAppend(HTMLGenerateSimpleTableLines(options)); + + if (__misc_state["in run"] || drinks_remaining > 0) + resource_entries.listAppend(ChecklistEntryMake("__item observational glasses", "clan_viplounge.php?action=speakeasy", ChecklistSubentryMake(pluralise(drinks_remaining, "speakeasy drink", "speakeasy drinks"), "", description), 8).ChecklistEntrySetIDTag("Clan VIP speakeasy resource")); //the eyes of T.J. Eckleburg + +} +//Spring Break Beach cash register +RegisterTaskGenerationFunction("IOTMSpringBreakBeachGenerateTasks"); +void IOTMSpringBreakBeachGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__misc_state["sleaze airport available"]) + return; + int dinerBucksLeft = clampi(4 - get_property_int("_sloppyDinerBeachBucks"), 0, 4); + string url; + string [int] description; + if (dinerBucksLeft > 0) + { + string title = (dinerBucksLeft + " Sloppy Seconds Diner cash register raids"); + url = "place.php?whichplace=airport_sleaze"; + description.listAppend("Money money money money monay!"); + if (!lookupSkill("sloppy secrets").have_skill()) { + description.listAppend("Learn Sloppy Secrets for more Beach Bucks."); + } + optional_task_entries.listAppend(ChecklistEntryMake("__item beach buck", url, ChecklistSubentryMake(title, "", description), 8)); + } +} + +// 2015 + +RegisterResourceGenerationFunction("IOTMBarrelGodGenerateResource"); +void IOTMBarrelGodGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[shrine to the Barrel god]]) + return; + + + if (!get_property_boolean("_barrelPrayer") && mafiaIsPastRevision(16316)) + { + string [int] description; + string [int][int] gear; + + if (__misc_state["can equip just about any weapon"] && !get_property_boolean("prayedForProtection")) + gear.listAppend(listMake("Protection", "+50 ML, +100 HP, +25% muscle offhand")); + if (!get_property_boolean("prayedForGlamour")) + gear.listAppend(listMake("Glamour", "+50% item, ~8 MP regen, +25% myst accessory")); + if (!get_property_boolean("prayedForVigor")) + gear.listAppend(listMake("Vigor", "+50% init, ~15 HP regen, +25% moxie pants")); + + if (gear.count() > 0) + description.listAppend("Once/ascension gear:|*" + HTMLGenerateSimpleTableLines(gear)); + string buff_description; + if (my_class() == $class[seal clubber]) + buff_description = "+150% weapon damage"; + else if (my_class() == $class[turtle tamer]) + buff_description = "ode-to-booze type for food"; + else if (my_class() == $class[pastamancer]) + buff_description = "+90% item"; + else if (my_class() == $class[sauceror]) + buff_description = "+150% spell damage"; + else if (my_class() == $class[disco bandit]) + buff_description = "+150% ranged damage"; + else if (my_class() == $class[accordion thief]) + buff_description = "ode-to-booze type / +45% booze drops"; + + if (buff_description != "") + description.listAppend(buff_description.capitaliseFirstLetter() + " buff for 50 turns." + ($item[map to the Biggest Barrel].available_amount() == 0 && (my_daycount() >= 7 || !in_ronin()) ? "|Might give the map to the Biggest Barrel." : "")); + + resource_entries.listAppend(ChecklistEntryMake("barrel god", "da.php?barrelshrine=1", ChecklistSubentryMake("Barrel worship", "", description), 8).ChecklistEntrySetIDTag("Barrel God resource")); + } + + item [int] barrels_around; + foreach it in $items[little firkin,normal barrel,big tun,weathered barrel,dusty barrel,disintegrating barrel,moist barrel,rotting barrel,mouldering barrel,barnacled barrel] + { + if (it.item_amount() > 0) + barrels_around.listAppend(it); + } + if (barrels_around.count() > 0) + { + string [int] plurals; + foreach key, it in barrels_around + { + plurals.listAppend(pluralise(it.item_amount(), it)); + } + string url = "inv_use.php?pwd=" + my_hash() + "&whichitem=" + barrels_around[0].to_int() + "&choice=1"; + string [int] description; + description.listAppend(plurals.listJoinComponents(", ", "and") + "."); + resource_entries.listAppend(ChecklistEntryMake("__item " + barrels_around[0], url, ChecklistSubentryMake("Smashable barrels", "", description), 8)); + + } +} +RegisterTaskGenerationFunction("IOTMBarrelGodGenerateTasks"); +void IOTMBarrelGodGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //we could suggest they defeat the barrelmech if they have the map anyways... hmm + if ($item[map to the Biggest Barrel].available_amount() > 0 && (!$item[chest barrel].haveAtLeastXOfItemEverywhere(1) || !$item[barrelhead].haveAtLeastXOfItemEverywhere(1) || !$item[bottoms of the barrel].haveAtLeastXOfItemEverywhere(1))) + { + string [int] description; + description.listAppend("Use map to the Biggest Barrel."); + description.listAppend("To defeat him, deal up to, but not over, 150 HP/round. Otherwise, he'll heal his HP.|You'll also want healing items."); + if ($skill[belch the rainbow].have_skill()) + description.listAppend("Could run -250 ML and cast belch the rainbow over and over, if you've upgraded that."); + if (!in_ronin()) + { + string line = "Could throw chipotle wasabi cilantro aioli repeatedly."; + if ($item[chipotle wasabi cilantro aioli].item_amount() < 22) + line += "|Acquire 22 of them first, though."; + description.listAppend(line); + } + description.listAppend("Can only be fought once a day, until defeated."); + optional_task_entries.listAppend(ChecklistEntryMake("barrel god", "inventory.php?ftext=map+to+the+Biggest+Barrel", ChecklistSubentryMake("Defeat the Barrelmech", "", description), 8).ChecklistEntrySetIDTag("Barrel god biggest fight")); + } +} + +record DOECSummon +{ + string [int] cards; + string reason; +}; + +DOECSummon DOECSummonMake(string [int] cards, string reason) +{ + DOECSummon summon; + summon.cards = cards; + summon.reason = reason; + return summon; +} + +DOECSummon DOECSummonMake(string card, string reason) +{ + string [int] cards; + cards.listAppend(card); + return DOECSummonMake(cards, reason); +} + +void listAppend(DOECSummon [int] list, DOECSummon entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +RegisterResourceGenerationFunction("IOTMDeckOfEveryCardGenerateResource"); +void IOTMDeckOfEveryCardGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[Deck of Every Card]]) + return; + + if (!mafiaIsPastRevision(16018)) + return; + + if (my_path().id == PATH_G_LOVER) return; // cannot use in glover + + int card_summons_left = clampi(15 - get_property_int("_deckCardsDrawn"), 0, 15); + + /* + In-run: + √Sheep - 3 stone wool + √X - The Wheel of Fortune - +100% item for 20 turns + √[mainstat cards] - gain 500 mainstat + √XVI - The Tower - DD key + Professor Plum - lets you make ten crimbo pies under the knoll sign. maybe useful if we have fullness over, like, twenty-five? + √Spare tire/Extra tank - something meatcar outside of knoll, might not be worth it? just summon the 10k card and buy a bus pass (ignoring... maybe surprising fist?) + Fish DNA - acquire a free runaway in... HCO? or any path where that's relevant (not HR) + X of Coins - X * 500 meat - if we have low meat and we've already summoned the mantle... maybe + √[three +mainstat cards] - stat test in the tower + √weapons + + + + Aftercore: + √random cards - fun! + √knife - meat farming + Laboratory - five random potions? ??? + √[monster types] - fight a random monster for factoids + √gift card - sell a draw in the mall to the needy + √IV - The Emperor - until we have outfit + IX - The Hermit - until we have all factoids + + Both: + √ancestral recall / Island - if you have Ancestral Recall, indirectly gives +3 adventures. not useful in S&S + √X of Clubs - +3 PVP fights + √1952 Mickey Mantle - 10k autosell + + Unknown: + X of Diamonds - X * 100 meat - never? maybe ~550 meat on average? even in run... eh... + X of Swords - technically optimal (saw one that gave two SBIPs and an antique machete) but random + + + one card/day/card limit when cheating + */ + + boolean in_run = __misc_state["in run"]; + + DOECSummon [int] summons; + + if (in_run && (__misc_state_int["fat loot tokens needed"] > 0 || (!in_ronin() && __misc_state_int["hero keys missing"] > 0))) + summons.listAppend(DOECSummonMake("XVI - The Tower", "Daily Dungeon key.")); + + + if (my_path().id != PATH_SLOW_AND_STEADY) + { + if ($skill[ancestral recall].skill_is_usable()) + { + summons.listAppend(DOECSummonMake(listMake("Ancestral Recall", "Island"), "+3 adventures via ancestral recall.")); + } + else if (!in_run) + { + summons.listAppend(DOECSummonMake("Ancestral Recall", "Gives +adventure summoning skill.")); + } + } + + if (hippy_stone_broken()) + summons.listAppend(DOECSummonMake("X of Clubs", "+3 PVP fights.")); + + if (in_run) + summons.listAppend(DOECSummonMake("X - The Wheel of Fortune", "+100% item for 20 turns.")); + + if (in_run && __misc_state["need to level"] && my_path().id != PATH_THE_SOURCE) + { + string card_name = "Cardiff"; + if (my_primestat() == $stat[muscle]) + card_name = "XXI - The World"; + else if (my_primestat() == $stat[mysticality]) + card_name = "III - The Empress"; + else if (my_primestat() == $stat[moxie]) + card_name = "VI - The Lovers"; + + summons.listAppend(DOECSummonMake(card_name, "+" + (500 * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0)).floor() + " mainstat.")); + } + + if (in_run && !__quest_state["Level 8"].state_boolean["Past mine"]) + { + int missing_ore = MAX(0, 3 - __quest_state["Level 8"].state_string["ore needed"].to_item().available_amount()); + if (missing_ore > 0) + summons.listAppend(DOECSummonMake("Mine", "One of every ore.")); + } + + if (!in_run && $item[knife].available_amount() == 0) + summons.listAppend(DOECSummonMake("Knife", "+50% meat farming weapon.")); + + if (in_run && $items[lead pipe,rope,wrench,candlestick,knife,revolver].items_missing().count() == 6) + { + /* + Important point on the +stat equipment - there's another card that gives 500 mainstat. So, if that's all you're using the weapon for, you'd need to use it for over 250 fights in a day to be worthwhile. + You can, of course, summon both... but in that situation, there's probably a better summon instead? + + √lead pipe - 1h club. +100% muscle, +50 HP, vanishes at rollover. + Hmm... for muscle classes that don't have familiars? Or seal clubbers? + +100% mainstat is a lot... + √rope - 1h whip. +2 muscle/fight, +10 familiar weight, vanishes at rollover. + Muscle classes. Any class that has a runaway familiar. Maybe just any class that has a familiar? + + √wrench - 1h utensil. +100% spell damage, +50 MP. + For myst classes that don't need stats. + √candlestick - 1h wand. +2 myst/fight, +100% myst, vanishes at rollover. + For myst classes that need stats. + + √knife - 1h knife. +50% meat, +100% moxie, vanishes at rollover. + For moxie classes. Even then... + +100% mainstat is a lot... + √revolver - 1h pistol. +50% init, +2 moxie/fight, vanishes at rollover. + For moxie classes that need stats? Ehh... + */ + DOECSummon [int] weapon_choices; + + + if (my_primestat() == $stat[muscle]) + { + if (!($skill[summon smithsness].skill_is_usable() && my_class() == $class[seal clubber])) + weapon_choices.listAppend(DOECSummonMake("Lead pipe", "+100% muscle, +HP club.")); + //Rope is mentioned elsewhere + } + if (my_primestat() == $stat[mysticality] && !$skill[summon smithsness].skill_is_usable()) + { + weapon_choices.listAppend(DOECSummonMake("Wrench", "+100% spell damage weapon.")); //this will do more damage on average than the candlestick, so it's more worthwhile? (compare capped spells versus scaling spells - spell damage affects saucestorm, +myst doesnt') + //Is the candlestick worth summoning? + if (__misc_state["need to level"]) + weapon_choices.listAppend(DOECSummonMake("Candlestick", "+100% myst, +2 myst/fight weapon. (wrench may be better)")); + } + if (my_primestat() == $stat[moxie] && !$skill[summon smithsness].skill_is_usable()) + { + if ($skill[tricky knifework].skill_is_usable()) + weapon_choices.listAppend(DOECSummonMake("Knife", "+50% meat, +100% moxie knife.")); + if (__misc_state["need to level"] && !$skill[tricky knifework].skill_is_usable()) + weapon_choices.listAppend(DOECSummonMake("Revolver", "+50% init, +2 moxie/fight ranged weapon.")); //ignored for DBs, because of the stat issue mentioned above + } + if (!__misc_state["familiars temporarily blocked"]) + { + //is this worthwhile for non-muscle classes without free runaway familiars? + string line; + line = "+10 familiar weight"; + if (my_primestat() == $stat[muscle] && __misc_state["need to level"]) + line += ", +2 muscle/fight"; + line += " weapon."; + weapon_choices.listAppend(DOECSummonMake("Rope", line)); + } + + foreach key, summon in weapon_choices + { + //FIXME combine? + summons.listAppend(summon); + } + } + + summons.listAppend(DOECSummonMake("1952 Mickey Mantle", "Autosells for 10k.")); + + + if (in_run && my_path().id != PATH_COMMUNITY_SERVICE) + { + int wool_needed = 0; + if (!$location[the hidden park].locationAvailable()) + { + wool_needed += 1; + if ($item[the nostril of the serpent].available_amount() == 0 && !get_property_ascension("lastTempleButtonsUnlock")) + wool_needed += 1; + } + if ($item[stone wool].available_amount() < wool_needed) + { + summons.listAppend(DOECSummonMake("Sheep", "3 stone wool.")); + } + else if ($item[stone wool].available_amount() - wool_needed <= 0 && !get_property_ascension("lastTempleAdventures") && my_path().id != PATH_SLOW_AND_STEADY) + { + summons.listAppend(DOECSummonMake("Sheep", "Stone wool for +3 adventures via temple.")); + } + } + + if (!in_run) + { + int missing_emperor_pieces = missing_outfit_components("The Emperor's New Clothes").count(); + if (missing_emperor_pieces > $item[The Emperor's dry cleaning].available_amount()) + summons.listAppend(DOECSummonMake("IV - The Emperor", "The Emperor's New Clothes outfit.")); + + summons.listAppend(DOECSummonMake("Gift card", "Sell to the needy.")); + + string [int][int] tooltip_table; + tooltip_table.listAppend(listMake("II - The High Priestess", "Hippy")); + tooltip_table.listAppend(listMake("V - The Hierophant", "Dude")); + tooltip_table.listAppend(listMake("VII - The Chariot", "Construct")); + tooltip_table.listAppend(listMake("XII - The Hanged Man", "Orc")); + tooltip_table.listAppend(listMake("XIII - Death", "Undead")); + tooltip_table.listAppend(listMake("XIV - Temperance", "Hobo")); + tooltip_table.listAppend(listMake("XV - The Devil", "Demon")); + tooltip_table.listAppend(listMake("XVII - The Star", "Constellation")); + tooltip_table.listAppend(listMake("XVIII - The Moon", "Horror")); + tooltip_table.listAppend(listMake("The Hive", "Bug")); + tooltip_table.listAppend(listMake("Goblin Sapper", "Goblin")); + tooltip_table.listAppend(listMake("Fire Elemental", "Elemental")); + tooltip_table.listAppend(listMake("Unstable Portal", "Weird")); + tooltip_table.listAppend(listMake("Werewolf", "Beast")); + tooltip_table.listAppend(listMake("Go Fish", "Fish")); + tooltip_table.listAppend(listMake("Plantable Greeting Card", "Plant")); + tooltip_table.listAppend(listMake("Pirate Birthday Card", "Pirate")); + tooltip_table.listAppend(listMake("Christmas Card", "Elf")); + tooltip_table.listAppend(listMake("Suit Warehouse Discount Card", "Penguin")); + tooltip_table.listAppend(listMake("Slimer Trading Card", "Slime")); + tooltip_table.listAppend(listMake("Aquarius Horoscope", "Mer-Kin")); + tooltip_table.listAppend(listMake("Hunky Fireman Card", "Humanoid")); + + buffer tooltip_text; + tooltip_text.append(HTMLGenerateTagWrap("div", "Monster Cards", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); + tooltip_text.append(HTMLGenerateSimpleTableLines(tooltip_table)); + + string title = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Monster card", "r_tooltip_outer_class"); + summons.listAppend(DOECSummonMake(title, "Past factoids.")); + } + + if (in_run && !__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "") + { + stat stat_race_type = __quest_state["Level 13"].state_string["Stat race type"].to_stat(); + string card_name = "Joker"; + effect relevant_effect; + if (stat_race_type == $stat[muscle]) + { + card_name = "XI - Strength"; + relevant_effect = to_effect("1912"); + } + else if (stat_race_type == $stat[mysticality]) + { + card_name = "I - The Magician"; + relevant_effect = to_effect("1911"); + } + else if (stat_race_type == $stat[moxie]) + { + card_name = "0 - The Fool"; + relevant_effect = to_effect("1910"); + } + if (relevant_effect.have_effect() == 0) + summons.listAppend(DOECSummonMake(card_name, "+200% " + stat_race_type.to_lower_case() + " for lair races. (marginal)")); + } + if (!in_run) + { + if (!haveAtLeastXOfItemEverywhere($item[talking spade], 1)) + summons.listAppend(DOECSummonMake("X of Spades", "Solve spade puzzle.")); + if (card_summons_left >= 5) + summons.listAppend(DOECSummonMake("Random card", pluralise(card_summons_left, "luck of the draw", "lucks of the draw") + ".")); + } + + boolean [string] cards_already_drawn = get_property("_deckCardsSeen").split_string("\\|").listInvert(); + + string [int][int] card_table; + if (card_summons_left >= 5) + { + foreach key, summon in summons + { + string [int] valid_cards; + foreach key, card in summon.cards + { + if (!cards_already_drawn[card]) + valid_cards.listAppend(card); + } + if (valid_cards.count() == 0) continue; + card_table.listAppend(listMake(valid_cards.listJoinComponents(" / "), summon.reason)); + } + } + + if ((card_table.count() > 0 || card_summons_left < 5) && card_summons_left > 0) + { + string title; + string [int] description; + + if (card_summons_left >= 5) + { + title = pluralise(card_summons_left / 5, "card drawable", "cards drawable"); + } + else + { + title = pluralise(card_summons_left, "random card summon", "random card summons"); + string line = "Luck of the draw."; + if (in_run) + line += " (may cost turns)"; + description.listAppend(line); + } + + + // Detect replica versus genie classic for the purposes of the URL + string activeDeckID = lookupItem("replica deck of every card").available_amount() > 0 ? "11230" : "8382"; + + if (card_table.count() > 0) + description.listAppend(HTMLGenerateSimpleTableLines(card_table)); + resource_entries.listAppend(ChecklistEntryMake("__item deck of every card", "inv_use.php?cheat=1&pwd=" + my_hash() + "&whichitem="+activeDeckID, ChecklistSubentryMake(title, "", description), 1).ChecklistEntrySetIDTag("Deck of every card resource")); + } +} + +RegisterResourceGenerationFunction("IOTMHauntedDoghouseGenerateResource"); +void IOTMHauntedDoghouseGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["in run"]) + return; + if ($item[tennis ball].available_amount() > 0 && in_ronin() && $item[tennis ball].item_is_usable()) + { + resource_entries.listAppend(ChecklistEntryMake("__item tennis ball", "", ChecklistSubentryMake(pluralise($item[tennis ball]), "", "Free run/banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Haunted doghouse banish")); + } + //I, um, hmm. I guess there's not much to say. Poor lonely file, nearly empty. +} + + + + +static +{ + string [item] __machine_elf_abstractions_description; + + void machineElfAbstractionDescriptionsInit() + { + __machine_elf_abstractions_description[$item[abstraction: motion]] = "+100% init"; + __machine_elf_abstractions_description[$item[abstraction: certainty]] = "+100% item"; + __machine_elf_abstractions_description[$item[abstraction: joy]] = "+10 familiar weight"; + __machine_elf_abstractions_description[$item[abstraction: category]] = "+25% mysticality gains"; + __machine_elf_abstractions_description[$item[abstraction: perception]] = "+25% moxie gains"; + __machine_elf_abstractions_description[$item[abstraction: purpose]] = "+25% muscle gains"; + } + machineElfAbstractionDescriptionsInit(); +} + +//Machine Elf DMT Alert +RegisterTaskGenerationFunction("IOTMMachineElfGenerateTasks"); +void IOTMMachineElfGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + string [int] description; + string url = "place.php?whichplace=dmt"; + int DMTDuplicationAscension = get_property_int("lastDMTDuplication"); + int DMTTimer = get_property_int("encountersUntilDMTChoice"); + if (DMTTimer == 0 && my_ascensions() > DMTDuplicationAscension) + { + description.listAppend("" + HTMLGenerateSpanFont("Item duplication available!", "blue") + ""); + description.listAppend("Copy a PVPable potion, food, drink, or spleen item."); + task_entries.listAppend(ChecklistEntryMake("__item abstraction: comprehension", url, ChecklistSubentryMake("Deep Machine Tunnels noncom ready!", "", description), -11)); + } +} + +RegisterResourceGenerationFunction("IOTMMachineElfFamiliarGenerateResource"); +void IOTMMachineElfFamiliarGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!$familiar[machine elf].familiar_is_usable()) + return; + + string url = "place.php?whichplace=dmt"; + if (my_familiar() != $familiar[machine elf]) + url = "familiar.php"; + int importance = 0; + if (!__misc_state["in run"] || !__misc_state["need to level"]) + importance = 6; + + ChecklistEntry entry; + entry.image_lookup_name = "__familiar machine elf"; + entry.url = url; + entry.tags.id = "Machine elf tunnels resource"; + entry.importance_level = importance; + if (__last_adventure_location == $location[the deep machine tunnels]) + entry.should_highlight = true; + + // Using prefs for this now! Whoo! + int lastDMTDuplication = get_property_int("lastDMTDuplication"); + int encountersUntilDMTChoice = get_property_int("encountersUntilDMTChoice"); + + // Starts every ascension at 5, but is every 50 turns after that first turn #6 dupe. Given + // how long ascensions take and how many turns are likely used in the DMT (read: not many), + // this feels like pretty safe logic as long as we keep the in_run checks in this code. + boolean duplication_nc_probably_visited = encountersUntilDMTChoice > 6 ? true : false; + + // if (!duplication_nc_probably_visited && $location[the deep machine tunnels].turns_spent >= 5) + // Checks that the DMT choice is up and you haven't gotten one this run + if (encountersUntilDMTChoice == 0 && lastDMTDuplication < my_ascensions()) + { + string [int] description; + description.listAppend("Next turn in the DMT. Costs a turn."); + description.listAppend("Copy a PVPable potion, food, drink, or spleen item."); + item [int] suggested_items; + if (suggested_items.count() > 0) + description.listAppend("Possibly " + suggested_items.listJoinComponents(", ", "or") + "."); + entry.subentries.listAppend(ChecklistSubentryMake("Item duplication available", "", description)); + } + + + + int free_fights_remaining = clampi(5 - get_property_int("_machineTunnelsAdv"), 0, 5); + if (free_fights_remaining > 0 && mafiaIsPastRevision(16550)) + { + string [int] description; + string [int] modifiers; + string [int] tasks; + if (my_familiar() != $familiar[machine elf]) + { + tasks.listAppend("bring along your machine elf"); + } + tasks.listAppend("adventure in the machine tunnels"); + string line = tasks.listJoinComponents(", ", "and").capitaliseFirstLetter(); + if (__misc_state["need to level"]) + { + modifiers.listAppend("+" + my_primestat().to_lower_case()); + line += " to gain stats"; + } + line += "."; + description.listAppend(line); + + if (spleen_limit() > 0) + { + //abstraction: sensation -> square monster -> abstraction: motion (+100% init) + //abstraction: thought -> triangle monster -> abstraction: certainty (+100% item) + //abstraction: action -> circle monster -> abstraction: joy (+10 familiar weight) + //FIXME suggest abstraction methods. + item [item] abstraction_conversions; + abstraction_conversions[$item[abstraction: sensation]] = $item[abstraction: motion]; + abstraction_conversions[$item[abstraction: thought]] = $item[abstraction: certainty]; + if (!__misc_state["familiars temporarily blocked"]) + abstraction_conversions[$item[abstraction: action]] = $item[abstraction: joy]; + + monster [item] abstraction_monsters; + abstraction_monsters[$item[abstraction: sensation]] = $monster[Performer of Actions]; + abstraction_monsters[$item[abstraction: thought]] = $monster[Perceiver of Sensations]; + abstraction_monsters[$item[abstraction: action]] = $monster[Thinker of Thoughts]; + + string [monster] monster_descriptions; + monster_descriptions[$monster[Performer of Actions]] = "square"; + monster_descriptions[$monster[Perceiver of Sensations]] = "triangle"; + monster_descriptions[$monster[Thinker of Thoughts]] = "circle"; + + + + foreach source, result in abstraction_conversions + { + string result_description = __machine_elf_abstractions_description[result]; + if (result_description == "") + continue; + if (source.item_amount() == 0) + continue; + + monster m = abstraction_monsters[source]; + string monster_text = monster_descriptions[m] + " monster"; + + string line = "Throw " + source + " at " + monster_text; + if (last_monster() == m) + line = HTMLGenerateSpanOfClass(line, "r_bold"); + line += " for " + result_description + " spleen potion. (50 turns)"; + + description.listAppend(line); + } + if ($item[abstraction: thought].item_amount() == 0) + description.listAppend("Possibly run the machine elf elsewhere first, for transmutable potions."); + } + //entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_fights_remaining, "free elf fight", "free elf fights"), modifiers, description)); + resource_entries.listAppend(ChecklistEntryMake(entry.image_lookup_name, entry.url, ChecklistSubentryMake(pluralise(free_fights_remaining, "free elf fight", "free elf fights"), modifiers, description)).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Machine elf free fights")); + } + if (entry.subentries.count() > 0) + { + resource_entries.listAppend(entry); + } +} + +RegisterResourceGenerationFunction("IOTMMachineElfGenerateResource"); +void IOTMMachineElfGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (in_ronin() && spleen_limit() > 0) + { + boolean [item] useful_abstractions; + + useful_abstractions[$item[abstraction: motion]] = true; + useful_abstractions[$item[abstraction: certainty]] = true; + if (!__misc_state["familiars temporarily blocked"]) + useful_abstractions[$item[abstraction: joy]] = true; + if (__misc_state["need to level"]) + { + if (my_primestat() == $stat[muscle]) + useful_abstractions[$item[abstraction: purpose]] = true; + else if (my_primestat() == $stat[mysticality]) + useful_abstractions[$item[abstraction: category]] = true; + else if (my_primestat() == $stat[moxie]) + useful_abstractions[$item[abstraction: perception]] = true; + } + + string image_name = ""; + ChecklistSubentry [int] abstraction_lines; + foreach it in useful_abstractions + { + if (it.available_amount() == 0 || !it.is_unrestricted()) + continue; + string description = __machine_elf_abstractions_description[it] + ". (50 turns, one spleen)"; + if (image_name == "") + image_name = "__item " + it; + abstraction_lines.listAppend(ChecklistSubentryMake(pluralise(it), "", description)); + } + if (abstraction_lines.count() > 0) + resource_entries.listAppend(ChecklistEntryMake(image_name, "inventory.php?which=1", abstraction_lines, 7).ChecklistEntrySetIDTag("Machine elf abstraction resource")); + } +} + +RegisterResourceGenerationFunction("IOTMMayoClinicGenerateResource"); +void IOTMMayoClinicGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (__misc_state["campground unavailable"]) + return; + if (__campground[$item[portable Mayo Clinic]] == 0 || in_bad_moon()) + return; + + //mayoLevel + int mayo_level = get_property_int("mayoLevel"); + + if (availableFullness() > 0) + { + //stuff: + //Mayonex - food adventures -> blood mayo (???) + //Mayodiol -> one fullness becomes one drunkenness + //Mayostat -> one-fullness same quality restore + //Mayozapine -> increased stat gains + //Mayoflex -> +1 adventure + //Mayo Minder™ -> um... I guess it uses the above things for you. reminds me of buying the autorefueler in EV.. + } + + if (!get_property_boolean("_mayoDeviceRented")) + { + string [int] description; + //sphygmayomanometer - +(20 + mayo_level)% stats + //tomayohawk-style reflex hammer - reusable combat item. stagger, mayo-level sleaze damage + //mayo lance - YR combat item, requires at least one blood mayo + //miracle whip - nice day two/three equip. +50% init, +50% item, +100% meat, +100% wait, I only get one of these a run? + + string line = "Lasts the rest of the day. Can only choose one."; + if (my_meat() < 2500) + line += "|Need at least 2500 meat first."; + description.listAppend(line); + + string [int][int] choices; + + choices.listAppend(listMake("Sphygmayomanometer", "+" + (20 + mayo_level) + "% all stats")); + choices.listAppend(listMake("Tomayohawk-style reflex hammer", "Reusable combat item.|Staggers and deals mayo-level sleaze damage.")); + string lance_description = "Yellow ray. "; + if (__misc_state["yellow ray available"]) + lance_description = "Shorter yellow ray. "; + lance_description += HTMLGenerateDivOfClass("Uses up blood mayo.", "r_word_wrap_group"); + choices.listAppend(listMake("Mayo lance", lance_description)); + + if (!get_property_boolean("mayoWhipRented") && !get_property_boolean("itemBoughtPerAscension8266") && my_path().id != PATH_GELATINOUS_NOOB) + { + choices.listAppend(listMake("Miracle whip", "Weapon, usable " + HTMLGenerateSpanFont("once", "red") + " per run.|+50% item, +100% meat, +50% init.")); + } + description.listAppend(HTMLGenerateSimpleTableLines(choices)); + resource_entries.listAppend(ChecklistEntryMake("__item sphygmayomanometer", "campground.php?action=workshed", ChecklistSubentryMake("Mayo Device Rental", "", description), 8).ChecklistEntrySetIDTag("Mayo clinic device resource")); + } + if (!get_property_boolean("_mayoTankSoaked") && __misc_state["in run"]) + { + string [int] description; + string [int] benefits; + if (my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) + benefits.listAppend("HP restore"); + benefits.listAppend("+2 all resistance"); + description.listAppend("Gives " + benefits.listJoinComponents(", ", "and") + "."); + resource_entries.listAppend(ChecklistEntryMake("__item bubblin' chemistry solution", "campground.php?action=workshed", ChecklistSubentryMake("Mayo Tank Soak", "", description), 8).ChecklistEntrySetIDTag("Mayo clinic tank soak resource")); + } + if ($item[mayo lance].available_amount() > 0) + { + string url = ""; + string [int] description; + int turns_yellow_ray_will_be = clampi(150 - get_property_int("mayoLevel") * 5, 0, 150); + if (get_property_int("mayoLevel") == 0) + { + string line = "Need blood mayo to yellow ray"; + if ($effect[everything looks yellow].have_effect() > 0) + line += " later"; + line += "."; + if (get_property("mayoInMouth") == "") + line += "|Use a mayo packet."; + description.listAppend(line); + if (availableFullness() > 0) + url = "campground.php?action=workshed"; + } + else + { + string line = pluralise(turns_yellow_ray_will_be, "turn", "turns") + " yellow ray"; + if ($effect[everything looks yellow].have_effect() > 0) + line += " later"; + line += ". Affected by mayo level."; + description.listAppend(line); + } + resource_entries.listAppend(ChecklistEntryMake("__item mayo lance", url, ChecklistSubentryMake("Mayo lance", "", description), 8).ChecklistEntrySetIDTag("Mayo clinic mayo lance resource")); + + } +} + +// 2016 + +RegisterResourceGenerationFunction("IOTMClanFloundryGenerateResource"); +void IOTMClanFloundryGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["VIP available"] || !$item[Clan Floundry].is_unrestricted()) + return; + if (!__misc_state["in run"]) + return; + if (my_path().id == PATH_G_LOVER) + return; + + //if (get_property_boolean("_floundryFabricated") || !mafiaIsPastRevision(18000)) + //return; + foreach it in $items[bass clarinet,fish hatchet,carpe,codpiece,troutsers,tunac] + { + if (it.available_amount() > 0) + return; + if (it == $item[none]) + return; + } + + string [int] description; + + string [int][int] equipment; + if (__misc_state["can equip just about any weapon"]) + { + //Bass clarinet: -10% combat, 1h ranged weapon, +100% moxie, -3 MP skill cost, +50 ranged damage, 10 white pixels + string line = "-10% combat, +100% moxie, -3 MP skill cost, +50 ranged damage"; + equipment.listAppend(listMake("Bass clarinet", "ranged weapon", line)); + //Fish hatchet: -10% combat, 1h axe, +100% muscle, +5 familiar weight, +50 weapon damage, +5 bridge progress + line = "-10% combat, +100% muscle, +5 familiar weight, +50 weapon damage"; + if (!__quest_state["Level 9"].state_boolean["bridge complete"]) + line += ", +5 bridge progress"; + equipment.listAppend(listMake("Fish hatchet", "weapon", line)); + } + //Codpiece: acc, -?% combat, +100% myst, +100 max MP, +50 spell damage, 8 bubblin' crudes + equipment.listAppend(listMake("Codpiece", "acc", "-10% combat, +100% myst, +100 max MP, +50 spell damage" + (can_interact() ? "" : ", 8 bubblin' crudes"))); + //Carpe: back, +combat, +50% myst, regen ~8 MP, +50% meat + equipment.listAppend(listMake("Carpe", "back", "+combat, +50% meat, +50% myst, regen ~8 MP")); + //Tunac tunac tun: +combat, shirt, +50% muscle, +25 ML, +25% item + if (__misc_state["Torso aware"]) + { + equipment.listAppend(listMake("Tunac", "shirt", "+combat, +25 ML, +25% item, +50% muscle")); + } + //Troutsers: pants, +50% moxie, +50% pickpocket, +5 all res, +11 prismatic damage + equipment.listAppend(listMake("Troutsers", " pants", "+50% moxie, +50% pickpocket, +5 all res, +11 prismatic damage")); + description.listAppend(HTMLGenerateSimpleTableLines(equipment)); + + + resource_entries.listAppend(ChecklistEntryMake("__item fishy fish", "clan_viplounge.php?action=floundry", ChecklistSubentryMake("Rentable floundry equipment", "", description), 8).ChecklistEntrySetIDTag("Clan floundry resource")); +} + +RegisterTaskGenerationFunction("IOTMDetectiveSchoolGenerateTasks"); +void IOTMDetectiveSchoolGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!mafiaIsPastRevision(17048)) + return; + if (!__iotms_usable[$item[detective school application]]) + return; + + //Should we always mention this in aftercore? + //Hmm... I suppose. + int cases_remaining = clampi(3 - get_property_int("_detectiveCasesCompleted"), 0, 3); + if (cases_remaining > 0) + { + optional_task_entries.listAppend(ChecklistEntryMake("__item noir fedora", "place.php?whichplace=town_wrong&action=townwrong_precinct", ChecklistSubentryMake("Solve " + pluraliseWordy(cases_remaining, "more case", "more cases"), "", "Gives cop dollars."), 5).ChecklistEntrySetIDTag("Detective school daily cases")); + } + if ($items[plastic detective badge,bronze detective badge,silver detective badge,gold detective badge].available_amount() == 0) + { + optional_task_entries.listAppend(ChecklistEntryMake("__item plastic detective badge", "place.php?whichplace=town_wrong&action=townwrong_precinct", ChecklistSubentryMake("Collect your Precinct badge", "", ""), 5).ChecklistEntrySetIDTag("Detective school new badge")); + + } +} + +RegisterResourceGenerationFunction("IOTMDetectiveSchoolGenerateResource"); +void IOTMDetectiveSchoolGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!mafiaIsPastRevision(17048)) + return; + if (!__iotms_usable[$item[detective school application]]) + return; + + //FIXME mention how much more they need to upgrade to the next badge? + if (__misc_state["in run"] && in_ronin()) + { + int cop_dollars_have = $item[cop dollar].available_amount(); + if (cop_dollars_have > 0) + { + string [int] description; + + string [int] buyables; + + string [int] ml_types_can_eat_drink; + if (__misc_state["can eat just about anything"]) + ml_types_can_eat_drink.listAppend("food"); + if (__misc_state["can drink just about anything"]) + ml_types_can_eat_drink.listAppend("drink"); + if (ml_types_can_eat_drink.count() > 0 && cop_dollars_have >= 4) + buyables.listAppend(ml_types_can_eat_drink.listJoinComponents("/")); + if (cop_dollars_have >= 10) + { + buyables.listAppend("a -combat potion (50 turns)"); + } + if (buyables.count() > 0) + description.listAppend("Buy " + buyables.listJoinComponents(", ", "or") + "."); + resource_entries.listAppend(ChecklistEntryMake("__item cop dollar", "shop.php?whichshop=detective", ChecklistSubentryMake(pluralise($item[cop dollar]), "", description), 7).ChecklistEntrySetIDTag("Detective school precinct shop")); + } + } +} + +//Gingerbread City +RegisterTaskGenerationFunction("IOTMGingerbreadCityGenerateTasks"); +void IOTMGingerbreadCityGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[$item[Build-a-City Gingerbread kit]]) return; + + string [int] description; + string [int] GCTurnsLeftdescription; + string [int] trainOptions; + string [int] civicOptions; + string [int] industrialOptions; + string [int] retailOptions; + string url = "place.php?whichplace=gingerbreadcity"; + { + int GingerCityTimer = get_property_int("_gingerbreadCityTurns"); + if (get_property_boolean("_gingerbreadClockAdvanced") == true) { + GingerCityTimer += 5; + //increment gingercity timer by 5 if clock is used + } + + if (GingerCityTimer < 30) + { + if (GingerCityTimer < 9) { + GCTurnsLeftdescription.listAppend(9 - GingerCityTimer + " combats until Noon."); + } + if (GingerCityTimer == 9) + { + trainOptions.listAppend("Look for candy."); + civicOptions.listAppend("Knock over a sprinkle column (+50 sprinkles)."); + if ($item[gingerbread blackmail photos].available_amount() == 1) { + civicOptions.listAppend("Use the photos to blackmail a politician."); + } + if (get_property_int("gingerLawChoice") >= 3) { + industrialOptions.listAppend("Buy a teethpick (1000 sprinkles)."); + } + if (get_property_boolean("gingerRetailUnlocked") == false) { + civicOptions.listAppend("Build a retail district."); + } + if (get_property_boolean("gingerSewersUnlocked") == false) { + civicOptions.listAppend("Build a sewer... district."); + } + if (get_property_boolean("gingerRetailUnlocked") == true) { + retailOptions.listAppend("Buy some stuff (50-500 sprinkles)."); + } + if ($item[fruit-leather negatives].available_amount() == 1) { + retailOptions.listAppend("Develop your fruit-leather negatives."); + } + if (get_property_boolean("gingerNegativesDropped") == true) { + retailOptions.listAppend("Pick up your blackmail photos."); + } + if (trainOptions.count() > 0) { + description.listAppend(HTMLGenerateSpanOfClass("Train Station:", "r_bold") + "|*" + trainOptions.listJoinComponents("|*")); + } + if (civicOptions.count() > 0) { + description.listAppend(HTMLGenerateSpanOfClass("Civic Center:", "r_bold") + "|*" + civicOptions.listJoinComponents("|*")); + } + if (industrialOptions.count() > 0) { + description.listAppend(HTMLGenerateSpanOfClass("Industrial District:", "r_bold") + "|*" + industrialOptions.listJoinComponents("|*")); + } + if (retailOptions.count() > 0) { + description.listAppend(HTMLGenerateSpanOfClass("Retail District:", "r_bold") + "|*" + retailOptions.listJoinComponents("|*")); + } + task_entries.listAppend(ChecklistEntryMake("__item gingerbread house", url, ChecklistSubentryMake("Gingerbread City Noon noncom available!", "", description), -11)); + } + if (GingerCityTimer < 19) { + GCTurnsLeftdescription.listAppend(19 - GingerCityTimer + " combats until Midnight."); + } + if (GingerCityTimer == 19) + { + if (get_property_int("gingerMuscleChoice") < 3) { + int gingerTracksLeft = clampi(3 - get_property_int("gingerMuscleChoice"), 0, 3); + trainOptions.listAppend("Lay some track (" + gingerTracksLeft + " remaining)."); + } + if (get_property_boolean("gingerSubwayLineUnlocked") == true && !get_property_boolean("gingerBlackmailAccomplished") == true) { + trainOptions.listAppend("Get some fruit-leather negatives."); + } + if ($item[teethpick].available_amount() == 1) { + int gingerDigsLeft = clampi(7 - get_property_int("gingerDigCount"), 0, 7); + if (gingerDigsLeft > 4) { + trainOptions.listAppend("Dig up " + pluralise(gingerDigsLeft -4, " green-iced sweet roll", "green-iced sweet rolls") + "."); + } + else if (gingerDigsLeft > 1) { + trainOptions.listAppend("Dig up " + pluralise(gingerDigsLeft -1, " green rock candy", "green rock candies") + "."); + } + else if (gingerDigsLeft == 1) { + trainOptions.listAppend("Dig up a sugar raygun (final)."); + } + } + if (get_property_boolean("_gingerbreadColumnDestroyed") == true) { + civicOptions.listAppend("Fight Judge Fudge to take his gavel " + HTMLGenerateSpanFont("(no other Civic options available)", "red")); + } + if (get_property_boolean("_gingerbreadColumnDestroyed") == false) { + civicOptions.listAppend("Buy some cigarettes (5 sprinkles)."); + civicOptions.listAppend("Buy a counterfeit city (300 sprinkles)."); + if (get_property_int("gingerLawChoice") < 3) { + int gingerStudiesLeft = clampi(3 - get_property_int("gingerLawChoice"), 0, 3); + civicOptions.listAppend("Study digging laws (" + gingerStudiesLeft + " remaining)."); + } + } + if (have_outfit_components("Gingerbread Best")) { + retailOptions.listAppend("Get some ginger wine (free)"); + retailOptions.listAppend("Buy a chocolate sculpture (300 sprinkles)"); + if (!is_wearing_outfit("Gingerbread Best")) { + retailOptions.listAppend(HTMLGenerateSpanFont("Retail District options require Gingerbread Best equipped", "red")); + } + else { + retailOptions.listAppend(HTMLGenerateSpanFont("Gingerbread Best equipped for Retail District options", "blue")); + } + } + if (trainOptions.count() > 0) { + description.listAppend(HTMLGenerateSpanOfClass("Train Station:", "r_bold") + "|*" + trainOptions.listJoinComponents("|*")); + } + if (civicOptions.count() > 0) { + description.listAppend(HTMLGenerateSpanOfClass("Civic Center:", "r_bold") + "|*" + civicOptions.listJoinComponents("|*")); + } + if (industrialOptions.count() > 0) { + description.listAppend(HTMLGenerateSpanOfClass("Industrial District:", "r_bold") + "|*" + industrialOptions.listJoinComponents("|*")); + } + if (retailOptions.count() > 0) { + description.listAppend(HTMLGenerateSpanOfClass("Retail District:", "r_bold") + "|*" + retailOptions.listJoinComponents("|*")); + } + + task_entries.listAppend(ChecklistEntryMake("__item gingerbread house", url, ChecklistSubentryMake("Gingerbread City Midnight noncom available!", "", description), -11)); + } + if (GingerCityTimer > 19) { + GCTurnsLeftdescription.listAppend("No NCs left."); + } + + if (($locations[Gingerbread Train Station,Gingerbread Civic Center,Gingerbread Industrial Zone,Gingerbread Upscale Retail District,Gingerbread Sewers] contains __last_adventure_location) && GingerCityTimer != 9 && GingerCityTimer != 19) + task_entries.listAppend(ChecklistEntryMake("__item gingerbread house", url, ChecklistSubentryMake(30 - GingerCityTimer + " Gingerbread City turns remaining", "", GCTurnsLeftdescription), -11)); + else + if (gingercitytimer == 9) { + GCTurnsLeftdescription.listAppend("Noon NC now!"); + } + if (gingercitytimer == 19) { + GCTurnsLeftdescription.listAppend("Midnight NC now!"); + } + optional_task_entries.listAppend(ChecklistEntryMake("__item gingerbread house", url, ChecklistSubentryMake(30 - GingerCityTimer + " Gingerbread City turns remaining", "", GCTurnsLeftdescription), 10)); + } + } +} + +RegisterTaskGenerationFunction("IOTMIntergnatGenerateTasks"); +void IOTMIntergnatGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + + if (!get_property_boolean("demonSummoned") && __misc_state["in run"] && !__quest_state["Level 13"].state_boolean["king waiting to be freed"] && $familiar[intergnat].familiar_is_usable() && my_path().id != PATH_AVATAR_OF_SNEAKY_PETE) + { + //Should we show this if they aren't using the intergnat? ... Yes? + //demonName12, thin black candle, scroll of ancient forbidden unspeakable evil + string [int] reasons; + if (!get_property("demonName12").contains_text("Neil ") && my_level() < 13) //13 is +50% init... it's kind of useful? But not worth mentioning if they don't have it by this point? + { + reasons.listAppend("learn demon name"); + } + if ($item[thin black candle].available_amount() < 3) + { + if ($item[thin black candle].available_amount() < 2) + reasons.listAppend("collect " + int_to_wordy(3 - $item[thin black candle].available_amount()) + " more thin black candles"); + else + reasons.listAppend("collect One More Thin black candle"); + } + if ($item[scroll of ancient forbidden unspeakable evil].available_amount() == 0) + { + reasons.listAppend("collect a scroll of ancient forbidden unspeakable evil"); + } + if (reasons.count() > 0) + { + string [int] description; + description.listAppend(reasons.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + string url = ""; + string title = "Continue running Intergnat for demon summon"; + if (my_familiar() != $familiar[intergnat]) + { + url = "familiar.php"; + title = "Possibly run Intergnat for demon summon"; + } + //Don't use the intergnat icon, because animation is distracting: + optional_task_entries.listAppend(ChecklistEntryMake("__item thin black candle", url, ChecklistSubentryMake(title, "", description)).ChecklistEntrySetIDTag("Intergnat summon Neil")); + } + } +} + +RegisterResourceGenerationFunction("IOTMIntergnatGenerateResource"); +void IOTMIntergnatGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[infinite BACON machine].available_amount() > 0 && !get_property_boolean("_baconMachineUsed") && mafiaIsPastRevision(16926)) + { + //suggest using it: + resource_entries.listAppend(ChecklistEntryMake("__item infinite BACON machine", "inventory.php?which=3?ftext=infinite+bacon+machine", ChecklistSubentryMake("Infinite BACON machine", "", "100 BACON/day."), 7).ChecklistEntrySetIDTag("Intergnat infinite bacon machine")); + } + if ($item[daily dungeon malware].available_amount() > 0 && __misc_state_int["fat loot tokens needed"] > 0) + { + resource_entries.listAppend(ChecklistEntryMake("__item daily dungeon malware", "da.php", ChecklistSubentryMake("Daily dungeon malware", "", "Use on a daily dungeon monster to gain a fat loot token."), 7).ChecklistEntrySetIDTag("Intergnat daily dungeon malware")); + } + int bacon_amount = $item[BACON].available_amount(); + if (__misc_state["in run"] && bacon_amount > 0 && in_ronin()) + { + /* + Viral video - YR if they don't have one. + Print screen button - Copy, kind of unlimited use. + Daily dungeon malware - It seems very expensive for what it does, but, we could suggest it? + + Gallon of milk - food, though not amazing. The debuff causes issues, but mostly just for the alcove. + */ + coinmaster meme_shop = "Internet Meme Shop".to_coinmaster(); + if (meme_shop != $coinmaster[none]) + { + string [item] bacon_description; + if (!__misc_state["yellow ray available"] & $effect[everything looks yellow].have_effect() == 0 && $item[viral video].item_is_usable()) + bacon_description[$item[Viral video]] = "yellow ray"; + if ($item[print screen button].item_is_usable()) + bacon_description[$item[print screen button]] = "copies a monster"; + if (__misc_state_int["fat loot tokens needed"] > 0) + bacon_description[$item[daily dungeon malware]] = "expensive DD token source"; + if (availableFullness() >= 15) + bacon_description[$item[gallon of milk]] = "lazy/expensive food source. Incurs a debuff"; + + string [int][int] table; + foreach it, item_description in bacon_description + { + int bacon_cost = meme_shop.sell_price(it); + string [int] line; + line.listAppend(it.capitaliseFirstLetter()); + line.listAppend(bacon_cost); + line.listAppend(item_description.capitaliseFirstLetter() + "."); + if (bacon_cost > bacon_amount) + { + foreach key in line + { + line[key] = HTMLGenerateSpanFont(line[key], "grey"); + } + } + table.listAppend(line); + } + if (table.count() > 0) + { + string [int] description; + description.listAppend(HTMLGenerateSimpleTableLines(table)); + + resource_entries.listAppend(ChecklistEntryMake("__item BACON", "shop.php?whichshop=bacon", ChecklistSubentryMake(pluralise($item[BACON]), "", description), 7).ChecklistEntrySetIDTag("Intergnat bacon shop resource")); + } + } + } +} + +//Extra data on monsters. +//We use the convention that $element[none] is physical. +record MonsterData +{ + //An example: Battlie Knight Ghost attack with both hot and physical. + //Useful to know when calculating Shoot Ghost. + boolean [element] basic_attack_elements; + boolean is_protonic_ghost; + float shoot_ghost_hp_attack_percentage; +}; + + +static +{ + MonsterData [monster] __monster_data; + + void initialiseMonsterData() + { + foreach m in $monsters[] + { + MonsterData blank; + __monster_data[m] = blank; + } + + //Now, hardcoded: + //Attack elements: + __monster_data[$monster[Battlie Knight Ghost]].basic_attack_elements = $elements[hot, none]; + __monster_data[$monster[Claybender Sorcerer Ghost]].basic_attack_elements = $elements[spooky, none]; + __monster_data[$monster[Dusken Raider Ghost]].basic_attack_elements = $elements[sleaze,none]; + __monster_data[$monster[Space Tourist Explorer Ghost]].basic_attack_elements = $elements[sleaze,cold,hot,none]; + __monster_data[$monster[Whatsian Commando Ghost]].basic_attack_elements = $elements[sleaze,none]; + + __monster_data[$monster[The ghost of Ebenoozer Screege]].basic_attack_elements = $elements[spooky]; + __monster_data[$monster[The ghost of Lord Montague Spookyraven]].basic_attack_elements = $elements[stench]; + __monster_data[$monster[The ghost of Waldo the Carpathian]].basic_attack_elements = $elements[hot]; + __monster_data[$monster[The Icewoman]].basic_attack_elements = $elements[cold]; + __monster_data[$monster[The ghost of Jim Unfortunato]].basic_attack_elements = $elements[sleaze]; + __monster_data[$monster[The ghost of Sam McGee]].basic_attack_elements = $elements[hot]; + __monster_data[$monster[Emily Koops\, a spooky lime]].basic_attack_elements = $elements[spooky]; + __monster_data[$monster[the ghost of Monsieur Baguelle]].basic_attack_elements = $elements[hot]; + __monster_data[$monster[The ghost of Vanillica "Trashblossom" Gorton]].basic_attack_elements = $elements[stench]; + __monster_data[$monster[the ghost of Oily McBindle]].basic_attack_elements = $elements[sleaze]; + __monster_data[$monster[boneless blobghost]].basic_attack_elements = $elements[spooky]; + __monster_data[$monster[The ghost of Richard Cockingham]].basic_attack_elements = $elements[spooky]; + __monster_data[$monster[The Headless Horseman]].basic_attack_elements = $elements[spooky]; + + __monster_data[$monster[chalkdust wraith]].basic_attack_elements = $elements[none]; + __monster_data[$monster[plaid ghost]].basic_attack_elements = $elements[none,sleaze]; + + //Protonic: + foreach m in $monsters[The ghost of Ebenoozer Screege, Emily Koops\, a spooky lime, the ghost of Monsieur Baguelle, The ghost of Lord Montague Spookyraven, The ghost of Waldo the Carpathian, The Icewoman, The ghost of Jim Unfortunato, The ghost of Sam McGee, The ghost of Vanillica "Trashblossom" Gorton, the ghost of Oily McBindle, boneless blobghost, The ghost of Richard Cockingham, The Headless Horseman] + __monster_data[m].is_protonic_ghost = true; + //We think each protonic monster uses a different HP multiplier. + //Emily and Jim, for instance, do way more damage than everyone else. + //It starts at monster ID 1946, which has 40%, and counts up by 5%. So the actual formula is: + //percentage = 0.05 * (monster_id - 1946) + 0.4 + __monster_data[$monster[boneless blobghost]].shoot_ghost_hp_attack_percentage = 0.45; + __monster_data[$monster[the ghost of Monsieur Baguelle]].shoot_ghost_hp_attack_percentage = 0.5; + __monster_data[$monster[The ghost of Ebenoozer Screege]].shoot_ghost_hp_attack_percentage = 0.65; + __monster_data[$monster[The ghost of Vanillica "Trashblossom" Gorton]].shoot_ghost_hp_attack_percentage = 0.75; + __monster_data[$monster[The ghost of Waldo the Carpathian]].shoot_ghost_hp_attack_percentage = 0.9; + __monster_data[$monster[Emily Koops\, a spooky lime]].shoot_ghost_hp_attack_percentage = 0.95; + + //These are from historical logs: + __monster_data[$monster[the ghost of Oily McBindle]].shoot_ghost_hp_attack_percentage = 0.4; //sleaze + __monster_data[$monster[The Headless Horseman]].shoot_ghost_hp_attack_percentage = 0.55; //spooky + __monster_data[$monster[The Icewoman]].shoot_ghost_hp_attack_percentage = 0.60; //cold + __monster_data[$monster[The ghost of Lord Montague Spookyraven]].shoot_ghost_hp_attack_percentage = 0.70; //stench + __monster_data[$monster[The ghost of Sam McGee]].shoot_ghost_hp_attack_percentage = 0.8; //hot + __monster_data[$monster[The ghost of Richard Cockingham]].shoot_ghost_hp_attack_percentage = 0.85; //spooky + __monster_data[$monster[The ghost of Jim Unfortunato]].shoot_ghost_hp_attack_percentage = 1.0; //sleaze + + } + initialiseMonsterData(); +} + +//Calculations: +float expectedDamageFromGhostAfterCastingShootGhost(monster m) +{ + if (!m.attributes.contains_text("GHOST")) //no ghost + return 0; + /* + Our guess for how shoot ghost works: + After you cast it, the ghost will always hit you. It still uses its regular attacks, with corresponding elements, but always deals a percentage of your maximum HP as damage. Your resistances, DA, and DR apply, as per usual. + Approximate full formula: + damage = (maximum_hp * ghost_specific_multiplier - DR) * resistance * DA + Each ghost has a specific multiplier. We're assuming non-protonic ghosts are 30%. But I've only checked a few. The protonic ones vary. + Oh, and then the monster does 84 damage instead of 80 and you have nooo idea why and you get beaten up. + */ + float percentage_multiplier = 0.3; + if (__monster_data[m].is_protonic_ghost) + { + //Different ghosts have different multipliers: + percentage_multiplier = 0.5; + if (__monster_data[m].shoot_ghost_hp_attack_percentage != 0.0) + percentage_multiplier = __monster_data[m].shoot_ghost_hp_attack_percentage; + } + float expected_damage = ceil(my_maxhp() * percentage_multiplier); + //Apply DR, resistance, and DA, in that order: + //We saw 2940 when we expected 2939. But then we saw 2939. So maybe these ceils do or do not happen. Or it's random rounding. + //Same with expected 4119, obtained 4120 and 4119. Fixed that by switching the order of resistance and damage absorption. So maybe resistance is applied before DA, then rrounded at each step...? + expected_damage = ceil(expected_damage - numeric_modifier("Damage Reduction")); + //Umm... something to note: Battlie Knight Ghosts will attack with hot damage, even though they're spooky aligned. + //Plus, they might just attack with physical damage. + //So, we need to know what types of damage each ghost does. + expected_damage = MAX(1, expected_damage); + if (__monster_data[m].basic_attack_elements.count() > 0 && !(__monster_data[m].basic_attack_elements contains $element[none])) + { + //They do elemental attacks only. Probably a protonic ghost. + float minimum_damage_seen = expected_damage; + //Go through each element: + foreach e in __monster_data[m].basic_attack_elements + { + float resistance = numeric_modifier(e + " resistance"); + if (m == $monster[The ghost of Jim Unfortunato]) //this is a guess + resistance -= 2.0; + if (m == $monster[The ghost of Waldo the Carpathian]) //this is a guess + resistance -= 1.0; + if (m == $monster[The ghost of Lord Montague Spookyraven]) //this is wrong, but I don't know what's correct + resistance -= 1.0; + //FIXME suspect others are the same + resistance = MAX(0, resistance); + + float resistance_percent = resistanceLevelToResistancePercent(resistance);//elemental_resistance(e); + float damage = MAX(1, ceil(expected_damage * (1.0 - resistance_percent / 100.0))); + if (damage < minimum_damage_seen) + minimum_damage_seen = damage; + } + expected_damage = minimum_damage_seen; + } + expected_damage = ceil(expected_damage * (1.0 - damage_absorption_percent() / 100.0)); + return MAX(1, ceil(expected_damage)); +} + + +RegisterTaskGenerationFunction("IOTMProtonicAcceleratorPackGenerateTasks"); +void IOTMProtonicAcceleratorPackGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!$item[protonic accelerator pack].have()) return; + { int nextGhostTurn = get_property_int("nextParanormalActivity"); + int nextGhostTimer = (nextGhostTurn - total_turns_played()); + string [int] description; + string url; + url = invSearch("protonic accelerator pack"); + + if (nextGhostTurn <= total_turns_played()) + { + description.listAppend(HTMLGenerateSpanFont("Who you gonna call? You!", "blue")); + if (!lookupItem("protonic accelerator pack").equipped()) + description.listAppend(HTMLGenerateSpanFont("Equip the protopack first", "red")); + task_entries.listAppend(ChecklistEntryMake("__item protonic accelerator pack", url, ChecklistSubentryMake("It's ghost bustin' time!", "", description), -11)); + } + else + description.listAppend(nextGhostTimer + " adventures until your next protonic ghost."); + optional_task_entries.listAppend(ChecklistEntryMake("__item protonic accelerator pack", url, ChecklistSubentryMake("It's ghost bustin' time... eventually.", "", description), 8)); + } + //Quest: + if (QuestState("questPAGhost").in_progress || get_property("ghostLocation") != "") + { + int priority = 0; + if (__misc_state["in run"]) + priority = -1; + location ghost_location = get_property_location("ghostLocation"); + monster ghost = __protonic_monster_for_location[ghost_location]; + float ml_in_location = ghost_location.monster_level_adjustment_for_location(); + string title = "Defeat the ghost in " + ghost_location; + string [int] description; + string [int] modifiers; + string url = ghost_location.getClickableURLForLocation(); + description.listAppend("Won't cost a turn."); + if ($item[protonic accelerator pack].equipped_amount() > 0) + { + float expected_damage = ghost.expectedDamageFromGhostAfterCastingShootGhost(); + float hp_needed = expected_damage * 3; + + //FIXME initial hit damage + //don't know if expected_damage() will be correct, it isn't always + float initial_hit_damage = ghost.expected_damage(); + float elemental_ml_damage = 0.0; + if (ml_in_location >= 26.0 && ghost.defense_element != $element[none]) + { + //[Monster Attack] * MIN( ( [Bonus ML] - 25 ) / 500 , 1 / 2 ) + //FIXME range. 1.1? + elemental_ml_damage = 1.1 * ghost.base_attack * min(0.5, (ml_in_location - 25.0) / 500.0); + elemental_ml_damage *= 1.0 - elemental_resistance(ghost.defense_element) / 100.0; + elemental_ml_damage = ceil(elemental_ml_damage); + } + hp_needed += elemental_ml_damage + initial_hit_damage; + + if (hp_needed >= my_maxhp()) + { + description.listAppend(HTMLGenerateSpanFont("Do not cast \"shoot ghost\", you won't survive.", "red")); + if (ml_in_location <= 50) + description.listAppend("Or stun the monster for multiple rounds, and cast \"shoot ghost\" three times, then \"trap ghost\"."); + } + else if (hp_needed >= my_hp()) + { + description.listAppend(HTMLGenerateSpanFont("Restore HP", "red") + " to cast \"shoot ghost\"."); + if (ml_in_location <= 50) + description.listAppend("Or stun the monster for multiple rounds, and cast \"shoot ghost\" three times, then \"trap ghost\"."); + } + else + { + description.listAppend("Cast \"shoot ghost\" three times, then \"trap ghost\"."); + } + description.listAppend("After casting \"shoot ghost\", the ghost will deal " + expected_damage.to_int() + " damage/round."); + } + item [int] items_to_equip; + if ($item[protonic accelerator pack].equipped_amount() == 0 && $item[protonic accelerator pack].available_amount() > 0) + { + //Strictly speaking, they don't need the pack equipped to fight the monster, but they won't be able to trap it and get the item. + url = "inventory.php?which=2"; + items_to_equip.listAppend($item[protonic accelerator pack]); + } + if (ghost_location == $location[inside the palindome] && $item[Talisman o' Namsilat].equipped_amount() == 0) + { + if ($item[Talisman o' Namsilat].available_amount() == 0) + { + priority = 10; + description.listAppend("Need Talisman o' Namsilat first."); + } + else + { + url = "inventory.php?which=2"; + items_to_equip.listAppend($item[talisman o' namsilat]); + } + } + if (ghost_location == $location[the skeleton store] && !ghost_location.locationAvailable()) + { + //bone with a price tag on it + if (my_path().id == PATH_NUCLEAR_AUTUMN) + { + if ($item[bone with a price tag on it].available_amount() > 0) + { + url = "inventory.php?ftext=bone+with+a+price+tag+on+it"; + description.listAppend("Use the bone with a price tag on it to unlock the store."); + } + } + else + { + url = "shop.php?whichshop=meatsmith&action=talk"; + description.listAppend("Talk to the meatsmith and start his quest."); + } + } + if (ghost_location == $location[The Overgrown Lot] && !ghost_location.locationAvailable()) + { + //bone with a price tag on it + if (my_path().id == PATH_NUCLEAR_AUTUMN) + { + if ($item[map to a hidden booze cache].available_amount() > 0) + { + url = "inventory.php?ftext=map+to+a+hidden+booze+cache"; + description.listAppend("Use the map to a hidden booze cache to unlock the store."); + } + } + else + { + url = "shop.php?whichshop=doc&action=talk"; + description.listAppend("Talk to Doc Galaktik and start his quest."); + } + } + if (ghost_location == $location[Madness Bakery] && !ghost_location.locationAvailable()) + { + //bone with a price tag on it + if (my_path().id == PATH_NUCLEAR_AUTUMN) + { + if ($item[hypnotic breadcrumbs].available_amount() > 0) + { + url = "inventory.php?ftext=hypnotic+breadcrumbs"; + description.listAppend("Use the hypnotic breadcrumbs to unlock the store."); + } + } + else + { + url = "shop.php?whichshop=armory&action=talk"; + description.listAppend("Talk to Armorer and start his quest."); + } + } + + if (items_to_equip.count() > 0) + description.listAppend("Equip the " + items_to_equip.listJoinComponents(", ", "and") + " first."); + + element [location] elements_to_resist; + elements_to_resist[$location[Cobb's Knob Treasury]] = $element[spooky]; + elements_to_resist[$location[The Haunted Conservatory]] = $element[stench]; + elements_to_resist[$location[The Haunted Gallery]] = $element[hot]; + elements_to_resist[$location[The Haunted Kitchen]] = $element[cold]; + elements_to_resist[$location[The Haunted Wine Cellar]] = $element[sleaze]; + elements_to_resist[$location[The Icy Peak]] = $element[hot]; + elements_to_resist[$location[Inside the Palindome]] = $element[spooky]; + elements_to_resist[$location[Madness Bakery]] = $element[hot]; + elements_to_resist[$location[The Old Landfill]] = $element[stench]; + elements_to_resist[$location[The Overgrown Lot]] = $element[sleaze]; + elements_to_resist[$location[The Skeleton Store]] = $element[spooky]; + elements_to_resist[$location[The Smut Orc Logging Camp]] = $element[spooky]; + elements_to_resist[$location[The Spooky Forest]] = $element[spooky]; + + if (elements_to_resist contains ghost_location) + modifiers.listAppend(HTMLGenerateSpanOfClass("+" + elements_to_resist[ghost_location] + " resist", "r_element_" + elements_to_resist[ghost_location])); + + if (ghost_location != $location[none]) + optional_task_entries.listAppend(ChecklistEntryMake("__item protonic accelerator pack", url, ChecklistSubentryMake(title, modifiers, description), priority).ChecklistEntrySetIDTag("Protonic pack ghost busting task")); + } +} + + +RegisterResourceGenerationFunction("IOTMProtonicAcceleratorPackGenerateResource"); +void IOTMProtonicAcceleratorPackGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[protonic accelerator pack]]) return; + + if (!get_property_boolean("_streamsCrossed") &&__misc_state["in run"] && mafiaIsPastRevision(17085) && my_path().id != PATH_G_LOVER) + { + string [int] description; + string url = "showplayer.php?who=2807390"; //ProtonicBot is a real bot that will steal your turtle mechs at the first sign of defiance. + description.listAppend("+20% stats for 10 turns."); + if ($item[protonic accelerator pack].equipped_amount() == 0) + { + url = "inventory.php?ftext=protonic+accelerator+pack"; + description.listAppend("Equip the protonic accelerator pack first."); + } + resource_entries.listAppend(ChecklistEntryMake("__item protonic accelerator pack", url, ChecklistSubentryMake("Stream crossing", "", description), 8).ChecklistEntrySetIDTag("Protonic pack cross stream")); + } +} + +RegisterResourceGenerationFunction("IOTMSnojoGenerateResource"); +void IOTMSnojoGenerateResource(ChecklistEntry [int] resource_entries) +{ + ChecklistEntry snojo_skill_entry; + if ($skill[Shattering Punch].skill_is_usable() && mafiaIsPastRevision(16617)) + { + int punches_left = clampi(3 - get_property_int("_shatteringPunchUsed"), 0, 3); + if (punches_left > 0) + { + string [int] description; + description.listAppend("Win a fight without taking a turn."); + + + //if (snojo_skill_entry.image_lookup_name == "") + //snojo_skill_entry.image_lookup_name = "__skill shattering punch"; + resource_entries.listAppend(ChecklistEntryMake("__skill shattering punch", "", ChecklistSubentryMake(pluralise(punches_left, "shattering punch", "shattering punches"), "", description), 0).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Snojo shattering punch free kill")); + + } + } + if ($skill[Snokebomb].skill_is_usable() && mafiaIsPastRevision(16599)) + { + int snokes_left = clampi(3 - get_property_int("_snokebombUsed"), 0, 3); + if (snokes_left > 0) + { + string [int] description; + description.listAppend("Free run, 30-turn banish."); + if (snojo_skill_entry.image_lookup_name == "") + snojo_skill_entry.image_lookup_name = "__skill Snokebomb"; + Banish snoke_banish = BanishByName("snokebomb"); + int turns_left_of_banish = snoke_banish.BanishTurnsLeft(); + if (turns_left_of_banish > 0) + { + //is this relevant? we don't describe this for pantsgiving + description.listAppend("Currently used on " + snoke_banish.banished_monster + " for " + pluralise(turns_left_of_banish, "more turn", "more turns") + "."); + } + //snojo_skill_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(snokes_left, "snokebomb", "snokebombs"), "", description)); + resource_entries.listAppend(ChecklistEntryMake("__skill snokebomb", "", ChecklistSubentryMake(pluralise(snokes_left, "snokebomb", "snokebombs"), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Snojo snokebomb banish")); + } + } + + if (snojo_skill_entry.subentries.count() > 0) + { + snojo_skill_entry.importance_level = 6; + if (!__misc_state["in run"]) + snojo_skill_entry.importance_level = 9; + resource_entries.listAppend(snojo_skill_entry); + } + + + //Everything past here is for snojo owners: + if (!__iotms_usable[$item[X-32-F snowman crate]]) + return; + + int fights_remaining = clampi(10 - get_property_int("_snojoFreeFights"), 0, 10); + if (!mafiaIsPastRevision(16598)) + fights_remaining = 0; + if (fights_remaining > 0) + { + item [stat] training_equipment_for_stat; + training_equipment_for_stat[$stat[muscle]] = $item[training belt]; + training_equipment_for_stat[$stat[mysticality]] = $item[training legwarmers]; + training_equipment_for_stat[$stat[moxie]] = $item[training helmet]; + + item [stat] consumable_reward_for_stat; + consumable_reward_for_stat[$stat[muscle]] = $item[ancient medicinal herbs]; + consumable_reward_for_stat[$stat[mysticality]] = $item[ice rice]; + consumable_reward_for_stat[$stat[moxie]] = $item[iced plum wine]; + + string [item] reward_descriptions; + reward_descriptions[$item[training belt]] = "+25 ML accessory"; + reward_descriptions[$item[training helmet]] = "+25% item hat"; + reward_descriptions[$item[training legwarmers]] = "+5 res accessory"; + reward_descriptions[$item[ice rice]] = "epic food"; + reward_descriptions[$item[iced plum wine]] = "epic drink"; + + + string [int] description; + + string setting = get_property("snojoSetting"); + + if (setting == "NONE" || setting == "") + { + description.listAppend("Visit the control console."); + } + + string wins_property = ""; + stat current_stat; + if (setting == "MUSCLE") + { + current_stat = $stat[muscle]; + wins_property = "snojoMuscleWins"; + } + else if (setting == "MOXIE") + { + current_stat = $stat[moxie]; + wins_property = "snojoMoxieWins"; + } + else if (setting == "MYSTICALITY") + { + current_stat = $stat[mysticality]; + wins_property = "snojoMysticalityWins"; + } + + int wins = 0; + if (wins_property != "") + wins = get_property_int(wins_property); + + + int [string] winnings; + if (wins_property != "") + { + winnings["skill scroll"] = 50; + if (reward_descriptions[training_equipment_for_stat[current_stat]] != "") + winnings[reward_descriptions[training_equipment_for_stat[current_stat]]] = 11; + if (consumable_reward_for_stat[current_stat] != $item[none]) + { + int value = ceil(wins.to_float() / 7.0) * 7; + if (value == wins) + value += 7; + winnings[consumable_reward_for_stat[current_stat].to_string()] = MAX(7, value); + } + } + + //Output in order of upcoming appearance: + string [int] winnings_order; + foreach winning in winnings + winnings_order.listAppend(winning); + sort winnings_order by winnings[value]; + + string [int] various_winnings_upcoming; + foreach key, winning in winnings_order + { + int timing = winnings[winning]; + if (wins >= timing) + continue; + int turns_remaining = timing - wins; + if (turns_remaining == 1) + various_winnings_upcoming.listAppend(winning + " next turn"); + else + various_winnings_upcoming.listAppend(winning + " in " + pluralise(turns_remaining, "turn", "turns")); + } + + if (various_winnings_upcoming.count() > 0) + description.listAppend(various_winnings_upcoming.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + + if (setting != "TOURNAMENT" && (!__misc_state["in run"] || wins >= 50)) + { + //Skill scrolls: + string [int] switchables; + if (get_property_int("snojoMuscleWins") < 50 && setting != "MUSCLE") + switchables.listAppend("muscle"); + if (get_property_int("snojoMoxieWins") < 50 && setting != "MOXIE") + switchables.listAppend("moxie"); + if (get_property_int("snojoMysticalityWins") < 50 && setting != "MYSTICALITY") + switchables.listAppend("mysticality"); + if (switchables.count() > 0) + { + string line = "Could switch to " + switchables.listJoinComponents(", ", "or") + " for "; + string additional = ""; + if (wins < 50) + additional = "different "; + if (switchables.count() > 1) + line += additional + "skill scrolls"; + else + line += "a " + additional + "skill scroll"; + line += "."; + description.listAppend(line); + } + } + if (__misc_state["in run"]) + { + //Possible rewards to switch to: + string [int] switchable_options; + foreach s in $stats[muscle,moxie,mysticality] + { + if (s == current_stat) + continue; + item training_equipment = training_equipment_for_stat[s]; + item consumable = consumable_reward_for_stat[s]; + + string [int] acquirable_descriptions; + if (training_equipment.available_amount() == 0 && my_path().id != PATH_GELATINOUS_NOOB) + { + acquirable_descriptions.listAppend("a " + reward_descriptions[training_equipment]); + } + if (s != $stat[muscle] && !(!__misc_state["can drink just about anything"] && s == $stat[moxie]) && !(!__misc_state["can eat just about anything"] && s == $stat[mysticality])) + { + acquirable_descriptions.listAppend(reward_descriptions[consumable]); + } + if (acquirable_descriptions.count() > 0) + switchable_options.listAppend(s.to_string().to_lower_case() + " for " + acquirable_descriptions.listJoinComponents("/")); + } + if (switchable_options.count() > 0) + { + description.listAppend("Could switch to " + switchable_options.listJoinComponents(", ", "or") + "."); + } + } + int importance = 6; + if (__misc_state["in run"]) + importance = 0; + ChecklistSubentry [int] subentries; + subentries.listAppend(ChecklistSubentryMake(pluralise(fights_remaining, "free Snojo fight", "free Snojo fights"), "", description)); + TagGroup tags; + tags.id = "Snojo X-32-F free fights"; + tags.combination = "daily free fight"; + resource_entries.listAppend(ChecklistEntryMake("__item snow suit", "place.php?whichplace=snojo", subentries, tags, importance, $locations[the x-32-f combat training snowman])); + } +} + +void IOTMSourceTerminalGenerateDigitiseTargets(string [int] description) +{ + string [int] potential_targets; + if (!__misc_state["in CS aftercore"]) { + if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) + potential_targets.listAppend("lobsterfrogman"); + if (__quest_state["Level 7"].state_int["alcove evilness"] > 31) + potential_targets.listAppend("modern zmobie"); + if (!__quest_state["Level 8"].state_boolean["Mountain climbed"] && $items[ninja rope,ninja carabiner,ninja crampons].available_amount() == 0 && !have_outfit_components("eXtreme Cold-Weather Gear")) + potential_targets.listAppend("ninja assassin"); + } + //FIXME witchess bishop or knight + if (__iotms_usable[$item[Witchess Set]] && get_property_int("_witchessFights") < 5) + { + string [int] witchess_list; + if (__misc_state["can eat just about anything"]) + witchess_list.listAppend("knight"); + if (__misc_state["can drink just about anything"] && my_path().id != PATH_G_LOVER) + witchess_list.listAppend("bishop"); + if (my_path().id != PATH_G_LOVER) + witchess_list.listAppend("rook"); + potential_targets.listAppend("witchess " + witchess_list.listJoinComponents("/")); + } + if (potential_targets.count() > 0) + description.listAppend("Could target a " + potential_targets.listJoinComponents(", ", "or") + "."); + if (get_property_int("_sourceTerminalDigitizeMonsterCount") >= 2) + description.listAppend("Could re-digitise to reset the window."); +} + +RegisterTaskGenerationFunction("IOTMSourceTerminalGenerateTasks"); +void IOTMSourceTerminalGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (in_bad_moon() || __campground[$item[Source Terminal]] == 0 || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + return; + if (!mafiaIsPastRevision(17011)) + return; + ChecklistSubentry [int] subentries; + + boolean [string] chips = getInstalledSourceTerminalSingleChips(); + //Learn extract/a skill if we don't have one: + boolean [skill] skills_have = getActiveSourceTerminalSkills(); + int skill_limit = 1; + if (chips["DRAM"]) + skill_limit = 2; + int skills_need = skill_limit - skills_have.count(); + if (skills_need > 0 && my_path().id != PATH_POCKET_FAMILIARS) + { + //FIXME this could be rewritten to suggest turbo + compress, when we have enough extractions. + string [int] possible_skills; + if (!skills_have[$skill[Extract]]) + possible_skills.listAppend("Extract"); + if (!skills_have[$skill[Turbo]]) + possible_skills.listAppend("Turbo"); + + string linker = "or"; + if (skills_need > 1) + linker = "and"; + subentries.listAppend(ChecklistSubentryMake("Learn " + pluralise(skills_need, "skill", "skills"), "", "Maybe " + possible_skills.listJoinComponents(", ", linker) + ".")); + } + + //Set an enquiry: + if (get_property("sourceTerminalEnquiry") == "" && my_path().id != PATH_G_LOVER) + { + //familiar - +5 familiar weight + //monsters - +25 ML (in-run) + //protect - +3 all res (?) + //stats - +all stats (in-run) + string [int][int] enquiries; + if (!__misc_state["familiars temporarily blocked"]) + enquiries.listAppend(listMake("familiar.enq", "+5 familiar weight")); + if (__misc_state["in run"]) + { + enquiries.listAppend(listMake("monsters.enq", "+25 ML")); + enquiries.listAppend(listMake("stats.enq", "+100% stats")); + } + string [int] description; + + if (chips["DIAGRAM"] && get_property_int("sourceTerminalGram") >= 10) + description.listAppend("200 turn buff gained at rollover."); + else //gram chips are mysterious + description.listAppend("Buff gained at rollover."); + foreach key in enquiries + { + description.listAppend(enquiries[key][0] + ": " + enquiries[key][1]); + } + subentries.listAppend(ChecklistSubentryMake("Set an enquiry", "", description)); + } + //"Digitise something" like arrow something? + if (get_property_int("_sourceTerminalDigitizeUses") == 0 && __misc_state["in run"] && my_path().id != PATH_ZOMBIE_SLAYER && my_path().id != PATH_LIVE_ASCEND_REPEAT && my_path().id != PATH_POCKET_FAMILIARS) + { + string [int] description; + IOTMSourceTerminalGenerateDigitiseTargets(description); + subentries.listAppend(ChecklistSubentryMake("Digitise a monster", "", description)); + } + //Complicated, since we have three uses, and those are sort of resources... + //Maybe suggest the first use, and always list in resources for the rest. + //"Upgrade your source terminal" suggestions? Chips, essentially. + + string url = "campground.php?action=terminal"; + if (my_path().id == PATH_NUCLEAR_AUTUMN) + url = "place.php?whichplace=falloutshelter&action=vault_term"; + if (subentries.count() > 0) + optional_task_entries.listAppend(ChecklistEntryMake("__item source essence", url, subentries, 5).ChecklistEntrySetIDTag("Source terminal task")); +} + +RegisterResourceGenerationFunction("IOTMSourceTerminalGenerateResource"); +void IOTMSourceTerminalGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (in_bad_moon() || __campground[$item[Source Terminal]] == 0 || my_path().id == PATH_ACTUALLY_ED_THE_UNDYING) + return; + + boolean [string] chips = getInstalledSourceTerminalSingleChips(); + //sourceTerminalChips, sourceTerminalPram, sourceTerminalGram, sourceTerminalSpam + ChecklistSubentry [int] subentries; + //Enhancement buffs: + int enhancement_limit = 1; + if (chips["CRAM"]) //CRAM chip installed + enhancement_limit += 1; + if (chips["SCRAM"]) //SCRAM chip installed + enhancement_limit += 1; + int enhancements_remaining = clampi(enhancement_limit - get_property_int("_sourceTerminalEnhanceUses"), 0, enhancement_limit); + if (enhancements_remaining > 0 && mafiaIsPastRevision(17011)) + { + int turn_duration = 25; //up to 100 + if (chips["INGRAM"]) + turn_duration += 25; + turn_duration += get_property_int("sourceTerminalPram") * 5; + turn_duration = clampi(turn_duration, 25, 100); + string turns_description = " (" + turn_duration + " turns)"; + string [int] description; + if (my_path().id != PATH_G_LOVER) + description.listAppend("items.enh: +30% item." + turns_description); + if (my_path().id != PATH_G_LOVER) + description.listAppend("meat.enh: +60% meat." + turns_description); + if (__misc_state["in run"] && my_path().id != PATH_G_LOVER) + description.listAppend("init.enh: +50% init." + turns_description); + if (my_path().id == PATH_G_LOVER) + description.listAppend("damage.enh: +5 prismatic damage, only usable buff in this path." + turns_description); + //the others are moderately boring + //+critical hit? niche + //+all elemental damage? useful in two places, but still niche enough to not be put here + //substats.enh is probably less than 150 mainstat. that's not a lot... +item is much more useful + subentries.listAppend(ChecklistSubentryMake(pluralise(enhancements_remaining, "source enhancement", "source enhancements") + " remaining", "", description)); + } + + int total_duplicate_uses_available = 1; + if (my_path().id == PATH_THE_SOURCE) + total_duplicate_uses_available = 5; + int duplicate_uses_remaining = clampi(total_duplicate_uses_available - get_property_int("_sourceTerminalDuplicateUses"), 0, total_duplicate_uses_available); + if (!mafiaIsPastRevision(17062)) + { + duplicate_uses_remaining = 1; + if (get_property_boolean("_sourceTerminalDuplicateUsed")) + duplicate_uses_remaining = 0; + } + if (my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_POCKET_FAMILIARS) + duplicate_uses_remaining = 0; + if (mafiaIsPastRevision(17031) && duplicate_uses_remaining > 0 && __misc_state["in run"] && my_path().id != PATH_G_LOVER) + { + //Duplication of a monster: + string [int] description; + boolean [skill] skills_have = getActiveSourceTerminalSkills(); + + string line = "Doubles"; + if (my_path().id == PATH_THE_SOURCE) + line = "Triples"; + string times = "once/day"; + if (total_duplicate_uses_available > 1) + times = total_duplicate_uses_available.int_to_wordy() + " times/day"; + line += " item drops from a monster, " + times + ".|Makes them stronger, so be careful."; + description.listAppend(line); + if (!skills_have[$skill[Duplicate]]) + { + description.listAppend("Learn with command \"educate duplicate.edu\"."); + } + + string [int] potential_targets; + //FIXME grey out if the area isn't available? + if ($item[goat cheese].available_amount() < 2 && !__quest_state["Level 8"].state_boolean["Past mine"]) + potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("dairy goat", $location[the goatlet])); + /*if (!__quest_state["Level 11"].finished && !__quest_state["Level 11 Palindome"].finished && $item[talisman o' namsilat].available_amount() == 0 && $items[gaudy key,snakehead charrrm].available_amount() < 2) + potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("gaudy pirate", $location[belowdecks])); //now obsolete*/ + if (my_path().id == PATH_THE_SOURCE) + { + //5x copies + //LFM, filthworms, evil eyes, tomb rats?, star monsters, Green Ops Soldier? + //FIXME actually test for these + potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("lobsterfrogman", $location[sonofa beach])); + potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("filthworms", $location[the hatching chamber])); + potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("defiled nook?", $location[the defiled nook])); + potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("tomb rats?", $location[the middle chamber])); + potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("hedge trimmers", $location[twin peak])); + potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("hole-in-the-sky monsters", $location[the hole in the sky])); + potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("green ops soldier", $location[the battlefield (frat uniform)])); + if (in_hardcore()) + potential_targets.listAppend(HTMLGenerateFutureTextByLocationAvailability("bloopers?", $location[8-bit realm])); + if (__iotms_usable[$item[Witchess Set]] && get_property_int("_witchessFights") < 5) + potential_targets.listAppend("witchess bishop/knight/rooks?"); + } + if (potential_targets.count() > 0) + description.listAppend("Could use on a " + potential_targets.listJoinComponents(", ", "or") + "."); + if (lookupItem("exploding cigar").item_amount() > 0) + description.listAppend("Use exploding cigar immediately after to win the fight."); + string title = "Duplication castable"; + if (total_duplicate_uses_available > 1) + { + title = pluralise(duplicate_uses_remaining, "duplication", "duplications"); + } + + subentries.listAppend(ChecklistSubentryMake(title, "", description)); + } + //Portscans: (the source) + int portscans_remaining = clampi(3 - get_property_int("_sourceTerminalPortscanUses"), 0, 3); + if (mafiaIsPastRevision(17031) && portscans_remaining > 0 && my_path().id == PATH_THE_SOURCE) + { + //Should we suggest portscan outside of the source? + //It's three scaling monsters a day, that can make one government potion/run, if optimally used in delay-burning areas. Otherwise, they're +turncount for no reason. + //So, do we give advice that's easy to get wrong? + + string [int] description; + description.listAppend("Cast to summon an agent next turn. Make sure to use it to burn delay."); + if (my_path().id == PATH_THE_SOURCE) + description.listAppend("To use optimally, cast once. Then set your autoattack to portscan, and adventure in a delay-burning area.|This will chain the agents, causing them to cost a single turn."); + if (get_property_int("sourceInterval") != 0 && my_path().id == PATH_THE_SOURCE) + description.listAppend("Wait a bit, this is better after an agent had just appeared."); + + subentries.listAppend(ChecklistSubentryMake(pluralise(portscans_remaining, "portscan", "portscans") + " remaining", "", description)); + + } + //Extrudes: + int extrudes_remaining = clampi(3 - get_property_int("_sourceTerminalExtrudes"), 0, 3); + + if (extrudes_remaining > 0 && mafiaIsPastRevision(16992) && my_path().id != PATH_ZOMBIE_SLAYER && my_path().id != PATH_POCKET_FAMILIARS && my_path().id != PATH_G_LOVER) + { + int essence = $item[source essence].available_amount(); + string [int] description; + if (__misc_state["can eat just about anything"] && my_path().id != PATH_NUCLEAR_AUTUMN) + { + string line = "Food: 4 fullness epic."; + if (essence < 10) + line = HTMLGenerateSpanFont(line, "grey"); + description.listAppend(line); + } + if ((my_path().id == PATH_LICENSE_TO_ADVENTURE || __misc_state["can drink just about anything"]) && my_path().id != PATH_NUCLEAR_AUTUMN) + { + string line = "Drink: 4 inebriety epic."; + if (__misc_state["in run"]) + line += " Useful nightcap."; + if (essence < 10) + line = HTMLGenerateSpanFont(line, "grey"); + description.listAppend(line); + } + if (!__misc_state["in run"]) + { + //In aftercore, suggest chips we don't have. Also the shades. + if ($item[source shades].available_amount() == 0 && essence >= 100) + description.listAppend("Source Shades: extra essence extracted when equipped."); + if (!$familiar[software bug].have_familiar() && essence >= 10000) + description.listAppend("Software bug: pet rock."); + string [int] chips_missing; + foreach s in $strings[CRAM,DRAM,TRAM] + { + if (!chips[s]) + chips_missing.listAppend(s); + } + if (get_property_int("sourceTerminalGram") < 10) + chips_missing.listAppend("GRAM"); + if (get_property_int("sourceTerminalPram") < 10) + chips_missing.listAppend("PRAM"); + if (get_property_int("sourceTerminalSpam") < 10) + chips_missing.listAppend("SPAM"); + if (chips_missing.count() > 0) + description.listAppend("Chip upgrades: " + chips_missing.listJoinComponents(", ", "or") + "."); + } + if (essence == 0 && __misc_state["in run"]) + { + boolean have_extract_skill = true; + if (!have_extract_skill) + description.listAppend("Learn and use the extract skill in combat for more essence."); + else + description.listAppend("Use the extract skill in combat for more essence."); + } + + subentries.listAppend(ChecklistSubentryMake(pluralise(extrudes_remaining, "source extrude", "source extrudes") + " remaining", "", description)); + } + //Digitise? + int digitisations = get_property_int("_sourceTerminalDigitizeUses"); + int digitisation_limit = 1; + if (chips["TRAM"]) + digitisation_limit += 1; + if (chips["TRIGRAM"]) + digitisation_limit += 1; + if (my_path().id == PATH_ZOMBIE_SLAYER || my_path().id == PATH_LIVE_ASCEND_REPEAT || my_path().id == PATH_POCKET_FAMILIARS) + digitisation_limit = 0; + int digitisations_left = clampi(digitisation_limit - digitisations, 0, 3); + if (digitisations_left > 0) + { + string [int] description; + string monster_name = get_property("_sourceTerminalDigitizeMonster").to_lower_case(); + if (monster_name != "") + description.listAppend("Currently set to " + monster_name + "."); + IOTMSourceTerminalGenerateDigitiseTargets(description); + + subentries.listAppend(ChecklistSubentryMake(pluralise(digitisations_left, "digitisation", "digitisations") + " remaining", "", description)); + } + string url = "campground.php?action=terminal"; + if (my_path().id == PATH_NUCLEAR_AUTUMN) + url = "place.php?whichplace=falloutshelter&action=vault_term"; + if (subentries.count() > 0) + resource_entries.listAppend(ChecklistEntryMake("__item source essence", url, subentries, 5).ChecklistEntrySetIDTag("Source terminal resource")); +} + +record LocationChoice +{ + location place; + string [int] reasons; + int importance; +}; + +LocationChoice LocationChoiceMake(location place, string [int] reasons, int importance) +{ + LocationChoice result; + result.place = place; + result.reasons = reasons; + result.importance = importance; + return result; +} + +LocationChoice LocationChoiceMake(location place, string reason, int importance) +{ + return LocationChoiceMake(place, listMake(reason), importance); +} + +LocationChoice LocationChoiceMake(location place, string reason) +{ + return LocationChoiceMake(place, reason, 0); +} + +void listAppend(LocationChoice [int] list, LocationChoice entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void LocationChoiceSort(LocationChoice [int] list) +{ + sort list by value.importance; +} + +string [int] LocationChoiceGenerateDescription(LocationChoice [int] list) +{ + string [int] description; + foreach key in list + { + LocationChoice lc = list[key]; + string [int] explanation = lc.reasons; + + if (explanation.count() == 0) + continue; + string first = lc.place.to_string(); + if (lc.place == $location[none]) + first = ""; + + string line; + if (explanation.count() > 1) + { + line = first + HTMLGenerateIndentedText(HTMLGenerateDiv(explanation.listJoinComponents("
"))); + } + else + { + line = listFirstObject(explanation); + if (line.stringHasPrefix("|") || first == "") + line = first + line; + else + line = first + ": " + line; + } + //string line = first + HTMLGenerateIndentedText(HTMLGenerateDiv(explanation.listJoinComponents(HTMLGenerateDivOfStyle("", "border-top:1px solid;width:30%;")))); + if (!locationAvailable(lc.place) && lc.place != $location[none]) + { + line = HTMLGenerateDivOfClass(line, "r_future_option"); + } + description.listAppend(line); + } + return description; +} + +RegisterTaskGenerationFunction("IOTMTelegraphOfficeGenerateTasks"); +void IOTMTelegraphOfficeGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[$item[LT&T telegraph office deed]]) + return; + + + if ($item[your cowboy boots].available_amount() == 0) + { + optional_task_entries.listAppend(ChecklistEntryMake("__item your cowboy boots", "place.php?whichplace=town_right", ChecklistSubentryMake("Acquire your cowboy boots", "", "Visit the LT&T office."), 0).ChecklistEntrySetIDTag("Telegraph office LT&T cowboy boots")); + + } + + + if (!mafiaIsPastRevision(16674)) + return; + + QuestState ltt_quest = QuestState("questLTTQuestByWire"); + + if (!ltt_quest.in_progress) + return; + + int difficulty = get_property_int("lttQuestDifficulty"); + int stage_count = get_property_int("lttQuestStageCount"); + string quest_name = get_property("lttQuestName"); + if (quest_name == "") + return; + + //step1 - the investigation begins + //step2 - The Investigation Continues + //step3 - The Investigation Continues + //step4 - boss fight + + int turns_completed = stage_count; + if (ltt_quest.mafia_internal_step > 2) + turns_completed += 10; + if (ltt_quest.mafia_internal_step > 3) + turns_completed += 10; + if (ltt_quest.mafia_internal_step > 4) + turns_completed += 10; + //quest_name is blank when not on the quest + int turns_remaining = clampi(29 - turns_completed, 0, 29); + //"Missing: Many Children" - clara + //"Wagon Train Escort Wanted" - Granny Hackleton + //"Madness at the Mine" - unusual construct + + monster [string] boss_for_quest; + + boss_for_quest["Missing: Fancy Man"] = $monster[Jeff the Fancy Skeleton]; + boss_for_quest["Help! Desperados!"] = $monster[Pecos Dave]; + boss_for_quest["Missing: Pioneer Daughter"] = $monster[Daisy the Unclean]; + + boss_for_quest["Big Gambling Tournament Announced"] = $monster[Snake-Eyes Glenn]; + boss_for_quest["Haunted Boneyard"] = $monster[Pharaoh Amoon-Ra Cowtep]; + boss_for_quest["Sheriff Wanted"] = $monster[Former Sheriff Dan Driscoll]; + + boss_for_quest["Missing: Many Children"] = $monster[Clara]; + boss_for_quest["Wagon Train Escort Wanted"] = $monster[Granny Hackleton]; + boss_for_quest["Madness at the Mine"] = $monster[unusual construct]; + + + + string [int] description; + string [int] modifiers; + if (turns_remaining > 0) + description.listAppend(pluraliseWordy(turns_remaining, "more turn", "more turns").capitaliseFirstLetter() + " until the boss."); + if (turns_remaining == 0 || ltt_quest.mafia_internal_step == 5) + { + string url = "inventory.php?ftext=plaintive+telegram"; + monster boss = boss_for_quest[quest_name]; + if (boss == $monster[none]) + description.listAppend("Defeat the boss."); + else + description.listAppend("Defeat " + boss + "."); + boolean frigidalmatian_eligible = false; + if (boss == $monster[Clara]) + { + modifiers.listAppend("+elemental resistance"); + description.listAppend("Use high-damage spells, like shrap + snow mobile/green lantern."); + frigidalmatian_eligible = true; + } + else if (boss == $monster[Granny Hackleton]) + { + description.listAppend("Use different high-damage combat items, or frigidalmatian and attack."); + //FIXME suggest a list of combat items to use + frigidalmatian_eligible = true; + } + else if (boss == $monster[unusual construct]) + { + description.listAppend("Each round, you have to respond with the correct shiny disc to survive. Mafia will select the correct one.|Maybe funksling with new-age hurting crystals."); + frigidalmatian_eligible = true; + } + else if (boss == $monster[Jeff the Fancy Skeleton]) + { + description.listAppend("Attack with a blunt weapon. (clubs, flails, saucepans...)"); + description.listAppend("Combat items won't work, skills are mostly blocked."); + } + else if (boss == $monster[Pecos Dave]) + { + description.listAppend("Attack with multiple sources of damage."); + if ($item[wicker slicker].available_amount() > 0 && $skill[shell up].have_skill()) + { + if ($item[wicker slicker].equipped_amount() > 0) + description.listAppend("Shell up on alternate rounds?"); + else + description.listAppend("Equip wicker slicker and shell up on alternate rounds?"); + } + frigidalmatian_eligible = true; + } + else if (boss == $monster[Daisy the Unclean]) + { + //FIXME + } + else if (boss == $monster[Snake-Eyes Glenn]) + { + description.listAppend("Immune to all but a single element type each round.|Previous round's second roll indicates which."); + } + else if (boss == $monster[Pharaoh Amoon-Ra Cowtep]) + { + description.listAppend("Avoid attacking with spell damage."); + } + else if (boss == $monster[Former Sheriff Dan Driscoll]) + { + description.listAppend("Acquire passive damage (glowing syringes?), attack repeatedly."); + frigidalmatian_eligible = true; + } + + // This already existed but it was in the wrong ash file lol. + string image_name = "__monster " + boss; + task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake("Defeat " + boss + "!", modifiers, description), -11)); + + if (frigidalmatian_eligible) + { + string [int] tasks; + boolean frigidalmatian_obtainable = false; + if ($effect[frigidalmatian].have_effect() > 0) + frigidalmatian_obtainable = true; + if ($effect[frigidalmatian].have_effect() == 0 && $skill[frigidalmatian].have_skill()) + { + frigidalmatian_obtainable = true; + tasks.listAppend("cast frigidalmatian"); + } + if (frigidalmatian_obtainable && $items[rain-doh green lantern,snow mobile].equipped_amount() == 0) + { + if ($item[rain-doh green lantern].available_amount() > 0) + { + tasks.listAppend("equip rain-doh green lantern"); + } + else if (lookupItems("meteorb,metal meteoroid").available_amount() > 0) + { + tasks.listAppend("equip meteorb"); + } + else if ($item[snow mobile].is_unrestricted()) + { + if ($item[snow mobile].available_amount() > 0) + { + tasks.listAppend("equip snow mobile"); + } + else + tasks.listAppend("acquire and equip snow mobile"); + } + } + if (tasks.count() > 0) + description.listAppend(tasks.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + } + } + + if (false) + { + foreach s in $strings[lttQuestDifficulty,lttQuestStageCount,lttQuestName,questLTTQuestByWire] + description.listAppend(s + " = " + get_property(s)); + } + + ChecklistEntry entry = ChecklistEntryMake("__item sea cowboy hat", "inventory.php?ftext=plaintive+telegram", ChecklistSubentryMake(quest_name, modifiers, description), $locations[Investigating a Plaintive Telegram]); + entry.tags.id = "Telegraph office LT&T quest"; + if (__misc_state["in run"]) + future_task_entries.listAppend(entry); + else + optional_task_entries.listAppend(entry); +} + +RegisterResourceGenerationFunction("IOTMTelegraphOfficeGenerateResource"); +void IOTMTelegraphOfficeGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (__misc_state["in run"] && $item[Clara's bell].available_amount() > 0 && !get_property_boolean("_claraBellUsed")) + { + string [int] description; + description.listAppend("Ring for a non-combat next turn, once/day."); + + LocationChoice [int] options; + + //√spooky forest - unlocking the hidden temple + //6 - advance one of the quest areas + //7 - defiled cranny + //8 - umm... maybe the extreme slow? unimportant? + //9 - twin peak + //10 - top/bottom of the castle, best place in the game(?) + //11 - copperhead, protestors, fun hidden city exploit, hidden temple but marginal, palindome but marginal, pyramid in situations where you can't run lots of +item, poop deck, haunted billiards room, haunted bathroom + //12 - starting the war(??) + + //2 - mosquito - not terribly important + //3 - tavern - forces a skippable NC, not important + + if (!get_property_ascension("lastTempleUnlock")) + { + //options.listAppend("") + options.listAppend(LocationChoiceMake($location[the spooky forest], "unlocking the hidden temple")); + } + + if (my_path().id == PATH_COMMUNITY_SERVICE) + { + foreach key in options + remove options[key]; + } + + if (options.count() > 0) + { + description.listAppend("Suggested areas:|*" + LocationChoiceGenerateDescription(options).listJoinComponents("|*")); + } + + + resource_entries.listAppend(ChecklistEntryMake("__item clara's bell", "inventory.php?ftext=clara's+bell", ChecklistSubentryMake("Clara's Bell", "", description), 5).ChecklistEntrySetIDTag("LT&T claras bell resource")); + } + + //skills: + //Bow-Legged Swagger -> _bowleggedSwaggerUsed + //Bend Hell -> _bendHellUsed + //Steely-Eyed Squint -> _steelyEyedSquintUsed + //bend hell - double elemental damage/elemental spell damage + if (true) + { + string [skill] telegraph_skill_properties; + if (__misc_state["in run"]) + { + telegraph_skill_properties[$skill[Bow-Legged Swagger]] = "_bowleggedSwaggerUsed"; + telegraph_skill_properties[$skill[Bend Hell]] = "_bendHellUsed"; + } + telegraph_skill_properties[$skill[Steely-Eyed Squint]] = "_steelyEyedSquintUsed"; + + string [skill] telegraph_skill_descriptions; + telegraph_skill_descriptions[$skill[Bow-Legged Swagger]] = "Double +initiative and physical damage. Once/day."; + telegraph_skill_descriptions[$skill[Bend Hell]] = "Double elemental damage/elemental spell damage. Once/day."; + telegraph_skill_descriptions[$skill[Steely-Eyed Squint]] = "Double +item. Once/day."; + + string image_name; + ChecklistSubentry [int] subentries; + foreach s, property in telegraph_skill_properties + { + if (!s.skill_is_usable()) + continue; + if (get_property_boolean(property)) + continue; + + if (image_name == "") + image_name = "__skill " + s; + subentries.listAppend(ChecklistSubentryMake(s + " castable", "", telegraph_skill_descriptions[s])); + } + if (subentries.count() > 0) + resource_entries.listAppend(ChecklistEntryMake(image_name, "skillz.php", subentries, 9).ChecklistEntrySetIDTag("LT&T daily cowboy skills resource")); + } +} + +RegisterResourceGenerationFunction("IOTMThanksgardenGenerateResource"); +void IOTMThanksgardenGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["in run"]) + return; + + item turkey_blaster = $item[turkey blaster]; + item stuffing_fluffer = $item[stuffing fluffer]; + item cashew = $item[cashew]; + item cornucopia = $item[cornucopia]; + + ChecklistSubentry [int] subentries; + string url; + string image_name; + TagGroup tags; + tags.id = "Campground thanksgarden cornucopia resource"; + + + + if (cornucopia.available_amount() > 0 && in_ronin()) + { + string [int] description; + description.listAppend("Open for thanksgarden food."); + if (image_name == "") + image_name = "__item cornucopia"; + if (url == "") + url = "inventory.php?ftext=cornucopia"; + subentries.listAppend(ChecklistSubentryMake(pluralise(cornucopia), "", description)); + } + int cashew_amount = cashew.available_amount(); + if (cashew_amount > 0 && in_ronin()) + { + string [int] description; + string [int] options; + //so creatable_amount() is weird, so we perform the calculation ourselves + /* + > ash $item[cashew].available_amount() + + Returned: 13 + + > ash $item[turkey blaster].creatable_amount() + + Returned: 0 + */ + if (my_path().id != PATH_NUCLEAR_AUTUMN && spleen_limit() > 0 && $item[cashew].available_amount() >= 3) + options.listAppend(HTMLGreyOutTextUnlessTrue(pluralise($item[cashew].available_amount() / 3, $item[turkey blaster]) + " to burn delay", cashew_amount >= 3)); + if (!__quest_state["Level 12"].finished) + options.listAppend(HTMLGreyOutTextUnlessTrue(pluralise($item[cashew].available_amount() / 3, $item[stuffing fluffer]) + " for the war", cashew_amount >= 3)); + if (my_path().id != PATH_NUCLEAR_AUTUMN && fullness_limit() > 0) + options.listAppend("various foods"); + if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"] && $item[gravy boat].available_amount() == 0) + options.listAppend(HTMLGreyOutTextUnlessTrue("gravy boat for the cyrpt (somewhat marginal)", cashew_amount >= 3)); + if (options.count() > 0) + description.listAppend("Could make into " + options.listJoinComponents(", ", "or") + "."); + + string [int] foods_we_can_make; + + if (image_name == "") + image_name = "__item cashew"; + if (url == "") + url = "shop.php?whichshop=thankshop"; + subentries.listAppend(ChecklistSubentryMake(pluralise(cashew), "", description)); + } + + if (turkey_blaster.available_amount() > 0 && my_path().id != PATH_NUCLEAR_AUTUMN) + { + string [int] description; + int uses_left = clampi(3 - get_property_int("_turkeyBlastersUsed"), 0, 3); + int pre_spleen_uses_left = uses_left; + uses_left = MIN(uses_left, availableSpleen() / 2); + + string [int] delay_areas; + foreach l in $locations[the outskirts of cobb's knob,the spooky forest,The Castle in the Clouds in the Sky (Ground Floor),the haunted gallery,the haunted bathroom,the haunted ballroom,the boss bat's lair] + { + if (l.delayRemainingInLocation() > 1) + delay_areas.listAppend(l); + } + + description.listAppend("Will burn five turns of delay in the last area you've adventured."); + if (delay_areas.count() > 0) + description.listAppend("Suggested areas:|*" + delay_areas.listJoinComponents(", ", "and") + "."); + if (uses_left == 0) + { + if (pre_spleen_uses_left > 0) + description.listAppend("Cannot use any more today; no spleen room."); + else + description.listAppend("Cannot use any more today."); + } + else + description.listAppend("Can use " + pluraliseWordy(uses_left, "more time", "more times") + " today."); + + + if (image_name == "") + image_name = "__item turkey blaster"; + if (url == "") + url = "inventory.php?ftext=turkey+blaster"; + subentries.listAppend(ChecklistSubentryMake(pluralise(turkey_blaster), "", description)); + } + if (!__quest_state["Level 12"].finished && __quest_state["Level 12"].state_int["frat boys left on battlefield"] > 0 && __quest_state["Level 12"].state_int["hippies left on battlefield"] > 0 && stuffing_fluffer.available_amount() > 0) + { + string [int] description; + description.listAppend("Clears out level twelve armies. Use before adventuring on the battlefield."); + + if (image_name == "") + image_name = "__item stuffing fluffer"; + if (url == "") + url = "inventory.php?ftext=stuffing+fluffer"; + subentries.listAppend(ChecklistSubentryMake(pluralise(stuffing_fluffer), "", description)); + } + + + if (subentries.count() > 0) + { + resource_entries.listAppend(ChecklistEntryMake(image_name, url, subentries, tags, 4)); + } + +} + +RegisterTaskGenerationFunction("IOTMThanksgardenGenerateTasks"); +void IOTMThanksgardenGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + int delay_limit = 4; + if (get_property_int("_turkeyBlastersUsed") < 3 && availableSpleen() >= 2 && $item[turkey blaster].available_amount() + $item[turkey blaster].creatable_amount() > 0 && get_property_location("lastAdventure").delayRemainingInLocation() >= delay_limit) + { + string url = ""; + if ($item[turkey blaster].available_amount() > 0) + url = "inventory.php?ftext=turkey+blaster"; + else + url = "shop.php?whichshop=thankshop"; + location last_location = get_property_location("lastAdventure"); + string [int] description; + description.listAppend("Save " + MIN(5, last_location.delayRemainingInLocation()) + " turns in " + last_location + "."); + if (my_level() < 4) + description.listAppend("Reach level four first."); + boolean allow = true; + if ($locations[the penultimate fantasy airship,the hidden office building,the hidden apartment building] contains last_location) + allow = false; + if (allow) + task_entries.listAppend(ChecklistEntryMake("__item turkey blaster", url, ChecklistSubentryMake("Chew turkey blaster", "", description), -11).ChecklistEntrySetIDTag("Campground thanksgarden turkey blaster resource")); + } +} + +RegisterResourceGenerationFunction("IOTMTimeSpinnerGenerateResource"); +void IOTMTimeSpinnerGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!mafiaIsPastRevision(17209)) + return; + //Warn about eating if they're low on turns - you can't use the time spinner when you're out of adventures. + if (!__iotms_usable[$item[Time-Spinner]]) return; + int minutes_left = clampi(10 - get_property_int("_timeSpinnerMinutesUsed"), 0, 10); + if (minutes_left <= 0) + return; + + string [int] description; + + if (minutes_left >= 3) + { + //Recent fight - 3 minutes - fight something past. Umm... hmm... same as any monster you copy? Though with restrictions. Plus olfaction-lite in NA. + int amount = minutes_left / 3; + description.listAppend(HTMLGenerateSpanOfClass(pluralise(amount, "recent fight", "recent fights"), "r_bold") + ": Re-fight a monster this ascension."); + //Delicious meal - 3 minutes + if (__misc_state["can eat just about anything"] && availableFullness() > 0) + { + description.listAppend(HTMLGenerateSpanOfClass(pluralise(amount, "meal", "meals"), "r_bold") + ": Re-eat something else today."); + } + } + //Way back in time - 1 minute, stats, costs a turn(?) + if (minutes_left >= 2) + { + //Visit the far future - 2 minutes, star-trek mini-game, lets you replicate things. Script fodder. + if (!get_property_boolean("_timeSpinnerReplicatorUsed")) + { + string [int] options; + if (__misc_state["can eat just about anything"] && availableFullness() > 0) + options.listAppend("epic food"); + if (__misc_state["can drink just about anything"] && availableDrunkenness() > 0) + options.listAppend("drink"); + if (!in_ronin()) + options.listAppend("something to sell"); + if (my_path().id == PATH_GELATINOUS_NOOB && !lookupSkill("Pathological Greed").have_skill() && $item[shot of Kardashian Gin].available_amount() == 0) + { + options.listAppend("Kardashian Gin for +meat skill"); + } + if (options.count() == 0) + options.listAppend("item"); + description.listAppend(HTMLGenerateSpanOfClass("Future", "r_bold") + ": once/day " + options.listJoinComponents(" / ") + "."); + } + } + //Play a time prank - 1 minute, heart + + resource_entries.listAppend(ChecklistEntryMake("__item Time-Spinner", "inv_use.php?whichitem=9104&pwd=" + my_hash(), ChecklistSubentryMake(pluralise(minutes_left, "Time-Spinner minute", "Time-Spinner minutes"), "", description), 5).ChecklistEntrySetIDTag("Time-spinner resource")); +} + +RegisterResourceGenerationFunction("IOTMWitchessGenerateResource"); +void IOTMWitchessGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[Witchess Set]]) + return; + if (!mafiaIsPastRevision(16813)) + return; + + string image_name = ""; + ChecklistSubentry [int] subentries; + if (get_property_int("_witchessFights") < 5) + { + string [int] description; + int fights_remaining = clampi(5 - get_property_int("_witchessFights"), 0, 5); + + string [int][int] fight_descriptions; + //fight_descriptions.listAppend(listMake(HTMLGenerateSpanOfClass("Piece", "r_bold"), HTMLGenerateSpanOfClass("Drop", "r_bold"))); + if (__misc_state["in run"]) + { + //√pawn - +50% init potion for moderns + if (__quest_state["Level 7"].state_boolean["alcove needs speed tricks"] && $item[armored prawn].available_amount() == 0 && $item[armored prawn].to_effect().have_effect() == 0 && my_path().id != PATH_G_LOVER) + { + fight_descriptions.listAppend(listMake("Pawn", "+50% init spleen potion.")); + } + //rook - +ML / +stat potion + if (my_path().id != PATH_G_LOVER) + fight_descriptions.listAppend(listMake("Rook", "+25 ML/+statgain potion. (25 turns)")); + //ox - shield + if ($item[ox-head shield].available_amount() == 0 && $item[ox-head shield].item_is_usable()) + fight_descriptions.listAppend(listMake("Ox", "+100HP, +2 all res, +8 PVP fights shield.")); + //king - club + if ((my_path().id == PATH_COMMUNITY_SERVICE || my_primestat() == $stat[muscle]) && $item[dented scepter].available_amount() == 0 && $item[dented scepter].item_is_usable()) + fight_descriptions.listAppend(listMake("King", "+5 muscle stats/fight, +50% muscle, +50% weapon damage club.")); + //queen - -combat hat + if ($item[very pointy crown].available_amount() == 0 && $item[very pointy crown].item_is_usable()) + fight_descriptions.listAppend(listMake("Queen", "-combat, +5 adventures, +50% moxie, +5 moxie stats/fight hat.|Queen is exceptionally difficult to defeat, probably requiring deleveling via items" + ($skill[tricky knifework].have_skill() ? ", or maybe knife tricks" : "") + ".")); + //witch - myst broom + if ((my_path().id == PATH_COMMUNITY_SERVICE || my_primestat() == $stat[mysticality]) && $item[battle broom].available_amount() == 0 && $item[battle broom].item_is_usable()) + fight_descriptions.listAppend(listMake("Witch", "+5 myst stats/fight, +50% myst, +100% spell damage accessory.|Immune to spells, but not skills.")); + } + //knight - epic food, +meat drop + if (__misc_state["can eat just about anything"]) + { + fight_descriptions.listAppend(listMake("Knight", "+100% meat epic food.")); + } + //bishop - epic drink, +50% item + if (__misc_state["can drink just about anything"] && my_path().id != PATH_G_LOVER) + { + fight_descriptions.listAppend(listMake("Bishop", "+50% item epic drink.")); + } + + if (fight_descriptions.count() > 0) + { + //Bold the piece names: + foreach key in fight_descriptions + { + fight_descriptions[key][0] = HTMLGenerateSpanOfClass(fight_descriptions[key][0], "r_bold"); + } + description.listAppend(HTMLGenerateSimpleTableLines(fight_descriptions)); + } + + image_name = "__itemsize __monster Witchess Pawn"; + //subentries.listAppend(ChecklistSubentryMake(pluralise(fights_remaining, "witchess fight", "witchess fights"), "", description)); + resource_entries.listAppend(ChecklistEntryMake(image_name, "campground.php?action=witchess", ChecklistSubentryMake(pluralise(fights_remaining, "witchess fight", "witchess fights"), "", description)).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Witchess set free fights")); + } + if (!get_property_boolean("_witchessBuff") && mafiaIsPastRevision(16879) && !__misc_state["familiars temporarily blocked"] && $effect[puzzle champ].effect_is_usable()) + { + int familiar_weight_modifier = MAX(5, get_property_int("puzzleChampBonus")); + if (image_name == "") + image_name = "__effect Puzzle Champ"; + subentries.listAppend(ChecklistSubentryMake("Witchess buff", "", "+" + familiar_weight_modifier + " familiar weight. (25 turns)")); + //resource_entries.listAppend(ChecklistEntryMake("__effect Puzzle Champ", "campground.php?action=witchess", ChecklistSubentryMake("Witchess buff", "", "+" + familiar_weight_modifier + " familiar weight. (25 turns)"), 4)); + } + if (subentries.count() > 0) + resource_entries.listAppend(ChecklistEntryMake(image_name, "campground.php?action=witchess", subentries, 4).ChecklistEntrySetIDTag("Witchess set resource")); +} + + +// 2017 + + +RegisterTaskGenerationFunction("IOTMAsdonMartinGenerateTasks"); +void IOTMAsdonMartinGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[lookupItem("Asdon martin keyfob")]) + return; + //BanishIsActive + if (!BanishIsActive("Spring-Loaded Front Bumper") && __misc_state["in run"] && (my_path().id != PATH_POCKET_FAMILIARS || (__iotms_usable[$item[source terminal]] && __iotms_usable[lookupItem("FantasyRealm membership packet")]))) + { + string description = "Banish" + (__misc_state["free runs usable"] ? "/free run" : "") + ", "; + + string fuel = "costs 50 fuel."; + if (get_fuel() < 50) + { + description += HTMLGenerateSpanFont(fuel, "red"); + description += "|" + HTMLGenerateSpanFont("Fuel up to 50 first.", "red"); + } + else + description += fuel; + if (my_path().id == PATH_POCKET_FAMILIARS) + description += "|In FantasyRealm, where you can extract for consumables."; + task_entries.listAppend(ChecklistEntryMake("__item Asdon Martin keyfob", "campground.php?action=fuelconvertor", ChecklistSubentryMake("Cast Spring-Loaded Front Bumper", "", description), -11).ChecklistEntrySetIDTag("Asdon front bumper reminder")); + } +} + +RegisterResourceGenerationFunction("IOTMAsdonMartinGenerateResource"); +void IOTMAsdonMartinGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[lookupItem("Asdon martin keyfob")]) + return; + ChecklistEntry entry; + entry.importance_level = 0; + entry.tags.id = "Asdon Martin resource"; + if (__misc_state["in run"] && in_ronin()) + { + item [int] fuelables = asdonMartinGenerateListOfFuelables(); + if (fuelables.count() > 0) + { + string [int] fuelables_extended; + string [int] fuelables_extended_part_2; + foreach key, fuelable in fuelables + { + int creatable_amount = fuelable.creatable_amount(); + string line; + line = " ("; + line += (fuelable.averageAdventuresForConsumable() * (creatable_amount + fuelable.item_amount())).round(); + if (fuelable.item_amount() == 0) + { + if (fuelable.craft_type() == "Summon Clip Art") continue; + line += ", "; + boolean first = true; + foreach it, amount in fuelable.get_ingredients_fast() + { + if (first) + first = false; + else + line += " + "; + if (amount > 1) + line += amount + " "; + line += it; + } + } + line += ")"; + line = fuelable.to_string() + HTMLGenerateSpanOfClass(line, "r_cl_modifier_inline"); + + string desired_colour = ""; + if (fuelable.quality == "EPIC") + desired_colour = "blueviolet"; + else if (fuelable.quality == "awesome") + desired_colour = "blue"; + else if (fuelable.quality == "good") + desired_colour = "green"; + else if (fuelable.quality == "crappy") + desired_colour = "#999999"; + boolean cannot_consume_anyways = false; + if (!__misc_state["can eat just about anything"] && fuelable.fullness > 0) + cannot_consume_anyways = true; + if (!__misc_state["can drink just about anything"] && fuelable.inebriety > 0 && !(my_path().id == PATH_LICENSE_TO_ADVENTURE && fuelable.image == "martini.gif")) + cannot_consume_anyways = true; + if (!fuelable.is_unrestricted()) + cannot_consume_anyways = true; + if (cannot_consume_anyways) + desired_colour = "#999999"; + if (desired_colour != "") + line = HTMLGenerateSpanFont(line, desired_colour); + if (key >= 0 && true) + { + fuelables_extended_part_2.listAppend(line); + //break; + } + else + fuelables_extended.listAppend(line); + } + string [int] description; + if (fuelables_extended_part_2.count() > 0) + { + //fuelables_extended.listAppend("(...)"); + int estimated_margin = fuelables_extended_part_2.count() * 1.2; + fuelables_extended.listAppend(HTMLGenerateSpanOfClass(HTMLGenerateTagWrap("span", fuelables_extended_part_2.listJoinComponents("
"), mapMake("class", "r_tooltip_inner_class r_tooltip_inner_class_margin", "style", "margin-top:-" + estimated_margin + "em;margin-left:-5em;")) + "Fuel list.", "r_tooltip_outer_class") + ($item[loaf of soda bread].creatable_amount() > 0 ? "|Or create and feed loaf of soda breads." : "")); + } + else if ($item[loaf of soda bread].creatable_amount() > 0) + description.listAppend("Or create and feed loaf of soda breads."); + //description.listAppend(HTMLGenerateSpanOfClass(HTMLGenerateTagWrap("span",HTMLGenerateSimpleTableLines(table, false), mapMake("class", "r_tooltip_inner_class r_tooltip_inner_class_margin", "style", "margin-top:-" + estimated_margin + "em;margin-left:-5em;")) + "Costs one spleen and two candies.", "r_tooltip_outer_class")); + //description.listAppend("Could fuel with:|*" + fuelables_extended.listJoinComponents("|*", "")); + description.listAppend(fuelables_extended.listJoinComponents("|*", "")); + entry.subentries.listAppend(ChecklistSubentryMake(get_fuel() + " Fuel", "", description)); + if (entry.url == "") + entry.url = "campground.php?action=fuelconvertor"; + if (entry.image_lookup_name == "") + entry.image_lookup_name = "__item Asdon Martin keyfob"; + } + } + if (!get_property_boolean("_missileLauncherUsed") && my_path().id != PATH_POCKET_FAMILIARS && my_path().id != PATH_G_LOVER) + { + if (entry.image_lookup_name == "") + entry.image_lookup_name = "__skill asdon martin: missile launcher"; + if (entry.url == "") + entry.url = "campground.php?action=workshed"; + string fuel_costs = "Costs 100 fuel"; + if (get_fuel() < 100) + fuel_costs = HTMLGenerateSpanFont(fuel_costs, "red"); + resource_entries.listAppend(ChecklistEntryMake("__item Asdon Martin keyfob", "campground.php?action=workshed", ChecklistSubentryMake("Asdon Missile", "", fuel_costs + ", instakill + YR-equivalent.")).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Asdon Martin missile launcher")); + //entry.subentries.listAppend(ChecklistSubentryMake("Asdon Missile", "", fuel_costs + ", instakill + YR-equivalent.")); + } + if (BanishIsActive("Spring-Loaded Front Bumper")) + { + Banish b = BanishByName("Spring-Loaded Front Bumper"); + int turns_left = b.banish_turn_length - (my_turncount() - b.turn_banished); + + if (turns_left > 0 && turns_left <= 30) + { + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(turns_left, "turn", "turns") + " to next asdon bumper", "", "Banish/runaway.")); + if (entry.image_lookup_name == "") + entry.image_lookup_name = "__item Asdon Martin keyfob"; + } + if (entry.url == "") + entry.url = "campground.php?action=workshed"; + } + if (entry.subentries.count() > 0) + { + resource_entries.listAppend(entry); + } +} + +RegisterResourceGenerationFunction("IOTMGenieBottleGenerateResource"); +void IOTMGenieBottleGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (lookupItem("genie bottle").item_amount() + lookupItem("pocket wish").item_amount() + lookupItem("replica genie bottle").item_amount() == 0) return; + + // Detect replica versus genie classic for the purposes of the URL + string activeGenieID = lookupItem("replica genie bottle").available_amount() > 0 ? "11234" : "9529"; + + int wishes_left = 0; + + // Add up all possible wish sources; pocket wishes, replicas, and genie bottles + if (__misc_state["in run"] && in_ronin()) + wishes_left += lookupItem("pocket wish").item_amount(); + if (lookupItem("genie bottle").item_amount() > 0 && mafiaIsPastRevision(18219) && my_path().id != PATH_BEES_HATE_YOU) + wishes_left += clampi(3 - get_property_int("_genieWishesUsed"), 0, 3); + if (lookupItem("replica genie bottle").item_amount() > 0) + wishes_left += clampi(3 - get_property_int("_genieWishesUsed"), 0, 3); + + string [int] description; + + if (wishes_left > 0) + { + + activeGenieID = get_property_int("_genieWishesUsed") >= 3 ? "9537" : activeGenieID; + + // URL to the correct genie as per activeGenieID + string url = "inv_use.php?pwd=" + my_hash() + "&whichitem=" + activeGenieID; + + boolean [monster] invalid_monsters = $monsters[ninja snowman assassin, modern zmobie, giant swarm of ghuol whelps, screambat, monstrous boiler]; + string potential_monsters = SFaxGeneratePotentialFaxes(true, invalid_monsters).listJoinComponents("|
"); + if (potential_monsters != "") + description.listAppend("Could fight a monster:
" + potential_monsters); + resource_entries.listAppend(ChecklistEntryMake("__item genie bottle", url, ChecklistSubentryMake(pluralise(wishes_left, "wish", "wishes"), "", description), 1).ChecklistEntrySetIDTag("Genie bottle resource")); + } +} + +RegisterResourceGenerationFunction("IOTMKGBriefcaseGenerateResource"); +void IOTMKGBriefcaseGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[lookupItem("kremlin's greatest briefcase")]) return; + ChecklistEntry entry; + entry.image_lookup_name = "__item Kremlin's Greatest Briefcase"; + entry.importance_level = 5; + entry.url = "place.php?whichplace=kgb"; + entry.tags.id = "Kremlin Briefcase resource"; + if (get_property_int("_kgbTranquilizerDartUses") < 3 && my_path().id != PATH_POCKET_FAMILIARS) + { + string [int] description; + description.listAppend("Free run, 20-turn banish.|Use the KGB tranquilizer dart skill in-combat."); + if (lookupItem("kremlin's greatest briefcase").equipped_amount() == 0) + { + description.listAppend(HTMLGenerateSpanFont("Equip the briefcase first!", "red")); + entry.url = "inventory.php?ftext=kremlin"; + } + resource_entries.listAppend(ChecklistEntryMake("__item Kremlin's Greatest Briefcase", entry.url, ChecklistSubentryMake(pluralise(3 - get_property_int("_kgbTranquilizerDartUses"), "briefcase dart", "briefcase darts"), "", description),0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Kremlin Briefcase tranq dart banish")); + } + int clicks_remaining = clampi(22 - get_property_int("_kgbClicksUsed"), 0, 22); + if (!mafiaIsPastRevision(18110)) + clicks_remaining = 0; + if (clicks_remaining > 0) + { + string [int] description; + description.listAppend("All sorts of things. Buffs, martinis, cigars!"); + entry.url = "place.php?whichplace=kgb"; + + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(clicks_remaining, "click", "clicks"), "", description)); + } + if (entry.subentries.count() > 0) + resource_entries.listAppend(entry); +} + + +//_macrometeoriteUses +//_meteorShowerUses +RegisterResourceGenerationFunction("IOTMMeteorLoreGenerateResource"); +void IOTMMeteorLoreGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupSkill("Meteor Lore").have_skill()) + return; + if (!__misc_state["in run"]) return; + if (!mafiaIsPastRevision(18174)) return; + if (my_path().id == PATH_G_LOVER) return; + + ChecklistEntry entry; + entry.image_lookup_name = "__skill Meteor Lore"; + entry.tags.id = "Meteor lore resource"; + entry.importance_level = 3; + if (get_property_int("_macrometeoriteUses") < 10) + { + int macrometeorite_uses_remaining = clampi(10 - get_property_int("_macrometeoriteUses"), 0, 10); + string [int] description; + description.listAppend("Reroll a monster to another in the area."); + + string [int] useful_places; + if (spleen_limit() > 0 && lookupFamiliar("space jellyfish").familiar_is_usable() && get_property_int("_spaceJellyfishDrops") < 4 && my_path().id != PATH_LIVE_ASCEND_REPEAT) + { + string line = "stench monster area"; + if ($location[Pirates of the Garbage Barges].locationAvailable()) + line += " (garbage pirates)"; + line += " - extract stench jelly repeatedly, with the space jellyfish"; + useful_places.listAppend(line); + } + if (!__quest_state["Level 11 Palindome"].finished && get_property_int("palindomeDudesDefeated") < 5) + useful_places.listAppend("inside the palindome"); + if (!__quest_state["Level 11 Manor"].finished && __quest_state["Level 11 Manor"].mafia_internal_step < 4 && $items[wine bomb, unstable fulminate].available_amount() == 0) + useful_places.listAppend("haunted laundry room / haunted wine cellar"); + useful_places.listAppend("anywhere you olfact and get the wrong monster" + (($item[time-spinner].available_amount() > 0) ? ", unless time-spinning" : "")); + + if (useful_places.count() > 0 && my_path().id != PATH_COMMUNITY_SERVICE) + description.listAppend("Reroll:|*-" + useful_places.listJoinComponents("|*-")); + + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(macrometeorite_uses_remaining, "macrometeorite", "macrometeorites"), "", description)); + } + if (get_property_int("_meteorShowerUses") < 5 && !__misc_state["familiars temporarily blocked"]) + { + int meteor_shower_uses_remaining = clampi(5 - get_property_int("_meteorShowerUses"), 0, 5); + + string [int] description; + description.listAppend("+200% weapon/spell damage, +20 familiar weight, for a single fight."); + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(meteor_shower_uses_remaining, "meteor shower", "meteor showers"), "", description)); + } + if (lookupItem("metal meteoroid").available_amount() > 0 && in_ronin()) + { + string [int] description; + description.listAppend("Craft into useful equipment."); + + string [item] item_descriptions; + item_descriptions[lookupItem("meteorb")] = "spell damage x2, like a lantern"; + item_descriptions[lookupItem("meteorthopedic shoes")] = "+5 adventures/day, +30% init, +15% moxie"; + item_descriptions[lookupItem("asteroid belt")] = "+10 ML, deflects attacks"; + //shooting morning star - 15% muscle tower test + //meteorthopedic shoes - 15% moxie tower test + //meteortarboard - 15% myst tower test + if (!__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "") + { + + stat stat_race_type = __quest_state["Level 13"].state_string["Stat race type"].to_stat(); + if (stat_race_type == $stat[muscle]) + item_descriptions[lookupItem("shooting morning star")] = "+15% muscle for tower test"; + else if (stat_race_type == $stat[mysticality]) + item_descriptions[lookupItem("meteortarboard")] = "+15% myst for tower test"; + } + string [int] items; + foreach it, desc in item_descriptions + { + if (it.available_amount() == 0) + items.listAppend(it + " (" + desc + ")"); + } + if (items.count() > 0) + description.listAppend("Could make " + items.listJoinComponents(", ", "or") + "."); + if (lookupItem("metal meteoroid").item_amount() > 0) + entry.url = "inv_use.php?pwd=" + my_hash() + "&whichitem=9516"; + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(lookupItem("metal meteoroid")), "", description)); + } + + if (entry.subentries.count() > 0) + resource_entries.listAppend(entry); +} + +RegisterResourceGenerationFunction("IOTMNewYouGenerateResource"); +void IOTMNewYouGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (__misc_state["in run"] && in_ronin()) + { + string [item] affirmation_effects; + string [item] affirmation_combat_uses; + affirmation_effects[lookupItem("Daily Affirmation: Adapt to Change Eventually")] = "+4 stats/fight, +50% init"; + if (!__misc_state["need to level"]) + affirmation_effects[lookupItem("Daily Affirmation: Adapt to Change Eventually")] = "+50% init"; + affirmation_effects[lookupItem("Daily Affirmation: Always be Collecting")] = "+50% item, +100% meat"; + affirmation_effects[lookupItem("Daily Affirmation: Be a Mind Master")] = "+100% spell damage, 15 MP regen"; + affirmation_effects[lookupItem("Daily Affirmation: Be Superficially interested")] = "-combat / +combat (togglable)"; + affirmation_effects[lookupItem("Daily Affirmation: Keep Free Hate in your Heart")] = "+30 ML"; + affirmation_effects[lookupItem("Daily Affirmation: Think Win-Lose")] = "+50% all stats"; + affirmation_effects[lookupItem("Daily Affirmation: Work For Hours a Week")] = "+5 familiar weight, 15 HP regen"; + if (__misc_state["familiars temporarily blocked"]) + affirmation_effects[lookupItem("Daily Affirmation: Work For Hours a Week")] = "15 HP regen"; + + + affirmation_combat_uses[lookupItem("Daily Affirmation: Adapt to Change Eventually")] = "reroll monster"; //monster change + affirmation_combat_uses[lookupItem("Daily Affirmation: Always be Collecting")] = "duplicate item drops"; + affirmation_combat_uses[lookupItem("Daily Affirmation: Be a Mind Master")] = "banish for 80 turns (not free)"; + if (!__misc_state["have reusable olfaction equivalent"]) + affirmation_combat_uses[lookupItem("Daily Affirmation: Be Superficially interested")] = "olfact weakly"; + if (hippy_stone_broken()) + affirmation_combat_uses[lookupItem("Daily Affirmation: Keep Free Hate in your Heart")] = "gain 3 PVP fights"; + affirmation_combat_uses[lookupItem("Daily Affirmation: Think Win-Lose")] = "instakill"; + affirmation_combat_uses[lookupItem("Daily Affirmation: Work For Hours a Week")] = "earn some meat"; + + ChecklistEntry entry; + foreach it in affirmation_effects + { + if (it.item_amount() == 0) continue; + if (!it.item_is_usable()) continue; + if (!it.to_effect().effect_is_usable()) continue; + if (entry.image_lookup_name == "") + entry.image_lookup_name = "__item " + it; + string combat_text = ""; + if (affirmation_combat_uses[it] != "") + combat_text = "Or throw in combat to " + affirmation_combat_uses[it] + "."; + ChecklistSubentry subentry = ChecklistSubentryMake(pluralise(it), "100 turns, " + affirmation_effects[it], combat_text); + if (it == lookupItem("Daily Affirmation: Think Win-Lose")) + { + resource_entries.listAppend(ChecklistEntryMake("__item " + it, "", subentry).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("New you affirmation win-lose free kill")); + } + else if (it == lookupItem("Daily Affirmation: Be a Mind Master")) + { + resource_entries.listAppend(ChecklistEntryMake("__item " + it, "", subentry, 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("New you affirmation mind master banish")); + } + else + entry.subentries.listAppend(subentry); + } + if (entry.subentries.count() > 0) + { + entry.url = "inventory.php?ftext=daily+affirmation"; + entry.tags.id = "New you affirmation resource"; + entry.importance_level = 6; + resource_entries.listAppend(entry); + } + } +} + + +RegisterTaskGenerationFunction("IOTMPortablePantogramGenerateTasks"); +void IOTMPortablePantogramGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[lookupItem("portable pantogram")]) return; + if (lookupItem("pantogram pants").available_amount() > 0) return; + + if (my_path().id == PATH_BEES_HATE_YOU) return; + string [int] description; + + + string [int][int] slot_options; + for i from 1 to 5 + slot_options[i] = listMakeBlankString(); + + //Slot 1: muscle, myst, moxie. Tower stat test, then muscle. + if (__misc_state["in run"] && !__quest_state["Level 13"].state_boolean["Stat race completed"] && __quest_state["Level 13"].state_string["Stat race type"] != "") + slot_options[1].listAppend(__quest_state["Level 13"].state_string["Stat race type"]); + else if (__misc_state["in run"]) + slot_options[1].listAppend("muscle"); + //Slot 2: Resistance. Cold? Spooky? + if (__misc_state["in run"]) + { + if (my_path().id == PATH_COMMUNITY_SERVICE) + slot_options[2].listAppend("hot resistance"); + else if (!__quest_state["Level 9"].state_boolean["bridge complete"]) + slot_options[2].listAppend("sleaze resistance"); //bridge building + else + slot_options[2].listAppend("spooky resistance"); //a-boo peak, and slightly more useful than cold resistance + } + //Slot 3: drops of blood (+40 HP). -3 MP to use skills is nice, I guess? but it takes a baconstone + if (__misc_state["in run"]) + slot_options[3].listAppend("drops of blood (+40 HP)"); + if ($item[baconstone].available_amount() > 0 && __misc_state["in run"]) + slot_options[3].listAppend("baconstone (-3 MP to use skills)"); + //Slot 4: + if ($item[taco shell].npc_price() > 0) + slot_options[4].listAppend("taco shell (+30% meat)"); + if (($item[porquoise].npc_price() > 0 && __misc_state["in run"]) || can_interact()) + slot_options[4].listAppend("porquoise (+60% meat)"); + if (my_path().id == PATH_COMMUNITY_SERVICE) + { + slot_options[4].listAppend("your hopes (+20 weapon damage)"); + slot_options[4].listAppend("your dreams (+20% spell damage)"); + } + if (__misc_state["in run"]) + { + } + else + { + slot_options[4].listAppend("tiny dancer (+30% item)"); + } + //slot_options[4].listAppend("???"); + //Slot 5: + slot_options[5].listAppend("some self-respect (-combat)"); + if (my_path().id != PATH_COMMUNITY_SERVICE) + slot_options[5].listAppend("some self-control (+combat)"); + if (!__misc_state["in run"]) + slot_options[5].listAppend("ten-leaf clover (hilarious items)"); + if ($item[bar skin].available_amount() > 0 && __misc_state["in run"]) + slot_options[5].listAppend("bar skin (+50% init)"); + + foreach slot_id in slot_options + { + if (slot_options[slot_id].count() == 0) continue; + description.listAppend(slot_options[slot_id].listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); + } + optional_task_entries.listAppend(ChecklistEntryMake("__item portable pantogram", "inv_use.php?pwd=" + my_hash() + "&whichitem=9573", ChecklistSubentryMake("Summon pants", "", description), 1).ChecklistEntrySetIDTag("Portable pantogram summon")); +} + + +RegisterTaskGenerationFunction("IOTMSpaceJellyfishGenerateTasks"); +void IOTMSpaceJellyfishGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!$familiar[space jellyfish].familiar_is_usable()) + return; + if (!get_property_boolean("_seaJellyHarvested") && my_level() >= 11 && !__misc_state["sea access blocked"]) + { + string url = "place.php?whichplace=thesea&action=thesea_left2"; + string [int] description; + if (!QuestState("questS01OldGuy").started) + { + url = "oldman.php"; + description.listAppend("Visit the old man first."); + } + else if (my_familiar() != $familiar[space jellyfish]) + { + url = "familiar.php"; + description.listAppend("Bring along your space jellyfish first."); + } + description.listAppend("Once/day."); + optional_task_entries.listAppend(ChecklistEntryMake("__familiar space jellyfish", url, ChecklistSubentryMake("Harvest sea jelly", "", description)).ChecklistEntrySetIDTag("Space jellyfish sea jelly harvest")); + } +} + + +RegisterResourceGenerationFunction("IOTMSpaceJellyfishGenerateResource"); +void IOTMSpaceJellyfishGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!$familiar[space jellyfish].familiar_is_usable()) + return; + + ChecklistEntry entry; + entry.url = ""; + entry.image_lookup_name = "__familiar space jellyfish"; + entry.tags.id = "Space jellyfish jelly extraction resource"; + entry.importance_level = 5; + + //_spaceJellyfishDrops + //_hotJellyUses + if (my_familiar() != $familiar[space jellyfish]) + { + entry.url = "familiar.php"; + } + + int [int] percent_chance_at_use = { + 0:100, + 1:50, + 2:33, + 3:25, + 4:20, + 5:5, + 6:5, + 7:5, + 8:5, + 9:5, + 10:5, + 11:5, + 12:5, + 13:5, + 14:5, + }; + //FIXME spade rest + + if (__misc_state["in run"] && spleen_limit() > 0) + { + /* + hot - free run/banish + spooky - YR with no cooldown + stench - clara's bell, more or less + + The other two aren't too useful in-run. + */ + if (get_property_int("_hotJellyUses") > 0) + { + resource_entries.listAppend(ChecklistEntryMake("__item hot jelly", "", ChecklistSubentryMake(pluralise(get_property_int("_hotJellyUses"), "breathe out", "breathe outs"), "", "Cast Breathe Out. Free run/banish.")).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Space jellyfish breathe out banish")); + } + + string [item] jelly_descriptions; + //jelly_descriptions[$item[hot jelly]] = "Free run/banish."; + jelly_descriptions[$item[spooky jelly]] = "YR with no cooldown."; + jelly_descriptions[$item[stench jelly]] = "Forces non-combat."; + foreach it, desc in jelly_descriptions + { + if (it.available_amount() > 0 && in_ronin()) + { + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", desc)); + } + } + + if ($item[hot jelly].available_amount() > 0 && in_ronin()) + resource_entries.listAppend(ChecklistEntryMake("__item hot jelly", "", ChecklistSubentryMake(pluralise($item[hot jelly]), "", "Chew for free run/banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Space jellyfish hot jelly banish")); + + + + int extractions = get_property_int("_spaceJellyfishDrops"); + string [int] description; + string line = "Extract jelly against elemental monsters."; + if (percent_chance_at_use contains extractions) + line += "|" + percent_chance_at_use[extractions] + "% chance of success."; + + //Should we list common areas to find these? + //Spooky is defiled alcove. Hot is the level six quest. Stench is level twelve, i.e. level never before you need it. + line += "|*" + HTMLGenerateSpanOfClass("Stench", "r_bold r_element_stench_desaturated") + " - forces non-combat"; + if (!__quest_state["Level 12"].finished) + line += " (try hippies)"; + line += "|*" + HTMLGenerateSpanOfClass("Spooky", "r_bold r_element_spooky_desaturated") + " - YR with no cooldown"; + if (!__quest_state["Level 7"].finished) + line += " (try cyrpt)"; + line += "|*" + HTMLGenerateSpanOfClass("Hot", "r_bold r_element_hot_desaturated") + " - free run/banish"; + if (!__quest_state["Level 12"].finished) + line += " (try friars)"; + description.listAppend(line); + if (availableDrunkenness() >= 0) + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(extractions, "jelly extraction", "jelly extractions"), "", description)); + } + + + if (entry.subentries.count() > 0) + resource_entries.listAppend(entry); +} + +//Spacegate +RegisterTaskGenerationFunction("IOTMSpacegateGenerateTasks"); +void IOTMSpacegateGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[lookupItem("Spacegate access badge")]) + return; + string [int] description; + string url = "place.php?whichplace=spacegate"; + { + int SpacegateTimer = get_property_int("_spacegateTurnsLeft"); + description.listAppend("Plan " + get_property("_spacegateCoordinates") + " from Outer Space"); + + if (SpacegateTimer > 0 && __last_adventure_location == $location[through the spacegate]) { + task_entries.listAppend(ChecklistEntryMake("__item portable spacegate", url, ChecklistSubentryMake(SpacegateTimer + " Spacegate turns remaining", "", description), -11)); + } + } +} + +RegisterResourceGenerationFunction("IOTMSpacegateGenerateResource"); +void IOTMSpacegateGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[lookupItem("Spacegate access badge")]) + return; + if (!get_property_boolean("_spacegateVaccine") && my_path().id != PATH_G_LOVER) + { + boolean rainbow_unlocked = get_property_boolean("spacegateVaccine1"); //+3 all res + boolean broad_spectrum_unlocked = get_property_boolean("spacegateVaccine2"); //+50% all stats + boolean emotional_unlocked = get_property_boolean("spacegateVaccine3"); //+30 ML + + string [int] options; + if (emotional_unlocked) + options.listAppend("+30 ML"); + if (broad_spectrum_unlocked) + options.listAppend("+50% stats"); + if (rainbow_unlocked) + options.listAppend("+3 all res"); + + boolean missing_one = !rainbow_unlocked || !broad_spectrum_unlocked || !emotional_unlocked; + if (missing_one && lookupItem("spacegate research").available_amount() > 0) + options.listAppend("unlock additional vaccines"); + if (options.count() > 0) + { + string [int] description; + description.listAppend("30 turns, once/day.|" + options.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); + + resource_entries.listAppend(ChecklistEntryMake("__item plus sign", "place.php?whichplace=spacegate&action=sg_vaccinator", ChecklistSubentryMake("Vaccination", "", description), 8).ChecklistEntrySetIDTag("Spacegate daily vaccine resource")); + } + } + if (__misc_state["in run"] && my_primestat() == $stat[moxie] && __misc_state["need to level"] && get_property("_spacegatePlanetName") == "") + { + //Dial TFHSXKK: + string [int] description; + description.listAppend("Dial TFHSXKK, and skip every adventure until you reach Paradise Under a Strange Sun.|Will give 1000 stats and cost a turn. Not strictly optimal."); + resource_entries.listAppend(ChecklistEntryMake("__item portable spacegate", "place.php?whichplace=spacegate&action=sg_Terminal", ChecklistSubentryMake("Spacegate dial", "", description), 8).ChecklistEntrySetIDTag("Spacegate moxie boost trick")); + } +} + +RegisterTaskGenerationFunction("IOTMTunnelOfLoveGenerateTasks"); +void IOTMTunnelOfLoveGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + //FIXME whatever these end up being named: + if (!mafiaIsPastRevision(17805)) + return; + if (!__iotms_usable[lookupItem("heart-shaped crate")]) + return; + if (get_property_boolean("_loveTunnelUsed")) + return; + + string [int] description; + //equipment: LOV Eardigan (+25% muscle exp, +25 ML), LOV Epaulettes (+25% myst exp), LOV Earrings (+25% moxie exp, +50% meat, +3 all res) + //50-turn buffs: Lovebotamy (10 stats/fight), Open Heart Surgery (+10 familiar weight), Wandering Eye Surgery (+50% item) + //item: boomerang (arrow), toy dart gun (???), chocolate (adventures), flowers (???), elephant (???), TOAST! (toasty!) + + description.listAppend("Three free fights. Attack, spell, and pickpocket respectively for elixirs."); + if (my_path().id == PATH_GELATINOUS_NOOB) + description.listAppend("Equipment choice unimportant."); + else + { + string [int] equipment_choices; + equipment_choices.listAppend(HTMLBoldIfTrue("Eardigan", my_primestat() == $stat[muscle] && __misc_state["in run"] && my_level() < 13) + " (+25% muscle exp, +25 ML)"); + if (my_path().id != PATH_G_LOVER) + equipment_choices.listAppend(HTMLBoldIfTrue("Epaulettes", my_primestat() == $stat[mysticality] && __misc_state["in run"] && my_level() < 13) + " (+25% myst exp)"); + equipment_choices.listAppend(HTMLBoldIfTrue("Earrings", (my_primestat() == $stat[moxie] && __misc_state["in run"] && my_level() < 13) || __misc_state["in aftercore"] || my_level() >= 13) + " (+25% moxie exp, +50% meat, +3 all res)"); + description.listAppend("Equipment choice:|*" + equipment_choices.listJoinComponents(", ", "or")); + } + string [int] buff_choices; + if (my_path().id != PATH_G_LOVER) + buff_choices.listAppend("+10 stats/fight"); + buff_choices.listAppend("+10 familiar weight"); + buff_choices.listAppend("+50% item"); + description.listAppend("Buff choice: (50 turns)|*" + buff_choices.listJoinComponents(", ", "or")); + + string [int] usable_items; + if (my_path().id != PATH_LIVE_ASCEND_REPEAT) + usable_items.listAppend("single-use wandering copier"); + usable_items.listAppend("chat hearts"); + if (my_path().id != PATH_SLOW_AND_STEADY && my_path().id != PATH_G_LOVER) + usable_items.listAppend("chocolate (adventures)"); + if ($familiar[space jellyfish].familiar_is_usable()) + usable_items.listAppend("toast"); + description.listAppend("Item choice:|*" + usable_items.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); + + optional_task_entries.listAppend(ChecklistEntryMake("__item pink candy heart", "place.php?whichplace=town_wrong", ChecklistSubentryMake("Take a love trip", "", description)).ChecklistEntrySetIDTag("Love tunnel daily trip")); +} + +RegisterResourceGenerationFunction("IOTMTunnelOfLoveGenerateResource"); +void IOTMTunnelOfLoveGenerateResource(ChecklistEntry [int] resource_entries) +{ + //mostly the boomerang + //what does sokka throw? a boomeraang! + + if (__misc_state["in run"] && in_ronin()) + { + /*item enamorang = $item[LOV Enamorang]; + if (enamorang.available_amount() > 0) + { + resource_entries.listAppend(ChecklistEntryMake("__item LOV Enamorang", "", ChecklistSubentryMake(pluralise(enamorang), "", "Copies the monster once as an arrow."), 5).ChecklistEntrySetIDTag("Love tunnel LOV enamorang")); + + }*/ + item chocolate = lookupItem("LOV Extraterrestrial Chocolate"); + if (chocolate.available_amount() > 0 && $item[LOV Extraterrestrial Chocolate].item_is_usable()) + { + //FIXME list other chocolates? + resource_entries.listAppend(ChecklistEntryMake("__item LOV Extraterrestrial Chocolate", "", ChecklistSubentryMake(pluralise(chocolate), "", "Adventures!"), 5).ChecklistEntrySetIDTag("Love tunnel chocolates resource")); + + } + } +} + + +RegisterResourceGenerationFunction("IOTMXOSkeletonGenerateResource"); +void IOTMXOSkeletonGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("XO Skeleton").familiar_is_usable()) return; + + + + int hugs_remaining = clampi(11 - get_property_int("_xoHugsUsed"), 0, 11); + + ChecklistEntry entry; + entry.image_lookup_name = "__familiar xo skeleton"; + entry.tags.id = "XO skeleton familiar resource"; + entry.importance_level = 3; + if (my_familiar() != lookupFamiliar("XO Skeleton")) + entry.url = "familiar.php"; + + + if ((my_familiar() == lookupFamiliar("XO Skeleton") || __misc_state["in run"]) && hugs_remaining > 0) + { + string [int] description; + description.listAppend("Instantly v-pocket an item."); + if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) + { + string [int] options; + if (!__quest_state["Level 12"].finished && get_property("sidequestOrchardCompleted") == "none" && !($effect[Filthworm Guard Stench].have_effect() > 0 || $item[Filthworm royal guard scent gland].available_amount() > 0)) + options.listAppend("filthworms"); + if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && !QuestState("questM20Necklace").finished) + options.listAppend("banshee librarian (killing jar)"); + if (get_property_int("hiddenApartmentProgress") < 7 || get_property_int("hiddenOfficeProgress") < 7) + options.listAppend("pygmy witch lawyer (short writs)"); + if (!have_outfit_components("Swashbuckling Getup") && __quest_state["Pirate Quest"].state_boolean["valid"]) + options.listAppend("obligatory pirate's cove (outfit)"); + if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] >= 90) + options.listAppend("Whatsian Commando Ghost (ghost free runaway)"); + if (options.count() > 0) + description.listAppend(options.listJoinComponents(", ").capitaliseFirstLetter() + ", etc."); + } + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(hugs_remaining, "hug", "hugs"), "", description)); + } + + if (__misc_state["in run"] && in_ronin()) + { + int xes = lookupItem("9543").available_amount(); + int os = lookupItem("9544").available_amount(); + + //two Os: pair of candy glasses (10 adventures of +50% item) + //Hide-rox™ cookie: 3 os, 1-size food, myst tower test + //jug of booze: 3 xes, 1-size booze, moxie tower test + //glyph of athleticism: 5 Os, 1-size spleen, muscle tower test + //bridge truss: 23 xes, 15 bridge progress, takes forever to acquire + + string header; + string [int] description; + if (xes > 0) + header += pluralise(xes, "X", "Xes"); + if (os > 0) + { + if (header != "") + header += ", "; + header += pluralise(os, "O", "Os"); + } + + boolean [string] options; + + options["pair of candy glasses: +50% item (10 turns)"] = (os >= 2); + if (!__quest_state["Level 9"].state_boolean["bridge complete"] && my_path().id != PATH_COMMUNITY_SERVICE) + { + int turns_left = (23 - xes) * 9 - get_property_int("xoSkeleltonXProgress"); + string line = "bridge truss: half a bridge"; + if (turns_left > 0) + line += ", " + pluralise(turns_left, "combat", "combats") + " to get"; + options[line] = (xes >= 23); + } + if (!__quest_state["Level 13"].state_boolean["Stat race completed"]) + { + stat stat_race_type = __quest_state["Level 13"].state_string["Stat race type"].to_stat(); + //if (stat_race_type == $stat[muscle]) + } + foreach option, available in options + { + string line = option; + if (!available) + line = HTMLGenerateSpanFont(line, "gray"); + description.listAppend(line); + } + + entry.subentries.listAppend(ChecklistSubentryMake(header, "", description)); + } + + if (entry.subentries.count() > 0) + resource_entries.listAppend(entry); +} + + +// 2018 + +RegisterTaskGenerationFunction("IOTMGarbageToteGenerateTasks"); +void IOTMGarbageToteGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[$item[January's Garbage Tote]]) return; + boolean [item] relevant_items; + if (get_property_int("garbageTreeCharge") > 0) + relevant_items[lookupItem("deceased crimbo tree")] = true; + if (get_property_int("garbageShirtCharge") > 0 && __misc_state["Torso aware"]) + relevant_items[lookupItem("makeshift garbage shirt")] = true; + if (get_property_int("garbageChampagneCharge") > 0) + relevant_items[lookupItem("broken champagne bottle")] = true; + relevant_items[lookupItem("tinsel tights")] = true; + relevant_items[lookupItem("wad of used tape")] = true; + if (relevant_items.available_amount() == 0) { + string [int] description; + if (my_level() < 13 && get_property_int("garbageShirtCharge") > 0 && __misc_state["Torso aware"]) { + description.listAppend("Makeshift garbage shirt (double statgain for " + pluralise(get_property_int("garbageShirtCharge"), "more turn", "more turns") + ".)"); + } + else if (my_level() < 13) + description.listAppend("Tinsel tights (+25 ML)"); + description.listAppend("Wad of used tape (+15% item, +30% meat)"); + if (get_property_int("garbageChampagneCharge") > 0) + description.listAppend("Broken champagne bottle (double +item for " + pluralise(get_property_int("garbageChampagneCharge"), "more turn", "more turns") + ".)"); + + // Use the right item ID depending on if you are using a replica or a non-replica + string activeToteID = lookupItem("replica January's Garbage Tote").available_amount() > 0 ? "11238" : "9690"; + + optional_task_entries.listAppend(ChecklistEntryMake("__item January's Garbage Tote", "inv_use.php?pwd=" + my_hash() + "&whichitem=" + activeToteID, ChecklistSubentryMake("Collect a garbage tote item", "", description), 1).ChecklistEntrySetIDTag("Garbage tote should switch item")); + } +} + + +RegisterResourceGenerationFunction("IOTMGarbageToteGenerateResource"); +void IOTMGarbageToteGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (lookupItem("January's Garbage Tote").available_amount() == 0) return; + //_garbageShirtCharge from 37 to 0 + //_garbageChampagneCharge from 11 to 0 + //_garbageTreeCharge from 1000 to 0 + + string [item] item_charge_property; + string [item] item_effect_description; + int [item] item_charge_default; + + if (__misc_state["Torso aware"]) { + item_charge_property[lookupItem("makeshift garbage shirt")] = "garbageShirtCharge"; + item_effect_description[lookupItem("makeshift garbage shirt")] = "Doubles statgain"; + item_charge_default[lookupItem("makeshift garbage shirt")] = 37; + } + + item_charge_property[lookupItem("broken champagne bottle")] = "garbageChampagneCharge"; + item_effect_description[lookupItem("broken champagne bottle")] = "Doubles +item"; + item_charge_default[lookupItem("broken champagne bottle")] = 11; + + item_charge_property[lookupItem("deceased crimbo tree")] = "garbageTreeCharge"; + item_effect_description[lookupItem("deceased crimbo tree")] = "Absorbs damage"; + item_charge_default[lookupItem("deceased crimbo tree")] = 1000; + + // Use the right item ID depending on if you are using a replica or a non-replica + string activeToteID = lookupItem("replica January's Garbage Tote").available_amount() > 0 ? "11238" : "9690"; + + ChecklistEntry entry; + entry.url = "inv_use.php?pwd=" + my_hash() + "&whichitem="+activeToteID; + entry.importance_level = 8; + entry.tags.id = "Garbage tote items resource"; + + boolean outdatedGarbage = !get_property_boolean("_garbageItemChanged"); + + foreach it, property_name in item_charge_property { + int charge = get_property_int(property_name); + boolean have = it.available_amount() > 0; + if (!have && outdatedGarbage) + charge = item_charge_default[it]; + + if (!have && charge == 0) continue; + if (!have && !(lookupItems("makeshift garbage shirt,broken champagne bottle") contains it)) continue; + string title; + string [int] description; + string url = "inventory.php?which=2"; + if (charge > 0) { + title = pluralise(charge, "charge", "charges") + " of " + it; + description.listAppend(item_effect_description[it] + "." + (!have ? " Not active." : "")); + if (have && outdatedGarbage) + description.listAppend("Charges are from previous day. Will get " + item_charge_default[it] + " more when you interact with the Tote (you will lose those " + charge + ")."); + } else { + title = HTMLGenerateSpanFont("No charges of " + it, "red"); + description.listAppend(outdatedGarbage ? "Interact with Tote to refill charges." : "Switch out for something else."); + url = "inv_use.php?pwd=" + my_hash() + "&whichitem="+activeToteID; + } + if (entry.image_lookup_name == "") + entry.image_lookup_name = "__item " + it; + entry.subentries.listAppend(ChecklistSubentryMake(title, "", description)); + //resource_entries.listAppend(ChecklistEntryMake("__item " + it, url, ChecklistSubentryMake(title, "", description), 8).ChecklistEntrySetIDTag("Garbage tote items resource")); + } + if (entry.subentries.count() > 0) + resource_entries.listAppend(entry); +} + + + +RegisterResourceGenerationFunction("IOTMZataraGenerateResource"); +void IOTMZataraGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["VIP available"] || !lookupItem("Clan Carnival Game").is_unrestricted()) + return; + ChecklistEntry entry; + entry.importance_level = 8; + entry.image_lookup_name = "__item genie's turbane"; + entry.url = "clan_viplounge.php?preaction=lovetester"; + entry.tags.id = "Clan VIP madame Zatara consults"; + if (!get_property_boolean("_clanFortuneBuffUsed")) + { + string [int] description; + if (!__misc_state["familiars temporarily blocked"] && __misc_state["in run"]) + description.listAppend(HTMLGenerateSpanOfClass("Susie:", "r_bold") + " +5 familiar weight, +familiar experience."); //only show in-run, because, like... +5 familiar weight for one hundred turns is not likely to pay out compared to hagnk/meatsmith in aftercore. + if (my_path().id != PATH_G_LOVER) + description.listAppend(HTMLGenerateSpanOfClass("Hagnk:", "r_bold") + " +50% item/booze/food."); + if (my_path().id != PATH_G_LOVER) + description.listAppend(HTMLGenerateSpanOfClass("Meatsmith:", "r_bold") + " +100% meat, +50% gear drop."); + + if (__misc_state["in run"]) + { + if (my_primestat() == $stat[muscle] || my_path().id == PATH_COMMUNITY_SERVICE) + description.listAppend(HTMLGenerateSpanOfClass("Gunther:", "r_bold") + " +5 muscle stats/fight, +100% muscle, +50% HP."); + if (my_primestat() == $stat[moxie] || my_path().id == PATH_COMMUNITY_SERVICE) + description.listAppend(HTMLGenerateSpanOfClass("Gorgonzola:", "r_bold") + " +5 myst stats/fight, +100% myst, +50% MP."); + //always show moxie, since I'm sure that +50% init will be super important to someone. maybe they have a bad lair test? + if (my_path().id != PATH_G_LOVER) + description.listAppend(HTMLGenerateSpanOfClass("Shifty:", "r_bold") + " +5 moxie stats/fight, +100% moxie, +50% init."); + } + entry.subentries.listAppend(ChecklistSubentryMake("Fortune buff (100 turns)", "", description)); + } + if (get_property_int("_clanFortuneConsultUses") < 3) + { + string [int] description; + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(3 - get_property_int("_clanFortuneConsultUses"), "fortune clan consult", "fortune clan consults"), "", description)); + } + if (entry.subentries.count() > 0) + resource_entries.listAppend(entry); +} + +// Missing: Pokefam +// Missing: FantasyRealm + +RegisterResourceGenerationFunction("IOTMGodLobsterGenerateResource"); +void IOTMGodLobsterGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("god lobster").familiar_is_usable()) return; + int free_fights_left = clampi(3 - get_property_int("_godLobsterFights"), 0, 3); + + if (free_fights_left == 0) return; + string url = "familiar.php"; + if (lookupFamiliar("god lobster") == my_familiar()) + url = ""; + + string [int] description; + //This is so complicated. + + item [int] equipment_order; + equipment_order.listAppend(lookupItem("God Lobster's Scepter")); + equipment_order.listAppend(lookupItem("God Lobster's Ring")); + equipment_order.listAppend(lookupItem("God Lobster's Rod")); + equipment_order.listAppend(lookupItem("God Lobster's Robe")); + equipment_order.listAppend(lookupItem("God Lobster's Crown")); + + item [item] equipment_to_next_reward; + equipment_to_next_reward[$item[none]] = lookupItem("God Lobster's Scepter"); + equipment_to_next_reward[lookupItem("God Lobster's Scepter")] = lookupItem("God Lobster's Ring"); + equipment_to_next_reward[lookupItem("God Lobster's Ring")] = lookupItem("God Lobster's Rod"); + equipment_to_next_reward[lookupItem("God Lobster's Rod")] = lookupItem("God Lobster's Robe"); + equipment_to_next_reward[lookupItem("God Lobster's Robe")] = lookupItem("God Lobster's Crown"); + equipment_to_next_reward[lookupItem("God Lobster's Crown")] = $item[none]; + + string [item] equipment_to_boon_description; + equipment_to_boon_description[$item[none]] = "40 mp/adv / +20 MP"; + equipment_to_boon_description[lookupItem("God Lobster's Scepter")] = "+10 stats/fight"; + equipment_to_boon_description[lookupItem("God Lobster's Ring")] = "-combat"; + equipment_to_boon_description[lookupItem("God Lobster's Rod")] = "+combat"; + equipment_to_boon_description[lookupItem("God Lobster's Robe")] = "+1 all res / +20 DA / +3 DR"; + equipment_to_boon_description[lookupItem("God Lobster's Crown")] = "doubles food statgain"; + + + string [item] equipment_to_equipment_effect_description; + equipment_to_equipment_effect_description[lookupItem("God Lobster's Scepter")] = "half-weight fairy/leprechaun"; + equipment_to_equipment_effect_description[lookupItem("God Lobster's Ring")] = "sombrero statgain"; + equipment_to_equipment_effect_description[lookupItem("God Lobster's Rod")] = "restore HP/MP after combat"; + equipment_to_equipment_effect_description[lookupItem("God Lobster's Robe")] = "blocking potato"; + equipment_to_equipment_effect_description[lookupItem("God Lobster's Crown")] = "full-weight fairy"; + + float [item] equipment_to_mainstat_multiplier; + equipment_to_mainstat_multiplier[$item[none]] = 1.5; + equipment_to_mainstat_multiplier[lookupItem("God Lobster's Scepter")] = 1.65; + equipment_to_mainstat_multiplier[lookupItem("God Lobster's Ring")] = 1.85; + equipment_to_mainstat_multiplier[lookupItem("God Lobster's Rod")] = 2.17; + equipment_to_mainstat_multiplier[lookupItem("God Lobster's Robe")] = 2.62; + equipment_to_mainstat_multiplier[lookupItem("God Lobster's Crown")] = 3.0; + + + item current_familiar_equipment = lookupFamiliar("god lobster").familiar_equipped_equipment(); + + string [int] current_rewards; + //[next equipment], [effect], [experience] + + current_rewards.listAppend(equipment_to_boon_description[current_familiar_equipment] + " effect (33 turns)"); + if (__misc_state["need to level"]) + { + float statgain = equipment_to_mainstat_multiplier[current_familiar_equipment] * my_basestat(my_primestat()) * (1.0 + numeric_modifier(my_primestat() + " experience percent") / 100.0); + current_rewards.listAppend(round(statgain) + " mainstat gain"); + } + + if (equipment_to_next_reward[current_familiar_equipment] != $item[none] && equipment_to_next_reward[current_familiar_equipment].available_amount() == 0) + current_rewards.listAppend("a " + equipment_to_next_reward[current_familiar_equipment].replace_string("God Lobster's", "").to_lower_case()); + + if (current_rewards.count() > 0) + description.listAppend("Can choose between " + current_rewards.listJoinComponents(", ", "or") + "."); + + string [int] other_equipment_to_switch_to; + foreach it in equipment_to_boon_description + { + if (it.available_amount() == 0) continue; + if (it == current_familiar_equipment) continue; + //FIXME write this + other_equipment_to_switch_to.listAppend(it + " (" + equipment_to_equipment_effect_description[it] + " and " + equipment_to_boon_description[it] + " obtainable effect)"); + } + + if (other_equipment_to_switch_to.count() > 0) + description.listAppend("Could switch equipment to " + other_equipment_to_switch_to.listJoinComponents(", ", "or") + "."); + + resource_entries.listAppend(ChecklistEntryMake("__familiar god lobster", url, ChecklistSubentryMake(pluralise(free_fights_left, "free God Lobster fight", "free God Lobster fights"), "", description)).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("God lobster daily fights")); +} + +//Songboom +RegisterTaskGenerationFunction("IOTMBoomBoxGenerateTasks"); +void IOTMBoomBoxGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (lookupItem("SongBoom™ BoomBox").available_amount() == 0) return; + + + string song = get_property("boomBoxSong"); + int changes_left = get_property_int("_boomBoxSongsLeft"); //the boys are back in town, eleven times. everyone will love it + + int boomboxProgress = get_property_int("_boomBoxFights"); + string [int] description; + { + description.listAppend("Now playing: " + HTMLGenerateSpanOfClass(song, "r_bold")); //+ " (" + changes_left + " song swaps today)"); + if (boomboxProgress < 9) + { + description.listAppend((11 - boomboxProgress).pluralise("combat", "combats") + " until next drop."); + optional_task_entries.listAppend(ChecklistEntryMake("__item SongBoom™ BoomBox", "inv_use.php?pwd=" + my_hash() + "&whichitem=9919", ChecklistSubentryMake("Boombox song stuff", "", description), 8)); + } + if (boomboxProgress == 9) + { + task_entries.listAppend(ChecklistEntryMake("__item SongBoom™ BoomBox", "inv_use.php?pwd=" + my_hash() + "&whichitem=9919", ChecklistSubentryMake("Boombox drop in 2 fights", "", description), -11)); + } + + if (boomboxProgress == 10) + { + task_entries.listAppend(ChecklistEntryMake("__item SongBoom™ BoomBox", "inv_use.php?pwd=" + my_hash() + "&whichitem=9919", ChecklistSubentryMake("Boombox drop this fight", "", description), -11)); + } + } + + if (song == "" && changes_left > 0) + { + string [int] description; + if (!__quest_state["Level 7"].finished && my_path().id != PATH_COMMUNITY_SERVICE) + description.listAppend("Eye of the Giger: Nightmare Fuel for the cyrpt."); + if (fullness_limit() > 0) + description.listAppend("Food Vibrations: extra adventures from food" + (__misc_state["in run"] ? ", +30% food drop" : "") + "."); + description.listAppend("Total Eclipse of Your Meat: extra meat, +30% meat."); + + optional_task_entries.listAppend(ChecklistEntryMake("__item SongBoom™ BoomBox", "inv_use.php?pwd=" + my_hash() + "&whichitem=9919", ChecklistSubentryMake("Set BoomBox song", "", description), 8).ChecklistEntrySetIDTag("SongBoom BoomBox turn on")); + } +} +RegisterResourceGenerationFunction("IOTMCatBurglarGenerateResource"); +void IOTMCatBurglarGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("cat burglar").familiar_is_usable()) return; + + int charges_left = CatBurglarChargesLeftToday(); + int burglar_progress = (get_property_int("_catBurglarCharge")); + if (charges_left > 0) + { + string [int] description; + string url = "familiar.php"; + if (my_familiar() == lookupFamiliar("cat burglar")) + url = "main.php?heist=1"; + //√rusty hedge trimmers + //√bowling ball + //cigarette lighter, if they're doing zeppelin + //scent glands, but only if they don't xoxoxoxo + //√green smoke bomb + //There are also certainly even more options. + description.listAppend("Obtains one item from a recent fight."); + if (burglar_progress >= 150) + description.listAppend("" + burglar_progress + "/310 charges today for 5th heist."); + else if (burglar_progress >= 70) + description.listAppend("" + burglar_progress + "/150 charges today for 4th heist."); + else if (burglar_progress >= 30) + description.listAppend("" + burglar_progress + "/70 charges today for 3rd heist."); + else if (burglar_progress >= 10) + description.listAppend("" + burglar_progress + "/30 charges today for 2nd heist."); + else if (burglar_progress >= 0) + description.listAppend("" + burglar_progress + "/10 charges today for 1st heist."); + + string [int] options; + if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) { + int bowling_progress = get_property_int("hiddenBowlingAlleyProgress"); + if (bowling_progress < 7) { + int balls_needed = 6 - bowling_progress - $item[bowling ball].available_amount(); + if (balls_needed > 0) + options.listAppend("Bowling ball, from the hidden bowling alley."); + } + if (get_property_int("twinPeakProgress") != 15 && $item[rusty hedge trimmers].available_amount() < __quest_state["Level 9"].state_int["peak tests remaining"]) { + options.listAppend("Rusty hedge trimmers, from the twin peak."); + } + if (!__quest_state["Level 12"].finished && get_property("sidequestOrchardCompleted") == "none") { + options.listAppend("Green smoke bomb, from the war."); + if (!lookupFamiliar("XO Skeleton").familiar_is_usable()) + options.listAppend("Scent glands, from the filthworms quest."); + } + if (get_property_int("zeppelinProtestors") < 80 && QuestState("questL11Ron").mafia_internal_step < 3) { + options.listAppend("Cigarette lighters, from the zeppelin protesters."); + } + if ($item[pirate fledges].available_amount() == 0 && !have_outfit_components("Swashbuckling Getup") && __quest_state["Pirate Quest"].state_boolean["valid"]) { + options.listAppend("Pirate outfit."); + } + + if ($item[S.O.C.K.].available_amount() == 0) { + string [int] airship_stealables; + foreach it in $items[mohawk wig,amulet of extreme plot significance] { + if (it.available_amount() == 0) { + if (it == $item[mohawk wig] && lookupSkill("Comprehensive Cartography").skill_is_usable() && $item[model airship].available_amount() >= 1) { + //mohawk wig not needed with a model airship and Cartography + } + else + airship_stealables.listAppend(it); + } + } + if (airship_stealables.count() > 0) + options.listAppend(airship_stealables.listJoinComponents(", ", "and").capitaliseFirstLetter() + ", from the airship."); + } + if (__quest_state["Level 4"].state_int["areas unlocked"] + $item[sonar-in-a-biscuit].available_amount() < 3) + options.listAppend("Sonar-in-a-biscuit, from the bat hole."); + if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && !__quest_state["Level 11 Desert"].state_boolean["Killing Jar Given"] && $item[killing jar].available_amount() == 0) // && !($location[The Haunted Gallery].locationAvailable() && !$location[The Haunted Library].locationAvailable()) //that was from when you could use copied/wished writing desks to skip the library... + options.listAppend("Killing jar, from the haunted library."); + if (!have_outfit_components("Knob Goblin Elite Guard Uniform") && !have_outfit_components("Knob Goblin Harem Girl Disguise") && !__quest_state["Level 5"].finished) + options.listAppend("Harem girl outfit, if you can't reach +400% item."); + } + if (options.count() > 0) + description.listAppend("Could steal:|*-" + options.listJoinComponents("|*-")); + + resource_entries.listAppend(ChecklistEntryMake("__familiar Cat Burglar", url, ChecklistSubentryMake(pluralise(charges_left, "heist", "heists"), "", description), 1).ChecklistEntrySetIDTag("Cat burglar resource")); + } +} + + +RegisterTaskGenerationFunction("IOTMBastilleBattalionGenerateTasks"); +void IOTMBastilleBattalionGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (lookupItem("Bastille Battalion control rig").available_amount() == 0 || my_sign().to_lower_case() == "bad moon") return; + + if (lookupItem("Draftsman's driving gloves").available_amount() > 0 || lookupItem("Nouveau nosering").available_amount() > 0 || lookupItem("Brutal brogues").available_amount() > 0) return; + + string [int] description; + string url = "inv_use.php?pwd=" + my_hash() + "&whichitem=9928"; + + //FIXME suggest the right configuration + if (lookupItem("Bastille Battalion control rig").storage_amount() > 0) + { + url = "storage.php?which=3"; + description.listAppend("Free pull from Hagnk's."); + } + //FIXME in the future, we might want to suggest options for them. We haven't, because it's a lot of space, especially the equipment. + string [int] suggested_configuration; + if (__misc_state["need to level"]) + { + int stats_gained = ceil(250 * (1.0 + numeric_modifier(my_primestat() + " experience percent") / 100.0)); + if (my_primestat() == $stat[muscle]) + { + description.listAppend(HTMLGenerateSpanOfClass("Babar", "r_bold") + ": " + stats_gained + " muscle stats."); + suggested_configuration.listAppend("Babar"); + } + else if (my_primestat() == $stat[mysticality]) + { + description.listAppend(HTMLGenerateSpanOfClass("Barbarian Barbecue", "r_bold") + ": " + stats_gained + " mysticality stats."); + suggested_configuration.listAppend("Barbarian Barbecue"); + } + else if (my_primestat() == $stat[moxie]) + { + description.listAppend(HTMLGenerateSpanOfClass("Barbershop", "r_bold") + ": " + stats_gained + " moxie stats."); + suggested_configuration.listAppend("Barbershop"); + } + } + string [int] accessories; + accessories.listAppend(HTMLGenerateSpanOfClass("Accessory:", "r_bold")); + accessories.listAppend(HTMLGenerateSpanOfClass("Brutalist", "r_bold") + ": +50% muscle, +50% weapon damage, +8 familiar weight, +4 muscle stats/fight."); + accessories.listAppend(HTMLGenerateSpanOfClass("Draftsman", "r_bold") + ": +50% myst, +50% spell damage, +8 adventures/day, +4 myst stats/fight."); + accessories.listAppend(HTMLGenerateSpanOfClass("Art Nouveau", "r_bold") + ": +50% moxie, +25% item, +25 HP/MP, +4 moxie stats/fight."); + description.listAppend(accessories.listJoinComponents("|*")); + + string [int] buffs; + buffs.listAppend(HTMLGenerateSpanOfClass("Buff:", "r_bold") + " (100 turns)"); + buffs.listAppend(HTMLGenerateSpanOfClass("Cannon", "r_bold") + ": +25 muscle, +10% critical hit, ~15 HP/adventure."); + buffs.listAppend(HTMLGenerateSpanOfClass("Catapult", "r_bold") + ": +25 myst, +10% spell critical hit, ~7.5 MP/adventure."); + buffs.listAppend(HTMLGenerateSpanOfClass("Gesture", "r_bold") + ": +25 moxie, +25% init, +25% meat."); + description.listAppend(buffs.listJoinComponents("|*")); + + if (!in_ronin()) + { + //+adventures in aftercore + suggested_configuration.listAppend("Draftsman"); + } + else if (my_primestat() == $stat[muscle]) + { + suggested_configuration.listAppend("Brutalist"); + } + else if (my_primestat() == $stat[mysticality]) + { + suggested_configuration.listAppend("Draftsman"); + } + else if (my_primestat() == $stat[moxie]) + { + suggested_configuration.listAppend("Art Nouveau"); + } + + if (!in_ronin()) + suggested_configuration.listAppend("Gesture"); + else + suggested_configuration.listAppend("Catapult"); + + description.listAppend("Suggested configuration: " + HTMLGenerateSpanOfClass(suggested_configuration.listJoinComponents(" / "), "r_bold") + "."); + + optional_task_entries.listAppend(ChecklistEntryMake("__item Bastille Battalion control rig", url, ChecklistSubentryMake("Collect Bastille rewards", "", description), 8).ChecklistEntrySetIDTag("Bastille Battalion daily")); +} + +RegisterTaskGenerationFunction("IOTMNeverendingPartyGenerateTasks"); +void IOTMNeverendingPartyGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!mafiaIsPastRevision(18865)) + return; + if (!__iotms_usable[lookupItem("Neverending Party invitation envelope")]) + return; + //Quest suggestions: + //_partyHard (boolean), _questPartyFair (Quest), _questPartyFairProgress (integer?), _questPartyFairQuest (string? - "partiers", ) + + QuestState quest_state = QuestState("_questPartyFair"); + //_questPartyFair is "" instead of unstarted if they didn't start it. + if (quest_state.in_progress) { + string quest_name = get_property("_questPartyFairQuest"); + //strange - went from "unstarted" to "step1" when accepting the partiers quest + boolean party_hard = get_property_boolean("_partyHard"); + int [int] progress_split; + foreach key, v in get_property("_questPartyFairProgress").split_string(" ") { + if (v == "") continue; + progress_split.listAppend(v.to_int()); + } + int progress = progress_split[0]; + + string [int] modifiers; + string [int] description; + string url = "place.php?whichplace=town_wrong"; + boolean finished = false; + if (party_hard && lookupItem("PARTY HARD T-shirt").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the PARTY HARD T-shirt.", "red")); + url = "inventory.php?ftext=party+hard+t-shirt"; + } + //partiers - progress starts at 50 in not-hard + if (quest_name == "partiers") { + if (progress > 0) { + description.listAppend(pluralise(progress, "partier", "partiers") + " remain."); + if (lookupItem("intimidating chainsaw").available_amount() == 0) { + description.listAppend("Collect the intimidating chainsaw.|" + listMake("Investigate the basement", "Grab the chainsaw").listJoinComponents(__html_right_arrow_character)); + } else if (lookupItem("intimidating chainsaw").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the intimidating chainsaw.", "red")); + url = "inventory.php?ftext=intimidating+chainsaw"; + } + if (lookupItem("jam band bootleg").item_amount() > 0) { + description.listAppend("Pop in the bootleg.|" + listMake("Head Upstairs", "Pop a bootleg in the stereo").listJoinComponents(__html_right_arrow_character)); + } else if (!in_ronin()) { + description.listAppend("Buy a jam band bootleg in the mall?"); + } + if (lookupItem("Purple Beast energy drink").item_amount() > 0) { + description.listAppend("Pour the energy drink into the pool.|" + listMake("Go to the back yard", "Pour Purple Beast into the pool").listJoinComponents(__html_right_arrow_character)); + } else if (!in_ronin()) { + description.listAppend("Buy a Purple Beast energy drink in the mall?"); + } + } else { + finished = true; + } + } else if (quest_name == "booze") { + //unremarkable duffel bag gives item; from jock + + if (quest_state.mafia_internal_step < 2) { + description.listAppend("Talk to Gerald.|" + listMake("Go to the back yard", "Find Gerald").listJoinComponents(__html_right_arrow_character)); + } else { + int amount_needed = progress_split[0]; + item item_needed = progress_split[1].to_item(); + if (item_needed == $item[none]) { + description.listAppend("Unknown item needed."); + } else if (item_needed.item_amount() < amount_needed) { + description.listAppend("Need to collect " + amount_needed + " " + item_needed + "."); + description.listAppend("Can collect from unremarkable duffel bags, from the jock."); + modifiers.listAppend("olfact jock"); + } else + description.listAppend("Talk to Gerald.|" + listMake("Go to the back yard", "Give Gerald the booze").listJoinComponents(__html_right_arrow_character)); + } + } else if (quest_name == "food") { + //van key gives item; from burnout + + if (quest_state.mafia_internal_step < 2) { + description.listAppend("Talk to Geraldine.|" + listMake("Check out the kitchen", "Talk to the woman").listJoinComponents(__html_right_arrow_character)); + } else { + int amount_needed = progress_split[0]; + item item_needed = progress_split[1].to_item(); + + if (item_needed == $item[none]) { + description.listAppend("Unknown item needed."); + } else if (item_needed.item_amount() < amount_needed) { + description.listAppend("Need to collect " + amount_needed + " " + item_needed + "."); + description.listAppend("Can collect from van keys, from the burnout."); + modifiers.listAppend("olfact burnout"); + } else + description.listAppend("Talk to Geraldine again.|" + listMake("Check out the kitchen", "Give Geraldine the snacks").listJoinComponents(__html_right_arrow_character)); + } + } else if (quest_name == "trash") { + if (true) { + modifiers.listAppend("+200% item"); + //Progress on this quest seems to be bugged - starts at zero, doesn't change unless we look at the quest log. + //description.listAppend("Progress: " + progress); + description.listAppend("Run +200% item."); + if (lookupItem("gas can").item_amount() > 0) { + description.listAppend(listMake("Check out the kitchen", "Burn some trash").listJoinComponents(__html_right_arrow_character)); + } else if (!in_ronin()) { + description.listAppend("Buy a gas can in the mall?"); + } + } else { + finished = true; + } + } else if (quest_name == "woots") { + if (progress < 100) { + description.listAppend(progress + " out of 100 megawoots."); + //equip cosmetic football + if (lookupItem("cosmetic football").available_amount() == 0 && !in_ronin()) { + description.listAppend("Buy the cosmetic football in the mall?"); + } + if (lookupItem("cosmetic football").available_amount() > 0 && lookupItem("cosmetic football").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the cosmetic football.", "red")); + url = "inventory.php?ftext=cosmetic+football"; + } + //very small red dress + if (lookupItem("very small red dress").item_amount() > 0) { + description.listAppend(listMake("Head upstairs", "Toss the red dress on the lamp").listJoinComponents(__html_right_arrow_character)); + } else if (!in_ronin()) { + description.listAppend("Buy a very small red dress in the mall?"); + } + //electronics kit + if (lookupItem("electronics kit").item_amount() > 0) { + description.listAppend(listMake("Investigate the basement", "Modify the living room lights").listJoinComponents(__html_right_arrow_character)); + } else if (!in_ronin()) { + description.listAppend("Buy a electronics kit in the mall?"); + } + } else + finished = true; + } else if (quest_name == "dj") { + if (progress > 0) { + modifiers.listAppend("+meat"); + modifiers.listAppend("olfact jocks"); + modifiers.listAppend("banish burnouts"); + description.listAppend(progress + " meat remaining."); + description.listAppend("Run +meat, olfact jocks, banish burnouts."); + if (my_buffedstat($stat[moxie]) >= 300) { + description.listAppend("Open the safe.|" + listMake("Head upstairs", "Crack the safe").listJoinComponents(__html_right_arrow_character)); + } else { + description.listAppend("Possibly buff to 300 moxie?"); + modifiers.listAppend("300 moxie"); + } + } else + finished = true; + } else if (quest_name == "") { + } else + description.listAppend("Unhandled quest \"" + quest_name + "\""); + if (finished) { + description.listAppend("Visit the party one last time to finish the quest."); + } + optional_task_entries.listAppend(ChecklistEntryMake("__item party hat", url, ChecklistSubentryMake("Neverending Party Quest", modifiers, description), 8, lookupLocations("The Neverending Party")).ChecklistEntrySetIDTag("Neverending party quest")); + } +} + +RegisterResourceGenerationFunction("IOTMNeverendingPartyGenerateResource"); +void IOTMNeverendingPartyGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!mafiaIsPastRevision(18865)) + return; + if (!__iotms_usable[lookupItem("Neverending Party invitation envelope")]) + return; + + int free_fights_left = clampi(10 - get_property_int("_neverendingPartyFreeTurns"), 0, 10); + string party_fair_state = get_property("_questPartyFair"); + if (party_fair_state == "finished") + free_fights_left = 0; + string [int] modifiers; + string [int] description; + modifiers.listAppend("+meat"); + + if (party_fair_state == "unstarted") // need to do it that way because Guide's QuestState logic confuses "unstarted" and "" + description.listAppend("Need to accept or reject daily quest first."); + + if (free_fights_left >= 2) { + if (__misc_state["need to level"]) { + string [int] directions; + if (my_primestat() == $stat[muscle]) { + directions.listAppend("Kitchen"); + directions.listAppend("Muscle spice"); + } else if (my_primestat() == $stat[mysticality]) { + directions.listAppend("Upstairs"); + directions.listAppend("Read the tomes"); + } else if (my_primestat() == $stat[moxie]) { + directions.listAppend("Basement"); + directions.listAppend("Use the hair gel"); + } + description.listAppend("Experience buff: " + directions.listJoinComponents(__html_right_arrow_character) + "."); + } + if (__misc_state["in run"]) + description.listAppend("ML buff: " + listMake("Backyard", "Candle wax").listJoinComponents(__html_right_arrow_character)); + } + if (free_fights_left > 0) + resource_entries.listAppend(ChecklistEntryMake("__item party hat", "place.php?whichplace=town_wrong", ChecklistSubentryMake(pluralise(free_fights_left, "free party fight", "free party fights"), modifiers, description), lookupLocations("The Neverending Party")).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Neverending party free fights")); + +} + + +RegisterResourceGenerationFunction("IOTMLatteGenerateResource"); +void IOTMLatteGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (lookupItem("latte lovers member's mug").available_amount() == 0) return; + + int refills_remaining = clampi(3 - get_property_int("_latteRefillsUsed"), 0, 3); + boolean banish_used = get_property_boolean("_latteBanishUsed"); + boolean copy_used = get_property_boolean("_latteCopyUsed"); //more of an olfact than a copy + boolean drink_used = get_property_boolean("_latteDrinkUsed"); + + int banishes_available = refills_remaining + (!banish_used ? 1 : 0); + int copies_available = refills_remaining + (!copy_used ? 1 : 0); + + string url; + boolean latte_needs_equipping = false; + if (lookupItem("latte lovers member's mug").equipped_amount() == 0) + { + url = "inventory.php?which=2"; + latte_needs_equipping = true; + } + if (banishes_available > 0 && $skill[Throw Latte on Opponent].skill_is_usable()) + { + string banish_url = url; + string [int] description; + + if (banish_used) { + banish_url = "main.php?latte=1"; + description.listAppend(HTMLGenerateSpanFont("Must refill latte first.", "red")); + } else if (latte_needs_equipping) { + banish_url = "inventory.php?which=3"; + description.listAppend(HTMLGenerateSpanFont("Equip the latte first", "red")); + } else { + description.listAppend("Free run/banish"); + } + + resource_entries.listAppend(ChecklistEntryMake("__item latte lovers member's mug", banish_url, ChecklistSubentryMake(pluralise(banishes_available, "latte banish", "latte banishes"), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Latte lovers mug throw banish")); + } + + ChecklistEntry entry; + entry.image_lookup_name = "__item latte lovers member's mug"; + entry.url = "main.php?latte=1"; + entry.tags.id = "Latte lovers mug resource"; + + if (refills_remaining > 0) + { + string [int] description; + if (!banish_used && __misc_state["in run"]) + description.listAppend(HTMLGenerateSpanFont("Use banish first.", "red")); + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(refills_remaining, "latte refill", "latte refills"), "", description)); + } + if (copies_available > 0 && $skill[Offer Latte to Opponent].skill_is_usable()) + { + string [int] description; + description.listAppend("Offer Latte to Opponent in combat."); + if (copy_used) + { + description.listAppend(HTMLGenerateSpanFont("Must refill latte first.", "red")); + } + if ($skill[Transcendent Olfaction].have_skill()) + description.listAppend("Stack with Transcendent Olfaction."); + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(copies_available, "latte olfaction", "latte olfactions"), "", description)); + } + if (!drink_used && my_path().id != PATH_VAMPIRE) + { + entry.subentries.listAppend(ChecklistSubentryMake("Gulp Latte available", "", "Restores half your HP and MP. Cast in combat.")); + } + if (entry.subentries.count() > 0) + resource_entries.listAppend(entry); +} + + +//Throw your voting boot: +RegisterTaskGenerationFunction("IOTMVotingBootGenerateTasks"); +void IOTMVotingBootGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!mafiaIsPastRevision(18965)) + return; + if (!__iotms_usable[lookupItem("voter registration form")] && lookupItem(""I Voted!" sticker").available_amount() == 0) return; + + if (lookupItem(""I Voted!" sticker").available_amount() == 0 || false) { + //Vote! + string [int] description; + if (in_ronin()) + description.listAppend("Gives special modifiers, and unlocks three free fights to burn delay."); + else + description.listAppend("Gives special modifiers."); + optional_task_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", "place.php?whichplace=town_right&action=townright_vote", ChecklistSubentryMake("Vote!", "", description), 8).ChecklistEntrySetIDTag("Voting booth daily ballot")); + return; + } + + int turns_before_vote_fight = 11 - (((total_turns_played() % 11) - 1 + 11) % 11); + boolean vote_fight_now = total_turns_played() % 11 == 1 && get_property_int("lastVoteMonsterTurn") < total_turns_played(); + int vote_free_fights_left = 3 - get_property_int("_voteFreeFights"); + + if (vote_free_fights_left > 0) { + if (vote_fight_now) { + string url = ""; + string [int] description; + if (lookupItem(""I Voted!" sticker").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the I Voted! sticker first.", "red")); + url = "inventory.php?ftext=i+voted!"; + } + description.listAppend("Free fight that burns delay. " + vote_free_fights_left + " left."); + location [int] possible_locations = generatePossibleLocationsToBurnDelay(); + if (possible_locations.count() > 0) { + description.listAppend("Adventure in " + possible_locations.listJoinComponents(", ", "or") + " to burn delay."); + if (url == "") + url = possible_locations[0].getClickableURLForLocation(); + } + monster fighting_monster = get_property_monster("_voteMonster"); + string title = "Fight voting monster"; + if (fighting_monster != $monster[none]) + title += " " + fighting_monster; + task_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", url, ChecklistSubentryMake(title, "", description), -11).ChecklistEntrySetIDTag("Voting booth voting monster now")); + } else { + optional_task_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", "", ChecklistSubentryMake("Voting monster after " + pluralise(turns_before_vote_fight, "More Turn", "more turns") + "", "", "Free fight to burn delay with (" + vote_free_fights_left + " left)."), 10).ChecklistEntrySetIDTag("Voting booth voting monster reminder")); //merge those two? or give the player the choice, at least? + } + } + + if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5 && vote_free_fights_left <= 0 && vote_fight_now && $skill[meteor lore].have_skill() && get_property_int("_macrometeoriteUses") < 10 && !CounterLookup("portscan.edu").CounterWillHitNextTurn() && $location[Sonofa Beach].locationAvailable()) { //Could change this to make it compatible with Replace Enemy? + string title = "Lobsterfrogman voting macrometeorite trick time"; + string [int] description; + string url = ""; + monster fighting_monster = get_property_monster("_voteMonster"); + if (lookupItem(""I Voted!" sticker").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the I Voted! sticker first.", "red")); + url = "inventory.php?ftext=i+voted!"; + } + description.listAppend("Adventure in the sonofa beach, macrometeorite the " + (fighting_monster == $monster[none] ? "voting monster" : fighting_monster.to_string()) + ", and you'll get a lobsterfrogman."); + task_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", url, ChecklistSubentryMake(title, "", description), -11).ChecklistEntrySetIDTag("Voting booth LFM wanderer-switch-copy trick")); + + } +} + +RegisterResourceGenerationFunction("IOTMVotingBootGenerateResource"); +void IOTMVotingBootGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (lookupItem(""I Voted!" sticker").available_amount() == 0) return; + + int vote_free_fights_left = 3 - get_property_int("_voteFreeFights"); + if (get_property_int("_voteFreeFights") < 3) { + resource_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", "", ChecklistSubentryMake(pluralise(vote_free_fights_left, "voting monster", "voting monsters"), "", "Free fight."), 8).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Voting booth voting monster free fight")); + } +} + +RegisterTaskGenerationFunction("IOTMBoxingDaycareGenerateTasks"); +void IOTMBoxingDaycareGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[lookupItem("Boxing Day care package")]) return; + //collect nap consumable + ChecklistEntry entry; + entry.url = "place.php?whichplace=town_wrong&action=townwrong_boxingdaycare"; + entry.image_lookup_name = "__item orange boxing gloves"; + entry.tags.id = "Boxing daycare daily tasks"; + entry.importance_level = 8; + if (!get_property_boolean("_daycareNap")) + { + entry.subentries.listAppend(ChecklistSubentryMake("Take a daycare nap", "", "Gives a consumable.")); + } + //scavenge once + if (get_property_int("_daycareGymScavenges") == 0 && __misc_state["need to level"]) + { + entry.subentries.listAppend(ChecklistSubentryMake("Scavenge for daycare equipment", "", "Statgain.")); + } + else if (get_property_int("_daycareRecruits") < 1 && __misc_state["in run"] && $skill[Army of Toddlers].skill_is_usable() && __misc_state["need to level"] && my_meat() >= 100) + { + entry.subentries.listAppend(ChecklistSubentryMake("Recruit at the boxing daycare?", "", "100 meat, benefits army of toddlers statgain.")); + } + if (entry.subentries.count() > 0) + { + optional_task_entries.listAppend(entry); + } +} + +RegisterResourceGenerationFunction("IOTMBoxingDaycareGenerateResource"); +void IOTMBoxingDaycareGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[lookupItem("Boxing Day care package")]) return; + //buffs + if (!get_property_boolean("_daycareSpa")) + { + string [int] description; + if (in_ronin() && my_path().id != PATH_G_LOVER) + { + description.listAppend("+200% muscle, +15 ML"); + description.listAppend("+200% moxie, +50% init"); + description.listAppend("+200% myst, +25% item"); + description.listAppend("+100 HP, +50 MP, +25 DR, +~8 MP regen, +~15 HP regen"); + } + else if (in_ronin() && my_path().id == PATH_G_LOVER) + description.listAppend("+100 HP, +50 MP, +25 DR, +~8 MP regen, +~15 HP regen"); + else + description.listAppend("+200% myst, +25% item"); + resource_entries.listAppend(ChecklistEntryMake("__item orange boxing gloves", "place.php?whichplace=town_wrong&action=townwrong_boxingdaycare", ChecklistSubentryMake("Boxing daycare buff (100 turns)", description), 5).ChecklistEntrySetCombinationTag("boxing daycare resources").ChecklistEntrySetIDTag("Boxing daycare daily spa")); + } + if (hippy_stone_broken() && !get_property_boolean("_daycareFights") && !__misc_state["in run"]) + { + string [int] description; + description.listAppend("Costs one adventure. Spar."); + if (get_property_int("daycareToddlers") <= 2) + description.listAppend("Should recruit first."); + resource_entries.listAppend(ChecklistEntryMake("__item orange boxing gloves", "place.php?whichplace=town_wrong&action=townwrong_boxingdaycare", ChecklistSubentryMake("Boxing daycare PVP fights", description), 5).ChecklistEntrySetCombinationTag("boxing daycare resources").ChecklistEntrySetIDTag("Boxing daycare daily spar")); + + } + if (__misc_state["in run"] && $skill[Army of Toddlers].skill_is_usable() && !get_property_boolean("_armyToddlerCast") && __misc_state["need to level"]) + { + string [int] description; + //is this mainstat or what + float total_statgain = sqrt(get_property_int("daycareToddlers"));// * (1.0 + numeric_modifier(my_primestat() + " experience percent") / 100.0); + float [stat] split_statgain = {$stat[muscle]:total_statgain * 0.25, $stat[mysticality]:total_statgain * 0.25, $stat[moxie]:total_statgain * 0.25}; + split_statgain[my_primestat()] = total_statgain * 0.5; + foreach s, v in split_statgain + { + split_statgain[s] = v * (1.0 + numeric_modifier(s + " experience percent") / 100.0); + } + string [int] stats_out; + stats_out.listAppend(split_statgain[$stat[muscle]].roundForOutput(0)); + stats_out.listAppend(split_statgain[$stat[mysticality]].roundForOutput(0)); + stats_out.listAppend(split_statgain[$stat[moxie]].roundForOutput(0)); + + description.listAppend("50 MP, gain " + stats_out.listJoinComponents(" / ") + " stats."); + if (split_statgain[my_primestat()] < 3.0 || get_property_int("daycareToddlers") <= 2) + description.listAppend("Might want to recruit first."); + resource_entries.listAppend(ChecklistEntryMake("__skill Army of Toddlers", "", ChecklistSubentryMake("Army of Toddlers castable", description), 5).ChecklistEntrySetCombinationTag("boxing daycare resources").ChecklistEntrySetIDTag("Boxing daycare toddler army")); + + } +} + + +// 2019 +RegisterTaskGenerationFunction("IOTMKramcoSausageOMaticGenerateTasks"); +void IOTMKramcoSausageOMaticGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[lookupItem("Kramco Sausage-o-Matic™")]) return; + + //If goblin is up, display reminder: + KramcoSausageFightInformation fight_information = KramcoCalculateSausageFightInformation(); + if (fight_information.turns_to_next_guaranteed_fight == 0 && my_path().id != PATH_LIVE_ASCEND_REPEAT && __misc_state["in run"]) + { + + string url = ""; + string [int] description; + string title = "Fight sausage goblin "; + int kramcosEquipped = lookupItem("Kramco Sausage-o-Matic™").equipped_amount() + lookupItem("replica Kramco Sausage-o-Matic™").equipped_amount(); + + if (kramcosEquipped == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the Kramco Sausage-o-Matic™ first.", "red")); + url = "inventory.php?ftext=kramco+sausage-o-matic"; + } + description.listAppend("Free fight that burns delay."); + location [int] possible_locations = generatePossibleLocationsToBurnDelay(); + if (possible_locations.count() > 0) { + description.listAppend("Adventure in " + possible_locations.listJoinComponents(", ", "or") + " to burn delay."); + if (url == "") + url = possible_locations[0].getClickableURLForLocation(); + } + task_entries.listAppend(ChecklistEntryMake("__item Kramco Sausage-o-Matic™", url, ChecklistSubentryMake(title, "", description), -11).ChecklistEntrySetIDTag("Kramco sausage grinder goblin fight reminder")); + } +} + +RegisterResourceGenerationFunction("IOTMKramcoSausageOMaticGenerateResource"); +void IOTMKramcoSausageOMaticGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[lookupItem("Kramco Sausage-o-Matic™")] || my_path().id == PATH_LIVE_ASCEND_REPEAT) return; + + ChecklistEntry entry; + entry.image_lookup_name = "__item Kramco Sausage-o-Matic™"; + entry.url = "inventory.php?action=grind"; + entry.tags.id = "Kramco sausage grinder resource"; + entry.importance_level = -2; + + string [int] main_description; + string main_title; + + KramcoSausageFightInformation fight_information = KramcoCalculateSausageFightInformation(); + + int kramcosEquipped = lookupItem("Kramco Sausage-o-Matic™").equipped_amount() + lookupItem("replica Kramco Sausage-o-Matic™").equipped_amount(); + + if (fight_information.turns_to_next_guaranteed_fight == 0) { + main_title = "Sausage goblin fight available"; + if (kramcosEquipped == 0) { + main_description.listAppend(HTMLGenerateSpanFont("Equip the Kramco Sausage-o-Matic™ first.", "red")); + entry.url = "inventory.php?action=grind"; + } + } else { + main_title = round(fight_information.probability_of_sausage_fight * 100.0) + "% chance of Kramco fight this turn"; + main_description.listAppend(pluralise(fight_information.turns_to_next_guaranteed_fight, "turn", "turns") + " until next guaranteed goblin fight."); + if (kramcosEquipped == 0) { + main_description.listAppend(HTMLGenerateSpanFont("Equip the Kramco Sausage-o-Matic™ first.", "red")); + entry.url = "inventory.php?action=grind"; + } + } + + main_description.listAppend("Does not cost a turn; burns delay."); + + int fights_so_far = get_property_int("_sausageFights"); + if (fights_so_far > 0) { + main_description.listAppend("Fought " + pluralise(fights_so_far, "goblin", "goblins") + " so far."); + } + + entry.subentries.listAppend(ChecklistSubentryMake(main_title, "", main_description)); + + int sausage_casings = lookupItem("magical sausage casing").available_amount(); + int sausages_eaten = get_property_int("_sausagesEaten"); + int sausages_available = lookupItem("magical sausage").available_amount(); + int possible_sausages = sausages_available + sausage_casings; + if (possible_sausages > 0 && sausages_eaten < 23) { + string [int] sausage_description; + int sausages_made = get_property_int("_sausagesMade"); + int meat_cost = 111 * (sausages_made + 1); + sausage_description.listAppend("+1 adventure and +999 MP each."); + sausage_description.listAppend(HTMLGenerateSpanOfClass(sausage_casings, "r_bold") + " casings available, " + HTMLGenerateSpanOfClass(sausages_eaten + "/23", "r_bold") + " eaten today."); + if (sausages_made > 22) + { + sausage_description.listAppend(HTMLGenerateSpanFont(sausages_made + " sausages made today.", "purple")); + } + else + { + sausage_description.listAppend(pluralise(sausages_made, "sausage", "sausages") + " made; next costs " + meat_cost + " meat."); + } + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(MIN(sausages_available, 23 - sausages_eaten), "magical sausage", "magical sausages") + " edible", "", sausage_description)); + } + + resource_entries.listAppend(entry); +} +RegisterTaskGenerationFunction("IOTMLilDoctorBagGenerateTasks"); +void IOTMLilDoctorBagGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (lookupItem("Lil' Doctor™ bag").available_amount() == 0) return; + //Quest: + int doctor_bag_upgrades = get_property_int("doctorBagUpgrades"); + int doctor_bag_lights = get_property_int("doctorBagQuestLights"); + string doctor_bag_quest_state = get_property("questDoctorBag"); + + if (doctor_bag_quest_state == "unstarted" && (doctor_bag_upgrades > 6 || __misc_state["in run"])) return; + + string title; + string [int] description; + string url; + + if (doctor_bag_quest_state != "unstarted") { + location doctor_bag_quest_location = get_property_location("doctorBagQuestLocation"); + item doctor_bag_quest_item = get_property_item("doctorBagQuestItem"); + title = "Medic! Medic!!"; + url = doctor_bag_quest_location.getClickableURLForLocation(); + + if (doctor_bag_quest_item.item_amount() == 0) + description.listAppend("Acquire a " + (doctor_bag_quest_item != $item[none] ? doctor_bag_quest_item + "." : "something..?")); + description.listAppend("Adventure in " + doctor_bag_quest_location + "."); + + description.listAppend("Will give " + (doctor_bag_upgrades < 7 ? "progress towards upgrading the bag and " : "") + "meat."); // There is no "n° of quests completed this ascension" property, so can't predict how much you'll get + } + + if (doctor_bag_upgrades < 7) { + if (title == "") { + title = "Upgrade your Lil' Doctor™ bag"; + description.listAppend("Adventure with your doctor bag equipped to get a delivery quest."); // no way to know if they "turned off" their bag + } + description.listAppend(pluralise(35 - doctor_bag_lights - doctor_bag_upgrades * 5, "quest", "quests") + " until bag is fully upgraded."); + } + + optional_task_entries.listAppend(ChecklistEntryMake("__item Lil' Doctor™ bag", url, ChecklistSubentryMake(title, "", description), 9).ChecklistEntrySetIDTag("Lil doctor bag upgrade quest")); +} + +RegisterResourceGenerationFunction("IOTMLilDoctorBagGenerateResource"); +void IOTMLilDoctorBagGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (lookupItem("Lil' Doctor™ bag").available_amount() == 0) return; + //Otoscope: +200% item + int otoscopes_left = clampi(3 - get_property_int("_otoscopeUsed"), 0, 3); + boolean otoscope_usable = my_path().id != PATH_G_LOVER && my_path().id != PATH_POCKET_FAMILIARS; + if (otoscopes_left > 0 && otoscope_usable && __misc_state["in run"]) + { + string url; + string [int] description; + description.listAppend("+200% item for one turn, cast in combat."); + + if (lookupItem("Lil' Doctor™ bag").equipped_amount() == 0) + { + description.listAppend("Equip the Lil' Doctor™ bag first."); + url = "inventory.php?ftext=lil'+doctor"; + } + resource_entries.listAppend(ChecklistEntryMake("__item Lil' Doctor™ bag", url, ChecklistSubentryMake(pluralise(otoscopes_left, "otoscope", "otoscopes"), "", description), 8).ChecklistEntrySetIDTag("Lil doctor bag otoscope")); + } + //Chest X-Ray: instakill + int instakills_left = clampi(3 - get_property_int("_chestXRayUsed"), 0, 3); + boolean instakills_usable = my_path().id != PATH_G_LOVER && my_path().id != PATH_POCKET_FAMILIARS; + if (instakills_left > 0 && instakills_usable) + { + string url; + string [int] description; + description.listAppend("Win a fight without taking a turn."); + + if (lookupItem("Lil' Doctor™ bag").equipped_amount() == 0) + { + description.listAppend("Equip the Lil' Doctor™ bag first."); + url = "inventory.php?ftext=lil'+doctor"; + } + resource_entries.listAppend(ChecklistEntryMake("__item Lil' Doctor™ bag", url, ChecklistSubentryMake(pluralise(instakills_left, "chest x-ray", "chest x-rays"), "", description), 0).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Lil doctor bag x-ray free kill")); + + } + //Reflex Hammer: Banish + int banishes_left = clampi(3 - get_property_int("_reflexHammerUsed"), 0, 3); + boolean banishes_usable = my_path().id != PATH_G_LOVER && my_path().id != PATH_POCKET_FAMILIARS; + if (banishes_left > 0 && banishes_usable) + { + string url; + string [int] description; + if (lookupItem("Lil' Doctor™ bag").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the Lil' Doctor™ bag first", "red")); + url = "inventory.php?ftext=lil'+doctor"; + } else { + description.listAppend("Free run, 30-turn banish."); + } + resource_entries.listAppend(ChecklistEntryMake("__item Lil' Doctor™ bag", url, ChecklistSubentryMake(pluralise(banishes_left, "reflex hammer", "reflex hammers"), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Lil doctor bag reflex hammer banish")); + } +} + + +RegisterResourceGenerationFunction("IOTMVampireCloakGenerateResource"); +void IOTMVampireCloakGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[vampyric cloake]]) return; + if (!(__misc_state["in run"] && in_ronin())) return; + + int uses_left = clampi(10 - get_property_int("_vampyreCloakeFormUses"), 0, 10); + if (uses_left > 0 && __iotms_usable[$item[vampyric cloake]] && my_path().id != PATH_POCKET_FAMILIARS) { + string [int] skills; + skills.listAppend("Wolf: +50% muscle, +50% meat"); + skills.listAppend("Mist: +2 all res"); + skills.listAppend("Bat: +50% item"); + + string [int] description; + description.listAppend("In-combat cast one of the Become skills, to gain a buff for that fight:|*" + skills.listJoinComponents("|*")); + resource_entries.listAppend(ChecklistEntryMake("__item vampyric cloake", !$item[vampyric cloake].equipped() ? $item[vampyric cloake].invSearch() : "", ChecklistSubentryMake(pluralise(uses_left, "vampyric skill use", "vampyric skill uses"), "", description), 5).ChecklistEntrySetIDTag("Vampyric cloake combat skills resource")); + } +} + +// Missing: PirateRealm +RegisterTaskGenerationFunction("IOTMMaySaberPartyGenerateTasks"); +void IOTMMaySaberPartyGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[$item[Fourth of May Cosplay Saber]]) return; + if (my_path().id == PATH_G_LOVER) return; // cannot use saber in g-lover + + if (get_property_int("_saberMod") == 0) { + string [int] options; + if (in_ronin()) { + options.listAppend("Regen ~17 MP/adventure."); + options.listAppend("+20 ML."); + options.listAppend("+3 all resistances."); + } + options.listAppend("+10 familiar weight."); + + string [int] description; + if (options.count() > 1) + description.listAppend("Choose one of:|*" + options.listJoinComponents("|*")); + else + description.listAppend(options.listJoinComponents("|")); + optional_task_entries.listAppend(ChecklistEntryMake("__item Fourth of May Cosplay Saber", "main.php?action=may4", ChecklistSubentryMake("Modify your lightsaber", "", description), 8).ChecklistEntrySetIDTag("Fourth may saber daily upgrade")); + } + + + monster saber_monster = get_property_monster("_saberForceMonster"); + if (saber_monster != $monster[none]) { + int fights_left = clampi(get_property_int("_saberForceMonsterCount"), 0, 3); + location [int] possible_appearance_locations = saber_monster.getPossibleLocationsMonsterCanAppearInNaturally().listInvert(); + + if (fights_left > 0 && possible_appearance_locations.count() > 0) + optional_task_entries.listAppend(ChecklistEntryMake("__monster " + saber_monster, possible_appearance_locations[0].getClickableURLForLocation(), ChecklistSubentryMake("Fight " + pluralise(fights_left, "more " + saber_monster, "more " + saber_monster + "s"), "", "Will appear when you adventure in " + possible_appearance_locations.listJoinComponents(", ", "or") + "."), -1).ChecklistEntrySetIDTag("Fourth may saber friend copies")); + } +} + +RegisterResourceGenerationFunction("IOTMMaySaberGenerateResource"); +void IOTMMaySaberGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[Fourth of May Cosplay Saber]]) + return; + + if (my_path().id == PATH_G_LOVER) return; // cannot use saber in g-lover + + int sabersEquipped = lookupItem("Fourth of May Cosplay Saber").equipped_amount() + lookupItem("replica Fourth of May Cosplay Saber").equipped_amount(); + + int uses_remaining = clampi(5 - get_property_int("_saberForceUses"), 0, 5); + + if (uses_remaining > 0) { + if (true) { + //The section that will be sent as a stand-alone resource + string url; + if (sabersEquipped == 0) + url = "inventory.php?ftext=fourth+of+may+cosplay+saber"; + + string [int] description; + description.listAppend("Use the force skill in combat, which lets you:"); + description.listAppend("Banish a monster for thirty turns."); + description.listAppend("Make the monster appear 3x times its zone."); + description.listAppend("Or collect all* their items."); + if (my_path().id == PATH_COMMUNITY_SERVICE && $skill[Meteor Lore].have_skill()) + description.listAppend("Bonus! Use Meteor Shower + lightsaber skill to save a bunch of turns on weapon damage/spell damage/familiar weight tests."); + + resource_entries.listAppend(ChecklistEntryMake("__item Fourth of May Cosplay Saber", url, ChecklistSubentryMake(uses_remaining.pluralise("force use", "forces uses"), "", description)).ChecklistEntrySetIDTag("Fourth may saber force resource")); //"forces uses"? typo or reference/joke? + } + + if (true) { + //The section that will be sent as a "banish" tile + string [int] description; + if (sabersEquipped == 0) + description.listAppend(HTMLGenerateSpanFont("Equip the Fourth of May saber first", "red")); + else + description.listAppend("Rollover runaway-like/banish"); + + resource_entries.listAppend(ChecklistEntryMake("__item Fourth of May Cosplay Saber", "inventory.php?which=2", ChecklistSubentryMake("(up to) " + uses_remaining.pluralise("force banish", "forces banishes"), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Fourth may saber force banish")); + } + } +} + +//moonTuned +RegisterResourceGenerationFunction("IOTMRuneSpoonGenerateResource"); +void IOTMRuneSpoonGenerateResource(ChecklistEntry [int] resource_entries) +{ + item spoon = lookupItem("hewn moon-rune spoon"); + if (!__iotms_usable[lookupItem("hewn moon-rune spoon")] && spoon.closet_amount() == 0 || my_sign().to_lower_case() == "bad moon") return; + if (my_path().id == PATH_G_LOVER) return; // glover does not get spoon tuning + + // Use the right item ID depending on if you are using a replica or a non-replica + string activeSpoonID = lookupItem("replica hewn moon-rune spoon").available_amount() > 0 ? "11242" : "10254"; + + if (!get_property_boolean("moonTuned")) + { + stat [string] stat_for_sign = + { + "Mongoose":$stat[Muscle], + "Wallaby":$stat[Mysticality], + "Vole":$stat[Moxie], + + "Platypus":$stat[Muscle], + "Opossum":$stat[Mysticality], + "Marmot":$stat[Moxie], + + "Wombat":$stat[Muscle], + "Blender":$stat[Mysticality], + "Packrat":$stat[Moxie], + }; + string [string] signs = + { + "Mongoose":"+20% physical damage, knoll access, and free smithing", + "Wallaby":"+20% spell damage, knoll access, and free smithing", + "Vole":"+20% init, knoll access, and free smithing", + + "Platypus":"+5 familiar weight and canadia access", + "Opossum":"+5 adventures/day from food and canadia access", + "Marmot":"+1 all resistance and canadia access", + + "Wombat":"+20% meat and gnome access", + "Blender":"+5 adventures/day from drinks and gnome access", + "Packrat":"+10% item and gnome access", + + }; + boolean [string] signs_to_output_as_ideas = $strings[Marmot,Platypus,Opossum,Blender,Packrat]; + + if (!__misc_state["in run"]) + signs_to_output_as_ideas = $strings[Platypus,Opossum,Wombat,Blender,Packrat]; + boolean our_sign_is_currently_good_for_stats = stat_for_sign[my_sign()] == my_primestat(); + string [int] description; + description.listAppend("Use the hewn moon-rune spoon. Lets you switch to any other moon sign."); + if ($strings[Mongoose,Wallaby,Vole] contains my_sign()) + { + string [int] todo; + if (!__misc_state["desert beach available"]) + todo.listAppend("assemble a bitchin' meatcar"); + if (!have_outfit_components("Bugbear Costume")) + todo.listAppend("buy a bugbear costume"); + if (todo.count() > 0) + description.listAppend("May want to " + todo.listJoinComponents(", ", "and") + " before switching signs."); + } + string [int] options; + + foreach sign, desc in signs + { + if (my_sign() == sign) continue; + if (!signs_to_output_as_ideas[sign]) continue; + if (sign == "Platypus" && __misc_state["familiars temporarily blocked"]) continue; + if (sign == "Opossum" && (!__misc_state["can eat just about anything"] || my_path().id == PATH_SLOW_AND_STEADY)) continue; + if (sign == "Blender" && (!__misc_state["can drink just about anything"] || my_path().id == PATH_SLOW_AND_STEADY)) continue; + boolean this_sign_is_good_for_mainstat_gain = stat_for_sign[sign] == my_primestat(); + string line = "" + sign + ": " + desc + "."; + if (!this_sign_is_good_for_mainstat_gain && __misc_state["need to level"] && __misc_state["in run"]) + line += " Won't give mainstat gains."; + else if (this_sign_is_good_for_mainstat_gain && __misc_state["need to level"] && __misc_state["in run"]) + line += " Will give mainstat gains."; + options.listAppend(line); + } + + description.listAppend("Currently " + my_sign() + ": " + signs[my_sign()] + "."); + if (options.count() > 0) + description.listAppend("Ideas:|*" + options.listJoinComponents("
")); + + string url = "inv_use.php?whichitem=" + activeSpoonID + "&pwd=" + my_hash(); + if (!__iotms_usable[lookupItem("hewn moon-rune spoon")] && spoon.closet_amount() > 0) + url = "closet.php?which=2"; + resource_entries.listAppend(ChecklistEntryMake("__item " + spoon, url, ChecklistSubentryMake("Moon sign tunable", "", description), 10).ChecklistEntrySetIDTag("Roon spoon moon boon toon moon")); + } +} + + +RegisterResourceGenerationFunction("IOTMBeachCombGenerateResource"); +void IOTMBeachCombGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (lookupItem("beach comb").available_amount() == 0) return; + int free_walks_left = clampi(11 - get_property_int("_freeBeachWalksUsed"), 0, 11); + if (free_walks_left == 0) + return; + + boolean [int] beach_heads_used = get_property("_beachHeadsUsed").stringToIntIntList(",").listInvert(); + + string [int] description; + string [int] buffs; + + string [int] elemental_buffs; + boolean in_run = __misc_state["in run"]; + if (!beach_heads_used[1]) + elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Hot-Headed", "r_element_hot")); + if (!beach_heads_used[2]) + elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Cold as Nice", "r_element_cold")); + if (!beach_heads_used[3]) + elemental_buffs.listAppend(HTMLGenerateSpanOfClass("A Brush with Grossness", "r_element_stench")); + if (!beach_heads_used[4]) + elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Does It Have a Skull In There??", "r_element_spooky")); + if (!beach_heads_used[5]) + elemental_buffs.listAppend(HTMLGenerateSpanOfClass("Oiled\, Slick", "r_element_sleaze")); + + if (elemental_buffs.count() > 0 && in_run) + buffs.listAppend("" + elemental_buffs.listJoinComponents(" / ") + ": +3 X resistance, +15 X damage, +15 X spell damage."); + if (!beach_heads_used[6] && in_run) + buffs.listAppend("Lack of Body-Building: +50% muscle, +25% weapon damage."); // hah + if (!beach_heads_used[7] && in_run) + buffs.listAppend("We're All Made of Starfish: +50% myst, +25% spell damage."); + if (!beach_heads_used[8] && in_run) + buffs.listAppend("Pomp & Circumsands: +50% moxie, +25% ranged damage."); + if (!beach_heads_used[9] && in_run) + buffs.listAppend("Resting Beach Face: +50% init."); + if (!beach_heads_used[10]) + buffs.listAppend("Do I Know You From Somewhere?: +5 familiar weight."); + if (!beach_heads_used[11] && in_run) + buffs.listAppend("You Learned Something Maybe!: +5 stats/fight."); + + if (buffs.count() > 0) + description.listAppend("Buffs:
" + buffs.listJoinComponents("
")); + if (free_walks_left >= 10) + description.listAppend((description.count() > 0 ? "Or collect" : "Collect") + " a bunch of items? (10 walks)"); + description.listAppend("Or farm the beach."); + resource_entries.listAppend(ChecklistEntryMake("__item beach comb", "main.php?comb=1", ChecklistSubentryMake(pluralise(free_walks_left, "beach comb", "beach combs"), "", description), 3).ChecklistEntrySetIDTag("Beach comb resource")); +} + +//Getaway Camp +RegisterResourceGenerationFunction("IOTMGetawayCampsiteGenerateResource"); +void IOTMGetawayCampsiteGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[lookupItem("Distant Woods Getaway Brochure")]) return; + + item firewood = lookupItem("stick of firewood"); + int cloud_buffs_left = clampi(1 - get_property_int("_campAwayCloudBuffs"), 0, 1); + int smile_buffs_left = clampi(3 - get_property_int("_campAwaySmileBuffs"), 0, 3); + + if (cloud_buffs_left > 0) { // && lookupEffect("That's Just Cloud-Talk, Man").have_effect() == 0) + string [int] description; + description.listAppend("Large +stat buff. Gaze at the stars."); + if (firewood.have() || lookupItem("campfire smoke").have()) + description.listAppend("If you don't see it, you could make and use campfire smoke first."); + resource_entries.listAppend(ChecklistEntryMake("__item Newbiesport™ tent", "place.php?whichplace=campaway", ChecklistSubentryMake("Cloud-talk buff obtainable", "", description), 0).ChecklistEntrySetCombinationTag("getaway campsite resources").ChecklistEntrySetIDTag("Getaway campsite cloud talk")); + } + if (smile_buffs_left > 0) { // && lookupEffect("That's Just Cloud-Talk, Man").have_effect() == 0) + // Implementation of campSmile.ash by @fredg1 + string [int] [string] buffCycle; + buffCycle [0] ["effect"] = my_sign() == "Blender" ? "+50% booze drop" : "+25% booze drop" ; + buffCycle [0] ["name"] = "Blender"; + buffCycle [1] ["effect"] = my_sign() == "Packrat" ? "+50% meat" : "+25% meat" ; + buffCycle [1] ["name"] = "Packrat"; + buffCycle [2] ["effect"] = my_sign() == "Mongoose" ? "+20% critical hit" : "+10% critical hit" ; + buffCycle [2] ["name"] = "Mongoose"; + buffCycle [3] ["effect"] = my_sign() == "Wallaby" ? "+20% spell critical hit" : "+10% spell critical hit" ; + buffCycle [3] ["name"] = "Wallaby"; + buffCycle [4] ["effect"] = my_sign() == "Vole" ? "+10-30 HP/adventure" : "+5-15 HP/adventure" ; + buffCycle [4] ["name"] = "Vole"; + buffCycle [5] ["effect"] = my_sign() == "Platypus" ? "+5 familiar experience" : "+3 familiar experience" ; + buffCycle [5] ["name"] = "Platypus"; + buffCycle [6] ["effect"] = my_sign() == "Opossum" ? "+100% candy drop" : "+50% candy drop" ; + buffCycle [6] ["name"] = "Opossum"; + buffCycle [7] ["effect"] = my_sign() == "Marmot" ? "+8~12 MP/adventure" : "+4~6 MP/adventure" ; + buffCycle [7] ["name"] = "Marmot"; + buffCycle [8] ["effect"] = my_sign() == "Wombat" ? "Damage Absorption +100" : "Damage Absorption +50" ; + buffCycle [8] ["name"] = "Wombat"; + + int getOffset(int year) { // made by @Skaazi + int offset = 5; // for 2020 + for ( int i = year; i > 2020; i-- ) { + if ( year_is_leap_year( i - 1 ) ) { offset += 1; } + offset += 365; + } + return offset % 9; + } + + string [int] description; + description.listAppend("Gaze at the stars."); + + int offset = getOffset(format_date_time("yyyyMMdd", today_to_string(), "yyyy").to_int()); + int todaysArbitraryNumber = format_date_time("yyyyMMdd", today_to_string(), "D").to_int() + my_path().id + offset; + int todaysCycleNumber = todaysArbitraryNumber % 9; + + description.listAppend("Will get: " + (my_sign() == buffCycle [todaysCycleNumber] ["name"] ? "Big " : "") + "Smile of the " + buffCycle [todaysCycleNumber] ["name"] + " (" + buffCycle [todaysCycleNumber] ["effect"] + ")"); + + string [int][int] tooltip_table; + + // Making today's buff name its own variable + string todaysBuff = buffCycle [todaysCycleNumber] ["name"]; + + // These are the given enchantments for each moonsign day + static string[string] smileEnchantments = { + "Mongoose":"% crit chance", + "Wallaby":"% spell crit", + "Vole":" HP regen", + "Platypus":" familiar XP", + "Opossum":"% candy drop", + "Marmot":" MP regen", + "Wombat":" DA", + "Blender":"% booze drop", + "Packrat":"% meat drop",}; + + // Doing a foreach through the enchantment list + foreach sign, enchantment in smileEnchantments { + // You get a "big smile" for extra bonus enchants for your given moonsign + boolean bigSmile = my_sign() == sign; + + string enchantAmount = ""; + + // There's clearly a better way to do this, but this works. It checks for big smile status + // then gives the correct enchant amount for the final list item. + if ($strings[Mongoose,Wallaby,Vole] contains sign) { + enchantAmount = bigSmile ? "20" : "10"; + } + if ($strings[Blender, Packrat] contains sign) { + enchantAmount = bigSmile ? "50" : "25"; + } + if (sign == "Platypus") { + enchantAmount = bigSmile ? "5" : "3"; + } + if ($strings[Opossum, Wombat] contains sign) { + enchantAmount = bigSmile ? "100" : "50"; + } + if (sign == "Marmot") { + enchantAmount = bigSmile ? "10" : "5" ; + } + + // UPDATE: ... I could've used what fred coded above I'm a big idiot ack + + // Highlight today's buff in red. + string signColor = todaysBuff == sign ? "blue" : "black"; + + // Add the sign to the tooltip table. + tooltip_table.listAppend(listMake(HTMLGenerateSpanFont(sign, signColor), HTMLGenerateSpanFont("+" + enchantAmount + enchantment, signColor))); + } + + buffer tooltip_text; + tooltip_text.append(HTMLGenerateTagWrap("div", "Campfire Smile cycle", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); + tooltip_text.append(HTMLGenerateSimpleTableLines(tooltip_table)); + + string campSmileCycleList = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Campfire Smile cycle", "r_tooltip_outer_class"); + description.listAppend(campSmileCycleList); + + resource_entries.listAppend(ChecklistEntryMake("__item Newbiesport™ tent", "place.php?whichplace=campaway", ChecklistSubentryMake(pluralise(smile_buffs_left, "smile buff", "smile buffs") + " obtainable", "20 turns", description), 5).ChecklistEntrySetCombinationTag("getaway campsite resources").ChecklistEntrySetIDTag("Getaway campsite sign smiles")); + } + if (firewood.have() && __misc_state["in run"]) { + string [int] description; + + string [int] various_options; + if (__misc_state["can eat just about anything"]) + various_options.listAppend("food"); + if (firewood.available_amount() >= 5 && my_path().id != PATH_GELATINOUS_NOOB) { + if (!lookupItem("whittled tiara").have()) + various_options.listAppend("whittled tiara for +elemental damage"); + if (!lookupItem("whittled shorts").have()) + various_options.listAppend("whittled shorts for +2 all res"); + if (!lookupItem("whittled flute").have()) + various_options.listAppend("whittled flute for +25% meat"); + if (firewood.available_amount() >= 10) { + if (!lookupItem("whittled bear figurine").have() && !__misc_state["familiars temporarily blocked"]) + various_options.listAppend("whittled bear figurine for +5 familiar weight"); + if (!lookupItem("whittled owl figurine").have()) + various_options.listAppend("whittled owl figurine for +20 ML"); + if (!lookupItem("whittled fox figurine").have()) + various_options.listAppend("whittled fox figurine figurine for +50% init"); + } + if (firewood.available_amount() >= 100 && !lookupItem("whittled walking stick").have()) + various_options.listAppend("whittled walking stick for a bunch of stuff"); + } + if (various_options.count() > 0) + description.listAppend(various_options.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); + resource_entries.listAppend(ChecklistEntryMake("__item Newbiesport™ tent", "shop.php?whichshop=campfire", ChecklistSubentryMake(pluralise(firewood), "", description), 5).ChecklistEntrySetCombinationTag("getaway campsite resources").ChecklistEntrySetIDTag("Getaway campsite firewood")); + } +} +RegisterResourceGenerationFunction("IOTMPocketProfessorResource"); +void IOTMPocketProfessorResource(ChecklistEntry [int] resource_entries) +{ + ChecklistSubentry getLecture() { + int lecturesAtWeight(int weight, boolean chipEquipped) { + return floor(sqrt(weight - 1)) + 1 + (chipEquipped ? 2 : 0); + } + + // Title + int lecturesUsed = get_property_int("_pocketProfessorLectures"); + int potentialWeight = effective_familiar_weight($familiar[Pocket Professor]) + weight_adjustment(); + int potentialWeightChip = potentialWeight - round(equipped_item($slot[familiar]).numeric_modifier('familiar weight')); + boolean chipEquipped = lookupItem("pocket professor memory chip").have_equipped(); + + int availableLectures = lecturesAtWeight(potentialWeight, chipEquipped) - lecturesUsed; + int nextLectureWeight = lecturesUsed ** 2 + 1; + int nextLectureWeightChip = (lecturesUsed - 2) ** 2 + 1; + + string main_title = (availableLectures > 0 ? pluralise(availableLectures, "lecture", "lectures") : "No lectures") + " available, " + lecturesUsed + " lectures used"; + + // Subtitle + string subtitle = ""; + + // Entries + string [int] description; + if (availableLectures > 0) { + description.listAppend(HTMLGenerateSpanOfClass("Relativity:", "r_bold") + " Fight monster again."); + description.listAppend(HTMLGenerateSpanOfClass("Mass:", "r_bold") + " 3 chances for item drops."); + description.listAppend(HTMLGenerateSpanOfClass("Velocity:", "r_bold") + " Delevel and substats."); + } else { + string noChipMessage = nextLectureWeight + " lbs (+" + (nextLectureWeight - potentialWeight) + " lbs)"; + string chipMessage = nextLectureWeightChip + " lbs (+" + (nextLectureWeightChip - potentialWeightChip) + " lbs)"; + if (!chipEquipped) { + if (nextLectureWeightChip <= potentialWeightChip) { + description.listAppend("Next lecture at " + noChipMessage + ", or now with chip."); + } else { + description.listAppend("Next lecture at " + noChipMessage + ", " + chipMessage + " with chip."); + } + } else { + description.listAppend("Next lecture at " + chipMessage + "."); + } + } + if (get_property("_feastedFamiliars").contains_text("Pocket Professor")) { + description.listAppend(HTMLGenerateSpanFont("Warning: Numbers may not be correct if Moveable Feast has expired.", "red")); + } + + return ChecklistSubentryMake(main_title, subtitle, description); + } + + string scalerMessage(string name, int add, int cap) { + int thesisAdventures(int hp) { + return clampi(2 * floor(hp ** .25), 0, 11); + } + + int ml = numeric_modifier('monster level'); + int muscle = my_buffedstat($stat[muscle]); + int defense = clampi(muscle + add, 0, cap) + ml; + int hp = max(floor(0.75 * defense), 1); + int adventures = thesisAdventures(hp); + string description = name + " (" + adventures + " advs"; + if (adventures < 11 && cap + ml >= 1296 / .75) { + int nextAdventures = adventures + 2; + int nextThreshhold = (nextAdventures / 2) ** 4; + int muscleToCap = ceil(nextThreshhold / .75 - ml - add); + description += ", +" + (muscleToCap - muscle) + " mus for " + clampi(nextAdventures, 0, 11) + " advs"; + } + description += ")"; + return description; + } + + ChecklistSubentry getDeliverYourThesis() { + int experience = $familiar[Pocket Professor].experience; + int experienceLeft = 400 - experience; + + // Title + string main_title = "Deliver thesis"; + + // Subtitle + string subtitle = ""; + + // Entries + string [int] description; + if (!get_property_boolean("_thesisDelivered")) { + if (experience >= 400) { + description.listAppend(HTMLGenerateSpanOfClass("1 instakill", "r_bold") + " but lose 200 familiar xp."); + } else { + description.listAppend("Need " + experienceLeft + " more experience."); + } + + string [int] potential_targets; + + // we don't need to support replicas here because you'll never have pocket prof + replica kramco! + + if (lookupItem("kramco sausage-o-matic").available_amount() > 0) + { + potential_targets.listAppend(scalerMessage("Sausage goblin", 11, 10000)); + } + if (get_property_boolean("neverendingPartyAlways") || get_property_boolean("_neverendingPartyToday")) + { + potential_targets.listAppend(scalerMessage("Neverending Party monster", 0, 20000)); + } + if (potential_targets.count() > 0) { + description.listAppend("Could use it on a:" + HTMLGenerateIndentedText(potential_targets)); + } + } + + return ChecklistSubentryMake(main_title, subtitle, description); + } + + if (!lookupFamiliar("Pocket Professor").familiar_is_usable()) return; + + ChecklistEntry entry; + entry.image_lookup_name = "__familiar pocket professor"; + entry.tags.id = "Pocket professor familiar resource"; + + ChecklistSubentry lectures = getLecture(); + if (lectures.entries.count() > 0) { + entry.subentries.listAppend(lectures); + } + + ChecklistSubentry thesis = getDeliverYourThesis(); + if (thesis.entries.count() > 0) { + entry.subentries.listAppend(thesis); + } + + if (entry.subentries.count() > 0) { + resource_entries.listAppend(entry); + } +} +RegisterResourceGenerationFunction("IOTMEightDaysAWeekPillsGenerateResource"); +void IOTMEightDaysAWeekPillsGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[lookupItem("Eight Days a Week Pill Keeper")]) return; + if (get_property_boolean("_freePillKeeperUsed") && spleen_limit() - my_spleen_use() < 3) return; + + ChecklistSubentry getPills() { + // Title + string main_title = "Take a pill"; + + // Subtitle + string subtitle = "First is Free!"; + if (get_property_boolean("_freePillKeeperUsed")) { + subtitle = "-3 Spleen"; + } + + // Entries + string [int] description; + description.listAppend(HTMLGenerateSpanOfClass("Monday:", "r_bold") + " Yellow ray (30 turns)"); + description.listAppend(HTMLGenerateSpanOfClass("Tuesday:", "r_bold") + " Double potion length"); + description.listAppend(HTMLGenerateSpanOfClass("Wednesday:", "r_bold") + " Force Non-Combat"); + description.listAppend(HTMLGenerateSpanOfClass("Thursday:", "r_bold") + " +4 all res (30 turns)"); + description.listAppend(HTMLGenerateSpanOfClass("Friday:", "r_bold") + " +100% all stats (30 turns)"); + description.listAppend(HTMLGenerateSpanOfClass("Saturday:", "r_bold") + " Familiars 20 pounds (30 turns)"); + description.listAppend(HTMLGenerateSpanOfClass("Sunday:", "r_bold") + " Get Lucky!"); + description.listAppend(HTMLGenerateSpanOfClass("Funday:", "r_bold") + " Random adventures (30 turns)"); + + return ChecklistSubentryMake(main_title, subtitle, description); + } + + ChecklistEntry entry; + entry.image_lookup_name = "__item Eight Days a Week Pill Keeper"; + entry.url = "main.php?eowkeeper=1"; + entry.tags.id = "Pill keeper resource"; + + ChecklistSubentry pills = getPills(); + if (pills.entries.count() > 0) { + entry.subentries.listAppend(pills); + } + + if (entry.subentries.count() > 0) { + resource_entries.listAppend(entry); + } +} +RegisterResourceGenerationFunction("IOTMPizzaCube"); +void IOTMPizzaCube(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[lookupItem("diabolic pizza cube")] || (fullness_limit() - my_fullness() < 3)) return; + + ChecklistSubentry getQuestItems() { + // Title + string main_title = "Make pizza"; + + // Subtitle + string subtitle = "Some ingredients give useful items"; + + // Entries + string [int] description; + + boolean need_cheese = !__quest_state["Trapper"].state_boolean["Past mine"] && $item[goat cheese].available_amount() < 3; + + if (need_cheese) { + description.listAppend(HTMLGenerateSpanOfClass("\"cheese\"/\"milk\":", "r_bold") + " 3 goat cheese"); + } + description.listAppend(HTMLGenerateSpanOfClass("\"luck\"/\"green\":", "r_bold") + " clover"); + description.listAppend(HTMLGenerateSpanOfClass("familiar equipment/hatchling:", "r_bold") + " equipment + xp for your familiar"); + description.listAppend(HTMLGenerateSpanOfClass("\"cloak\":", "r_bold") + " dead mimic"); + description.listAppend(HTMLGenerateSpanOfClass("combat item:", "r_bold") + " 3 of sonar-in-a-biscuit, Duskwalker syringe, cocktail napkin, unnamed cocktail, cigarette lighter, glark cable, short writ of habeas corpus"); + + return ChecklistSubentryMake(main_title, subtitle, description); + } + + ChecklistSubentry getBuffs() { + // Title + string main_title = "Buffs"; + + // Subtitle + string subtitle = ""; + + // Entries + string [int] description; + + description.listAppend("Get any wishable buff"); + + return ChecklistSubentryMake(main_title, subtitle, description); + } + + ChecklistEntry entry; + entry.image_lookup_name = "__item diabolic pizza"; + entry.url = "campground.php?action=workshed"; + entry.tags.id = "Diabolic pizza cube resource"; + + ChecklistSubentry questItems = getQuestItems(); + if (questItems.entries.count() > 0) { + entry.subentries.listAppend(questItems); + } + + ChecklistSubentry buffs = getBuffs(); + if (buffs.entries.count() > 0) { + entry.subentries.listAppend(buffs); + } + + if (entry.subentries.count() > 0) { + resource_entries.listAppend(entry); + } +} + +RegisterTaskGenerationFunction("IOTMRedNosedSnapperTask"); +void IOTMRedNosedSnapperTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!lookupFamiliar("Red Nosed Snapper").familiar_is_usable()) return; + if (my_familiar() != lookupFamiliar("Red Nosed Snapper")) return; + + phylum current_snapper_phylum = get_property("redSnapperPhylum").to_phylum(); + + if (current_snapper_phylum == $phylum[none]) { + optional_task_entries.listAppend(ChecklistEntryMake("__familiar red-nosed snapper", "familiar.php?action=guideme&pwd=" + my_hash(), ChecklistSubentryMake("Track monsters", "+ of them and gives items", "Choose a phylum".HTMLGenerateSpanOfClass("r_element_important")), 8).ChecklistEntrySetIDTag("Red nosed snapper familiar set tracking")); + return; + } + + + //Check if the currently tracked phylum is undoing a banish + location l = __last_adventure_location; + if (!__setting_location_bar_uses_last_location && !get_property_boolean("_relay_guide_setting_ignore_next_adventure_for_location_bar") && get_property_location("nextAdventure") != $location[none]) //want to mimic location bar popup, so they can look at it for information + l = get_property_location("nextAdventure"); + + monster [int] banishes_undone_by_snapper; + foreach index, monstr in l.get_monsters() + if (monstr.phylum == current_snapper_phylum && monstr.is_banished()) + banishes_undone_by_snapper.listAppend(monstr); + + if (banishes_undone_by_snapper.count() > 0) { + string title = "Your Snapper is undoing a banish".HTMLGenerateSpanOfClass("r_element_important"); + task_entries.listAppend(ChecklistEntryMake("__familiar red-nosed snapper", "familiar.php?action=guideme&pwd=" + my_hash(), ChecklistSubentryMake(title, "Change tracked phylum or switch familiar", "Bringing your snapper while it is tracking " + current_snapper_phylum + " is unbanishing " + banishes_undone_by_snapper.listJoinComponents(", ", "and")), -10).ChecklistEntrySetIDTag("Red nosed snapper familiar warning")); + + ChecklistEntry pop_up_reminder_entry = ChecklistEntryMake("__familiar red-nosed snapper", "", ChecklistSubentryMake(title), -11); + pop_up_reminder_entry.tags.id = "Red nosed snapper familiar popup"; + pop_up_reminder_entry.only_show_as_extra_important_pop_up = true; + pop_up_reminder_entry.container_div_attributes["onclick"] = "navbarClick(0, 'Tasks_checklist_container')"; + pop_up_reminder_entry.container_div_attributes["class"] = "r_clickable"; + task_entries.listAppend(pop_up_reminder_entry); + } +} + +RegisterResourceGenerationFunction("IOTMRedNosedSnapperResource"); +void IOTMRedNosedSnapperResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("Red Nosed Snapper").familiar_is_usable()) return; + + boolean always_display = false; //user-preference + + if (my_familiar() != lookupFamiliar("Red Nosed Snapper") && !__misc_state["in run"] && !always_display) return; + + //beast = +5 cold res (not a lot of places to go for those, esp. since it's for a quite optional effect...) + //bug = +100% HP, 8-10 HP regen (spleen) (not really... useful enough to mention those outside of the zones having them..?) + //constellation = Yellow ray + //construct = +150% init (spleen) + //demon = +5 hot res (suggested in a zone that already has one (haunted kitchen)) (there's some hellseals, though..?) + //dude = All-day free (3x/day) banish item + //elemental = +50% MP, 3-5 MP regen (spleen) (would recommend the snowman ninja lair, but we can't know if they chose hippy route instead; we know when they ARE there...) + //elf = +50% candy (not encountered in-run, nor has... any... use?) + //fish = Fishy (spleen) + //goblin = 3-size food + //hippy = +5 stench res + //hobo = +100% meat (spleen) (only seen in overgrown lot, sleazy back alley, or hobopolis) + //horror = 5x/day free kill + //humanoid = +50% muscle stats (spleen) + //mer-kin = +30% underwater items + //orc = 3-size booze + //penguin = gives meat (never useful, nor encountered in run, really) + //pirate = +50% moxie stats (spleen) + //plant = Full HP restore in combat + //slime = +5 sleaze res (would be good for bridge, but there's very few slimes before that...) + //undead = +5 spooky res + //weird = +50% myst stats (spleen) (way too rare in-run to recommend) + + boolean going_in_Degrassi_Knoll = !knoll_available() && my_path().id != PATH_NUCLEAR_AUTUMN && !__misc_state["desert beach available"] && __misc_state["guild open"]; + boolean making_Junk_Junk = !__misc_state["mysterious island available"] && __quest_state["Old Landfill"].in_progress; + boolean Azazel_quest_is_in_progress = __quest_state["Azazel"].in_progress && !in_bad_moon() && $locations[The Laugh Floor, Infernal Rackets Backstage].turnsAttemptedInLocation() > 0; + boolean nemesis_quest_at_clown_house = __quest_state["Nemesis"].mafia_internal_step == 6; + boolean nemesis_quest_at_Fungal_Nethers = $ints[13,14,15] contains __quest_state["Nemesis"].mafia_internal_step; + boolean cyrpt_modern_zmobies_are_appreciated = !__quest_state["Cyrpt"].state_boolean["alcove finished"] && __quest_state["Cyrpt"].state_int["alcove evilness"] > 1; + boolean at_chasm_bridge = __quest_state["Highland Lord"].mafia_internal_step == 1; + boolean past_chasm_bridge = __quest_state["Highland Lord"].mafia_internal_step > 1; + boolean want_more_rusty_hedge_trimmers = __quest_state["Highland Lord"].state_boolean["can complete twin peaks quest quickly"] && __quest_state["Highland Lord"].state_int["twin peak progress"] < 15 && $item[rusty hedge trimmers].available_amount() < __quest_state["Highland Lord"].state_int["peak tests remaining"]; + boolean looking_for_mining_gear = __quest_state["Trapper"].in_progress && !__quest_state["Trapper"].state_boolean["Past mine"] && __quest_state["Trapper"].state_string["ore needed"].to_item().available_amount() < 3 && !have_outfit_components("Mining Gear") && my_path().id != PATH_AVATAR_OF_BORIS && my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST; + boolean they_may_be_ninjas = __quest_state["Trapper"].state_boolean["Past mine"] && ($location[lair of the ninja snowmen].turns_spent > 0 || $location[the extreme slope].turns_spent == 0); + boolean have_some_pirating_to_do = __misc_state["mysterious island available"] && __quest_state["Pirate Quest"].state_boolean["valid"] && !__quest_state["Island War"].state_boolean["War in progress"]; + boolean have_access_to_giant_castle = $item[s.o.c.k.].available_amount() > 0 || my_path().id == PATH_EXPLOSION; + boolean top_floor_done = __quest_state["Castle"].mafia_internal_step > 10 && $location[the hole in the sky].locationAvailable(); + boolean going_in_the_HITS = $location[the hole in the sky].locationAvailable() && $item[richard\'s star key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["Richard's star key used"]; + boolean exploring_desert = __quest_state["Level 11"].in_progress && !__quest_state["Level 11 Desert"].state_boolean["Desert Explored"]; + boolean at_hidden_city = __quest_state["Hidden Temple Unlock"].finished && __quest_state["Level 11 Hidden City"].in_progress; + boolean have_more_dense_lianas_to_fight = at_hidden_city && __quest_state["Level 11 Hidden City"].state_int["lianas left"] > 0; + boolean making_wine_bomb = __quest_state["Level 11 Manor"].mafia_internal_step == 3 && get_property("spookyravenRecipeUsed") == "with_glasses"; + boolean helping_Yossarian = __quest_state["Island War"].state_boolean["War in progress"] && !__quest_state["Island War"].state_boolean["Junkyard Finished"]; + boolean fighting_filthworms = __quest_state["Island War"].state_boolean["War in progress"] && !__quest_state["Island War"].state_boolean["Orchard Finished"] && my_path().id != PATH_2CRS; + boolean CS_need_to_pass_hot_res_test = my_path().id == PATH_COMMUNITY_SERVICE && !(get_property("csServicesPerformed").split_string_alternate(",").listInvert() contains "Clean Steam Tunnels"); + + + string [int] currentlyReachableInstancesOfPhylum(phylum phyl) { + string [int] reachable_instances; + if (phyl == $phylum[constellation] && !$location[the hole in the sky].locationAvailable()) + reachable_instances.listAppend("Unreachable"); + + switch (phyl) { + case $phylum[beast]: //twin peak topiary animals (is that really all there is to "good" beasts locations?) + if (past_chasm_bridge && want_more_rusty_hedge_trimmers) + reachable_instances.listAppend("twin peak topiary animals"); + break; + + case $phylum[bug]: //desert and filthworms + if (exploring_desert) + reachable_instances.listAppend("arid, extra-dry desert"); + if (fighting_filthworms) + reachable_instances.listAppend("filthworms"); + break; + + case $phylum[constellation]: //Hole in the Sky, and nothing else + if (going_in_the_HITS) + reachable_instances.listAppend("hole in the sky"); + break; + + case $phylum[construct]: //monstrous boiler and wine rack + if (making_wine_bomb) { + if ($item[unstable fulminate].available_amount() == 0 && $item[bottle of Chateau de Vinegar].available_amount() == 0) + reachable_instances.listAppend("wine rack"); + reachable_instances.listAppend("monstrous boiler"); + } + break; + + case $phylum[demon]: //(some) hellseals and demons from friars and hey-deze + if (my_class() == $class[seal clubber] && my_level() >= 5) + reachable_instances.listAppend("figurine of " + (my_level() >= 6 ? "ancient" : "cute baby") + " seal"); + if (__quest_state["Friars"].in_progress) + reachable_instances.listAppend("dark X of the woods (friars)"); + if (Azazel_quest_is_in_progress) + reachable_instances.listAppend("Hey Deze"); + break; + + case $phylum[dude]: //they're everywhere!!!! (I'm not even gonna TRY to do anything past that.) + reachable_instances.listAppend("too many to count"); + break; + + case $phylum[elemental]: //ninja snowmen, not really worth it, though..? + if (they_may_be_ninjas && !__quest_state["Trapper"].state_boolean["Mountain climbed"]) + reachable_instances.listAppend("ninja snowmen"); + break; + + case $phylum[elf]: //can't reach, nor want, in-run + break; + + case $phylum[fish]: //can't reach, nor want, in-run + break; + + case $phylum[goblin]: //kramco & cobbs knob + if (lookupItem("Kramco Sausage-o-Matic™").available_amount() > 0) + reachable_instances.listAppend("kramco sausage goblins"); + if (!__quest_state["Knob Goblin King"].finished) + reachable_instances.listAppend("cobbs knob"); + break; + + case $phylum[hippy]: //hippy camp + if (__misc_state["mysterious island available"] && __quest_state["Island War"].state_string["Side seemingly fighting for"] != "hippy") + reachable_instances.listAppend(__quest_state["Island War"].state_boolean["War in progress"] ? "war hippies" : "The Hippy Camp"); + break; + + case $phylum[hobo]: //no hobos in one's normal path. There's some in the wrong side of the track, but we don't recommend they go there for that. + break; + + case $phylum[horror]: //(some) hellseals and clowns + if (my_class() == $class[seal clubber]) + reachable_instances.listAppend("figurine of wretched-looking" + (my_level() >= 9 ? "/armored" : "") + " seal"); + if (nemesis_quest_at_clown_house) + reachable_instances.listAppend("clown fun house"); + break; + + case $phylum[humanoid]: //Degrassi Knoll, castle giants, old landfill, 7-foot dwarves, Junkyard gremlins + if (going_in_Degrassi_Knoll) + reachable_instances.listAppend("Degrassi Knoll"); + if (have_access_to_giant_castle && !top_floor_done) + reachable_instances.listAppend("castle giants"); + if (making_Junk_Junk) + reachable_instances.listAppend("old landfill"); + if (looking_for_mining_gear) + reachable_instances.listAppend("7-foot dwarves"); + if (helping_Yossarian) + reachable_instances.listAppend("island junkyard"); + break; + + case $phylum[mer-kin]: //can't reach, nor want, in-run + break; + + case $phylum[orc]: //smut orc logging camp and frat boys/warriors + if (at_chasm_bridge) + reachable_instances.listAppend("smut orcs"); + if (__misc_state["mysterious island available"] && __quest_state["Island War"].state_string["Side seemingly fighting for"] != "frat boys") + reachable_instances.listAppend("frat " + (__quest_state["Island War"].state_boolean["War in progress"] ? "warriors" : "boys")); + break; + + case $phylum[penguin]: //can't reach, nor want, in-run + break; + + case $phylum[pirate]: //pirate cove + if (have_some_pirating_to_do) + reachable_instances.listAppend("pirate cove"); + break; + + case $phylum[plant]: //fungal nethers and dense lianas + if (nemesis_quest_at_Fungal_Nethers) + reachable_instances.listAppend("fungal nethers"); + if (have_more_dense_lianas_to_fight) + reachable_instances.listAppend("dense lianas"); + break; + + case $phylum[slime]: //oil peak (yes, I KNOW that the +5 sleaze res is supposed to be for the BRIDGE BUILDING, but there's just no consistent source of slimes before that; go cry me a river won't you) + if (past_chasm_bridge && __quest_state["Highland Lord"].state_float["oil peak pressure"] > 0.0) + reachable_instances.listAppend("oil peak"); + break; + + case $phylum[undead]: //The whole spookyraven manor, or the cyrpt + if (__quest_state["Manor Unlock"].in_progress) + reachable_instances.listAppend("Spookyraven manor"); + if (__quest_state["Cyrpt"].in_progress) + reachable_instances.listAppend("Cyrpt"); + break; + + case $phylum[weird]: //I've got nuthin', they are too rare in-run + break; + } + return reachable_instances; + } + + + boolean [phylum] want_phylum_drop; + if (true) { //always up for those if available: + want_phylum_drop[$phylum[constellation]] = true; //yellow-ray + want_phylum_drop[$phylum[dude]] = true; //banish + want_phylum_drop[$phylum[horror]] = true; //free kill + want_phylum_drop[$phylum[hobo]] = true; //+100% meat + } + + if (false) { //those just... don't have an use + want_phylum_drop[$phylum[elf]] = true; //+50% candy drop + want_phylum_drop[$phylum[penguin]] = true; //an envelope which gives some meat... + want_phylum_drop[$phylum[bug]] = true; //+100% HP, ~9HP regen (not really worth it...) + } + + if (__misc_state["in run"]) { + if (__misc_state["need to level"]) + switch (my_primestat()) { //+50% gains + case $stat[muscle]: + want_phylum_drop[$phylum[humanoid]] = true; break; + case $stat[mysticality]: + want_phylum_drop[$phylum[weird]] = true; break; + case $stat[moxie]: + want_phylum_drop[$phylum[pirate]] = true; break; + } + + if (!__quest_state["Level 13"].state_boolean["Init race completed"] || cyrpt_modern_zmobies_are_appreciated) + want_phylum_drop[$phylum[construct]] = true; //+150% initiative + + if (my_path().id != PATH_COMMUNITY_SERVICE && $item[Spookyraven billiards room key].available_amount() == 0 && get_property_int("manorDrawerCount") < 20) { + if (numeric_modifier("hot resistance") < 7) + want_phylum_drop[$phylum[demon]] = true; //+5 hot res + if (numeric_modifier("stench resistance") < 7) + want_phylum_drop[$phylum[hippy]] = true; //+5 stench res + } else if (CS_need_to_pass_hot_res_test) + want_phylum_drop[$phylum[demon]] = true; //demon again; +5 hot res + + if (past_chasm_bridge) { + if (__quest_state["Highland Lord"].state_boolean["can complete twin peaks quest quickly"] && !__quest_state["Highland Lord"].state_boolean["Peak Stench Completed"] && numeric_modifier("stench resistance") <= 1.0) //if they have 2 or 3, they don't need a plus-FIVE + want_phylum_drop[$phylum[hippy]] = true; //hippy again; +5 stench res + + if (__quest_state["Highland Lord"].state_int["a-boo peak hauntedness"] > 2) { + want_phylum_drop[$phylum[beast]] = true; //+5 cold res + want_phylum_drop[$phylum[undead]] = true; //+5 spooky res + } + } else if (at_chasm_bridge) + want_phylum_drop[$phylum[slime]] = true; //+5 sleaze res + + if (they_may_be_ninjas && !__quest_state["Trapper"].state_boolean["Groar defeated"] && numeric_modifier("cold resistance") < 3.0) //if they have 3 or 4, they don't need a plus-FIVE + want_phylum_drop[$phylum[beast]] = true; //beast again; +5 cold res + + if (!lookupItem("Eight Days a Week Pill Keeper").have()) + want_phylum_drop[$phylum[elemental]] = true; //+50% MP, ~4MP regen + + if (__quest_state["Lair"].state_boolean["shadow will need to be defeated"]) + want_phylum_drop[$phylum[plant]] = true; + } else if (__quest_state["Sea Monkees"].in_progress || __quest_state["Sea Temple"].in_progress || __quest_state["Sea Monkees"].state_string["skate park status"] == "war") { + want_phylum_drop[$phylum[fish]] = true; //fishy + want_phylum_drop[$phylum[mer-kin]] = true; //+30% underwater items (meh...) + } + + if (in_ronin() && my_path().id != PATH_NUCLEAR_AUTUMN) { + if (fullness_limit() >= 3) + want_phylum_drop[$phylum[goblin]] = true; //size 3 awesome food + if (inebriety_limit() >= 3) + want_phylum_drop[$phylum[orc]] = true; //size 3 awesome booze + } + + + boolean [phylum] current_location_phylums; + foreach index, monstr in __last_adventure_location.get_monsters() + current_location_phylums[monstr.phylum] = true; + + phylum current_snapper_phylum = get_property("redSnapperPhylum").to_phylum(); + + //The selection presented to the player. The currently tracked phylum and those present in the current locations will always be in there + //This is meant to inform the player on the DROPS they can get, NOT on which phylum they could track to help progress (at least it's not the focus here) + boolean [phylum] phylum_display_list; + string [phylum] [int] reachable_options; + + foreach phyl in $phylums[] { + string [int] options = currentlyReachableInstancesOfPhylum(phyl); + + if (phyl == current_snapper_phylum) //obviously show the one they are tracking + phylum_display_list[phyl] = true; + else if (current_location_phylums contains phyl) //show those in the current location + phylum_display_list[phyl] = true; + else if (want_phylum_drop[phyl] && (options.count() > 0 || !__misc_state["in run"]) && options[0] != "Unreachable") + phylum_display_list[phyl] = true; + + reachable_options[phyl] = options; + } + + int progress = get_property_int("redSnapperProgress"); + + string title = "Track monsters"; + if (current_snapper_phylum != $phylum[none]) + title = (11 - progress).pluralise(current_snapper_phylum + " kill", current_snapper_phylum + " kills") + " until next Snapper drop"; + + string [int] description; + + if (progress > 0) + description.listAppend("Changing phylum resets progress."); + + string [phylum] snapper_drop = { + $phylum[beast]:"+5 " + "cold".HTMLGenerateSpanOfClass("r_element_cold") + " res (20 turns)", + $phylum[bug]:"+100% HP, 8-10 HP regen (1 spleen, 60 turns)", + $phylum[constellation]:"Yellow ray item (150 turns of Ev. Looks Yellow)", + $phylum[construct]:"+150% init (1 spleen, 30 turns)", + $phylum[demon]:"+5 " + "hot".HTMLGenerateSpanOfClass("r_element_hot") + " res (20 turns)", + $phylum[dude]:"All-day free (3x/day) banish item", + $phylum[elemental]:"+50% MP, 3-5 MP regen (1 spleen, 60 turns)", + $phylum[elf]:"+50% candy (20 turns)", + $phylum[fish]:"Fishy (1 spleen, 30 turns)", + $phylum[goblin]:"3-size " + "awesome".HTMLGenerateSpanOfClass("r_element_awesome") + " food", + $phylum[hippy]:"+5 " + "stench".HTMLGenerateSpanOfClass("r_element_stench") + " res (20 turns)", + $phylum[hobo]:"+100% meat (1 spleen, 60 turns)", + $phylum[horror]:"5x/day free kill item", + $phylum[humanoid]:"+50% muscle stats (1 spleen, 30 turns)", + $phylum[mer-kin]:"+30% underwater items (20 turns)", + $phylum[orc]:"3-size " + "awesome".HTMLGenerateSpanOfClass("r_element_awesome") + " booze", + $phylum[penguin]:"(500 + 500 * +meat%) meat item", + $phylum[pirate]:"+50% moxie stats (1 spleen, 30 turns)", + $phylum[plant]:"Full HP restore combat item", + $phylum[slime]:"+5 " + "sleaze".HTMLGenerateSpanOfClass("r_element_sleaze") + " res (20 turns)", + $phylum[undead]:"+5 " + "spooky".HTMLGenerateSpanOfClass("r_element_spooky") + " res (20 turns)", + $phylum[weird]:"+50% myst stats (1 spleen, 30 turns)" + }; + + foreach phyl in phylum_display_list { + string line; + if (current_location_phylums contains phyl) + line += "• "; + if (current_snapper_phylum == phyl) + line += __html_right_arrow_character; + line += capitaliseFirstLetter(phyl + ": ").HTMLGenerateSpanOfClass("r_bold"); + line += snapper_drop[phyl]; + + + //FIXME Is there a "good" way to add reachable_options to this? + + //remember to add a string HTMLGenerateSimpleTableLines(string [int] lines) to page.ash if ending up using this + /*if (reachable_options[phyl].count() > 0 && false) { + buffer tooltip; + tooltip.append(reachable_options[phyl].HTMLGenerateSimpleTableLines().HTMLGenerateSpanOfClass("r_tooltip_inner_class r_tooltip_inner_class_margin")); + tooltip.append(line); + line = tooltip.HTMLGenerateSpanOfClass("r_tooltip_outer_class"); + }*/ + + description.listAppend(line); + } + + resource_entries.listAppend(ChecklistEntryMake("__familiar red-nosed snapper", "familiar.php?action=guideme&pwd=" + my_hash(), ChecklistSubentryMake(title, "+1 item / 11 kills of tracked phylum", description)).ChecklistEntrySetIDTag("Red nosed snapper familiar tracking drops resource")); +} + + +// 2020 +RegisterTaskGenerationFunction("IOTMBirdADayGenerateTasks"); +void IOTMBirdADayGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[$item[Bird-a-Day calendar]]) return; + if (!get_property_boolean("_canSeekBirds")) { + string [int] description; + + description.listAppend("Use your calendar to get a new skill for the day."); + if (have_effect($effect[Blessing of the Bird]) > 0) + description.listAppend(HTMLGenerateSpanFont("Still have an old blessing", "red") + "|Using the calendar will replace the old buff's modifiers with the new ones."); + + optional_task_entries.listAppend(ChecklistEntryMake("__effect Blessing of the Bird", "inventory.php?ftext=bird-a-day+calendar", ChecklistSubentryMake("Discover your daily Bird", "", description), 8).ChecklistEntrySetIDTag("Bird-a-day calendar")); + } +} + +RegisterResourceGenerationFunction("IOTMBirdADayCalendar"); +void IOTMBirdADayCalendar(ChecklistEntry [int] resource_entries) +{ + ChecklistSubentry getBirdMods() { + + string birdMods = get_property("_birdOfTheDayMods"); + int birdsSought = get_property_int("_birdsSoughtToday"); + + // Title + string main_title = "Seek birds! " + birdsSought + " birds sought today"; + + // Subtitle + string subtitle = "10 Turn Buff"; + + // Entries + string [int] description; + int mp_cost = 5 * 2**(birdsSought); + description.listAppend("Currently costs " + mp_cost + " MP to watch."); + description.listAppend("Seek up to 6 times and still keep your old favorite."); + description.listAppend("Must make it your new favorite to watch 7 or more times."); + if (get_property_boolean("_canSeekBirds")) { + string [int] modStrings = birdMods.split_string(", "); + foreach index, modString in modStrings { + string [int] modProperties = modString.split_string(": "); + string modName = modProperties[0]; + string modValue = modProperties[1]; + + string name = modName + ": "; + switch(modName) { + case "Cold Resistance": + name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_cold"); + break; + case "Hot Resistance": + name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_hot"); + break; + case "Sleaze Resistance": + name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_sleaze"); + break; + case "Spooky Resistance": + name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_spooky"); + break; + case "Stench Resistance": + name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_stench"); + break; + } + + description.listAppend(HTMLGenerateSpanOfClass(name, "r_bold") + modValue); + } + } + + return ChecklistSubentryMake(main_title, subtitle, description); + } + + ChecklistSubentry getFavoriteBird() { + + string favoriteBirdMods = get_property("yourFavoriteBirdMods"); + boolean canSeekFavBird = have_skill($skill[Visit your Favorite Bird]); + + // Title + string main_title = "Favorite"; + + // Subtitle + string subtitle = "20 Turn Buff"; + + // Entries + string [int] description; + + if (favoriteBirdMods != "" && canSeekFavBird && !get_property_boolean("_favoriteBirdVisited")) { + string [int] modStrings = favoriteBirdMods.split_string(", "); + foreach index, modString in modStrings { + string [int] modProperties = modString.split_string(": "); + string modName = modProperties[0]; + string modValue = modProperties[1]; + + string name = modName + ": "; + switch(modName) { + case "Cold Resistance": + name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_cold"); + break; + case "Hot Resistance": + name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_hot"); + break; + case "Sleaze Resistance": + name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_sleaze"); + break; + case "Spooky Resistance": + name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_spooky"); + break; + case "Stench Resistance": + name = HTMLGenerateSpanOfClass(modName + ": ", "r_element_stench"); + break; + } + + description.listAppend(HTMLGenerateSpanOfClass(name, "r_bold") + modValue); + } + } + + return ChecklistSubentryMake(main_title, subtitle, description); + } + + + if (!__iotms_usable[$item[Bird-a-Day calendar]]) + return; + + ChecklistEntry entry; + entry.image_lookup_name = "__effect Blessing of the Bird"; + entry.url = "skillz.php"; + entry.tags.id = "Bird-a-day cast"; + + ChecklistSubentry birdMods = getBirdMods(); + if (birdMods.entries.count() > 0) { + entry.subentries.listAppend(birdMods); + } + + ChecklistSubentry favoriteBird = getFavoriteBird(); + if (favoriteBird.entries.count() > 0) { + entry.subentries.listAppend(favoriteBird); + } + + if (entry.subentries.count() > 0) { + resource_entries.listAppend(entry); + } +} + +RegisterResourceGenerationFunction("IOTMPowerfulGloveGenerateResource"); +void IOTMPowerfulGloveGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[Powerful Glove]]) return; + if (my_path().id == PATH_G_LOVER) return; // while you can equip the glove, you can use none of the skills lol + + int chargeLeft = 100 - get_property_int("_powerfulGloveBatteryPowerUsed"); + + if (chargeLeft < 5) return; + + string url = "skillz.php"; + if (!$item[Powerful Glove].equipped()) + url = "inventory.php?ftext=powerful+glove"; + + string [int] description; + description.listAppend(HTMLGenerateSpanOfClass("Invisible Avatar (5% charge):", "r_bold") + " -10% combat."); + description.listAppend(HTMLGenerateSpanOfClass("Triple Size (5% charge):", "r_bold") + " +200% all attributes."); + if (chargeLeft >= 10) + description.listAppend(HTMLGenerateSpanOfClass("Replace Enemy (10% charge):", "r_bold") + " Swap monster."); + description.listAppend(HTMLGenerateSpanOfClass("Shrink Enemy (5% charge):", "r_bold") + " Delevel."); + + resource_entries.listAppend(ChecklistEntryMake("__item Powerful Glove", url, ChecklistSubentryMake(chargeLeft + "% Powerful Glove battery charge", "", description)).ChecklistEntrySetIDTag("Powerful glove skills resource")); +} + +RegisterTaskGenerationFunction("IOTMPowerfulGloveTask"); +void IOTMPowerfulGloveTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // This doesn't have replica handling, but I don't really care -- you really only need this for Plumber now, and otherwise it's meh. + if (!__misc_state["in run"] || !$item[Powerful Glove].have() || $item[Powerful Glove].have_equipped()) return; + + boolean is_plumber = my_path().id == PATH_OF_THE_PLUMBER; + + string [int] glove_drops; + + if (!__quest_state["Level 13"].state_boolean["digital key used"] && $item[digital key].available_amount() + $item[digital key].creatable_amount() == 0) + glove_drops.listAppend("pixels"); + if (is_plumber) + glove_drops.listAppend("coins"); + + if (glove_drops.count() == 0) return; + + optional_task_entries.listAppend(ChecklistEntryMake("__item white pixel", "place.php?whichplace=forestvillage&action=fv_mystic", ChecklistSubentryMake("Equip Powerful Glove", "", "Get extra " + glove_drops.listJoinComponents(" and ") + "."), is_plumber ? -10 : 0).ChecklistEntrySetIDTag("Powerful glove equip reminder")); +} +RegisterResourceGenerationFunction("IOTMBetterShroomsAndGardensGenerateResource"); +void IOTMBetterShroomsAndGardensGenerateResource(ChecklistEntry [int] resource_entries) +{ + ChecklistSubentry getFreeFights() { + int freeFightsUsed = get_property_int("_mushroomGardenFights"); + int totalFreeFights = 1; + + if (my_path().id == PATH_OF_THE_PLUMBER) { + totalFreeFights = 5; + } + int freeFightsLeft = totalFreeFights - freeFightsUsed; + + // Title + string main_title = pluralise(freeFightsLeft,"Piranha Plant fight","Piranha Plant fights"); + + // Subtitle + string subtitle = ""; + + // Entries + string [int] description; + if (freeFightsLeft > 0) { + description.listAppend("Free fight."); + if (my_path().id == PATH_OF_THE_PLUMBER) { + description.listAppend("Drops extra coins and mushrooms."); + } + } + + return ChecklistSubentryMake(main_title, subtitle, description); + } + + ChecklistSubentry getMushroomState() { + int mushroomLevel = get_property_int("mushroomGardenCropLevel"); + int expectedFilets = MIN(3, mushroomLevel)*3; + int expectedSlabs = clampi(mushroomLevel - 3, 0, 2); + + // Title + string main_title = "Upkeep your mushroom"; + + // Subtitle + string subtitle = "One action per day"; + + // Entries + string [int] description; + + string [int] shroomYield; + string [int] futureYield; + if (!get_property_boolean("_mushroomGardenVisited")) { + description.listAppend("Mushroom is at tier " + mushroomLevel); + shroomYield.listAppend(expectedFilets + " filets"); + if (mushroomLevel > 3) + shroomYield.listAppend( pluralise(expectedSlabs,"slab","slabs") ); + + if (mushroomLevel < 2) + futureYield.listAppend("+3 filets at tier 2"); + if (mushroomLevel < 3) + futureYield.listAppend("+3 filets at tier 3"); + if (mushroomLevel < 4) + futureYield.listAppend("+1 slab at tier 4"); + if (mushroomLevel < 5) + futureYield.listAppend("+1 slab at tier 5"); + + if (mushroomLevel > 10) + shroomYield.listAppend("A mushroom house"); + else + futureYield.listAppend("+1 mushroom house at tier 11"); + + description.listAppend("Harvesting now will give:" + HTMLGenerateIndentedText(shroomYield)); + description.listAppend( mushroomLevel > 10 ? HTMLGenerateSpanOfClass("No reason to fertilize any longer", "r_bold") : to_buffer("Otherwise, fertilize it, incrementing its size:" + HTMLGenerateIndentedText(futureYield)) ); + } + + return ChecklistSubentryMake(main_title, subtitle, description); + } + + if (!__iotms_usable[lookupItem("packet of mushroom spores")]) return; + + ChecklistEntry entry; + entry.image_lookup_name = "__item Better Shrooms and Gardens catalog"; + entry.url = "campground.php"; + entry.tags.id = "Mushroom garden resource"; + + ChecklistSubentry piranhas = getFreeFights(); + if (piranhas.entries.count() > 0) { + entry.subentries.listAppend(piranhas); + // Want this part to appear both in the garden's tile, and the free fights tile, so making a new entry + resource_entries.listAppend(ChecklistEntryMake("__item Better Shrooms and Gardens catalog", "campground.php", piranhas).ChecklistEntrySetCombinationTag("daily free fight")); + } + + ChecklistSubentry shroom = getMushroomState(); + if (shroom.entries.count() > 0) { + entry.subentries.listAppend(shroom); + } + + if (entry.subentries.count() > 0) { + resource_entries.listAppend(entry); + } +} + +// Missing: Left-Hand Man +RegisterTaskGenerationFunction("IOTMGuzzlrGenerateTask"); +void IOTMGuzzlrGenerateTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { + + if (!lookupItem("Guzzlr tablet").have()) return; + + boolean startedQuest = get_property("questGuzzlr") != "unstarted"; + string questTier = get_property("guzzlrQuestTier"); + + int guzzlrQuestProgressLeft = 100 - get_property_int("guzzlrDeliveryProgress"); + float guzzlrQuestIncrement = max(3, 10 - get_property_int("_guzzlrDeliveries")); + float guzzlrQuestShoedIncrement = floor(1.5 * guzzlrQuestIncrement); + int guzzlrQuestFightsLeft = ceil(guzzlrQuestProgressLeft / guzzlrQuestIncrement); + int guzzlrQuestShoedFightsLeft = ceil(guzzlrQuestProgressLeft / guzzlrQuestShoedIncrement); + + boolean hasShoes = lookupItem("Guzzlr shoes").available_amount() > 0; + boolean hasPants = lookupItem("Guzzlr pants").available_amount() > 0; + + if (startedQuest) { + boolean hasShoesEquipped = lookupItem("Guzzlr shoes").equipped_amount() > 0; + boolean hasPantsEquipped = lookupItem("Guzzlr pants").equipped_amount() > 0; + + location questLocation = get_property("guzzlrQuestLocation").to_location(); + item questBooze = get_property("guzzlrQuestBooze").to_item(); + boolean [item] questBoozePlatinum; + foreach platinumDrink in $strings[Steamboat, Ghiaccio Colada, Nog-on-the-Cob, Sourfinger, Buttery Boy] { + questBoozePlatinum [lookupItem(platinumDrink)] = true; + } + + boolean hasBooze = questTier == "platinum" ? questBoozePlatinum.item_amount() > 0 : questBooze.item_amount() > 0; + boolean hasBoozeSomewhere = questTier == "platinum" ? questBoozePlatinum.available_amount() + questBoozePlatinum.display_amount() > 0 : questBooze.available_amount() + questBooze.display_amount() > 0; + + boolean oneFightRemains = hasShoesEquipped && guzzlrQuestShoedFightsLeft <= 1 || !hasShoesEquipped && guzzlrQuestFightsLeft <= 1; + + string subtitle = "free fights"; + initialiseLocationCombatRates(); //not done anywhere else in this script + if (__location_combat_rates contains questLocation) { + int rate = __location_combat_rates [questLocation]; + + if (rate == -1) //if unknown + subtitle += ", +combat"; + else if (rate != 100 && rate != 0) + subtitle += ", +" + (100 - rate) + "% combat"; + } else //if unlisted + subtitle += ", +combat"; + + string [int] description; + + if (hasBooze) { + description.listAppend("Deliver " + (questTier == "platinum" ? "platinum booze" : questBooze) + " by adventuring in " + questLocation + "."); + } else { + string color_of_reminder_to_get_drink = __last_adventure_location == questLocation ? "red" : "dark"; + + if (questTier == "platinum") { + int [item] creatablePlatinumDrinks = questBoozePlatinum.creatable_items(); + buffer message; + + message.append(HTMLGenerateSpanFont("Obtain one of the following:", color_of_reminder_to_get_drink)); + message.append(to_buffer("| • Steamboat" + (creatablePlatinumDrinks contains lookupItem("Steamboat") ? " (can make with a miniature boiler)" : "") + " | • Ghiaccio Colada" + (creatablePlatinumDrinks contains lookupItem("Ghiaccio Colada") ? " (can make with a cold wad)" : "") + " | • Nog-on-the-Cob" + (creatablePlatinumDrinks contains lookupItem("Nog-on-the-Cob") ? " (can make with a robin's egg)" : "") + " | • Sourfinger" + (creatablePlatinumDrinks contains lookupItem("Sourfinger") ? " (can make with a mangled finger)" : "") + " | • Buttery Boy" + (creatablePlatinumDrinks contains lookupItem("Buttery Boy") ? " (can make with a Dish of Clarified Butter)" : "") ) ); + description.listAppend(message); + + if (hasBoozeSomewhere) { + string [int] goLookThere; + + if (get_property_boolean("autoSatisfyWithStorage") && questBoozePlatinum.storage_amount() > 0 && can_interact()) + goLookThere.listAppend("in hagnk's storage"); + if (get_property_boolean("autoSatisfyWithCloset") && questBoozePlatinum.closet_amount() > 0) + goLookThere.listAppend("in your closet"); + if (get_property_boolean("autoSatisfyWithStash") && questBoozePlatinum.stash_amount() > 0) + goLookThere.listAppend("in your clan stash"); + if (questBoozePlatinum.display_amount() > 0) // there's no relevant mafia property; is never taken into consideration + goLookThere.listAppend("in your display case"); + + description.listAppend("Go look " + (goLookThere.count() > 0 ? goLookThere.listJoinComponents(", ", "or") + "." : "...somewhere?")); + } + } else { + description.listAppend(HTMLGenerateSpanFont("Obtain a " + questBooze + ".", color_of_reminder_to_get_drink)); + if (hasBoozeSomewhere) { + string [int] goLookThere; + + if (get_property_boolean("autoSatisfyWithStorage") && questBooze.storage_amount() > 0 && can_interact()) + goLookThere.listAppend(questBooze.storage_amount() + " in hagnk's storage"); + if (get_property_boolean("autoSatisfyWithCloset") && questBooze.closet_amount() > 0) + goLookThere.listAppend(questBooze.closet_amount() + " in your closet"); + if (get_property_boolean("autoSatisfyWithStash") && questBooze.stash_amount() > 0) + goLookThere.listAppend(questBooze.stash_amount() + " in your clan stash"); + if (questBooze.display_amount() > 0) + goLookThere.listAppend(questBooze.display_amount() + " in your display case"); + + description.listAppend("Have " + (goLookThere.count() > 0 ? goLookThere.listJoinComponents(", ", "and") + "." : "some... somewhere..?")); + } + + if (questBooze.creatable_amount() > 0) + description.listAppend("Could craft one."); + } + } + + if (guzzlrQuestProgressLeft == 1 || guzzlrQuestShoedFightsLeft == 1) + { + if (hasShoesEquipped) + description.listAppend("Takes " + pluralise(guzzlrQuestShoedFightsLeft, "more fight", "more fights") + " (" + guzzlrQuestFightsLeft + " without shoes)."); + else { + if (hasShoes) description.listAppend(HTMLGenerateSpanFont("Equip your Guzzlr shoes for quicker deliveries.", "red")); + } + #task_entries.listAppend(ChecklistEntryMake("__item Guzzlr tablet", "inventory.php?tap=guzzlr", ChecklistSubentryMake("Guzzlr delivery", "", description), -11)); + task_entries.listAppend(ChecklistEntryMake("__item Guzzlr tablet", questLocation.getClickableURLForLocation(), ChecklistSubentryMake("Guzzlr delivery", subtitle, description), -11, boolean [location] {questLocation:true}).ChecklistEntrySetIDTag("Guzzlr quest task")); + } + + if (guzzlrQuestProgressLeft <= 0) + description.listAppend("Shouldn't this be over already?"); + else if (guzzlrQuestProgressLeft == 1) + description.listAppend(HTMLGenerateSpanFont("Delivery on next fight", "blue")); + else if (guzzlrQuestShoedFightsLeft == 1) + description.listAppend(HTMLGenerateSpanFont("Equip shoes to receive delivery on next fight", "blue")); + else if (!hasShoes || guzzlrQuestFightsLeft == guzzlrQuestShoedFightsLeft) // if no shoes or if doesn't matter at that point + description.listAppend("Takes " + pluralise(guzzlrQuestFightsLeft, "more fight", "more fights") + "."); + else if (hasShoesEquipped) + description.listAppend("Takes " + pluralise(guzzlrQuestShoedFightsLeft, "more fight", "more fights") + " (" + guzzlrQuestFightsLeft + " without shoes)."); + else { + description.listAppend("Takes " + guzzlrQuestFightsLeft + " more fights (" + guzzlrQuestShoedFightsLeft + " with shoes)."); + description.listAppend(HTMLGenerateSpanFont("Equip your Guzzlr shoes for quicker deliveries.", "red")); + } + + if (hasPants && !hasPantsEquipped) + description.listAppend(HTMLGenerateSpanFont("Equip your Guzzlr pants for more Guzzlrbucks.", (oneFightRemains ? "red" : "dark"))); + + if (!hasShoes) + description.listAppend(HTMLGenerateSpanFont("Could buy Guzzlr shoes for quicker deliveries.", "grey")); + if (!hasPants) + description.listAppend(HTMLGenerateSpanFont("Could buy Guzzlr pants for more Guzzlrbucks.", "grey")); + + optional_task_entries.listAppend(ChecklistEntryMake("__item Guzzlrbuck", questLocation.getClickableURLForLocation(), ChecklistSubentryMake("Deliver booze", subtitle, description), boolean [location] {questLocation:true}).ChecklistEntrySetIDTag("Guzzlr quest task")); + } + + + if (true) { // for either telling the player to accept a quest, or reminding them if they can abandon it + boolean canAbandonQuest = !get_property_boolean("_guzzlrQuestAbandoned"); + int platinumDeliveriesLeft = 1 - get_property_int("_guzzlrPlatinumDeliveries"); + int goldDeliveriesLeft = 3 - get_property_int("_guzzlrGoldDeliveries"); + int bronzeDeliveriesTotal = get_property_int("guzzlrBronzeDeliveries"); + boolean canAcceptPlatinum = get_property_int("guzzlrGoldDeliveries") >= 5; + boolean canAcceptGold = bronzeDeliveriesTotal >= 5; + + string main_title; + string subtitle; + string [int] description; + + if (startedQuest && canAbandonQuest) { + main_title = "Can abandon quest"; + description.listAppend("I mean... if you think you're not up to it..."); + if (questTier == "platinum") { + description.listAppend("Do this to keep the Guzzlr cocktail set for yourself"); + } + } else if (!startedQuest) { + if (__misc_state["in run"] && platinumDeliveriesLeft > 0 && canAcceptPlatinum) { + main_title = "Get your daily Guzzlr cocktail set"; + subtitle = "Accept a platinum quest"; + description.listAppend(canAbandonQuest ? "Then, abandon the quest." : "Will be stuck with this quest for the rest of the day."); + } else if (!__misc_state["in run"]) { + main_title = "Accept a booze delivery quest"; + string [int] chooseDeliveryMessage; + + if (bronzeDeliveriesTotal < 196) + chooseDeliveryMessage.listAppend("• Bronze"); + + if (goldDeliveriesLeft > 0 && canAcceptGold) + chooseDeliveryMessage.listAppend("• Gold " + HTMLGenerateSpanFont("(" + goldDeliveriesLeft + " available)", "grey")); + + if (platinumDeliveriesLeft > 0 && canAcceptPlatinum) + chooseDeliveryMessage.listAppend("• Platinum " + HTMLGenerateSpanFont("(" + platinumDeliveriesLeft + " available)", "grey") + (canAbandonQuest ? " (Abandon for free cocktail set?)" : "")); + + if (chooseDeliveryMessage.count() > 0) { + description.listAppend("Start a delivery by choosing a client:" + chooseDeliveryMessage.HTMLGenerateIndentedText()); + description.listAppend("Will take " + (hasShoes ? guzzlrQuestShoedFightsLeft + "-" : "") + guzzlrQuestFightsLeft + " fights."); + if (canAbandonQuest) + description.listAppend("Can abandon 1 more quest today."); + } + } + } + + if (description.count() > 0) + optional_task_entries.listAppend(ChecklistEntryMake("__item Guzzlr tablet", "inventory.php?tap=guzzlr", ChecklistSubentryMake(main_title, subtitle, description)).ChecklistEntrySetIDTag("Guzzlr tablet tap")); + } +} +// Missing: Iunion +RegisterTaskGenerationFunction("IOTMMelodramedaryGenerateTasks"); +void IOTMMelodramedaryGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_familiar() != lookupFamiliar("Melodramedary")) return; + + if (get_property_int("camelSpit") == 100) + task_entries.listAppend(ChecklistEntryMake("__familiar Melodramedary", "familiar.php", ChecklistSubentryMake("Melodramedary: Locked and Loaded!", "", HTMLGenerateSpanFont("Spit!", "blue")), -11).ChecklistEntrySetIDTag("Melodramedary familiar spit ready")); +} + +RegisterResourceGenerationFunction("IOTMMelodramedaryResource"); +void IOTMMelodramedaryResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("Melodramedary").familiar_is_usable()) return; + + int spit_o_meter = get_property_int("camelSpit"); + + if (!__misc_state["in run"] && spit_o_meter < 100 && my_familiar() != lookupFamiliar("Melodramedary")) return; + + string title; + string [int] description; + + if (spit_o_meter < 100) { + title = spit_o_meter + "% Melodramedary Spit Charge"; + + boolean camelCapped = lookupFamiliar("Melodramedary").familiar_equipped_equipment() == lookupItem("dromedary drinking helmet"); + int fights_left = floor((101 - spit_o_meter) / 3.33); + if (camelCapped) + fights_left = ceil(fights_left / 1.3); + + description.listAppend("Ready in " + (camelCapped ? "~" : "") + fights_left.pluralise("fight", "fights") + "."); + } else { + title = "Melodramedary: Locked and Loaded!"; + description.listAppend(HTMLGenerateSpanFont("Spit!", "blue")); + } + + description.listAppend("Spit on self for 15 turns of +100% stats & weapon/spell dmg."); + description.listAppend("Spit on monsters to get 4x of each of their items (2x for conditional items)."); + //There are also certainly even more options of varying effectiveness. + + string [int] options; + if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) { + int bowling_progress = get_property_int("hiddenBowlingAlleyProgress"); + if (bowling_progress > 0 && bowling_progress < 7) { + int balls_needed = 6 - bowling_progress - $item[bowling ball].available_amount(); + if (balls_needed >= 2) + options.listAppend("Pygmy bowler; needs +150% item."); + } + + if (__quest_state["Level 9"].state_boolean["bridge complete"] && __quest_state["Level 9"].state_int["twin peak progress"] != 15 && $item[rusty hedge trimmers].available_amount() < __quest_state["Level 9"].state_int["peak tests remaining"] - 1) + options.listAppend("Hedge beast; needs +567% item."); + + if (__quest_state["Level 11 Ron"].mafia_internal_step == 3 || __quest_state["Level 11 Ron"].mafia_internal_step == 4) //Can't really compare with progress/cable uses for that day, since they could encounter red herring/snapper / wait for the next day + options.listAppend("Red butler; needs +234% item."); + + if (__quest_state["Level 12"].mafia_internal_step > 1 && !__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 4) + options.listAppend("Lobsterfrogman; prob. a weak option."); + + if (!__quest_state["Level 12"].finished && __quest_state["Level 12"].state_int["hippies left on battlefield"] > 0 && __quest_state["Level 12"].state_int["hippies left on battlefield"] <= 600 && __misc_state["yellow ray potentially available"]) + options.listAppend("Green Ops Soldier (for free runaways); needs yellow ray."); + } + if (options.count() > 0) + description.listAppend("Possible targets:" + options.listJoinComponents("
").HTMLGenerateIndentedText()); + + resource_entries.listAppend(ChecklistEntryMake("__familiar Melodramedary", "familiar.php", ChecklistSubentryMake(title, description), 1).ChecklistEntrySetIDTag("Melodramedary familiar resource")); +} + +RegisterResourceGenerationFunction("IOTMSpinmasterLatheGenerateResource"); +void IOTMSpinmasterLatheGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (available_amount($item[SpinMaster™ lathe]) < 1 || !is_unrestricted($item[SpinMaster™ lathe])) return; + + if (!get_property_boolean("_spinmasterLatheVisited")) { + string image_name = "__item purpleheart logs"; + string description = "Get wood for an +xp weapon."; + + resource_entries.listAppend(ChecklistEntryMake("__item purpleheart logs", "inventory.php?ftext=spinmaster", ChecklistSubentryMake("SpinMaster lathe wood obtainable", "", description), 1).ChecklistEntrySetIDTag("SpinMaster lathe resource")); + } +} + +RegisterResourceGenerationFunction("IOTMCargoCultistShortsGenerateResource"); +void IOTMCargoCultistShortsGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[Cargo Cultist Shorts]]) return; + + if (!get_property_boolean("_cargoPocketEmptied")) { + string image_name = "__item cargo cultist shorts"; + + boolean [int] empty_pockets; + string [int] empty_pocket_list = split_string(get_property("cargoPocketsEmptied"), ","); + foreach _, pocket in empty_pocket_list { + empty_pockets[to_int(pocket)] = true; + } + + string [int] options; + string [int] description; + description.listAppend("Pick a pocket for something useful! Too many to list!"); + if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) + { + if (locationAvailable($location[The royal guard Chamber]) == true && !(empty_pockets contains 343)) + { + options.listAppend(HTMLGenerateSpanOfClass("343 - Filthworm Drone Stench:", "r_bold") + " Stinky!"); + } + if ($item[star chart].available_amount() == 0 && $item[richard's star key].available_amount() == 0 && !(empty_pockets contains 533)) + { + options.listAppend(HTMLGenerateSpanOfClass("533 - greasy desk bell:", "r_bold") + " star key components"); + } + if (locationAvailable($location[The eXtreme Slope]) == false && !(empty_pockets contains 565)) + { + options.listAppend(HTMLGenerateSpanOfClass("565 - mountain man:", "r_bold") + " YR for 2x ore"); + } + if (locationAvailable($location[The Battlefield (Frat Uniform)]) == false && !(empty_pockets contains 589)) + { + options.listAppend(HTMLGenerateSpanOfClass("589 - Green Ops Soldier:", "r_bold") + " olfact for funny meme strategies."); + } + + } + if (options.count() > 0) + description.listAppend("Potentially pickable pockets:|*" + options.listJoinComponents("|*")); + + resource_entries.listAppend(ChecklistEntryMake("__item cargo cultist shorts", "inventory.php?action=pocket", ChecklistSubentryMake("Cargo shorts pocket openable", "", description), 1).ChecklistEntrySetIDTag("Cargo shorts resource")); + } +} +//comprehensive cartography +RegisterTaskGenerationFunction("IOTMComprehensiveCartographyGenerateTasks"); +void IOTMComprehensiveCartographyGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!lookupSkill("Comprehensive Cartography").have_skill()) return; + if (get_property_boolean("mappingMonsters")) { + task_entries.listAppend(ChecklistEntryMake("__skill Map the Monsters", "", ChecklistSubentryMake("Mapping the Monsters now!", "", "Fight a chosen monster in the next zone."), -11).ChecklistEntrySetIDTag("Cartography skill map now")); + } +} + +RegisterResourceGenerationFunction("IOTMComprehensiveCartographyGenerateResource"); +void IOTMComprehensiveCartographyGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupSkill("Comprehensive Cartography").have_skill()) + return; + int maps_left = clampi(3 - get_property_int("_monstersMapped"), 0, 3); + string [int] description; + string [int] options; + string [int] monsterMaps; + if (maps_left > 0) + { + description.listAppend("Map the monsters you want to fight!"); + + if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) + { + //automatic carto NCs + description.listAppend("This IotM also gives you a special noncom in the following zones:"); + int cartoAbooAscension = get_property_int("lastCartographyBooPeak"); + if (my_ascensions() > cartoAbooAscension) { + options.listAppend(HTMLGenerateSpanOfClass("First adv", "r_bold") + " A-Boo Peak: free A-boo clue"); + } + int cartoCastleAscension = get_property_int("lastCartographyCastleTop"); + if (my_ascensions() > cartoCastleAscension) { + options.listAppend("Castle Top: finish quest"); + } + int cartoDarkNeckAscension = get_property_int("lastCartographyDarkNeck"); + if (my_ascensions() > cartoDarkNeckAscension) { + options.listAppend("The Dark Neck of the Woods: +2 progress"); + } + int cartoNookAscension = get_property_int("lastCartographyDefiledNook"); + if (my_ascensions() > cartoNookAscension) { + options.listAppend("The Defiled Nook: +2 Evil Eyes"); + } + int cartoFratAscension = get_property_int("lastCartographyFratHouse"); + if (my_ascensions() > cartoFratAscension) { + options.listAppend(HTMLGenerateSpanOfClass("First adv", "r_bold") + " Orcish Frat House: free garbage"); + } + int cartoGuanoAscension = get_property_int("lastCartographyGuanoJunction"); + if (my_ascensions() > cartoGuanoAscension) { + options.listAppend(HTMLGenerateSpanOfClass("First adv", "r_bold") + " Guano Junction: Screambat"); + } + int cartoBilliardsAscension = get_property_int("lastCartographyHauntedBilliards"); + if (my_ascensions() > cartoBilliardsAscension) { + options.listAppend("Haunted Billiards: play pool immediately"); + } + int cartoProtestersAscension = get_property_int("lastCartographyZeppelinProtesters"); + if (my_ascensions() > cartoProtestersAscension) { + options.listAppend("Mob of Zeppelin Protesters: pick any NC"); + } + int cartoWarFratAscension = get_property_int("lastCartographyFratHouseVerge"); + if (my_ascensions() > cartoWarFratAscension) { + options.listAppend("Wartime Frat House: pick any NC"); + } + int cartoWarHippyAscension = get_property_int("lastCartographyHippyCampVerge"); + if (my_ascensions() > cartoWarHippyAscension) { + options.listAppend("Wartime Hippy Camp: pick any NC"); + } + //monstermap options + if (!__quest_state["Level 11 Ron"].finished) + { + monsterMaps.listAppend("Red Butler, 30% free kill item and 15% fun drop item. Combine with Olfaction/Use the Force?"); + } + if (get_property_int("twinPeakProgress") < 15 && $item[rusty hedge trimmers].available_amount() < 4) + { + monsterMaps.listAppend("hedge beast, 15% quest progress item. Possibly Spit."); + } + if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0) + { + monsterMaps.listAppend("Whatsian Commander Ghost, 15% free runaway item. Possibly Spit."); + } + if ($item[star chart].available_amount() < 1 || $item[richard's star key].available_amount() < 1) + { + monsterMaps.listAppend("Astronomer"); + } + if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) + { + monsterMaps.listAppend("Lobsterfrogman, probably a weak option. Combine with Use the Force?"); + } + if ($location[The Battlefield (Frat Uniform)].turns_spent > 20) + { + monsterMaps.listAppend("Green Ops Soldier. Combine with Olfaction/Use the Force and Spit and Explodinal pills."); + } + if (options.count() > 0) + description.listAppend(HTMLGenerateSpanOfClass("Noncoms of interest:", "r_bold") + "|*-" + options.listJoinComponents("|*-")); + if (monsterMaps.count() > 0) + description.listAppend(HTMLGenerateSpanOfClass("Monsters to map:", "r_bold") + "|*-" + monsterMaps.listJoinComponents("|*-")); + } + resource_entries.listAppend(ChecklistEntryMake("__item Comprehensive Cartographic Compendium", "", ChecklistSubentryMake(pluralise(maps_left, "Cartography skill use", "Cartography skill uses"), "", description), 5).ChecklistEntrySetIDTag("Cartography skills resource")); + } +} +/* RegisterTaskGenerationFunction("IOTMSuperheroCapeGenerateTasks"); +void IOTMSuperheroCapeGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + task_entries.listAppend(ChecklistEntryMake("__item unwrapped knock-off retro superhero cape", "", ChecklistSubentryMake("", "", ""), -11).ChecklistEntrySetIDTag("Superhero cape now")); +} */ + +RegisterResourceGenerationFunction("IOTMSuperheroCapeGenerateResource"); +void IOTMSuperheroCapeGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!mafiaIsPastRevision(20494)) return; + item cape = lookupItem("unwrapped knock-off retro superhero cape"); + if (!__iotms_usable[$item[unwrapped knock-off retro superhero cape]]) return; + + if (!__misc_state["in run"]) return; //Only relevant information in aftercore is YR, but the YR tile will already mention the cape if needed anyway, in aftercore. + + // Not too sure if this should even be kept? There's no real precedent of Guide showing a resource that "never ends"... + // We could make a new section that lists a player's possessions and everything special related to them, and this would go there, but currently... not too sure... + // To be clear, I'm not saying this should be erased, just... commented out for the time being? IDK... + + string current_hero = get_property("retroCapeSuperhero"); + string current_wash = get_property("retroCapeWashingInstructions"); + + record CapeConfiguration { + string hero_name; + string main_modifiers; + string [string] tmhmkmkm; + }; + + CapeConfiguration [string] cape_configurations = { + "vampire":new CapeConfiguration( + "Vampire Slicer", + "+30% muscle, +50 HP", + string [string] { + "hold":"+3 all resistances", + "thrill":"+3 muscle stats/fight", + "kiss":"Skill: Smooch of the Daywalker|Drain 20% of your foe's HP", + "kill":"Skill: Slay the Dead|Undead insta-bone (NOT free kill, requires sword).|+1% Cyrpt evilness reduction." + } + ), + "heck":new CapeConfiguration( + "Heck General", + "+30% myst, +50 MP", + string [string] { + "hold":"Auto 3 rounds stun at start of combats", + "thrill":"+3 myst stats/fight", + "kiss":"Skill: Unleash the Devil's Kiss|Yellow Ray (100 turns)", + "kill":"+100% (multiplicative) spell dmg, dealt as spooky dmg" + } + ), + "robot":new CapeConfiguration( + "Robot Police", + "+30% moxie, +25 HP/MP", + string [string] { + "hold":"Skill: Deploy Robo-Handcuffs|Stagger + 20% delevel 1x/fight", + "thrill":"+3 moxie stats/fight", + "kiss":"Skill: Blow a Robo-Kiss
Deal ~50 sleaze damage", + "kill":"Skill: Precision Shot|Stagger + critical hit (requires gun)." + } + ) + }; + + CapeConfiguration current_cape = cape_configurations[current_hero]; + + + ChecklistSubentry getCurrentCapeConfig() { + // Title + string main_title = "Superhero Cape"; + + // Subtitle + string main_hero = current_cape.hero_name != "" ? current_cape.hero_name : "unknown?"; + string subtitle = " (" + main_hero + " / " + current_wash + " me)"; + + // Entries + string [int] description; + if (cape_configurations contains current_hero) { + description.listAppend( current_cape.main_modifiers ); + description.listAppend( current_cape.tmhmkmkm[current_wash] ); + } + + return ChecklistSubentryMake(main_title, subtitle, description); + } + + + ChecklistSubentry usefulCapeConfigs() { + string main_title = "Useful configurations: "; + string [int] description; + string cape_stats; + switch ( my_primestat() ) { + case $stat[Muscle]: + cape_stats = "Vampire"; + break; + case $stat[Mysticality]: + cape_stats = "Heck"; + break; + case $stat[Moxie]: + cape_stats = "Robot"; + break; + } + if ( __misc_state["need to level"] && cape_stats != "" && (current_hero != cape_stats.to_lower_case() || current_wash != "thrill") ) + description.listAppend( HTMLGenerateSpanOfClass("Mainstat exp: ", "r_bold" ) + cape_stats + " + Thrill" ); + + if ( $effect[Everything looks yellow].have_effect() == 0 && (current_hero != "heck" || current_wash != "kiss") ) + description.listAppend( HTMLGenerateSpanOfClass("Yellow ray: ", "r_bold" ) + "Heck + Kiss" ); + + if ( current_hero != "vampire" || current_wash != "hold" ) + description.listAppend( HTMLGenerateSpanOfClass("+3 Res: ", "r_bold" ) + "Vampire + Hold" ); + + if ( current_hero != "vampire" || current_wash != "kill" ) //reminder: add this to the cyrpt tile + description.listAppend( HTMLGenerateSpanOfClass("Instakill / Cyrpt Evil: ", "r_bold" ) + "Vampire + Kill" ); + + return ChecklistSubentryMake(main_title, "", description); + } + + + ChecklistEntry entry; + entry.image_lookup_name = "__item unwrapped knock-off retro superhero cape"; + entry.url = cape.equipped() ? "inventory.php?action=hmtmkmkm" : cape.invSearch(); // we don't even need to change/adapt the name, kol recognizes it anyway! + entry.tags.id = "Superhero cape resource"; + entry.should_indent_after_first_subentry = true; + entry.importance_level = 5; + + ChecklistSubentry ccc = getCurrentCapeConfig(); + if ( ccc.entries.count() > 0 ) { + entry.subentries.listAppend(ccc); + } + + ChecklistSubentry ucc = usefulCapeConfigs(); + if ( ucc.entries.count() > 0 ) { + entry.subentries.listAppend(ucc); + } + + if ( entry.subentries.count() > 0 ) { + resource_entries.listAppend(entry); + } +} + +//Ghost of Crimbo Commerce +RegisterTaskGenerationFunction("IOTMCommerceGhostGenerateTasks"); +void IOTMCommerceGhostGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + item commerce_item = get_property_item("commerceGhostItem"); + int commerce_statgain1 = (my_level() * 20) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); + int commerce_statgain2 = (my_level() * 25) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); + boolean in_grey_you = my_class() == $class[grey goo]; // Grey You gains zero stats from your commerce ghost. + + if (__misc_state["in run"] && $familiar[Ghost of Crimbo Commerce].familiar_is_usable() && !in_grey_you) + { + // Title + string url = "familiar.php"; + string title = get_property("commerceGhostCombats") + "/11 Commerce Ghost combats"; + string [int] description; + description.listAppend(HTMLGenerateSpanFont("Don't", "red") + " " + HTMLGenerateSpanFont("ask", "green") + " " + HTMLGenerateSpanFont("questions,", "red") + " " + HTMLGenerateSpanFont("just", "green") + " " + HTMLGenerateSpanFont("consume", "red") + " " + HTMLGenerateSpanFont("product", "green") + " " + HTMLGenerateSpanFont("and", "red") + " " + HTMLGenerateSpanFont("then", "green") + " " + HTMLGenerateSpanFont("get", "red") + " " + HTMLGenerateSpanFont("excited", "green") + " " + HTMLGenerateSpanFont("for", "red") + " " + HTMLGenerateSpanFont("new", "green") + " " + HTMLGenerateSpanFont("products.", "red")); + description.listAppend("Gain ~" + commerce_statgain1 + "-" + commerce_statgain2 + " to all 3 substats."); + description.listAppend("Wins, losses, banishes, anything works."); + + if (commerce_item != $item[none]) + { + string title = "Give yourself the gift of getting!"; + description.listAppend(HTMLGenerateSpanFont("Buy", "red") + " " + HTMLGenerateSpanFont("buy ", "green") + " " + HTMLGenerateSpanFont("buy", "red") + " " + HTMLGenerateSpanFont("buy ", "green") + " " + HTMLGenerateSpanFont("buy!", "red")); + + string url = "mall.php?justitems=0&pudnuggler=%22" + commerce_item + "%22"; + + description.listAppend("Buy " + commerce_item + " to get ~" + commerce_statgain1 + "-" + commerce_statgain2 + " to all 3 substats!"); + description.listAppend(HTMLGenerateSpanFont("Buy", "green") + " " + HTMLGenerateSpanFont("buy ", "red") + " " + HTMLGenerateSpanFont("buy ", "green") + " " + HTMLGenerateSpanFont("buy", "red") + " " + HTMLGenerateSpanFont("buy!", "green")); + + task_entries.listAppend(ChecklistEntryMake("__familiar Ghost of Crimbo Commerce", url, ChecklistSubentryMake(title, description), -11)); + } + optional_task_entries.listAppend(ChecklistEntryMake("__familiar Ghost of Crimbo Commerce", url, ChecklistSubentryMake(title, description))); + } +} + +// 2021 +// Miniature Crystal ball +RegisterTaskGenerationFunction("IOTMCrystalBallGenerateTasks"); +void IOTMCrystalBallGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + string title; + + title = "Miniature crystal ball monster prediction(s)"; + string image_name = "__item packaged miniature crystal ball"; + string crystalBall = (get_property("crystalBallPredictions")); + string url; + url = "inventory.php?ponder=1"; + string [int] description; + description.listAppend("The future foretells... dickstabbing!"); + + // Adding replica handling for LOL + int ballsEquipped = lookupItem("miniature crystal ball").equipped_amount() + lookupItem("replica miniature crystal ball").equipped_amount(); + + if (__iotms_usable[$item[miniature crystal ball]]) + { + if (ballsEquipped == 0) //when mcb is not equipped + { + if (crystalBall != "") + { + string [int] predictionsSection; + predictionsSection.listAppend(HTMLGenerateSpanOfClass("Predictions:", "r_bold")); + string[] predictions = crystalBall.split_string("[|]"); + foreach i in (predictions) { + string[] predictions_split = predictions[i].split_string(":"); + predictionsSection.listAppend(predictions_split[1] + " - " + predictions_split[2]); + } + description.listAppend(predictionsSection.listJoinComponents("|*")); + description.listAppend("" + HTMLGenerateSpanFont("Equip the miniature crystal ball first!", "red") + ""); + url = "inventory.php?ponder=1"; + task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(title, description), -11)); + } + else + { + description.listAppend("Equip the miniature crystal ball to predict a monster!"); + url = invSearch("miniature crystal ball"); + optional_task_entries.listAppend(ChecklistEntryMake("__item quantum of familiar", url, ChecklistSubentryMake(title, description))); + } + } + else //when mcb is equipped + { + if (crystalBall != "") + { + string [int] predictionsSection; + predictionsSection.listAppend(HTMLGenerateSpanOfClass("Predictions:", "r_bold")); + string[] predictions = crystalBall.split_string("[|]"); + foreach i in (predictions) { + string[] predictions_split = predictions[i].split_string(":"); + predictionsSection.listAppend(predictions_split[1] + " - " + predictions_split[2]); + } + description.listAppend(predictionsSection.listJoinComponents("|*")); + description.listAppend("" + HTMLGenerateSpanFont("Miniature crystal ball equipped!", "blue") + ""); + task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(title, description), -11)); + } + else + { + description.listAppend("Adventure in a snarfblat to predict a monster!"); + description.listAppend("" + HTMLGenerateSpanFont("Miniature crystal ball equipped!", "blue") + ""); + task_entries.listAppend(ChecklistEntryMake("__item quantum of familiar", url, ChecklistSubentryMake(title, description), -11)); + } + } + } +} +//Emotion Chip +RegisterResourceGenerationFunction("IOTMEmotionChipGenerateResource"); +void IOTMEmotionChipGenerateResource(ChecklistEntry [int] resource_entries) +{ + string url = invSearch("emotion chip"); + + // User does not have emotionally chipped or replica emotionally chipped, but we think they should, and we flag it. + if (!lookupSkill("Emotionally Chipped").have_skill() && !lookupSkill("replica Emotionally Chipped").have_skill() && __iotms_usable[$item[emotion chip]]) { + resource_entries.listAppend(ChecklistEntryMake("__skill feel excitement", url, ChecklistSubentryMake("Emotion Chip Usable", "", "Feel new emotions and use your shiny chip!")).ChecklistEntrySetIDTag("Use emotion chip")); + return; + } + + // Exit out of the tile if they have neither skill and we don't actually think they should, either + if (!lookupSkill("Emotionally Chipped").have_skill() && !lookupSkill("replica Emotionally Chipped").have_skill() && !__iotms_usable[$item[emotion chip]]) return; + + // Otherwise, feel your feelings and get your emotions in check. + ChecklistSubentry getEmotions() { + // Title + string main_title = "Emotion chip feelings"; + // Entries + string [int] description; + string [int] emotions; + + int emotionEnvy = clampi(3 - get_property_int("_feelEnvyUsed"), 0, 3); + if (emotionEnvy > 0 && $skill[Feel Envy].skill_is_usable()) + { + emotions.listAppend(emotionEnvy + " Envys left. Forces the monster to drop all items, but leaves killing it up to you."); + } + int emotionExcitement = clampi(3 - get_property_int("_feelExcitementUsed"), 0, 3); + if (emotionExcitement > 0 && $skill[Feel Excitement].skill_is_usable()) + { + emotions.listAppend(emotionExcitement + " Excitement left. 20 advs of +25 Mus/Mys/Mox."); + } + int emotionHatred = clampi(3 - get_property_int("_feelHatredUsed"), 0, 3); + if (emotionHatred > 0 && $skill[Feel Hatred].skill_is_usable()) + { + emotions.listAppend(emotionHatred + " Hatreds left. 50-turn banish."); + + resource_entries.listAppend(ChecklistEntryMake("__skill feel hatred", "", ChecklistSubentryMake(pluralise(emotionHatred, "Feel Hatred", "Feels Hatreds"), "", "Free run, 50-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Emotion chip feel hatred banish")); + } + int emotionLonely = clampi(3 - get_property_int("_feelLonelyUsed"), 0, 3); + if (emotionLonely > 0 && $skill[Feel Lonely].skill_is_usable()) + { + emotions.listAppend(emotionLonely + " Lonelys left. 20 advs of -5% Combat."); + } + int emotionLost = clampi(3 - get_property_int("_feelLostUsed"), 0, 3); + if (emotionLost > 0 && $skill[Feel Lost].skill_is_usable()) + { + emotions.listAppend(emotionLost + " Losts left. 20 advs of a weird Teleportitis buff."); + } + int emotionNervous = clampi(3 - get_property_int("_feelNervousUsed"), 0, 3); + if (emotionNervous > 0 && $skill[Feel Nervous].skill_is_usable()) + { + emotions.listAppend(emotionNervous + " Nervouses left. 20 advs of passive damage."); + } + int emotionNostalgic = clampi(3 - get_property_int("_feelNostalgicUsed"), 0, 3); + monster nostalgicMonster = (get_property_monster("lastCopyableMonster")); + if (emotionNostalgic > 0 && $skill[Feel Nostalgic].skill_is_usable()) + { + emotions.listAppend(emotionNostalgic + " Nostalgias left. Copy a drop table. Can currently feel nostalgic for: " + HTMLGenerateSpanFont(nostalgicMonster, "blue")); + } + int emotionPeaceful = clampi(3 - get_property_int("_feelPeacefulUsed"), 0, 3); + if (emotionPeaceful > 0 && $skill[Feel Peaceful].skill_is_usable()) + { + emotions.listAppend(emotionPeaceful + " Peacefuls left. 20 advs of +2 elemental resist."); + } + int emotionPride = clampi(3 - get_property_int("_feelPrideUsed"), 0, 3); + if (emotionPride > 0 && $skill[Feel Pride].skill_is_usable()) + { + emotions.listAppend(emotionPride + " Prides left. Triple stat gain from current fight."); + } + int emotionSuperior = clampi(3 - get_property_int("_feelSuperiorUsed"), 0, 3); + if (emotionSuperior > 0 && $skill[Feel Superior].skill_is_usable()) + { + emotions.listAppend(emotionSuperior + " Superiors left. +1 PvP Fight if used as killshot."); + } + int emotionDisappointed = clampi(3 - get_property_int("_feelDisappointedUsed"), 0, 3); + if (emotionDisappointed > 0 && $skill[Feel Disappointed].skill_is_usable()) + { + emotions.listAppend(emotionDisappointed + " Disappointments left. Your therapist has a lot of feelings about this one."); + } + return ChecklistSubentryMake(main_title, description, emotions); + } + + ChecklistEntry entry; + entry.image_lookup_name = "__item emotion chip"; + entry.tags.id = "emotion chip resource"; + + ChecklistSubentry emotions = getEmotions(); + if (emotions.entries.count() > 0) { + entry.subentries.listAppend(emotions); + } + + if (entry.subentries.count() > 0) { + resource_entries.listAppend(entry); + } +} + +//Power Plant +RegisterResourceGenerationFunction("IOTMPowerPlantGenerateResource"); +void IOTMPowerPlantGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupItem("potted power plant").have()) + return; + + // cannot use plant batteries in g-lover. if the user is at d7 of g-lover they probably + // should pick them but i don't want to enable this tile only if it's >d7. + if (my_path().id == PATH_G_LOVER) return; + + // Title + string [int] description; + string batteriesToHarvest = (get_property("_pottedPowerPlant")); + // Entries + if (batteriesToHarvest != "0,0,0,0,0,0,0") + { + string main_title = "Power plant batteries"; + string [int] harvest; + harvest.listAppend("Harvest your potted power plant batteries."); + resource_entries.listAppend(ChecklistEntryMake("__item potted power plant", "inv_use.php?pwd=" + my_hash() + "&whichitem=10738", ChecklistSubentryMake(main_title, "", harvest), 1)); + } + + int batteryTotalCharge; + string url; + url = "inventory.php?ftext=battery+("; + for i from 1 to 6 + { + batteryTotalCharge += i*available_amount(to_item(10738+i)); + } + if (batteriesToHarvest != "0,0,0,0,0,0,0") { + description.listAppend("(Harvest your batteries for a more accurate count.)"); + } + if (batteryTotalCharge > 3) + { + description.listAppend("Make " + HTMLGenerateSpanOfClass(batteryTotalCharge / 4, "r_bold") + " 9-volt batteries to Shockingly Lick."); + description.listAppend("Alternatively, make " + HTMLGenerateSpanOfClass(batteryTotalCharge / 5, "r_bold") + " lantern batteries for a Lick and +100% item drops."); + description.listAppend("Alternatively, make " + HTMLGenerateSpanOfClass(batteryTotalCharge / 6, "r_bold") + " car batteries for a Lick and +100% item and meat drops."); + } + else if (__misc_state["in run"]) + { + description.listAppend("Can't do much with so few batteries, but you can still use them as expensive potions. Maybe save them?"); + } + int shockingLicksAvailable = get_property_int("shockingLickCharges"); + if (shockingLicksAvailable > 0) { + string title; + title = HTMLGenerateSpanFont((get_property_int("shockingLickCharges")) + " Shocking Licks available", "orange"); + description.listAppend(HTMLGenerateSpanFont("This free kill is also a yellow ray!", "orange")); + description.listAppend("Still have " + HTMLGenerateSpanOfClass(batteryTotalCharge, "r_bold") + " charge worth of batteries."); + resource_entries.listAppend(ChecklistEntryMake("__item eternal car battery", url, ChecklistSubentryMake(title, "", description), 0).ChecklistEntrySetCombinationTag("batteries available").ChecklistEntrySetIDTag("Shocking lick free kill")); + } + else if (shockingLicksAvailable == 0 && batteryTotalCharge > 0) + { + resource_entries.listAppend(ChecklistEntryMake("__item battery (aaa)", url, ChecklistSubentryMake("Power plant battery charge: " + (batteryTotalCharge), "", description), 0).ChecklistEntrySetCombinationTag("batteries available").ChecklistEntrySetIDTag("Shocking lick free kill")); + } + +} +//Backup Camera +RegisterResourceGenerationFunction("IOTMBackupCameraGenerateResource"); +void IOTMBackupCameraGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupItem("backup camera").have()) return; + // Title + string main_title = "Back It Up, Back It Up"; + string [int] description; + + + // Entries + int backup_camera_snapsUsed = get_property_int("_backUpUses"); + int totalBackupCameras = 11; + if (my_path().id == PATH_YOU_ROBOT) { + totalBackupCameras = 16; + //for whatever awful reason, this is buggy and will miscount when you break prism until you relog + } + + string url = "inventory.php?ftext=backup+camera"; + int backup_camera_uses_remaining = totalBackupCameras - backup_camera_snapsUsed; + if (backup_camera_uses_remaining > 0) + { + string [int] description; + monster nostalgicMonster = (get_property_monster("lastCopyableMonster")); + description.listAppend(HTMLGenerateSpanFont(nostalgicMonster, "blue") + " is currently in your camera."); + + if (!lookupItem("backup camera").equipped()) + description.listAppend(HTMLGenerateSpanFont("Equip the backup camera first", "red")); + else + description.listAppend("Back up and fight your backup monster!"); + resource_entries.listAppend(ChecklistEntryMake("__item backup camera", url, ChecklistSubentryMake(backup_camera_uses_remaining + " backup camera snaps left", "", description)).ChecklistEntrySetIDTag("Backup camera skill resource")); + } +} + +//Shortest-Order Cook +RegisterResourceGenerationFunction("IOTMShortCookGenerateResource"); +void IOTMShortCookGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["in run"]) return; + if (!lookupFamiliar("Shorter-Order Cook").familiar_is_usable()) return; + if (my_path().id == PATH_G_LOVER) return; // no cook in glover + + int shartCookCharge = get_property_int("_shortOrderCookCharge"); + string [int] description; + string url = "familiar.php"; + string subtitle = "also, use your cook to feed XP to another familiar"; + if (shartCookCharge < 11) + { + description.listAppend("Use the short cook to get a +10 famwt potion."); + resource_entries.listAppend(ChecklistEntryMake("__familiar shorter-order cook", url, ChecklistSubentryMake(shartCookCharge + "/11 Shorter-Order Cook charge", subtitle, description), 8)); + } +} +//Familiar scrapbook +RegisterResourceGenerationFunction("IOTMFamiliarScrapbookGenerateResource"); +void IOTMFamiliarScrapbookGenerateResource(ChecklistEntry [int] resource_entries) +{ + // Title + string main_title = "Familiar scraps"; + string [int] description; + + // Entries + int familiar_scraps = get_property_int("scrapbookCharges"); + int familiar_scrap_banishes = familiar_scraps / 100; + + if (available_amount($item[familiar scrapbook]) > 0) { + if (familiar_scraps < 100) { + description.listAppend(familiar_scraps + " /100 scraps until a banish is available."); + } + else + { + description.listAppend("Free run, 100-turn banish for 100 scraps.|"+familiar_scraps + " scraps collected."); + } + + description.listAppend("Charge up your familiar scrapbook by letting familiars act in combat."); + if (!have_equipped($item[familiar scrapbook])) + description.listAppend(HTMLGenerateSpanFont("Equip the familiar scrapbook first", "red")); + + string url = invSearch("familiar scrapbook"); + resource_entries.listAppend(ChecklistEntryMake("__item familiar scrapbook", url, ChecklistSubentryMake(familiar_scraps / 100 + " scrapbook banishes available", "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Familiar scrapbook boring pictures banish")); + } +} + +//Underground Fireworks Shop +RegisterTaskGenerationFunction("IOTMUndergroundFireworksShopGenerateTasks"); +void IOTMUndergroundFireworksShopGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (__misc_state["in run"] && __misc_state["can eat just about anything"] && available_amount($item[Clan VIP Lounge key]) > 0 && get_property("_fireworksShop").to_boolean() && my_path().id != PATH_G_LOVER) + { + if ($effect[Ready to Eat].have_effect() > 0) + { + string [int] description; + description.listAppend(HTMLGenerateSpanFont("5x food statgain on the next thing you eat!", "red")); + description.listAppend(HTMLGenerateSpanFont("Don't waste it on fire crackers!", "red")); + task_entries.listAppend(ChecklistEntryMake("__effect Ready to Eat", "", ChecklistSubentryMake("Ready to Eat!", "", description), -11)); + } + if ($effect[Everything Looks Red].have_effect() == 0 && my_class() != $class[pig skinner]) + { + string [int] description; + string url = "clan_viplounge.php?action=fwshop&whichfloor=2"; + description.listAppend(HTMLGenerateSpanFont("5x food statgain on the next thing you eat.", "red")); + optional_task_entries.listAppend(ChecklistEntryMake("__item red rocket", url, ChecklistSubentryMake("Fire a red rocket", "", description), 8)); + } + if ($effect[Everything Looks Blue].have_effect() == 0 && my_class() != $class[jazz agent]) + { + string [int] description; + string url = "clan_viplounge.php?action=fwshop&whichfloor=2"; + description.listAppend(HTMLGenerateSpanFont("More MP than your body has room for!", "blue")); + optional_task_entries.listAppend(ChecklistEntryMake("__item blue rocket", url, ChecklistSubentryMake("Fire a blue rocket", "", description), 8)); + } + if ($effect[Everything Looks Yellow].have_effect() == 0 && my_class() != $class[cheese wizard]) + { + string [int] description; + string url = "clan_viplounge.php?action=fwshop&whichfloor=2"; + description.listAppend(HTMLGenerateSpanFont("Best yellow ray!", "orange")); + optional_task_entries.listAppend(ChecklistEntryMake("__item yellow rocket", url, ChecklistSubentryMake("Fire a yellow rocket", "", description), 8)); + } + } +} + +//FIXME: these do not track properly and will remain even when purchased, may fix eventually + +RegisterResourceGenerationFunction("IOTMUndergroundFireworksShopGenerateResource"); +void IOTMUndergroundFireworksShopGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id == PATH_G_LOVER) return; // none of this stuff has G in it! + + // Adding a way to get this to yank out the tile if you're in standard. + if (!lookupItem("fedora-mounted fountain").is_unrestricted()) return; + + if (!get_property_boolean("_fireworksShopEquipmentBought") && available_amount($item[Clan VIP Lounge key]) > 0 && get_property("_fireworksShop").to_boolean() && my_path() != $path[Legacy of Loathing]) + { + string [int] description; + description.listAppend("Can buy one of the following (1000 meat):"); + description.listAppend("Catherine Wheel: +3 exp back item"); + description.listAppend("Oversized sparkler: +20% item drop club"); + description.listAppend("Rocket boots: +100% initiative accessory"); + resource_entries.listAppend(ChecklistEntryMake("__item oversized sparkler", "clan_viplounge.php?action=fwshop&whichfloor=2", ChecklistSubentryMake("Explosive equipment", description), 8).ChecklistEntrySetIDTag("Clan fireworks equipment resource")); + } + if (!get_property_boolean("_fireworksShopHatBought") && available_amount($item[Clan VIP Lounge key]) > 0 && my_path() != $path[Legacy of Loathing]) + { + string [int] description; + description.listAppend("Can buy one of the following (500 meat):"); + description.listAppend("Fedora-mounted fountain: +20 ML hat"); + description.listAppend("Sombrero-mounted sparkler: +5% combat hat"); + description.listAppend("Porkpie-mounted popper: -5% combat hat"); + resource_entries.listAppend(ChecklistEntryMake("__item fedora-mounted fountain", "clan_viplounge.php?action=fwshop&whichfloor=2", ChecklistSubentryMake("Dangerous hats", description), 8).ChecklistEntrySetIDTag("Clan fireworks hat resource")); + } +} + +// Missing: Candles +//Industrial fire extinguisher +RegisterResourceGenerationFunction("IOTMFireExtinguisherGenerateResource"); +void IOTMFireExtinguisherGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[industrial fire extinguisher]]) return; + + string [int] description; + string [int] options; + + // Entries + int extinguisher_charge = get_property_int("_fireExtinguisherCharge"); + boolean extinguisher_refill = get_property_boolean("_fireExtinguisherRefilled"); + boolean is_on_fire = my_path().id == 43; // Path 43 is Wildfire. + + string url = "inventory.php?ftext=industrial+fire+extinguisher"; + description.listAppend("Extinguish the fires in your life!"); + if (extinguisher_charge >= 5) + { + description.listAppend(HTMLGenerateSpanOfClass("Blast the Area (5% charge):", "r_bold") + " 1 turn of passive damage."); + description.listAppend(HTMLGenerateSpanOfClass("Foam 'em Up (5% charge):", "r_bold") + " Stun!"); + if (extinguisher_charge >= 10) + description.listAppend(HTMLGenerateSpanOfClass("Foam Yourself (10% charge):", "r_bold") + " 1 turn of +30 Hot Resist."); + description.listAppend(HTMLGenerateSpanOfClass("Polar Vortex (10% charge):", "r_bold") + " Hugpocket duplicator, usable more than once per fight."); + } + + + if (__misc_state["in run"] && is_on_fire && !get_property_boolean("_fireExtinguisherRefilled") ) + { + string description = "Tank refill available"; + resource_entries.listAppend(ChecklistEntryMake("__item fireman's helmet", "place.php?whichplace=wildfire_camp&action=wildfire_captain", ChecklistSubentryMake("Tank refill available", "", description)).ChecklistEntrySetIDTag("Tank refill resource")); + } + + if (!lookupItem("industrial fire extinguisher").equipped()) + description.listAppend(HTMLGenerateSpanFont("Equip the fire extinguisher first.", "red")); + + if (__misc_state["in run"] && my_path().id != 25 && extinguisher_charge >= 20) // Path 25 is Community Service. + { + if (!get_property_boolean("fireExtinguisherBatHoleUsed") && !__quest_state["Level 4"].finished) + { + options.listAppend(HTMLGenerateSpanOfClass("Bat Hole:", "r_bold") + " Unlock next zone for free."); + } + if (!get_property_boolean("fireExtinguisherHaremUsed") && !__quest_state["Level 5"].finished) + { + options.listAppend(HTMLGenerateSpanOfClass("Cobb's Knob Harem:", "r_bold") + " Get harem outfit for free."); + } + if (!get_property_boolean("fireExtinguisherCyrptUsed") && !__quest_state["Level 7"].finished) + { + options.listAppend(HTMLGenerateSpanOfClass("The Cyrpt:", "r_bold") + " -10 Evilness in one zone."); + } + if (!get_property_boolean("fireExtinguisherChasmUsed") && !__quest_state["Level 9"].finished) + { + options.listAppend(HTMLGenerateSpanOfClass("Smut Orc Logging Camp:", "r_bold") + " +66% Blech House progress."); + } + if (!get_property_boolean("fireExtinguisherDesertUsed") && !locationAvailable($location[The Upper Chamber]) == true) + { + options.listAppend(HTMLGenerateSpanOfClass("Arid, Extrawhatever Desert:", "r_bold") + " Ultrahydrated (15 advs)."); + } + + if (options.count() > 0) + description.listAppend(HTMLGenerateSpanOfClass("Zone-specific skills (20% charge):", "r_bold") + " 1/ascension special options in the following zones:|*-" + options.listJoinComponents("|*-")); + } + if ((is_on_fire && !get_property_boolean("_fireExtinguisherRefilled") || extinguisher_charge >= 5)) { + resource_entries.listAppend(ChecklistEntryMake("__item industrial fire extinguisher", url, ChecklistSubentryMake(extinguisher_charge + "% fire extinguisher available", "", description)).ChecklistEntrySetIDTag("industrial fire extinguisher skills resource")); + } +} + +//Vampire Vintner +RegisterTaskGenerationFunction("IOTMVampireVintnerGenerateTasks"); +void IOTMVampireVintnerGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__misc_state["in run"] || !lookupFamiliar("vampire vintner").familiar_is_usable()) return; + + // For some reason, Vintner leaked into subsequent standards. Unfortunately, the wine isn't standard, so... + if (!lookupItem("1950 vampire vintner wine").is_unrestricted()) return; + + int vintnerFightsLeft = clampi(14 - get_property_int("vintnerCharge"), 0, 14); + int vintnerWineLevel = get_property_int("vintnerWineLevel"); + string url = "familiar.php"; + + string [int] description; + string [int] wineDescription; + string wineType = (get_property("vintnerWineType")); + description.listAppend("Use certain damage types to get premium wines:"); + description.listAppend(HTMLGenerateSpanFont("Hot damage:", "red") + " +item% wine."); + description.listAppend(HTMLGenerateSpanFont("Cold damage:", "blue") + " +meat% wine."); + description.listAppend(HTMLGenerateSpanFont("Familiar damage:", "orange") + " +fam xp and +ML wine."); + + if ($item[1950 vampire vintner wine].available_amount() == 1 && $item[1950 vampire vintner wine].item_is_usable()) + { + url = "inventory.php?ftext=vintner+wine"; + wineDescription.listAppend(HTMLGenerateSpanFont("Can't charge another vintner wine until you use this one.", "red")); + switch (wineType) + { + case "hot": + wineDescription.listAppend(HTMLGenerateSpanFont("Hot wine: grants +" + vintnerWineLevel * 3 + " hot damage and +" + vintnerWineLevel * 5 + "% item drops.", "red")); break; + case "cold": + wineDescription.listAppend(HTMLGenerateSpanFont("Cold wine: grants +" + vintnerWineLevel * 3 + " cold damage and +" + vintnerWineLevel * 5 + "% meat drops.", "blue")); break; + case "stench": + wineDescription.listAppend(HTMLGenerateSpanFont("Stench wine: grants +" + vintnerWineLevel * 3 + " stench damage and +" + vintnerWineLevel + " familiar weight.", "green")); break; + case "spooky": + wineDescription.listAppend(HTMLGenerateSpanFont("Spooky wine: grants +" + vintnerWineLevel * 4 + " spooky damage and +" + vintnerWineLevel * 2 + "% spell critical.", "grey")); break; + case "sleaze": + wineDescription.listAppend(HTMLGenerateSpanFont("Sleaze wine: grants +" + vintnerWineLevel * 3 + " sleaze damage and +" + vintnerWineLevel * 5 + "% pickpocket chance.", "purple")); break; + case "physical": + wineDescription.listAppend(HTMLGenerateSpanFont("Physical wine: grants +" + vintnerWineLevel * 2 + "% critical hit and +" + vintnerWineLevel * 10 + "% initiative.", "black")); break; + case "familiar": + wineDescription.listAppend(HTMLGenerateSpanFont("Familiar wine: grants +" + vintnerWineLevel + " familiar experience and +" + vintnerWineLevel * 3 + " ML.", "purple")); break; + } + optional_task_entries.listAppend(ChecklistEntryMake("__item 1950 vampire vintner wine", url, ChecklistSubentryMake("Drink your vampire vintner wine", wineDescription))); + } + else if (vintnerFightsLeft > 1) + { + optional_task_entries.listAppend(ChecklistEntryMake("__familiar vampire vintner", url, ChecklistSubentryMake(vintnerFightsLeft + " Vintner combats remaining", "", description))); + } + else if (vintnerFightsLeft == 1) + { + description.listAppend(HTMLGenerateSpanFont("Vintner will make wine next combat.", "purple")); + task_entries.listAppend(ChecklistEntryMake("__familiar vampire vintner", url, ChecklistSubentryMake("Vintner wine soon", "", description), -11)); + } +} +RegisterResourceGenerationFunction("IOTMVampireVintnerGenerateResource"); +void IOTMVampireVintnerGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__misc_state["in run"]) return; + int vintnerWineLevel = get_property_int("vintnerWineLevel"); + string [int] description; + string [int] wineDescription; + string url = "inventory.php?ftext=vintner+wine"; + string wineType = (get_property("vintnerWineType")); + + if ($item[1950 vampire vintner wine].available_amount() == 1 && $item[1950 vampire vintner wine].item_is_usable()) + { + wineDescription.listAppend(HTMLGenerateSpanFont("Can't charge another vintner wine until you use this one.", "red")); + switch (wineType) + { + case "hot": + wineDescription.listAppend(HTMLGenerateSpanFont("Hot wine: grants +" + vintnerWineLevel * 3 + " hot damage and +" + vintnerWineLevel * 5 + "% item drops.", "red")); break; + case "cold": + wineDescription.listAppend(HTMLGenerateSpanFont("Cold wine: grants +" + vintnerWineLevel * 3 + " cold damage and +" + vintnerWineLevel * 5 + "% meat drops.", "blue")); break; + case "stench": + wineDescription.listAppend(HTMLGenerateSpanFont("Stench wine: grants +" + vintnerWineLevel * 3 + " stench damage and +" + vintnerWineLevel + " familiar weight.", "green")); break; + case "spooky": + wineDescription.listAppend(HTMLGenerateSpanFont("Spooky wine: grants +" + vintnerWineLevel * 4 + " spooky damage and +" + vintnerWineLevel * 2 + "% spell critical.", "grey")); break; + case "sleaze": + wineDescription.listAppend(HTMLGenerateSpanFont("Sleaze wine: grants +" + vintnerWineLevel * 3 + " sleaze damage and +" + vintnerWineLevel * 5 + "% pickpocket chance.", "purple")); break; + case "physical": + wineDescription.listAppend(HTMLGenerateSpanFont("Physical wine: grants +" + vintnerWineLevel * 2 + "% critical hit and +" + vintnerWineLevel * 10 + "% initiative.", "black")); break; + case "familiar": + wineDescription.listAppend(HTMLGenerateSpanFont("Familiar wine: grants +" + vintnerWineLevel + " familiar experience and +" + vintnerWineLevel * 3 + " ML.", "purple")); break; + } + resource_entries.listAppend(ChecklistEntryMake("__item 1950 vampire vintner wine", url, ChecklistSubentryMake("Drink your vampire vintner wine", wineDescription), -11)); + } +} +//Daylight Shavings Helmet + +string [int, string] dshBuffOrder = { + {"Spectacle Moustache": "+50% item and +5 " + HTMLGenerateSpanFont("Spooky", "grey") + " resist"}, + {"Toiletbrush Moustache": "+25 ML and +5 " + HTMLGenerateSpanFont("Stench", "green") + " resist"}, + {"Barbell Moustache": "+25 Muscle and +50% Gear drops"}, + {"Grizzly Beard": "+25-50 MP regen and +5 " + HTMLGenerateSpanFont("Cold", "blue") + " resist"}, + {"Surrealist's Moustache": "+25 Mysticality and +50% Food drops"}, + {"Musician's Musician's Moustache": "+25 Moxie and +50% Booze drops"}, + {"Gull-Wing Moustache": "+100% init and +5 " + HTMLGenerateSpanFont("Hot", "red") + " resist"}, + {"Space Warlord's Beard": "+25 Weapon damage and +10% Crit"}, + {"Pointy Wizard Beard": "+25 Spell damage and +10% Spell Crit"}, + {"Cowboy Stache": "+25 Ranged damage and +50 maximum HP"}, + {"Friendly Chops": "+100% meat and +5 " + HTMLGenerateSpanFont("Sleaze", "purple") + " resist"} +}; + +// Reorder the default list based on our class +string [int, string] currentClassBuffOrder() { + string [int, string] beardOrder; + int classId = my_class().to_int(); + int classIdMod = (classId <= 6) ? classId : (classId % 6 + 1); + for i from 0 to 10 { + int nextBeard = (classIdMod * i) % 11; + beardOrder[i] = dshBuffOrder[nextBeard]; + } + return beardOrder; +} + +// Get our last beard buff and map it into the order for our class +int lastBeardIndex() { + string lastBeardBuffName = get_property_int("lastBeardBuff").to_effect().name; + if (lastBeardBuffName == "") { + return 0; + } + + foreach i, name in currentClassBuffOrder() { + if (name == lastBeardBuffName) { + return i; + } + } + return 0; +} + +boolean isValuableBeard(string beardName) { + return listContainsValue(listMake( + "Spectacle Moustache", + "Toiletbrush Moustache", + "Gull-Wing Moustache", + "Friendly Chops", + "Surrealist's Moustache" + ), beardName); +} + +buffer boldIfValuable(string beardName) { + return isValuableBeard(beardName) ? + HTMLGenerateSpanOfClass(beardName, "r_bold") : + to_buffer(beardName); +} + +RegisterTaskGenerationFunction("IOTMDaylightShavingsHelmetGenerateTasks"); +void IOTMDaylightShavingsHelmetGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__misc_state["in run"]) return; + if (!lookupItem("daylight shavings helmet").have()) return; + + string [int] description; + string url = "inventory.php?ftext=daylight+shavings+helmet"; + description.listAppend("Shave turns off of your sanity!"); + + int beardBuff = get_property_int("lastBeardBuff"); + + // Shaving buff prediction + string [int, string] buffOrder = currentClassBuffOrder(); + string [string] nextBeardBuff = buffOrder[(lastBeardIndex() + 1) % 11]; + string nextBeardBuffDescription; + string nextBeardBuffEffect; + foreach nextBeardBuffName in nextBeardBuff { + nextBeardBuffDescription = nextBeardBuff[nextBeardBuffName]; + nextBeardBuffEffect = boldIfValuable(nextBeardBuffName) + ", " + to_buffer(nextBeardBuffDescription); + } + description.listAppend("Next shavings effect:
" + nextBeardBuffEffect); + + string [int][int] tooltip_table; + for i from lastBeardIndex() + 1 to lastBeardIndex() + 11 { + string [string] buff = currentClassBuffOrder()[i % 11]; + string buffDescription; + foreach buffName in buff { + buffDescription = buff[buffName]; + tooltip_table.listAppend(listMake(boldIfValuable(buffName), buffDescription)); + } + } + + buffer tooltip_text; + tooltip_text.append(HTMLGenerateTagWrap("div", "DSH beard cycle", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); + tooltip_text.append(HTMLGenerateSimpleTableLines(tooltip_table)); + + if (!lookupItem("daylight shavings helmet").equipped()) + description.listAppend(HTMLGenerateSpanFont("Equip the helmet first.", "red")); + else + description.listAppend(HTMLGenerateSpanFont("Your equipped helmet will buff you.", "blue")); + + string beardCycleList = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Full beard cycle", "r_tooltip_outer_class"); + description.listAppend(beardCycleList); + + if ($effect[Toiletbrush Moustache].have_effect() < 2 && $effect[Barbell Moustache].have_effect() < 2 && $effect[Grizzly Beard].have_effect() < 2 && $effect[Surrealist's Moustache].have_effect() < 2 && $effect[Musician's Musician's Moustache].have_effect() < 2 && $effect[Gull-Wing Moustache].have_effect() < 2 && $effect[Space Warlord's Beard].have_effect() < 2 && $effect[Pointy Wizard Beard].have_effect() < 2 && $effect[Cowboy Stache].have_effect() < 2 && $effect[Friendly Chops].have_effect() < 2 && $effect[Spectacle Moustache].have_effect() < 2) { + task_entries.listAppend(ChecklistEntryMake("__item daylight shavings helmet", url, ChecklistSubentryMake("Daylight Shavings Helmet buff available", "", description), -11)); + } + else { + optional_task_entries.listAppend(ChecklistEntryMake("__item daylight shavings helmet", url, ChecklistSubentryMake("Daylight Shavings Helmet buff charging", "", description), 8)); + } +} +RegisterTaskGenerationFunction("IOTMColdMedicineCabinetGenerateTasks"); +void IOTMColdMedicineCabinetGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + monster gregarious_monster = get_property_monster("beGregariousMonster"); + int fights_left = clampi(get_property_int("beGregariousFightsLeft"), 0, 3); + string [int] description; + + if (gregarious_monster != $monster[none] && fights_left > 0) + { + description.listAppend("Neaaaar, faaaaaaar, wherever you spaaaaaaar, I believe that the heart does go onnnnn."); + description.listAppend("Will appear in any zone, so try to find a zone with few monsters."); + optional_task_entries.listAppend(ChecklistEntryMake("__monster " + gregarious_monster, "url", ChecklistSubentryMake("Fight " + pluralise(fights_left, "more gregarious " + gregarious_monster, "more gregarious " + gregarious_monster + "s"), "", description), -1)); + } + if (!__iotms_usable[lookupItem("cold medicine cabinet")]) return; + + // Parsing the lastCombatEnvironments for a count of CMC combats. + string cmcCombatString = get_property("lastCombatEnvironments"); + string[int] splitCMC = split_string(cmcCombatString, ""); + int uTurns; + int iTurns; + int oTurns; + + foreach turn in splitCMC { + if (splitCMC[turn] == "i") {iTurns +=1;} + if (splitCMC[turn] == "u") {uTurns +=1;} + if (splitCMC[turn] == "o") {oTurns +=1;} + } + + string expectedSpleenItem = "Fleshazole"; + + if (uTurns > 10) expectedSpleenItem = "Breathitin"; + if (iTurns > 10) expectedSpleenItem = "Extrovermectin"; + if (oTurns > 10) expectedSpleenItem = "Homebodyl"; + + int CMC_consults = clampi(5 - get_property_int("_coldMedicineConsults"), 0, 5); + if (CMC_consults > 0) + { + int next_CMC_Turn = get_property_int("_nextColdMedicineConsult"); + int next_CMC_Timer = (next_CMC_Turn - total_turns_played()); + string [int] description; + string url = "campground.php?action=workshed"; + + if (next_CMC_Turn -1 == total_turns_played()) + { + description.listAppend(HTMLGenerateSpanFont("Consultation ready next turn!", "red")); + description.listAppend("You'll be prescribed " + HTMLGenerateSpanOfClass(expectedSpleenItem, "r_bold")); + description.listAppend("You have " + CMC_consults + " consultations remaining."); + task_entries.listAppend(ChecklistEntryMake("__item snow suit", url, ChecklistSubentryMake("The cold medicine cabinet is almost in session", "", description), -11)); + } + else if (next_CMC_Turn <= total_turns_played()) + { + description.listAppend(HTMLGenerateSpanFont("Just what the doctor ordered!", "blue")); + description.listAppend("You'll be prescribed " + HTMLGenerateSpanOfClass(expectedSpleenItem, "r_bold")); + description.listAppend("You have " + CMC_consults + " consultations remaining."); + task_entries.listAppend(ChecklistEntryMake("__item snow suit", url, ChecklistSubentryMake("The cold medicine cabinet is in session", "", description), -11)); + } + } +} + +RegisterResourceGenerationFunction("IOTMColdMedicineCabinetGenerateResource"); +void IOTMColdMedicineCabinetGenerateResource(ChecklistEntry [int] resource_entries) +{ + //gregariousness + int uses_remaining = get_property_int("beGregariousCharges"); + if (uses_remaining > 0) + { + if (true) + { + //The section that will be sent as a stand-alone resource + string url; + + string [int] description; + description.listAppend("Be gregarious in combat, which lets you turn foes into friends!"); + string [int] gregfriends; + gregfriends.listAppend("Bob Racecar, or his brother Racecar Bob"); + gregfriends.listAppend("dirty old lihc (cyrpt progress)"); + gregfriends.listAppend("lobsterfrogman (gunpowder)"); + gregfriends.listAppend("modern zmobie (cyrpt progress)"); + gregfriends.listAppend("dense liana (free fight)"); + gregfriends.listAppend("drunk pygmy (free fight)"); + gregfriends.listAppend("eldritch tentacle (free fight, difficult)"); + gregfriends.listAppend("lynyrd (free fight)"); + gregfriends.listAppend("[degenerate aftercore farming target]"); + description.listAppend("Potentially good friendships:|*" + gregfriends.listJoinComponents("|*")); + resource_entries.listAppend(ChecklistEntryMake("__effect Good Karma", url, ChecklistSubentryMake(uses_remaining.pluralise("gregarious handshake", "gregarious handshakes"), "", description)).ChecklistEntrySetIDTag("gregarious wanderer resource")); + } + } + + //breathitin + int breaths_remaining = get_property_int("breathitinCharges"); + if (breaths_remaining > 0) + { + string [int] description; + description.listAppend("Outdoor fights become free."); + resource_entries.listAppend(ChecklistEntryMake("__item beefy pill", "", ChecklistSubentryMake(pluralise(breaths_remaining, "breathitin breath", "breathitin breaths"), "", description), -2)); + } + + //homebodyl + int homebodyls_remaining = get_property_int("homebodylCharges"); + if (homebodyls_remaining > 0) + { + string [int] description; + description.listAppend("Free crafting."); + description.listAppend("Lynyrd equipment, potions, and more."); + resource_entries.listAppend(ChecklistEntryMake("__item excitement pill", "", ChecklistSubentryMake(pluralise(homebodyls_remaining, "homebodyl free craft", "homebodyl free crafts"), "", description))); + } + + //consultation counter + int CMC_consults = clampi(5 - get_property_int("_coldMedicineConsults"), 0, 5); + if (CMC_consults > 0 && __iotms_usable[lookupItem("cold medicine cabinet")]) + { + // Tracking tile; gives the user information about the last turn-taking combats per the pref. + int next_CMC_Turn = get_property_int("_nextColdMedicineConsult"); + int next_CMC_Timer = (next_CMC_Turn - total_turns_played()); + int fleshazoleMeat = clampi(my_level(),0,11)*1000; + + // Parsing the lastCombatEnvironments for a count of CMC combats. + string cmcCombatString = get_property("lastCombatEnvironments"); + string[int] splitCMC = split_string(cmcCombatString, ""); + int uTurns; + int iTurns; + int oTurns; + string dotMatrix = ''; + + foreach turn in splitCMC { + if (splitCMC[turn] == "i") {iTurns +=1; dotMatrix = dotMatrix+'🞓 ';} + if (splitCMC[turn] == "u") {uTurns +=1; dotMatrix = dotMatrix+'🞮 ';} + if (splitCMC[turn] == "o") {oTurns +=1; dotMatrix = dotMatrix+'🞉 ';} + if (splitCMC[turn] == "?") {oTurns +=1; dotMatrix = dotMatrix+'';} + } + + string expectedSpleenItem = "Fleshazole"; + + if (uTurns > 10) expectedSpleenItem = "Breathitin"; + if (iTurns > 10) expectedSpleenItem = "Extrovermectin"; + if (oTurns > 10) expectedSpleenItem = "Homebodyl"; + + string [int] description; + string url = "campground.php?action=workshed"; + + description.listAppend(HTMLGenerateSpanFont("Route turn-taking combats into the correct environments for a helpful spleen item!", "blue")); + if (next_CMC_Turn > total_turns_played()) + { + description.listAppend("" + HTMLGenerateSpanOfClass(next_CMC_Timer, "r_bold") + " adventures until your next consultation."); + + // Commenting these out. It would be nice to actually solve the issue here, but the logic just needs to be better. + // description.listAppend("Spend " + HTMLGenerateSpanOfClass(next_CMC_Timer - 9, "r_bold") + " non-environmental adventures to double your pill."); + // description.listAppend("" + HTMLGenerateSpanOfClass("Last 20 environments: ", "r_bold") + cmcCombatString + ""); + } + + // Append the lil dot guy if it's useful. + if (length(dotMatrix) > 5) { + description.listAppend(dotMatrix); + } + + string uFormat = uTurns > 10 ? "black" : "grey"; + string iFormat = iTurns > 10 ? "black" : "grey"; + string oFormat = oTurns > 10 ? "black" : "grey"; + + string [int] currentState; + currentState.listAppend(HTMLGenerateSpanOfClass("Currently Expected Spleener: ", "r_bold")+ expectedSpleenItem); + currentState.listAppend(HTMLGenerateSpanFont(uTurns.to_string() + " Underground turns", uFormat)); + currentState.listAppend(HTMLGenerateSpanFont(iTurns.to_string() + " Indoor turns", iFormat)); + currentState.listAppend(HTMLGenerateSpanFont(oTurns.to_string() + " Outdoor turns", oFormat)); + description.listAppend(currentState.listJoinComponents("|*")); + + string [int][int] spleeners; + // Generates a reference table for the user of the spleener effects. + spleeners.listAppend(listMake("Spleen Item", "Environment", "Effect")); + spleeners.listAppend(listMake("Extrovermectin","Indoors 🞓","+3 Wandering Monsters")); + spleeners.listAppend(listMake("Breathitin","Underground 🞮","+5 Outdoor Free Kills")); + spleeners.listAppend(listMake("Homebodyl","Outdoors 🞉","+11 Free Crafts")); + spleeners.listAppend(listMake("Fleshazole","N/A","+"+fleshazoleMeat.to_string()+" meat")); + description.listAppend(HTMLGenerateSimpleTableLines(spleeners)); + + resource_entries.listAppend(ChecklistEntryMake("__item snow suit", url, ChecklistSubentryMake(CMC_consults.pluralise("CMC consultation", "CMC consultations" + " remaining"), "", description)).ChecklistEntrySetIDTag("cold medicine cabinet resource")); + } +} + +// 2022 +//2022: cursed magnifying glass +RegisterTaskGenerationFunction("IOTYCursedMagnifyingGlassGenerateTasks"); +void IOTYCursedMagnifyingGlassGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (lookupItem("cursed magnifying glass").available_amount() == 0) return; + + int free_void_fights_left = clampi(5 - get_property_int("_voidFreeFights"), 0, 5); + int cursedGlassCounter = get_property_int("cursedMagnifyingGlassCount"); + string url; + string [int] description; + if (lookupItem("cursed magnifying glass").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the cursed magnifying glass", "red")); + url = invSearch("cursed magnifying glass"); + } + { + if (cursedGlassCounter < 12) + { + url = invSearch("cursed magnifying glass"); + description.listAppend((13 - cursedGlassCounter).pluralise("combat", "combats") + " until next void fight."); + optional_task_entries.listAppend(ChecklistEntryMake("__item cursed magnifying glass", url, ChecklistSubentryMake("Cursed magnifying glass combat", "", description), 8)); + } + + if (cursedGlassCounter == 12) + { + description.listAppend(HTMLGenerateSpanFont("One more fight until you encounter a void.", "blue")); + task_entries.listAppend(ChecklistEntryMake("__item void stone", url, ChecklistSubentryMake("Cursed magnifying glass combat", "", description), -11)); + } + + if (cursedGlassCounter == 13) + { + if (lookupItem("cursed magnifying glass").equipped_amount() == 0) + { + task_entries.listAppend(ChecklistEntryMake("__item void stone", url, ChecklistSubentryMake("Cursed magnifying glass combat", "", description), -11)); + } + else + { + description.listAppend(HTMLGenerateSpanFont("Void combat next adventure, ", "red") + HTMLGenerateSpanFont("magnifying glass equipped", "blue")); + task_entries.listAppend(ChecklistEntryMake("__item void stone", url, ChecklistSubentryMake("Cursed magnifying glass combat", "", description), -11)); + } + } + if (free_void_fights_left > 0) + { + description.listAppend("" + free_void_fights_left + " free void fights remaining."); + } + else if (lookupSkill("Meteor Lore").have_skill() || lookupItem("powerful glove").available_amount() > 0) + { + description.listAppend("No free void fights remaining, but you can replace them with lobsterfrogmen or something."); + } + else + { + description.listAppend("No free void fights remaining, but you can charge it up for tomorrow?"); + } + } +} + +RegisterResourceGenerationFunction("IOTYCursedMagnifyingGlassGenerateResource"); +void IOTYCursedMagnifyingGlassGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (lookupItem("cursed magnifying glass").available_amount() == 0) return; + + int free_void_fights_left = clampi(5 - get_property_int("_voidFreeFights"), 0, 5); + int cursedGlassCounter = get_property_int("cursedMagnifyingGlassCount"); + string url; + string [int] description; + + if (get_property_int("_voidFreeFights") < 5) { + int cursedGlassCounter = get_property_int("cursedMagnifyingGlassCount"); + url = invSearch("cursed magnifying glass"); + description.listAppend((13 - cursedGlassCounter).pluralise("combat", "combats") + " until next void fight."); + + resource_entries.listAppend(ChecklistEntryMake("__item void stone", "", ChecklistSubentryMake(pluralise(free_void_fights_left, "void glass monster", "void glass monsters"), "", description), 8).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Cursed magnifying glass free fight")); + } +} +//Cosmic Bowling Ball +RegisterTaskGenerationFunction("IOTMCosmicBowlingBallGenerateTasks"); +void IOTMCosmicBowlingBallGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!get_property_boolean("hasCosmicBowlingBall") == true) return; + if (!$item[cosmic bowling ball].is_unrestricted()) return; // Remove from standard-restricted paths + if (my_path() == $path[Legacy of Loathing]) return; + if (my_path().id == PATH_G_LOVER) return; // you can technically use it to bank buffs but the buffs don't work + + int bowlingUses = get_property_int("_cosmicBowlingSkillsUsed"); + int bowlingCooldown2 = bowlingUses * 2 + 5; + int bowlingCooldown = get_property_int("cosmicBowlingBallReturnCombats"); + boolean bowlingSupernag = get_property_boolean("tourGuideBowlingBallSupernag"); + + string url; + if (bowlingCooldown == 1) + { + string [int] description; + string main_title = "Cosmic bowling ball usable"; + description.listAppend(HTMLGenerateSpanFont("You can bowl again next turn!", "blue")); + description.listAppend("Next use has " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " duration."); + task_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake("Cosmic bowling ball returns next combat", "", description), -11)); + } + + if (bowlingCooldown < 0 && bowlingSupernag) + { + string [int] description; + string main_title = "Cosmic bowling ball usable"; + description.listAppend(HTMLGenerateSpanFont("You can bowl again -- right now!", "blue")); + description.listAppend("Next use has " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " duration."); + task_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake("Cosmic bowling ball is in your inventory!", "", description), -11)); + } +} + + +RegisterResourceGenerationFunction("IOTMCosmicBowlingBallGenerateResource"); +void IOTMCosmicBowlingBallGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!get_property_boolean("hasCosmicBowlingBall") == true) return; + if (my_path() == $path[Legacy of Loathing]) return; + if (my_path().id == PATH_G_LOVER) return; // not generating tiles when nothing works right + if (!$item[cosmic bowling ball].is_unrestricted()) return; + + // Entries + int bowlingUses = get_property_int("_cosmicBowlingSkillsUsed"); + int bowlingCooldown2 = bowlingUses * 2 + 5; + int bowlingCooldown = get_property_int("cosmicBowlingBallReturnCombats"); + string url; + if (bowlingCooldown == -1) + { + string main_title = "Cosmic bowling ball usable"; + string [int] description; + description.listAppend("Hit a strike! Knock the competition down a pin with your hole-y ball."); + description.listAppend("Give yourself an item/meat buff, gain stats in a zone, or banish for the next " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " combats."); + + resource_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", "", ChecklistSubentryMake("Bowl a Curveball with your Cosmic Bowling Ball", "", "Has " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " duration and cooldown."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Cosmic bowling ball banish")); + resource_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake("Cosmic bowling ball use available", "", description)).ChecklistEntrySetCombinationTag("special").ChecklistEntrySetIDTag("Cosmic bowling ball skills")); + } + if (bowlingCooldown > -1) + { + string main_title = HTMLGenerateSpanFont("" + bowlingCooldown, "red") + " combats until cosmic bowling ball returns"; + string [int] description; + Banish banish_entry = BanishByName("Bowl a Curveball"); + int turns_left_of_banish = banish_entry.BanishTurnsLeft(); + if (turns_left_of_banish > 0) + { + description.listAppend("Currently used on " + banish_entry.banished_monster + " for " + pluralise(turns_left_of_banish, "more turn", "more turns") + "."); + } + if (bowlingCooldown == 1) + { + description.listAppend(HTMLGenerateSpanFont("You can bowl again next turn!", "blue")); + description.listAppend("Next use has " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " duration."); + resource_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake("Cosmic bowling ball returns next combat", "", description), -11).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Cosmic bowling ball skills")); + resource_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake(main_title, "", description)).ChecklistEntrySetCombinationTag("special").ChecklistEntrySetIDTag("Cosmic bowling ball skills")); + } + else + { + description.listAppend("Bowling ball in the sky with your diamonds."); + description.listAppend("Next use has " + HTMLGenerateSpanOfClass(bowlingCooldown2, "r_bold") + " duration."); + resource_entries.listAppend(ChecklistEntryMake("__item cosmic bowling ball", url, ChecklistSubentryMake(main_title, "", description)).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Cosmic bowling ball skills")); + resource_entries.listAppend(ChecklistEntryMake("__effect trash-wrapped", url, ChecklistSubentryMake(main_title, "", description)).ChecklistEntrySetCombinationTag("special").ChecklistEntrySetIDTag("Cosmic bowling ball skills")); + } + } +} + +//Combat lover's locket +RegisterResourceGenerationFunction("IOTMCombatLoversLocketGenerateResource"); +void IOTMCombatLoversLocketGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupItem("combat lover's locket").have()) return; + { + // Title + string title = "Combat lover's locket reminiscence"; + string [int] options; + string [int] description; + string url = "inventory.php?reminisce=1"; + string locketType = (get_property("locketPhylum")); + string locketEnchant; + switch (get_property("locketPhylum")) + { + case "beast": + locketEnchant = "+10% Crit Chance and +20 Muscle"; break; + case "bug": + locketEnchant = "+25% Weapon Damage and +25% max MP"; break; + case "constellation": + locketEnchant = "+10% Spell Crit and +20 Mysticality"; break; + case "construct": + locketEnchant = "+3 Moxie exp and +25 Spell Damage"; break; + case "demon": + locketEnchant = HTMLGenerateSpanFont("+25 Hot", "red") + " and +50% Gear drops"; break; + case "dude": + locketEnchant = HTMLGenerateSpanFont("+25 Cold", "cold") + " and +50% Moxie"; break; + case "elemental": + locketEnchant = HTMLGenerateSpanFont("+3 Hot res", "red") + " and " + HTMLGenerateSpanFont("+25 Stench Spell", "dark green"); break; + case "elf": + locketEnchant = "+5 exp and +75% Candy drops"; break; + case "fish": + locketEnchant = "+50% Meat Drops and " + HTMLGenerateSpanFont("+25 Spooky Spell", "grey"); break; + case "goblin": + locketEnchant = HTMLGenerateSpanFont("+25 Stench", "dark green") + " and +50% Mysticality"; break; + case "hippy": + locketEnchant = HTMLGenerateSpanFont("+3 Stench res", "dark green") + " and +10 DR"; break; + case "hobo": + locketEnchant = "+3 Mysticality exp and " + HTMLGenerateSpanFont("+25 Hot Spell", "red"); break; + case "horror": + locketEnchant = HTMLGenerateSpanFont("+3 Spooky res", "grey") + " and +50 HP"; break; + case "humanoid": + locketEnchant = "+25% Spell Damage and +20 Moxie"; break; + case "mer-kin": + locketEnchant = "+25% Item Drops and " + HTMLGenerateSpanFont("+25 Sleaze Spell", "purple"); break; + case "orc": + locketEnchant = HTMLGenerateSpanFont("+3 Sleaze res", "purple") + " and +25 MP"; break; + case "penguin": + locketEnchant = "+3 Muscle exp and " + HTMLGenerateSpanFont("+25 Cold Spell", "blue"); break; + case "pirate": + locketEnchant = "+50% Booze Drops and " + HTMLGenerateSpanFont("+25 Sleaze", "purple"); break; + case "plant": + locketEnchant = "+50% Initiative and +50% max HP"; break; + case "slime": + locketEnchant = HTMLGenerateSpanFont("+3 Cold res", "cold") + " and +50 DA"; break; + case "undead": + locketEnchant = HTMLGenerateSpanFont("+25 Spooky", "grey") + " and +50% Muscle"; break; + case "weird": + locketEnchant = "+50% Food Drops and +25 Weapon Damage"; break; + } + + description.listAppend(HTMLGenerateSpanOfClass("Current enchantment: ", "r_bold") + locketType); + description.listAppend(HTMLGenerateSpanFont(locketEnchant, "blue") + ""); + + // Entries + int monstersReminisced = clampi(3 - count(split_string(get_property("_locketMonstersFought"), ",")), 0, 3); + if (get_property("_locketMonstersFought") == "") { + resource_entries.listAppend(ChecklistEntryMake("__item combat lover's locket", url, ChecklistSubentryMake("" + "3 Combat lover's locket reminiscences", "", description)).ChecklistEntrySetIDTag("Locket fax resource")); + } + else { + if (monstersReminisced > 0) + { + if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) { + options.listAppend(HTMLGenerateSpanOfClass("Fax replacements", "r_bold") + ""); + options.listAppend("Black crayon scalers, any phylum"); + options.listAppend("Frat warrior outfit, if no numberology"); + options.listAppend("Mountain man"); + options.listAppend("Ninja snowman assassin"); + options.listAppend("Swarm of ghuol whelps"); + options.listAppend("Sausage goblin"); + options.listAppend("Baa'baa'bu'ran"); + options.listAppend("Forest spirit (for a machete, with some free crafts)"); + options.listAppend(HTMLGenerateSpanOfClass("Map replacements:", "r_bold") + ""); + options.listAppend("Astronomer OR camel's toe OR skinflute"); + options.listAppend("Lobsterfrogman"); + options.listAppend("Beanbat"); + options.listAppend("Dairy goat"); + options.listAppend("Blur"); + options.listAppend("Lynyrd skinner"); + } + if (options.count() > 0) { + description.listAppend("Rain Man the IotM:|*" + options.listJoinComponents("|*")); + } + resource_entries.listAppend(ChecklistEntryMake("__item combat lover's locket", url, ChecklistSubentryMake(pluralise(monstersReminisced, "Combat lover's locket reminiscence", "Combat lover's locket reminiscences"), "", description), 5).ChecklistEntrySetIDTag("Locket fax resource")); + } + } + } +} +//Grey Goose +RegisterTaskGenerationFunction("IOTMGreyGooseGenerateTasks"); +void IOTMGreyGooseGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // This tile just posts up a task if your Goose is hefty enough to snag adventures, and you have it equipped. + int gooseDrones = get_property_int("gooseDronesRemaining"); + int gooseWeight = min(floor(sqrt($familiar[Grey Goose].experience)),20); + int gooseExperience = ($familiar[Grey Goose].experience); + string [int] description; + description.listAppend("GOOSO IS LIT."); + + // Originally this was designed to only pop up when goose was equipped, but TES changed that by adding the duping stuff. + // if (my_familiar() != lookupFamiliar("Grey Goose")) return; + + if (gooseDrones > 0) + { + string main_title = HTMLGenerateSpanFont(gooseDrones, "brown") + HTMLGenerateSpanFont(" GOOSO drones deployed", "grey"); + description.listAppend("Automatically duplicates non-conditional drops."); + task_entries.listAppend(ChecklistEntryMake("__familiar grey goose", "", ChecklistSubentryMake(main_title,"",description),-11)); + } + + // Surprisingly, the "class" is called Grey Goo even if the path is Grey You. This is not a typo! + if (my_class() == $class[grey goo] && gooseWeight > 5) + { + string main_title = HTMLGenerateSpanFont("GOOSO is " + gooseWeight + " pounds (" + gooseExperience + " exp)", "grey"); + description.listAppend("Re-Process a bunch of matter to gain a bunch of adventures in Grey You."); + task_entries.listAppend(ChecklistEntryMake("__familiar grey goose", "", ChecklistSubentryMake(main_title, "", description), -11)); + } +} + +RegisterResourceGenerationFunction("IOTMGreyGooseGenerateResource"); +void IOTMGreyGooseGenerateResource(ChecklistEntry [int] resource_entries) +{ + // Properly avoid a goose tile if the user has no familiar + if (!lookupFamiliar("Grey Goose").familiar_is_usable()) return; + + // Title + int gooseWeight = floor(sqrt($familiar[Grey Goose].experience)); + int gooseExperience = ($familiar[Grey Goose].experience); + int famExperienceGain = numeric_modifier("familiar experience") +1; + int famExpNeededForNextPound = ((gooseWeight +1) ** 2 - gooseExperience); + int famExpNeededForTwoPounds = ((gooseWeight +2) ** 2 - gooseExperience); + int horribleFamExpCalculation = ceil((36 - gooseExperience) / famExperienceGain); + int horribleFamExpCalculationForGreyYou = ceil((196 - gooseExperience) / famExperienceGain); + int horribleFamExpCalculationForStandard = ceil((400 - gooseExperience) / famExperienceGain); + int newGooseExp = gooseExperience + famExperienceGain; + string [int] description; + string [int] stathelp; + string url = "familiar.php"; + if (gooseWeight < 6) + { + if ((gooseWeight +1) **2 > newGooseExp) + { + description.listAppend("Currently have " + HTMLGenerateSpanOfClass(gooseWeight, "r_bold") + " weight (" + HTMLGenerateSpanOfClass(gooseExperience, "r_bold") + " experience), currently gain " + HTMLGenerateSpanOfClass(famExperienceGain, "r_bold") + " fam exp per fight. (Will become " + HTMLGenerateSpanFont(newGooseExp, "red") +")"); + } + else + { + description.listAppend("Currently have " + HTMLGenerateSpanOfClass(gooseWeight, "r_bold") + " weight (" + HTMLGenerateSpanOfClass(gooseExperience, "r_bold") + " experience), currently gain " + HTMLGenerateSpanOfClass(famExperienceGain, "r_bold") + " fam exp per fight. (Will become " + HTMLGenerateSpanFont(newGooseExp, "blue") +")"); + } + description.listAppend("" + HTMLGenerateSpanOfClass((CEIL(famExpNeededForNextPound / famExperienceGain)), "r_bold") + " combats until next pound, or " + HTMLGenerateSpanOfClass((CEIL(horribleFamExpCalculation)), "r_bold") + " combats for 6 weight."); + resource_entries.listAppend(ChecklistEntryMake("__familiar Grey Goose", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Grey goose skills charging", "grey"), "", description), -2)); + } + if (gooseWeight >= 6) + { + if ((gooseWeight +1) **2 > newGooseExp) + { + description.listAppend("Currently have " + HTMLGenerateSpanOfClass(gooseWeight, "r_bold") + " weight (" + HTMLGenerateSpanOfClass(gooseExperience, "r_bold") + " experience), currently gain " + HTMLGenerateSpanOfClass(famExperienceGain, "r_bold") + " fam exp per fight. (Will become " + HTMLGenerateSpanFont(newGooseExp, "red") +")"); + } + else + { + description.listAppend("Currently have " + HTMLGenerateSpanOfClass(gooseWeight, "r_bold") + " weight (" + HTMLGenerateSpanOfClass(gooseExperience, "r_bold") + " experience), currently gain " + HTMLGenerateSpanOfClass(famExperienceGain, "r_bold") + " fam exp per fight. (Will become " + HTMLGenerateSpanFont(newGooseExp, "blue") +")"); + } + description.listAppend("" + HTMLGenerateSpanOfClass(famExpNeededForNextPound, "r_bold") + " famxp needed for next pound or " + HTMLGenerateSpanOfClass(famExpNeededForTwoPounds, "r_bold") + " for the one after that."); + if (famExperienceGain < famExpNeededForNextPound) + description.listAppend(HTMLGenerateSpanFont("Insufficient famxp for next fight.", "red") + ""); + description.listAppend("Can emit " + HTMLGenerateSpanOfClass(gooseWeight -5, "r_bold") + " drones to duplicate items."); + + //boring in-run nonsense + if (__misc_state["in run"] && gooseWeight > 5) + { + if (my_class() == $class[grey goo] && gooseWeight > 5 && my_level() < 11) + { + description.listAppend("Can generate " + HTMLGenerateSpanOfClass((gooseWeight -5) ** 2, "r_bold") + " mainstat."); + description.listAppend("" + HTMLGenerateSpanOfClass("GREY YOU: " + (CEIL(famExpNeededForNextPound / famExperienceGain)), "r_bold") + " combats until next pound, or " + HTMLGenerateSpanOfClass((CEIL(horribleFamExpCalculationForGreyYou)), "r_bold") + " combats for 14 weight."); + } + else if (__misc_state["in run"] && gooseWeight > 5 && my_level() < 11) + { + #description.listAppend("Can generate " + HTMLGenerateSpanOfClass((gooseWeight -5) ** 3, "r_bold") + " substats."); + float mainstat_gain = ((gooseWeight -5) ** 3) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); + float mainstat_gain_for_four_hundred = ((15) ** 3) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); + description.listAppend("Can generate " + HTMLGenerateSpanOfClass(mainstat_gain.roundForOutput(0), "r_bold") + " substats. (" + HTMLGenerateSpanOfClass((gooseWeight -5) ** 3, "r_bold") +" base)."); + description.listAppend("" + HTMLGenerateSpanOfClass("STAT GOOSO: " + (CEIL(famExpNeededForNextPound / famExperienceGain)), "r_bold") + " combats until next pound, or " + HTMLGenerateSpanOfClass((CEIL(horribleFamExpCalculationForStandard)), "r_bold") + " combats for 20 weight."); + } + #resource_entries.listAppend(ChecklistEntryMake("__familiar grey goose", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Grey goose skills ready!", "grey"), "", stathelp))); + } + if (!get_property_boolean("_meatifyMatterUsed")) { + description.listAppend("Can meatify matter for " + HTMLGenerateSpanOfClass((gooseWeight -5) ** 4, "r_bold") + " meat."); + } + if (!__misc_state["in run"]) + { + if (famExperienceGain >= 39) //from 25 to 64 + description.listAppend(HTMLGenerateSpanFont("Can GOOSO 3 drops per fight!", "green") + ""); + else if (famExperienceGain >= 24) //from 25 to 49 + description.listAppend(HTMLGenerateSpanFont("Can GOOSO 2 drops per fight!", "blue") + ""); + else if (famExperienceGain >= 11) //from 25 to 36 + description.listAppend(HTMLGenerateSpanFont("Can GOOSO 1 drop per fight!", "purple") + ""); + else if (famExperienceGain < 11) //cannot gooso + description.listAppend(HTMLGenerateSpanFont("Cannot GOOSO any drops per fight!", "red") + ""); + } + resource_entries.listAppend(ChecklistEntryMake("__familiar Grey Goose", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Grey goose skills ready!", "grey"), "", description), -2)); + } +} +//Unbreakable Umbrella +RegisterResourceGenerationFunction("IOTMUnbreakableUmbrellaGenerateResource"); +void IOTMUnbreakableUmbrellaGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id == PATH_G_LOVER) return; // no umbrella in glover + item unbrella = lookupItem("unbreakable umbrella"); + if (!unbrella.have()) return; + if (!__misc_state["in run"] && $item[unbreakable umbrella].equipped_amount() == 0) return; + string url; + string unbrellaMode = get_property("umbrellaState"); + string unbrellaEnchant; + string [int] description; + url = invSearch("unbreakable umbrella"); + // Title + string main_title = "Umbrella machine " + HTMLGenerateSpanFont("B", "red") + "roke"; + description.listAppend("Understanda" + HTMLGenerateSpanFont("B", "red") + "le have a nice day."); + + switch (get_property("umbrellaState")) + { + case "broken": + int modifiedML = round(numeric_modifier("monster level") * 1.25,0); + unbrellaEnchant = "+25% ML. Unbrella-boosted ML will be " + modifiedML + "."; break; + case "forward-facing": + unbrellaEnchant = "+25 DR shield"; break; + case "bucket style": + unbrellaEnchant = "+25% item drops"; break; + case "pitchfork style": + unbrellaEnchant = "+25 Weapon Damage"; break; + case "constantly twirling": + unbrellaEnchant = "+25 Spell Damage"; break; + case "cocoon": + unbrellaEnchant = "-10% Combat Frequency"; break; + } + description.listAppend(HTMLGenerateSpanOfClass("Current enchantment: ", "r_bold") + unbrellaMode); + description.listAppend(HTMLGenerateSpanFont(unbrellaEnchant, "blue") + ""); + resource_entries.listAppend(ChecklistEntryMake("__item unbreakable umbrella", "inventory.php?action=useumbrella&pwd=" + my_hash(), ChecklistSubentryMake(main_title, "", description))); +} +// MayDay Package +RegisterResourceGenerationFunction("IOTMMayDayContractGenerateResource"); +void IOTMMayDayContractGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[MayDay™ supply package].available_amount() > 0) #&& in_ronin() && $item[MayDay™ supply package].item_is_usable()) + { + string [int] description; + string url = invSearch("MayDay"); + description.listAppend("Use for 30 advs of +100% init as well as useful seeded drops (formerly ten bucks)"); + resource_entries.listAppend(ChecklistEntryMake("__item MayDay™ supply package", url, ChecklistSubentryMake(pluralise($item[MayDay™ supply package]), "", description))); + } +} +//June cleaver +RegisterTaskGenerationFunction("IOTMJuneCleaverGenerateTasks"); +void IOTMJuneCleaverGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!lookupItem("June cleaver").have()) return; + + string url = "inventory.php?ftext=june+cleaver"; + string [int] description; + string main_title = "June Cleaver dream ready!"; + + int juneCleaverCharge = (get_property_int("_juneCleaverFightsLeft")); + int juneCleaverEncounters = (get_property_int("_juneCleaverEncounters")); + int juneCleaverSkips = clampi(5 - get_property_int("_juneCleaverSkips"), 0, 5); + + //cleaver dream charging + if (juneCleaverCharge == 0) + { + description.listAppend("Cleaver dream ready!"); + description.listAppend("" + juneCleaverSkips + " dream skips remaining for today."); + //cleaver dream queue + string [int] possibleDreams; + if (!get_property("juneCleaverQueue").contains_text("1467")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Poetic Justice", "r_bold") + ", +5 advs, +250 mox, +125 mys"); + } + if (!get_property("juneCleaverQueue").contains_text("1468")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Aunts not Ants", "r_bold") + ", +150 mox, +250 mus, or +exp buff"); + } + if (!get_property("juneCleaverQueue").contains_text("1469")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Beware of Aligator", "r_bold") + ", +ML buff, booze, or 1500 meat"); + } + if (!get_property("juneCleaverQueue").contains_text("1470")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Teacher's Pet", "r_bold") + ", +famxp accessory or +250 mus"); + } + if (!get_property("juneCleaverQueue").contains_text("1471")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Lost and Found", "r_bold") + ", +meat potion, +100 mus, +250 mys"); + } + if (!get_property("juneCleaverQueue").contains_text("1472")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Summer Days", "r_bold") + ", noncom potion or +250 mox"); + } + if (!get_property("juneCleaverQueue").contains_text("1473")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Bath Time", "r_bold") + ", +150 mus or resist buff"); + } + if (!get_property("juneCleaverQueue").contains_text("1474")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Delicious Sprouts", "r_bold") + ", big exp food, +250 mys, +125 mus"); + } + if (!get_property("juneCleaverQueue").contains_text("1475")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Hypnotic Master", "r_bold") + ", +rest accessory or +250 mus"); + } + if (possibleDreams.count() > 0) + description.listAppend(HTMLGenerateSpanOfClass("Possible dreams (not in any order):", "r_bold") + "|*" + possibleDreams.listJoinComponents("|*")); + + if (lookupItem("june cleaver").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the June cleaver", "red")); + } + task_entries.listAppend(ChecklistEntryMake("__item June Cleaver", url, ChecklistSubentryMake(main_title, description), -11).ChecklistEntrySetIDTag("June cleaver dreams")); + } +} + +RegisterResourceGenerationFunction("IOTMJuneCleaverGenerateResource"); +void IOTMJuneCleaverGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupItem("June cleaver").have()) return; + + string url = "inventory.php?ftext=june+cleaver"; + string [int] description; + string main_title = "You can be a June Cleaver"; + + int juneCleaverCharge = (get_property_int("_juneCleaverFightsLeft")); + int juneCleaverEncounters = (get_property_int("_juneCleaverEncounters")); + int juneCleaverSkips = clampi(5 - get_property_int("_juneCleaverSkips"), 0, 5); + + if (juneCleaverCharge == 0) + description.listAppend("Cleaver dream ready!"); + else if (juneCleaverCharge > 0) + description.listAppend("" + juneCleaverCharge + " combats left until next dream."); + description.listAppend("" + juneCleaverSkips + " dream skips remaining for today."); + //cleaver dream queue + string [int] possibleDreams; + if (!get_property("juneCleaverQueue").contains_text("1467")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Poetic Justice", "r_bold") + ", +5 advs, +250 mox, +125 mys"); + } + if (!get_property("juneCleaverQueue").contains_text("1468")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Aunts not Ants", "r_bold") + ", +150 mox, +250 mus, or +exp buff"); + } + if (!get_property("juneCleaverQueue").contains_text("1469")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Beware of Aligator", "r_bold") + ", +ML buff, booze, or 1500 meat"); + } + if (!get_property("juneCleaverQueue").contains_text("1470")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Teacher's Pet", "r_bold") + ", +famxp accessory or +250 mus"); + } + if (!get_property("juneCleaverQueue").contains_text("1471")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Lost and Found", "r_bold") + ", +meat potion, +100 mus, +250 mys"); + } + if (!get_property("juneCleaverQueue").contains_text("1472")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Summer Days", "r_bold") + ", noncom potion or +250 mox"); + } + if (!get_property("juneCleaverQueue").contains_text("1473")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Bath Time", "r_bold") + ", +150 mus or resist buff"); + } + if (!get_property("juneCleaverQueue").contains_text("1474")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Delicious Sprouts", "r_bold") + ", big exp food, +250 mys, +125 mus"); + } + if (!get_property("juneCleaverQueue").contains_text("1475")) + { + possibleDreams.listAppend(HTMLGenerateSpanOfClass("Hypnotic Master", "r_bold") + ", +rest accessory or +250 mus"); + } + if (possibleDreams.count() > 0) + description.listAppend(HTMLGenerateSpanOfClass("Possible dreams (not in any order):", "r_bold") + "|*" + possibleDreams.listJoinComponents("|*")); + + resource_entries.listAppend(ChecklistEntryMake("__item June Cleaver", url, ChecklistSubentryMake(main_title, description)).ChecklistEntrySetIDTag("June cleaver dreams")); +} +//ants +RegisterResourceGenerationFunction("IOTMDesignerSweatpantsResource"); +void IOTMDesignerSweatpantsResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[designer sweatpants]]) return; + + int sweat_o_meter = get_property_int("sweat"); + int booze_sweats_left = clampi(3 - get_property_int("_sweatOutSomeBoozeUsed"), 0, 3); + + string title; + string [int] description; + string url = "inventory.php?ftext=designer+sweatpants"; + + if (sweat_o_meter < 100) { + title = HTMLGenerateSpanFont(sweat_o_meter + "% sweatpants Sweatiness", "purple"); + } else { + title = HTMLGenerateSpanFont("Designer sweatpants: 100% sweaty!", "purple"); + description.listAppend(HTMLGenerateSpanFont("Use up your sweat, maybe!", "purple")); + } + + description.listAppend(HTMLGenerateSpanOfClass("Sweat Flick (1% sweat):", "r_bold") + HTMLGenerateSpanFont(" " + sweat_o_meter + " Sleaze Damage attack", "purple")); + description.listAppend(HTMLGenerateSpanOfClass("Sweat Spray (3% sweat):", "r_bold") + HTMLGenerateSpanFont(" recurring Sleaze Damage attack", "purple")); + description.listAppend(HTMLGenerateSpanOfClass("Sweat Flood (5% sweat):", "r_bold") + " 5-turn stun"); + description.listAppend(HTMLGenerateSpanOfClass("Sip Some Sweat (5% sweat):", "r_bold") + " Regain 50 MP"); + description.listAppend(HTMLGenerateSpanOfClass("Sweat Sip (5% sweat):", "r_bold") + " Regain 50 MP"); + description.listAppend(HTMLGenerateSpanOfClass("Drench Yourself In Sweat (15% sweat):", "r_bold") + " +100% Initiative"); + description.listAppend(HTMLGenerateSpanOfClass("Make Sweat-Ade (50% sweat):", "r_bold") + " make a PvP Fight spleen item"); + if (booze_sweats_left > 0) + description.listAppend(HTMLGenerateSpanOfClass("Sweat Out Some Booze (25% sweat):", "r_bold") + HTMLGenerateSpanFont(" -1 Drunkenness. " + booze_sweats_left + " uses left for today.", "orange")); + resource_entries.listAppend(ChecklistEntryMake("__item designer sweatpants", url, ChecklistSubentryMake(title, description), 1).ChecklistEntrySetIDTag("designer sweatpants resource")); +} +//Tiny stillsuit +RegisterTaskGenerationFunction("IOTMTinyStillsuitGenerateTasks"); +void IOTMTinyStillsuitGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!lookupItem("tiny stillsuit").have()) return; + int fam_sweat_o_meter = get_property_int("familiarSweat"); + + string title; + string [int] description; + string url = "inventory.php?action=distill&pwd=" + my_hash(); + + int sweatCalcSweat; + int sweatAdvs = round(to_int(get_property("familiarSweat"))**0.4); + + // Adding a few conditions to turn off the supernag. + boolean canGuzzleSweat = (availableDrunkenness() > 0); + boolean inStillsuitPath = (!__misc_state["familiars temporarily blocked"] && my_path() != $path[A Shrunken Adventurer am I]); + + // TODO: Turn this into an actual math function instead of an else-if lol + if (fam_sweat_o_meter >= 358) { + sweatCalcSweat = 449; + } + else if (fam_sweat_o_meter >= 279) { + sweatCalcSweat = 358; + } + else if (fam_sweat_o_meter >= 211) { + sweatCalcSweat = 279; + } + else if (fam_sweat_o_meter >= 155) { + sweatCalcSweat = 211; + } + else if (fam_sweat_o_meter >= 108) { + sweatCalcSweat = 155; + } + else if (fam_sweat_o_meter >= 71) { + sweatCalcSweat = 108; + } + else if (fam_sweat_o_meter >= 43) { + sweatCalcSweat = 71; + } + else if (fam_sweat_o_meter >= 23) { + sweatCalcSweat = 43; + } + else if (fam_sweat_o_meter >= 10) { + sweatCalcSweat = 23; + } + else if (fam_sweat_o_meter < 10) { + sweatCalcSweat = 10; + } + + if (fam_sweat_o_meter > 449) { + description.listAppend("" + HTMLGenerateSpanOfClass(sweatAdvs, "r_bold") + " advs when guzzling now (costs 1 liver)."); + description.listAppend("You should probably guzzle your sweat now."); + } + else { + description.listAppend(HTMLGenerateSpanOfClass(fam_sweat_o_meter + "/" + sweatCalcSweat, "r_bold") + " drams of stillsuit sweat for next adventure."); + description.listAppend("" + HTMLGenerateSpanOfClass(sweatCalcSweat - fam_sweat_o_meter, "r_bold") + " more sweat until +1 more adventure. (" + (1+ (sweatCalcSweat - fam_sweat_o_meter)/3) + " combats on current familiar)"); + } + + // Still generate the "warning, not generating sweat" supernag so long as familiars aren't blocked + if ($item[tiny stillsuit].item_amount() == 1 && !__misc_state["familiars temporarily blocked"]) { + title = HTMLGenerateSpanFont("Equip the stillsuit", "purple"); + description.listAppend("" + HTMLGenerateSpanFont("Not collecting sweat from any familiar right now.", "red") + ""); + url = "familiar.php"; + task_entries.listAppend(ChecklistEntryMake("__item tiny stillsuit", url, ChecklistSubentryMake(title, description), -11).ChecklistEntrySetIDTag("tiny stillsuit task")); + } + else if ($item[tiny stillsuit].equipped_amount() == 1) { + description.listAppend("" + HTMLGenerateSpanFont("Currently collecting sweat from current familiar!", "purple") + ""); + } else { + description.listAppend("" + HTMLGenerateSpanFont("Currently collecting sweat on a different familiar!", "fuchsia") + ""); + } + title = HTMLGenerateSpanFont(sweatAdvs + " adv stillsuit sweat booze", "purple"); + + // However, if the user is in a path where they can't use stillsuit or cannot drink the distillate right now, do not show this supernag. + if (!inStillsuitPath || !canGuzzleSweat) return; + + if (__misc_state["in run"] && sweatAdvs > 6) { + task_entries.listAppend(ChecklistEntryMake("__item tiny stillsuit", url, ChecklistSubentryMake(title, description), -11).ChecklistEntrySetIDTag("tiny stillsuit task")); + } + else if (!__misc_state["in run"] && sweatAdvs > 10) { + task_entries.listAppend(ChecklistEntryMake("__item tiny stillsuit", url, ChecklistSubentryMake(title, description), -11).ChecklistEntrySetIDTag("tiny stillsuit task")); + } +} + +RegisterResourceGenerationFunction("IOTMTinyStillsuitGenerateResource"); +void IOTMTinyStillsuitGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupItem("tiny stillsuit").have()) return; + + int fam_sweat_o_meter = get_property_int("familiarSweat"); + int sweatAdvs = round(to_int(get_property("familiarSweat"))**0.4); +# int nextSweatDrams = (sweatAdvs+0.51) ** 2.5;# - fam_sweat_o_meter; + + string title; + string [int] description; + string url = "inventory.php?action=distill&pwd=" + my_hash(); + int sweatCalcSweat; + + description.listAppend("Two gross tastes that taste horrible together."); + //an amish paradise is as primitive as can be + + if (fam_sweat_o_meter >= 358) { + sweatCalcSweat = 449; + } + else if (fam_sweat_o_meter >= 279) { + sweatCalcSweat = 358; + } + else if (fam_sweat_o_meter >= 211) { + sweatCalcSweat = 279; + } + else if (fam_sweat_o_meter >= 155) { + sweatCalcSweat = 211; + } + else if (fam_sweat_o_meter >= 108) { + sweatCalcSweat = 155; + } + else if (fam_sweat_o_meter >= 71) { + sweatCalcSweat = 108; + } + else if (fam_sweat_o_meter >= 43) { + sweatCalcSweat = 71; + } + else if (fam_sweat_o_meter >= 23) { + sweatCalcSweat = 43; + } + else if (fam_sweat_o_meter >= 10) { + sweatCalcSweat = 23; + } + else if (fam_sweat_o_meter < 10) { + sweatCalcSweat = 10; + } + + if (fam_sweat_o_meter > 358) { + description.listAppend("" + HTMLGenerateSpanOfClass("11", "r_bold") + " advs when guzzling now (costs 1 liver)."); + description.listAppend("You should probably guzzle your sweat now."); + } + else if (fam_sweat_o_meter > 10) { + description.listAppend("" + HTMLGenerateSpanOfClass(sweatAdvs, "r_bold") + " advs when guzzling now (costs 1 liver)."); + description.listAppend("" + HTMLGenerateSpanOfClass(sweatCalcSweat - fam_sweat_o_meter, "r_bold") + " more sweat until +1 more adventure. (" + (1+ (sweatCalcSweat - fam_sweat_o_meter)/3) + " combats on current familiar)"); + } + else { + description.listAppend("" + HTMLGenerateSpanFont("Not enough sweat to guzzle.", "red") + ""); + description.listAppend("" + HTMLGenerateSpanOfClass(sweatCalcSweat - fam_sweat_o_meter, "r_bold") + " more sweat until +1 more adventure. (" + (1+ (sweatCalcSweat - fam_sweat_o_meter)/3) + " combats on current familiar)"); + } + + if ($item[tiny stillsuit].item_amount() == 1) { + description.listAppend("" + HTMLGenerateSpanFont("Not collecting sweat from any familiar right now.", "red") + ""); + url = "familiar.php"; + } + else if ($item[tiny stillsuit].equipped_amount() == 1) { + description.listAppend("" + HTMLGenerateSpanFont("Currently collecting sweat from current familiar!", "purple") + ""); + } else { + description.listAppend("" + HTMLGenerateSpanFont("Currently collecting sweat on a different familiar!", "fuchsia") + ""); + } + + title = HTMLGenerateSpanFont(fam_sweat_o_meter + "/" + sweatCalcSweat + " drams of stillsuit sweat", "purple"); + + //sweat chart + string [int][int] tooltip_table; + + // These are the mappings for drams needed for certain adv thresholds. + static string[int] advDramsTable = { + 3:"10", + 4:"23", + 5:"43", + 6:"71", + 7:"108", + 8:"155", + 9:"211", + 10:"279", + 11:"358", + 12:"449", + 13:"553", + 14:"670", + 15:"801", + 16:"946", + 17:"1106", + 18:"1282",}; + + foreach advs, drams in advDramsTable { + // Only append it if the user hasn't yet reached that # of drams + if (drams.to_int() > fam_sweat_o_meter) { + tooltip_table.listAppend(listMake(advs.to_string(), drams+" drams (" + (drams.to_int() - fam_sweat_o_meter) + " more sweat)" )); + } + } + + if (fam_sweat_o_meter > 553) { + tooltip_table.listAppend(listMake("> 13", "... yknow, you should probably just drink it, buddy")); + } + + buffer tooltip_text; + tooltip_text.append(HTMLGenerateTagWrap("div", "Sweat to Advs Conversion Table", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); + tooltip_text.append(HTMLGenerateSimpleTableLines(tooltip_table)); + + string stillSweatTooltip = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Sweat/Advs conversion", "r_tooltip_outer_class"); + description.listAppend(stillSweatTooltip); + + //famtype chart + string [int][int] tooltip_table2; + tooltip_table2.listAppend(listMake("Cubeling / Stomping Boots", "+item")); + tooltip_table2.listAppend(listMake("Levitating Potato / Candy Carnie / Flan", "+item and +food")); + tooltip_table2.listAppend(listMake("Star Starfish / Emilio / Globmule / Waifuton", "+item and +sleaze")); + + buffer tooltip_text2; + tooltip_text2.append(HTMLGenerateTagWrap("div", "Stillsuit buff target", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); + tooltip_text2.append(HTMLGenerateSimpleTableLines(tooltip_table2)); + + string stillSweatTypeTooltip = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text2, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Suggested Stillsuit Familiars", "r_tooltip_outer_class"); + description.listAppend(stillSweatTypeTooltip); + resource_entries.listAppend(ChecklistEntryMake("__item tiny stillsuit", url, ChecklistSubentryMake(title, description), -2).ChecklistEntrySetIDTag("tiny stillsuit resource")); +} +//Jurassic parka +RegisterTaskGenerationFunction("IOTMJurassicParkaGenerateTasks"); +void IOTMJurassicParkaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // Task-based nag for using the parka. Instruct the user to swap modes or equip parka if needed. + if (!__iotms_usable[$item[Jurassic Parka]]) return; + + // Fondeluge is the only skill strictly better than Jurassic acid; don't show this tile if you happen to have it + if (lookupSkill("Fondeluge").have_skill()) return; + if (__misc_state["in run"] && available_amount($item[jurassic parka]) > 0 && my_path().id != PATH_COMMUNITY_SERVICE) + { + string [int] description; + string url = "inventory.php?ftext=jurassic+parka"; + + // TODO: Perhaps a centralized YR supernag would be better? Not sure, tbh. + if ($effect[everything looks yellow].have_effect() == 0) + { + if (lookupItem("jurassic parka").equipped_amount() == 0) + { + description.listAppend(HTMLGenerateSpanFont("Equip your Jurassic Parka!", "red")); + } + else description.listAppend(HTMLGenerateSpanFont("Parka equipped.", "orange")); + if (get_property("parkaMode") != "dilophosaur") + { + description.listAppend(HTMLGenerateSpanFont("Change your parka to dilophosaur mode!", "red")); + } + else description.listAppend(HTMLGenerateSpanFont("Dilophosaur mode enabled.", "orange")); + task_entries.listAppend(ChecklistEntryMake("__item jurassic parka", url, ChecklistSubentryMake("Parka yellow ray is ready; spit some acid!", "", description), -11)); + } + } +} + +RegisterResourceGenerationFunction("IOTMJurassicParkaGenerateResource"); +void IOTMJurassicParkaGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[Jurassic Parka]]) return; + if (!__misc_state["in run"]) return; + if (my_path().id == PATH_G_LOVER) return; // cannot use parka in g-lover + + string url; + string parkaMode = get_property("parkaMode"); + string parkaEnchant; + string [int] description; + + url = invSearch("jurassic parka"); + + int spikos_left = clampi(5 - get_property_int("_spikolodonSpikeUses"), 0, 5); + + // Title + string main_title = "Jurassic Parka"; + description.listAppend("You're the dinosaur now, dawg."); + + switch (get_property("parkaMode")) + { + case "kachungasaur": + parkaEnchant = "+100% HP, +50% meat, +2 Cold res."; break; + case "dilophosaur": + parkaEnchant = "+20 Sleaze and Sleaze Spell, +2 Stench res, YR free kill."; break; + case "spikolodon": + parkaEnchant = "+ML, +2 Sleaze res, NC forcing ability."; break; + case "ghostasaurus": + parkaEnchant = "+10 DR, +50 MP, +2 Spooky res."; break; + case "pterodactyl": + parkaEnchant = "-5% Combat Frequency, +50% Initiative, +2 Hot res."; break; + } + description.listAppend(HTMLGenerateSpanOfClass("Current enchantment: ", "r_bold") + parkaMode); + description.listAppend(HTMLGenerateSpanFont(parkaEnchant, "blue") + ""); + description.listAppend(HTMLGenerateSpanOfClass(spikos_left, "r_bold") + " spikolodon spikes available."); + resource_entries.listAppend(ChecklistEntryMake("__item jurassic parka", "inventory.php?action=jparka", ChecklistSubentryMake(main_title, "", description))); +} + +//Autumnaton +RegisterTaskGenerationFunction("IOTMAutumnatonGenerateTasks"); +void IOTMAutumnatonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + # if (!__misc_state["in run"]) return; // Turned off because TES likes this tile to appear in aftercore + if (!get_property_boolean("hasAutumnaton")) return; // Don't show if they don't actually have Fall-E + if (!$item[autumn dollar].is_unrestricted()) return; // Remove from standard-restricted paths + if (my_path() == $path[Legacy of Loathing]) return; // Cannot use fall-e in LoL + if (my_path().id == PATH_G_LOVER) return; // Cannot use fall-e in G-Lover + if (in_bad_moon()) return; // Cannot use fall-e in Bad Moon + + int autobotsToday = get_property_int("_autumnatonQuests"); + int turncountWhereAutobotReturns = get_property_int("autumnatonQuestTurn"); + + if (get_property("autumnatonUpgrades").contains_text("leftleg1")) { + autobotsToday -= 1; + } + if (get_property("autumnatonUpgrades").contains_text("rightleg1")) { + autobotsToday -= 1; + } + + int autobotsReturnTime = autobotsToday; + + if (autobotsToday < 1) { + autobotsReturnTime = 11; + } + else { + autobotsReturnTime = autobotsToday * 11; + } + + string url; + string [int] description; + string [int] [int] targets; + + description.listAppend("Autobot grabs items from a zone you've previously visited."); + + // Autobot on expedition + if (lookupItem("autumn-aton").available_amount() > 0) + { + string main_title = "Use your autumn-aton"; + description.listAppend("Next use will take " + HTMLGenerateSpanOfClass(autobotsReturnTime, "r_bold") + " adventures."); + task_entries.listAppend(ChecklistEntryMake("__item autumn-aton", "inv_use.php?pwd=" + my_hash() + "&whichitem=10954", ChecklistSubentryMake(main_title, "", description), -11)); + } + else if (turncountWhereAutobotReturns > total_turns_played()) + { + string main_title = "Autumn-aton on a mission"; + string autobotZone = get_property("autumnatonQuestLocation"); + description.listAppend("Will return in " + HTMLGenerateSpanOfClass(turncountWhereAutobotReturns +1 - total_turns_played(), "r_bold") + " adventures."); + description.listAppend(HTMLGenerateSpanOfClass("Currently exploring: ", "r_bold") + autobotZone); + optional_task_entries.listAppend(ChecklistEntryMake("__item autumn-aton", url, ChecklistSubentryMake("Autumn-aton on a mission", description), 8)); + } + else if (turncountWhereAutobotReturns <= total_turns_played()) + { + string main_title = "Autumn-aton returns next adventure"; + string autobotZone = get_property("autumnatonQuestLocation"); + description.listAppend("Next mission takes " + HTMLGenerateSpanOfClass(autobotsReturnTime, "r_bold") + " adventures."); + description.listAppend(HTMLGenerateSpanOfClass("Currently exploring: ", "r_bold") + autobotZone); + task_entries.listAppend(ChecklistEntryMake("__item autumn-aton", url, ChecklistSubentryMake(main_title, description), -11)); + } + + if (!get_property("autumnatonUpgrades").contains_text("cowcatcher")) { + description.listAppend("Visit mid underground for +1 autumn item (Cyrpt zone, Daily Dungeon?)"); + } + if (!get_property("autumnatonUpgrades").contains_text("leftarm1")) { + description.listAppend("Visit low indoor for +1 item (Haunted Pantry?)"); + } + if (!get_property("autumnatonUpgrades").contains_text("rightarm1")) { + description.listAppend("Visit mid outdoor for +1 item (Smut Orc Camp?)"); + } + if (!get_property("autumnatonUpgrades").contains_text("leftleg1")) { + description.listAppend("Visit low underground for -11 cooldown (Ratbats?)"); + } + if (!get_property("autumnatonUpgrades").contains_text("rightleg1")) { + description.listAppend("Visit mid indoor for -11 cooldown (Haunted Library?)"); + } + + if (__misc_state["in run"] && my_path().id != 25) + { + if (locationAvailable($location[sonofa beach]) == true && get_property("sidequestLighthouseCompleted") == "none" && available_amount($item[barrel of gunpowder]) < 5) + { + targets.listAppend(listMake("barrel of gunpowder", "Sonofa Beach")); + } + if (locationAvailable($location[twin peak]) == false && get_property_int("chasmBridgeProgress") < 30) + { + targets.listAppend(listMake("bridge parts", "The Smut Orc Logging Camp")); + } + if (get_property_int("hiddenBowlingAlleyProgress") + available_amount($item[bowling ball]) < 6) + { + targets.listAppend(listMake("bowling balls", "The Hidden Bowling Alley")); + } + if (get_property_int("twinPeakProgress") < 14 && available_amount($item[jar of oil]) < 1 && available_amount($item[bubblin' crude]) < 12) + { + targets.listAppend(listMake("bubblin' crude", "Oil Peak")); + } + // gnasirProgress is a weird property, please read the mafia wiki for clarification: + // https://wiki.kolmafia.us/index.php/Quest_Tracking_Preferences#gnasirProgress + if (get_property_int("desertExploration") < 100 && available_amount($item[killing jar]) < 1 && (get_property_int("gnasirProgress") & 4) == 0) + { + targets.listAppend(listMake("killing jar", "The Haunted Library")); + } + if (locationAvailable($location[the oasis]) == true && get_property_int("desertExploration") < 100) + { + targets.listAppend(listMake("drum machine", "An Oasis")); + } + if (__quest_state["Level 11 Ron"].mafia_internal_step < 5) + { + targets.listAppend(listMake("glark cables", "The Red Zeppelin")); + } + if (targets.count() > 0) + { + buffer tooltip_text; + tooltip_text.append(HTMLGenerateTagWrap("div", "Potential Targets", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); + tooltip_text.append(HTMLGenerateSimpleTableLines(targets)); + string potentialTargets = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Potential Autumnaton Targets", "r_tooltip_outer_class"); + description.listAppend(potentialTargets); + } + } +} + +RegisterTaskGenerationFunction("IOTMCookbookbatGenerateTasks"); +void IOTMCookbookbatGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!lookupFamiliar("Cookbookbat").familiar_is_usable()) return; + string url = "familiar.php"; + string [int] description; + string cbbIngredient = (get_property("_cookbookbatQuestIngredient")); + string cbbTarget = (get_property("_cookbookbatQuestMonster")); + string cbbZone = (get_property("_cookbookbatQuestLastLocation")); + int cbbResetTimer = get_property_int("_cookbookbatCombatsUntilNewQuest"); + string main_title = HTMLGenerateSpanFont("Cookbookbat hunt", "black"); + description.listAppend(HTMLGenerateSpanOfClass(cbbResetTimer, "r_bold") + " fights until new hunt"); + int cbbIngredientDrop = 11 - get_property_int("cookbookbatIngredientsCharge"); + description.listAppend(HTMLGenerateSpanOfClass(cbbIngredientDrop, "r_bold") + " wins until 3x ingredient"); + + if (cbbTarget != "" && cbbIngredient != "") { + description.listAppend("Hunt: " + HTMLGenerateSpanFont(cbbTarget, "blue")); + description.listAppend("Zone: " + HTMLGenerateSpanFont(cbbZone, "purple")); + description.listAppend("Reward: 3x " +HTMLGenerateSpanFont(cbbIngredient, "green")); + location questLocation = get_property("_cookbookbatQuestLastLocation").to_location(); + + if (my_familiar() == lookupFamiliar("cookbookbat")) { + task_entries.listAppend(ChecklistEntryMake("__familiar cookbookbat", questLocation.getClickableURLForLocation(), ChecklistSubentryMake(main_title, description), -11, boolean [location] {questLocation:true}).ChecklistEntrySetIDTag("cookbookbat hunt")); + } + else if (my_familiar() != lookupFamiliar("cookbookbat")) { + optional_task_entries.listAppend(ChecklistEntryMake("__familiar cookbookbat", questLocation.getClickableURLForLocation(), ChecklistSubentryMake(main_title, description), 10, boolean [location] {questLocation:true}).ChecklistEntrySetIDTag("cookbookbat hunt")); + } + } + if (cbbTarget == "" && cbbIngredient == "" && my_familiar() == lookupFamiliar("cookbookbat")) { + task_entries.listAppend(ChecklistEntryMake("__familiar cookbookbat", url, ChecklistSubentryMake("Cookbookbat charging", description), -11)); + } +} + +RegisterResourceGenerationFunction("IOTMCookbookbatGenerateResource"); +void IOTMCookbookbatGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("Cookbookbat").familiar_is_usable()) return; + + // Look up amount for the three constituent items for the bookbat foods + int wheys = lookupItem("10968").available_amount(); + int vegs = lookupItem("10969").available_amount(); + int yeasts = lookupItem("10967").available_amount(); + + // Do not generate a tile if you can't eat stuff or don't have any constituent items + if (!__misc_state["can eat just about anything"] && (wheys + vegs + yeasts) < 1) + return; + + string [int] description; + string url = "craft.php?mode=cook"; + + description.listAppend("Follow the old bat's wise counsel and craft legendary gluten bombs!"); + description.listAppend("You currently have "+wheys.to_string()+" whey, "+vegs.to_string()+" veg, and "+yeasts.to_string()+" yeast."); + + // How many can we make of each food item? + int borisBreadCraftable = floor(yeasts/2); + int roastedVegCraftable = floor(vegs/2); + int focacciaCraftable = roastedVegCraftable > 0 && borisBreadCraftable > 0 ? min(borisBreadCraftable, roastedVegCraftable) : 0; + + // Generating strings for the three most important food items + string borisBread = ""+borisBreadCraftable+"x Boris's Bread: +100% meat"; // yeast + yeast + string roastedVeg = ""+roastedVegCraftable+"x Roasted Vegetable of Jarlsberg: +100% item"; // veg + veg"; + string focaccia = ""+focacciaCraftable+"x Roasted Vegetable Focaccia: +10 Fam XP"; // bread + roast veg"; + + // Here, we're generating a list of what you can make with your loadout. + string [int] pizzaParlorMenu; + pizzaParlorMenu.listAppend("You can make..."); + pizzaParlorMenu.listAppend(borisBread); + pizzaParlorMenu.listAppend(roastedVeg); + pizzaParlorMenu.listAppend(focaccia); + description.listAppend(pizzaParlorMenu.listJoinComponents("|*")); + + string [int][int] pizzaParlorRecipes; + pizzaParlorRecipes.listAppend(listMake("Boris's Bread = yeast + yeast")); + pizzaParlorRecipes.listAppend(listMake("Roasted Vegetable of Jarlsberg = veg + veg")); + pizzaParlorRecipes.listAppend(listMake("Roasted Vegetable Focaccia = bread + roastveg")); + + buffer tooltip_text; + tooltip_text.append(HTMLGenerateTagWrap("div", "Cookbookbat Recipes!", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); + tooltip_text.append(HTMLGenerateSimpleTableLines(pizzaParlorRecipes)); + + description.listAppend(HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip_text, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Important Recipes", "r_tooltip_outer_class")); + + int cbbIngredientDrop = 11 - get_property_int("cookbookbatIngredientsCharge"); + int cbbResetTimer = get_property_int("_cookbookbatCombatsUntilNewQuest"); + description.listAppend(HTMLGenerateSpanOfClass(cbbIngredientDrop, "r_bold") + " wins until 3x ingredient"); + description.listAppend(HTMLGenerateSpanOfClass(cbbResetTimer, "r_bold") + " fights until new hunt"); + + int cookings_remaining = clampi(5 - get_property_int("_cookbookbatCrafting"), 0, 5); + if (cookings_remaining > 0) + { + description.listAppend(HTMLGenerateSpanOfClass(cookings_remaining, "r_bold") + " free cooks: Unstable fulminate, potions, and more."); + } + + resource_entries.listAppend(ChecklistEntryMake("__familiar cookbookbat", url, ChecklistSubentryMake("Pizza party with the Cookbookbat!", "", description)).ChecklistEntrySetIDTag("Cookbookbat Resource")); +} + +RegisterResourceGenerationFunction("IOTMOliversPlaceGenerateResource"); +void IOTMOliversPlaceGenerateResource(ChecklistEntry [int] resource_entries) +{ + // Only generate if they actually have Oliver's Place + if (!get_property_boolean("ownsSpeakeasy")) return; + + int free_oliver_fights_left = 3 - get_property_int("_speakeasyFreeFights"); + string url = "place.php?whichplace=speakeasy"; + string [int] description; + + if (free_oliver_fights_left > 0) { + description.listAppend("Consider dragging wanderers into the speakeasy."); + + resource_entries.listAppend(ChecklistEntryMake("__item Marltini", "", ChecklistSubentryMake(pluralise(free_oliver_fights_left, "Oliver's Tavern fight", "Oliver's Tavern fights"), "", description), 9).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Oliver's Tavern free fights")); + } +} +string [string, string] stationDescriptions; + +int trainSetReconfigurableIn() { + int trainPosition = get_property_int("trainsetPosition"); + int whenTrainsetWasConfigured = get_property_int("lastTrainsetConfiguration"); + if (whenTrainsetWasConfigured == trainPosition || + trainPosition - whenTrainsetWasConfigured >= 40) { + return 0; + } else { + return 40 - (trainPosition - whenTrainsetWasConfigured); + } +} + +boolean stationConfigured(string station) { + return contains_text(get_property("trainsetConfiguration"), station); +} + +boolean oreConfiguredWhenNotNeeded() { + boolean oreConfigured = stationConfigured("ore_hopper"); + string oreNeeded = get_property("trapperOre"); + boolean haveAllOreNeeded = __quest_state["Level 8"].state_boolean["Past mine"] || + (oreNeeded != "" && to_item(oreNeeded).available_amount() >= 3) || + (to_item("asbestos ore").available_amount() >= 3 && + to_item("chrome ore").available_amount() >= 3 && + to_item("linoleum ore").available_amount() >= 3); + return __misc_state["in run"] && oreConfigured && haveAllOreNeeded; +} + +boolean loggingMillConfiguredWhenNotNeeded() { + boolean loggingMillConfigured = stationConfigured("logging_mill"); + int fastenersNeeded = __quest_state["Level 9"].state_int["bridge fasteners needed"]; + int lumberNeeded = __quest_state["Level 9"].state_int["bridge lumber needed"]; + boolean haveAllPartsNeeded = __quest_state["Level 9"].mafia_internal_step > 1 || + (fastenersNeeded == 0 && lumberNeeded == 0); + return __misc_state["in run"] && loggingMillConfigured && haveAllPartsNeeded; +} + +boolean statsConfiguredWhenNotNeeded() { + boolean statsConfigured = stationConfigured("viewing_platform") || + (stationConfigured("brawn_silo") && my_primestat() == $stat[muscle]) || + (stationConfigured("brain_silo") && my_primestat() == $stat[mysticality]) || + (stationConfigured("groin_silo") && my_primestat() == $stat[moxie]); + boolean haveAllStatsNeeded = my_level() >= 13; + return __misc_state["in run"] && statsConfigured && haveAllStatsNeeded; +} + +boolean shouldNag() { + return trainSetReconfigurableIn() == 0 && + (oreConfiguredWhenNotNeeded() || + loggingMillConfiguredWhenNotNeeded() || + statsConfiguredWhenNotNeeded() || + stationConfigured("empty")); +} + +RegisterTaskGenerationFunction("IOTMModelTrainSetGenerateTasks"); +void IOTMModelTrainSetGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[lookupItem("model train set")]) return; + + string url = "campground.php?action=workshed"; + string [int] description; + string main_title = "Model train set progress"; + + int trainPosition = get_property_int("trainsetPosition"); + int whenTrainsetWasConfigured = get_property_int("lastTrainsetConfiguration"); + string[int] stations = split_string(get_property("trainsetConfiguration"), ","); + + if (count(stations) < 8) { + description.listAppend("We can't tell how your trainset is configured. Click this tile to fix."); + task_entries.listAppend(ChecklistEntryMake("__item toy crazy train", url, ChecklistSubentryMake(main_title, description), -11).ChecklistEntrySetIDTag("Model train set")); + return; + } + + if (oreConfiguredWhenNotNeeded()) { + description.listAppend(HTMLGenerateSpanFont("Have ore configured when it's not needed!", "red")); + } + if (loggingMillConfiguredWhenNotNeeded()) { + description.listAppend(HTMLGenerateSpanFont("Have lumber mill configured when it's not needed!", "red")); + } + if (statsConfiguredWhenNotNeeded()) { + description.listAppend(HTMLGenerateSpanFont("Have stats configured when they're not needed!", "red")); + } + if (stationConfigured("empty")) { + description.listAppend(HTMLGenerateSpanFont("Have an empty station configured!", "red")); + } + + int reconfigurableIn = trainSetReconfigurableIn(); + if (reconfigurableIn == 0) + { + HTMLGenerateSpanFont("Train set reconfigurable!", "blue"); + } + else { + description.listAppend("Train set reconfigurable in " + HTMLGenerateSpanOfClass(reconfigurableIn.to_string() + " combats.", "r_bold")); + } + + string[string] nextStation = stationDescriptions[stations[trainPosition % 8]]; + description.listAppend("Next station: " + HTMLGenerateSpanOfClass(nextStation["name"], "r_bold") + " - " + nextStation["description"]); + + string [int][int] tooltipTable; + for i from trainPosition to trainPosition + 7 { + string[string] station = stationDescriptions[stations[i % 8]]; + tooltipTable.listAppend(listMake(HTMLGenerateSpanOfClass(station["name"], "r_bold"), station["description"])); + } + buffer tooltipText; + tooltipText.append(HTMLGenerateTagWrap("div", "Train station cycle", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); + tooltipText.append(HTMLGenerateSimpleTableLines(tooltipTable)); + string trainCycleList = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltipText, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "Full train cycle", "r_tooltip_outer_class"); + description.listAppend(trainCycleList); + + ChecklistEntry[int] whereToAddTile = optional_task_entries; + int priority = 8; + + if (shouldNag()) { + whereToAddTile = task_entries; + priority = -11; + } + + whereToAddTile.listAppend(ChecklistEntryMake("__item toy crazy train", url, ChecklistSubentryMake(main_title, description), priority).ChecklistEntrySetIDTag("Model train set")); +} + +stationDescriptions = { + "unknown": { + "name": "Unknown", + "description": "We don't recognize that train station!", + }, + "empty": { + "name": "Empty station", + "description": HTMLGenerateSpanFont("Train set isn't fully configured!", "red"), + }, + "meat_mine": { + "name": "Meat Mine", + "description": "Bonus meat", + }, + "tower_fizzy": { + "name": "Fizzy Tower", + "description": "MP regen", + }, + "viewing_platform": { + "name": "Viewing Platform", + "description": "Gain extra stats", + }, + "tower_frozen": { + "name": "Frozen Tower", + "description": HTMLGenerateSpanFont("Hot", "red") + " res, " + HTMLGenerateSpanFont("Cold", "blue") + " dmg", + }, + "spooky_graveyard": { + "name": "Spooky Graveyard", + "description": HTMLGenerateSpanFont("Stench", "green") + " res, " + HTMLGenerateSpanFont("Spooky", "grey") + " dmg", + }, + "logging_mill": { + "name": "Logging Mill", + "description": "Bridge parts or stats", + }, + "candy_factory": { + "name": "Candy Factory", + "description": "Pick up random candy", + }, + "coal_hopper": { + "name": "Coal Hopper", + "description": "Double power of next station", + }, + "tower_sewage": { + "name": "Sewage Tower", + "description": HTMLGenerateSpanFont("Cold", "blue") + " res, " + HTMLGenerateSpanFont("Stench", "green") + " dmg", + }, + "oil_refinery": { + "name": "Oil Refinery", + "description": HTMLGenerateSpanFont("Spooky", "grey") + " res, " + HTMLGenerateSpanFont("Sleaze", "purple") + " dmg", + }, + "oil_bridge": { + "name": "Oil Bridge", + "description": HTMLGenerateSpanFont("Sleaze", "purple") + " res, " + HTMLGenerateSpanFont("Hot", "red") + " dmg", + }, + "water_bridge": { + "name": "Bridge Over Troubled Water", + "description": "Increase ML", + }, + "groin_silo": { + "name": "Groin Silo", + "description": "Gain moxie", + }, + "grain_silo": { + "name": "Grain Silo", + "description": "Get base booze", + }, + "brain_silo": { + "name": "Brain Silo", + "description": "Gain mysticality", + }, + "brawn_silo": { + "name": "Brawn Silo", + "description": "Gain muscle", + }, + "prawn_silo": { + "name": "Prawn Silo", + "description": "Acquire more food", + }, + "trackside_diner": { + "name": "Trackside Diner", + "description": "Serves the last food you found", + }, + "ore_hopper": { + "name": "Ore Hopper", + "description": "Get some ore", + } +}; + + +// 2023 +string gravelMessage(int gravels) +{ + return HTMLGenerateSpanOfClass(gravels, "r_bold") + "x groveling gravel (free kill*)"; +} + +string whetStoneMessage(int whetStones) +{ + return HTMLGenerateSpanOfClass(whetStones, "r_bold") + "x whet stone (+1 adv on food)"; +} + +string milestoneMessage(int milestones) +{ + int desertProgress = get_property_int("desertExploration"); + return HTMLGenerateSpanOfClass(milestones, "r_bold") + "x milestone (+5% desert progress), " + (100 - desertProgress) + "% remaining"; +} + +// Prompt to harvest your garden in run when useful items are growing in it +RegisterTaskGenerationFunction("IOTMRockGardenGenerateTasks"); +void IOTMRockGardenGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { + string [int] description; + string url = "campground.php"; + + int gardenGravels = __campground[$item[groveling gravel]]; + int gardenMilestones = __campground[$item[milestone]]; + int gardenWhetstones = __campground[$item[whet stone]]; + + if (!__iotms_usable[lookupItem("packet of rock seeds")] || + !__misc_state["in run"] || + my_path().id == PATH_COMMUNITY_SERVICE || + gardenGravels + gardenMilestones + gardenWhetstones == 0) + return; + + int desertProgress = get_property_int("desertExploration"); + + if (gardenGravels > 0) + { + description.listAppend(gravelMessage(gardenGravels)); + } + + if (gardenWhetstones > 0) + { + description.listAppend(whetStoneMessage(gardenWhetstones)); + } + + if (gardenMilestones > 0 && desertProgress < 100) + { + description.listAppend(milestoneMessage(gardenMilestones)); + } + + task_entries.listAppend(ChecklistEntryMake("__item rock garden guide", url, ChecklistSubentryMake("Harvest your rock garden", "", description)).ChecklistEntrySetIDTag("rock garden task")); +} + +// Prompt to use garden resources when they're helpful +RegisterResourceGenerationFunction("IOTMRockGardenGenerateResource"); +void IOTMRockGardenGenerateResource(ChecklistEntry [int] resource_entries) { + string [int] description; + string url = "campground.php"; + + if (!get_property_boolean("_molehillMountainUsed") && available_amount($item[molehill mountain]) > 0) + { + resource_entries.listAppend(ChecklistEntryMake("__item molehill mountain", url = "inventory.php?ftext=molehill+mountain", ChecklistSubentryMake("Molehill moleman", "", "Free scaling fight."), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Molehill free fight")); + } + + int availableGravels = available_amount($item[groveling gravel]); + int availableMilestones = available_amount($item[milestone]); + int availableWhetStones = available_amount($item[whet stone]); + + // Ascension stuff + if (!__misc_state["in run"] || + my_path().id == PATH_COMMUNITY_SERVICE || + availableGravels + availableMilestones + availableWhetstones == 0) + return; + + int desertProgress = get_property_int("desertExploration"); + + if (availableGravels > 0 && $item[groveling gravel].item_is_usable()) + { + description.listAppend(gravelMessage(availableGravels)); + } + + if (availableWhetStones > 0 && $item[whet stone].item_is_usable() && (__misc_state["can eat just about anything"])) + { + description.listAppend(whetStoneMessage(availableWhetStones)); + } + + if (availableMilestones > 0 && $item[milestone].item_is_usable() && desertProgress < 100) + { + description.listAppend(milestoneMessage(availableMilestones)); + } + + resource_entries.listAppend(ChecklistEntryMake("__item rock garden guide", url, ChecklistSubentryMake("Rock garden resources", "", description)).ChecklistEntrySetIDTag("rock garden resource")); +} + +boolean hasAnySkillOf(string [int] skillNames) { + foreach i in skillNames { + string skillName = skillNames[i]; + if (lookupSkill(skillName).have_skill()) { + return true; + } + } + return false; +} + +RegisterTaskGenerationFunction("IOTMSITCertificateGenerateTasks"); +void IOTMSITCertificateGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { + // Don't generate a tile if the user doesn't have SIT. + if (!lookupItem("S.I.T. Course Completion Certificate").have()) return; + + // Cannot use S.I.T. in G-Lover + if (my_path().id == PATH_G_LOVER) return; + + boolean completedSITToday = get_property_boolean("_sitCourseCompleted"); + + // Don't generate a tile if the user has completed SIT already today. + if (completedSITToday) return; + + string [int] description; + string url = "inv_use.php?pwd=" + my_hash() + "&which=3&whichitem=11116"; + string main_title = "S.I.T. Course Enrollment"; + string subtitle = ""; + + string [int] miscPhrases = { + "Don't play hooky!", + "You already paid for it.", + "This one time in college...", + "Bright college days, oh, carefree days that fly.", // <3 tom lehrer + "No child of mine is leaving here without a degree!", + "Make like a tree and leaf (through your papers).", + }; + + string [int] skillNames = {"Psychogeologist", "Insectologist", "Cryptobotanist"}; + + if (hasAnySkillOf(skillNames)) { + // If they already have a skill, generate an optional task or a less-shiny supernag + if (lookupSkill("Psychogeologist").have_skill()) subtitle = "you have ML; consider Insectology, for meat?"; + if (lookupSkill("Insectologist").have_skill()) subtitle = "you have Meat; consider Psychogeology, for ML?"; + if (lookupSkill("Cryptobotanist").have_skill()) subtitle = "you have Init; consider Insectology, for meat?"; + + if (__misc_state["in run"]) { + // If in-run, generate a supernag + description.listAppend("Try changing your S.I.T. course to accumulate different items."); + task_entries.listAppend(ChecklistEntryMake("__item S.I.T. Course Completion Certificate", url, ChecklistSubentryMake(main_title, subtitle, description), -11).ChecklistEntrySetIDTag("S.I.T. Course Completion Certificate")); + } + else { + // If not, generate an optional task + main_title = "Could change your S.I.T. skill, for new items..."; + optional_task_entries.listAppend(ChecklistEntryMake("__item S.I.T. Course Completion Certificate", url, ChecklistSubentryMake(main_title, subtitle, description), 1).ChecklistEntrySetIDTag("S.I.T. Course Completion Certificate")); + } + } + else { + // If they don't have a skill, generate a supernag. + string miscPhrase = miscPhrases[random(count(miscPhrases))]; + description.listAppend(HTMLGenerateSpanFont(miscPhrase + " Take your S.I.T. course!", "red")); + task_entries.listAppend(ChecklistEntryMake("__item S.I.T. Course Completion Certificate", url, ChecklistSubentryMake(main_title, subtitle, description), -11).ChecklistEntrySetIDTag("S.I.T. Course Completion Certificate")); + } + +} +//shadow phone +QuestState parseRufusQuestState() { + /* + Below description from Veracity's PR introducing Rufus quest tracking: + https://github.com/kolmafia/kolmafia/pull/1613 + > "unstarted" -> we have not accepted a quest + > "started" -> we have accepted a quest but not yet fulfilled the requirement + > "step1" -> we have fulfilled the requirement but not called Rufus back yet to report our success + > (Calling Rufus back and fulfilling the quest sends us back to "unstarted".) + + This works nicely with TourGuide's QuestState tracking so we can parse right out of it. + */ + QuestState state = QuestState("questRufus"); + + // Because mafia_internal_step tracking is confusing, and the quest never actually gets + // marked as finished, let's add a boolean to track whether we've done the objective + // (but not yet called Rufus back) + state.state_boolean["quest objective fulfilled"] = state.mafia_internal_step == 2; + + return state; +} + +record ShadowBrickLocation { + string zoneName; + string extraItems; + boolean canAccess; +}; + +string getShadowBrickLocationTooltip() { + ShadowBrickLocation [int] shadowBrickLocations = { + new ShadowBrickLocation( + "Cemetary", + "(also has bread, stick)", + can_adventure($location[Shadow Rift (The Misspelled Cemetary)]) + ), + new ShadowBrickLocation( + "Hidden City", + "(also has sinew, nectar)", + can_adventure($location[Shadow Rift (The Hidden City)]) + ), + new ShadowBrickLocation( + "Pyramid", + "(also has sausage, sinew)", + can_adventure($location[Shadow Rift (The Ancient Buried Pyramid)]) + ) + }; + + string [int][int] shadowBricksTable; + foreach index, brickLocation in shadowBrickLocations { + string formattedLocationName = brickLocation.canAccess ? + HTMLGenerateSpanOfClass(brickLocation.zoneName, "r_bold") : + HTMLGenerateSpanOfClass(HTMLGenerateSpanFont(brickLocation.zoneName, "gray"), "r_bold"); + shadowBricksTable.listAppend(listMake(formattedLocationName, brickLocation.extraItems)); + } + + string shadowBricksTooltip = HTMLGenerateSimpleTableLines(shadowBricksTable); + return HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(shadowBricksTooltip, "r_tooltip_inner_class") + "Shadow Brick locations", "r_tooltip_outer_class"); +} + +RegisterTaskGenerationFunction("IOTMClosedCircuitPayPhoneGenerateTasks"); +void IOTMClosedCircuitPayPhoneGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { + if (!lookupItem("closed-circuit pay phone").have()) + return; + + if (my_path().id == PATH_G_LOVER) return; // cannot use payphone in g-lover + + string url = "inv_use.php?pwd=" + my_hash() + "&which=3&whichitem=11169"; + QuestState state = parseRufusQuestState(); + + ChecklistEntry [int] whereToAddRufusQuestTile; + string rufusImage = "__item closed-circuit pay phone"; + string rufusQuestTitle; + string rufusQuestTarget = get_property("rufusQuestTarget"); + string [int] rufusQuestDescription; + int rufusQuestPriority; + int shadowRiftFightsDoableRightNow = $effect[Shadow Affinity].have_effect(); + + int shadowLodestones = available_amount($item[Rufus's shadow lodestone]); + if (shadowLodestones > 0) { + rufusQuestDescription.listAppend(HTMLGenerateSpanFont("Have " + pluralise($item[Rufus's shadow lodestone]) + ".", "purple")); + } + + int riftAdvsUntilNC = get_property_int("encountersUntilSRChoice"); + if (shadowRiftFightsDoableRightNow > 0) { + rufusQuestDescription.listAppend(HTMLGenerateSpanFont("" + shadowRiftFightsDoableRightNow + " Shadow Rift free fights", "purple")); + } + rufusQuestDescription.listAppend(HTMLGenerateSpanFont(riftAdvsUntilNC + " encounters until NC/boss.", "black")); + + if (state.state_boolean["quest objective fulfilled"]) { + // We've fulfilled the quest objective but still need to call Rufus + rufusQuestDescription.listAppend(HTMLGenerateSpanFont("Call Rufus and get a lodestone", "black")); + rufusQuestTitle = "Rufus quest done"; + rufusQuestPriority = -11; + whereToAddRufusQuestTile = task_entries; + } + else if (state.started && riftAdvsUntilNC == 0) { + rufusQuestDescription.listAppend("Looking for " + HTMLGenerateSpanFont(rufusQuestTarget, "blue")); + rufusQuestTitle = "Shadow Rift NC up next"; + rufusQuestPriority = -11; + rufusImage = "__item shadow bucket"; + whereToAddRufusQuestTile = task_entries; + } + else if (state.started) { + rufusQuestTitle = "Rufus quest in progress"; + rufusQuestPriority = 999; + whereToAddRufusQuestTile = optional_task_entries; + } + else if (!state.started) { + boolean calledRufusToday = get_property_boolean("_shadowAffinityToday"); + string textColor = calledRufusToday ? "black" : "blue"; + string callRufusMessage = calledRufusToday ? "Optionally call Rufus again for another (turn-taking) quest." : "Haven't called Rufus yet today."; + rufusQuestDescription.listAppend(HTMLGenerateSpanFont(callRufusMessage, textColor)); + rufusQuestTitle = "Rufus quest doable now"; + rufusQuestPriority = 999; + whereToAddRufusQuestTile = optional_task_entries; + } + + rufusQuestDescription.listAppend(getShadowBrickLocationTooltip()); + + whereToAddRufusQuestTile.listAppend(ChecklistEntryMake(rufusImage, url, ChecklistSubentryMake(rufusQuestTitle, "", rufusQuestDescription), rufusQuestPriority)); + + if ($effect[Shadow Affinity].have_effect() > 0 && riftAdvsUntilNC != 0 && !state.state_boolean["quest objective fulfilled"]) { + int riftAdvsUntilNC = get_property_int("encountersUntilSRChoice"); + string [int] affinityDescription; + if (shadowLodestones > 0) { + affinityDescription.listAppend(HTMLGenerateSpanFont("Have " + pluralise($item[Rufus's shadow lodestone]) + ".", "purple")); + } + affinityDescription.listAppend(HTMLGenerateSpanFont("Shadow Rift fights are free!", "purple")); + affinityDescription.listAppend(HTMLGenerateSpanFont(riftAdvsUntilNC + " encounters until NC/boss.", "black")); + affinityDescription.listAppend(HTMLGenerateSpanFont("(don't use other free kills in there)", "black")); + task_entries.listAppend(ChecklistEntryMake("__effect Shadow Affinity", url, ChecklistSubentryMake(shadowRiftFightsDoableRightNow + " Shadow Rift free fights", "", affinityDescription), -11)); + } +} + +void showShadowBrickFreeKills(ChecklistEntry [int] resource_entries) { + int shadowBricks = available_amount($item[shadow brick]); + int shadowBrickUsesLeft = clampi(13 - get_property_int("_shadowBricksUsed"), 0, 13); + if ($item[shadow brick].available_amount() > 0) { + string header = $item[shadow brick].pluralise().capitaliseFirstLetter(); + if (shadowBrickUsesLeft < shadowBricks) { + if (shadowBrickUsesLeft == 0) + header += " (not usable today)"; + else + header += " (" + shadowBrickUsesLeft + " usable today)"; + } + resource_entries.listAppend(ChecklistEntryMake("__item shadow brick", "", ChecklistSubentryMake(header, "", "Win a fight without taking a turn.")).ChecklistEntrySetCombinationTag("free instakill")); + } +} + +RegisterResourceGenerationFunction("IOTMClosedCircuitPayPhoneGenerateResource"); +void IOTMClosedCircuitPayPhoneGenerateResource(ChecklistEntry [int] resource_entries) { + // Shadow bricks don't depend on having the IOTM + showShadowBrickFreeKills(resource_entries); + + if (!lookupItem("closed-circuit pay phone").have()) + return; + + if (my_path().id == PATH_G_LOVER) return; // cannot use payphone in g-lover + + string url = "inv_use.php?pwd=" + my_hash() + "&which=3&whichitem=11169"; + + int shadowLodestones = available_amount($item[Rufus's shadow lodestone]); + + if (shadowLodestones > 0) { + string [int] lodestoneDescription; + lodestoneDescription.listAppend("30 advs of +100% init, +100% item, +200% meat, -10% combat."); + lodestoneDescription.listAppend("Triggers on next visit to any Shadow Rift."); + resource_entries.listAppend(ChecklistEntryMake("__item Rufus's shadow lodestone", url, ChecklistSubentryMake(shadowLodestones + " Rufus's shadow lodestones", lodestoneDescription), 5)); + } + + if (!get_property_boolean("_shadowAffinityToday")) { + string [int] affinityDescription; + affinityDescription.listAppend("Call Rufus to get 11+ free Shadow Rift combats."); + resource_entries.listAppend(ChecklistEntryMake("__effect Shadow Affinity", url, ChecklistSubentryMake("Shadow Affinity free fights", "", affinityDescription), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Shadow affinity free fights")); + } +} + +record MonkeyWish { + // If the wish is an item, set that here. Otherwise, use $item[none]. + item theItem; + + // If the wish is an effect, set that here. Otherwise, use $effect[none]. + effect theEffect; + + // If you want additional description text other than the item/effect name, + // set that here. + string additionalDescription; + + // A boolean value indicating whether the wish is useful at all. + boolean shouldDisplay; + + // A boolean value indicating whether the wish is currently accessible + // (since the paw will prevent wishes you can't access). + boolean currentlyAccessible; +}; + +string showWish(MonkeyWish wish) { + string color = wish.currentlyAccessible ? "black" : "gray"; + string wishStr; + string additionalDescription = wish.additionalDescription != "" ? + `: {wish.additionalDescription}` : + ""; + if (wish.theItem != $item[none]) { + wishStr = `{wish.theItem.name}{additionalDescription}`; + } else if (wish.theEffect != $effect[none]) { + wishStr = `{wish.theEffect.name}{additionalDescription}`; + } else { + wishStr = "Unknown item/effect. Report to TourGuide devs >:("; + } + return HTMLGenerateSpanFont(wishStr, color); +} + +string [int] showWishes(MonkeyWish [int] wishes) { + string [int] currentWishes = {}; + string [int] futureWishes = {}; + // My kingdom for polymorphic filter :| + foreach index, wish in wishes { + if (!wish.shouldDisplay) continue; + + if (wish.currentlyAccessible) { + currentWishes.listAppend(showWish(wish)); + } else { + futureWishes.listAppend(showWish(wish)); + } + } + string [int] allWishes = {}; + allWishes.listAppendList(currentWishes); + allWishes.listAppendList(futureWishes); + return allWishes; +} + +record MonkeySkill { + int fingerCount; + skill theSkill; + string description; +}; + +RegisterResourceGenerationFunction("IOTMCursedMonkeysPawGenerateResource"); +void IOTMCursedMonkeysPawGenerateResource(ChecklistEntry [int] resource_entries) { + if (!lookupItem("cursed monkey's paw").have()) return; + + string url; + string [int] description; + url = "main.php?action=cmonk&pwd=" + my_hash() + ""; + description.listAppend("Return to monke. Wish for items or effects:"); + + MonkeyWish [int] inRunWishes = { + new MonkeyWish( + $item[sonar-in-a-biscuit], + $effect[none], + "", + get_property("questL04Bat") != "finished" && + !locationAvailable($location[The Boss Bat's Lair]), + locationAvailable($location[Guano Junction]) + ), + new MonkeyWish( + $item[enchanted bean], + $effect[none], + "", + !__quest_state["Level 10"].state_boolean["beanstalk grown"] && + available_amount($item[enchanted bean]) < 1, + locationAvailable($location[The Beanbat Chamber]) + ), + new MonkeyWish( + $item[none], + $effect[Knob Goblin Perfume], + "", + !__quest_state["Level 5"].finished && + available_amount($item[Knob Goblin perfume]) < 1, + true + ), + new MonkeyWish( + $item[Knob Goblin harem veil], + $effect[none], + "", + !__quest_state["Level 5"].finished && + available_amount($item[Knob Goblin harem veil]) < 1, + locationAvailable($location[Cobb's Knob Harem]) + ), + new MonkeyWish( + $item[Knob Goblin harem pants], + $effect[none], + "", + !__quest_state["Level 5"].finished && + available_amount($item[Knob Goblin harem pants]) < 1, + locationAvailable($location[Cobb's Knob Harem]) + ), + new MonkeyWish( + $item[stone wool], + $effect[none], + "", + !locationAvailable($location[The Hidden Park]) && + available_amount($item[stone wool]) < 2, + locationAvailable($location[The Hidden Temple]) + ), + new MonkeyWish( + $item[amulet of extreme plot significance], + $effect[none], + "", + !locationAvailable($location[The Castle In The Clouds In The Sky (Ground Floor)]) && + available_amount($item[amulet of extreme plot significance]) < 1, + locationAvailable($location[The Penultimate Fantasy Airship]) + ), + new MonkeyWish( + $item[mohawk wig], + $effect[none], + "", + !__quest_state["Level 10"].finished && + available_amount($item[mohawk wig]) < 1, + locationAvailable($location[The Penultimate Fantasy Airship]) + ), + new MonkeyWish( + $item[book of matches], + $effect[none], + "", + my_ascensions() != get_property_int("hiddenTavernUnlock") && + $item[book of matches].available_amount() < 1, + locationAvailable($location[The Hidden Park]) + ), + new MonkeyWish( + $item[rusty hedge trimmers], + $effect[none], + "", + get_property_int("twinPeakProgress") < 13, + locationAvailable($location[Twin Peak]) + ), + new MonkeyWish( + $item[killing jar], + $effect[none], + "", + !__quest_state["Level 11 Desert"].state_boolean["Killing Jar Given"] && + get_property_int("desertExploration") < 100 && + available_amount($item[killing jar]) < 1, + locationAvailable($location[The Haunted Library]) + ), + new MonkeyWish( + $item[none], + $effect[Dirty Pear], + HTMLGenerateSpanFont("double sleaze damage", "purple"), + get_property_int("zeppelinProtestors") < 80, + true + ), + new MonkeyWish( + $item[none], + $effect[Painted-On Bikini], + HTMLGenerateSpanFont("+100 sleaze damage", "purple"), + get_property_int("zeppelinProtestors") < 80, + true + ), + new MonkeyWish( + $item[glark cable], + $effect[none], + "", + __quest_state["Level 11 Ron"].mafia_internal_step < 5, + locationAvailable($location[The Red Zeppelin]) + ), + new MonkeyWish( + $item[short writ of habeas corpus], + $effect[none], + "", + !__quest_state["Level 11 Hidden City"].finished, + locationAvailable($location[The Hidden Park]) + ), + new MonkeyWish( + $item[lion oil], + $effect[none], + "", + $item[mega gem].available_amount() < 1 && + $item[lion oil].available_amount() < 1, + locationAvailable($location[Whitey's Grove]) + ), + new MonkeyWish( + $item[bird rib], + $effect[none], + "", + $item[mega gem].available_amount() < 1 && + $item[bird rib].available_amount() < 1, + locationAvailable($location[Whitey's Grove]) + ), + new MonkeyWish( + $item[drum machine], + $effect[none], + "", + get_property_int("desertExploration") < 100 && + $item[drum machine].available_amount() < 1, + locationAvailable($location[The Oasis]) + ), + new MonkeyWish( + $item[shadow brick], + $effect[none], + "", + get_property_int("_shadowBricksUsed") + available_amount($item[shadow brick]) < 13, + true + ), + new MonkeyWish( + $item[green smoke bomb], + $effect[none], + "", + !__quest_state["Level 12"].finished && + __quest_state["Level 12"].state_string["Side seemingly fighting for"] != "hippy", + __quest_state["Level 12"].state_boolean["War in progress"] && + get_property_int("hippiesDefeated") >= 400 + ), + new MonkeyWish( + $item[star chart], + $effect[none], + "", + !__quest_state["Level 13"].state_boolean["Richard's star key used"] && + $item[Richard's star key].available_amount() < 1 && + $item[star chart].available_amount() < 1, + locationAvailable($location[The Hole In The Sky]) + ), + new MonkeyWish( + $item[none], + $effect[Frosty], + "init/item/meat", + !__quest_state["Level 13"].state_boolean["digital key used"] && + $item[digital key].available_amount() < 1 && + get_property("8BitScore") < 10000, + true + ), + new MonkeyWish( + $item[none], + $effect[Staying Frosty], + HTMLGenerateSpanFont("cold damage race", "blue"), + !__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && + __quest_state["Level 13"].state_string["Elemental damage race type"] == "cold", + true + ), + new MonkeyWish( + $item[none], + $effect[Dragged Through the Coals], + HTMLGenerateSpanFont("hot damage race", "red"), + !__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && + __quest_state["Level 13"].state_string["Elemental damage race type"] == "hot", + true + ), + new MonkeyWish( + $item[none], + $effect[Bored Stiff], + HTMLGenerateSpanFont("spooky damage race", "gray"), + !__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && + __quest_state["Level 13"].state_string["Elemental damage race type"] == "spooky", + true + ), + new MonkeyWish( + $item[none], + $effect[Sewer-Drenched], + HTMLGenerateSpanFont("stench damage race", "green"), + !__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && + __quest_state["Level 13"].state_string["Elemental damage race type"] == "stench", + true + ), + new MonkeyWish( + $item[none], + $effect[Fifty Ways to Bereave Your Lover], + HTMLGenerateSpanFont("sleaze damage race", "purple"), + !__quest_state["Level 13"].state_boolean["Elemental damage race completed"] && + __quest_state["Level 13"].state_string["Elemental damage race type"] == "sleaze" && + get_property_int("zeppelinProtestors") > 79, + true + ), + new MonkeyWish( + $item[lowercase N], + $effect[none], + "summon the nagamar", + !__quest_state["Level 13"].state_boolean["king waiting to be freed"] && + // This accounts for being on a path that needs the wand as well + // as whether you already have one. See State.ash + __misc_state["wand of nagamar needed"] && + $item[lowercase N].available_amount() < 1 && + $item[ruby W].available_amount() > 0 && + $item[metallic A].available_amount() > 0 && + $item[heavy D].available_amount() > 0, + locationAvailable($location[The Valley of Rof L'm Fao]) + ) + }; + + MonkeyWish [int] aftercoreWishes = { + new MonkeyWish( + $item[bag of foreign bribes], + $effect[none], + "", + locationAvailable($location[The Ice Hotel]), + true + ) + }; + + int monkeyWishesLeft = clampi(5 - get_property_int("_monkeyPawWishesUsed"), 0, 5); + string [int] options; + if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) { + options.listAppendList(showWishes(inRunWishes)); + } + if (!__misc_state["in run"]) { + options.listAppendList(showWishes(aftercoreWishes)); + if (count(options) == 0) { + options.listAppend("The poors will have to settle for wishing effects."); + } + } + + if (count(options) > 0) { + description.listAppend("Possible wishes:" + options.listJoinComponents("
").HTMLGenerateIndentedText()); + } + + MonkeySkill [int] monkeySkills = { + new MonkeySkill(5, $skill[Monkey Slap], "killbanish"), + new MonkeySkill(4, $skill[Monkey Tickle], "delevel"), + new MonkeySkill(3, $skill[Evil Monkey Eye], "spooky delevel"), + new MonkeySkill(2, $skill[Monkey Peace Sign], "heal"), + new MonkeySkill(1, $skill[Monkey Point], "Olfaction-lite") + // No need for 0 (physical damage), tile is invisible anyway + }; + + string imageName; + foreach index, monkeySkill in monkeySkills { + description.listAppend(HTMLGenerateSpanOfClass(pluralise(monkeySkill.fingerCount, "finger", "fingers") + ": ", "r_bold") + monkeySkill.description); + if (monkeySkill.fingerCount == monkeyWishesLeft) { + imageName = `__skill {monkeySkill.theSkill.name}`; + } + } + + if (monkeyWishesLeft > 0) { + resource_entries.listAppend(ChecklistEntryMake(imageName, url, ChecklistSubentryMake(pluralise(monkeyWishesLeft, "monkey's paw wish", `monkey's paw wishes`), "", description)).ChecklistEntrySetIDTag("Monkey wishes")); + } + + // Banish combination tag for the monkey slap, if you've got it. + if (monkeyWishesLeft == 5) { + string [int] description; + string url; + url = "main.php"; + description.listAppend("Turn-taking repeat-use banish. Lasts until you use it again!"); + if ($item[cursed monkey's paw].equipped_amount() == 0) { + description.listAppend("Equip your cursed monkey paw first."); + url = "inventory.php?ftext=cursed+monkey"; + } + resource_entries.listAppend(ChecklistEntryMake("__skill monkey slap", "", ChecklistSubentryMake("Monkey Slap usable", "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Cursed monkey paw banish")); + } +} + +RegisterResourceGenerationFunction("IOTMCinchoDeMayoGenerateResource"); +void IOTMCinchoDeMayoGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[Cincho de Mayo]]) return; + + // _cinchUsed is a weird preference that actually means distance from 100% you are at in your current cinch. + int freeRests = __misc_state_int["total free rests possible"]; + int freeRestsRemaining = __misc_state_int["free rests remaining"]; + int cinchoRests = get_property_int('_cinchoRests'); + int cinchUsed = get_property_int('_cinchUsed'); + + // Resting when Cincho is full might burn some of the Cincho rests + freeRests = min(freeRests, cinchoRests + freeRestsRemaining); + + // Since the pref is weird, this tells you your current total cinch + int currentCinch = 100 - cinchUsed; + + // Calculating total available cinch requires storing the degradation of rest value + int [int] cinchLevels = listMake(30,30,30,30,30,25,20,15,10,5); + + // Reiterating current state so the while loop can update it + int totalCinch = 100 - cinchUsed; + int rest = cinchoRests; + + // This while loop expands your possible cinch starting at rests you haven't used. + while (rest < freeRests) + { + int cinchAmount = rest >= count(cinchLevels) ? 5 : cinchLevels[rest]; + totalCinch += cinchAmount; + rest += 1; + } + + // This gives you your possible uses of the most powerful skill, Fiesta Exits + int possibleFiestaExits = floor(totalCinch/60); + + // return if there is no cinch remaining for the homeboys + if (totalCinch == 0) return; + + string [int] description; + string [int] cinchUses; + + // If not equipped, link to the inventory. + string url = "inventory.php?ftext=cincho"; + + // If equipped, link to skills. + if ($item[Cincho de Mayo].equipped_amount() == 1) { + url = 'skills.php'; + + // ... unless you have <60 cinch lol + if (totalCinch < 60) { + url = 'campground.php'; + } + } + + // For each use, check that there's enough cinch remaining to use it before appending. + if (totalCinch > 25) { + cinchUses.listAppend("Dispense Salt & Lime (25%): Add stats to your next drink."); + cinchUses.listAppend("Party Soundtrack (25%): 30 advs of +5 fam weight."); + } + + if (totalCinch > 5) { + cinchUses.listAppend("Confetti Extravaganza (5%): 2x stats, in-combat"); + cinchUses.listAppend("Projectile Piñata (5%): 50 damage, complex candy, in-combat"); + cinchUses.listAppend("Party Foul (5%): 100"+HTMLGenerateSpanOfClass(" sleaze ", "r_element_sleaze")+"damage, stun, in-combat"); + } + + // This should always be true because there's no way to have <5 cinch and not hit the return on line 33. + // Still including it as a conditional for the tile build as a failsafe I guess. + if (cinchUses.count() > 0) + description.listAppend("Use your Cincho de Mayo to cast skills in exchange for cinch; when you're out of cinch, take a free rest!?"); + + // Doing this one outside of the large list append, because it's more important. + if (totalCinch > 60) { + description.listAppend(""+HTMLGenerateSpanOfClass("Fiesta Exit (60%)", "r_element_sleaze")+": Force a NC on your next adventure. "+`You have {possibleFiestaExits} more possible, with {totalCinch % 60}% cinch leftover`); + } + + // Merge the list components together. + description.listAppend("|*"+ cinchUses.listJoinComponents("
|*")); + + description.listAppend(`You have {totalCinch}% more cinch available, accounting for your {pluralise(freeRestsRemaining,"remaining free rest","remaining free rests")}.`); + + if (lookupItem("June cleaver").have() && !lookupItem("mother's necklace").have()) { + description.listAppend("You do "+HTMLGenerateSpanOfClass("not", "r_element_hot")+" have a mother's necklace yet, so you're missing 5 free rests. Be careful of overusing the combat skills!"); + } + + resource_entries.listAppend(ChecklistEntryMake("__item cincho de mayo", url, ChecklistSubentryMake(`{currentCinch}% belt cinch`, "", description), 3).ChecklistEntrySetIDTag("Cincho de Mayo resource")); +} + +//2002 Mr. Store +RegisterTaskGenerationFunction("IOTM2002MrStoreGenerateTasks"); +void IOTM2002MrStoreGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + { int nextVHSTurn = get_property_int("spookyVHSTapeMonsterTurn") + 8; + int nextVHSTimer = (nextVHSTurn - total_turns_played()); + + string image_name = get_property("spookyVHSTapeMonster"); + string [int] description; + string [int] warnings; + + // Adding a few warnings for the sake of it + boolean [string] holidayTracker = getHolidaysToday(); + + if (holidayTracker["El Dia de Los Muertos Borrachos"] == true || holidayTracker["Feast of Boris"] == true) { + warnings[1] = 'Be careful -- Borrachos & Feast of Boris wanderers can show up instead of your VHS wanderer!'; + } + + if (get_property_int("breathitinCharges") > 0) { + warnings[2] = 'Breathitin is active; avoid putting your VHS wanderer outdoors, the wanderer is already free!'; + } + + if (nextVHSTurn <= total_turns_played() && (image_name != "")) + { + description.listAppend(HTMLGenerateSpanFont("Free fight + YR!", "black")); + + // Only show warnings if it's right about to happen + foreach i, warning in warnings { + description.listAppend(HTMLGenerateSpanFont("|* ➾ "+warning, "red")); + } + task_entries.listAppend(ChecklistEntryMake("__monster " + image_name, "", ChecklistSubentryMake("Spooky VHS: " + get_property("spookyVHSTapeMonster") + HTMLGenerateSpanFont(" now", "red"), "", description), -11)); + } + else if (nextVHSTurn -1 == total_turns_played() && (image_name != "")) + { + description.listAppend(HTMLGenerateSpanFont("Free fight + YR next turn!", "black")); + task_entries.listAppend(ChecklistEntryMake("__monster " + image_name, "", ChecklistSubentryMake("Spooky VHS: " + get_property("spookyVHSTapeMonster") + HTMLGenerateSpanFont(" in 1 more adv", "blue"), "", description), -11)); + } + else if (image_name != "") + { + description.listAppend(nextVHSTimer + " adventures until your free fight YR VHS fight."); + optional_task_entries.listAppend(ChecklistEntryMake("__monster " + image_name, "", ChecklistSubentryMake("Spooky VHS: " + get_property("spookyVHSTapeMonster") + "", "", description), 10)); + } + } +} + +RegisterResourceGenerationFunction("IOTM2002MrStoreGenerateResource"); +void IOTM2002MrStoreGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[2002 Mr. Store Catalog]]) return; + + int Mr2002Credits = get_property_int("availableMrStore2002Credits"); + + string main_title = (Mr2002Credits + " 2002 Mr. Store credits"); + string [int] description; + + // Use the right item ID depending on if you are using a replica or a non-replica + string active2002ID = lookupItem("Replica 2002 Mr. Store Catalog").available_amount() > 0 ? "11280" : "11257"; + + string url = "inv_use.php?pwd=" + my_hash() + "&which=3&whichitem="+active2002ID; + + if (Mr2002Credits > 0) { + description.listAppend("Spend credits on prehistoric IotMs!"); + + string [int] options; + if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) + { + if ($item[Flash Liquidizer Ultra Dousing Accessory].available_amount() == 0) + { + options.listAppend(HTMLGenerateSpanOfClass("Flash Liquidizer Ultra Dousing Accessory:", "r_bold") + " +3 BLARTpockets"); + } + if ($item[pro skateboard].available_amount() == 0) + { + options.listAppend(HTMLGenerateSpanOfClass("Pro skateboard:", "r_bold") + " +1 duplicate"); + } + if ($item[letter from carrie bradshaw].available_amount() == 0 && $item[red-soled high heels].available_amount() == 0) + { + options.listAppend(HTMLGenerateSpanOfClass("Letter from Carrie Bradshaw:", "r_bold") + " +50% booze drop accessory"); + } + if ($item[Loathing Idol Microphone].available_amount() < 69420) + { + options.listAppend(HTMLGenerateSpanOfClass("Loathing Idol Microphone:", "r_bold") + " +100% init, +50% items, +5% combat; 4 uses"); + } + if ($item[Spooky VHS Tape].available_amount() < 69420) + { + options.listAppend(HTMLGenerateSpanOfClass("Spooky VHS Tape:", "r_bold") + " wandering freekill YR of the monster you used it on; try GROPs!"); + } + } + if (options.count() > 0) + description.listAppend("Possible purchases:|*" + options.listJoinComponents("|*")); + } + int availableVHSes = available_amount($item[Spooky VHS Tape]); + + // List out the mics from least to most charged + item [int] listOfMics = listMake($item[Loathing Idol Microphone (25% charged)],$item[Loathing Idol Microphone (50% charged)],$item[Loathing Idol Microphone (75% charged)],$item[Loathing Idol Microphone]); + int totalIdolCharge; + + foreach i, micItem in listOfMics { + // Add # of charge based on index of the above list to the total charge. + totalIdolCharge += i*available_amount(micItem); + } + + boolean McTwistUsed = get_property_boolean("_epicMcTwistUsed"); + int FLUDAdousesLeft = clampi(3 - get_property_int("_douseFoeUses"), 0, 3); + + // Ascension stuff + if (!__misc_state["in run"] || + my_path().id == PATH_COMMUNITY_SERVICE || + availableVHSes + totalIdolCharge + FLUDAdousesLeft == 0) + return; + + // Generate useful VHS copy list + string [int] optionsVHS; + + if (__quest_state["Level 12"].state_int["hippies left on battlefield"] > 5) optionsVHS.listAppend("War monsters; especially GROPs"); + if (!__quest_state["Level 7"].state_boolean["cranny finished"]) optionsVHS.listAppend("Giant swarm of ghuol whelps"); + if (!__quest_state["Level 8"].state_boolean["Mountain climbed"]) optionsVHS.listAppend("Ninja snowman assassin"); + if ($item[amulet of extreme plot significance].available_amount() == 0) optionsVHS.listAppend("Quiet Healer"); + if ($item[mohawk wig].available_amount() == 0) optionsVHS.listAppend("Burly Sidekick"); + + if (availableVHSes > 0 && $item[Spooky VHS Tape].item_is_usable()) + { + string VHSDescription = "Have " + availableVHSes + " VHS tapes."; + if (optionsVHS.count() > 0) { + VHSDescription += " Use to free-copy into delay & guarantee drops from:|*"+optionsVHS.listJoinComponents("|*"); + } + description.listAppend(VHSDescription); + } + if (totalIdolCharge > 0) + { + description.listAppend("Have " + totalIdolCharge + " Loathing Idol microphone uses. (50% item, 5% com, or 100% init.)"); + } + + string [int] optionsMcTwist; + + if ($item[goat cheese].available_amount() < 2 && !__quest_state["Level 8"].state_boolean["Past mine"]) + optionsMcTwist.listAppend(HTMLGenerateFutureTextByLocationAvailability("a dairy goat", $location[the goatlet])); + if (__quest_state["Level 9"].state_int["twin peak progress"] < 15) + optionsMcTwist.listAppend(HTMLGenerateFutureTextByLocationAvailability("a hedge trimmer monster", $location[Twin Peak])); + if (!__quest_state["Level 7"].state_boolean["nook finished"]) + optionsMcTwist.listAppend(HTMLGenerateFutureTextByLocationAvailability("an evil eye monster", $location[the defiled nook])); + if (__quest_state["Level 12"].state_int["hippies left on battlefield"] > 5) + optionsMcTwist.listAppend(HTMLGenerateFutureTextByLocationAvailability("a green ops soldier", $location[the battlefield (frat uniform)])); + + if (available_amount($item[pro skateboard]) > 0 && McTwistUsed == False) { + string mcTwistDescription = "Can Epic McTwist to double drops!"; + if (optionsMcTwist.count() > 0) { + mcTwistDescription += " Consider using on: "+optionsMcTwist.listJoinComponents(", ", "or ") + "."; + } + + description.listAppend(mcTwistDescription); + } + string [int] optionsFLUDA; + + if ($item[goat cheese].available_amount() < 2 && !__quest_state["Level 8"].state_boolean["Past mine"]) + optionsFLUDA.listAppend(HTMLGenerateFutureTextByLocationAvailability("goat cheese", $location[the goatlet])); + if (!__quest_state["Level 12"].state_boolean["Orchard Finished"] && my_path().id != PATH_2CRS) + optionsFLUDA.listAppend(HTMLGenerateFutureTextByLocationAvailability("filthworm sweat glands", $location[the battlefield (frat uniform)])); + + + if (available_amount($item[Flash Liquidizer Ultra Dousing Accessory]) > 0 && FLUDAdousesLeft > 0) { + string fludaDescription = "Can waterpocket " + FLUDAdousesLeft + " more foes with FLUDA."; + if (optionsFLUDA.count() > 0) { + fludaDescription += " Try stealing some "+optionsFLUDA.listJoinComponents(", ", "or ")+"."; + } + description.listAppend(fludaDescription); + } + + resource_entries.listAppend(ChecklistEntryMake("__item mr. accessaturday", url, ChecklistSubentryMake(main_title, description), 8)); +} + +//Patriotic Eagle +RegisterTaskGenerationFunction("IOTMPatrioticEagleGenerateTasks"); +void IOTMPatrioticEagleGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!lookupFamiliar("Patriotic Eagle").familiar_is_usable()) return; + + monster RWB_monster = get_property_monster("rwbMonster"); + + if (RWB_monster != $monster[none]) { + int fights_left = clampi(get_property_int("rwbMonsterCount"), 0, 2); + + // Use ezan's weird location-finding-thing + location [int] possible_appearance_locations = RWB_monster.getPossibleLocationsMonsterCanAppearInNaturally().listInvert(); + + // Make the entry a bit more explicitly for readability + ChecklistEntry entry; + + entry.url = possible_appearance_locations[0].getClickableURLForLocation(); + entry.image_lookup_name = "__monster " + RWB_monster; + entry.tags.id = "RWB monster copies"; + entry.importance_level = -1; + + string [int] description; + + description.listAppend("Copied by your eagle's blast. Will appear when you adventure in " + possible_appearance_locations.listJoinComponents(", ", "or") + "."); + + phylum eaglePhylumBanished = $phylum[none]; + + if (get_property("banishedPhyla") != "") + eaglePhylumBanished = get_property("banishedPhyla").split_string(":")[1].to_phylum(); + + if (RWB_monster.phylum == eaglePhylumBanished) { + description.listAppend(HTMLGenerateSpanFont("WARNING! This monster will not appear, it's banished by your eagle screech!", "red")); + } + + entry.subentries.listAppend(ChecklistSubentryMake("Fight " + pluralise(fights_left, "more " + RWB_monster, "more " + RWB_monster + "s"), "", description)); + + if (fights_left > 0 && possible_appearance_locations.count() > 0) + optional_task_entries.listAppend(entry); + } + + // Extra nag from TES re: setting your global pledge. + string [int] description2; + + if (__misc_state["in run"] && ($effect[Citizen of a Zone].have_effect() == 0)) { + description2.listAppend("Haunted Kitchen: +100% init"); + description2.listAppend("Haunted Library/Laundry: +30% item"); + description2.listAppend("Batrat/Ninja Snowmen/Frat Battlefield: +50% meat"); + task_entries.listAppend(ChecklistEntryMake("__familiar Patriotic Eagle", "familiar.php", ChecklistSubentryMake("Pledge to a zone!", description2), -5).ChecklistEntrySetIDTag("Patriotic Eagle familiar pledge reminder")); + } + +} + +RegisterResourceGenerationFunction("IOTMPatrioticEagleGenerateResource"); +void IOTMPatrioticEagleGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("Patriotic Eagle").familiar_is_usable()) return; + + phylum eaglePhylumBanished = $phylum[none]; + + if (get_property("banishedPhyla") != "") + eaglePhylumBanished = get_property("banishedPhyla").split_string(":")[1].to_phylum(); + + int screechRecharge = get_property_int("screechCombats"); + + string title; + string [int] description; + + if (screechRecharge > 0) { + title = (screechRecharge + " combats (or freeruns) until your Patriotic Eagle can screech again."); + } else { + title = "Patriotic Eagle can screech and banish an entire phylum!"; + description.listAppend(HTMLGenerateSpanFont("SCREEEE", "red") + HTMLGenerateSpanFont("EEEEE", "grey") + HTMLGenerateSpanFont("EEEEE!,", "blue")); + } + + // Color the pledge zones by zone availability + string [int] itemPledges; + itemPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Library", $location[the haunted library])); + itemPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Laundry Room", $location[the haunted laundry room])); + itemPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Whitey's Grove", $location[Whitey's Grove])); + + string [int] meatPledges; + meatPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Ninja Snowmen Lair", $location[Lair of the Ninja Snowmen])); + meatPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Hidden Hospital", $location[The Hidden Hospital])); + meatPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Bathroom", $location[The Haunted Bathroom])); + meatPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("the Oasis", $location[the oasis])); + + string [int] initPledges; + initPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Kitchen", $location[the haunted kitchen])); + initPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Oil Peak", $location[oil peak])); + initPledges.listAppend(HTMLGenerateFutureTextByLocationAvailability("Oliver's Tavern", $location[an unusually quiet barroom brawl])); + + if ($effect[Citizen of A Zone].have_effect() == 0) { + description.listAppend(HTMLGenerateSpanFont("Pledge ", "red") + HTMLGenerateSpanFont("allegiance ", "grey") + HTMLGenerateSpanFont("to a zone!", "blue")); + if (itemPledges.count() > 0) description.listAppend("|*"+HTMLGenerateSpanOfClass("+30% item: ", "r_bold") + itemPledges.listJoinComponents(", ", "or ") + "."); + if (meatPledges.count() > 0) description.listAppend("|*"+HTMLGenerateSpanOfClass("+50% meat: ", "r_bold") + meatPledges.listJoinComponents(", ", "or ") + "."); + if (initPledges.count() > 0) description.listAppend("|*"+HTMLGenerateSpanOfClass("+100% init: ", "r_bold") + initPledges.listJoinComponents(", ", "or ") + "."); + } + + // Making option frames for the phylums you want to banish, with if statements that should remove them + // when you have completed the task. Additionally, the location availability should ensure these show + // in gray if you cannot access the zone. + + string [int] dudeOptions; + if ( __quest_state["Level 11"].mafia_internal_step < 2) + dudeOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Black Forest (2/5)", $location[The Black Forest])); + if (__quest_state["Level 9"].state_int["twin peak progress"] < 15) + dudeOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Twin Peak (5/8)", $location[Twin Peak])); + if (!__quest_state["Level 11 Palindome"].state_boolean["dr. awkward's office unlocked"]) + dudeOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Whitey's Grove (1/4)", $location[Whitey's Grove])); + + string [int] beastOptions; + if (__quest_state["Level 11 Hidden City"].state_boolean["need machete for liana"]) + beastOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Hidden Park (1/4)", $location[The Hidden Park])); + if (!__quest_state["Level 11 Palindome"].state_boolean["dr. awkward's office unlocked"]) + beastOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Palindome (3/7)", $location[Inside the Palindome])); + if (!$location[The Castle in the Clouds in the Sky (Basement)].locationAvailable()) + beastOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Airship (2/7)", $location[The Penultimate Fantasy Airship])); + + string [int] constructOptions; + if (!__quest_state["Level 11 Palindome"].state_boolean["dr. awkward's office unlocked"]) + constructOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Whitey's Grove (1/4)", $location[Whitey's Grove])); + if (!$location[The Castle in the Clouds in the Sky (Basement)].locationAvailable()) + constructOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Airship (1/7)", $location[The Penultimate Fantasy Airship])); + + string [int] undeadOptions; + if (!$location[The Haunted Bathroom].locationAvailable()) + undeadOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Library (1/3)", $location[The Haunted Library])); + if (__quest_state["Level 11 Ron"].mafia_internal_step <= 4) + undeadOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Red Zeppelin (1/5)", $location[The Red Zeppelin])); + if (__quest_state["Level 11 Manor"].mafia_internal_step < 4) + undeadOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Wine Cellar (1/3)", $location[The Haunted Wine Cellar])); + if (__quest_state["Level 11 Manor"].mafia_internal_step < 4) + undeadOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Haunted Boiler (1/3)", $location[The Haunted Boiler Room])); + if (!__quest_state["Level 11 Pyramid"].finished) + undeadOptions.listAppend(HTMLGenerateFutureTextByLocationAvailability("Pyramid Middle (1/3)", $location[The Middle Chamber])); + + + string [int] options; + { + if (dudeOptions.count() > 0) options.listAppend(HTMLGenerateSpanOfClass("Dude: ", "r_bold") + dudeOptions.listJoinComponents(", ")); + if (beastOptions.count() > 0) options.listAppend(HTMLGenerateSpanOfClass("Beast: ", "r_bold") + beastOptions.listJoinComponents(", ")); + if (constructOptions.count() > 0) options.listAppend(HTMLGenerateSpanOfClass("Construct: ", "r_bold") + constructOptions.listJoinComponents(", ")); + if (undeadOptions.count() > 0) options.listAppend(HTMLGenerateSpanOfClass("Undead: ", "r_bold") + undeadOptions.listJoinComponents(", ")); + } + if (options.count() > 0) + description.listAppend("Screech these phylums away to banish a fraction of monsters from a relevant zone:" + options.listJoinComponents("
").HTMLGenerateIndentedText()); + + resource_entries.listAppend(ChecklistEntryMake("__familiar Patriotic Eagle", "familiar.php", ChecklistSubentryMake(title, description), 8).ChecklistEntrySetIDTag("Patriotic Eagle familiar resource")); +} +// August Scepter tile creation. This is... an annoying item. + +// Start by associating skill names with the associated cast check variable +static { + string [string] __augSkillsToVars; + void initializeAugustSkills() { + __augSkillsToVars["Aug. 1st: Mountain Climbing Day!"] = "_aug1Cast"; // turnbloat (+3) + __augSkillsToVars["Aug. 2nd: Find an Eleven-Leaf Clover Day"] = "_aug2Cast"; // lucky! + __augSkillsToVars["Aug. 3rd: Watermelon Day!"] = "_aug3Cast"; // skip, though it could be good for some i guess + __augSkillsToVars["Aug. 4th: Water Balloon Day!"] = "_aug4Cast"; // skip + __augSkillsToVars["Aug. 5th: Oyster Day!"] = "_aug5Cast"; // skip + __augSkillsToVars["Aug. 6th: Fresh Breath Day!"] = "_aug6Cast"; // +com for ninjas + __augSkillsToVars["Aug. 7th: Lighthouse Day!"] = "_aug7Cast"; // +50 item/+100 meat + __augSkillsToVars["Aug. 8th: Cat Day!"] = "_aug8Cast"; // skip + __augSkillsToVars["Aug. 9th: Hand Holding Day!"] = "_aug9Cast"; // mild sniff + __augSkillsToVars["Aug. 10th: World Lion Day!"] = "_aug10Cast"; // banish skill (non-free) + __augSkillsToVars["Aug. 11th: Presidential Joke Day!"] = "_aug11Cast"; // myst stats + __augSkillsToVars["Aug. 12th: Elephant Day!"] = "_aug12Cast"; // mus stats + __augSkillsToVars["Aug. 13th: Left/Off Hander's Day!"] = "_aug13Cast"; // double lewd deck in softcore + __augSkillsToVars["Aug. 14th: Financial Awareness Day!"] = "_aug14Cast"; // skip; extra space? + __augSkillsToVars["Aug. 15th: Relaxation Day!"] = "_aug15Cast"; // skip + __augSkillsToVars["Aug. 16th: Roller Coaster Day!"] = "_aug16Cast"; // -full & +food for spookyraven + __augSkillsToVars["Aug. 17th: Thriftshop Day!"] = "_aug17Cast"; // -1000 meat on your kitchen + __augSkillsToVars["Aug. 18th: Serendipity Day!"] = "_aug18Cast"; // i cannot believe this terrible thing is now meta + __augSkillsToVars["Aug. 19th: Honey Bee Awareness Day!"] = "_aug19Cast"; // skip + __augSkillsToVars["Aug. 20th: Mosquito Day!"] = "_aug20Cast"; // skip + __augSkillsToVars["Aug. 21st: Spumoni Day!"] = "_aug21Cast"; // allstats but skip i think + __augSkillsToVars["Aug. 22nd: Tooth Fairy Day!"] = "_aug22Cast"; // free tooth monster + __augSkillsToVars["Aug. 23rd: Ride the Wind Day!"] = "_aug23Cast"; // mox stats + __augSkillsToVars["Aug. 24th: Waffle Day!"] = "_aug24Cast"; // 3 macros this rules + __augSkillsToVars["Aug. 25th: Banana Split Day!"] = "_aug25Cast"; // skip + __augSkillsToVars["Aug. 26th: Toilet Paper Day!"] = "_aug26Cast"; // skip the sgeea-like, it is not worth it in a post-on-the-trail world + __augSkillsToVars["Aug. 27th: Just Because Day!"] = "_aug27Cast"; // crazy horse for crazy folks + __augSkillsToVars["Aug. 28th: Race Your Mouse Day!"] = "_aug28Cast"; // +10 fam weight melting fam equip; skip if they have pet sweater? + __augSkillsToVars["Aug. 29th: More Herbs, Less Salt Day!"] = "_aug29Cast"; // skip; extra space? + __augSkillsToVars["Aug. 30th: Beach Day!"] = "_aug30Cast"; // +7 adv melting equip; turnbloat + __augSkillsToVars["Aug. 31st: Cabernet Sauvignon Day!"] = "_aug31Cast"; // booze drops + good booze. also, extra space? + } + initializeAugustSkills(); +} + + +// Associate skill names with the thing they give you +static { + string [string] __augSkillsToValue; + void initializeAugustSkills() { + __augSkillsToValue["Aug. 1st: Mountain Climbing Day!"] = "a +adv buff"; + __augSkillsToValue["Aug. 2nd: Find an Eleven-Leaf Clover Day"] = "lucky!"; + __augSkillsToValue["Aug. 3rd: Watermelon Day!"] = "a watermelon"; + __augSkillsToValue["Aug. 4th: Water Balloon Day!"] = "three water balloons"; + __augSkillsToValue["Aug. 5th: Oyster Day!"] = "some oyster eggs"; + __augSkillsToValue["Aug. 6th: Fresh Breath Day!"] = "a +com buff"; + __augSkillsToValue["Aug. 7th: Lighthouse Day!"] = "an item/meat buff"; + __augSkillsToValue["Aug. 8th: Cat Day!"] = "a catfight, meow"; + __augSkillsToValue["Aug. 9th: Hand Holding Day!"] = "a foe's hand held"; + __augSkillsToValue["Aug. 10th: World Lion Day!"] = "roars like a lion"; + __augSkillsToValue["Aug. 11th: Presidential Joke Day!"] = "myst stats"; + __augSkillsToValue["Aug. 12th: Elephant Day!"] = "mus stats"; + __augSkillsToValue["Aug. 13th: Left/Off Hander's Day!"] = "double offhands"; + __augSkillsToValue["Aug. 14th: Financial Awareness Day!"] = "bad meatgain"; + __augSkillsToValue["Aug. 15th: Relaxation Day!"] = "a full heal"; + __augSkillsToValue["Aug. 16th: Roller Coaster Day!"] = "-full & +food%"; + __augSkillsToValue["Aug. 17th: Thriftshop Day!"] = "a 1000 meat coupon"; + __augSkillsToValue["Aug. 18th: Serendipity Day!"] = "a bunch of items"; + __augSkillsToValue["Aug. 19th: Honey Bee Awareness Day!"] = "stalked by bees"; + __augSkillsToValue["Aug. 20th: Mosquito Day!"] = "HP regen"; + __augSkillsToValue["Aug. 21st: Spumoni Day!"] = "stats of all kinds"; + __augSkillsToValue["Aug. 22nd: Tooth Fairy Day!"] = "a free tooth monster"; + __augSkillsToValue["Aug. 23rd: Ride the Wind Day!"] = "mox stats"; + __augSkillsToValue["Aug. 24th: Waffle Day!"] = "three waffles"; + __augSkillsToValue["Aug. 25th: Banana Split Day!"] = "a banana split"; + __augSkillsToValue["Aug. 26th: Toilet Paper Day!"] = "some toilet paper"; + __augSkillsToValue["Aug. 27th: Just Because Day!"] = "three random effects"; + __augSkillsToValue["Aug. 28th: Race Your Mouse Day!"] = "a melting fam equip"; + __augSkillsToValue["Aug. 29th: More Herbs, Less Salt Day!"] = "a food stat enhancer"; + __augSkillsToValue["Aug. 30th: Beach Day!"] = "a +7 adv accessory"; + __augSkillsToValue["Aug. 31st: Cabernet Sauvignon Day!"] = "two bottles of +booze% wine"; + } + initializeAugustSkills(); +} + +// Convert the user's mainstat to an August statgain skill +int mainstatAugustSkill() { + switch (my_primestat()) + { + case $stat[muscle]: + return 12; // "Aug. 12th: Elephant Day!" + case $stat[mysticality]: + return 11; // "Aug. 11th: Presidential Joke Day!" + case $stat[moxie]: + return 23; // "Aug. 23rd: Ride the Wind Day!" + } + return 12; // "return muscle if you can't " +} + +// Helper function to grab the first # in the string +int grabNumber(string s){ + matcher numMatcher = create_matcher("\\d+",s); + if (numMatcher.find()){ + return numMatcher.group(0).to_int(); + } else { + return 0; + } +} + +RegisterResourceGenerationFunction("IOTMAugustScepterGenerateResource"); +void IOTMAugustScepterGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[lookupItem("August Scepter")]) return; + + // Figure out how many of your five skills are still available; no tile if none are there! + int skillsAvailable = 5 - get_property_int("_augSkillsCast"); + if (skillsAvailable < 1) return; + + // A string for demarcation of 30 turn buffs + string buffString = HTMLGenerateSpanFont(" (buff)", "gray", "0.9em"); + + // Similar to calculate the universe, store reasons why things have value while using + // the day as the key. Should make the tile less painful to read, though a bit more + // confusing. Will *definitely* need a little summary text. + string [int] usefulAugustSkills; + + foreach augSkillName, augSkillPref in __augSkillsToVars { + + // Convert text to number. You could argue that I should've just initially stored + // them as ints, but I wanted to store full skill names just in case we see a + // good use case for the full skill names later. + int augSkillNumber = grabNumber(augSkillName); + + // For these particularly mediocre/bad skills, don't even look up the pref. This covers 12/31 skills + if ($ints[3, 4, 5, 8, 14, 15, 19, 20, 21, 25, 26, 29] contains augSkillNumber) continue; + + // Skip the tile-creation logic for that guy if the skill has already been cast. + if (get_property_boolean(augSkillPref)) { + continue; + } + + // Within this foreach, add descriptions for the valuable casts, if they're still + // valuable to the player. + + // LEVELING HELP; gain 50*level mainstats. 12, 11, 23 for 15/31 skills + if (__misc_state["need to level"]) { + + if (augSkillNumber == mainstatAugustSkill()) { + int statsGained = (50 * my_level() * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0)).floor(); + usefulAugustSkills[augSkillNumber] = "+"+statsGained+" mainstat"; + } + + } + + // TURNBLOAT; baywatch (30) + spirit (1) for 17/31 skills + if (my_path() != $path[Slow and Steady]) { + + // Only show mountain effect if they need goat cheese, as there aren't many mountains in-run. + if ($item[goat cheese].available_amount() < 2 && !__quest_state["Level 8"].state_boolean["Past mine"]) { + if (augSkillNumber == 1) { + usefulAugustSkills[1] = "+2-5 turns "+HTMLGenerateSpanFont("(spend turns @ the Goatlet)", "gray", "0.9em"); + } + } + + if (augSkillNumber == 30) { + usefulAugustSkills[30] = "+7 advs rollover accessory "+HTMLGenerateSpanFont("(melting)", "gray", "0.9em"); + } + } + + // +ITEM BUFFS; food/booze/base, with 31, 16, and 7. 20/31 skills + + boolean manorCheck = __quest_state["Level 11 Manor"].mafia_internal_step < 3 && __quest_state["Level 11 Manor"].state_boolean["Can use fast route"]; + string blastingAddendum = manorCheck && $item[blasting soda].available_amount() == 0 ? ""+HTMLGenerateSpanFont("(blasting soda!)", "gray", "0.9em") : ""; + + // I suppose -1 fullness is always good for turnbloat? + if (augSkillNumber == 16) usefulAugustSkills[16] = "-1 fullness, +100% food drop "+blastingAddendum; + + if (manorCheck) { + // Only need booze drop if you don't already have vinegar + if ($item[bottle of Chateau de Vinegar].available_amount() == 0) { + if (augSkillNumber == 31) usefulAugustSkills[31] = "+100% booze drop wine "+HTMLGenerateSpanFont("(chateau de vinegar!)", "gray", "0.9em"); + } + + } + + // +item/meat is always good times + if (augSkillNumber == 7) usefulAugustSkills[7] = "+50% item, +100% meat"+buffString; + + // LUCKY!; 2, but important! 21/31 skills + if (augSkillNumber == 2) usefulAugustSkills[2] = "get Lucky!"; + + // WAFFLES!; 24, but the best guy here. 22/31 + if (augSkillNumber == 24) usefulAugustSkills[24] = "3 waffles, for monster replacement"; + + + // FREE TOOTH MONSTER; lol what the actual heck (22) 24/31 + if (augSkillNumber == 22) usefulAugustSkills[22] = "free fight for teeeeeeeeeeeth"; + + // +COM FOR NINJAS; kind of a crock but why not (6) 25/31 + if (!__quest_state["Level 8"].state_boolean["Mountain climbed"]) { + if (augSkillNumber == 6) usefulAugustSkills[6] = "+10% combat"+buffString; + } + + // HAND HOLDING; we still don't know exactly what this does (9) 26/31 + if (augSkillNumber == 9) usefulAugustSkills[9] = "hold hands for a minor sniff"; + + // LION BANISH; definitely worth calling out; NOT a killbanish (10) 27/31 + if (augSkillNumber == 10) usefulAugustSkills[10] = "non-free reusable banishes"+buffString; + + // OFFHAND DOUBLER; wild stuff folks (13) 28/31 + int usefulOffhands = $item[deck of lewd playing cards].available_amount(); + int protestorsRemaining = clampi(80 - get_property_int("zeppelinProtestors"), 0, 80); + + if (usefulOffhands > 0 && protestorsRemaining > 10) { + // you could probably add a few other things to this, like -ML for goo or big smithsness. but eh. + if (augSkillNumber == 13) usefulAugustSkills[13] = "double offhand enchantments "+HTMLGenerateSpanOfClass("(sleaze ", "r_element_sleaze_desaturated")+"for protestors)"; + } + + // SAVE 1000 MEAT; barely useful, only show if they're strapped (17) 29/31 + + // CRAZY HORSE RETURNS; just because (27) 30/31 + string randomInRainbow = HTMLGenerateSpanOfClass("r", "r_element_hot_desaturated")+HTMLGenerateSpanOfClass("a", "r_element_stench_desaturated")+HTMLGenerateSpanOfClass("n", "r_element_sleaze_desaturated")+HTMLGenerateSpanOfClass("d", "r_element_cold_desaturated")+HTMLGenerateSpanOfClass("o", "r_element_spooky_desaturated")+HTMLGenerateSpanOfClass("m", "r_element_hot_desaturated"); + if (augSkillNumber == 27) usefulAugustSkills[27] = "+3 "+randomInRainbow+" effects"+buffString; + + // +10 FAM WEIGHT; this won't appear in modern standard lol (28) 31/31 + if (__misc_state["free runs usable"] && ($familiar[pair of stomping boots].familiar_is_usable() || ($skill[the ode to booze].skill_is_usable() && $familiar[Frumious Bandersnatch].familiar_is_usable()))) { + if ($item[astral pet sweater].available_amount() == 0) { + if (augSkillNumber == 28) usefulAugustSkills[28] = "+10 weight familiar equipment "+HTMLGenerateSpanFont("(melting)", "gray", "0.9em"); + } + } + } + + string [int][int] table; + string [int] description; + + table.listAppend(listMake(HTMLGenerateSpanOfClass("Day", "r_bold"), HTMLGenerateSpanOfClass("Result", "r_bold"))); + + foreach day, reason in usefulAugustSkills { + table.listAppend(listMake(day.to_string(), reason)); + } + + string table_description = ""; + if (table.count() > 0) + table_description += "|*" + HTMLGenerateSimpleTableLines(table); + + // Summary of the august tile + string summarizeAugust = "Celebrate August tidings; cast skills corresponding to the given day to get valuable benefits."; + + if (table_description != "") + description.listAppend(summarizeAugust + table_description); + else + description.listAppend(summarizeAugust); + + string title = "Cast "+pluralise(skillsAvailable, "August Scepter skill", "August Scepter skills"); + + string subtitle = "all buffs are 30 turns"; + + // Make a big tooltip with all skills & their results listed out and colored + string [int] [int] allSkills; + int todaySkillInt = today_to_string().to_int() % 100; + + allSkills.listAppend(listMake(HTMLGenerateSpanOfClass("Day", "r_bold"), HTMLGenerateSpanOfClass("Gives you...", "r_bold"))); + + + // Have to do this to ensure the tooltip orders appropriately + string [int] allAugustSkills; + + foreach augSkill, augSkillValue in __augSkillsToValue { + allAugustSkills[grabNumber(augSkill)] = augSkill; + } + + // Now that it is correctly iterating in order, color appropriately and build the allSkill table. + foreach augSkillNumber, augSkill in allAugustSkills { + string lineColor = "black"; + string augSkillValue = __augSkillsToValue[augSkill]; + + // Color the "free" skill in blue if they're in aftercore + if (!__misc_state["in run"] && augSkillNumber == todaySkillInt) lineColor = "blue"; + if (get_property_boolean(__augSkillsToVars[augSkill])) lineColor = "gray"; + + allSkills.listAppend(listMake(HTMLGenerateSpanFont(augSkillNumber, lineColor),HTMLGenerateSpanFont(augSkillValue, lineColor))); + } + + // give a tip of the cap to the ol tools here + buffer tooltip; + tooltip.append(HTMLGenerateTagWrap("div", "Well, you asked for it!", mapMake("class", "r_bold r_centre", "style", "padding-bottom:0.25em;"))); + tooltip.append(HTMLGenerateSimpleTableLines(allSkills)); + string tooltipEnumerated = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip, "r_tooltip_inner_class r_tooltip_inner_class_margin") + "No, TourGuide, show me ALL the skills.", "r_tooltip_outer_class"); + description.listAppend(tooltipEnumerated); + + resource_entries.listAppend(ChecklistEntryMake("__item August Scepter", "skillz.php", ChecklistSubentryMake(title, subtitle, description), -1).ChecklistEntrySetIDTag("August Scepter resource")); + +} +//Book of FActs +RegisterTaskGenerationFunction("IOTMBookofFactsGenerateTasks"); +void IOTMBookofFactsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // Exit out of the tile if they have neither skill and we don't actually think they should, either + if (!lookupSkill("Just the Facts").have_skill() && !__iotms_usable[$item[book of facts (dog-eared)]]) return; + + monster habitat_monster = get_property_monster("_monsterHabitatsMonster"); + int fights_left = clampi(get_property_int("_monsterHabitatsFightsLeft"), 0, 5); + string [int] description; + + // If they have an eagle, remind them they can eagle-banish to make it easier to find the habitat guys + string eagleString = lookupFamiliar("Patriotic Eagle").familiar_is_usable() ? "; remember, you can phylum-banish with your Patriotic Eagle to make it easier!" : "." ; + phylum eaglePhylumBanished = $phylum[none]; + + if (get_property("banishedPhyla") != "") + eaglePhylumBanished = get_property("banishedPhyla").split_string(":")[1].to_phylum(); + + if (habitat_monster != $monster[none] && fights_left > 0) + { + description.listAppend("Neaaaar, faaaaaaar, wherever you spaaaaaaar, I believe that the heart does go onnnnn."); + description.listAppend("Appears as a wandering monster in any zone. Try a place with few competing monsters"+eagleString); + + if (eaglePhylumBanished == habitat_monster.phylum) { + description.listAppend(HTMLGenerateSpanFont(`WARNING: {habitat_monster}'s phylum is banished!`, "red")); + } + + if (habitat_monster.is_banished()) { + description.listAppend(HTMLGenerateSpanFont(`WARNING: {habitat_monster} is banished!`, "red")); + } + + optional_task_entries.listAppend(ChecklistEntryMake("__monster " + habitat_monster, "", ChecklistSubentryMake("Fight " + pluralise(fights_left, "more non-native " + habitat_monster, "more non-native " + habitat_monster + "s"), "", description), -4)); + } + + // Moving priority on this down a tiny bit due to in-run mediocrity + int circadianAdv = (get_property_int("_circadianRhythmsAdventures")); + if ($effect[Recalling Circadian Rhythms].have_effect() > 0 && circadianAdv < 10) { + string [int] circadianDescription; + string circadianPhylum = (get_property("_circadianRhythmsPhylum")); + circadianDescription.listAppend("Fight " + (11 - circadianAdv) + " more " + circadianPhylum + "s to get RO advs."); + task_entries.listAppend(ChecklistEntryMake("__item cheap wind-up clock", "", ChecklistSubentryMake("Circadian Rhythms turngen", circadianDescription), -1).ChecklistEntrySetIDTag("Circadian Rhythms turngen")); + } +} + +RegisterResourceGenerationFunction("IOTMBookofFactsGenerateResource"); +void IOTMBookofFactsGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupSkill("Just the Facts").have_skill() && !__iotms_usable[$item[book of facts (dog-eared)]]) return; + string [int] description; + string [int] circadianDescription; + + // Populating different things based on run state & IOTM availability + string constructDescriptor = __iotms_usable[$item[X-32-F snowman crate]] ? " + snojo" : ""; + if (lookupItem("[glitch season reward name]").item_amount() > 0) constructDescriptor += " + glitch"; + string dudeDescriptor = __iotms_usable[$item[Witchess Set]] ? " + witchess" : ""; + if (__iotms_usable[lookupItem("Neverending Party invitation envelope")]) dudeDescriptor += " + NEP"; + string horrorDescriptor = lookupItem("closed-circuit pay phone").have() ? " + shadow rifts" : ""; + + if (!get_property_boolean("_circadianRhythmsRecalled")) { + circadianDescription.listAppend("Can recall Circadian Rhythms to get +11 RO adv."); + circadianDescription.listAppend("Good targets: construct (nightstands"+constructDescriptor+"), dudes (pygmies"+dudeDescriptor+"), horrors (copied tentacles"+horrorDescriptor+")"); + resource_entries.listAppend(ChecklistEntryMake("__item cheap wind-up clock", "", ChecklistSubentryMake("Circadian Rhythms turngen", circadianDescription), 11).ChecklistEntrySetIDTag("Circadian Rhythms turngen")); + } + + int habitatRecallsLeft = clampi(3 - get_property_int("_monsterHabitatsRecalled"), 0, 3); + if (get_property_int("_monsterHabitatsRecalled") < 3) { + description.listAppend("Good targets include monsters you want 6 of:"); + description.listAppend("Fantasy bandit, eldritch tentacle, black crayon orc if the stars align"); + resource_entries.listAppend(ChecklistEntryMake("__item hey deze map", "", ChecklistSubentryMake(pluralise(habitatRecallsLeft, "Habitat recall", "Habitat recalls"), "", description), 8).ChecklistEntrySetIDTag("habitat recalls")); + } + + // TODO: Once mt_rand is exposed, show on-path wishes. Not really doable yet lol + string [int] BOFAdropsDescription; + int BOFApocketwishes = clampi(3 - get_property_int("_bookOfFactsWishes"), 0, 3); + if (get_property_int("_bookOfFactsWishes") < 3) { + BOFAdropsDescription.listAppend("" + BOFApocketwishes + " BOFA wishes available."); + } + + // NOTE: Altering as of 2024 ELG change, as tatters are 40 turns vs the 30 of spring shoes. + // There is a remote chance in some future standard context tatters will be the best option + // for a user with some odd IOTM configurations, which is why I didn't entirely extract + // this, but it at least shouldn't be present if they own the candles or the shoes. + + if (!__iotms_usable[lookupItem("spring shoes")] && $item[roman candelabra].available_amount() == 0) { + int BOFAtatters = clampi(11 - get_property_int("_bookOfFactsTatters"), 0, 11); + if (get_property_int("_bookOfFactsTatters") < 11) { + BOFAdropsDescription.listAppend("" + BOFAtatters + " BOFA tatters available."); + } + } + + resource_entries.listAppend(ChecklistEntryMake("__item book of facts", "", ChecklistSubentryMake(("Miscellaneous valuable BOFA drops"), "", BOFAdropsDescription), 8).ChecklistEntrySetIDTag("bofa tatters")); +} + +// TILE SPEC: +// - Remind the user to get a halloween map. +// - Remind the user to get an LED candle. +// - Recommend halloween monsters for habitation. + +// CANNOT DO YET: +// - Add halloween fights to freebies combination tag; need better mafia tracking... + +RegisterResourceGenerationFunction("IOTMJillv2GenerateResource"); +void IOTMJillv2GenerateResource(ChecklistEntry [int] resource_entries) +{ + familiar bigJillyStyle = lookupFamiliar("Jill-of-All-Trades"); + if (!bigJillyStyle.familiar_is_usable()) return; + + int mapsDropped = get_property_int("_mapToACandyRichBlockDrops"); + + string url = "familiar.php"; + if (bigJillyStyle == my_familiar()) + url = ""; + + // Initial chance is 35% with a masssive dropoff (multiply by 5% per map dropped) + float estimatedMapProbability = 35 * (0.05 ** clampi(mapsDropped, 0, 3)); // confirmed by cannonfire to stop decreasing after 3rd time + + // Convert to turns + float turnsToMap = 1/(estimatedMapProbability/100); + + string [int] description; + if (mapsDropped == 0) { + description.listAppend("You haven't gotten a map to halloween town yet! Try using your Jill for a map at ~"+round(estimatedMapProbability)+"% chance, or approximately "+round(turnsToMap,1)+" turns."); + } + else if (mapsDropped < 2) { // The third map drop chance is less than 1 in a thousand - not something that is particularly useful to hunt for + description.listAppend("You have a map; the next map is at a ~"+round(estimatedMapProbability)+"% chance, or approximately "+round(turnsToMap,1)+" turns."); + } + + int habitatRecallsLeft = clampi(3 - get_property_int("_monsterHabitatsRecalled"), 0, 3); + if (!lookupSkill("Just the Facts").have_skill() && !__iotms_usable[$item[book of facts (dog-eared)]]) habitatRecallsLeft = 0; + if (habitatRecallsLeft > 0) + description.listAppend("Halloween monsters make excellent targets for Recall Habitat from BoFA."); + + // Adding a small exception here to not generate this if they weirdly acquired LED through other means (like casual or a pull or something) + if (!get_property_boolean("ledCandleDropped") && $item[LED Candle].item_amount() < 1) { + description.listAppend("Fight a dude for an LED candle, to tune your Jill!"); + } + + // If we have nothing to say, do not display the tile + if (count(description) == 0) return; + + resource_entries.listAppend(ChecklistEntryMake("__familiar jill-of-all-trades", url, ChecklistSubentryMake("Celebrating the Jillenium", "", description)).ChecklistEntrySetIDTag("Jill of All Trades tile")); +} + +// TILE SPEC: +// - Remind the user to spend their leaves. +// - Advise the user of top leafy options. +// - Add leafy free fights to the freefightcombinationtag + +Record LeafyFight +{ + int leafCost; + monster summonedMonster; + string scaling; + int leavesDropped; + string extraDrops; +}; + +LeafyFight LeafyFightMake(int cost, monster summonedMonster, string scaling, int leavesDropped, string itemDropped) +{ + LeafyFight summon; + + summon.leafCost = cost; + summon.summonedMonster = summonedMonster; + summon.scaling = scaling; + summon.leavesDropped = leavesDropped; + summon.extraDrops = itemDropped; + + return summon; +} + +Record LeafySummon +{ + int leafCost; + item summonedItem; + string description; + boolean meltingStatus; + string prefName; +}; + +LeafySummon LeafySummonMake(int cost, item summonedItem, string desc, boolean melts, string prefName) +{ + LeafySummon summon; + + summon.leafCost = cost; + summon.summonedItem = summonedItem; + summon.description = desc; + summon.meltingStatus = melts; + summon.prefName = prefName; + + return summon; +} + +void listAppend(LeafyFight [int] list, LeafyFight entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +void listAppend(LeafySummon [int] list, LeafySummon entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +RegisterResourceGenerationFunction("IOTMBurningLeavesGenerateResource"); +void IOTMBurningLeavesGenerateResource(ChecklistEntry [int] resource_entries) +{ + // Don't generate these tiles if they cannot actually use their leaves + if (!__iotms_usable[$item[A Guide to Burning Leaves]]) return; + + string url = "campground.php?preaction=burningleaves"; + + // Make two tiles for spending leaves + int leafCount = $item[inflammable leaf].item_amount(); + string [int] itemsDescription; + string [int] monstersDescription; + + // To use these, if you do "aftercoreStuff[##]" it'll return true if it's in the list or false if not + boolean [int] aftercoreStuff = $ints[99,222,1111,6666,11111]; + boolean [int] inRunStuff = $ints[42,43,44,66]; + + if ($item[inflammable leaf].have()) { + + LeafySummon [int] leafySummons; + // leafySummons.listAppend(LeafySummonMake(#leafcost, $item[leafsummon], "tile desc", t/f(melts), "name of summon check pref")); + leafySummons.listAppend(LeafySummonMake(37, $item[autumnic bomb], "potion; prismatic stinging (25 turns)", false, "")); + leafySummons.listAppend(LeafySummonMake(42, $item[impromptu torch], "weapon; +2 mus/fight", true, "")); + leafySummons.listAppend(LeafySummonMake(43, $item[flaming fig leaf], "pants; +2 mox/fight", true, "")); + leafySummons.listAppend(LeafySummonMake(44, $item[smoldering drape], "cape; +2 mys/fight, +20% stat", true, "")); + leafySummons.listAppend(LeafySummonMake(50, $item[distilled resin], "potion; generate +1 leaf/fight (100 turns)", false, "")); + leafySummons.listAppend(LeafySummonMake(66, $item[autumnal aegis], "shield; +250 DA, +2 all res", false, "")); + leafySummons.listAppend(LeafySummonMake(69, $item[lit leaf lasso], "combat item; lasso leaf freebies for extra end-of-combat triggers", false, "_leafLassosCrafted")); + leafySummons.listAppend(LeafySummonMake(74, $item[forest canopy bed], "bed; +5 free rests, stats via rests", false, "")); + leafySummons.listAppend(LeafySummonMake(99, $item[autumnic balm], "potion; +2 all res (100 turns)", false, "")); + leafySummons.listAppend(LeafySummonMake(222, $item[day shortener], "spend 5 turns for a +turn item", false, "_leafDayShortenerCrafted")); + leafySummons.listAppend(LeafySummonMake(1111, $item[coping juice], "copium for the masses", false, "")); + leafySummons.listAppend(LeafySummonMake(6666, $item[smoldering leafcutter ant egg], "mosquito & leaves familiar", false, "_leafAntEggCrafted")); + leafySummons.listAppend(LeafySummonMake(11111, $item[super-heated leaf], "burn leaves into your skiiiin", false, "_leafTattooCrafted")); + + // Make a big summons table for a leaf summoning tile + string [int][int] summonOptions; + + // Header for the item summons table + if (true) + { + string [int] option; + option.listAppend("cost"); + option.listAppend("item"); + option.listAppend("description"); + foreach key, s in option + { + option[key] = HTMLGenerateSpanOfClass(s, "r_bold"); + } + summonOptions.listAppend(option); + } + + // Populate the table + foreach key, summon in leafySummons + { + // Adding some skip conditions for aftercore/in-run options + // if (__misc_state["in run"] && aftercoreStuff[summon.leafCost]) continue; + // if (!__misc_state["in run"] && inRunStuff[summon.leafCost]) continue; + + // Run pref checks & do not generate a row if you cannot summon it anymore + boolean userCanSummon = true; + + if (summon.prefName == "") + userCanSummon = true; + else if (summon.prefName == "_leafLassosCrafted") + userCanSummon = get_property_int("_leafLassosCrafted") < 3; // can make a lasso if you've made <3 + else + userCanSummon = !get_property_boolean(summon.prefName); // prefs are false if non-summoned, true if summoned and you're locked out + + if (!userCanSummon) continue; + + // A handful of conditional exclusions. Enumerated reasons in the comments! + + // The bomb is useful if you aren't able to use crab or short-order cook. Otherwise, not particularly useful. + boolean canUseShorty = lookupFamiliar("Shorter-Order Cook").familiar_is_usable(); + boolean canUseCrab = lookupFamiliar("Imitation Crab").familiar_is_usable(); + + if (canUseShorty || canUseCrab) { + if (summon.leafCost == 37) continue; + } + + // If the user is level 12 or higher, no reason to show fig or torch. Going to still + // show drape if they don't have it, as 20% stat might be useful slot-filler for some + // weird user somewhere. + if (my_level() > 11) { + if ($ints[42,43] contains summon.leafCost) continue; + } + + // If the user has Tao of the Terrapin available, they probably don't need the aegis + if (lookupSkill("Tao of the Terrapin").have_skill()) { + if (summon.leafCost == 66) continue; + } + + // Do not get 2 of any of the equips or other one-use items + if (summon.summonedItem.available_amount() > 0) { + if ($ints[42,43,44,66,74] contains summon.leafCost) continue; + } + + // Do not show the bed if it is already installed either + if (get_campground() contains $item[forest canopy bed]) { + if (summon.leafCost == 74) continue; + } + + // Set the color to gray if you don't have enough leaves + boolean hasEnoughLeaves = leafCount >= summon.leafCost; + string rowColor = hasEnoughLeaves ? "black" : "gray"; + + // Add smaller melting tag to description, if it's melting + string summonDesc = summon.description; + if (summon.meltingStatus) + summonDesc += HTMLGenerateSpanFont(" (melting)", "gray", "0.7em"); + + // Hide aftercore stuff while in-run, and visa versa + if (__misc_state["in run"]) { + if (aftercoreStuff[summon.leafCost]) continue; + } + + if (!__misc_state["in run"]) { + if (inRunStuff[summon.leafCost]) continue; + } + + string [int] option; + // add cost + option.listAppend(summon.leafCost); + option.listAppend(summon.summonedItem.to_string()); + option.listAppend(summonDesc); + foreach key, s in option + { + option[key] = HTMLGenerateSpanFont(s, rowColor); + } + summonOptions.listAppend(option); + } + itemsDescription.listAppend(HTMLGenerateSimpleTableLines(summonOptions)); + resource_entries.listAppend(ChecklistEntryMake("__item inflammable leaf", url, ChecklistSubentryMake(pluralise(leafCount, "leaf to burn for items", "leaves to burn for items"), "", itemsDescription), 14).ChecklistEntrySetIDTag("Burning leaf item summons")); + + // With item summons done, make a seal-esque fights tile + + int fightsRemaining = clampi(5 - get_property_int("_leafMonstersFought"), 0, 5); + + if (fightsRemaining > 0) { + LeafyFight [int] leafyFights; + // leafyFights.listAppend(LeafyFightMake(#leafcost, $monster[leafmonster], "scaling desc", #leafdrops, "extra drops")); + leafyFights.listAppend(LeafyFightMake(11, $monster[flaming leaflet], "11/11/11", 4, "")); + leafyFights.listAppend(LeafyFightMake(111, $monster[flaming monstera], "scaling", 7, "leafy browns")); + + // No particular need to fight leaviathan over monstera in run if the user owns the crown already + if (!(__misc_state["in run"] && $item[flaming leaf crown].have())) { + leafyFights.listAppend(LeafyFightMake(666, $monster[leaviathan], "scaling boss (hard!)", 125, "flaming leaf crown")); + } + + string [int][int] fightOptions; + + // Header for the fight summons table + if (true) + { + string [int] option; + option.listAppend("cost"); + option.listAppend("monster"); + option.listAppend("stats & info"); + foreach key, s in option + { + option[key] = HTMLGenerateSpanOfClass(s, "r_bold"); + } + fightOptions.listAppend(option); + } + + foreach key, summon in leafyFights + { + boolean hasEnoughLeaves = leafCount >= summon.leafCost; + string rowColor = hasEnoughLeaves ? "black" : "gray"; + + // Add smaller melting tag to description, if it's melting + string summonDesc = summon.scaling + "; ~"+summon.leavesDropped+" leaves dropped "; + if (summon.extraDrops != "") + summonDesc += HTMLGenerateSpanFont("(also, drops "+summon.extraDrops+")", "gray", "0.7em"); + + string [int] option; + // add cost + option.listAppend(summon.leafCost); + option.listAppend(summon.summonedMonster.to_string()); + option.listAppend(summonDesc); + foreach key, s in option + { + option[key] = HTMLGenerateSpanFont(s, rowColor); + } + fightOptions.listAppend(option); + } + + int leafletsUserCanSummon = leafCount/11; + + monstersDescription.listAppend(HTMLGenerateSimpleTableLines(fightOptions)); + if (leafCount > 111*fightsRemaining) { + monstersDescription.listAppend("With your "+pluralise(leafCount, "leaf", "leaves")+", you can summon "+fightsRemaining+" monstera, for scaling fights"); + } + else if (leafCount > 11*fightsRemaining) { + monstersDescription.listAppend("With your "+pluralise(leafCount, "leaf", "leaves")+", you can summon "+fightsRemaining+" leaflets, for familiar turns"); + } + else if (leafCount > 11) { + monstersDescription.listAppend("With your "+pluralise(leafCount, "leaf", "leaves")+", you can currently summon "+pluralise(leafletsUserCanSummon,"leaflet","leaflets")+"; save leaves for more!"); + } + else { + monstersDescription.listAppend("With your "+pluralise(leafCount, "leaf", "leaves")+", you cannot currently summon a free fight; save leaves for more!"); + } + + resource_entries.listAppend(ChecklistEntryMake("__monster flaming leaflet", url, ChecklistSubentryMake(pluralise(fightsRemaining, "remaining free burned leaf fight", "remaining free burned leaf fights"), "remember to lasso for +1 fight!", monstersDescription), 13).ChecklistEntrySetIDTag("Burning leaf fight summons")); + + } + + } + + // Make a free fights combo tag for available free leaf fights + int fightsRemaining = clampi(5 - get_property_int("_leafMonstersFought"), 0, 5); + int leafletsUserCanSummon = leafCount/11; + + string [int] description; + ChecklistSubentry [int] subentries; + + if (fightsRemaining > 0) { + + if (leafCount >= 111*fightsRemaining) { + description.listAppend("Have enough leaves for "+fightsRemaining+" flaming monstera"); + } + else if (leafCount >= 11*fightsRemaining) { + description.listAppend("Have enough leaves for "+fightsRemaining+" leaflets"); + } + else if (leafCount >= 8*fightsRemaining) { + description.listAppend("Have enough leaves, if you let the leaflets drop their bounty!"); + } + else { + description.listAppend(HTMLGenerateSpanFont("Can summon "+leafletsUserCanSummon+" of your "+fightsRemaining+" leaflets... get more leaves!", "orange")); + } + + subentries.listAppend(ChecklistSubentryMake(pluralise(fightsRemaining, "free flaming leaflet fight", "free flaming leaflet fights"), "", description)); + TagGroup tags; + tags.id = "Burning Leaves free fights"; + tags.combination = "daily free fight"; + resource_entries.listAppend(ChecklistEntryMake("__item tied-up flaming leaflet", url, subentries, tags, 0)); + } +} +// Candy Cane Sword Cane +RegisterTaskGenerationFunction("IOTMCandyCaneSwordGenerateTasks"); +void IOTMCandyCaneSwordGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // Initialization. Good use of "lookupItem" for backwards compatibility reasons. + if (!__iotms_usable[lookupItem("candy cane sword cane")]) return; + int ccscEquipped = lookupItem("candy cane sword cane").equipped_amount(); + string ccscEquipStatement = ccscEquipped > 0 ? "Keep your Candy Cane Sword Cane equipped!" : "Equip your Candy Cane Sword Cane!"; + string [int] description; + string [int] describeSupernag; + string [int] options; + + // Added a check for all paths where you do not want the tile at all: + // - Community Service & Grey Goo: irrelevant + // - Avatar of Boris: cannot wield a weapon other than trusty or use a familiar + // - 11,037 Leagues Under the Sea: irrelevant + boolean pathCheck = true; + pathCheck = my_path().id == PATH_SEA ? false : true; + pathCheck = my_path().id == PATH_COMMUNITY_SERVICE ? false : true; + pathCheck = my_path().id == PATH_GREY_GOO ? false : true; + pathCheck = my_path().id == PATH_AVATAR_OF_BORIS ? false : true; + + // Only show when in run, for obvious reasons. + if (__misc_state["in run"] && pathCheck) + { + string url = "inventory.php?ftext=candy+cane+sword+cane"; + // This is the description for the supernag. The supernag is in the task_entries, buried within conditional ifs and only shows up if you're in the zone. + describeSupernag.listAppend(HTMLGenerateSpanFont("You're", "red") + " " + HTMLGenerateSpanFont("in a", "green") + " " + HTMLGenerateSpanFont("candy", "red") + " " + HTMLGenerateSpanFont("cane", "green") + " " + HTMLGenerateSpanFont("sword", "red") + " " + HTMLGenerateSpanFont("cane", "green") + " " + HTMLGenerateSpanFont("noncom", "red") + " " + HTMLGenerateSpanFont("zone!", "green")); + + // This enumerates the useful CCSC adventures + if (!get_property_boolean("_candyCaneSwordLyle")) { + options.listAppend(HTMLGenerateSpanOfClass("Bonus:", "r_bold") + " Lyle's Monorail Buff (+40% init)"); + } + + // Added a check for if they are past black forest + if (!get_property_boolean("candyCaneSwordBlackForest") && __quest_state["Level 11"].mafia_internal_step < 2) { + options.listAppend(HTMLGenerateSpanOfClass("Bonus:", "r_bold") + " The Black Forest (+8 exploration)"); + if (($locations[The Black Forest] contains __last_adventure_location)) { + task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); + } + } + + // Added a check for if they need the loot token. + if (!get_property_boolean("candyCaneSwordDailyDungeon") && __misc_state_int["fat loot tokens needed"] > 0) { + options.listAppend(HTMLGenerateSpanOfClass("Bonus:", "r_bold") + " Daily Dungeon (+1 fat loot token)"); + if (($locations[The Daily Dungeon] contains __last_adventure_location)) { + task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); + } + } + + // Added a check for if they need a curse + if (!get_property_boolean("candyCaneSwordApartmentBuilding") && get_property_int("hiddenApartmentProgress") < 8) { + options.listAppend(HTMLGenerateSpanOfClass("Bonus:", "r_bold") + " Hidden Apartment (+1 Curse)"); + if (($locations[The Hidden Apartment Building] contains __last_adventure_location)) { + task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); + } + } + + // Added a check for if they need bowling alley access by checking the bowling alley progress var + if (!get_property_boolean("candyCaneSwordBowlingAlley") && get_property_int("hiddenBowlingAlleyProgress") < 7) { + options.listAppend(HTMLGenerateSpanOfClass("Bonus:", "r_bold") + " Hidden Bowling Alley (+1 free bowl)"); + if (($locations[The Hidden Bowling Alley] contains __last_adventure_location)) { + task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); + } + } + + // Added a check for if they need shore access + if (!get_property_boolean("candyCaneSwordShore") && !__misc_state["mysterious island available"]) { + options.listAppend(HTMLGenerateSpanOfClass("Alternate:", "r_bold") + " Shore (2 scrips for the price of 1)"); + if (($locations[The Shore\, Inc. Travel Agency] contains __last_adventure_location)) { + task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); + } + } + + // Added a check for if war is finished + if (locationAvailable($location[The Battlefield (Frat Uniform)]) == false && !__quest_state["Level 12"].finished) { + options.listAppend(HTMLGenerateSpanOfClass("Alternate:", "r_bold") + " Hippy Camp (Redirect to the War Start NC)"); + if (($locations[Wartime Hippy Camp,Wartime Frat House] contains __last_adventure_location)) { + task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); + } + } + + // Changed condition to <80 protestors check + if (get_property_int("zeppelinProtestors") < 80) { + options.listAppend(HTMLGenerateSpanOfClass("Alternate: ", "r_bold") + "Zeppelin Protesters " + HTMLGenerateSpanFont("(double Sleaze damage!)", "purple")); + if (($locations[A Mob of Zeppelin Protesters] contains __last_adventure_location)) { + task_entries.listAppend(ChecklistEntryMake("__item candy cane sword cane", url, ChecklistSubentryMake(ccscEquipStatement, "", describeSupernag), -11)); + } + } + + if (options.count() > 0) { + description.listAppend("Ensure your CCSC is equipped for useful NCs:" + options.listJoinComponents("
").HTMLGenerateIndentedText()); + + // Darkened from bright red to maroon as it will be irrelevant for many parts of the run. + if (lookupItem("candy cane sword cane").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the Candy Cane Sword Cane!", "maroon")); + } + + optional_task_entries.listAppend(ChecklistEntryMake("__item Candy cane sword cane", url, ChecklistSubentryMake("Candy Cane Sword Cane NCs", description)).ChecklistEntrySetCombinationTag("CCSC tasks").ChecklistEntrySetIDTag("CCSC")); + } + + } + +} + + + +// 2024 +//2024 +//Chest Mimic +RegisterResourceGenerationFunction("IOTMChestMimicGenerateResource"); +void IOTMChestMimicGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("Chest Mimic").familiar_is_usable()) return; + + // Title + int famExperienceGain = numeric_modifier("familiar experience") + 1; + int chestExperience = ($familiar[chest mimic].experience); + int famExpNeededForNextEgg = (50 - (chestExperience % 50)); + string fightsForNextEgg; + if (famExperienceGain > 0) { + fightsForNextEgg = pluralise(ceil(to_float(famExpNeededForNextEgg) / famExperienceGain), "fight", "fights"); + } + else { + fightsForNextEgg = "cannot get"; + } + int mimicEggsLeft = clampi(11 - get_property_int("_mimicEggsObtained"), 0, 11); + + string [int] description; + string url = "familiar.php"; + description.listAppend(`Currently have {HTMLGenerateSpanOfClass(chestExperience, "r_bold")} experience, currently gain {HTMLGenerateSpanOfClass(famExperienceGain, "r_bold")} fam exp per fight.`); + description.listAppend(`Need {HTMLGenerateSpanOfClass(famExpNeededForNextEgg, "r_bold")} more famxp for next egg. ({fightsForNextEgg})`); + description.listAppend(`Can lay {HTMLGenerateSpanOfClass(mimicEggsLeft, "r_bold")} more eggs today.`); + + resource_entries.listAppend(ChecklistEntryMake("__familiar chest mimic", url, ChecklistSubentryMake("Chest mimic fxp", "", description), -2)); + if ($item[mimic egg].available_amount() > 0) { + string header = $item[mimic egg].pluralise().capitaliseFirstLetter(); + string url = `inv_use.php?pwd={my_hash()}&whichitem=11542`; + resource_entries.listAppend(ChecklistEntryMake("__item mimic egg", url, ChecklistSubentryMake(header, "", "Fight some copies"), -1).ChecklistEntrySetCombinationTag("fax and copies")); + } +} + +//Spring shoes +RegisterTaskGenerationFunction("IOTMSpringShoesGenerateTasks"); +RegisterResourceGenerationFunction("IOTMSpringShoesGenerateResource"); + +void IOTMSpringShoesGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // Initialization. Do not generate if you don't have spring shoes. + if (!__iotms_usable[lookupItem("spring shoes")]) return; + + // Added a check for all paths where you do not want the tile at all: + // - Community Service: irrelevant + // - WereProfessor: is not a free run. + + boolean pathCheck = true; + pathCheck = my_path().id == PATH_COMMUNITY_SERVICE ? false : true; + pathCheck = my_path().id == PATH_WEREPROFESSOR ? false : true; + + // Technically, the available_amount here precludes the need for the initialization up top. + if (__misc_state["in run"] && available_amount($item[spring shoes]) > 0 && pathCheck) + { + if ($effect[everything looks green].have_effect() == 0) + { + string [int] description; + string url = "inventory.php?ftext=spring+shoes"; + description.listAppend(HTMLGenerateSpanFont("Free-run away from your problems with the Spring Away skill!", "green")); + if (lookupItem("spring shoes").equipped_amount() == 0) + { + description.listAppend(HTMLGenerateSpanFont("Equip the spring shoes first.", "red")); + } + task_entries.listAppend(ChecklistEntryMake("__item spring shoes", url, ChecklistSubentryMake("Spring shoes runaway available!", "", description), -11)); + } + } +} + +void IOTMSpringShoesGenerateResource(ChecklistEntry [int] resource_entries) +{ + // Initialization. Do not generate if you don't have spring shoes. + if (!__iotms_usable[lookupItem("spring shoes")]) return; + + string [int] banishDescription; + banishDescription.listAppend("All day banish, doesn't end combat"); + if (lookupItem("spring shoes").equipped_amount() == 0) + { + banishDescription.listAppend(HTMLGenerateSpanFont("Equip the spring shoes first.", "red")); + } + resource_entries.listAppend(ChecklistEntryMake("__skill spring shoes", "", ChecklistSubentryMake("Spring Kick", "", banishDescription), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Spring shoes spring kick banish")); +} +//Everfull Dart Holster via TES +RegisterTaskGenerationFunction("IOTMEverfullDartsGenerateTasks"); +void IOTMEverfullDartsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!__iotms_usable[$item[everfull dart holster]]) return; + + string [int] description; + string url = "inventory.php?ftext=everfull+dart_holster"; + + if ($effect[everything looks red].have_effect() == 0) { + int dartCooldown = 50; + if (get_property("everfullDartPerks").contains_text("You are less impressed by bullseyes")) { + dartCooldown -= 10; + } + if (get_property("everfullDartPerks").contains_text("Bullseyes do not impress you much")) { + dartCooldown -= 10; + } + description.listAppend(HTMLGenerateSpanFont(`Shoot a bullseye! ({dartCooldown} ELR)`, "red")); + if (lookupItem("everfull dart holster").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the dart holster first.", "red")); + } + else { + description.listAppend(HTMLGenerateSpanFont("Dart holster equipped", "blue")); + } + task_entries.listAppend(ChecklistEntryMake("__item everfull dart holster", url, ChecklistSubentryMake("Everfull Darts free kill available!", "", description), -11)); + } +} + +RegisterResourceGenerationFunction("IOTMEverfullDartsGenerateResource"); +void IOTMEverfullDartsGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[$item[everfull dart holster]] || !__misc_state["in run"]) return; + + string [int] description; + string url = "inventory.php?ftext=everfull+dart_holster"; + + int dartSkill = get_property_int("dartsThrown"); + if (dartSkill < 401) { + int dartsNeededForNextPerk = floor(sqrt(dartSkill) + 1) ** 2 - dartSkill; + description.listAppend(`Current dart skill: {dartSkill}`); + description.listAppend(`{HTMLGenerateSpanFont(dartsNeededForNextPerk, "blue")} darts needed for next Perk`); + + if (lookupItem("everfull dart holster").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the dart holster first.", "red")); + } + else { + description.listAppend(HTMLGenerateSpanFont("Dart holster equipped", "blue")); + } + resource_entries.listAppend(ChecklistEntryMake("__item everfull dart holster", url, ChecklistSubentryMake("🍑🎯 Everfull Dart Holster charging", "", description), 11)); + } +} + +// Apriling band helmet +RegisterResourceGenerationFunction("IOTMAprilingBandHelmetGenerateResource"); +void IOTMAprilingBandHelmetGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (available_amount($item[apriling band helmet]) < 1) + return; + + string [int] description; + + //battle of the bands + int aprilingBandConductorTimer = get_property_int("nextAprilBandTurn"); + string url = "inventory.php?pwd=" + my_hash() + "&action=apriling"; + + if (aprilingBandConductorTimer <= total_turns_played()) { + description.listAppend(HTMLGenerateSpanFont("You can change your tune!", "blue")); + if ($effect[Apriling Band Patrol Beat].have_effect() > 0) { + description.listAppend(HTMLGenerateSpanFont("-10% Combat Frequency", "blue")); + description.listAppend("+10% Combat Frequency"); + description.listAppend("+25% booze, +50% food, +100% candy"); + } + if ($effect[Apriling Band Battle Cadence].have_effect() > 0) { + description.listAppend("-10% Combat Frequency"); + description.listAppend(HTMLGenerateSpanFont("+10% Combat Frequency", "blue")); + description.listAppend("+25% booze, +50% food, +100% candy"); + } + if ($effect[Apriling Band Celebration Bop].have_effect() > 0) { + description.listAppend("+10% Combat Frequency"); + description.listAppend("-10% Combat Frequency"); + description.listAppend(HTMLGenerateSpanFont("+25% booze, +50% food, +100% candy", "blue")); + } + } + else { + description.listAppend((aprilingBandConductorTimer - total_turns_played()) + " adventures until you can change your tune."); + } + resource_entries.listAppend(ChecklistEntryMake("__item apriling band helmet", url, ChecklistSubentryMake("Apriling band helmet buff", "", description), 8)); + + int aprilingBandSaxUsesLeft = clampi(3 - get_property_int("_aprilBandSaxophoneUses"), 0, 3); + int aprilingBandQuadTomUsesLeft = clampi(3 - get_property_int("_aprilBandTomUses"), 0, 3); + int aprilingBandTubaUsesLeft = clampi(3 - get_property_int("_aprilBandTubaUses"), 0, 3); + int aprilingBandPiccoloUsesLeft = clampi(3 - get_property_int("_aprilBandPiccoloUses"), 0, 3); + int instrumentUses = get_property_int("_aprilBandSaxophoneUses") + + get_property_int("_aprilBandTomUses") + + get_property_int("_aprilBandTubaUses") + + get_property_int("_aprilBandPiccoloUses"); + + string [int] instrumentDescription; + + int aprilingBandInstrumentsAvailable = clampi(2 - get_property_int("_aprilBandInstruments"), 0, 2); + if (aprilingBandInstrumentsAvailable > 0) { + instrumentDescription.listAppend(HTMLGenerateSpanFont("Can pick " + aprilingBandInstrumentsAvailable + " more instruments!", "green")); + } + + if (instrumentUses < 6) { + string url = "inventory.php?ftext=apriling"; + if (aprilingBandSaxUsesLeft > 0 && available_amount($item[apriling band saxophone]) > 0) { + instrumentDescription.listAppend(`Can play the Sax {aprilingBandSaxUsesLeft} more times. {HTMLGenerateSpanFont("LUCKY!", "green")}`); + } + if (aprilingBandQuadTomUsesLeft > 0 && available_amount($item[apriling band quad tom]) > 0) { + instrumentDescription.listAppend(`Can play the Quad Toms {aprilingBandQuadTomUsesLeft} more times. {HTMLGenerateSpanFont("Sandworm!", "orange")}`); + } + if (aprilingBandTubaUsesLeft > 0 && available_amount($item[apriling band tuba]) > 0) { + instrumentDescription.listAppend(`Can play the Tuba {aprilingBandTubaUsesLeft} more times. {HTMLGenerateSpanFont("SNEAK!", "grey")}`); + } + if (aprilingBandPiccoloUsesLeft > 0 && available_amount($item[apriling band piccolo]) > 0) { + instrumentDescription.listAppend(`Can play the Piccolo {aprilingBandPiccoloUsesLeft} more times. {HTMLGenerateSpanFont("+40 fxp", "purple")}`); + } + resource_entries.listAppend(ChecklistEntryMake("__item apriling band helmet", url, ChecklistSubentryMake("Apriling band instruments", "", instrumentDescription), 8)); + } +} + +record MayamSymbol { + // Which ring the symbol is in + int ring; + + // Printable name for the symbol + string friendlyName; + + // What mafia calls the symbol + string mafiaName; + + // The player-friendly description of the symbol + string description; +}; + +void addToBothDescriptions(string [int] description1, string [int] description2, string text) { + description1.listAppend(text); + description2.listAppend(text); +} + +//Mayam calendar +RegisterResourceGenerationFunction("IOTMMayamCalendarGenerateResource"); +void IOTMMayamCalendarGenerateResource(ChecklistEntry [int] resource_entries) +{ + // Adding this prior to the check if the user has stinkbombs. + if ($item[stuffed yam stinkbomb].available_amount() > 0 ) + { + resource_entries.listAppend(ChecklistEntryMake("__item stuffed yam stinkbomb", "", ChecklistSubentryMake(pluralise($item[stuffed yam stinkbomb]), "", "Free run/banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Haunted doghouse banish")); + } + + if (available_amount($item[mayam calendar]) < 1) + return; + + MayamSymbol [int] mayamSymbols = { + new MayamSymbol(1, "A yam", "yam1", "craftable ingredient"), + new MayamSymbol(1, "Sword", "sword", `+{min(150, 10 * my_level())} mus stats`), + new MayamSymbol(1, "Vessel", "vessel", "+1000 MP"), + new MayamSymbol(1, "Fur", "fur", "+100 Fxp"), + new MayamSymbol(1, "Chair", "chair", "+5 free rests"), + new MayamSymbol(1, "Eye", "eye", "+30% item for 100 advs"), + new MayamSymbol(2, "Another yam", "yam2", "craftable ingredient"), + new MayamSymbol(2, "Lightning", "lightning", `+{min(150, 10 * my_level())} mys stats`), + new MayamSymbol(2, "Bottle", "bottle", "+1000 HP"), + new MayamSymbol(2, "Wood", "wood", "+4 bridge parts"), + new MayamSymbol(2, "Meat", "meat", `+{min(150, 10 * my_level())} meat`), + new MayamSymbol(3, "A third yam", "yam3", "craftable ingredient"), + new MayamSymbol(3, "Eyepatch", "eyepatch", `+{min(150, 10 * my_level())} mox stats`), + new MayamSymbol(3, "Wall", "wall", "+2 res for 100 advs"), + new MayamSymbol(3, "Cheese", "cheese", "+1 goat cheese"), + new MayamSymbol(4, "A fourth yam", "yam4", "yep."), + new MayamSymbol(4, "Clock", "clock", "+5 advs"), + new MayamSymbol(4, "Explosion", "explosion", "+5 fites") + }; + + string [int] description, hoverDescription; + + int templeResetAscension = get_property_int("lastTempleAdventures"); + addToBothDescriptions(description, hoverDescription, "Happy Mayam New Year!"); + + ChecklistEntry entry; + entry.url = "inv_use.php?pwd=" + my_hash() + "&which=99&whichitem=11572"; + entry.image_lookup_name = "mayam calendar"; + entry.tags.id = "Mayam Calendar"; + entry.importance_level = 8; + + if (!get_property("_mayamSymbolsUsed").contains_text("yam4") || + !get_property("_mayamSymbolsUsed").contains_text("clock") || + !get_property("_mayamSymbolsUsed").contains_text("explosion") || + my_ascensions() > templeResetAscension) + { + description.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); + hoverDescription.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); + + int[int] rings = {1, 2, 3, 4}; + foreach ring in rings { + string ringOrdinal = capitaliseFirstLetter(substring(int_to_ordinal(ring + 1), 1)); + hoverDescription.listAppend(HTMLGenerateSpanOfClass(`{ringOrdinal} ring:`, "r_bold")); + + string [int] unusedSymbols; + foreach index, mayamSymbol in mayamSymbols { + if (mayamSymbol.ring == ring + 1 && !get_property("_mayamSymbolsUsed").contains_text(mayamSymbol.mafiaName)) { + hoverDescription.listAppend(`- {HTMLGenerateSpanOfClass(mayamSymbol.friendlyName, "r_bold")}: {mayamSymbol.description}`); + unusedSymbols.listAppend(mayamSymbol.friendlyName); + } + } + description.listAppend(`{HTMLGenerateSpanOfClass(`{ringOrdinal} ring:`, "r_bold")} {unusedSymbols.listJoinComponents(", ")}`); + hoverDescription.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); + } + description.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); + + string [int] resonances; + resonances.listAppend(HTMLGenerateSpanOfClass("15-turn banisher", "r_bold") + ": Vessel + Yam + Cheese + Explosion"); + resonances.listAppend(HTMLGenerateSpanOfClass("Yam and swiss", "r_bold") + ": Yam + Meat + Cheese + Yam"); + resonances.listAppend(HTMLGenerateSpanOfClass("+55% meat accessory", "r_bold") + ": Yam + Meat + Eyepatch + Yam"); + resonances.listAppend(HTMLGenerateSpanOfClass("+100% Food drops", "r_bold") + ": Yam + Yam + Cheese + Clock"); + + addToBothDescriptions(description, hoverDescription, HTMLGenerateSpanOfClass("Cool Mayam combos!", "r_bold") + resonances.listJoinComponents("
").HTMLGenerateIndentedText()); + + if (my_ascensions() > templeResetAscension) { + addToBothDescriptions(description, hoverDescription, HTMLGenerateSpanFont("Temple reset available!", "r_bold") + ""); + } + + entry.subentries.listAppend(ChecklistSubentryMake("Mayam Calendar", "", description)); + entry.subentries_on_mouse_over.listAppend(ChecklistSubentryMake("Mayam Calendar", "", hoverDescription)); + resource_entries.listAppend(entry); + } +} + +//Roman Candelabra +RegisterTaskGenerationFunction("IOTMRomanCandelabraGenerateTasks"); +void IOTMRomanCandelabraGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[roman candelabra].available_amount() == 0) return; + + string url = "inventory.php?ftext=Roman+Candelabra"; + + // Extra runaway nag for spring shoes unhavers + if ($effect[Everything Looks Green].have_effect() == 0 && $item[spring shoes].available_amount() == 0) + { + string [int] description; + description.listAppend(HTMLGenerateSpanFont("Green candle runaway!", "green")); + if (lookupItem("Roman Candelabra").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the Roman Candelabra first.", "red")); + } + else { + description.listAppend(HTMLGenerateSpanFont("Candelbra equipped", "green")); + } + task_entries.listAppend(ChecklistEntryMake("__item Roman Candelabra", url, ChecklistSubentryMake("Roman Candelabra runaway available!", "", description), -11)); + } + + // Purple people beater + if ($effect[Everything Looks Purple].have_effect() == 0) + { + string [int] description; + if (lookupItem("Roman Candelabra").equipped_amount() == 0) + { + description.listAppend(HTMLGenerateSpanFont("Equip the Roman Candelabra, for your purple ray.", "red")); + } + else + { + description.listAppend(HTMLGenerateSpanFont("Candelbra equipped, blow your purple candle!", "purple")); + } + task_entries.listAppend(ChecklistEntryMake("__item Roman Candelabra", url, ChecklistSubentryMake("Roman Candelabra monster chain ready", "", description), -11)); + } +} + +// Mini-Kiwi +RegisterResourceGenerationFunction("IOTMMiniKiwiGenerateResource"); +void IOTMMiniKiwiGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("Mini Kiwi").familiar_is_usable()) return; + + // This familiar sucks. It's really bad. Still, fine to have a tile, I guess. + int miniKiwiCount = $item[mini kiwi].available_amount(); + float kiwiWeight = effective_familiar_weight($familiar[Mini Kiwi]) + weight_adjustment(); + float kiwiModifier = $item[aviator goggles].available_amount() > 0 ? 0.75 : 0.50; + + // Calculating the chance of a kiwi per fight; weight * your modifier + int kiwiChance = to_int(min(kiwiWeight * kiwiModifier,100.0)); + boolean kiwiSpiritsBought = get_property_boolean("_miniKiwiIntoxicatingSpiritsBought"); + int miniKiwiBikiniCount = $item[mini kiwi bikini].available_amount(); + + // Tile setup stuff + string [int] description; + string url = "familiar.php"; // Could send to the kwiki mart, but don't care enough. + string header = pluralise(miniKiwiCount, "mini kiwi available", "mini kiwis available"); + + description.listAppend(`At {to_int(kiwiWeight)} weight, you have a {kiwiChance}% chance of a mini kiwi each fight.`); + + if (!kiwiSpiritsBought) { + description.listAppend('|*Consider purchasing mini kiwi intoxicating spirits, for 3 kiwis.'); + } + + if (miniKiwiBikiniCount < 1 && get_property_int("zeppelinProtestors") < 80) { + description.listAppend('|*Consider purchasing mini kiwi bikinis, for the Zeppelin sleaze test.'); + } + + resource_entries.listAppend(ChecklistEntryMake("__familiar mini kiwi", url, ChecklistSubentryMake(header, "", description), 10)); + +} + +// Tearaway Pants +RegisterTaskGenerationFunction("IOTMTearawayPantsGenerateTask"); +void IOTMTearawayPantsGenerateTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // Don't show the tile if you don't have the pants. + if (!__iotms_usable[lookupItem("tearaway pants")]) return; + + // Don't show the tile if you aren't a moxie class. + if (!($classes[disco bandit,accordion thief] contains my_class())) return; + + // I can't believe I'm doing this. I have truly lost control of my life. + QuestState base_quest_state = __quest_state["Guild"]; + if (base_quest_state.finished || !base_quest_state.startable || base_quest_state.mafia_internal_step == 2) return; + + // Do you have the stupid pants equipped? + boolean havePantsEquipped = $slot[pants].equipped_item() == $item[tearaway pants]; + + string [int] description; + + // If equipped, send user to the guild. If not, send them to the inventory. + string url = havePantsEquipped ? "guild.php" : "inventory.php?ftext=tearaway+pants"; + string header = "Tear away your tearaway pants!"; + + if (havePantsEquipped) description.listAppend(`Visit the Department of Shadowy Arts and Crafts to unlock the guild!`); + if (!havePantsEquipped) description.listAppend(`Visit the Department of Shadowy Arts and Crafts with your pants equipped to unlock the guild!`); + + optional_task_entries.listAppend(ChecklistEntryMake("__item tearaway pants", url, ChecklistSubentryMake(header, "", description), 0)); + +} +// Sept-Ember Censer +RegisterResourceGenerationFunction("IOTMSeptemberCenserGenerateResource"); +void IOTMSeptemberCenserGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[Sept-Ember Censer].available_amount() == 0) return; + + int septEmbers = get_property_int("availableSeptEmbers"); + string [int] description; + float coldResistance = numeric_modifier("cold resistance"); + int mainstatGain = (7 * (coldResistance) ** 1.7) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); + string url = "shop.php?whichshop=september"; + string title = "Sept-Ember Censer"; + int bembershootCount = $item[bembershoot].available_amount(); + int mouthwashCount = $item[Mmm-brr! brand mouthwash].available_amount(); + int structureCount = $item[structural ember].available_amount(); + int hunkCount = $item[embering hunk].available_amount(); + boolean hulkFought = get_property_boolean("_emberingHulkFought"); + boolean structureUsed = get_property_boolean("_structuralEmberUsed"); + + if (septEmbers > 0) + { + description.listAppend(`Have {HTMLGenerateSpanFont(septEmbers, "red")} Sept-Embers to make stuff with!`); + } + + description.listAppend(`1 embers: +5 cold res accessory (You have {HTMLGenerateSpanFont(bembershootCount, "red")})`); + description.listAppend(`2 embers: mmm-brr! mouthwash for {HTMLGenerateSpanFont(mainstatGain, "blue")} mainstat. (You have {HTMLGenerateSpanFont(mouthwashCount, "red")})`); + + if (structureUsed) { + description.listAppend((HTMLGenerateSpanFont("Already used structural ember today", "red"))); + } else { + description.listAppend("4 embers: +5/5 bridge parts (1/day)"); + } + + if (hulkFought) { + description.listAppend((HTMLGenerateSpanFont("Already fought embering hulk today", "red"))); + } else { + description.listAppend("6 embers: embering hulk (1/day)"); + } + + description.listAppend(`(You have {HTMLGenerateSpanFont(hunkCount, "red")} hunks)`); + + resource_entries.listAppend(ChecklistEntryMake("__item sept-ember censer", url, ChecklistSubentryMake(title, "", description), 8)); +} + +// Bat Wings +RegisterTaskGenerationFunction("IOTMRomanBatWingsTasks"); +void IOTMRomanBatWingsTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[bat wings].available_amount() == 0) return; + + string [int] description; + string url; + // 25 bridge parts + int bridgeProg = get_property_int("chasmBridgeProgress"); + { + if (bridgeProg >= 25 && !locationAvailable($location[Oil Peak])) + { + if (lookupItem("bat wings").equipped_amount() == 0) { + url = "inventory.php?ftext=bat+wings"; + description.listAppend(HTMLGenerateSpanFont("Equip the bat wings first.", "red")); + } + else { + url = "place.php?whichplace=orc_chasm"; + description.listAppend(HTMLGenerateSpanFont("Leap across the bridge!", "blue")); + } + task_entries.listAppend(ChecklistEntryMake("__item miniature suspension bridge", url, ChecklistSubentryMake("Bat wings to cross the chasm!", "", description), -11)); + } + } +} + +RegisterResourceGenerationFunction("IOTMBatWingsGenerateResource"); +void IOTMBatWingsGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (available_amount($item[bat wings]) < 1) + return; + + string [int] description; + string url = "inventory.php?ftext=bat+wings"; + + //save the city of gotpork, battyman! + int batWingSwoopsLeft = clampi(11 - get_property_int("_batWingsSwoopUsed"), 0, 11); + int batWingRestsLeft = clampi(11 - get_property_int("_batWingsRestUsed"), 0, 11); + int batWingCauldronsLeft = clampi(11 - get_property_int("_batWingsCauldronUsed"), 0, 11); + int batWingFreeFlapsLeft = clampi(5 - get_property_int("_batWingsFreeFights"), 0, 5); + int bridge = get_property_int("chasmBridgeProgress"); + + if (lookupItem("bat wings").equipped_amount() == 0) + { + description.listAppend(HTMLGenerateSpanFont("Equip your bat wings.", "red")); + } + else + { + description.listAppend(HTMLGenerateSpanFont("Nanananananananana Battyman!", "purple")); + } + if (!$location[The Castle in the Clouds in the Sky (Basement)].locationAvailable()) { + description.listAppend(HTMLGenerateSpanFont("This saves turns in the Airshit!", "blue")); + } + if (batWingSwoopsLeft == 0) + { + description.listAppend(HTMLGenerateSpanFont("0 Swoop Evilpockets left.", "red")); + } + else + { + description.listAppend("Swoop Evilpockets: " + (HTMLGenerateSpanOfClass(batWingSwoopsLeft, "r_bold")) + " left."); + } + if (batWingRestsLeft == 0) + { + description.listAppend(HTMLGenerateSpanFont("0 Bat Rests left.", "red")); + } + else + { + description.listAppend("Rest +1000 HP/MP: " + (HTMLGenerateSpanOfClass(batWingRestsLeft, "r_bold")) + " left."); + } + if (batWingFreeFlapsLeft == 0) + { + description.listAppend(HTMLGenerateSpanFont("0 Free Flaps left.", "red")); + } + else + { + description.listAppend("Free flaps: " + (HTMLGenerateSpanOfClass(batWingFreeFlapsLeft, "r_bold")) + " left."); + } + + if (bridge >= 25 && !locationAvailable($location[Oil Peak])) { + description.listAppend("You can skip the rest of the bridge!"); + } + if (($locations[A Mob of Zeppelin Protesters] contains __last_adventure_location)) { + description.listAppend("This does... something useful!"); + } + + boolean guanoBat = get_property_boolean("batWingsGuanoJunction"); + + if (!guanoBat) { + description.listAppend("Visit the Bat Hole zones to unlock the Beanbat Chamber and get a bean"); + } + + resource_entries.listAppend(ChecklistEntryMake("__item bat wings", url, ChecklistSubentryMake("Bat Wings functions", "", description), 8)); +} + +// Clan VIP Photo booth +RegisterResourceGenerationFunction("IOTMVIPPhotoBoothGenerateResource"); +void IOTMVIPPhotoBoothGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (available_amount($item[Clan VIP Lounge key]) < 1) + return; + + string [int] description; + string url = "inventory.php?ftext=sheriff"; + + int photosLeft = clampi(3 - get_property_int("_photoBoothEffects"), 0, 3); + if (photosLeft > 0) + { + description.listAppend(HTMLGenerateSpanFont("Get your photo taken:", "black")); + description.listAppend(HTMLGenerateSpanFont("photobooth west: +50% init, +noncom%", "black")); + description.listAppend(HTMLGenerateSpanFont("photobooth tower: +com%", "black")); + description.listAppend(HTMLGenerateSpanFont("photobooth space: this sucks", "black")); + + resource_entries.listAppend(ChecklistEntryMake("__item expensive camera", url, ChecklistSubentryMake(photosLeft + " clan photos takeable", description), 8)); + } + //this here town ain't big enough for the two of us + int sheriffings = clampi(3 - get_property_int("_assertYourAuthorityCast"), 0, 3); + if (sheriffings > 0) + { + if (lookupItem("sheriff badge").equipped_amount() == 1 && lookupItem("sheriff moustache").equipped_amount() == 1 && lookupItem("sheriff pistol").equipped_amount() == 1) + { + description.listAppend(HTMLGenerateSpanFont("Assert your authority!", "blue")); + } + else + { + description.listAppend(HTMLGenerateSpanFont("Equip your sheriff gear first.", "red")); + } + resource_entries.listAppend(ChecklistEntryMake("__item badge of authority", url, ChecklistSubentryMake(sheriffings + " Sheriff Authority free kill(s)", description), 5)); + } +} + +RegisterResourceGenerationFunction("IOTMPeaceTurkeyGenerateResource"); +void IOTMPeaceTurkeyGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("Peace Turkey").familiar_is_usable()) return; + + // Purkey Title +//still needs a fix for famwt when not active (currently returns 0 but still functions) + int turkeyProc = 24; + if (my_familiar() == lookupFamiliar("peace turkey")); + { + int turkeyProc = 24 + sqrt(effective_familiar_weight($familiar[peace turkey]) + weight_adjustment()); + } + int PeasCount = available_amount($item[whirled peas]); + int PeaSoupCount = available_amount($item[handful of split pea soup]); + string [int] description; + string url = "familiar.php"; + { + description.listAppend("" + PeasCount + " peas available (need to paste them)"); + description.listAppend("" + PeaSoupCount + " peabanishers available"); + resource_entries.listAppend(ChecklistEntryMake("__familiar peace turkey", url, ChecklistSubentryMake(HTMLGenerateSpanFont(turkeyProc +"% Peace Turkey proc", "black"), "", description), 2)); + } + if ($item[handful of split pea soup].available_amount() > 0 ) + { + resource_entries.listAppend(ChecklistEntryMake("__item handful of split pea soup", "", ChecklistSubentryMake(pluralise($item[handful of split pea soup]), "", "Free run/banish. Also have " + PeasCount + " peas."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Purkey banish")); + } +} + +//Takerspace +RegisterResourceGenerationFunction("IOTMTakerspaceGenerateResource"); +void IOTMTakerspaceGenerateResource(ChecklistEntry [int] resource_entries) +{ + //you wouldn't download a boat + if (__iotms_usable[lookupItem("TakerSpace letter of Marque")]) return; + + string [int] description; + string url = "campground.php?action=workshed"; + int TSAnchors = get_property_int("takerSpaceAnchor"); + int TSGold = get_property_int("takerSpaceGold"); + int TSMasts = get_property_int("takerSpaceMast"); + int TSRum = get_property_int("takerSpaceRum"); + int TSSilk = get_property_int("takerSpaceSilk"); + int TSSpice = get_property_int("takerSpaceSpice"); + + if (TSAnchors + TSGold + TSMasts + TSRum + TSSilk + TSSpice > 0) + { + description.listAppend(HTMLGenerateSpanOfClass("Spices: ", "r_bold") + "" + TSSpice + ""); + description.listAppend(HTMLGenerateSpanOfClass("Rum: ", "r_bold") + "" + TSRum + ""); + description.listAppend(HTMLGenerateSpanOfClass("Anchors: ", "r_bold") + "" + TSAnchors + ""); + description.listAppend(HTMLGenerateSpanOfClass("Masts: ", "r_bold") + "" + TSMasts + ""); + description.listAppend(HTMLGenerateSpanOfClass("Silk: ", "r_bold") + "" + TSSilk + ""); + description.listAppend(HTMLGenerateSpanOfClass("Gold: ", "r_bold") + "" + TSGold + ""); + + if ($item[pirate dinghy].available_amount() == 0 ) { + description.listAppend(HTMLGenerateSpanFont("Boat: 1 anchor/1 mast/1 silk", "blue")); + } + if ($item[deft pirate hook].available_amount() == 0 ) { + description.listAppend(HTMLGenerateSpanFont("Hook: 1 anchor/1 mast/1 gold", "blue")); + } + if ($item[jolly roger flag].available_amount() == 0 ) { + description.listAppend(HTMLGenerateSpanFont("Flag: 1 rum/1 mast/1 silk/1 gold", "blue")); + } + resource_entries.listAppend(ChecklistEntryMake("__item pirate dinghy", url, ChecklistSubentryMake("Takerspace resources", description), 1)); + } +} + + +// 2024 +//CyberRealm +RegisterTaskGenerationFunction("IOTYCyberRealmGenerateTasks"); +void IOTYCyberRealmGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[server room key].available_amount() < 1) return; + + int CyberFree = get_property_int("_cyberFreeFights"); + int zone1Turns = get_property_int("_cyberZone1Turns"); + int zone2Turns = get_property_int("_cyberZone2Turns"); + int zone3Turns = get_property_int("_cyberZone3Turns"); + int CyberZoneLeft = zone1turns + zone2turns + zone3turns; + string [int] description; + string url = "place.php?whichplace=CyberRealm"; + string image_name = "__skill stats+++"; + + if ($item[familiar-in-the-middle wrapper].equipped_amount() == 1) { + description.listAppend(HTMLGenerateSpanFont("FITMW equipped. Extra 1 per fight.", "blue")); + } + else if ($item[familiar-in-the-middle wrapper].equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip your FITMW for an extra 1 per fight.", "red")); + } + + #if (zone1Turns < 20) + { + if (zone1Turns < 9) { + description.listAppend(9 - zone1Turns + " combats until Zone 1 Eleres test."); + } + else if (zone1Turns == 9) + { + description.listAppend(HTMLGenerateSpanFont("Get 11 eleres for the Cyberzone 1 test", "blue")); + image_name = "__skill overclock(10)"; + } + else if (zone1Turns < 19) + { + description.listAppend(19 - zone1Turns + " combats until Zone 1 reward."); + } + else if (zone1Turns == 19) + { + description.listAppend(HTMLGenerateSpanFont("Cyberzone 1 reward!", "green")); + image_name = "__skill sleep(5)"; + } + else if (zone1Turns > 19) { + description.listAppend(HTMLGenerateSpanFont("Cyberzone 1 finished.", "grey")); + } + } + + #if (zone2Turns < 20) + { + if (zone2Turns < 9) { + description.listAppend(9 - zone2Turns + " combats until Zone 2 Eleres test."); + } + else if (zone2Turns == 9) + { + description.listAppend(HTMLGenerateSpanFont("Get 11 eleres for the Cyberzone 2 test", "blue")); + image_name = "__skill overclock(10)"; + } + else if (zone2Turns < 19) + { + description.listAppend(19 - zone2Turns + " combats until Zone 2 reward."); + } + else if (zone2Turns == 19) + { + description.listAppend(HTMLGenerateSpanFont("Cyberzone 2 reward!", "green")); + image_name = "__skill sleep(5)"; + } + else if (zone2Turns > 19) { + description.listAppend(HTMLGenerateSpanFont("Cyberzone 2 finished.", "grey")); + } + } + + #if (zone3Turns < 20) + { + if (zone3Turns < 9) { + description.listAppend(9 - zone3Turns + " combats until Zone 3 Eleres test."); + } + else if (zone3Turns == 9) + { + description.listAppend(HTMLGenerateSpanFont("Get 11 eleres for the Cyberzone 3 test", "blue")); + image_name = "__skill overclock(10)"; + } + else if (zone3Turns < 19) + { + description.listAppend(19 - zone3Turns + " combats until Zone 3 reward."); + } + else if (zone3Turns == 19) + { + description.listAppend(HTMLGenerateSpanFont("Cyberzone 3 reward!", "green")); + image_name = "__skill sleep(5)"; + } + else if (zone3Turns > 19) { + description.listAppend(HTMLGenerateSpanFont("Cyberzone 3 finished.", "grey")); + } + } + + if (($locations[Cyberzone 1,Cyberzone 2,Cyberzone 3] contains __last_adventure_location)) + { + description.listAppend(HTMLGenerateSpanFont("Have " + (10 - CyberFree) + " free fights left!", "green")); + task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(60 - CyberZoneLeft + " CyberRealm adventures!", "", description), -11)); + } + else + { + if (get_property_int("_cyberFreeFights") < 10 && lookupSkill("OVERCLOCK(10)").have_skill()) { + description.listAppend(HTMLGenerateSpanFont("Have " + (10 - CyberFree) + " free fights left!", "green")); + } + else { + description.listAppend(HTMLGenerateSpanFont("No free fights left", "red")); + } + optional_task_entries.listAppend(ChecklistEntryMake(image_name, url, ChecklistSubentryMake(60 - CyberZoneLeft + " CyberRealm adventures!", "", description), 10)); + } +} + +RegisterResourceGenerationFunction("IOTYCyberRealmGenerateResource"); +void IOTYCyberRealmGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[server room key].available_amount() < 1) return; + + int CyberFree = clampi(10 - get_property_int("_cyberFreeFights"), 0, 10); + string url; + string [int] description; + + if (get_property_int("_cyberFreeFights") < 10 && lookupSkill("OVERCLOCK(10)").have_skill()) { + string url = "place.php?whichplace=CyberRealm"; + description.listAppend("Hack into the system!"); + resource_entries.listAppend(ChecklistEntryMake("__skill stats+++", url, ChecklistSubentryMake(pluralise(CyberFree, "CyberRealm fight", "CyberRealm fights"), "", description), 8).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("CyberRealm free fight")); + } +} + + +//Ski set +RegisterTaskGenerationFunction("IOTMSkiSetGenerateTasks"); +void IOTMSkiSetGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[McHugeLarge duffel bag].available_amount() < 1) return; + + if ($item[McHugeLarge duffel bag].available_amount() > 0 && $item[McHugeLarge right ski].available_amount() == 0) + { + task_entries.listAppend(ChecklistEntryMake("__item McHugeLarge duffel bag", "inventory.php?ftext=McHugeLarge+duffel+bag", ChecklistSubentryMake("McHugeLarge duffel bag", "", "Open it!"), -10).ChecklistEntrySetIDTag("McHugeLarge duffel bag resource")); + } +} + + +RegisterResourceGenerationFunction("IOTMSkiSetGenerateResource"); +void IOTMSkiSetGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[McHugeLarge duffel bag].available_amount() < 1) return; + + int skiAvalanchesLeft = clampi(3 - get_property_int("_mcHugeLargeAvalancheUses"), 0, 3); + int skiSlashesLeft = clampi(3 - get_property_int("_mcHugeLargeSlashUses"), 0, 3); + string [int] description; + string url = "inventory.php?ftext=McHugeLarge"; + + if (skiAvalanchesLeft > 0) + { + description.listAppend(HTMLGenerateSpanOfClass(skiSlashesLeft + " avalanches", "r_bold") + " left. Sneak!"); + //fixme: currently not supported by sneako tile + if (lookupItem("McHugeLarge left ski").equipped_amount() == 1) + { + description.listAppend(HTMLGenerateSpanFont("|*LEFT SKI equipped!", "blue")); + } + else if (lookupItem("McHugeLarge left ski").equipped_amount() == 0) + { + description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT SKI first.", "red")); + } + } + if (skiSlashesLeft > 0) + { + description.listAppend(HTMLGenerateSpanOfClass(skiSlashesLeft + " slashes", "r_bold") + " left. Track a monster."); + if (lookupItem("McHugeLarge left pole").equipped_amount() == 1) + { + description.listAppend(HTMLGenerateSpanFont("|*LEFT POLE equipped!", "blue")); + } + else if (lookupItem("McHugeLarge left pole").equipped_amount() == 0) + { + description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT POLE first.", "red")); + } + } + resource_entries.listAppend(ChecklistEntryMake("__item McHugeLarge duffel bag", url, ChecklistSubentryMake("McHugeLarge ski set skills", description), 1)); +} + +//leprecondo +RegisterTaskGenerationFunction("IOTMLeprecondoGenerateTasks"); +void IOTMLeprecondoGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[leprecondo].available_amount() == 0) return; + string url = "inv_use.php?pwd=" + my_hash() + "&which=99&whichitem=11861"; + string [int] description; + + int lepCondoChanges = clampi(3 - get_property_int("_leprecondoRearrangements"), 0, 3); + string lepCondoSetup = (get_property("leprecondoInstalled")); + if (lepCondoSetup == "0,0,0,0") { + description.listAppend("Decorate the Leprecondo"); + task_entries.listAppend(ChecklistEntryMake("__item leprecondo", url, ChecklistSubentryMake("Decorate your Leprecondo", "", description), -11)); + } +} + +RegisterResourceGenerationFunction("IOTMLeprecondoGenerateResource"); +void IOTMLeprecondoGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[leprecondo].available_amount() == 0) return; + string url = "inv_use.php?pwd=" + my_hash() + "&which=99&whichitem=11861"; + string [int] description; + + int lepCondoChanges = clampi(3 - get_property_int("_leprecondoRearrangements"), 0, 3); + string lepCondoCurrent = (get_property("leprecondoCurrentNeed")); + string lepCondoCycle = (get_property("leprecondoNeedOrder")); + string lepCondoSetup = (get_property("leprecondoInstalled")); + description.listAppend("Current setup: " + lepCondoSetup + "."); + if (lepCondoChanges > 0) { + description.listAppend(HTMLGenerateSpanFont("Can redecorate " + lepCondoChanges + " more times today.", "green")); + } + description.listAppend("Need cycle: " + lepCondoCycle + "."); + description.listAppend("Current need: " + lepCondoCurrent + "."); + + int nextCondoTurn = get_property_int("leprecondoLastNeedChange"); + + if (nextCondoTurn +5 <= turns_played()) { + description.listAppend(HTMLGenerateSpanFont("Condo trigger time!", "blue")); + } + else { + description.listAppend(HTMLGenerateSpanFont("Condo trigger in " + (nextCondoTurn +5 - turns_played()) + " advs.", "blue")); + } + int punchOutChanges = (get_property_int("preworkoutPowderUses")); + if (punchOutChanges > 0) + { + resource_entries.listAppend(ChecklistEntryMake("__item orange boxing gloves", "", ChecklistSubentryMake(pluralise(get_property_int("preworkoutPowderUses"), "Condo Punch", "Condo Punches"), "", "Free run/banish.")).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("condo punch banish")); + } + + resource_entries.listAppend(ChecklistEntryMake("__item leprecondo", url, ChecklistSubentryMake("Leprecondo stuff", description), 11)); +} +//shower thoughts +RegisterTaskGenerationFunction("IOTMAprilShowerThoughtsGenerateTasks"); +void IOTMAprilShowerThoughtsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[April Shower Thoughts shield].available_amount() == 0) return; + string url = "inventory.php?action=shower&pwd=" + my_hash(); + string [int] description; + + boolean showerGlobs = get_property_boolean("_aprilShowerGlobsCollected"); + if (showerGlobs == false) { + description.listAppend("Collect globs"); + task_entries.listAppend(ChecklistEntryMake("__item April Shower Thoughts shield", url, ChecklistSubentryMake("Shower for Globs", "", description), -11)); + } + if (lookupItem("april shower thoughts shield").equipped_amount() == 1) + { + string main_title = HTMLGenerateSpanFont("April Shower Powers", "black"); + boolean showerNEYR = get_property_boolean("_aprilShowerNorthernExplosion"); + if (showerNEYR == false) { + description.listAppend(HTMLGenerateSpanFont("Northern Explosion YR available", "blue")); + task_entries.listAppend(ChecklistEntryMake("__item april shower thoughts shield", "", ChecklistSubentryMake(main_title, description), -11).ChecklistEntrySetIDTag("april shower thoughts calendar tasks")); + } + } +} + +RegisterResourceGenerationFunction("IOTMAprilShowerThoughtsGenerateResource"); +void IOTMAprilShowerThoughtsGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[April Shower Thoughts shield].available_amount() == 0) return; + string url = "shop.php?whichshop=showerthoughts"; + string [int] description; + + string main_title = HTMLGenerateSpanFont("April Shower Powers", "black"); + boolean showerNEYR = get_property_boolean("_aprilShowerNorthernExplosion"); + if (showerNEYR == false) { + description.listAppend(HTMLGenerateSpanFont("Northern Explosion YR available", "blue")); + } + int globCount = available_amount($item[glob of wet paper]); + { + description.listAppend("Craft your shower thoughts, with your "+pluralise(globCount,"glob","globs")+"!"); + } + resource_entries.listAppend(ChecklistEntryMake("__item april shower thoughts shield", url, ChecklistSubentryMake(main_title, description), 10).ChecklistEntrySetIDTag("april shower thoughts calendar resource")); +} +//peridot of peril +RegisterTaskGenerationFunction("IOTMPeridotGenerateTasks"); +void IOTMPeridotGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[peridot of peril].available_amount() == 0) return; + string url = "inventory.php?ftext=peridot+of+peril"; + string [int] description; + + if (lookupItem("peridot of peril").equipped_amount() == 1) + { + description.listAppend(HTMLGenerateSpanFont("PERIDOT POWER!", "green")); + string main_title = HTMLGenerateSpanFont("Peridot picking power", "green"); + task_entries.listAppend(ChecklistEntryMake("__item peridot of peril", "", ChecklistSubentryMake(main_title, description), -11).ChecklistEntrySetIDTag("peridot task")); + } + else if (lookupItem("peridot of peril").equipped_amount() == 0 && (__misc_state["in run"])) + { + description.listAppend(HTMLGenerateSpanFont("Equip the peridot to map monsters", "red")); + optional_task_entries.listAppend(ChecklistEntryMake("__item peridot of peril", "", ChecklistSubentryMake("Peridot picking power", description), 10).ChecklistEntrySetIDTag("peridot task")); + } +} +//prismatic beret +RegisterResourceGenerationFunction("IOTMPrismaticBeretGenerateResource"); +void IOTMPrismaticBeretGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[prismatic beret].available_amount() == 0) return; + + string url = "inventory.php?ftext=prismatic+beret"; + int busksLeft = clampi(5 - get_property_int("_beretBuskingUses"), 0, 5); + string [int] description; + string title = HTMLGenerateSpanFont(busksLeft + " Prismatic Beret Busks", "purple"); + + int hatpower; + int pantspower; + int shartpower; + int total = 0; + item thing; + item shart2; + foreach shart in $slots[shirt] { + shart2 = equipped_item(shart); + if (shart2 != $item[none]) + shartpower += get_power(shart2); + } + foreach it in $slots[hat] { + thing = equipped_item(it); + if (thing != $item[none]) + hatpower += get_power(thing); + } + + foreach it in $slots[pants] { + thing = equipped_item(it); + if (thing != $item[none]) + pantspower += get_power(thing); + } + + if (busksLeft > 0) + { + if (lookupSkill("tao of the terrapin").have_skill()) total += hatpower*2 + pantspower*2; + if ($effect[Hammertime].have_effect() > 0) total += pantspower*3; + description.listAppend("Gain buffs based on current equipment Power"); + description.listAppend("Currently " + (HTMLGenerateSpanFont(shartpower+total, "blue")) + " Power"); + + if (lookupItem("prismatic beret").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip the beret to busk!", "red")); + } + if (lookupFamiliar("mad hatrack").familiar_is_usable() && $item[sane hatrack].is_unrestricted()) { + description.listAppend(HTMLGenerateSpanFont("(You can put it on your hatrack)", "blue")); + } + + resource_entries.listAppend(ChecklistEntryMake("__item prismatic beret", url, ChecklistSubentryMake(title, "", description))); + } +} +//cooler yeti +RegisterTaskGenerationFunction("IOTMCoolerYetiGenerateTasks"); +void IOTMCoolerYetiGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!lookupFamiliar("Cooler Yeti").familiar_is_usable()) return; + if (my_familiar() != lookupFamiliar("Cooler Yeti")) return; + string url = "familiar.php"; + string [int] description; + + int yetiExperience = ($familiar[cooler yeti].experience); + int famExpNeededFor400 = (400 - yetiExperience); + string fightsForYeti; + + if (!get_property_boolean("_coolerYetiAdventures")) { + if (yetiExperience >= 400) { + description.listAppend("" + HTMLGenerateSpanFont("Doublebooze ready!", "blue")); + string url = "main.php?talktoyeti=1"; + task_entries.listAppend(ChecklistEntryMake("__item dreadsylvanian cold-fashioned", url, ChecklistSubentryMake("Yeti booze time", description), -11).ChecklistEntrySetIDTag("cooler yeti booze time")); + } + } +} + +RegisterResourceGenerationFunction("IOTMCoolerYetiGenerateResource"); +void IOTMCoolerYetiGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("Cooler Yeti").familiar_is_usable()) return; + + // Title + int famExperienceGain = numeric_modifier("familiar experience") + 1; + int yetiExperience = ($familiar[cooler yeti].experience); + int famExpNeededFor400 = (400 - yetiExperience); + string [int] description; + string url = "familiar.php"; + string fightsForYeti; + string title = HTMLGenerateSpanFont("Cooler Yeti fxp", "blue"); + if (famExperienceGain > 0) { + fightsForYeti = pluralise(ceil(to_float(famExpNeededFor400) / famExperienceGain), "fight", "fights"); + } + else { + fightsForYeti = "cannot get"; + } + if (!get_property_boolean("_coolerYetiAdventures")) { + if (yetiExperience >= 400) { + description.listAppend(HTMLGenerateSpanOfClass("Doubles next booze adv", "r_bold") + " costs 400 fxp."); + url = "main.php?talktoyeti=1"; + } + } + if (yetiExperience >= 225) { + description.listAppend(HTMLGenerateSpanOfClass("100 advs of +100% item/meat", "r_bold") + " costs 225 fxp."); + } + + description.listAppend(`Currently have {HTMLGenerateSpanOfClass(yetiExperience, "r_bold")} experience, currently gain {HTMLGenerateSpanOfClass(famExperienceGain, "r_bold")} fam exp per fight.`); + if (yetiExperience < 400) { + description.listAppend(`Need {HTMLGenerateSpanOfClass(famExpNeededFor400, "r_bold")} more famxp for doublebooze. ({fightsForYeti})`); + } + + resource_entries.listAppend(ChecklistEntryMake("__familiar cooler yeti", url, ChecklistSubentryMake(title, "", description), -1)); +} +//allied radio backpack +RegisterResourceGenerationFunction("IOTTAlliedRadioBackpackGenerateResource"); +void IOTTAlliedRadioBackpackGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[allied radio backpack].available_amount() == 0) return; + + string url = "inventory.php?action=requestdrop&pwd=" + my_hash(); + int radioDropsLeft = clampi(3 - get_property_int("_alliedRadioDropsUsed"), 0, 3); + boolean usedIntel = get_property_boolean("_alliedRadioMaterielIntel"); + string [int] description; + string title = HTMLGenerateSpanFont(radioDropsLeft + " Allied Radio Drops", "black"); + + if (radioDropsLeft > 0) + { + description.listAppend("Request an airdrop!"); + description.listAppend("|*" + HTMLGenerateSpanOfClass("SNIPER SUPPORT", "r_bold") + " for a sneak!"); + if (!usedIntel) description.listAppend("|*" + HTMLGenerateSpanOfClass("MATERIAL INTEL", "r_bold") + " for +100% item! "+HTMLGenerateSpanFont("(10 turns)", "gray", "0.9em")); + description.listAppend("|*" + HTMLGenerateSpanOfClass("FUEL or RATIONS", "r_bold") + " for weak turngen!"); + resource_entries.listAppend(ChecklistEntryMake("__item allied radio backpack", url, ChecklistSubentryMake(title, "", description))); + } +} +// mobius ring +RegisterTaskGenerationFunction("IOTMMobiusRingGenerateTasks"); +void IOTMMobiusRingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + item mobRing = $item[Möbius ring]; + if (mobRing.available_amount() == 0) return; + + // Native game prefs. Note that my_paradoxicity() also exists! + int lastMobiusTurn = get_property_int("_lastMobiusStripTurn"); + int countMobiusNCs = get_property_int("_mobiusStripEncounters"); + int countTimeCops = get_property_int("_timeCopsFoughtToday"); + + // Is it equipped? + boolean mobEquipped = mobRing.equipped_amount() == 1; + + // There are clearly better ways to do this, but I'm tired and this + // is "fine." After 17 NCs, they'll all be 76 turns between, so cap + // inputs to 17. + + int [int] turnsBetweenNCs = {1:4, 2:7, 3:13, 4:19, 5:25, 6:31, 7:41, 8:41, 9:41, 10:41, 11:41, 12:51, 13:51, 14:51, 15:51, 16:51, 17:76}; + int turnsSinceLastNC = total_turns_played() - lastMobiusTurn; + int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - (lastMobiusTurn == 0 ? my_turncount() : turnsSinceLastNC)); + int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] + turnsUntilNextNC); + + // This is sort of a dumb way to do this too, but alas. + int [int] timeCopRate = { + 0:2, 1:2, 2:2, 3:2, 4:2, + 5:4, 6:4, 7:4, 8:4, 9:4, + 10:8, 11:8, 12:8, 13:8, 14:8, + 15:16, 16:16, 17:16, 18:16, 19:19, + 20:32}; + int currentTimeCopRate = timeCopRate[min(my_paradoxicity(), 20)]; + + // First, a generic time cop counter task. Low priority if you have + // freebies left, high priority if you don't. + string url = "inventory.php?ftext=bius+ring"; + string [int] copDescription; + string copSubTitle = "Forecast is "+currentTimeCopRate+"% chance of cops"; + string copTitle = HTMLGenerateSpanFont(pluralise(min(11-countTimeCops, 0), "free Time Cops fought today", "free Time Cops fought today"), "black"); + boolean copsNoLongerFree = countTimeCops > 11; + int priority = 10; + + if (mobEquipped) { + if (!copsNoLongerFree) { + copDescription.listAppend(HTMLGenerateSpanFont("Ring equipped, it's Möbing time!", "blue")); + optional_task_entries.listAppend(ChecklistEntryMake("__monster time cop", "", ChecklistSubentryMake(copTitle, copSubtitle, copDescription), priority).ChecklistEntrySetIDTag("morb ring cop task")); + } + if (copsNoLongerFree) + { + copDescription.listAppend(HTMLGenerateSpanFont("Möbius ring equipped, danger!", "red")); + priority = -11; + task_entries.listAppend(ChecklistEntryMake("__monster time cop", "", ChecklistSubentryMake(copTitle, copSubtitle, copDescription), priority).ChecklistEntrySetIDTag("morb ring cop task")); + } + } + + // Next, a supernag if you happen to have an NC available. (Demote from + // a supernag if you already have 11 free cops fought, though.) + string [int] ncDescription; + string ncTitle = "Möbius non-combat available!"; + string ncSubtitle = "Currently @ " + my_paradoxicity() + " paradoxicity"; + int ncPriority = copsNoLongerFree ? 0 : -11; + + if (mobEquipped) ncDescription.listAppend("Keep your Möbius ring equipped for an NC"); + if (!mobEquipped) ncDescription.listAppend(HTMLGenerateSpanFont("Equip your Möbius ring for a shot at a Paradoxicity NC!", "red")); + + if(turnsUntilNextNC == 0) task_entries.listAppend(ChecklistEntryMake("__item Möbius ring", "", ChecklistSubentryMake(ncTitle, ncSubtitle, ncDescription), ncPriority).ChecklistEntrySetIDTag("morb ring nc task")); + +} + +RegisterResourceGenerationFunction("IOTMMobiusRingGenerateResource"); +void IOTMMobiusRingGenerateResource(ChecklistEntry [int] resource_entries) +{ + item mobRing = $item[Möbius ring]; + if (mobRing.available_amount() == 0) return; + + // Native game prefs. Note that my_paradoxicity() also exists! + int lastMobiusTurn = get_property_int("_lastMobiusStripTurn"); + int countMobiusNCs = get_property_int("_mobiusStripEncounters"); + int countTimeCops = get_property_int("_timeCopsFoughtToday"); + + // Is it equipped? + boolean mobEquipped = mobRing.equipped_amount() == 1; + + // There are clearly better ways to do this, but I'm tired and this + // is "fine." After 17 NCs, they'll all be 76 turns between, so cap + // inputs to 17. + + int [int] turnsBetweenNCs = {1:4, 2:7, 3:13, 4:19, 5:25, 6:31, 7:41, 8:41, 9:41, 10:41, 11:41, 12:51, 13:51, 14:51, 15:51, 16:51, 17:76}; + int turnsSinceLastNC = total_turns_played() - lastMobiusTurn; + int turnsUntilNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 1)] - (lastMobiusTurn == 0 ? my_turncount() : turnsSinceLastNC)); + int turnsUntilNextNextNC = max(0, turnsBetweenNCs[min(17, countMobiusNCs + 2)] + turnsUntilNextNC); + + // This is sort of a dumb way to do this too, but alas. + int [int] timeCopRate = { + 0:2, 1:2, 2:2, 3:2, 4:2, + 5:4, 6:4, 7:4, 8:4, 9:4, + 10:8, 11:8, 12:8, 13:8, 14:8, + 15:16, 16:16, 17:16, 18:16, 19:19, + 20:32}; + int currentTimeCopRate = timeCopRate[min(my_paradoxicity(), 20)]; + + string [int] description; + string url = "inventory.php?ftext=bius+ring"; + string title = HTMLGenerateSpanFont(pluralise(turnsUntilNextNC, " turn", " turns") + " to your next Möbius NC", "black"); + + if (turnsUntilNextNC == 0) description.listAppend(HTMLGenerateSpanFont("You can encounter NC #" + (countMobiusNCs+1) +" right now!", "blue")); + if (turnsUntilNextNC > 0) description.listAppend("You have "+pluralise(turnsUntilNextNC, " turn", " turns")+" turns to NC #" +(countMobiusNCs+1)+ "."); + description.listAppend("|*You have at least "+pluralise(turnsUntilNextNextNC, " turn", " turns")+" until NC #"+(countMobiusNCs+2)+"."); + description.listAppend("" + countTimeCops +"/11 free time cops today. (currently @ "+currentTimeCopRate+"% rate)"); + if(countTimeCops > 11) description.listAppend(HTMLGenerateSpanFont("No free time cops remain; be careful wearing your ring!", "red")); + if(my_paradoxicity() < 13) description.listAppend("Boost to 13 Paradoxicity for +100% item & +50% booze drop!"); + resource_entries.listAppend(ChecklistEntryMake("__item Möbius ring", url, ChecklistSubentryMake(title, "", description), 0)); +} + + +RegisterTaskGenerationFunction("PathActuallyEdtheUndyingGenerateTasks"); +void PathActuallyEdtheUndyingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) return; + + int skills_available = MIN(15, my_level()) - MIN(15, my_level()) / 3 + get_property_int("edPoints"); //assumption + + skills_available = MIN(21, skills_available); + + int skills_have = 0; + foreach s in lookupSkillsInt($ints[17000,17001,17002,17003,17004,17005,17006,17007,17008,17009,17010,17011,17012,17013,17014,17015,17016,17017,17018,17019,17020]) + { + if (s.skill_is_usable()) + skills_have += 1; + } + //FIXME describe what the next three skills do...? + + if (skills_available > skills_have) + { + string image_name = "__skill wisdom of thoth"; + string [int] description; + description.listAppend("At least " + pluraliseWordy(skills_available - skills_have, "skill", "skills") + " available."); + + skill [int] desired_skill_order; + + if (get_property_int("edPoints") >= 5 && get_property("sleazeAirportAlways").to_boolean()) + { + desired_skill_order.listAppend($skill[Fist of the Mummy]); + desired_skill_order.listAppend($skill[Howl of the Jackal]); + desired_skill_order.listAppend($skill[Roar of the Lion]); + desired_skill_order.listAppend($skill[Prayer of Seshat]); + desired_skill_order.listAppend($skill[Wisdom of Thoth]); + desired_skill_order.listAppend($skill[Power of Heka]); + desired_skill_order.listAppend($skill[Hide of Sobek]); + desired_skill_order.listAppend($skill[Blessing of Serqet]); + desired_skill_order.listAppend($skill[Shelter of Shed]); + desired_skill_order.listAppend($skill[Bounty of Renenutet]); + + + desired_skill_order.listAppend($skill[Storm of the Scarab]); + desired_skill_order.listAppend($skill[Purr of the Feline]); + desired_skill_order.listAppend($skill[Lash of the Cobra]); + desired_skill_order.listAppend($skill[Wrath of Ra]); + + desired_skill_order.listAppend($skill[Curse of the Marshmallow]); + desired_skill_order.listAppend($skill[Curse of Indecision]); + desired_skill_order.listAppend($skill[Curse of Yuck]); + desired_skill_order.listAppend($skill[Curse of Heredity]); + desired_skill_order.listAppend($skill[Curse of Fortune]); + desired_skill_order.listAppend($skill[Curse of Vacation]); + + desired_skill_order.listAppend($skill[Curse of Stench]); + } + else + { + desired_skill_order.listAppend($skill[Fist of the Mummy]); + desired_skill_order.listAppend($skill[Prayer of Seshat]); + desired_skill_order.listAppend($skill[Wisdom of Thoth]); + desired_skill_order.listAppend($skill[Power of Heka]); + desired_skill_order.listAppend($skill[Hide of Sobek]); + desired_skill_order.listAppend($skill[Blessing of Serqet]); + desired_skill_order.listAppend($skill[Shelter of Shed]); + desired_skill_order.listAppend($skill[Bounty of Renenutet]); + + + desired_skill_order.listAppend($skill[Howl of the Jackal]); + desired_skill_order.listAppend($skill[Roar of the Lion]); + desired_skill_order.listAppend($skill[Storm of the Scarab]); + desired_skill_order.listAppend($skill[Purr of the Feline]); + desired_skill_order.listAppend($skill[Lash of the Cobra]); + desired_skill_order.listAppend($skill[Wrath of Ra]); + + desired_skill_order.listAppend($skill[Curse of the Marshmallow]); + desired_skill_order.listAppend($skill[Curse of Indecision]); + desired_skill_order.listAppend($skill[Curse of Yuck]); + desired_skill_order.listAppend($skill[Curse of Heredity]); + desired_skill_order.listAppend($skill[Curse of Fortune]); + desired_skill_order.listAppend($skill[Curse of Vacation]); + + desired_skill_order.listAppend($skill[Curse of Stench]); + } + skill [int] suggestions; + foreach key, s in desired_skill_order + { + if (s.have_skill()) + continue; + suggestions.listAppend(s); + if (suggestions.count() >= skills_available - skills_have) + break; + } + description.listAppend("Maybe " + suggestions.listJoinComponents(", ", "and") + "."); + optional_task_entries.listAppend(ChecklistEntryMake(image_name, "place.php?whichplace=edbase&action=edbase_book", ChecklistSubentryMake("Buy Undying skills", "", description), 11).ChecklistEntrySetIDTag("UNDYING path buy skills")); + } + + if (my_level() >= 13 && QuestState("questL13Final").finished) + { + if ($item[7965].available_amount() > 0 || $item[2334].available_amount() > 0) //holy macguffins + { + string [int] description; + description.listAppend("Finishes the path."); + if (availableSpleen() > 0) + description.listAppend("May want to fill your " + availableSpleen() + " extra spleen first."); + task_entries.listAppend(ChecklistEntryMake("Pyramid", "place.php?whichplace=edbase&action=edbase_altar", ChecklistSubentryMake("Put back the Holy MacGuffin", "", description), -10).ChecklistEntrySetIDTag("UNDYING path quest end path")); + } + else + { + //tutorial.php + string [int] modifiers; + string [int] description; + string url = "tutorial.php"; + + if (!$monster[warehouse janitor].is_banished()) + modifiers.listAppend("banish janitor"); + + description.listAppend("Adventure in the Secret Government Warehouse, use the items you find."); + + int progress_remaining = clampi(40 - get_property_int("warehouseProgress"), 0, 40); + if ($item[warehouse inventory page].available_amount() > 0 && $item[warehouse map page].available_amount() > 0) + { + description.listClear(); + description.listAppend("Use warehouse inventory page."); + url = "inventory.php?ftext=warehouse+inventory+page"; + } + else if (progress_remaining > 0) + { + if ($skill[Lash of the Cobra].have_skill()) + { + description.listAppend("Use lash of the cobra on the clerk and guard."); + } + else + { + modifiers.listAppend("+item"); + } + } + string [int] items_available; + foreach it in $items[warehouse inventory page,warehouse map page] + { + if (it.available_amount() > 0) + items_available.listAppend(pluraliseWordy(it)); + } + if (items_available.count() > 0) + { + description.listAppend(items_available.listJoinComponents(", ", "and").capitaliseFirstLetter() + " available."); + } + + string line;// = pluraliseWordy(progress_remaining, "remaining aisle", "remaining aisles").capitaliseFirstLetter() + "."; + if (progress_remaining <= 0) + line += "MacGuffin next turn"; + else + line += "Fight " + progress_remaining + " more combats"; + if (progress_remaining > 1) + { + int page_pairs_remaining = ceil(progress_remaining.to_float() / 8.0); + + /*string [int] bring_me_the_red_pages; + + int first_value = -1; + boolean identical_twins = false; + foreach it in $items[warehouse inventory page,warehouse map page] + { + int pages_remaining = page_pairs_remaining - it.available_amount(); + if (pages_remaining > 0) + { + if (first_value == -1) + first_value = pages_remaining; + else if (first_value == pages_remaining) + { + identical_twins = true; + bring_me_the_red_pages.listAppend(it); + continue; + } + bring_me_the_red_pages.listAppend(pluraliseWordy(pages_remaining, it)); + } + } + + if (identical_twins) + line += bring_me_the_red_pages.listJoinComponents("/"); + else + line += bring_me_the_red_pages.listJoinComponents(", ", "and");*/ + + line += " or collect "; + line += pluraliseWordy(page_pairs_remaining, "more page pair", "more page pairs"); + } + line += "."; + description.listAppend(line); + + task_entries.listAppend(ChecklistEntryMake("__item 2334", url, ChecklistSubentryMake("Retrieve the Holy MacGuffin", modifiers, description), $locations[The Secret Council Warehouse]).ChecklistEntrySetIDTag("UNDYING path quest final steps")); + } + } +} + +RegisterResourceGenerationFunction("PathActuallyEdtheUndyingGenerateResource"); +void PathActuallyEdtheUndyingGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_ACTUALLY_ED_THE_UNDYING) return; + item ka = $item[Ka coin]; + if (ka.available_amount() > 0) + { + string [int] description; + + string [int][int] ka_table; + + int haunches_edible = clampi(availableSpleen() / 5, 0, 7); + if (haunches_edible > $item[mummified beef haunch].available_amount()) + { + int haunches_want = haunches_edible - $item[mummified beef haunch].available_amount(); + //15 ka coin + string name; + if (haunches_want > 1) + name = pluralise(haunches_want, $item[mummified beef haunch]); + else + name = "mummified beef haunch"; + ka_table.listAppend(listMake(name, 15, "best spleen consumable")); + } + if ($item[linen bandages].available_amount() == 0 && $item[cotton bandages].available_amount() == 0 && $item[silk bandages].available_amount() == 0) + { + //linen bandages, 1 ka coin + ka_table.listAppend(listMake("linen bandages", 1, "when beaten up outside a fight")); + } + + //seven talisman of Renenutet (1 ka coin) + //talisman of Horus (5 ka coin, +combat) + int talismen_of_horus_wanted = 0; + if (!__quest_state["Level 8"].state_boolean["Mountain climbed"]) + talismen_of_horus_wanted += 2; + if (!__quest_state["Level 12"].state_boolean["Lighthouse Finished"] && $item[barrel of gunpowder].available_amount() < 5) + talismen_of_horus_wanted += 2; + if (talismen_of_horus_wanted == 0) //where else do you need +combat? pirate's cove? + talismen_of_horus_wanted = 1; + if ($item[talisman of Horus].available_amount() < talismen_of_horus_wanted) + { + ka_table.listAppend(listMake("talisman of Horus", 5, "+combat potion")); + } + ka_table.listAppend(listMake("talisman of Renenutet", 1, "+lots item for one combat")); + //body upgrades: + string [int][int] skill_upgrade_order; + skill_upgrade_order.listAppend(listMake("Extra Spleen", 5, "+5 spleen")); + skill_upgrade_order.listAppend(listMake("Another Extra Spleen", 10, "+5 spleen")); + skill_upgrade_order.listAppend(listMake("Yet Another Extra Spleen", 15, "+5 spleen")); + skill_upgrade_order.listAppend(listMake("Still Another Extra Spleen", 20, "+5 spleen")); + skill_upgrade_order.listAppend(listMake("Replacement Stomach", 30, "+5 stomach")); //fortune cookie + skill_upgrade_order.listAppend(listMake("Just One More Extra Spleen", 25, "+5 spleen")); + skill_upgrade_order.listAppend(listMake("Okay Seriously, This is the Last Spleen", 30, "+5 spleen")); + skill_upgrade_order.listAppend(listMake("Replacement Liver", 30, "can drink")); + skill_upgrade_order.listAppend(listMake("Upgraded Legs", 10, "+50% init")); + skill_upgrade_order.listAppend(listMake("More Legs", 20, "+50% init")); + skill_upgrade_order.listAppend(listMake("Elemental Wards", 10, "+1 all res")); + skill_upgrade_order.listAppend(listMake("More Elemental Wards", 20, "+2 all res")); + skill_upgrade_order.listAppend(listMake("Tougher Skin", 10, "+100 DA")); + skill_upgrade_order.listAppend(listMake("Even More Elemental Wards", 30, "+3 all res")); + skill_upgrade_order.listAppend(listMake("Upgraded Spine", 20, "+50% moxie")); + skill_upgrade_order.listAppend(listMake("Upgraded Arms", 20, "+50% muscle")); + skill_upgrade_order.listAppend(listMake("Armor Plating", 10, "+10 DR")); //marginal + //skill_upgrade_order.listAppend(listMake("Bone Spikes", 20)); + //skill_upgrade_order.listAppend(listMake("Arm Blade", 20)); + //skill_upgrade_order.listAppend(listMake("Healing Scarabs")); //only useful if it prevents beaten up from non-combats? + + foreach key in skill_upgrade_order + { + string [int] l = skill_upgrade_order[key]; + skill s = l[0].lookupSkill(); + int ka_cost = l[1].to_int_silent(); + string reason = l[2]; + if (s == $skill[none]) + break; + if (s.have_skill()) continue; + + + /*string line = "Could upgrade your body with " + s + "."; + if (ka_cost > ka.available_amount()) + line = HTMLGenerateSpanFont(line, "grey"); + description.listAppend(line);*/ + ka_table.listAppend(listMake(s, ka_cost, reason)); + break; + } + + if (ka_table.count() > 0) + { + foreach key in ka_table + { + int ka_needed = ka_table[key][1].to_int_silent(); + if (ka_needed > ka.available_amount()) + { + foreach key2 in ka_table[key] + { + ka_table[key][key2] = HTMLGenerateSpanFont(ka_table[key][key2], "grey"); + } + } + } + description.listAppend(HTMLGenerateSimpleTableLines(ka_table)); + } + + string url = ""; + string [int] places_to_farm_ka; + if (getHolidaysToday()["Halloween"]) + { + places_to_farm_ka.listAppend("trick or treating"); + url = "place.php?whichplace=town"; + } + if (__misc_state["spooky airport available"]) + { + places_to_farm_ka.listAppend("laboratory on conspiracy island"); + if (url.length() == 0) url = $location[the secret government laboratory].getClickableURLForLocation(); + } + if (__misc_state["hot airport available"]) + { + places_to_farm_ka.listAppend("smooch army HQ"); + if (url.length() == 0) url = $location[The SMOOCH Army HQ].getClickableURLForLocation(); + } + if (__misc_state["mysterious island available"] && !__quest_state["Level 12"].in_progress && my_level() < 9) //we test if we're under level 9 and the level 12 quest isn't in progress. maybe they ate a lot of hot dogs. it could happen! + { + places_to_farm_ka.listAppend("The Hippy Camp"); + if (url.length() == 0) url = $location[The Hippy Camp].getClickableURLForLocation(); + } + if (!__misc_state["mysterious island available"] && my_basestat($stat[mysticality]) < 40) + { + places_to_farm_ka.listAppend("sleazy back alley (last resort)"); + } + + if (places_to_farm_ka.count() > 0) + description.listAppend("Could farm ka in the " + places_to_farm_ka.listJoinComponents(", ", "or") + "."); + + resource_entries.listAppend(ChecklistEntryMake("__item ka coin", url, ChecklistSubentryMake(ka.pluralise(), "", description), 6).ChecklistEntrySetIDTag("UNDYING path spend ka coin")); + } + + if (true) + { + ChecklistSubentry [int] subentries; + string image_name = ""; + string [item] path_relevant_items; + + path_relevant_items[$item[talisman of Renenutet]] = "+lots% item in a single combat"; + path_relevant_items[$item[talisman of Horus]] = "+lots% combat potion"; + path_relevant_items[$item[ancient cure-all]] = "SGEEA-equivalent?"; + foreach s in $strings[linen bandages,cotton bandages,silk bandages] + { + if (lookupItem(s).available_amount() > 0) + { + path_relevant_items[lookupItem(s)] = "heal at zero HP"; + break; + } + } + foreach it, reason in path_relevant_items + { + if (it.available_amount() > 0) + { + subentries.listAppend(ChecklistSubentryMake(pluralise(it), "", reason.capitaliseFirstLetter() + ".")); + if (image_name.length() == 0) + image_name = "__item " + it; + } + } + if (subentries.count() > 0) + resource_entries.listAppend(ChecklistEntryMake(image_name, "", subentries, 6).ChecklistEntrySetIDTag("UNDYING path ed special items resource")); + } + + if ($skill[Lash of the cobra].have_skill() && mafiaIsPastRevision(15553)) + { + int lashes_remaining = 30 - get_property_int("_edLashCount"); + if (lashes_remaining > 0) + { + string [int] description; + string [int] stealables; + //Stuff: + //snake +ML + //badge of authority (HC) + //warehouse + //barret, aerith + //pygmy witch lawyers + //filthworms + //war hippy drill sergeant + //war outfit (if wrath of ra not available) + //pirate outfit? specific monsters left + //hot wings from p imp / g imp + //beanbats (if unlocked, else batrats/ratbats, else guano junction) + //skeletons in the nook + //topiary animals in twin peak + //dusken raider ghost (if oil needed) + //oil cartel(?) + if (stealables.count() > 0) + description.listAppend("Steals a random item:|*" + stealables.listJoinComponents("|*")); + else + description.listAppend("Steals a random item."); + + resource_entries.listAppend(ChecklistEntryMake("__item cool whip", "", ChecklistSubentryMake(pluralise(lashes_remaining, "lash", "lashes") + " of the cobra left", "", description), 6).ChecklistEntrySetIDTag("UNDYING path cobra lash resource")); + } + } +} + +boolean PathJarlsbergGenerateStaff(ChecklistEntry entry, item staff, string property_name, string description, boolean always_output) +{ + if (staff.available_amount() == 0) + return false; + + + int uses_remaining = MAX(0, 5 - get_property_int(property_name)); + if (uses_remaining > 0 || always_output) + { + string title; + title = staff; + if (uses_remaining != 0) + { + title = uses_remaining + " " + staff.to_string().replace_string("Staff of the ", ""); + if (staff == $item[Staff of the Standalone Cheese]) + { + if (uses_remaining == 1) + title += " staff banish"; + else + title += " staff banishes"; + } + else + { + if (uses_remaining == 1) + title += " use"; + else + title += " uses"; + } + } + //description = pluraliseWordy(uses_remaining, "use remains", "uses remain").capitaliseFirstLetter() + ".|" + description; + entry.subentries.listAppend(ChecklistSubentryMake(title, "", description)); + if (entry.image_lookup_name == "") + entry.image_lookup_name = "__item " + staff; + return true; + } + return false; +} + + +RegisterResourceGenerationFunction("PathJarlsbergGenerateResource"); +void PathJarlsbergGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_AVATAR_OF_JARLSBERG) return; + + ChecklistEntry entry; + entry.tags.id = "Jarlsberg path staff resource"; + + + //wizard staff: + //Show uses: + //_jiggleCheesedMonsters split by | + + PathJarlsbergGenerateStaff(entry, $item[Staff of the All-Steak], "_jiggleSteak", "+300% items.", false); + + if (true) + { + string olfacted_monster = get_property("_jiggleCreamedMonster"); + boolean always_output = false; + string cream_line = "Monster olfaction"; + if (olfacted_monster != "") + { + always_output = true; + cream_line += "|Following a " + olfacted_monster.HTMLEscapeString() + "."; + } + PathJarlsbergGenerateStaff(entry, $item[Staff of the Cream of the Cream], "_jiggleCream", cream_line, always_output); + } + if (true) + { + //I must capture the avatar (of jarlsberg) to regain my honor + string [int] banished_monsters = split_string_alternate(get_property("_jiggleCheesedMonsters"), "\\|"); + boolean always_output = false; + string cheese_line = ""; + if (get_property("_jiggleCheesedMonsters") != "") + { + cheese_line += "Monsters banished: " + banished_monsters.listJoinComponents(", ", "and").HTMLEscapeString() + "."; + always_output = true; + } + + ChecklistEntry entry2; + boolean should_add = PathJarlsbergGenerateStaff(entry2, $item[Staff of the Standalone Cheese], "_jiggleCheese", cheese_line, always_output); + entry2.tags.id = "Jarlsberg path staff banish"; + entry2.tags.combination = "banish"; + if (should_add) + resource_entries.listAppend(entry2); + } + PathJarlsbergGenerateStaff(entry, $item[Staff of the Staff of Life], "_jiggleLife", "Restores all HP.", false); + + if (entry.subentries.count() > 0) + resource_entries.listAppend(entry); +} + + + +RegisterResourceGenerationFunction("PathSneakyPeteGenerateResource"); +void PathSneakyPeteGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_AVATAR_OF_SNEAKY_PETE || !mafiaIsPastRevision(13785)) return; + + + ChecklistEntry entry; + entry.tags.id = "Sneaky Pete path skills resource"; + entry.importance_level = 1; + + if (true) + { + int total_free_peel_outs_available = 10; + if (get_property("peteMotorbikeTires") == "Racing Slicks") + total_free_peel_outs_available += 20; + + int free_peel_outs_available = MAX(0, total_free_peel_outs_available - get_property_int("_petePeeledOut")); + + if ($skill[Peel Out].skill_is_usable() && free_peel_outs_available > 0) + { + if (entry.image_lookup_name.length() == 0) + entry.image_lookup_name = "__skill Easy Riding"; + + ChecklistSubentry subentry = ChecklistSubentryMake(pluralise(free_peel_outs_available, "peel out", "peel outs"), "10 MP/cast", listMakeBlankString()); + + if (get_property("peteMotorbikeMuffler") == "Extra-Smelly Muffler") + { + subentry.entries.listAppend("Free runaway/banish in-combat."); + TagGroup tags; + tags.id = "Sneaky Pete path peel out banish"; + tags.combination = "banish"; + resource_entries.listAppend(ChecklistEntryMake("__skill Easy Riding", "", subentry, tags)); + } + else + { + subentry.entries.listAppend("Free runaway in-combat."); + entry.subentries.listAppend(subentry); + } + } + } + + if ($skill[Fix Jukebox].skill_is_usable() && get_property_int("_peteJukeboxFixed") < 3) + { + int uses_remaining = MAX(0, 3 - get_property_int("_peteJukeboxFixed")); + + string [int] description; + description.listAppend("+300% item, one combat."); + description.listAppend("+10 audience love."); + + if (entry.image_lookup_name.length() == 0) + entry.image_lookup_name = "__effect jukebox hero"; + + string [int] targets; + //√banshee, √a batrat for sonar, √harem girl (contested), √burly sidekick, √quiet healer, √filthworms, √f'c'le without natural dancer, √a-boo clues + if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && !__quest_state["Level 11 Desert"].state_boolean["Killing Jar Given"] && $item[killing jar].available_amount() == 0) + targets.listAppend("Haunted Library - Banshee - Killing Jar to speed up desert exploration."); + if (__quest_state["Level 4"].state_int["areas unlocked"] + $item[sonar-in-a-biscuit].available_amount() < 3) + targets.listAppend("Batrat/Ratbat - Sonar-in-a-biscuit."); + + if (!have_outfit_components("Knob Goblin Elite Guard Uniform") && !have_outfit_components("Knob Goblin Harem Girl Disguise") && !__quest_state["Level 5"].finished) + targets.listAppend("Harem Girl - disguise for quest. (20% drop)"); + + if (!__quest_state["Level 10"].finished && $item[mohawk wig].available_amount() == 0 && $item[s.o.c.k.].available_amount() == 0) + targets.listAppend("Burly Sidekick (Mohawk wig) - speed up top floor of castle."); + if ($item[amulet of extreme plot significance].available_amount() == 0 && !__quest_state["Level 10"].finished && !$location[The Castle in the Clouds in the Sky (Ground floor)].locationAvailable() && $item[s.o.c.k.].available_amount() == 0) + targets.listAppend("Quiet Healer (amulet of extreme plot significance) - speed up castle basement."); + if (!__quest_state["Level 12"].state_boolean["Orchard Finished"]) + targets.listAppend("Filthworms."); + + if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0 && $item[a-boo clue].available_amount() < 3) + targets.listAppend("A-Boo Peak - a-boo clues. (15% drop)"); + + if (targets.count() > 0) + description.listAppend("Potential targets:|*" + targets.listJoinComponents("
|*")); + + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(uses_remaining, "jukebox fix", "jukebox fixes"), "25 MP", description)); + } + + if ($skill[Jump Shark].skill_is_usable() && get_property_int("_peteJumpedShark") < 3) + { + int uses_remaining = MAX(0, 3 - get_property_int("_peteJumpedShark")); + + string [int] description; + description.listAppend((10 * my_level()) + " muscle/mysticality/moxie. (increases with level)"); + description.listAppend("+10 audience hate."); + + if (entry.image_lookup_name.length() == 0) + entry.image_lookup_name = "__skill jump shark"; + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(uses_remaining, "shark jump", "shark jumps"), "25 MP", description)); + } + + + if (entry.subentries.count() > 0) + resource_entries.listAppend(entry); +} + +RegisterTaskGenerationFunction("PathSneakyPeteGenerateTasks"); +void PathSneakyPeteGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_AVATAR_OF_SNEAKY_PETE || !mafiaIsPastRevision(13785)) return; + + + if (true) + { + string [int] parts_not_upgraded; + int motorcycle_upgrades_have = 0; + + foreach s in $strings[peteMotorbikeTires,peteMotorbikeGasTank,peteMotorbikeHeadlight,peteMotorbikeCowling,peteMotorbikeMuffler,peteMotorbikeSeat] + { + if (get_property(s) != "") + motorcycle_upgrades_have += 1; + else + parts_not_upgraded.listAppend(s); + } + int motorcycle_upgrades_available = MIN(6, my_level() / 2); + + if (motorcycle_upgrades_have < motorcycle_upgrades_available) + { + string [int] description; + description.listAppend(pluralise(motorcycle_upgrades_available - motorcycle_upgrades_have, "upgrade", "upgrades") + " available."); + + string [int] upgrades; + foreach key in parts_not_upgraded + { + string property_name = parts_not_upgraded[key]; + + string name = ""; + string [int] options; + + if (property_name == "peteMotorbikeSeat") + { + name = "Seat"; + + options.listAppend("regenerate 5-6 HP/MP"); + options.listAppend("find meat after combat (marginal)"); + options.listAppend("-30 ML (harmful)"); + } + else if (property_name == "peteMotorbikeCowling") + { + name = "Cowling"; + if (__quest_state["Level 7"].state_int["alcove evilness"] > 26 || __quest_state["Level 7"].state_int["cranny evilness"] > 26 || __quest_state["Level 7"].state_int["niche evilness"] > 26 || __quest_state["Level 7"].state_int["nook evilness"] > 26) + options.listAppend("faster cyrpt"); + if (__quest_state["Level 12"].finished) + options.listAppend("passive +damage/round"); + else + options.listAppend("passive +damage/round and +3 war kills"); + options.listAppend("+5 stats/fight"); + } + else if (property_name == "peteMotorbikeGasTank") + { + name = "Gas tank"; + + if (!knoll_available() && !__misc_state["desert beach available"]) + options.listAppend("desert beach access"); + if (!__misc_state["mysterious island available"]) + options.listAppend("mysterious island access"); + options.listAppend("+50% combat initiative"); + } + else if (property_name == "peteMotorbikeHeadlight") + { + name = "Headlight"; + + if ($skill[Flash Headlight].skill_is_usable()) + { + options.listAppend("yellow ray from flash headlight"); + options.listAppend("prismatic damage from flash headlight"); + } + else + { + options.listAppend("yellow ray (need flash headlight)"); + options.listAppend("prismatic damage (need flash headlight)"); + } + if (!__quest_state["Level 11 Desert"].state_boolean["Desert Explored"]) + options.listAppend("+2% desert exporation"); + } + else if (property_name == "peteMotorbikeMuffler") + { + name = "Muffler"; + if ($skill[Rev Engine].skill_is_usable()) + { + options.listAppend("+combat% from rev engine"); + options.listAppend("-combat% from rev engine"); + } + else + { + options.listAppend("+X% combat from rev engine (need skill)"); + options.listAppend("-X% combat from rev engine (need skill)"); + } + if ($skill[Peel Out].skill_is_usable()) + options.listAppend("peel out banishes"); + else + options.listAppend("peel out banishes (need skill)"); + } + else if (property_name == "peteMotorbikeTires") + { + name = "Tires"; + if ($skill[Peel Out].skill_is_usable()) + options.listAppend("extra free runs with peel out"); + else + options.listAppend("extra free runs (need peel out)"); + if ($skill[Pop Wheelie].skill_is_usable()) + options.listAppend("pop wheelie does more damage"); + else + options.listAppend("pop wheelie does more damage (need skill)"); + + if (!__quest_state["Level 8"].state_boolean["Mountain climbed"]) + options.listAppend("near-instant level 8 quest completion"); + } + + if (name != "") + { + upgrades.listAppend(HTMLGenerateSpanOfClass(name, "r_bold") + " - " + options.listJoinComponents(", ", "or").capitaliseFirstLetter() + "."); + //upgrades.listAppend(HTMLGenerateSpanOfClass(name, "r_bold") + "|*" + options.listJoinComponents("|*")); + } + } + description.listAppendList(upgrades); + + + optional_task_entries.listAppend(ChecklistEntryMake("__skill Easy Riding", "main.php?action=motorcycle", ChecklistSubentryMake("Upgrade your bike", "", description), 11).ChecklistEntrySetIDTag("Sneaky Pete path upgrade motorcycle")); + } + } + + if ($skill[Check Mirror].skill_is_usable()) + { + boolean have_intrinsic = false; + foreach s in $strings[1553,Pompadour,Cowlick,Fauxhawk] + { + effect e = s.lookupEffect(); + if (e == $effect[none]) + { + have_intrinsic = true; //can't track + continue; + } + if (e.have_effect() == 2147483647) + have_intrinsic = true; + } + if (!have_intrinsic) + { + string [int] description; + + description.listAppend("One adventure cost for an intrinsic."); + string [int] options; + options.listAppend("+3 all resistances (slicked-back do)"); + options.listAppend("+3 stats/fight (best, pompadour)"); + if (my_audience() >= 20) + options.listAppend("+50% meat (cowlick)"); + else + options.listAppend(HTMLGenerateSpanFont("+50% meat (requires 20 love)", "grey")); + if (my_audience() <= -20) + options.listAppend("+50% init (fauxhawk)"); + else + options.listAppend(HTMLGenerateSpanFont("+50% init (requires 20 hate)", "grey")); + + //description.listAppend("Potential options:|*|*|*+|*"); + description.listAppend("Potential options:|*" + options.listJoinComponents("|*")); + optional_task_entries.listAppend(ChecklistEntryMake("__skill Check Mirror", "skills.php", ChecklistSubentryMake("Check mirror", "", description), 11).ChecklistEntrySetIDTag("Sneaky Pete path mirror")); + } + } + int audience_max = 30; + if ($item[Sneaky Pete's leather jacket].equipped_amount() > 0 || $item[Sneaky Pete's leather jacket (collar popped)].equipped_amount() > 0) + { + audience_max = 50; + } + if ($skill[Throw Party].skill_is_usable() && my_audience() == audience_max && !get_property_boolean("_petePartyThrown")) + task_entries.listAppend(ChecklistEntryMake("__item party hat", "skills.php", ChecklistSubentryMake("Throw a party!", "", "Drinks."), -11).ChecklistEntrySetIDTag("Sneaky Pete path party andience")); + if ($skill[Incite Riot].skill_is_usable() && my_audience() == -audience_max && !get_property_boolean("_peteRiotIncited")) + task_entries.listAppend(ChecklistEntryMake("__item fire", "skills.php", ChecklistSubentryMake("Incite a riot", "", "Breaking the law, breaking the law."), -11).ChecklistEntrySetIDTag("Sneaky Pete path riot audience")); + + //sneakyPetePoints first + int skills_available = MIN(30, MIN(15, my_level()) + get_property_int("sneakyPetePoints")); + + int skills_have = 0; + //foreach s in lookupSkills("Catchphrase,Mixologist,Throw Party,Fix Jukebox,Snap Fingers,Shake It Off,Check Hair,Cocktail Magic,Make Friends,Natural Dancer,Rev Engine,Born Showman,Pop Wheelie,Rowdy Drinker,Peel Out,Easy Riding,Check Mirror,Riding Tall,Biker Swagger,Flash Headlight,Insult,Live Fast,Incite Riot,Jump Shark,Animal Magnetism,Smoke Break,Hard Drinker,Unrepentant Thief,Brood,Walk Away From Explosion") + foreach s in lookupSkillsInt($ints[15027,15019,15012,15028,15001,15007,15017,15008,15016,15004,15020,15025,15031,15021,15024,15023,15009,15002,15010,15015,15013,15011,15018,15014,15006,15026,15005,15003,15032,15030]) + { + if (s.skill_is_usable()) + skills_have += 1; + } + + if (skills_available > skills_have) + { + string [int] description; + description.listAppend("At least " + pluraliseWordy(skills_available - skills_have, "skill", "skills") + " available."); + optional_task_entries.listAppend(ChecklistEntryMake("__skill Natural Dancer", "da.php?place=gate3", ChecklistSubentryMake("Buy Sneaky Pete skills", "", description), 11).ChecklistEntrySetIDTag("Sneaky Pete path new skills")); + } +} + + +RegisterResourceGenerationFunction("PathAvatarOfWestOfLoathingGenerateResource"); +void PathAvatarOfWestOfLoathingGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING && !($classes[snake oiler,beanslinger,cow puncher] contains my_class())) return; + + //Oils: + string image_name = ""; + ChecklistSubentry [int] subentries; + + if (mafiaIsPastRevision(16881) && $skill[Extract Oil].have_skill()) + { + int oils_extracted = get_property_int("_oilExtracted"); + int oils_remaining = clampi(15 - oils_extracted, 0, 15); + if (oils_extracted < 15) + { + string description; + if (oils_extracted >= 5) + { + int percentage_left = clampi(100 - (oils_extracted - 5) * 10, 0, 100); + description = percentage_left + "% chance."; + } + item monster_oil_type = lookupAWOLOilForMonster(last_monster()); + if (monster_oil_type != $item[none]) + { + if (description != "") + description += " "; + description += monster_oil_type.capitaliseFirstLetter() + " against " + last_monster() + "."; + } + if (image_name == "") + image_name = "__item Snake oil"; + subentries.listAppend(ChecklistSubentryMake(pluralise(oils_remaining, "extractable oil", "extractable oils"), "", description)); + } + } + float [int] subentries_sort_value; + + string [item] tonic_descriptions; + tonic_descriptions[$item[Eldritch oil]] = "craftable"; + tonic_descriptions[$item[Unusual oil]] = "+50% item (20 turns), craftable"; + tonic_descriptions[$item[Skin oil]] = "+100% moxie (20 turns), craftable"; + tonic_descriptions[$item[Snake oil]] = "+venom/medicine, craftable"; + + tonic_descriptions[$item[patent alacrity tonic]] = "+100% init (20 turns)"; //eldritch + unusual + tonic_descriptions[$item[patent sallowness tonic]] = "+30 ML (50 turns)"; //eldritch + skin + tonic_descriptions[$item[patent avarice tonic]] = "+50% meat (30 turns)"; //skin + unusual + tonic_descriptions[$item[patent invisibility tonic]] = "-15% combat (30 turns)"; //eldritch + snake + tonic_descriptions[$item[patent aggression tonic]] = "+15% combat (30 turns)"; //unusual + snake + tonic_descriptions[$item[patent preventative tonic]] = "+3 all res (30 turns)"; //skin + snake + + foreach it in tonic_descriptions + { + if (it.available_amount() == 0 && it.creatable_amount() == 0) + continue; + + string description = tonic_descriptions[it]; + if (image_name == "") + image_name = "__item " + it; + string name; + if (it.available_amount() > 0) + name = pluralise(it); + if (it.creatable_amount() > 0) + { + if (it.available_amount() != 0) + name += " (" + it.creatable_amount() + " craftable)"; + else + name = pluralise(it.creatable_amount(), "craftable " + it, "craftable " + it.plural); + } + if (it.available_amount() == 0) + { + subentries_sort_value[subentries.count()] = 1.0; + name = HTMLGenerateSpanFont(name, "grey"); + description = HTMLGenerateSpanFont(description, "grey"); + } + else + { + subentries_sort_value[subentries.count()] = 0.0; + } + subentries.listAppend(ChecklistSubentryMake(name, "", description)); + } + sort subentries by subentries_sort_value[index]; + if (subentries.count() > 0) + resource_entries.listAppend(ChecklistEntryMake(image_name, "", subentries, 2).ChecklistEntrySetIDTag("West Loathing path oils resource")); + + + //Should we display beancannon in aftercore? I guess we could suggest a cheap source of it...? Maybe another time. + if ($skill[Beancannon].have_skill() && in_ronin()) + { + string [int] banish_sources; + int banish_count = 0; + int equipped_amount = 0; + foreach it in __beancannon_source_items + { + if (it.available_amount() == 0) + continue; + banish_count += it.available_amount(); + string description = it; + if (it.available_amount() > 1) + description = it.pluralise(); + equipped_amount += it.equipped_amount(); + banish_sources.listAppend(description); + } + if (banish_count > 0 || !in_ronin()) + { + string [int] description; + if (banish_sources.count() > 0) + description.listAppend("From " + banish_sources.listJoinComponents(", ", "and").capitaliseFirstLetter() + "."); + string url = ""; + if (equipped_amount == 0) + { + description.listAppend("Equip one before banishing."); + url = "inventory.php?which=2"; + } + string title = pluralise(banish_count, "beancannon banish", "beancannon banishes"); + if (!in_ronin()) + title = "Beancannon banishes"; + resource_entries.listAppend(ChecklistEntryMake("__skill beancannon", url, ChecklistSubentryMake(title, "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("West Loathing path beancannon banish")); + } + } + + if ($skill[Long Con].have_skill() && mafiaIsPastRevision(16812) && get_property_int("_longConUsed") < 5) + { + int uses_remaining = clampi(5 - get_property_int("_longConUsed"), 0, 5); + string [int] description; + string line = "Olfaction."; + description.listAppend(line); + resource_entries.listAppend(ChecklistEntryMake("__effect Greaser Lightnin'", "", ChecklistSubentryMake(pluralise(uses_remaining, "long con", "long cons") + " remaining", "", description), 8).ChecklistEntrySetIDTag("West Loathing path long con resource")); + } +} + + +RegisterTaskGenerationFunction("PathAvatarOfWestOfLoathingGenerateTasks"); +void PathAvatarOfWestOfLoathingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_AVATAR_OF_WEST_OF_LOATHING) + return; + string skill_url; + ChecklistSubentry [int] skill_subentries; + + int [class] class_points; + class_points[my_class()] = my_level(); + class_points[$class[Cow Puncher]] += get_property_int("awolPointsCowpuncher"); + class_points[$class[Beanslinger]] += get_property_int("awolPointsBeanslinger"); + class_points[$class[Snake Oiler]] += get_property_int("awolPointsSnakeoiler"); + + item [class] tale_for_class; + tale_for_class[$class[Cow Puncher]] = $item[Tales of the West: Cow Punching]; + tale_for_class[$class[Beanslinger]] = $item[Tales of the West: Beanslinging]; + tale_for_class[$class[Snake Oiler]] = $item[Tales of the West: Snake Oiling]; + + boolean [class] have_advanced_skills_for_class; + if ($skill[Unleash Cowrruption].have_skill() || $skill[[18008]Hard Drinker].have_skill() || $skill[Walk: Cautious Prowl].have_skill()) + have_advanced_skills_for_class[$class[Cow Puncher]] = true; + if ($skill[Beancannon].have_skill() || $skill[Prodigious Appetite].have_skill() || $skill[Walk: Prideful Strut].have_skill()) + have_advanced_skills_for_class[$class[Beanslinger]] = true; + if ($skill[Long Con].have_skill() || $skill[Tolerant Constitution].have_skill() || $skill[Walk: Leisurely Amble].have_skill()) + have_advanced_skills_for_class[$class[Snake Oiler]] = true; + float priority = 0; + foreach c in class_points + { + int total_points_available = class_points[c]; + if (total_points_available == 0) + continue; + + int class_skills_learned = 0; + foreach key, s in __skills_by_class[c] + { + if (s.have_skill()) + class_skills_learned += 1; + } + if (class_skills_learned >= 10) + continue; + + int skills_left_to_learn = total_points_available - class_skills_learned; + if (skills_left_to_learn <= 0) + continue; + + int limit = 7; //theoretically, they might be unable to learn the advanced skills, so only make this a priority if we're under that or know we have advanced skills + if (have_advanced_skills_for_class[c]) + limit = 10; + if (class_skills_learned < limit) + priority = -11; + item tale = tale_for_class[c]; + + string title = "Learn a " + c + " skill"; + if (skills_left_to_learn > 1) + title = "Learn " + skills_left_to_learn.int_to_wordy() + " " + c + " skills"; + if (skill_url == "") + { + skill_url = "inv_use.php?pwd=" + my_hash() + "&whichitem=" + tale.to_int(); + } + skill_subentries.listAppend(ChecklistSubentryMake(title, "", "Use " + tale + ".")); + } + + if (skill_subentries.count() > 0) + { + task_entries.listAppend(ChecklistEntryMake("__item tales of the west: beanslinging", skill_url, skill_subentries, priority).ChecklistEntrySetIDTag("West Loathing path new skills")); + } + + if (my_class() == $class[Cow Puncher] && $item[corrupted marrow].available_amount() > 0 && $item[corrupted marrow].to_effect().have_effect() < 100 && in_ronin()) + { + task_entries.listAppend(ChecklistEntryMake("__effect Cowrruption", "inventory.php?ftext=corrupted+marrow", ChecklistSubentryMake("Use corrupted marrow", "", "+200% weapon damage/spell damage"), -11).ChecklistEntrySetIDTag("West Loathing path cow puncher corrupted marrow")); + } +} + + +RegisterTaskGenerationFunction("PathBugbearInvasionGenerateTasks"); +void PathBugbearInvasionGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_BUGBEAR_INVASION) + return; + if (!__misc_state["in run"]) + return; + + + //task_entries.listAppend(ChecklistEntryMake("bugbear", "place.php?whichplace=bugbearship", ChecklistSubentryMake("Bugbears!", "", "I have no idea."))); + + /* + Properties: + statusEngineering + statusGalley + statusMedbay + statusMorgue + statusNavigation + statusScienceLab + statusSonar + statusSpecialOps + statusWasteProcessing + mothershipProgress + + Possible values for status: + [number] - Number of biodata collected. + unlocked - area unlocked, but floor not open in mothership...? + open - area unlocked, area available + cleared - maybe? + + mothershipProgress: 0 at start + 1 when unlocked science lab, morgue, and special ops + 2 when unlocked engineering, navigation, galley + 3 when unlocked bridge + + */ + //Let's see... first you need a key-o-tron to access the mothership. + //With that, you can collect biometric data for each area. + //Then there's mothershipProgress for each zone and tasks for each zone. + + boolean defiled_nook_open = true; + if (get_property_int("cyrptNookEvilness") == 0 && __quest_state["Level 7"].started) + defiled_nook_open = false; + + location [int] location_evaluation_order; + location_evaluation_order.listAppend($location[Medbay]); + location_evaluation_order.listAppend($location[Waste Processing]); + location_evaluation_order.listAppend($location[Sonar]); + location_evaluation_order.listAppend($location[Science Lab]); + location_evaluation_order.listAppend($location[Morgue]); + location_evaluation_order.listAppend($location[Special Ops]); + location_evaluation_order.listAppend($location[Engineering]); + location_evaluation_order.listAppend($location[Navigation]); + location_evaluation_order.listAppend($location[Galley]); + + + string [location] property_names_for_areas; + property_names_for_areas[$location[Engineering]] = "statusEngineering"; //does not seem to track battlesuit types fought + property_names_for_areas[$location[Galley]] = "statusGalley"; + property_names_for_areas[$location[Medbay]] = "statusMedbay"; + property_names_for_areas[$location[Morgue]] = "statusMorgue"; + property_names_for_areas[$location[Navigation]] = "statusNavigation"; + property_names_for_areas[$location[Science Lab]] = "statusScienceLab"; + property_names_for_areas[$location[Sonar]] = "statusSonar"; + property_names_for_areas[$location[Special Ops]] = "statusSpecialOps"; + property_names_for_areas[$location[Waste Processing]] = "statusWasteProcessing"; + + string [location] image_name_for_location; + image_name_for_location[$location[Engineering]] = "__monster " + $monster[liquid metal bugbear]; + image_name_for_location[$location[Galley]] = "__monster " + $monster[trendy bugbear chef]; + image_name_for_location[$location[Medbay]] = "__monster " + $monster[anesthesiologist bugbear]; + image_name_for_location[$location[Morgue]] = "__monster " + $monster[bugbear mortician]; + image_name_for_location[$location[Navigation]] = "__monster " + $monster[N-space Virtual Assistant]; + image_name_for_location[$location[Science Lab]] = "__monster " + $monster[bugbear scientist]; + image_name_for_location[$location[Sonar]] = "__monster " + $monster[batbugbear]; + image_name_for_location[$location[Special Ops]] = "__monster " + $monster[Black Ops Bugbear]; + image_name_for_location[$location[Waste Processing]] = "__monster " + $monster[scavenger bugbear]; + + + string [location] printable_names_for_areas; + printable_names_for_areas[$location[Engineering]] = "the engineering room"; + printable_names_for_areas[$location[Galley]] = "the galley"; + printable_names_for_areas[$location[Medbay]] = "the medbay"; + printable_names_for_areas[$location[Morgue]] = "the morgue"; + printable_names_for_areas[$location[Navigation]] = "the navigation room"; + printable_names_for_areas[$location[Science Lab]] = "the science lab"; + printable_names_for_areas[$location[Sonar]] = "the sonar room"; + printable_names_for_areas[$location[Special Ops]] = "the special ops room"; + printable_names_for_areas[$location[Waste Processing]] = "the waste processing room"; + + int [location] minimum_mothership_progress_for_area; + minimum_mothership_progress_for_area[$location[Engineering]] = 2; + minimum_mothership_progress_for_area[$location[Galley]] = 2; + minimum_mothership_progress_for_area[$location[Navigation]] = 2; + minimum_mothership_progress_for_area[$location[Morgue]] = 1; + minimum_mothership_progress_for_area[$location[Science Lab]] = 1; + minimum_mothership_progress_for_area[$location[Special Ops]] = 1; + minimum_mothership_progress_for_area[$location[Medbay]] = 0; + minimum_mothership_progress_for_area[$location[Sonar]] = 0; + minimum_mothership_progress_for_area[$location[Waste Processing]] = 0; + + if ($item[key-o-tron].available_amount() == 0) + { + if ($item[key-o-tron].creatable_amount() > 0) + { + task_entries.listAppend(ChecklistEntryMake("__item key-o-tron", "inv_use.php?pwd=" + my_hash() + "&whichitem=5683", ChecklistSubentryMake("Create key-o-tron", "", "Use 5 BURTs."), -11).ChecklistEntrySetIDTag("Bugbear invasion path make key")); + } + else + { + string url = ""; + int burts_needed = clampi(5 - $item[BURT].available_amount(), 0, 5); + string [int] description; + description.listAppend("To make a key-o-tron."); + + string [int] source_locations_available; + string [int] source_locations_unavailable; + //Possible areas: + + boolean [location] unavailable_locations_to_show = $locations[The Sleazy Back Alley,The Spooky Forest,cobb's knob Laboratory,The Defiled Nook,Lair of the Ninja Snowmen,The Penultimate Fantasy Airship,The Haunted Gallery,The Battlefield (Frat Uniform)]; + + boolean [location] relevant_locations = $locations[The Sleazy Back Alley,The Spooky Forest,The Bat Hole Entrance,The Batrat and Ratbat Burrow,Guano Junction,The Beanbat Chamber,cobb's knob Laboratory,Lair of the Ninja Snowmen,The Penultimate Fantasy Airship,The Haunted Gallery,The Battlefield (Frat Uniform),The Orcish Frat House (Bombed Back to the Stone Age),The Hippy Camp (Bombed Back to the Stone Age)].makeConstantLocationArrayMutable(); //FIXME the battlefield (hippy uniform)? + relevant_locations[$location[the very unquiet garves]] = true; + + if (defiled_nook_open) + relevant_locations[$location[the defiled nook]] = true; + else + relevant_locations[$location[The VERY Unquiet Garves]] = true; + + //FIXME always URL in areas we have olfacted...? + foreach l in relevant_locations + { + string place = l.to_string(); + + if (!l.locationAvailable()) + { + if (unavailable_locations_to_show contains l) + source_locations_unavailable.listAppend(HTMLGenerateSpanFont(place, "grey")); + } + else + { + source_locations_available.listAppend(place); + string place_url = l.getClickableURLForLocation(); + if (place_url.length() != 0) + url = place_url; + } + } + string line = "Places to collect them:|*" + source_locations_available.listJoinComponents("|*"); + if (source_locations_unavailable.count() > 0) + line += "|*" + source_locations_unavailable.listJoinComponents("|*"); + description.listAppend(line); + + task_entries.listAppend(ChecklistEntryMake("__item key-o-tron", url, ChecklistSubentryMake("Collect " + int_to_wordy(burts_needed) + " more BURT" + ((burts_needed) > 1 ? "s" : ""), "", description)).ChecklistEntrySetIDTag("Bugbear invasion path key-o-tron")); + } + } + else + { + // + location [location][int] locations_relevant_to_acquire_biodata; + int [location] biodata_amount_needed_for_area; + + + biodata_amount_needed_for_area[$location[Engineering]] = 9; + biodata_amount_needed_for_area[$location[Galley]] = 9; + biodata_amount_needed_for_area[$location[Medbay]] = 3; + biodata_amount_needed_for_area[$location[Morgue]] = 6; + biodata_amount_needed_for_area[$location[Navigation]] = 9; + biodata_amount_needed_for_area[$location[Science Lab]] = 6; + biodata_amount_needed_for_area[$location[Sonar]] = 3; + biodata_amount_needed_for_area[$location[Special Ops]] = 6; + biodata_amount_needed_for_area[$location[Waste Processing]] = 3; + + monster [location] bugbears_to_hunt_for_location; + + bugbears_to_hunt_for_location[$location[Engineering]] = $monster[Battlesuit Bugbear Type]; + bugbears_to_hunt_for_location[$location[Galley]] = $monster[trendy bugbear chef]; + bugbears_to_hunt_for_location[$location[Medbay]] = $monster[hypodermic bugbear]; + bugbears_to_hunt_for_location[$location[Morgue]] = $monster[bugaboo]; + bugbears_to_hunt_for_location[$location[Navigation]] = $monster[ancient unspeakable bugbear]; + bugbears_to_hunt_for_location[$location[Science Lab]] = $monster[bugbear scientist]; + bugbears_to_hunt_for_location[$location[Sonar]] = $monster[batbugbear]; + bugbears_to_hunt_for_location[$location[Special Ops]] = $monster[Black Ops Bugbear]; + bugbears_to_hunt_for_location[$location[Waste Processing]] = $monster[scavenger bugbear]; + + foreach l in property_names_for_areas + { + locations_relevant_to_acquire_biodata[l] = listMakeBlankLocation(); + } + + locations_relevant_to_acquire_biodata[$location[waste processing]].listAppend($location[the sleazy back alley]); + locations_relevant_to_acquire_biodata[$location[Medbay]].listAppend($location[the Spooky Forest]); + locations_relevant_to_acquire_biodata[$location[Sonar]].listAppend($location[The Bat Hole Entrance]); + locations_relevant_to_acquire_biodata[$location[Sonar]].listAppend($location[The Batrat and Ratbat Burrow]); + locations_relevant_to_acquire_biodata[$location[Sonar]].listAppend($location[Guano Junction]); + locations_relevant_to_acquire_biodata[$location[Sonar]].listAppend($location[The Beanbat Chamber]); + + locations_relevant_to_acquire_biodata[$location[Science Lab]].listAppend($location[cobb's knob laboratory]); + + + locations_relevant_to_acquire_biodata[$location[Special Ops]].listAppend($location[Lair of the Ninja Snowmen]); + locations_relevant_to_acquire_biodata[$location[Engineering]].listAppend($location[The Penultimate Fantasy Airship]); + locations_relevant_to_acquire_biodata[$location[Navigation]].listAppend($location[The Haunted Gallery]); + + if (!__quest_state["Level 12"].finished) + { + locations_relevant_to_acquire_biodata[$location[Galley]].listAppend($location[The Battlefield (Frat Uniform)]); + } + else + { + //FIXME determine which side won + locations_relevant_to_acquire_biodata[$location[Galley]].listAppend($location[The Orcish Frat House (Bombed Back to the Stone Age)]); + locations_relevant_to_acquire_biodata[$location[Galley]].listAppend($location[The Hippy Camp (Bombed Back to the Stone Age)]); + } + + if (defiled_nook_open) + locations_relevant_to_acquire_biodata[$location[Morgue]].listAppend($location[the defiled nook]); + else + locations_relevant_to_acquire_biodata[$location[Morgue]].listAppend($location[The VERY Unquiet Garves]); + + string url = ""; + boolean do_not_override_url = false; + + string [int] description; + boolean [location] relevant_locations; + foreach l, biodata_needed in biodata_amount_needed_for_area + { + string biodata_have_string = get_property(property_names_for_areas[l]); + if (!biodata_have_string.is_integer()) + continue; + int biodata_have = biodata_have_string.to_int_silent(); + if (biodata_have >= biodata_needed) + continue; + int biodata_remaining = MAX(0, biodata_needed - biodata_have); + + //FIXME check if we have an area open + location [int] areas_we_can_adventure_in; + foreach key, l2 in locations_relevant_to_acquire_biodata[l] + { + areas_we_can_adventure_in.listAppend(l2); + relevant_locations[l2] = true; + + string this_url = l2.getClickableURLForLocation(); + if (this_url != "" && !do_not_override_url && l2.locationAvailable()) + url = this_url; + if (get_property_monster("olfactedMonster") == bugbears_to_hunt_for_location[l]) + { + do_not_override_url = true; + } + } + if (areas_we_can_adventure_in.count() > 0 && l.turns_spent == 0) + { + + boolean tracking_works = true; + if ($locations[the Penultimate Fantasy Airship,Lair of the Ninja Snowmen] contains l && biodata_remaining == biodata_needed) + tracking_works = false; + boolean at_least_one_area_open = false; + foreach key, l in areas_we_can_adventure_in + { + if (l.locationAvailable()) + at_least_one_area_open = true; + } + string line; + line += "Fight " + int_to_wordy(biodata_remaining); + + if (!tracking_works) + line += " total "; + else + line += " more "; + line += bugbears_to_hunt_for_location[l] + " in"; + + if (areas_we_can_adventure_in.count() == 1) + { + line += " " + areas_we_can_adventure_in.listJoinComponents("") + "."; + line += "|Unlocks " + l + "."; + } + else + { + line += ": |*" + areas_we_can_adventure_in.listJoinComponents("|*"); + line += "|*
Unlocks " + l + "."; + } + if (!tracking_works) + line += "|Umm... unless you already did that. (no tracking)"; + if (!at_least_one_area_open) + line = HTMLGenerateSpanFont(line, "grey"); + description.listAppend(line); + } + } + if (description.count() > 0) + { + if ($item[crayon shavings].available_amount() > 0) + description.listPrepend($item[crayon shavings].available_amount().int_to_wordy().capitaliseFirstLetter() + " crayon shavings available for copying bugbears."); + if ($item[bugbear detector].available_amount() > 0 && $item[bugbear detector].equipped_amount() == 0) + description.listPrepend(HTMLGenerateSpanFont("Equip bugbear detector first.", "red")); + task_entries.listAppend(ChecklistEntryMake("__item software glitch", url, ChecklistSubentryMake("Collect biodata", "", description), relevant_locations).ChecklistEntrySetIDTag("Bugbear invasion path collect biodata")); + } + } + int mothership_progress = get_property_int("mothershipProgress"); + + if (true) + { + ChecklistEntry entry; + entry.url = "place.php?whichplace=bugbearship"; + entry.image_lookup_name = "bugbear"; + entry.tags.id = "Bugbear invasion path quest mothership"; + foreach key, l in location_evaluation_order + { + string property_name = property_names_for_areas[l]; + if (get_property(property_name) != "open" && !(get_property(property_name).is_integer() && l.turns_spent > 0)) + continue; + + if (mothership_progress < minimum_mothership_progress_for_area[l]) + continue; + if (entry.image_lookup_name == "bugbear" && image_name_for_location[l] != "") + entry.image_lookup_name = image_name_for_location[l]; + + string [int] modifiers; + string [int] description; + if (l == $location[medbay]) + { + modifiers.listAppend("olfact anesthesiologist bugbear"); + description.listAppend("Fight anesthesiologist bugbears to summon and defeat the robo-surgeon."); + description.listAppend("Banishes won't help...?"); + } + else if (l == $location[sonar]) + { + modifiers.listAppend("-combat"); + description.listAppend("Run -combat, look for the machine."); + description.listAppend("Set Pinging machine to 2."); + description.listAppend("Set Whurming machine to 4."); + description.listAppend("Set Boomchucking machine to 8."); + } + else if (l == $location[waste processing]) + { + if ($item[bugbear communicator badge].available_amount() > 0) + { + if ($item[bugbear communicator badge].equipped_amount() == 0) + { + description.listAppend("Equip the bugbear communicator badge."); + } + else + { + description.listAppend("Adventure once to finish the area."); + } + } + else + { + modifiers.listAppend("olfact creepy eye-stalk tentacle monster"); + modifiers.listAppend("+item"); + description.listAppend("Acquire and use handfuls of juicy garbage."); + if ($item[handful of juicy garbage].available_amount() > 0) + { + task_entries.listAppend(ChecklistEntryMake("__item handful of juicy garbage", "inventory.php?ftext=handful+of+juicy+garbage", ChecklistSubentryMake("Use handful of juicy garbage", "", "Might find a bugbear communicator badge."), -11).ChecklistEntrySetIDTag("Bugbear invasion path juicy garbage")); + } + } + } + else if (l == $location[science lab]) + { + //FIXME want tracking for scientists trapped + modifiers.listAppend("+item"); + description.listAppend("Collect quantum nanopolymer spider webs from spiderbugbears, use them on the poor innocent scientists."); + if ($item[quantum nanopolymer spider web].available_amount() > 0) + description.listAppend(pluraliseWordy($item[quantum nanopolymer spider web]).capitaliseFirstLetter() + " available."); + } + else if (l == $location[morgue]) + { + //FIXME want tracking of parts + if ($item[bugbear autopsy tweezers].available_amount() > 0) + modifiers.listAppend("-combat"); + if ($item[bugbear autopsy tweezers].available_amount() < 5) + { + if (!$monster[bugaboo].is_banished()) + modifiers.listAppend("banish bugaboos OR olfact bugbear morticians"); + description.listAppend("Collect bugbear autopsy tweezers from bugbear morticians."); + } + + if ($item[bugbear autopsy tweezers].available_amount() > 0) + description.listAppend("Run -combat to use the tweezers on the choice adventure."); + } + else if (l == $location[special ops]) + { + boolean [item] relevant_equipment = $items[fire,uv monocular,rain-doh green lantern,fluorescent lightbulb]; + item [int] items_to_equip; + foreach it in relevant_equipment + { + if (it.available_amount() > 0 && it.equipped_amount() == 0) + items_to_equip.listAppend(it); + } + if (items_to_equip.count() > 0) + description.listAppend(HTMLGenerateSpanFont("Equip your " + items_to_equip.listJoinComponents(", ", "and") + ".", "red")); + if ($item[uv monocular].available_amount() == 0 && $item[uv monocular].creatable_amount() > 0) + description.listAppend("Could create the UV Monocular with your BURTs."); + + description.listAppend("Search in darkness."); + + if ($item[flaregun].available_amount() > 0) + description.listAppend("Shoot a flare in the choice adventure if you haven't."); + } + else if (l == $location[Engineering]) + { + //FIXME want tracking on liquid metal bugbears + modifiers.listAppend("+item"); + if (!$monster[Battlesuit Bugbear Type].is_banished()) + { + modifiers.listAppend("banish " + $monster[Battlesuit Bugbear Type]); + } + description.listAppend("Collect drone self-destruct chips from drones, use them on liquid metal bugbears."); + if ($item[drone self-destruct chip].available_amount() > 0) + description.listAppend(pluraliseWordy($item[drone self-destruct chip]).capitaliseFirstLetter() + " available."); + } + else if (l == $location[Navigation]) + { + if ($effect[N-Spatial vision].have_effect() > 0) + { + string method_to_remove = ""; + //FIXME write this + if ($skill[disco nap].skill_is_usable() && $skill[adventurer of leisure].skill_is_usable()) + method_to_remove = "disco nap."; + else if ($item[bugbear purification pill].available_amount() > 0) + method_to_remove = "bugbear purification pill."; + else if ($item[bugbear purification pill].creatable_amount() > 0) + method_to_remove = "bugbear purification pill. (make from BURTs)"; + else if ($item[soft green echo eyedrop antidote].available_amount() > 0) + method_to_remove = "soft green echo eyedrop antidote. (probably not worth it)"; + + if (method_to_remove != "") + description.listAppend("Remove N-Spatial vision with " + method_to_remove); + else + description.listAppend("Avoid adventuring here until N-Spatial vision is gone."); + } + else + { + if (!$monster[ancient unspeakable bugbear].is_banished()) + { + modifiers.listAppend("banish ancient unspeakable bugbears OR olfact n-space virtual assistants"); //zero space. Zee-roh spaa ce. Spac-uh. + } + description.listAppend("Defeat ~ten total N-space assistants."); + } + } + else if (l == $location[Galley]) + { + //FIXME tracking ML defeated, cavebugbear attack + modifiers.listAppend("+ML"); + if (!$monster[trendy bugbear chef].is_banished()) + { + modifiers.listAppend("banish trendy bugbear chefs OR olfact angry cavebugbears"); + } + description.listAppend("Defeat 5k ML worth of angry cavebugbears."); + if ($item[pacification grenade].creatable_amount() + $item[pacification grenade].available_amount() > 0) + description.listAppend("Can " + ($item[pacification grenade].available_amount() == 0 ? "make and " : "") + "throw a pacification grenade if they become too difficult."); + } + + entry.subentries.listAppend(ChecklistSubentryMake("Clear " + printable_names_for_areas[l], modifiers, description)); + if ($locations[Medbay,Waste Processing,Sonar,Science Lab,Morgue,Special Ops,Engineering,Navigation,Galley] contains __last_adventure_location) + entry.should_highlight = true; + } + if (entry.subentries.count() > 0) + task_entries.listAppend(entry); + } + + if (mothership_progress >= 3) + { + // + boolean other_quests_completed = true; + for i from 2 to 12 + { + if (!__quest_state["Level " + i].finished) + other_quests_completed = false; + } + if (other_quests_completed && my_level() >= 13) + { + ChecklistEntry entry; + if ($item[jeff goldblum larva].available_amount() == 0) + { + //hacky: + entry = ChecklistEntryMake("council", "place.php?whichplace=town", ChecklistSubentryMake("Visit the Council of Loathing", "", "Obtain Jeff Goldblum larva.")); + } + else + { + //no tracking for bridge captain defeated? + entry = ChecklistEntryMake("bugbear", "place.php?whichplace=bugbearship", ChecklistSubentryMake("Fight the Bugbear Captain", "", listMake("On the bridge.", "Then free the king. Maybe."))); + } + entry.tags.id = "Bugbear invastion path quest final steps"; + task_entries.listAppend(entry); + } + } +} + +RegisterResourceGenerationFunction("PathBugbearInvasionGenerateResource"); +void PathBugbearInvasionGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_BUGBEAR_INVASION) + return; + if (!__misc_state["in run"]) + return; + if ($item[crayon shavings].available_amount() > 0) + { + resource_entries.listAppend(ChecklistEntryMake("__item crayon shavings", "", ChecklistSubentryMake(pluralise($item[crayon shavings].available_amount(), "crayon shaving copy", "crayon shaving copies") + " available", "", "Bugbears only.")).ChecklistEntrySetIDTag("Bugbear invasion path crayon shaving resource")); + } + if ($item[BURT].available_amount() > 0) + { + string [int] description; + + string [item] item_reason; + item_reason[$item[pacification grenade]] = "trades speed for survivability in the galley"; + item_reason[$item[key-o-tron]] = "collects biodata"; + item_reason[$item[bugbear detector]] = "find the elusive creature"; + item_reason[$item[uv monocular]] = "useful in special ops"; + item_reason[$item[bugbear purification pill]] = "removes a negative effect"; + if (get_property("statusNavigation") != "cleared" && !($skill[disco nap].skill_is_usable() && $skill[adventurer of leisure].skill_is_usable())) + item_reason[$item[bugbear purification pill]] += " (useful in Navigation)"; + item [int] relevant_items; + relevant_items.listAppend($item[bugbear purification pill]); + if (get_property("statusGalley") != "cleared") + relevant_items.listAppend($item[pacification grenade]); + relevant_items.listAppend($item[key-o-tron]); + relevant_items.listAppend($item[bugbear detector]); + if (get_property("statusSpecialOps") != "cleared") + relevant_items.listAppend($item[uv monocular]); + + int [item] amount_wanted; + amount_wanted[$item[pacification grenade]] = -1; + + foreach key, it in relevant_items + { + if (it.available_amount() > 0 && amount_wanted[it] != -1) + continue; + string line = it + " - "; + line += item_reason[it] + "."; + + if (it.creatable_amount() == 0) + line = HTMLGenerateSpanFont(line, "grey"); + description.listAppend(line); + } + resource_entries.listAppend(ChecklistEntryMake("__item BURT", "inv_use.php?pwd=" + my_hash() + "&whichitem=5683", ChecklistSubentryMake(pluralise($item[BURT]) + " available", "", description), 8).ChecklistEntrySetIDTag("Bugbear invasion path BURT resource")); + } +} + +RegisterTaskGenerationFunction("PathCommunityServiceGenerateTasks"); +void PathCommunityServiceGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_COMMUNITY_SERVICE) + return; + if (!__misc_state["in run"]) + return; + boolean [item] blacklist; + + /*string [int] service_display_order = {0:"Coil Wire", + 1:"", + 2:"", + 3:"", + 4:"", + 5:"", + 6:"", + 7:"", + 8:"", + 9:"", + 10:"" + };*/ + boolean [string] services_performed = listInvert(get_property("csServicesPerformed").split_string_alternate(",")); + string [int] choice_id_order = { + "Coil Wire", //flat + "Donate Blood", + "Feed The Children (But Not Too Much)", + "Build Playground Mazes", + "Feed Conspirators", + "Breed More Collies", + "Reduce Gazelle Population", + "Make Sausage", + "Be a Living Statue", + "Make Margaritas", + "Clean Steam Tunnels" + }; + //the spreadsheet we were using does +item before the stat tests, but I'm moving it after them, because cold-filtered water is ten turns, and the +item test doesn't give anything that helps with stats + //and technically, muscle gives bag of grain + string [int] service_display_order = { + "Coil Wire", //flat + "Feed The Children (But Not Too Much)", //muscle + "Feed Conspirators", //moxie + "Donate Blood", //hp + "Build Playground Mazes", //myst + "Make Margaritas", //item/booze + "Reduce Gazelle Population", //melee + "Make Sausage", //spell + "Clean Steam Tunnels", //hot res + "Breed More Collies", //familiar weight + "Be a Living Statue", //-combat + }; + /*string [string] service_names_to_property = {"Donate Blood":"REPLACEME" + "Feed The Children (But Not Too Much)":"Muscle", + "Build Playground Mazes":"Mysticality", + "Feed Conspirators":"Moxie", + "Breed More Collies":"Familiar Weight", + "Reduce Gazelle Population":"REPLACEME", + "Make Sausage":"REPLACEME", + "Be a Living Statue":"REPLACEME", + "Make Margaritas":"REPLACEME", + "Clean Steam Tunnels":"Hot Resistance", + };*/ + //None, HP, muscle, mysticality, moxie, familiar weight, melee damage, spell damage, noncombat, booze drop, hot res + //list in ideal order to finish the path as you are(?) + int REPLACEME = 10000; + foreach key, service_name in service_display_order + { + string [int] modifiers; + string [int] description; + int turns = PathCommunityServiceEstimateTurnsTakenForTask(service_name); + string service_lookup_name = service_name; + if (service_lookup_name == "Feed The Children (But Not Too Much)") + service_lookup_name = "Feed The Children"; + if (services_performed[service_lookup_name]) continue; + + boolean [string] numeric_modifiers; + string short_test_description; + boolean prefer_negative = false; + string image_name = ""; + if (service_name == "Donate Blood") + { + image_name = "__item blood-drive sticker"; + modifiers.listAppend("HP"); + modifiers.listAppend("muscle"); + short_test_description = "HP"; + numeric_modifiers = $strings[Buffed HP Maximum,Maximum HP,Muscle,Muscle Percent]; + } + else if (service_name == "Coil Wire") + { + image_name = "__item a ten-percent bonus"; + } + else if (service_name == "Make Margaritas") + { + image_name = "__item emergency margarita"; + modifiers.listAppend("item"); + modifiers.listAppend("booze drop"); + short_test_description = "item drop, booze drop"; + numeric_modifiers = $strings[Item Drop,Booze Drop]; + } + else if (service_name == "Feed The Children (But Not Too Much)" || service_name == "Build Playground Mazes" || service_name == "Feed Conspirators") + { + stat using_stat; + if (service_name == "Feed The Children (But Not Too Much)") + { + using_stat = $stat[muscle]; + image_name = "__item bag of grain"; + } + else if (service_name == "Build Playground Mazes") + { + using_stat = $stat[mysticality]; + image_name = "__item pocket maze"; + } + else if (service_name == "Feed Conspirators") + { + using_stat = $stat[moxie]; + image_name = "__item shady shades"; + } + modifiers.listAppend("+" + using_stat); + short_test_description = using_stat; + numeric_modifiers[using_stat.to_string()] = true; + numeric_modifiers[using_stat + " Percent"] = true; + int basestat = my_basestat(using_stat); + boolean relevant_thrall_active = false; + if (my_thrall() == $thrall[Elbow Macaroni] && using_stat == $stat[muscle]) + { + basestat = my_basestat($stat[mysticality]); + relevant_thrall_active = true; + } + if (my_thrall() == $thrall[Penne Dreadful] && using_stat == $stat[moxie]) + { + basestat = my_basestat($stat[mysticality]); + relevant_thrall_active = true; + } + + turns = 60 - (my_buffedstat(using_stat) - basestat) / 30; + if (turns > 1) + { + //turns saved = (buffed - base) / 30 + //59 = (buffed - base) / 30 + //1770 = buffed - base + //buffed = 1770 + base + int needed_buffed_stat = 1770 + basestat; + float percentage = to_float(needed_buffed_stat - my_buffedstat(using_stat)) / to_float(basestat) * 100.0; + description.listAppend("Need to buff " + using_stat + " to " + needed_buffed_stat + " (+" + (needed_buffed_stat - my_buffedstat(using_stat)) + " / +" + percentage.round() + "% from here)"); + if (relevant_thrall_active) + { + } + else if (using_stat != $stat[mysticality] && my_primestat() == $stat[mysticality] && $item[oil of expertise].to_effect().have_effect() == 0) + { + description.listAppend("Possibly use oil of expertise to equalise basestats." + ($items[cherry,oil of expertise].available_amount() == 0 ? "|Can get a cherry from novelty tropical skeleton in the skeleton store. Run +234% item." : "")); + if (my_class() == $class[pastamancer]) description.listAppend("Or use pastamancer thralls."); + } + } + } + else if (service_name == "Reduce Gazelle Population") + { + image_name = "__item weird gazelle steak"; + modifiers.listAppend("+weapon damage, +weapon damage percent"); + short_test_description = "melee damage, melee damage percent"; + numeric_modifiers = $strings[Weapon Damage,Weapon Damage Percent]; + if ($skill[Bow-Legged Swagger].have_skill() && $effect[Bow-Legged Swagger].have_effect() == 0 && !get_property_boolean("_bowleggedSwaggerUsed")) + { + description.listAppend("Cast Bow-Legged Swagger for twice effectiveness."); + } + } + else if (service_name == "Make Sausage") + { + image_name = "__item sausage without a cause"; + modifiers.listAppend("+spell damage, +spell damage percent"); + short_test_description = "spell damage"; + numeric_modifiers = $strings[Spell Damage,Spell Damage Percent]; + } + else if (service_name == "Clean Steam Tunnels") + { + image_name = "__item vintage smart drink"; + //FIXME red + modifiers.listAppend("+hot resistance"); + short_test_description = "hot resistance"; + numeric_modifiers = $strings[Hot Resistance]; + } + else if (service_name == "Breed More Collies") + { + image_name = "__item squeaky toy rose"; + modifiers.listAppend("+familiar weight"); + short_test_description = "familiar weight"; + numeric_modifiers = $strings[Familiar Weight]; + } + else if (service_name == "Be a Living Statue") + { + image_name = "__item silver face paint"; + modifiers.listAppend("-combat"); + short_test_description = "-combat"; + numeric_modifiers = $strings[Combat Rate]; + prefer_negative = true; + } + + turns = clampi(turns, 1, 60); + if (short_test_description != "") + description.listAppend("Buff " + short_test_description + "."); + + + + + description.listAppend(pluralise(turns, "turn", "turns") + "."); + task_entries.listAppend(ChecklistEntryMake(image_name, "council.php", ChecklistSubentryMake(service_name, modifiers, description)).ChecklistEntrySetIDTag("Community service path " + service_lookup_name)); + } + //equaliser potions + /*if (true) + { + item [int] hp_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Buffed HP Maximum", 150.0, blacklist); //what a strange lookup name + item [int] hp_potions_2 = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Maximum HP", 150.0, blacklist); //something else? + + item [int] muscle_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Muscle", 0.0, blacklist); + item [int] muscle_percent_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier("Muscle Percent", 0.0, blacklist); + + + string [int] relevant_potions_output; + foreach key, it in hp_potions + { + relevant_potions_output.listAppend(it + " (+" + it.to_effect().numeric_modifier("Buffed HP Maximum").roundForOutput(0) + ")"); + } + + task_entries.listAppend(ChecklistEntryMake("__item helmet turtle", "council.php", ChecklistSubentryMake("Perform HP service", "+hp", relevant_potions_output.listJoinComponents(", ", "and")))); + } + + + foreach s in $strings[Buffed HP Maximum,Muscle,Muscle Percent,Moxie,Moxie Percent,Mysticality,Mysticality Percent,Weapon Damage,Weapon Damage Percent,spell damage, spell damage percent,Combat Rate,hot resistance] + { + item [int] relevant_potions = ItemFilterGetPotionsCouldPullToAddToNumericModifier(s, -100000.0, blacklist); //what a strange lookup name + string [int] relevant_potions_output; + foreach key, it in relevant_potions + { + relevant_potions_output.listAppend(it + " (+" + it.to_effect().numeric_modifier(s).roundForOutput(0) + ")"); + } + task_entries.listAppend(ChecklistEntryMake("__item helmet turtle", "council.php", ChecklistSubentryMake("Perform " + s + " service", "", relevant_potions_output.listJoinComponents(", ", "and")))); + }*/ +} + + +RegisterTaskGenerationFunction("PathHeavyRainsGenerateTasks"); +void PathHeavyRainsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_HEAVY_RAINS) return; + + item thunder_item = $item[thunder thigh]; + item rain_item = $item[aquaconda brain]; + item lightning_item = $item[lightning milk]; + + boolean [item] all_skill_items; + all_skill_items[thunder_item] = true; + all_skill_items[rain_item] = true; + all_skill_items[lightning_item] = true; + + if (thunder_item.available_amount() + rain_item.available_amount() + lightning_item.available_amount() > 0) + { + //Let's learn skills: + skill [item][int] skills_for_item; + + skills_for_item[thunder_item] = listMakeBlankSkill(); + skills_for_item[rain_item] = listMakeBlankSkill(); + skills_for_item[lightning_item] = listMakeBlankSkill(); + + skills_for_item[thunder_item].listAppend($skill[Thunder Clap]); + skills_for_item[thunder_item].listAppend($skill[Thundercloud]); + skills_for_item[thunder_item].listAppend($skill[Thunder Bird]); + skills_for_item[thunder_item].listAppend($skill[Thunderheart]); + skills_for_item[thunder_item].listAppend($skill[Thunderstrike]); + skills_for_item[thunder_item].listAppend($skill[Thunder Down Underwear]); + skills_for_item[thunder_item].listAppend($skill[Thunder Thighs]); + + skills_for_item[rain_item].listAppend($skill[Rain Man]); + skills_for_item[rain_item].listAppend($skill[Rainy Day]); + skills_for_item[rain_item].listAppend($skill[Make it Rain]); + skills_for_item[rain_item].listAppend($skill[Rain Dance]); + skills_for_item[rain_item].listAppend($skill[Rainbow]); + skills_for_item[rain_item].listAppend($skill[Rain Coat]); + skills_for_item[rain_item].listAppend($skill[Rain Delay]); + + skills_for_item[lightning_item].listAppend($skill[Lightning Strike]); + skills_for_item[lightning_item].listAppend($skill[Clean-Hair Lightning]); + skills_for_item[lightning_item].listAppend($skill[Ball Lightning]); + skills_for_item[lightning_item].listAppend($skill[Sheet Lightning]); + skills_for_item[lightning_item].listAppend($skill[[16025]Lightning Bolt]); + skills_for_item[lightning_item].listAppend($skill[Lightning Rod]); + skills_for_item[lightning_item].listAppend($skill[Riding the Lightning]); + + string [skill] description_for_skill; + + description_for_skill[$skill[Thunder Clap]] = "Turn-costing banish. (lasts 40 turns, no stats, no items, no meat)"; + description_for_skill[$skill[Thundercloud]] = "Water depth increasing effect"; + description_for_skill[$skill[Thunderheart]] = "+100% HP, surviving"; + description_for_skill[$skill[Thunderstrike]] = "Monster stunning"; + description_for_skill[$skill[Thunder Thighs]] = "Thunder regen, passive"; + description_for_skill[$skill[Thunder Bird]] = "Monster deleveling"; + if (in_hardcore()) + description_for_skill[$skill[Thunder Down Underwear]] = "safety pants (if you want to)"; + + + description_for_skill[$skill[Rain Man]] = "Fax any monster repeatedly"; + description_for_skill[$skill[Rainy Day]] = "Water depth increasing effect"; + if (!__quest_state["Level 12"].state_boolean["Nuns Finished"]) + description_for_skill[$skill[Make it Rain]] = "+300% meat for a single turn (nuns)"; + description_for_skill[$skill[Rain Dance]] = "+20% item effect"; + description_for_skill[$skill[Rain Delay]] = "passive, +3 resist all"; + + description_for_skill[$skill[Lightning Strike]] = "Kills monster, gain stats/drops, makes adventure not use a turn (effective free run/hipster)"; + description_for_skill[$skill[Ball Lightning]] = "Yellow ray (100 turn cooldown)"; + description_for_skill[$skill[Riding the Lightning]] = "passive, +100% max MP"; + + + description_for_skill[$skill[Sheet Lightning]] = "+100% spell damage effect"; + //description_for_skill[$skill[Thunder Down Underwear]] = "Summon once/day pants: +100 DA/HP, HP regen"; + //description_for_skill[$skill[Rain Coat]] = "Summons once/day shirt: +40% init, +10% item, +2 resist all"; + //description_for_skill[$skill[Lightning Rod]] = "Summons once/day weapon: +200% spell damage"; + + + int [item] available_skills_for_item; + int [item] max_available_skills_for_item; + + foreach it in skills_for_item + { + foreach key in skills_for_item[it] + { + skill s = skills_for_item[it][key]; + if (s.skill_is_usable()) + continue; + max_available_skills_for_item[it] += 1; + available_skills_for_item[it] = MIN(max_available_skills_for_item[it], it.available_amount()); + } + } + + //available_skills_for_item[thunder_item] = 7; + //available_skills_for_item[rain_item] = 7; + //available_skills_for_item[lightning_item] = 7; + + + string [int] description; + + string [int] available_skill_types; + + string [int] items_to_use_description; + + string [item] item_to_typename; + item_to_typename[thunder_item] = "thunder"; + item_to_typename[rain_item] = "rain"; + item_to_typename[lightning_item] = "lightning"; + + string url = ""; + string [item] item_to_url; + + item_to_url[thunder_item] = "inv_use.php?which=3&whichitem=7648&pwd=" + my_hash(); + item_to_url[rain_item] = "inv_use.php?which=3&whichitem=7647&pwd=" + my_hash(); + foreach it in all_skill_items + { + if (available_skills_for_item[it] > 0) + { + available_skill_types.listAppend(item_to_typename[it]); + items_to_use_description.listAppend(pluralise(available_skills_for_item[it], it)); + + if (url.length() == 0) + url = item_to_url[it]; + } + } + + url = "inventory.php?which=3"; //mafia won't remove the skill glands quite properly (needs to happen when you click the NC option, not at inv_use.php) + + description.listAppend("Use " + items_to_use_description.listJoinComponents(", ", "and") + "."); + + + foreach it in all_skill_items + { + if (available_skills_for_item[it] == 0) + continue; + + int other_count = 0; + string [int] relevant_descriptions; + foreach key in skills_for_item[it] + { + skill s = skills_for_item[it][key]; + if (s.skill_is_usable()) + continue; + if (!(description_for_skill contains s)) + { + other_count += 1; + continue; + } + relevant_descriptions.listAppend(s + ": " + description_for_skill[s]); + } + if (other_count > 0) + { + if (relevant_descriptions.count() > 0) + relevant_descriptions.listAppend("Or " + pluraliseWordy(other_count, "other skill", "other skills") + "."); + else + relevant_descriptions.listAppend(pluraliseWordy(other_count, "possible skill", "possible skills").capitaliseFirstLetter() + "."); + } + + description.listAppend(HTMLGenerateSpanOfClass(item_to_typename[it].capitaliseFirstLetter() + ":", "r_bold") + HTMLGenerateIndentedText(relevant_descriptions.listJoinComponents("
"))); + } + + if (available_skill_types.count() > 0) + task_entries.listAppend(ChecklistEntryMake("__familiar personal raincloud", url, ChecklistSubentryMake("Learn " + available_skill_types.listJoinComponents(", ", "and") + " skills", "", description), -10).ChecklistEntrySetIDTag("Heavy rains path new skills")); + } +} + +RegisterResourceGenerationFunction("PathHeavyRainsGenerateResource"); +void PathHeavyRainsGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_HEAVY_RAINS) return; + + //resource_entries.listAppend(ChecklistEntryMake("__item gym membership card", "inventory.php?ftext=gym+membership+card", ChecklistSubentryMake(pluralise($item[gym membership card]), "", description), importance_level_item)); + + + int fishbone_amount = $item[freshwater fishbone].available_amount(); + + if (fishbone_amount >= 5) //only show if there's something to buy + { + int [item] fishbone_item_costs; + string [item] fishbone_item_descriptions; + + //Are these worth suggesting? + //fishbone_item_descriptions[$item[fishbone facemask]] = "-30 ML"; + //fishbone_item_costs[$item[fishbone facemask]] = 5; + //fishbone_item_descriptions[$item[fishbone fins]] = "survivability"; + //fishbone_item_costs[$item[fishbone fins]] = 20; + + fishbone_item_descriptions[$item[fishbone bracers]] = "+100% spell damage"; + fishbone_item_costs[$item[fishbone bracers]] = 5; + + + fishbone_item_descriptions[$item[fishbone corset]] = "-water depth"; + fishbone_item_costs[$item[fishbone corset]] = 10; + + + fishbone_item_descriptions[$item[fishbone kneepads]] = "+60% init"; + fishbone_item_costs[$item[fishbone kneepads]] = 15; + + fishbone_item_descriptions[$item[fishbone catcher's mitt]] = "-washaway"; + fishbone_item_costs[$item[fishbone catcher's mitt]] = 30; + + string [int] description; + foreach it in fishbone_item_costs + { + if (it == $item[none]) + continue; + int cost = fishbone_item_costs[it]; + + + int amount_needed = 1; + if (it.to_slot() == $slot[acc1] || it.to_slot() == $slot[acc2] || it.to_slot() == $slot[acc3]) + amount_needed = 3; + + int creatable = 0; + if (fishbone_item_costs[it] != 0) + creatable = MIN(amount_needed, fishbone_amount / fishbone_item_costs[it]); + + if (it.available_amount() >= amount_needed || creatable == 0) + continue; + int amount_to_make = MIN(creatable, amount_needed - it.available_amount()); + + description.listAppend(pluralise(amount_to_make, it) + ": " + fishbone_item_descriptions[it]); + } + resource_entries.listAppend(ChecklistEntryMake("__item freshwater fishbone", "shop.php?whichshop=fishbones", ChecklistSubentryMake(pluralise($item[freshwater fishbone]), "", description), 7).ChecklistEntrySetIDTag("Heavy rains path fishbone shop")); + } + + if ($item[catfish whiskers].available_amount() > 0) + { + //should we add in area suggestions? + resource_entries.listAppend(ChecklistEntryMake("__item catfish whiskers", "inventory.php?ftext=catfish+whiskers", ChecklistSubentryMake(pluralise($item[catfish whiskers]), "", "40 turns of -washaway"), 7).ChecklistEntrySetIDTag("Heavy rains path catfish whiskers resource")); + } +} + +RegisterTaskGenerationFunction("PathKOLHSGenerateTasks"); +void PathKOLHSGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_KOLHS) + return; + + item [string][int] items_wanted_in_classes; + effect [string] relevant_intrinsic; + items_wanted_in_classes["Art Class"] = listMakeBlankItem(); + relevant_intrinsic["Art Class"] = $effect[greaser lightnin']; + items_wanted_in_classes["Art Class"].listAppend($item[quasireligious sculpture]); + items_wanted_in_classes["Art Class"].listAppend($item[Sticky clay homunculus]); + items_wanted_in_classes["Art Class"].listAppend($item[Modeling claymore]); + items_wanted_in_classes["Art Class"].listAppend($item[Giant eraser]); + + items_wanted_in_classes["Shop Class"] = listMakeBlankItem(); + relevant_intrinsic["Shop Class"] = $effect[Jamming with the Jocks]; + items_wanted_in_classes["Shop Class"].listAppend($item[miniature suspension bridge]); + items_wanted_in_classes["Shop Class"].listAppend($item[world's most dangerous birdhouse]); + items_wanted_in_classes["Shop Class"].listAppend($item[deathchucks]); + if ($skill[Spirit of Rigatoni].have_skill() && my_primestat() == $stat[mysticality]) + items_wanted_in_classes["Shop Class"].listAppend($item[Staff of the Lunch Lady]); + + items_wanted_in_classes["Chemistry Class"] = listMakeBlankItem(); + items_wanted_in_classes["Chemistry Class"].listAppend($item[grains of salt]); + items_wanted_in_classes["Chemistry Class"].listAppend($item[Dirty stinkbomb]); + items_wanted_in_classes["Chemistry Class"].listAppend($item[Sodium pentasomething]); + items_wanted_in_classes["Chemistry Class"].listAppend($item[superwater]); + items_wanted_in_classes["Chemistry Class"].listAppend($item[Yellowcake bomb]); + + string [item] class_item_description; + class_item_description[$item[giant eraser]] = "free runaway"; + class_item_description[$item[grains of salt]] = "+3 adventures from a food"; + class_item_description[$item[Dirty stinkbomb]] = "banisher"; + class_item_description[$item[Sodium pentasomething]] = "+20 ML for 20 turns potion"; + class_item_description[$item[superwater]] = "50 turns of ultrahydrated"; + class_item_description[$item[Yellowcake bomb]] = "75-turn yellow-ray"; + class_item_description[$item[quasireligious sculpture]] = "-4.5 evil in cyrpt"; + class_item_description[$item[Sticky clay homunculus]] = "monster copier without daily limit"; + class_item_description[$item[Modeling claymore]] = "clears battlefield a bit"; + class_item_description[$item[miniature suspension bridge]] = "10 planks for the chasm bridge"; + class_item_description[$item[world's most dangerous birdhouse]] = "instakill"; + class_item_description[$item[deathchucks]] = "free banisher"; + class_item_description[$item[Staff of the Lunch Lady]] = "chefstaff"; + + ChecklistSubentry subentry; + subentry.header = "Kingdom of Loathing High School"; + + int adventures_used = get_property_int("_kolhsAdventures"); + int adventures_remaining = 40 - adventures_used; + int bell_ring_ring_ring = get_property_int("_kolhsSavedByTheBell"); + int ring_ring_ring_ring_left = 3 - bell_ring_ring_ring; + int priority = 0; + if (adventures_remaining > 0) + { + priority = -11; + if ($effect[jamming with the jocks].have_effect() == 0 && $effect[greaser lightnin'].have_effect() == 0 && $effect[Nerd is the Word].have_effect() == 0) + subentry.entries.listAppend("Acquire intrinsic in halls - use a moxie, muscle, or mysticality combat skill."); + if ($effect[jamming with the jocks].have_effect() > 0) + subentry.entries.listAppend("Adventure in shop class."); + if ($effect[greaser lightnin'].have_effect() > 0) + subentry.entries.listAppend("Adventure in art class."); + if ($effect[Nerd is the Word].have_effect() > 0) + subentry.entries.listAppend("Adventure in chemistry class."); + subentry.entries.listAppend(pluralise(adventures_remaining, "adventure", "adventures") + " left in school."); + } + else if (ring_ring_ring_ring_left > 0) + { + subentry.entries.listAppend(pluralise(ring_ring_ring_ring_left, "bell ring", "bell rings") + " left."); + if ($item[Yearbook Club Camera].available_amount() == 0) + subentry.entries.listAppend("Could acquire a yearbook camera. (Yearbook Club)"); + else if (get_property_boolean("yearbookCameraPending") && my_daycount() > 1) + subentry.entries.listAppend("Could turn yesterday's photograph... if you took it yesterday..."); + + subentry.entries.listAppend("Choir club for a +100% meat, +50% item buff.|It's important to sing every day!"); + + if (__misc_state["need to level"]) + { + if (my_primestat() == $stat[muscle]) + { + subentry.entries.listAppend("Gym - 50 turns of +2 mainstat/fight."); + } + else if (my_primestat() == $stat[mysticality]) + { + subentry.entries.listAppend("Undead Poets Society - 50 turns of +2 mainstat/fight."); + } + else if (my_primestat() == $stat[moxie]) + { + subentry.entries.listAppend("Bleachers - 50 turns of +2 mainstat/fight."); + } + } + + string class_can_make_things_in; + boolean [item] potential_items_creatable; + string [item] creatable_item_descriptions; + if ($effect[jamming with the jocks].have_effect() > 0) + { + class_can_make_things_in = "Shop Class"; + } + if ($effect[greaser lightnin'].have_effect() > 0) + { + class_can_make_things_in = "Art Class"; + } + if ($effect[Nerd is the Word].have_effect() > 0) + { + class_can_make_things_in = "Chemistry Class"; + } + if (class_can_make_things_in != "") + { + string [int] sorts_of_things; + foreach key, it in items_wanted_in_classes[class_can_make_things_in] + { + if (it.creatable_amount() > 0) + { + string line = pluralise(it.creatable_amount(), it); + if (class_item_description contains it) + line += " - " + class_item_description[it] + "."; + sorts_of_things.listAppend(line); + } + } + string line = class_can_make_things_in + " - make all sorts of things"; + if (sorts_of_things.count() > 0) + line += ":|*" + sorts_of_things.listJoinComponents("|*"); + else + line += "."; + subentry.entries.listAppend(line); + } + } + + if (adventures_remaining <= 0) + { + if ($item[Yearbook Club Camera].available_amount() > 0 && !get_property_boolean("yearbookCameraPending") && get_property("yearbookCameraTarget") != "" && get_property_int("yearbookCameraUpgrades") < 21) + { + string line = "Could take a picture of a " + get_property("yearbookCameraTarget") + "."; //"mine worker" is a seen value + if ($item[Yearbook Club Camera].equipped_amount() == 0) + line += "|Equip the yearbook club camera first."; + subentry.entries.listAppend(line); + } + } + + if (subentry.entries.count() > 0) + task_entries.listAppend(ChecklistEntryMake("high school", "place.php?whichplace=KOLHS", listMake(subentry), priority, $locations[the hallowed halls, shop class, chemistry class, art class]).ChecklistEntrySetIDTag("KoLHS path school time")); + + + foreach it in $items[can of the cheapest beer,bottle of fruity "wine",single swig of vodka] + { + if (it.available_amount() > 0 && my_inebriety() < 8) //is this eight or nine or + { + int importance = -11; + string [int] description; + description.listAppend("Next one won't show up until you do."); + if (__campground[$item[portable mayo clinic]] > 0) + { + importance = -10; + description.listAppend("Or drink via the mayo clinic."); + } + task_entries.listAppend(ChecklistEntryMake("__item " + it, "", ChecklistSubentryMake("Drink " + it, "", description), importance).ChecklistEntrySetIDTag("KoLHS path booze for minors")); + break; + } + } +} + +//Some simple suggestions for this forgotten path: +RegisterResourceGenerationFunction("PathWOTSFGenerateResource"); +void PathWOTSFGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_WAY_OF_THE_SURPRISING_FIST) + return; + //Meat: + if (have_outfit_components("Knob Goblin Harem Girl Disguise") && !get_property_boolean("_treasuryHaremMeatCollected") && locationAvailable($location[Cobb's Knob Barracks])) + { + resource_entries.listAppend(ChecklistEntryMake("meat", "cobbsknob.php", ChecklistSubentryMake("Cobb's Knob treasury meat", "", "Wear harem girl disguise, adventure once for 500 meat."), 5).ChecklistEntrySetIDTag("Surprising fist path knob harem meat")); + } + //Skills: + string [int] fist_teaching_properties = split_string_alternate("fistTeachingsBarroomBrawl,fistTeachingsBatHole,fistTeachingsConservatory,fistTeachingsFratHouse,fistTeachingsFunHouse,fistTeachingsHaikuDungeon,fistTeachingsMenagerie,fistTeachingsNinjaSnowmen,fistTeachingsPokerRoom,fistTeachingsRoad,fistTeachingsSlums", ","); + location [string] teaching_properties_to_locations; + teaching_properties_to_locations["fistTeachingsBarroomBrawl"] = $location[A Barroom Brawl]; + teaching_properties_to_locations["fistTeachingsBatHole"] = $location[The Bat Hole Entrance]; + teaching_properties_to_locations["fistTeachingsConservatory"] = $location[The Haunted Conservatory]; + teaching_properties_to_locations["fistTeachingsFratHouse"] = $location[The Orcish Frat House]; + teaching_properties_to_locations["fistTeachingsFunHouse"] = $location[The "Fun" House]; + teaching_properties_to_locations["fistTeachingsHaikuDungeon"] = $location[The Haiku Dungeon]; + teaching_properties_to_locations["fistTeachingsMenagerie"] = $location[Cobb's Knob Menagerie\, Level 2]; + teaching_properties_to_locations["fistTeachingsNinjaSnowmen"] = $location[Lair of the Ninja Snowmen]; + teaching_properties_to_locations["fistTeachingsPokerRoom"] = $location[The Poker Room]; + teaching_properties_to_locations["fistTeachingsRoad"] = $location[The Road to the White Citadel]; + teaching_properties_to_locations["fistTeachingsSlums"] = $location[Pandamonium Slums]; + + string [int] missing_areas; + foreach key in fist_teaching_properties + { + string property = fist_teaching_properties[key]; + if (!get_property_boolean(property)) + { + location place = teaching_properties_to_locations[property]; + missing_areas.listAppend(place.HTMLGenerateFutureTextByLocationAvailability()); + } + } + if (missing_areas.count() > 0) + resource_entries.listAppend(ChecklistEntryMake("__item Teachings of the Fist", "", ChecklistSubentryMake("Teachings of the Fist", "", "Found in " + missing_areas.listJoinComponents(", ", "and") + "."), 5).ChecklistEntrySetIDTag("Surprising fist path find fist skills")); + +} + +RegisterTaskGenerationFunction("PathTheSourceGenerateTasks"); +void PathTheSourceGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_THE_SOURCE) return; + if (!mafiaIsPastRevision(16944)) + return; + + /* + questM26Oracle + sourceOracleTarget + sourceAgentsDefeated + sourceEnlightenment + sourcePoints + */ + + int enlightenment = get_property_int("sourceEnlightenment"); + int learned_skill_count = 0; + foreach s in lookupSkills("Overclocked,Bullet Time,True Disbeliever,Code Block,Disarmament,Big Guns,Humiliating Hack,Source Kick,Reboot,Restore,Data Siphon") + { + if (s.have_skill()) + learned_skill_count += 1; + } + if (enlightenment > 0 && learned_skill_count < 11) + { + string [int] description; + + skill [int] desired_skill_order; + if (get_property_int("sourcePoints") < 3) //once you have three, you can always go the hack-siphon-kick route + desired_skill_order.listAppend($skill[Big Guns]); //tons of damage + desired_skill_order.listAppend($skill[Humiliating Hack]); //delevel a bunch + desired_skill_order.listAppend($skill[Data Siphon]); //restore MP from attacks + desired_skill_order.listAppend($skill[Source Kick]); //also a lot of damage...? + desired_skill_order.listAppend($skill[Overclocked]); //+init + + desired_skill_order.listAppend($skill[Restore]); //restore HP + desired_skill_order.listAppend($skill[Bullet Time]); //dodge 3 ranged + desired_skill_order.listAppend($skill[True Disbeliever]); //dodge 3 hack + desired_skill_order.listAppend($skill[Code Block]); //dodge 3 melee + + desired_skill_order.listAppend($skill[Disarmament]); //something + desired_skill_order.listAppend($skill[Reboot]); //removes latency + desired_skill_order.listAppend($skill[Big Guns]); //tons of damage + + foreach key, s in desired_skill_order + { + if (!s.have_skill()) + { + description.listAppend("Maybe " + s + " next."); + break; + } + } + + task_entries.listAppend(ChecklistEntryMake("ringing phone", "place.php?whichplace=manor1&action=manor1_sourcephone_ring", ChecklistSubentryMake("Learn source skill", "", description), -11).ChecklistEntrySetIDTag("Source path new skills")); + } + + if (enlightenment + learned_skill_count < 11) + { + boolean later = false; + string title = ""; + string [int] description; + string url = ""; + string target = get_property("sourceOracleTarget"); + location target_location = target.to_location(); + if ($item[no spoon].available_amount() > 0) + { + title = "Return to the Oracle"; + url = "place.php?whichplace=town_wrong&action=townwrong_oracle"; + } + else if (target == "" || !QuestState("questM26Oracle").started) + { + title = "Visit the Oracle"; + url = "place.php?whichplace=town_wrong&action=townwrong_oracle"; + string line = "If you want another source skill."; + if (learned_skill_count > 0) + line += " (have " + learned_skill_count + " so far.)"; + description.listAppend(line); + } + else if (target_location != $location[none]) + { + title = "Oracle Quest"; + url = target_location.getClickableURLForLocation(); + if (!target_location.locationAvailable()) + { + later = true; + title += " later"; + if (target_location == $location[the skeleton store]) + { + later = false; + title = "Start the skeleton store quest"; + description.listAppend("Visit the meatsmith."); + url = "shop.php?whichshop=meatsmith&action=talk"; + } + else if (target_location == $location[madness bakery]) + { + later = false; + title = "Start the madness bakery quest"; + description.listAppend("Visit the Armory and Leggery."); + url = "shop.php?whichshop=armory&action=talk"; + } + else if (target_location == $location[the overgrown lot]) + { + later = false; + title = "Start the Galaktik quest"; + description.listAppend("Visit Doc Galaktik."); + url = "shop.php?whichshop=doc&action=talk"; + } + description.listAppend("Unlock " + target_location + " first."); + } + else + { + description.listAppend("Adventure in " + target_location + "."); + description.listAppend("No spoon unappears after eleven combat turns."); + } + } + + if (title != "") + { + ChecklistEntry entry = ChecklistEntryMake("__item cookie cookie", url, ChecklistSubentryMake(title, "", description), -1); + entry.tags.id = "Source path oracle main quest"; + if (target_location != $location[none] && target_location == __last_adventure_location) + entry.should_highlight = true; + if (later) + future_task_entries.listAppend(entry); + else + optional_task_entries.listAppend(entry); + } + } + + int source_interval = get_property_int("sourceInterval"); + if (source_interval == 200 || source_interval == 400) + { + string [int] description; + CopiedMonstersGenerateDescriptionForMonster("source agent", description, true, false); + + task_entries.listAppend(ChecklistEntryMake("__item software glitch", "", ChecklistSubentryMake("Source agent now or soon", "", description), -11).ChecklistEntrySetIDTag("Source path source agent fight now")); + } + else if (source_interval > 0) + { + string [int] description; + int turns = (source_interval - 400) / 200; + if (get_property_int("sourceAgentsDefeated") > 0) + description.listAppend(pluralise(get_property_int("sourceAgentsDefeated"), "agent", "agents") + " defeated so far."); + if (QuestState("questM26Oracle").in_progress) + description.listAppend("Oracle quests won't advance the counter."); + optional_task_entries.listAppend(ChecklistEntryMake("__item software glitch", "", ChecklistSubentryMake("Source agent after ~" + pluralise(turns, "won combat", "won combats"), "", description)).ChecklistEntrySetIDTag("Source path source agent fight later")); + } +} + +RegisterResourceGenerationFunction("PathTheSourceGenerateResource"); +void PathTheSourceGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_THE_SOURCE) + return; +} + +RegisterTaskGenerationFunction("PathZombieSlayerGenerateTasks"); +void PathZombieSlayerGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_ZOMBIE_SLAYER) + return; + //zombiePoints is the number of points "permed" on the character, not how many they have at the moment + //Let's see.. I think this means we can infer how many points they have to spend, right? You start with zombiePoints + 1, then gain one for each level you have, minus how many hunter brains you have, minus whether you've fought the right hunter yet... but, we can't know that information. Hmm. So, no, no reminder. Alas. + //We could, however, suggest they eat a hunter brain. + //ashq string out; foreach s in $skills[] if (s.class == $class[zombie master]) out += ", " + s; print(out); + if ($item[hunter brain].available_amount() > 0 && availableFullness() >= 1) + { + int zombie_skills_have = 0; + foreach s in $skills[Infectious Bite, Bite Minion, Lure Minions, Undying Greed, Hunter's Sprint, Insatiable Hunger, Devour Minions, Indefatigable, Skullcracker, Neurogourmet, Ravenous Pounce, Distracting Minion, Plague Claws, Flesh Mob, Elemental Obliviousness, Vigor Mortis, Virulence, Bilious Burst, Unyielding Flesh, Corpse Pile, Howl of the Alpha, Summon Minion, Zombie Chow, Smash & Graaagh, Scavenge, Meat Shields, Summon Horde, His Master's Voice, Ag-grave-ation, Disquiet Riot, Zombie Maestro, Recruit Zombie] + { + if (s.have_skill()) + zombie_skills_have += 1; + } + if (zombie_skills_have < 30) + { + //probably should suggest eat X hunter brains but + optional_task_entries.listAppend(ChecklistEntryMake("__item hunter brain", "inventory.php?ftext=hunter+brain", ChecklistSubentryMake("Eat a hunter brain", "", "Gain a skill point."), -1).ChecklistEntrySetIDTag("Zombie slayer path skill points")); + } + } + +} + +RegisterResourceGenerationFunction("PathZombieSlayerGenerateResource"); +void PathZombieSlayerGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_ZOMBIE_SLAYER) return; + + if ($item[right bear arm].available_amount() > 0 && $item[left bear arm].available_amount() > 0) + { + int bear_hugs_remaining = clampi(10 - get_property_int("_bearHugs"), 0, 10); + + if (bear_hugs_remaining > 0) + { + string url; + string [int] description; + description.listAppend("Converts monster to zombies. Ideally, use against group monsters."); + string [int] items_to_equip; + foreach it in $items[right bear arm,left bear arm] + { + if (it.equipped_amount() == 0) + items_to_equip.listAppend(it); + } + if (items_to_equip.count() > 0) + { + url = "inventory.php?which=2"; + description.listAppend("Equip " + items_to_equip.listJoinComponents(", ", "and") + "."); + } + resource_entries.listAppend(ChecklistEntryMake("__item right bear arm", url, ChecklistSubentryMake(pluralise(bear_hugs_remaining, "bear hug", "bear hugs"), "", description), 8).ChecklistEntrySetIDTag("Zombie slayer path bear arms hugs")); + + } + } +} + +RegisterTaskGenerationFunction("PathNuclearAutumnGenerateTasks"); +void PathNuclearAutumnGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_NUCLEAR_AUTUMN) + return; + string url = "place.php?whichplace=falloutshelter"; + + ChecklistSubentry [int] subentries; + + if (get_property_int("falloutShelterLevel") >= 2 && (my_turncount() >= 50 || get_property_boolean("falloutShelterChronoUsed"))) + { + if ($item[Rad-Pro (1 oz.)].to_effect().have_effect() <= 1 && my_meat() >= 500 && $item[lead umbrella].equipped_amount() == 0) + { + url = "shop.php?whichshop=vault1"; + if ($item[Rad-Pro (1 oz.)].available_amount() > 0) + url = "inventory.php?ftext=rad-pro"; //FIXME + subentries.listAppend(ChecklistSubentryMake("Use rad-pro", "", "Protect from radiation.")); + } + } + + if (get_property_int("falloutShelterLevel") >= 8 && !get_property_boolean("falloutShelterCoolingTankUsed")) + { + subentries.listAppend(ChecklistSubentryMake("Use cooling tank", "", "Gain 300 rads.")); + } + if (get_property_int("falloutShelterLevel") >= 5 && !get_property_boolean("falloutShelterChronoUsed")) + { + subentries.listAppend(ChecklistSubentryMake("Use chronodynamics laboratory", "", "Increase rads gained.")); + } + if (get_property_int("falloutShelterLevel") >= 4 && $item[wrist-boy].available_amount() == 0 && my_meat() >= 5000) + { + subentries.listAppend(ChecklistSubentryMake("Acquire wrist-boy", "", "Unlocks buff records.")); + url = "shop.php?whichshop=vault2"; + } + + if (subentries.count() > 0) + task_entries.listAppend(ChecklistEntryMake("__item rad", url, subentries, 0).ChecklistEntrySetIDTag("Nuclear autumn path shelter action suggestion")); +} + +RegisterResourceGenerationFunction("PathNuclearAutumnGenerateResource"); +void PathNuclearAutumnGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_NUCLEAR_AUTUMN) return; + + item rad = $item[rad]; + if (rad.available_amount() > 0) + { + int [skill] skill_rad_cost; + + foreach s in $skills[Boiling Tear Ducts,Projectile Salivary Glands,Translucent Skin,Skunk Glands,Throat Refrigerant,Internal Soda Machine] + skill_rad_cost[s] = 30; + foreach s in $skills[Steroid Bladder,Magic Sweat,Flappy Ears,Self-Combing Hair,Intracranial Eye,Mind Bullets,Extra Kidney,Extra Gall Bladder] + skill_rad_cost[s] = 60; + foreach s in $skills[Extra Muscles,Adipose Polymers,Metallic Skin,Hypno-Eyes,Extra Brain,Squid Glands,Extremely Punchable Face,Magnetic Ears,Firefly Abdomen,Bone Springs] + skill_rad_cost[s] = 90; + foreach s in $skills[Sucker Fingers,Backwards Knees] + skill_rad_cost[s] = 120; + + string [skill] skill_descriptions; + skill_descriptions[$skill[Extra Gall Bladder]] = "+100% adventures from food"; + skill_descriptions[$skill[Extra Kidney]] = "+100% Adventures from booze"; + skill_descriptions[$skill[Internal Soda Machine]] = "Restore MP for meat"; + skill_descriptions[$skill[Squid Glands]] = "-10% combat buff"; + skill_descriptions[$skill[Steroid Bladder]] = "+50% muscle buff"; + skill_descriptions[$skill[Extra Muscles]] = "+50% muscle passive"; + skill_descriptions[$skill[Self-Combing Hair]] = "+50% moxie buff"; + skill_descriptions[$skill[Hypno-Eyes]] = "+50% moxie passive"; + skill_descriptions[$skill[Intracranial Eye]] = "+50% myst buff"; + skill_descriptions[$skill[Extra Brain]] = "+50% myst passive"; + skill_descriptions[$skill[Extremely Punchable Face]] = "+30 ML buff"; + skill_descriptions[$skill[Magnetic Ears]] = "15% item buff"; + skill_descriptions[$skill[Sucker Fingers]] = "15% item passive"; + skill_descriptions[$skill[Firefly Abdomen]] = "+10% combat buff"; + skill_descriptions[$skill[Throat Refrigerant]] = "Cold damage spell"; + skill_descriptions[$skill[Flappy Ears]] = "+2 all res buff"; + skill_descriptions[$skill[Metallic Skin]] = "+2 all res passive"; + skill_descriptions[$skill[Bone Springs]] = "+20% init buff"; + skill_descriptions[$skill[Backwards Knees]] = "+20% init passive"; + skill_descriptions[$skill[Magic Sweat]] = "+100 DA, +10 DR buff"; + skill_descriptions[$skill[Adipose Polymers]] = "+100 DA, +10 DR passive"; + skill_descriptions[$skill[Mind Bullets]] = "stunning spell"; + + skill [int] desired_skill_order; + + desired_skill_order.listAppend($skill[Extra Gall Bladder]); //Passive - +100% adventures from food + desired_skill_order.listAppend($skill[Extra Kidney]); //Passive - +100% Adventures from booze + desired_skill_order.listAppend($skill[Internal Soda Machine]); //Passive - Spend 20 meat to recover 10 MP + + desired_skill_order.listAppend($skill[Squid Glands]); //-10% combat rate buff + if (my_primestat() == $stat[muscle]) + { + desired_skill_order.listAppend($skill[Steroid Bladder]); //Buff - +50% Muscle + desired_skill_order.listAppend($skill[Extra Muscles]); //Passive - +50% Muscle + } + else if (my_primestat() == $stat[moxie]) + { + desired_skill_order.listAppend($skill[Self-Combing Hair]); //Buff - +50% Moxie + desired_skill_order.listAppend($skill[Hypno-Eyes]); //Passive - +50% Moxie + } + else if (my_primestat() == $stat[Mysticality]) + { + desired_skill_order.listAppend($skill[Intracranial Eye]); //Buff - +50% Mysticality + desired_skill_order.listAppend($skill[Extra Brain]); //Passive - +50% Mysticality + } + + desired_skill_order.listAppend($skill[Extremely Punchable Face]); //+30 ML buff + desired_skill_order.listAppend($skill[Magnetic Ears]); //15% item buff + desired_skill_order.listAppend($skill[Sucker Fingers]); //15% item passive + desired_skill_order.listAppend($skill[Firefly Abdomen]); //+10% combat rate buff + + desired_skill_order.listAppend($skill[Throat Refrigerant]); //Combat - Cold damage + desired_skill_order.listAppend($skill[Flappy Ears]); //Buff - +2 resistance to all elements + desired_skill_order.listAppend($skill[Metallic Skin]); //Passive - +2 resistance to all elements + + + desired_skill_order.listAppend($skill[Bone Springs]); //+20% init buff + desired_skill_order.listAppend($skill[Backwards Knees]); //+20% init passive + + desired_skill_order.listAppend($skill[Magic Sweat]); //Buff - Damage Absorption +100 - Damage Reduction: 10 + desired_skill_order.listAppend($skill[Adipose Polymers]); //Passive - Damage Absorption +100 - Damage Reduction: 10 + desired_skill_order.listAppend($skill[Mind Bullets]); //Combat - Stuns opponent + desired_skill_order.listAppend($skill[Self-Combing Hair]); //Buff - +50% Moxie + desired_skill_order.listAppend($skill[Hypno-Eyes]); //Passive - +50% Moxie + desired_skill_order.listAppend($skill[Steroid Bladder]); //Buff - +50% Muscle + desired_skill_order.listAppend($skill[Extra Muscles]); //Passive - +50% Muscle + desired_skill_order.listAppend($skill[Intracranial Eye]); //Buff - +50% Mysticality + desired_skill_order.listAppend($skill[Extra Brain]); //Passive - +50% Mysticality + + //desired_skill_order.listAppend($skill[Boiling Tear Ducts]); //Combat - Hot damage + //desired_skill_order.listAppend($skill[Projectile Salivary Glands]); //Combat - Sleaze damage + //desired_skill_order.listAppend($skill[Translucent Skin]); //Combat - Spooky damage + //desired_skill_order.listAppend($skill[Skunk Glands]); //Combat - Stench damage + + string [int] description; + + boolean [skill] already_displayed_skill; + foreach key, s in desired_skill_order + { + if (s.have_skill()) + continue; + if (($skills[Magnetic Ears,Sucker Fingers,Extremely Punchable Face,Firefly Abdomen,Bone Springs,Squid Glands,Backwards Knees] contains s) && get_property_int("falloutShelterLevel") < 6) //not yet + continue; + if (already_displayed_skill[s]) + continue; + already_displayed_skill[s] = true; + string line = s + ": " + skill_descriptions[s]; + if (skill_rad_cost[s] > $item[rad].available_amount()) + line = HTMLGenerateSpanFont(line, "gray"); + description.listAppend(line); + } + + resource_entries.listAppend(ChecklistEntryMake("__item rad", "shop.php?whichshop=mutate", ChecklistSubentryMake(pluralise(rad) + " available", "", description), 8).ChecklistEntrySetIDTag("Nuclear autumn path rad shop")); + } + if (get_property_int("falloutShelterLevel") >= 3 && !get_property_boolean("_falloutShelterSpaUsed")) + { + //FIXME sync with above + } +} +static +{ + item [skill][int] __gelatinous_items_that_give_skill; + + string [int] __gelatinous_skill_ids_to_descriptions {23001:"+1 hot res", 23002:"+1 hot res", 23003:"+2 hot res", 23004:"+2 hot res", 23005:"+3 hot res", 23006:"+1 cold res", 23007:"+1 cold res", 23008:"+2 cold res", 23009:"+2 cold res", 23010:"+3 cold res", 23011:"+1 stench res", 23012:"+1 stench res", 23013:"+2 stench res", 23014:"+2 stench res", 23015:"+3 stench res", 23016:"+1 spooky res", 23017:"+1 spooky res", 23018:"+2 spooky res", 23019:"+2 spooky res", 23020:"+3 spooky res", 23021:"+1 sleaze res", 23022:"+1 sleaze res", 23023:"+2 sleaze res", 23024:"+2 sleaze res", 23025:"+3 sleaze res", 23026:"+30 DA", 23027:"+40 DA", 23028:"+50 DA", 23029:"+60 DA", 23030:"+70 DA", 23031:"+5 DR", 23032:"+5 DR", 23033:"+10 DR", 23034:"+10 DR", 23035:"+20 DR", 23036:"+10% init", 23037:"+20% init", 23038:"+30% init", 23039:"+40% init", 23040:"+50% init", 23041:"+3 stats/fight", 23042:"+3 stats/fight", 23043:"+5 stats/fight", 23044:"+5 stats/fight", 23045:"+7 stats/fight", 23046:"+1 adv/absorbed item", 23047:"+1 adv/absorbed item", 23048:"+2 adv/absorbed item", 23049:"+2 adv/absorbed item", 23050:"+3 adv/absorbed item", 23051:"+5 stats/absorbed item", 23052:"+10 stats/absorbed item", 23053:"+15 stats/absorbed item", 23054:"+20 stats/absorbed item", 23055:"+25 stats/absorbed item", 23056:"+20% HP", 23057:"+30% HP", 23058:"+40% HP", 23059:"+50% HP", 23060:"+100% HP", 23061:"+20% MP", 23062:"+30% MP", 23063:"+40% MP", 23064:"+50% MP", 23065:"+100% MP", 23066:"+20% item", 23067:"+20% item", 23068:"+30% item", 23069:"+40% item", 23070:"+50% item", 23071:"+10% pickpocket", 23072:"+20% pickpocket", 23073:"+30% pickpocket", 23074:"+40% pickpocket", 23075:"+50% pickpocket", 23076:"+30% meat", 23077:"+40% meat", 23078:"+50% meat", 23079:"+60% meat", 23080:"+70% meat", 23081:"+5 muscle", 23082:"+10 muscle", 23083:"+15 muscle", 23084:"+20 muscle", 23085:"+25 muscle", 23086:"+5 myst", 23087:"+10 myst", 23088:"+15 myst", 23089:"+20 myst", 23090:"+25 myst", 23091:"+5 moxie", 23092:"+10 moxie", 23093:"+15 moxie", 23094:"+20 moxie", 23095:"+25 moxie", 23096:"+7 damage", 23097:"+9 damage", 23098:"+11 damage", 23099:"+13 damage", 23100:"+15 damage", 23101:"+3 Hot Damage", 23102:"+5 Hot Damage", 23103:"+7 Hot Damage", 23104:"+9 Hot Damage", 23105:"+11 Hot Damage", 23106:"+3 Cold Damage", 23107:"+5 Cold Damage", 23108:"+7 Cold Damage", 23109:"+9 Cold Damage", 23110:"+11 Cold Damage", 23111:"+3 Stench Damage", 23112:"+5 Stench Damage", 23113:"+7 Stench Damage", 23114:"+9 Stench Damage", 23115:"+11 Stench Damage", 23116:"+3 Spooky Damage", 23117:"+5 Spooky Damage", 23118:"+7 Spooky Damage", 23119:"+9 Spooky Damage", 23120:"+11 Spooky Damage", 23121:"+3 Sleaze Damage", 23122:"+5 Sleaze Damage", 23123:"+7 Sleaze Damage", 23124:"+9 Sleaze Damage", 23125:"+11 Sleaze Damage", 23301:"-combat buff", 23302:"-combat buff", 23303:"-combat buff", 23304:"+combat buff", 23305:"+combat buff", 23306:"+combat buff"}; + int [int] __gelatinous_evaluation_order {0:23301, 1:23302, 2:23303, 3:23304, 4:23305, 5:23306, 6:23046, 7:23047, 8:23048, 9:23049, 10:23050, 11:23051, 12:23052, 13:23053, 14:23054, 15:23055, 16:23041, 17:23042, 18:23043, 19:23044, 20:23045, 21:23066, 22:23067, 23:23068, 24:23069, 25:23070, 26:23076, 27:23077, 28:23078, 29:23079, 30:23080, 31:23026, 32:23027, 33:23028, 34:23029, 35:23030, 36:23031, 37:23032, 38:23033, 39:23034, 40:23035, 41:23036, 42:23037, 43:23038, 44:23039, 45:23040, 46:23056, 47:23057, 48:23058, 49:23059, 50:23060, 51:23061, 52:23062, 53:23063, 54:23064, 55:23065, 56:23071, 57:23072, 58:23073, 59:23074, 60:23075, 61:23001, 62:23002, 63:23003, 64:23004, 65:23005, 66:23006, 67:23007, 68:23008, 69:23009, 70:23010, 71:23011, 72:23012, 73:23013, 74:23014, 75:23015, 76:23016, 77:23017, 78:23018, 79:23019, 80:23020, 81:23021, 82:23022, 83:23023, 84:23024, 85:23025, 86:23081, 87:23082, 88:23083, 89:23084, 90:23085, 91:23086, 92:23087, 93:23088, 94:23089, 95:23090, 96:23091, 97:23092, 98:23093, 99:23094, 100:23095, 101:23096, 102:23097, 103:23098, 104:23099, 105:23100, 106:23101, 107:23102, 108:23103, 109:23104, 110:23105, 111:23106, 112:23107, 113:23108, 114:23109, 115:23110, 116:23111, 117:23112, 118:23113, 119:23114, 120:23115, 121:23116, 122:23117, 123:23118, 124:23119, 125:23120, 126:23121, 127:23122, 128:23123, 129:23124, 130:23125}; + + int [int] __gelatinous_skill_raw_modifier_number {23001:1, 23002:1, 23003:2, 23004:2, 23005:3, 23006:1, 23007:1, 23008:2, 23009:2, 23010:3, 23011:1, 23012:1, 23013:2, 23014:2, 23015:3, 23016:1, 23017:1, 23018:2, 23019:2, 23020:3, 23021:1, 23022:1, 23023:2, 23024:2, 23025:3, 23026:30, 23027:40, 23028:50, 23029:60, 23030:70, 23031:5, 23032:5, 23033:10, 23034:10, 23035:20, 23036:10, 23037:20, 23038:30, 23039:40, 23040:50, 23041:3, 23042:3, 23043:5, 23044:5, 23045:7, 23046:1, 23047:1, 23048:2, 23049:2, 23050:3, 23051:5, 23052:10, 23053:15, 23054:20, 23055:25, 23056:20, 23057:30, 23058:40, 23059:50, 23060:100, 23061:20, 23062:30, 23063:40, 23064:50, 23065:100, 23066:20, 23067:20, 23068:30, 23069:40, 23070:50, 23071:10, 23072:20, 23073:30, 23074:40, 23075:50, 23076:30, 23077:40, 23078:50, 23079:60, 23080:70, 23081:5, 23082:10, 23083:15, 23084:20, 23085:25, 23086:5, 23087:10, 23088:15, 23089:20, 23090:25, 23091:5, 23092:10, 23093:15, 23094:20, 23095:25, 23096:7, 23097:9, 23098:11, 23099:13, 23100:15, 23101:3, 23102:5, 23103:7, 23104:9, 23105:11, 23106:3, 23107:5, 23108:7, 23109:9, 23110:11, 23111:3, 23112:5, 23113:7, 23114:9, 23115:11, 23116:3, 23117:5, 23118:7, 23119:9, 23120:11, 23121:3, 23122:5, 23123:7, 23124:9, 23125:11}; +} +void initialiseGelatinousStatics() +{ + if (__gelatinous_items_that_give_skill.count() > 0) + return; + foreach it in $items[] + { + if (!it.item_is_pvp_stealable() && !(it.gift && it.discardable) && !(lookupItems("interesting clod of dirt,dirty bottlecap,discarded button") contains it)) continue; + + if ($slots[hat,weapon,off-hand,back,shirt,pants,acc1,acc2,acc3] contains it.to_slot()) //familiar equipment fine + continue; + if ($items[map to Madness Reef,map to the Marinara Trench,map to Anemone Mine,map to the Dive Bar,map to the Skate Park, glass of "milk", cup of "tea", thermos of "whiskey", Lucky Lindy, Bee's Knees, Sockdollager, Ish Kabibble, Hot Socks, Phonus Balonus, Flivver, Sloppy Jalopy] contains it) //' + continue; + + int lookup = it.descid.to_int_silent() % 125 + 23001; + int item_id = it.to_int(); + //Hardcoded: + if (item_id == 9353) + lookup = 23302; + else if (item_id == 9349) + lookup = 23304; + else if (item_id == 9357) + lookup = 23301; + else if (item_id == 9359) + lookup = 23306; + else if (item_id == 9361) + lookup = 23305; + else if (item_id == 9354) + lookup = 23303; + skill s = lookup.to_skill(); + if (!(__gelatinous_items_that_give_skill contains s)) + __gelatinous_items_that_give_skill[s] = listMakeBlankItem(); + __gelatinous_items_that_give_skill[s].listAppend(it); + } + + +} + + +RegisterTaskGenerationFunction("PathGelatinousNoobGenerateTasks"); +void PathGelatinousNoobGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_GELATINOUS_NOOB) return; + + int total_absorptions = 2 + MIN(13, my_level()); + int absorptions_used = get_property_int("_noobSkillCount"); + //int absorptions_used = my_absorbs(); //FIXME next point release, 17.7 + int absorptions_left = total_absorptions - absorptions_used; + if (!mafiaIsPastRevision(17821)) //tracking + absorptions_left = 0; + if (absorptions_left > 0) + { + initialiseGelatinousStatics(); + string [int] description; + + + if (true) + { + boolean [item] blocklist; + + if (__quest_state["Level 9"].state_int["peak tests remaining"] > 0) + blocklist[$item[rusty hedge trimmers]] = true; + if ($item[goat cheese].available_amount() <= 3 && !__quest_state["Level 8"].state_boolean["Past mine"]) + { + blocklist[$item[goat cheese]] = true; + blocklist[$item[goat cheese pizza]] = true; + } + foreach it in $items[print screen button,spooky-gro fertilizer,cuppa obscuri tea] + blocklist[it] = true; + if (__quest_state["Pirate Quest"].state_boolean["hot wings relevant"] && $item[hot wing].available_amount() <= 3) + blocklist[$item[hot wing]] = true; + + //Collect a list for each grouping: + + int [int][int] first_level_group_evaluation_indices; + for grouping_index from 23125 to 23001 by -5 + { + int [int] group_indices; + for i from grouping_index to grouping_index - 4 by -1 + { + group_indices.listAppend(i); + } + first_level_group_evaluation_indices[grouping_index] = group_indices; + } + first_level_group_evaluation_indices[23301] = listMake(23303, 23302, 23301); + first_level_group_evaluation_indices[23304] = listMake(23306, 23305, 23304); + + string [int][int] grouping_to_relevant_items; + + skill [int][int] grouping_to_group_skills; + skill [int] grouping_to_relevant_items_skill; + boolean [int] grouping_should_grey_out; + //for grouping_index from 23125 to 23001 by -5 + foreach grouping_index in first_level_group_evaluation_indices + { + int [int] group_indices = first_level_group_evaluation_indices[grouping_index]; + + skill [int] group_skills; + //for i from grouping_index to grouping_index - 4 by -1 + foreach key2, i in group_indices + { + skill s = i.to_skill(); + if (s.have_skill()) continue; + group_skills.listAppend(s); + } + //print_html("group_skills = " + group_skills.to_json()); + grouping_to_group_skills[grouping_index] = group_skills; + //The ideal here is, we want to find a list of items for the best skill in the group. + //If that's not possible, we do the second best skill, etc. We also list the best pull, but only if it's relevant + item pullable_item = $item[none]; + item [int] relevant_items; + boolean on_first = true; + foreach key, s in group_skills + { + if (key > 0) + on_first = false; + foreach key2, it in __gelatinous_items_that_give_skill[s] + { + if (blocklist contains it) + continue; + if (it.available_amount() == 0 && it.creatable_amount() == 0 && (it.npc_price() == 0 || it.npc_price() > my_meat())) + { + if (pulls_remaining() > 0 && !it.gift && key == 0 && it.is_unrestricted()) + { + if (pullable_item == $item[none] || (it.historical_price() < pullable_item.historical_price() && it.historical_price() > 0)) + pullable_item = it; + } + continue; + } + relevant_items.listAppend(it); + } + if (relevant_items.count() > 0) + { + grouping_to_relevant_items_skill[grouping_index] = s; + break; + } + } + boolean should_grey_out = false; + if (grouping_to_relevant_items_skill[grouping_index] == $skill[none]) + { + grouping_to_relevant_items_skill[grouping_index] = group_skills[0]; + should_grey_out = true; + } + grouping_should_grey_out[grouping_index] = should_grey_out; + string [int] relevant_items_out; + //sort relevant_items by (value.historical_price() <= 0 ? 999999999 : value.historical_price()); + //NPC price is more relevant in-run, since cost of acquisition. + sort relevant_items by (value.npc_price() > 0 ? value.npc_price() : (value.historical_price() <= 0 ? 999999999 : value.historical_price())); + if (relevant_items[0].npc_price() > 0 && relevant_items[0].npc_price() <= 1000) //something cheap and obtainable? ignore the rest + { + //examples: fermenting powder, herbs, pickled egg + relevant_items_out.listAppend(relevant_items[0]); + } + else + { + foreach key, it in relevant_items + { + if (key > 2) break; + relevant_items_out.listAppend(it); + } + } + if (pulls_remaining() > 0 && (!on_first || relevant_items.count() == 0) && pullable_item != $item[none]) + { + string line = pullable_item + " (pull"; + if (!should_grey_out) + line += " for +" + __gelatinous_skill_raw_modifier_number[group_skills[0].to_int()]; + line += ")"; + line = HTMLGenerateSpanFont(line, "gray"); + relevant_items_out.listPrepend(line); + } + grouping_to_relevant_items[grouping_index] = relevant_items_out; + } + + foreach key, s_id in __gelatinous_evaluation_order + { + if (s_id % 5 != 0 && s_id != 23301 && s_id != 23304) continue; + skill s = s_id.to_skill(); + int grouping_index = s_id; + + string [int] relevant_items = grouping_to_relevant_items[grouping_index]; + skill [int] group_skills = grouping_to_group_skills[grouping_index]; + skill relevant_items_skill = grouping_to_relevant_items_skill[grouping_index]; + + //print_html("s = " + s + " group_skills = " + group_skills.to_json() + ", relevant_items = " + relevant_items.to_json()); + + //description.listAppend(relevant_items_skill + ": " + __gelatinous_skill_ids_to_descriptions[relevant_items_skill.to_int()]); + string extra_data; + if (lookupFamiliar("robortender").familiar_is_usable()) + { + phylum [int] phylums_to_run_against; + if (grouping_index == 23301) + { + if (!lookupSkill("bendable knees").have_skill() && lookupItem("bottle of gregnadigne").available_amount() == 0) + phylums_to_run_against.listAppend($phylum[humanoid]); + if (!lookupSkill("retractable toes").have_skill() && lookupItem("cocktail mushroom").available_amount() == 0) + phylums_to_run_against.listAppend($phylum[goblin]); + if (!lookupSkill("ink gland").have_skill() && lookupItem("shot of granola liqueur").available_amount() == 0) + phylums_to_run_against.listAppend($phylum[hippy]); + } + if (grouping_index == 23304) + { + if (!lookupSkill("frown muscles").have_skill() && lookupItem("bottle of novelty hot sauce").available_amount() == 0) + phylums_to_run_against.listAppend($phylum[demon]); + if (!lookupSkill("anger glands").have_skill() && lookupItem("limepatch").available_amount() == 0) + phylums_to_run_against.listAppend($phylum[pirate]); + if (!lookupSkill("powerful vocal chords").have_skill() && lookupItem("baby oil shooter").available_amount() == 0) + phylums_to_run_against.listAppend($phylum[orc]); + } + if (phylums_to_run_against.count() > 0) + extra_data += "Run robortender against " + phylums_to_run_against.listJoinComponents(", ", "and"); + } + + string line = HTMLGenerateSpanOfClass(__gelatinous_skill_ids_to_descriptions[relevant_items_skill.to_int()], "r_bold"); + if (relevant_items.count() > 0 || extra_data != "") + { + if (relevant_items.count() > 0) + line += ": " + relevant_items.listJoinComponents(", ", "or"); + if (extra_data != "") + line += "|*" + extra_data; + line += "."; + if (grouping_should_grey_out[grouping_index]) + line = HTMLGenerateSpanFont(line, "gray"); + description.listAppend(line); + } + + } + description.listAppend("Or equipment, for their buffs." + (combat_rate_modifier() > -25 ? "|*Bram's choker, ring of conflict, duonoculars, rusted shootin' iron, or red shoe especially." : "")); + if (lookupSkill("Large Intestine").have_skill()) + description.listAppend("Or potted cactus, for +5 adventures."); + //foreach s in __gelatinous_items_that_give_skill + /*foreach key, s_id in __gelatinous_evaluation_order + { + skill s = s_id.to_skill(); + if (s.have_skill()) continue; + + string [int] relevant_items; + item pullable_item = $item[none]; + boolean should_grey_out = false; + foreach key, it in __gelatinous_items_that_give_skill[s] + { + if (blocklist contains it) + continue; + if (it.available_amount() == 0 && it.creatable_amount() == 0 && (it.npc_price() == 0 || it.npc_price() > my_meat())) + { + if (pulls_remaining() > 0 && !it.gift) + { + if (pullable_item == $item[none] || (it.historical_price() < pullable_item.historical_price() && it.historical_price() > 0)) + pullable_item = it; + } + continue; + } + relevant_items.listAppend(it); + } + if (pullable_item != $item[none] && relevant_items.count() == 0) + { + if (relevant_items.count() == 0) + should_grey_out = true; + relevant_items.listAppend(HTMLGenerateSpanFont(pullable_item + " (pull)", "gray")); + } + string line = HTMLGenerateSpanOfClass(__gelatinous_skill_ids_to_descriptions[s.to_int()], "r_bold"); + if (relevant_items.count() > 0) + line += ": " + relevant_items.listJoinComponents(", ", "or") + "."; + else + should_grey_out = true; + if (should_grey_out) + line = HTMLGenerateSpanFont(line, "gray"); + description.listAppend(line); + }*/ + } + optional_task_entries.listAppend(ChecklistEntryMake("__familiar Gelatinous Cubeling", "inventory.php", ChecklistSubentryMake("Absorb " + pluralise(absorptions_left, "item", "items"), "", description), -1).ChecklistEntrySetIDTag("Gelatinous noob path absorption suggestions")); + } + + if (lookupFamiliar("Robortender").have_familiar()) + { + + string url = ""; + + if (my_familiar() != lookupFamiliar("Robortender")) + url = "familiar.php"; + phylum [int] phylums_to_run_against; + location [int] suggested_locations; + string [int] matchup_type; + boolean have_minus = false; + boolean have_plus = false; + if (!lookupSkill("bendable knees").have_skill() && lookupItem("bottle of gregnadigne").available_amount() == 0) + { + phylums_to_run_against.listAppend($phylum[humanoid]); + suggested_locations.listAppend($location[the old landfill]); + matchup_type.listAppend("-"); + have_minus = true; + } + if (!lookupSkill("retractable toes").have_skill() && lookupItem("cocktail mushroom").available_amount() == 0) + { + phylums_to_run_against.listAppend($phylum[goblin]); + suggested_locations.listAppend($location[the outskirts of cobb's knob]); + matchup_type.listAppend("-"); + have_minus = true; + } + if (!lookupSkill("ink gland").have_skill() && lookupItem("shot of granola liqueur").available_amount() == 0) + { + phylums_to_run_against.listAppend($phylum[hippy]); + suggested_locations.listAppend($location[The Hippy Camp]); + matchup_type.listAppend("-"); + have_minus = true; + } + if (!lookupSkill("frown muscles").have_skill() && lookupItem("bottle of novelty hot sauce").available_amount() == 0) + { + phylums_to_run_against.listAppend($phylum[demon]); + suggested_locations.listAppend($location[the dark heart of the woods]); + matchup_type.listAppend("+"); + have_plus = true; + } + if (!lookupSkill("anger glands").have_skill() && lookupItem("limepatch").available_amount() == 0) + { + phylums_to_run_against.listAppend($phylum[pirate]); + suggested_locations.listAppend($location[the obligatory pirate's cove]); + matchup_type.listAppend("+"); + have_plus = true; + } + if (!lookupSkill("powerful vocal chords").have_skill() && lookupItem("baby oil shooter").available_amount() == 0) + { + phylums_to_run_against.listAppend($phylum[orc]); + suggested_locations.listAppend($location[The Orcish Frat House]); + matchup_type.listAppend("+"); + have_plus = true; + } + + string [int] skill_types; + if (have_minus) + skill_types.listAppend("-combat"); + if (have_plus) + skill_types.listAppend("+combat"); + string [int] description; + description.listAppend("Collect components for " + skill_types.listJoinComponents(", ", "and") + " skills."); + if (suggested_locations.count() > 0) + { + string [int] locations_out; + foreach key, l in suggested_locations + { + locations_out.listAppend(l + " (" + matchup_type[key] + ")"); + } + description.listAppend("Could look in " + locations_out.listJoinComponents(", ", "and") + "."); + if (url == "") + url = suggested_locations[0].getClickableURLForLocation(); + } + if (phylums_to_run_against.count() > 0) + { + string [int] phylums_out; + foreach key, p in phylums_to_run_against + { + phylums_out.listAppend(p + " (" + matchup_type[key] + ")"); + } + optional_task_entries.listAppend(ChecklistEntryMake("__familiar Robortender", url, ChecklistSubentryMake("Run robortender against " + phylums_out.listJoinComponents(", ", "and"), "", description), 5).ChecklistEntrySetIDTag("Gelatinous noob path robortender familiar")); + } + } +} + +RegisterTaskGenerationFunction("PathLicenseToAdventureGenerateTasks"); +void PathLicenseToAdventureGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_LICENSE_TO_ADVENTURE) + return; + if (lookupItem("Victor's Spoils").available_amount() > 0 && !get_property_boolean("_victorSpoilsUsed")) + { + task_entries.listAppend(ChecklistEntryMake("__item victor's spoils", "inventory.php?ftext=victor's+spoils", ChecklistSubentryMake("Use Victor's Spoils", "", "Gives eleven adventures."), 3).ChecklistEntrySetIDTag("License to adventure victor's spoils")); + } + + int lair_progress = get_property_int("_villainLairProgress"); + if (lair_progress < 999 && mafiaIsPastRevision(18065)) //revision is a guess + { + //_villainLairColorChoiceUsed, _villainLairDoorChoiceUsed, _villainLairSymbologyChoiceUsed + //_villainLairCanLidUsed, _villainLairFirecrackerUsed, _villainLairWebUsed + string [int] description; + string [int] modifiers; + description.listAppend("Prevents disavowed debuff. Costs quite a few turns, though, so consider skipping if you're leaderboarding."); + description.listAppend("Progress: " + lair_progress + " minions."); + + if (!get_property_boolean("bondSymbols") && get_property_boolean("_villainLairSymbologyChoiceUsed")) + description.listAppend("May want to learn LI-11's Universal Symbology Guide first, saves fifteen turns."); + + item [int] items_to_throw; + if (!get_property_boolean("_villainLairCanLidUsed") && $item[razor-sharp can lid].item_amount() > 0) + items_to_throw.listAppend($item[razor-sharp can lid]); + if (!get_property_boolean("_villainLairFirecrackerUsed")) + { + if ($item[Knob Goblin firecracker].item_amount() > 0) + items_to_throw.listAppend($item[Knob Goblin firecracker]); + else if (!$location[cobb's knob barracks].locationAvailable()) + description.listAppend("Farm a Knob Goblin Firecracker from the Outskirts of Cobb's Knob first, but only while you're still on that quest."); + } + if (!get_property_boolean("_villainLairWebUsed") && $item[spider web].item_amount() > 0) + items_to_throw.listAppend($item[spider web]); + if (lookupItem("can of Minions-Be-Gone").item_amount() > 0) + description.listAppend("Use " + pluralise(lookupItem("can of Minions-Be-Gone")) + "."); + + if (items_to_throw.count() > 0) + description.listAppend("Use " + items_to_throw.listJoinComponents(", ", "and") + " in combat at the lair."); + + if (lair_progress >= 5 && (!get_property_boolean("_villainLairColorChoiceUsed") || !get_property_boolean("_villainLairDoorChoiceUsed") || !get_property_boolean("_villainLairSymbologyChoiceUsed"))) + { + //I think there might be an in-game bug here? Someone noted seeing an NC first turn, even though CDMspading has it at five minions minimum? + modifiers.listAppend("-combat"); + description.listAppend("Run -combat to speed up acquiring choices."); + } + task_entries.listAppend(ChecklistEntryMake("__item victor's spoils", "", ChecklistSubentryMake("Adventure in the Villain's Lair", modifiers, description), 3, lookupLocations("Super Villain's Lair")).ChecklistEntrySetIDTag("License to adventure path villain's lair disavowed")); + } + + int social_capital_available = licenseToAdventureSocialCapitalAvailable(); + if (social_capital_available > 0) + { + int bond_points = get_property_int("bondPoints"); + string [int] description; + + //FIXME bond_points values are guesses + if (!get_property_boolean("bondJetpack") && social_capital_available >= 3) + { + description.listAppend("Short-Range Jetpack: saves quite a few turns"); + } + if (!get_property_boolean("bondSymbols") && social_capital_available >= 3) + { + description.listAppend("Universal Symbology Guide: if you're doing the lairs"); + } + if (!get_property_boolean("bondBridge") && social_capital_available >= 3 && bond_points >= 3) + { + description.listAppend("Portable Pocket Bridge: speeds up level nine quest"); + } + if (!get_property_boolean("bondWar") && social_capital_available >= 3 && bond_points >= 5) + { + description.listAppend("Trained Sniper, Felicity Snuggles: speeds up war"); + } + if (!get_property_boolean("bondItem3") && social_capital_available >= 4 && bond_points >= 7) + { + description.listAppend("Electromagnetic Ring: +30% item"); + } + if (!get_property_boolean("bondDrunk2") && social_capital_available >= 3) + { + description.listAppend("Soberness Injection Pen: +2 max drunkenness"); + } + if (!get_property_boolean("bondDrunk1") && social_capital_available >= 2) + { + description.listAppend("Belt-Implanted Still: +1 max drunkenness"); + } + if (!get_property_boolean("bondItem2") && social_capital_available >= 2) + { + description.listAppend("Sticky Climbing Gloves: +20% item"); + } + if (!get_property_boolean("bondAdv") && social_capital_available >= 1) + { + description.listAppend("Super-Accurate Spy Watch: +11 adventures/rollover"); + } + if (!get_property_boolean("bondMartiniTurn") && social_capital_available >= 1) + { + description.listAppend("Exotic Bartender, Barry L. Eagle: +1 adv/drink"); + } + if (!get_property_boolean("bondItem1") && social_capital_available >= 1) + { + description.listAppend("Master Art Thief, Sly Richard: +10% item"); + } + if (!get_property_boolean("bondInit") && social_capital_available >= 1) + { + description.listAppend("Jet-Powered Skis: +30% init"); + } + if (!get_property_boolean("bondSpleen") && social_capital_available >= 5 && bond_points >= 9) + { + description.listAppend("Robo-Speen: +2 max spleen."); + } + + + optional_task_entries.listAppend(ChecklistEntryMake("__item briefcase", "place.php?whichplace=town_right&action=town_bondhq", ChecklistSubentryMake("Spend " + social_capital_available + " social capital", "", description), 3).ChecklistEntrySetIDTag("License to adventure path bond points shop")); + } +} + + +RegisterResourceGenerationFunction("PathGLoverGenerateResource"); +void PathGLoverGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_G_LOVER) + return; + + item g = lookupItem("9909"); + if (g.available_amount() > 0) + { + string [int] description; + if (__quest_state["Level 9"].state_int["a-boo peak hauntedness"] > 0 && !__quest_state["Level 9"].finished && lookupItems("a-boo glue,glued a-boo clue").available_amount() * 30 < __quest_state["Level 9"].state_int["a-boo peak hauntedness"]) + description.listAppend("A-Boo glue: lets you use one a-boo clue."); + if (!__quest_state["Level 9"].state_boolean["Peak Jar Completed"] && !__quest_state["Level 9"].finished && $item[jar of oil].available_amount() == 0 && g.available_amount() >= 3) + description.listAppend("Crude oil congealer: lets you create a jar of oil."); + description.listAppend("Food, drink, +100% spleen item for fifty turns."); + resource_entries.listAppend(ChecklistEntryMake("__item g", "shop.php?whichshop=glover", ChecklistSubentryMake(pluralise(g) + " available", "", description), 3).ChecklistEntrySetIDTag("G-lover path G shop")); + } +} + + +RegisterResourceGenerationFunction("PathDarkGiftGenerateResource"); +void PathDarkGiftGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_VAMPIRE) + return; + + int banishes_left = clampi(10 - get_property_int("_balefulHowlUses"), 0, 10); + if (banishes_left > 0 && lookupSkill("Baleful Howl").skill_is_usable()) + { + string url; + string [int] description; + description.listAppend("Free run/banish."); + description.listAppend("There's a lot of them, so you might just want to use them as a free run?"); + Banish banish_entry = BanishByName("Baleful Howl"); + int turns_left_of_banish = banish_entry.BanishTurnsLeft(); + if (turns_left_of_banish > 0) + { + //is this relevant? we don't describe this for pantsgiving + description.listAppend("Currently used on " + banish_entry.banished_monster + " for " + pluralise(turns_left_of_banish, "more turn", "more turns") + "."); + } + resource_entries.listAppend(ChecklistEntryMake("__skill Baleful Howl", url, ChecklistSubentryMake(pluralise(banishes_left, "baleful howl", "baleful howls"), "", description), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Dark gyffte path baleful howl banish")); + } +} + + +RegisterResourceGenerationFunction("PathExplosionsGenerateResource"); +void PathExplosionsGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_EXPLOSIONS) + return; + item isotopes = lookupItem("rare Meat isotope"); + if (isotopes.have()) + { + string [int] description; + int isotope_amount = isotopes.available_amount(); + if (isotope_amount >= 5) + { + description.listAppend("Space chowder - for eating or hippy-fighting war."); + description.listAppend("Space wine - for drinking or frat-fighting war."); + } + if (isotope_amount >= 10 && !$item[antique accordion].have() && my_class() != $class[accordion thief]) + description.listAppend("antique accordion - casting AT buffs."); + if (isotope_amount >= 25 && !lookupItem("signal jammer").have()) + description.listAppend("signal jammer - deals with those troublesome wandering skeletons. Equipped this in non-delay-burning areas."); + if (isotope_amount >= 25 && !lookupItem("space shield").have() && ($item[digital key].have() || $item[white pixel].available_amount() >= 30)) + description.listAppend("space shield - wear this everywhere that is adventure.php, prevents invader bullets"); + + + //if (isotope_amount >= 10 && !lookupItem("low-pressure oxygen tank").have()) + //description.listAppend("low-pressure oxygen tank - prevents HP damage at end of fight, but you probably want to ignore this."); + + resource_entries.listAppend(ChecklistEntryMake("__item rare Meat isotope", "shop.php?whichshop=exploathing", ChecklistSubentryMake(pluralise(isotopes), "", description), 5).ChecklistEntrySetIDTag("Exploathing path rare meat isotope shop")); + } +} + +//missing plumber + +RegisterLowKeyGenerationFunction("PathLowKeyGenerateKeys"); +void PathLowKeyGenerateKeys(ChecklistEntry [int] low_key_entries) { + + if (my_path().id != PATH_LOW_KEY_SUMMER) return; + if (__quest_state["Lair"].state_boolean["past keys"]) return; + + //LKS-specific keys + foreach index, key in LKS_keys { + if (key.was_used || key.it.available_amount() > 0) continue; + + string url; + + // Entries + string [int] description; + + // Set unlock messages or delay messages + if (!key.zone.locationAvailable()) { + description.listAppend("Unlock " + key.zone + " by " + key.condition_for_unlock); + url = key.pre_unlock_url; + } else { + int delayLeft = 11 - key.zone.turns_spent; + if (delayLeft > 0) + description.listAppend("Delay for " + pluralise(delayLeft, "turn", "turns") + " in " + key.zone + " to find key."); + else + description.listAppend("Find key on next turn in " + key.zone); + + url = key.zone.getClickableURLForLocation(); + } + + low_key_entries.listAppend(ChecklistEntryMake("__item " + key.it.name, url, ChecklistSubentryMake(key.it.name.capitaliseFirstLetter(), key.enchantment, description), boolean [location] {key.zone:true}).ChecklistEntrySetIDTag("Low key summer path " + key.it.name)); + } + + //base keys + SLevel13DoorGenerateMissingItems(low_key_entries); +} + +RegisterTaskGenerationFunction("PathGreyGooGenerateTasks"); +void PathGreyGooGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (my_path().id != PATH_GREY_GOO) + return; + + if (my_daycount() >= 3) { + task_entries.listAppend(ChecklistEntryMake("astral gash", "place.php?whichplace=greygoo", ChecklistSubentryMake("Ascend", "", "Prism appeared. Ascend whenever."),-10).ChecklistEntrySetIDTag("Grey goo path prism open")); + } +} + +RegisterResourceGenerationFunction("PathDinoFallGenerateResource"); +void PathDinoFallGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_FALL_OF_THE_DINOSAURS) + return; + + // #10944 = Dinodollar, the currency in the Dinostaur (good joke!) + item dd = lookupItem("10944"); + + int repellantsAvailable = (dd.available_amount() - (dd.available_amount() % 5))/5; + + if (dd.available_amount() > 0) + { + string [int] description; + if (lookupItem("10941").available_amount() == 0) + description.listAppend("Dino DNAde™: +300% to all stats, good for survival & the tower"); + + description.listAppend("Dinosaur Repellent: You can purchase " + repellantsAvailable.to_string() + " freeruns!"); + resource_entries.listAppend(ChecklistEntryMake("__item Dinodollar", "shop.php?whichshop=dino", ChecklistSubentryMake(pluralise(dd) + " available", "", description), 3).ChecklistEntrySetIDTag("The Dinostaur")); + } +} + +RegisterTaskGenerationFunction("PathShadowsOverLoathingGenerateTasks"); +void PathShadowsOverLoathingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (lookupSkill("Free-For-All").have_skill()) { + if ($effect[Everything Looks Red].have_effect() > 0) return; + string [int] description; + string main_title = HTMLGenerateSpanFont("Free-For-All castable", "red"); + description.listAppend("Free instakill (25 adv cooldown)"); + task_entries.listAppend(ChecklistEntryMake("__item orange boxing gloves", "", ChecklistSubentryMake(main_title, "", description), -11)); + } + else if (lookupSkill("Fondeluge").have_skill()) { + if ($effect[Everything Looks Yellow].have_effect() > 0) return; + string [int] description; + string main_title = HTMLGenerateSpanFont("Fondeluge castable", "orange"); + description.listAppend("Free YR (50 adv cooldown)"); + task_entries.listAppend(ChecklistEntryMake("__skill fondeluge", "", ChecklistSubentryMake(main_title, "", description), -11)); + } + else if (lookupSkill("Motif").have_skill()) { + if ($effect[Everything Looks Blue].have_effect() > 0) return; + string [int] description; + string main_title = HTMLGenerateSpanFont("Motif castable", "blue"); + description.listAppend("Olfact (25 adv cooldown)"); + task_entries.listAppend(ChecklistEntryMake("__skill Motif", "", ChecklistSubentryMake(main_title, "", description), -11)); + } +} + +record CursedItem { + item theItem; + monster boss; + string description; + boolean shouldDisplay; + boolean valuableToGooseDupe; +}; + +void showCursedItemsResourceTile(ChecklistEntry [int] resource_entries) { + CursedItem [int] cursedItems = { + new CursedItem( + $item[cursed goblin cape], + $monster[goblin king's shadow], + "-15% combat!", + __quest_state["Knob Goblin King"].finished != true, + false + ), + new CursedItem( + $item[cursed bat paw], + $monster[two-headed shadow bat], + "+25 ML", + __quest_state["Boss Bat"].finished != true, + true + ), + new CursedItem( + $item[cursed dragon wishbone], + $monster[shadowboner shadowdagon], + "+50% item", + __quest_state["Cyrpt"].finished != true, + true + ), + new CursedItem( + $item[cursed blanket], + $monster[shadow of groar], + "+3 res", + __quest_state["Trapper"].finished != true, + false + ), + new CursedItem( + $item[cursed machete], + $monster[corruptor shadow], + "+50% meat", + __quest_state["Level 11 Hidden City"].finished != true, + false + ), + new CursedItem( + $item[cursed medallion], + $monster[shadow of the 1960s], + "+100% init", + __quest_state["Island War"].finished != true, + false + ) + }; + + string [int] description; + foreach index, cursedItem in cursedItems { + if (cursedItem.shouldDisplay) { + string goose = cursedItem.valuableToGooseDupe ? "🦢 " : ""; + description.listAppend(`{goose}{HTMLGenerateSpanOfClass(cursedItem.boss.name, "r_bold")}: {cursedItem.description}`); + } + } + + if (count(description) > 0) { + resource_entries.listAppend(ChecklistEntryMake("__monster shadow prism", "", ChecklistSubentryMake("Cursed boss drops", "consider duping the items with 🦢", description), 2).ChecklistEntrySetIDTag("Avatar of Shadows Over Loathing cursed items resource")); + } +} + +void showDecurseResourceTile(ChecklistEntry [int] resource_entries) { + int fastenersNeeded = __quest_state["Level 9"].state_int["bridge fasteners needed"]; + int lumberNeeded = __quest_state["Level 9"].state_int["bridge lumber needed"]; + boolean needBridgeParts = __quest_state["Level 9"].mafia_internal_step == 1 && // Bridge not complete yet + (fastenersNeeded > 0 || lumberNeeded > 0 ); // And we need some parts + boolean shouldDecurseBatPaw = my_level() >= 12 && + __quest_state["Cyrpt"].finished == true && + __quest_state["Typical Tavern"].finished == true && + needBridgeParts && + $item[uncursed bat paw].available_amount() < 1; + + if (shouldDecurseBatPaw) { + string description = `{HTMLGenerateSpanOfClass("cursed bat paw", "r_bold")} to get -ML for bridge parts!`; + resource_entries.listAppend(ChecklistEntryMake("__item uncursed bat paw", "", ChecklistSubentryMake("Useful items to decurse", "", description), 0).ChecklistEntrySetIDTag("Avatar of Shadows Over Loathing decurse resource")); + } +} + +RegisterResourceGenerationFunction("PathShadowsOverLoathingGenerateResource"); +void PathShadowsOverLoathingGenerateResource(ChecklistEntry [int] resource_entries) { + if (my_path() != $path[Avatar of Shadows Over Loathing]) return; + + showCursedItemsResourceTile(resource_entries); + showDecurseResourceTile(resource_entries); +} + +RegisterTaskGenerationFunction("PathLegacyOfLoathingGenerateTasks"); +void PathLegacyOfLoathingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + + // Variables re: replicas available and path currency available. + int replicasAvailable = $item[replica mr. accessory].available_amount(); + int momsCreditCardAvailable = $item[replica ten dollars].available_amount(); + int momsCreditCardUsed = $path[legacy of loathing].points; + + // Only generate tile if the user has replicas and is in-path. + if (replicasAvailable + momsCreditCardAvailable == 0) return; + if (my_path() != $path[Legacy of Loathing]) return; + + ChecklistEntry entry; + string [int] description; + + entry.url = "shop.php?whichshop=mrreplica"; + entry.image_lookup_name = "__item replica mr. accessory"; + entry.tags.id = "Replicas available reminder"; + entry.importance_level = -11; + + + description.listAppend("Use all your replicas for shiny old treasures!"); + + if (momsCreditCardAvailable > 0) { + if (momsCreditCardUsed < 19) { + int usableDollars = min(19-momsCreditCardUsed, momsCreditCardAvailable); + description.listAppend(`You also have {usableDollars} usable replica ten dollars for more progression; try using those?`); + entry.url = "inventory.php?ftext=replica+ten+dollars"; + } + } + + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(replicasAvailable, "replica Mr. Accessory","replica Mr. Accessories"), "", description)); + + task_entries.listAppend(entry); + +} + +RegisterResourceGenerationFunction("PathWereProfessorGenerateResource"); +void PathWereProfessorGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (my_path().id != PATH_WEREPROFESSOR) return; + + // Smashed scientific equipment + location [int] scientific_locations = { + $location[Noob Cave], + $location[The Haunted Pantry], + $location[Madness Bakery], + $location[The Thinknerd Warehouse], + $location[Vanya's Castle], + $location[The Old Landfill], + $location[Cobb's Knob Laboratory], + $location[Cobb's Knob Menagerie, Level 1], + $location[Cobb's Knob Menagerie, Level 2], + $location[Cobb's Knob Menagerie, Level 3], + $location[The Haunted Laboratory], + $location[The Castle in the Clouds in the Sky (Top Floor)], + $location[The Hidden Hospital] + }; + + string [int] scientific_locations_description; + scientific_locations_description.listAppend("Found in a free non-combat on 7th adventure in a zone."); + if ($effect[Mild-Mannered Professor].have_effect() > 0) scientific_locations_description.listAppend(HTMLGenerateSpanFont("Can only be found as a Beast", "red")); + + location [int] scientific_locations_options; + foreach key, loc in scientific_locations { + boolean obtained_equipment = false; + foreach nc_key, nc in loc.locationSeenNoncombats() { + if (nc == "The Antiscientific Method") obtained_equipment = true; + } + if (!obtained_equipment) scientific_locations_options.listAppend(loc); + } + + int scientific_locations_sort(location loc) { + int score = 0; + // +1 for each turn spent, up to 6 + // -30 if location is inaccessible + // +3 if location is a quest one and the relevant quest is not yet done + // +10 if location is the last adventured location + + int turns_spent = loc.turns_spent; + score += min(6, loc.turns_spent); + if (!loc.locationAvailable()) score -= 30; + + if (loc == $location[Vanya's Castle]) score += 3; // should always get that one in the optimal scenario + if (loc == $location[The Castle in the Clouds in the Sky (Top Floor)] && !__quest_state["Level 10"].finished) score += 3; + if (loc == $location[The Hidden Hospital] && !__quest_state["Level 11 Hidden City"].state_boolean["Hospital finished"]) score += 3; + + if (__last_adventure_location == loc) score += 10; + return score; + } + + sort scientific_locations_options by -scientific_locations_sort(value); + + string [int] loc_descriptions; + + foreach key, loc in scientific_locations_options { + int turns_spent = loc.turns_spent; + string scientific_locations_option = loc.HTMLGenerateFutureTextByLocationAvailability(); + if (turns_spent < 6) scientific_locations_option += " - " + pluralise(6 - turns_spent, "turn left", "turns left"); + else scientific_locations_option += " - drops next turn"; + loc_descriptions.listAppend(scientific_locations_option); + } + + if (scientific_locations_options.count() > 0) { + if (scientific_locations_options.count() > 3) { + scientific_locations_description.listAppend("Drop locations:" + (loc_descriptions[0] + "
" + HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(loc_descriptions.listJoinComponents("
").HTMLGenerateIndentedText(), "r_tooltip_inner_class") + "All locations", "r_tooltip_outer_class")).HTMLGenerateIndentedText()); + } + else scientific_locations_description.listAppend("Drop locations:" + loc_descriptions.listJoinComponents("
").HTMLGenerateIndentedText()); + + resource_entries.listAppend(ChecklistEntryMake("__item smashed scientific equipment", "", ChecklistSubentryMake("Obtain smashed scientific equipment", "", scientific_locations_description))); + } + + // Owned smashed scientific equipment + if (have($item[smashed scientific equipment])) { + string [int] smashed_equipment_description; + string [int] craftable_items; + + if ($effect[Savage Beast].have_effect() > 0) smashed_equipment_description.listAppend("Wait until you are a Professor to craft stuff."); + + // Science-producting hats -- TODO: ignore if have all Stomach/Liver upgrades (pending Mafia support) + if (!have($item[biphasic molecular oculus]) && !have($item[triphasic molecular oculus])) craftable_items.listAppend("biphasic molecular oculus (more Research Points)"); + if (have($item[biphasic molecular oculus])) craftable_items.listAppend("triphasic molecular oculus (more Research Points)"); + // Exoskeletons + if (!have($item[high-tension exoskeleton]) && !have($item[ultra-high-tension exoskeleton]) && !have($item[irresponsible-tension exoskeleton])) craftable_items.listAppend("high-tension exoskeleton (avoid attacks)"); + if (have($item[high-tension exoskeleton])) craftable_items.listAppend("ultra-high-tension exoskeleton (avoid attacks)"); + if (have($item[ultra-high-tension exoskeleton])) craftable_items.listAppend("irresponsible-tension exoskeleton (avoid attacks)"); + // Initiative, consider if no Spring Shoes available (since they do the same thing) and cannot equip Parka (protection from the jump) + if (!(__misc_state["Torso aware"] && have($item[Jurassic Parka])) && !have($item[spring shoes]) && !have($item[motion sensor])) craftable_items.listAppend("motion sensor (+100% initiative accessory)"); + + if (craftable_items.count() > 0) { + smashed_equipment_description.listAppend("Consider crafting:" + craftable_items.listJoinComponents("
").HTMLGenerateIndentedText()); + } + + resource_entries.listAppend(ChecklistEntryMake("__item smashed scientific equipment", "shop.php?whichshop=wereprofessor_tinker", ChecklistSubentryMake(pluralise($item[smashed scientific equipment]) + " available", "", smashed_equipment_description))); + } +} + +RegisterTaskGenerationFunction("PathWereProfessorGenerateTasks"); +void PathWereProfessorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($effect[Mild-Mannered Professor].have_effect() > 0) { + boolean should_nag = false; + + string [int] professor_tips; + + // Too high ML! + if (monster_level_adjustment() > 25) { + should_nag = true; + professor_tips.listAppend(HTMLGenerateSpanFont(`Reduce ML, elemental-aligned monsters will kill you at the start of combat with +{monster_level_adjustment()} ML.`, "red")); + } + + boolean wearing_quest_outfit = false; + if (is_wearing_outfit("Knob Goblin Harem Girl Disguise")) wearing_quest_outfit = true; + if (is_wearing_outfit("Knob Goblin Elite Guard Uniform")) wearing_quest_outfit = true; + if (is_wearing_outfit("eXtreme Cold-Weather Gear")) wearing_quest_outfit = true; + if (is_wearing_outfit("War Hippy Fatigues")) wearing_quest_outfit = true; + if (is_wearing_outfit("Frat Warrior Fatigues")) wearing_quest_outfit = true; + + // Equip research equipment. TODO: don't show it if we have 2250 points total; don't nag it if we have all of stomach and liver skills + foreach it in $items[biphasic molecular oculus,triphasic molecular oculus] { + if (have(it) && it.equipped_amount() == 0) { + if (!wearing_quest_outfit) { + should_nag = true; + professor_tips.listAppend(HTMLGenerateSpanFont(`Equip your {it} to do advanced research.`, "red")); + } + else professor_tips.listAppend(`Equip your {it} to do advanced research.`); + } + } + + // Equip attack avoidance pants + foreach it in $items[high-tension exoskeleton,ultra-high-tension exoskeleton,irresponsible-tension exoskeleton] { + if (have(it) && it.equipped_amount() == 0) { + professor_tips.listAppend(`Equip your {it} to avoid enemy attacks.`); + } + } + + // Equip something to avoid the jump + if (initiative_modifier() < 100 && $item[Jurassic Parka].equipped_amount() == 0) { + if (__misc_state["Torso aware"] && have($item[Jurassic Parka])) { + should_nag = true; + professor_tips.listAppend(HTMLGenerateSpanFont("Equip your Jurassic Parka to avoid enemies getting the jump and instakilling you.", "red")); + } + else { + professor_tips.listAppend(`Increase your initiative (currently {initiative_modifier()}%) to avoid enemies getting the jump and instakilling you.`); + } + } + + // Buy stuff + string [int] stuff_to_buy; + if (get_property_int("_cloversPurchased") < 3) stuff_to_buy.listAppend("11-leaf clovers"); + if (!__misc_state["desert beach available"]) { + if (!knoll_available()) stuff_to_buy.listAppend("desert bus pass"); + else stuff_to_buy.listAppend("bitchin' meatcar components"); + } + if (knoll_available() && !have($item[detuned radio])) stuff_to_buy.listAppend("detuned radio"); + if (__quest_state["Level 11"].mafia_internal_step >= 2) { // Black Market open + if (__quest_state["Level 11"].mafia_internal_step == 2 && !have($item[forged identification documents])) stuff_to_buy.listAppend("forged identification documents"); + if (!__quest_state["Level 11 Desert"].state_boolean["Black Paint Given"] && !have($item[can of black paint])) stuff_to_buy.listAppend("can of black paint"); + if (__quest_state["Level 11 Ron"].mafia_internal_step <= 4 && !have($item[red zeppelin ticket])) stuff_to_buy.listAppend("Red Zeppelin ticket"); + } + if (!have($item[UV-resistant compass])) stuff_to_buy.listAppend("UV-resistant compass"); + if (!have($item[dinghy plans]) && !__misc_state["mysterious island available"]) stuff_to_buy.listAppend("dinghy plans"); + if (!have($item[dingy planks]) && !__misc_state["mysterious island available"]) stuff_to_buy.listAppend("dingy planks"); + if (__quest_state["Level 11 Manor"].mafia_internal_step < 4 && !have($item[Dramatic™ range]) && !get_property_boolean("hasRange")) stuff_to_buy.listAppend("Dramatic™ range"); + + if (stuff_to_buy.count() > 0) { + professor_tips.listAppend("Buy stuff before you become a Beast again: " + stuff_to_buy.listJoinComponents(", ", "or") + "."); + } + + int priority = 12; + ChecklistEntry [int] tips_location = optional_task_entries; + if (should_nag) { + priority = -11; + tips_location = task_entries; + } + + if (professor_tips.count() > 0) { + tips_location.listAppend(ChecklistEntryMake("WereProfessor", "", ChecklistSubentryMake("You are a Professor", professor_tips), priority)); + } + } +} + + +void runMain(string relay_filename) +{ + string [string] form_fields = form_fields(); + if (form_fields["API status"] != "") + { + string [string] api_response = generateAPIResponse(); + write(api_response.to_json()); + return; + } + + boolean output_body_tag_only = false; + if (form_fields["body tag only"] != "") + { + output_body_tag_only = true; + } + else if (form_fields["set user preferences"] != "") + { + processSetUserPreferences(form_fields); + return; + } + else if (form_fields.count() > 0) + print_html("Form fields: " + form_fields.to_json()); + + + PageInit(); + ChecklistInit(); + contextMenuInit(); + setUpCSSStyles(); + + + Checklist [int] ordered_output_checklists; + generateChecklists(ordered_output_checklists); + + string guide_title = "TourGuide"; + if (isAprilFools()) { + guide_title = "Glup Shitto Stole Rogue V's Targeting Computer"; + } + if (limit_mode() == "batman") + guide_title = "Bat-Guide"; + + PageSetTitle(guide_title); + + if (__setting_use_kol_css) + PageWriteHead(HTMLGenerateTagPrefix("link", mapMake("rel", "stylesheet", "type", "text/css", "href", "/images/styles.css"))); + + PageWriteHead(HTMLGenerateTagPrefix("meta", mapMake("name", "viewport", "content", "width=device-width"))); + + + if (relay_filename.to_lower_case() == "relay_guide.ash") + PageSetBodyAttribute("onload", "GuideInit('relay_Guide.ash'," + __setting_horizontal_width + ");"); + else + PageSetBodyAttribute("onload", "GuideInit('" + relay_filename + "'," + __setting_horizontal_width + ");"); //not escaped + + boolean drunk = $item[beer goggles].equipped_amount() > 0; + + if (drunk) + PageWrite(HTMLGenerateTagPrefix("div", mapMake("style", "-webkit-filter:blur(4.0px) brightness(1.01);"))); //FIXME make this animated + + boolean buggy = (my_familiar() == $familiar[software bug] || $item[iShield].equipped_amount() > 0); + if (buggy) + { + //Ideally we'd want to layer over a mosaic filter, giving a Cinepak look, but pixel manipulation techniques are limited in HTML. + string chosen_font; + //chosen_font = "'Comic Sans MS', cursive, sans-serif;"; //DO NOT USE + //chosen_font = "'Courier New', Courier, monospace;"; + chosen_font = "'Helvetica Neue',Arial, Helvetica, sans-serif;font-weight:300;"; + PageWrite(HTMLGenerateTagPrefix("div", mapMake("style", "font-family:" + chosen_font))); + //PageWrite(HTMLGenerateTagPrefix("div", mapMake("style", ""))); + // + } + + boolean displaying_navbar = false; + if (__setting_show_navbar) + { + if (ordered_output_checklists.count() > 1) + displaying_navbar = true; + } + if (displaying_navbar) + { + buffer navbar = generateNavbar(ordered_output_checklists); + PageWrite(navbar); + } + + boolean displaying_location_bar = __setting_show_location_bar; + if (displaying_location_bar) + { + buffer location_bar = generateLocationBar(displaying_navbar); + if (location_bar.length() == 0) + displaying_location_bar = false; + else + PageWrite(location_bar); + } + + + int max_width_setting = __setting_horizontal_width; + + string bottom_margin; + float bottom_offset = (__setting_navbar_height_in_em - 0.05) * (displaying_navbar.to_int() + displaying_location_bar.to_int()); + if (bottom_offset > 0.0) + bottom_margin = "margin-bottom:" + bottom_offset + "em;"; + + string horizontal_container_styles = "position:relative;max-width:" + max_width_setting + "px;" + bottom_margin; + if (isAprilFools()) { + horizontal_container_styles += "transform: rotate3d(1, 1.5, 0.2, 30deg); transform-origin: 10px top"; + } + PageWrite(HTMLGenerateTagPrefix("div", mapMake("class", "r_centre", "id", "Guide_horizontal_container", "style", horizontal_container_styles))); //centre holding container + + + + if (true) + { + //Buttons. + string [string] base_image_map; + base_image_map["width"] = "12"; + base_image_map["height"] = "12"; + base_image_map["class"] = "r_button"; + + //position:fixed holding container for the Close button: + string [string] image_map = mapCopy(base_image_map); + image_map["src"] = __close_image_data; + image_map["onclick"] = "buttonCloseClicked(event)"; + image_map["style"] = "left:5px;top:5px;"; + image_map["id"] = "button_close_box"; + image_map["alt"] = "Close"; + image_map["title"] = image_map["alt"]; + PageWrite(HTMLGenerateTagWrap("div", HTMLGenerateTagPrefix("img", image_map), string [string] {"id":"close_button_position_reference", "style":"position:fixed;z-index:5;width:100%;max-width:" + max_width_setting + "px;"})); + + //Hacky layout, sorry: + image_map = mapCopy(base_image_map); + image_map["width"] = "12"; + image_map["height"] = "12"; + image_map["class"] = "r_button"; + image_map["src"] = __refresh_image_data; + image_map["id"] = "button_refresh"; + image_map["onclick"] = "document.location.reload(true)"; + image_map["style"] = "right:5px;top:5px;"; + image_map["alt"] = "Refresh"; + image_map["title"] = image_map["alt"]; + PageWrite(HTMLGenerateTagWrap("div", HTMLGenerateTagPrefix("img", image_map), string [string] {"id":"refresh_button_position_reference", "style":"position:fixed;z-index:5;width:100%;max-width:" + max_width_setting + "px;"})); + + //position:absolute holding container, so we can absolutely position these, absolutely: + PageWrite(HTMLGenerateTagPrefix("div", mapMake("id", "top_buttons_position_reference", "style", "position:absolute;" + "width:100%;max-width:" + max_width_setting + "px;"))); + + image_map = mapCopy(base_image_map); + image_map["src"] = __new_window_image_data; + image_map["id"] = "button_new_window"; + image_map["onclick"] = "buttonNewWindowClicked(event)"; + image_map["style"] = "right:30px;top:5px;"; + image_map["alt"] = "Open in new window"; + image_map["title"] = image_map["alt"]; + PageWrite(HTMLGenerateTagPrefix("img", image_map)); + + image_map = mapCopy(base_image_map); + image_map["src"] = __left_arrow_image_data; + image_map["id"] = "button_arrow_right_left"; + image_map["onclick"] = "buttonRightLeftClicked(event)"; + image_map["style"] = "right:55px;top:5px;"; + image_map["alt"] = "Show chat pane"; + image_map["title"] = image_map["alt"]; + PageWrite(HTMLGenerateTagPrefix("img", image_map)); + + image_map = mapCopy(base_image_map); + image_map["src"] = __right_arrow_image_data; + image_map["id"] = "button_arrow_right_right"; + image_map["onclick"] = "buttonRightRightClicked(event)"; + image_map["style"] = "right:55px;top:5px;"; + image_map["alt"] = "Hide chat pane"; + image_map["title"] = image_map["alt"]; + PageWrite(HTMLGenerateTagPrefix("img", image_map)); + + image_map = mapCopy(base_image_map); + image_map["id"] = "button_global_settings"; + image_map["onclick"] = "callSettingsContextualMenu(event)"; + image_map["oncontextmenu"] = "callSettingsContextualMenu(event)"; + image_map["style"] = "right:5px;top:30px;visibility:visible;"; + image_map["alt"] = "Global Settings"; + //image_map["title"] = image_map["alt"]; //useless here + image_map["aria-hidden"] = "true"; + image_map["focusable"] = "false"; + image_map["data-prefix"] = "fas"; + image_map["data-icon"] = "cog"; + image_map["class"] = image_map["class"] + " svg-inline--fa fa-cog fa-w-16"; + image_map["role"] = "img"; + image_map["xmlns"] = "http://www.w3.org/2000/svg"; + image_map["viewBox"] = "0 0 512 512"; + remove image_map["width"]; + PageWrite(HTMLGenerateTagWrap("svg", 'Global SettingsGlobal Settings', image_map)); //https://fontawesome.com/license + + image_map = mapCopy(base_image_map); + image_map["id"] = "button_expand_all"; + image_map["onclick"] = "buttonExpandAllClicked(event)"; + image_map["style"] = "right:30px;top:30px;"; + image_map["alt"] = "Expand all"; + //image_map["title"] = image_map["alt"]; //useless here + image_map["aria-hidden"] = "true"; + image_map["focusable"] = "false"; + image_map["data-prefix"] = "fas"; + image_map["data-icon"] = "angle-double-down"; + image_map["role"] = "img"; + image_map["class"] = image_map["class"] + " svg-inline--fa fa-angle-double-down fa-w-10"; + image_map["xmlns"] = "http://www.w3.org/2000/svg"; + image_map["viewBox"] = "0 50 320 400"; + remove image_map["width"]; + PageWrite(HTMLGenerateTagWrap("svg", 'Expand allExpand all', image_map)); //https://fontawesome.com/license + + PageWrite(""); + } + + if (true) + { + //Holding container: + string style = ""; + style += "padding-top:5px;padding-bottom:0.25em;"; + if (!__setting_fill_vertical) + style += "background-color:" + __setting_page_background_colour + ";"; + if (!__setting_side_negative_space_is_dark && !__setting_fill_vertical) + { + style += "border:1px solid;border-top:1px solid;border-bottom:1px solid;"; + style += "border-color:" + __setting_line_colour + ";"; + } + PageWrite(HTMLGenerateTagPrefix("div", mapMake("id", "Guide_body", "style", style))); + } + + buffer information_cache; + + string player_name = my_name().to_lower_case().HTMLEscapeString(); + if (player_name == "") + player_name = "anonymous"; + information_cache.append(HTMLGenerateTagWrap("div", player_name, string [string] {"id":"player_name"})); + + information_cache.append(HTMLGenerateTagWrap("div", gameday_to_int(), string [string] {"id":"in_game_day"})); + + information_cache.append(HTMLGenerateTagWrap("div", my_ascensions(), string [string] {"id":"ascension_count"})); + + PageWrite(HTMLGenerateTagWrap("div", information_cache, string [string] {"id":"ASH_information_cache", "style":"display:none;"})); + + if (true) + { + // Head text + + // Title + string titleStyles = "font-weight:bold; font-size:1.5em;"; + if (isAprilFools()) { + titleStyles = titleStyles + "background-image: linear-gradient(-225deg,#231557 0%,#44107a 15%,#ff1361 30%,#fff800 60%);background-size: auto auto;background-clip: border-box;background-size: 200% auto;color: #fff;background-clip: text;text-fill-color: transparent;-webkit-background-clip: text;-webkit-text-fill-color: transparent;display: inline-block"; + } + PageWrite(HTMLGenerateSpanOfStyle(guide_title, titleStyles)); + + // Day + Turn Count + if (__misc_state["in run"] && playerIsLoggedIn()) { + PageWrite(HTMLGenerateDivOfClass("Day " + my_daycount() + ". " + pluralise(my_turncount(), "turn", "turns") + " played.", "r_bold")); + } + // Path + if (my_path() != "" && my_path() != "None" && playerIsLoggedIn()) { + PageWrite(HTMLGenerateDivOfClass(my_path(), "r_bold")); + } + // Random Message (which we'll have to remove :c ) + PageWrite(HTMLGenerateDivOfStyle(generateRandomMessage(), "padding-left:20px;padding-right:20px;")); + PageWrite(HTMLGenerateTagWrap("div", "", mapMake("id", "extra_words_at_top"))); + // Example mode + if (__misc_state["Example mode"]) { + PageWrite("
"); + PageWrite(HTMLGenerateDivOfStyle("Example ascension", "text-align:center; font-weight:bold;")); + } + } + + + outputChecklists(ordered_output_checklists); + + + if (true) + { + //Gray text at the bottom: + string line; + line = HTMLGenerateTagWrap("span", "
Automatic refreshing disabled.", mapMake("id", "refresh_status")); + line += HTMLGenerateTagWrap("a", "
Created by the almighty Ezandora", generateMainLinkMap("showplayer.php?who=1557284")); + line += "
Forked and maintained by the ASS team"; + line += "
" + __version; + + PageWrite(HTMLGenerateTagWrap("div", line, mapMake("style", "font-size:0.777em;color:gray;margin-top:-12px;", "id", "Guide_foot"))); + } + boolean matrix_enabled = false; + if (my_path().id == PATH_THE_SOURCE || $familiars[dataspider,Baby Bugged Bugbear] contains my_familiar()) + { + matrix_enabled = !PreferenceGetBoolean("matrix disabled"); + if (true) + { + //We support disabling this feature, largely because it causes someone's browser to crash. Probably bad RAM. + //I personally consider that to be a path-appropriate feature, but... + string [string] image_map; + image_map["width"] = "16"; + image_map["height"] = "16"; + image_map["class"] = "r_button"; + image_map["id"] = "button_refresh"; + image_map["style"] = "position:relative;top:-16px;left:3px;visibility:visible;"; + if (matrix_enabled) + { + image_map["src"] = __red_pill_image; + image_map["onclick"] = "setMatrixStatus(true)"; + image_map["alt"] = "Matrix enabled"; + } + else + { + image_map["src"] = __blue_pill_image; + image_map["onclick"] = "setMatrixStatus(false)"; + image_map["alt"] = "Matrix disabled"; + } + image_map["title"] = image_map["alt"]; + PageWrite(HTMLGenerateDivOfStyle(HTMLGenerateTagPrefix("img", image_map), "max-height:0px;width:100%;text-align:left;")); + } + } + + //Contextual menu + PageWrite(HTMLGenerateTagWrap("div", generateContextualMenu(), string [string] {"class":"menu"})); + + PageWrite(""); + PageWrite(""); + + if (__setting_fill_vertical) + { + PageWrite(HTMLGenerateTagWrap("div", "", mapMake("id", "color_fill", "class", "r_vertical_fill", "style", "z-index:-1;background-color:" + __setting_page_background_colour + ";max-width:" + __setting_horizontal_width + "px;"))); //Color fill + PageWrite(HTMLGenerateTagWrap("div", "", mapMake("id", "vertical_border_lines", "class", "r_vertical_fill", "style", "z-index:-11;border-left:1px solid;border-right:1px solid;border-color:" + __setting_line_colour + ";width:" + (__setting_horizontal_width) + "px;"))); //Vertical border lines, empty background + } + PageWriteHead(""); + + if (matrix_enabled) + { + PageWrite(HTMLGenerateTagPrefix("div", mapMake("style", "opacity:0;visibility:hidden;background:black;position:fixed;top:0;left:0;z-index:303;width:100%;height:100%;", "id", "matrix_canvas_holder", "onclick", "matrixStopAnimation();", "onmousemove", "matrixStopAnimation();"))); + PageWrite(HTMLGenerateTagWrap("canvas", "", mapMake("width", "1", "height", "1", "id", "matrix_canvas", "style", ""))); + PageWrite(""); + PageWrite(HTMLGenerateTagPrefix("img", mapMake("src", __matrix_glyphs, "id", "matrix_glyphs", "style", "display:none;"))); + } + + if (drunk) + PageWrite(""); + if (buggy) + PageWrite(""); + + if (output_body_tag_only) + write(PageGenerateBodyContents()); + else + PageGenerateAndWriteOut(); +} + + +void main() +{ + runMain(__FILE__); +} From 3b7787b395199fb82f52bde16ce2b3217dfbb39b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Mon, 18 Aug 2025 16:20:43 +0000 Subject: [PATCH 18/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 0c0ae1c3..7e4d3810 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -55027,6 +55027,25 @@ void IOTMCursedMonkeysPawGenerateResource(ChecklistEntry [int] resource_entries) ) }; + // For sea path, need knowledge of which clues are accessible to suggest things. + + MonkeyWish [int] seaPathWishes = { + new MonkeyWish( + $item[mer-kin knucklebone], + $effect[none], + "1x dreadscroll clue", + , + locationAvailable($location[mer-kin library]) + ), + new MonkeyWish( + $item[mer-kin cowbell], + $effect[none], + "1x dreadscroll clue", + locationAvailable($location[mer-kin library]), + true + ), + } + MonkeyWish [int] aftercoreWishes = { new MonkeyWish( $item[bag of foreign bribes], @@ -55035,11 +55054,14 @@ void IOTMCursedMonkeysPawGenerateResource(ChecklistEntry [int] resource_entries) locationAvailable($location[The Ice Hotel]), true ) - }; + } + + // Rejecting bad wishes for CS, Goo, and Sea path + boolean inNonQuestPath = (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO || my_path().id == PATH_SEA); int monkeyWishesLeft = clampi(5 - get_property_int("_monkeyPawWishesUsed"), 0, 5); string [int] options; - if (__misc_state["in run"] && my_path().id != PATH_COMMUNITY_SERVICE) { + if (__misc_state["in run"] && !inNonQuestPath) { options.listAppendList(showWishes(inRunWishes)); } if (!__misc_state["in run"]) { @@ -57452,7 +57474,7 @@ void IOTMMobiusRingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt string url = "inventory.php?ftext=bius+ring"; string [int] copDescription; string copSubTitle = "Forecast is "+currentTimeCopRate+"% chance of cops"; - string copTitle = HTMLGenerateSpanFont(pluralise(min(11-countTimeCops, 0), "free Time Cops fought today", "free Time Cops fought today"), "black"); + string copTitle = HTMLGenerateSpanFont(pluralise(max(11-countTimeCops, 0), "free Time Cops fought today", "free Time Cops fought today"), "black"); boolean copsNoLongerFree = countTimeCops > 11; int priority = 10; From b1bfde339f35eda86f6b14d418fe7a3360d4d530 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 19 Aug 2025 01:56:19 +0000 Subject: [PATCH 19/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 106 ++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 17 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 7e4d3810..618a6ab3 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -20745,7 +20745,9 @@ void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] o need_minus_combat_modifier = true; temple_subentry.entries.listAppend("Adventure in the Mer-Kin outpost, find non-combat.|" + nc_details); } else { + int turns_spent = $location[The Mer-Kin Outpost].turns_spent; temple_subentry.entries.listAppend("Adventure in the Mer-Kin outpost to acquire a lockkey."); + if (my_path().id == PATH_SEA && turns_spent < 26) temple_subentry.entries.listAppend((24 - turns_spent) +" to " + (26 - turns_spent) + " total delay remaining."); temple_subentry.entries.listAppend("Unless you discovered the currents already (can't tell), in which case go ask grandpa about currents."); } } else if (monkees_quest_state.mafia_internal_step == 6 || grandpa_ncs_remaining == 0) { @@ -26896,6 +26898,8 @@ void SMiscItemsGenerateResource(ChecklistEntry [int] resource_entries) if ($item[harold's bell].available_amount() > 0 && $item[harold's bell].item_is_usable()) resource_entries.listAppend(ChecklistEntryMake("__item harold's bell", "", ChecklistSubentryMake(pluralise($item[harold's bell]), "", "Takes a turn, 20-turn banish."), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Harold's bell banish")); + if ($item[anchor bomb].available_amount() > 0 ) + resource_entries.listAppend(ChecklistEntryMake("__item anchor bomb", "", ChecklistSubentryMake(pluralise($item[anchor bomb]), "", "Free run/banish. (30 turns)"), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Purkey banish")); if ($item[lost key].available_amount() > 0 && $item[lost key].item_is_usable()){ string [int] details; details.listAppend("Lost pill bottle is mini-fridge, take a nap, open the pill bottle."); @@ -55028,20 +55032,37 @@ void IOTMCursedMonkeysPawGenerateResource(ChecklistEntry [int] resource_entries) }; // For sea path, need knowledge of which clues are accessible to suggest things. + /* + Mer-kin Library 1 -> dreadScroll1 + Mer-kin healscroll -> dreadScroll2 + Deep Dark Visions -> dreadScroll3 + Mer-kin knucklebone -> dreadScroll4 + Mer-kin killscroll -> dreadScroll5 + Mer-kin Library 2 -> dreadScroll6 + Mer-kin worktea -> dreadScroll7 + Mer-kin Library 3 -> dreadScroll8 + */ MonkeyWish [int] seaPathWishes = { new MonkeyWish( $item[mer-kin knucklebone], $effect[none], "1x dreadscroll clue", - , + get_property_int("dreadscroll5") >=1, locationAvailable($location[mer-kin library]) ), new MonkeyWish( - $item[mer-kin cowbell], + $item[mer-kin worktea], $effect[none], - "1x dreadscroll clue", - locationAvailable($location[mer-kin library]), + "1x dreadscroll clue... with sushi!", + get_property_int("dreadscroll7") >=1, + locationAvailable($location[mer-kin library]) + ), + new MonkeyWish( + $item[none], + $effect[Frosty], + "init/item/meat", + true, true ), } @@ -56360,6 +56381,43 @@ void IOTMCandyCaneSwordGenerateTasks(ChecklistEntry [int] task_entries, Checklis } +// Wardrobe-o-Matic +RegisterTaskGenerationFunction("IOTMWardrobeOMaticGenerateTasks"); +void IOTMWardrobeOMaticGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { + // Don't generate a tile if the user doesn't have the wardrobe. + if (!lookupItem("wardrobe-o-matic").have()) return; + + // If the property is populated, the user has opened the wardrobe. + boolean openedWardrobe = length(get_property("_futuristicHatModifier"))>10; + + // Don't generate a tile if the user has opened the wardrobe today. + if (openedWardrobe) return; + + string [int] description; + string url = "inventory.php?ftext=drobe-o-matic"; + string main_title = "Open your Wardrobe-O-Matic"; + string subtitle; + int priority = 11; + boolean isMainTask = false; + + // If they're > 15, promote to tasks. If they're >20, promote to supernag. + if (my_level() >= 15) isMainTask = true; + if (my_level() >= 20) priority = -11; + + // Level needed for your next wardrobe tier + if (my_level() < 5) subtitle = "advances @ level 5"; + if (my_level() < 10) subtitle = "advances @ level 10"; + if (my_level() < 15) subtitle = "advances @ level 15... with new mods!"; + if (my_level() < 20) subtitle = "advances @ level 20"; + + // Add a little note if you've maxed it. + description.listAppend("Acquire some questionably useful clothing!"); + if (my_level() < 20) description.listAppend(HTMLGenerateSpanFont("You're level "+my_level()+"? It can't get any better, open it!", "blue")); + + if (isMainTask) task_entries.listAppend(ChecklistEntryMake("__item wardrobe-o-matic", url, ChecklistSubentryMake(main_title, subtitle, description), -11).ChecklistEntrySetIDTag("Wardrobe-o-Matic")); + if (!isMainTask) optional_task_entries.listAppend(ChecklistEntryMake("__item wardrobe-o-matic", url, ChecklistSubentryMake(main_title, subtitle, description), -11).ChecklistEntrySetIDTag("Wardrobe-o-Matic")); + +} // 2024 //2024 @@ -56621,6 +56679,7 @@ void IOTMMayamCalendarGenerateResource(ChecklistEntry [int] resource_entries) string [int] description, hoverDescription; int templeResetAscension = get_property_int("lastTempleAdventures"); + string mayamSymbolsUsed = get_property("_mayamSymbolsUsed"); addToBothDescriptions(description, hoverDescription, "Happy Mayam New Year!"); ChecklistEntry entry; @@ -56629,11 +56688,17 @@ void IOTMMayamCalendarGenerateResource(ChecklistEntry [int] resource_entries) entry.tags.id = "Mayam Calendar"; entry.importance_level = 8; - if (!get_property("_mayamSymbolsUsed").contains_text("yam4") || - !get_property("_mayamSymbolsUsed").contains_text("clock") || - !get_property("_mayamSymbolsUsed").contains_text("explosion") || + if (!mayamSymbolsUsed.contains_text("yam4") || + !mayamSymbolsUsed.contains_text("clock") || + !mayamSymbolsUsed.contains_text("explosion") || my_ascensions() > templeResetAscension) { + // do not generate the tile if in sea path and no picks left + if (mayamSymbolsUsed.contains_text("yam4") && + mayamSymbolsUsed.contains_text("clock") && + mayamSymbolsUsed.contains_text("explosion") && + my_path().id == PATH_SEA) return; + description.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); hoverDescription.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); @@ -56655,14 +56720,21 @@ void IOTMMayamCalendarGenerateResource(ChecklistEntry [int] resource_entries) description.listAppend(HTMLGenerateSpanFont(" ", "r_bold") + ""); string [int] resonances; - resonances.listAppend(HTMLGenerateSpanOfClass("15-turn banisher", "r_bold") + ": Vessel + Yam + Cheese + Explosion"); - resonances.listAppend(HTMLGenerateSpanOfClass("Yam and swiss", "r_bold") + ": Yam + Meat + Cheese + Yam"); - resonances.listAppend(HTMLGenerateSpanOfClass("+55% meat accessory", "r_bold") + ": Yam + Meat + Eyepatch + Yam"); - resonances.listAppend(HTMLGenerateSpanOfClass("+100% Food drops", "r_bold") + ": Yam + Yam + Cheese + Clock"); + + // adding some filtering to remove from resonance list if cannot make + if (!mayamSymbolsUsed.contains_text("vessel") && !mayamSymbolsUsed.contains_text("yam2") && !mayamSymbolsUsed.contains_text("cheese") && !mayamSymbolsUsed.contains_text("explosion")) + resonances.listAppend(HTMLGenerateSpanOfClass("15-turn banisher", "r_bold") + ": Vessel + Yam + Cheese + Explosion"); + if (!mayamSymbolsUsed.contains_text("yam1") && !mayamSymbolsUsed.contains_text("meat") && !mayamSymbolsUsed.contains_text("cheese") && !mayamSymbolsUsed.contains_text("yam4")) + resonances.listAppend(HTMLGenerateSpanOfClass("Yam and swiss", "r_bold") + ": Yam + Meat + Cheese + Yam"); + if (!mayamSymbolsUsed.contains_text("yam1") && !mayamSymbolsUsed.contains_text("meat") && !mayamSymbolsUsed.contains_text("eyepatch") && !mayamSymbolsUsed.contains_text("yam4")) + resonances.listAppend(HTMLGenerateSpanOfClass("+55% meat accessory", "r_bold") + ": Yam + Meat + Eyepatch + Yam"); + if (!mayamSymbolsUsed.contains_text("yam1") && !mayamSymbolsUsed.contains_text("yam2") && !mayamSymbolsUsed.contains_text("cheese") && !mayamSymbolsUsed.contains_text("clock")) + resonances.listAppend(HTMLGenerateSpanOfClass("+100% Food drops", "r_bold") + ": Yam + Yam + Cheese + Clock"); - addToBothDescriptions(description, hoverDescription, HTMLGenerateSpanOfClass("Cool Mayam combos!", "r_bold") + resonances.listJoinComponents("
").HTMLGenerateIndentedText()); + if (length(resonances) > 0) + addToBothDescriptions(description, hoverDescription, HTMLGenerateSpanOfClass("Cool Mayam combos!", "r_bold") + resonances.listJoinComponents("
").HTMLGenerateIndentedText()); - if (my_ascensions() > templeResetAscension) { + if (my_ascensions() > templeResetAscension && my_path().id != PATH_SEA) { addToBothDescriptions(description, hoverDescription, HTMLGenerateSpanFont("Temple reset available!", "r_bold") + ""); } @@ -57172,11 +57244,11 @@ void IOTMSkiSetGenerateResource(ChecklistEntry [int] resource_entries) //fixme: currently not supported by sneako tile if (lookupItem("McHugeLarge left ski").equipped_amount() == 1) { - description.listAppend(HTMLGenerateSpanFont("|*LEFT SKI equipped!", "blue")); + description.listAppend(HTMLGenerateSpanFont("|*LEFT SKI equipped!", "blue")+""); } else if (lookupItem("McHugeLarge left ski").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT SKI first.", "red")); + description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT SKI first.", "red")+""); } } if (skiSlashesLeft > 0) @@ -57184,11 +57256,11 @@ void IOTMSkiSetGenerateResource(ChecklistEntry [int] resource_entries) description.listAppend(HTMLGenerateSpanOfClass(skiSlashesLeft + " slashes", "r_bold") + " left. Track a monster."); if (lookupItem("McHugeLarge left pole").equipped_amount() == 1) { - description.listAppend(HTMLGenerateSpanFont("|*LEFT POLE equipped!", "blue")); + description.listAppend(HTMLGenerateSpanFont("|*LEFT POLE equipped!", "blue")+""); } else if (lookupItem("McHugeLarge left pole").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT POLE first.", "red")); + description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT POLE first.", "red")+""); } } resource_entries.listAppend(ChecklistEntryMake("__item McHugeLarge duffel bag", url, ChecklistSubentryMake("McHugeLarge ski set skills", description), 1)); From bc41a7ae5a571900699e7b739ce94f5d2bffda35 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 19 Aug 2025 15:21:15 +0000 Subject: [PATCH 20/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 618a6ab3..0b8747d1 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -20215,8 +20215,7 @@ void QNemesisGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [in void QSeaInit() { // While in 11,037 leagues under the sea, you want this showing no matter what. - - if (my_path().id != 55){ + if (my_path().id != PATH_SEA){ //Have they adventured anywhere underwater? boolean have_adventured_in_relevant_area = false; foreach l in $locations[the briny deeps, the brinier deepers, the briniest deepests, an octopus's garden,the wreck of the edgar fitzsimmons, the mer-kin outpost, madness reef,the marinara trench, the dive bar,anemone mine, the coral corral, mer-kin elementary school,mer-kin library,mer-kin gymnasium,mer-kin colosseum,the caliginous abyss] { @@ -20229,6 +20228,8 @@ void QSeaInit() if (!have_adventured_in_relevant_area && $items[Mer-kin trailmap,Mer-kin lockkey,Mer-kin stashbox,wriggling flytrap pellet,damp old boot,Grandma's Map,Grandma's Chartreuse Yarn,Grandma's Fuchsia Yarn,Grandma's Note,black glass].available_amount() == 0) return; } + + if (my_path().id == PATH_SEA) QuestStateParseMafiaQuestPropertyValue(state, "started"); if (true) { @@ -55065,7 +55066,7 @@ void IOTMCursedMonkeysPawGenerateResource(ChecklistEntry [int] resource_entries) true, true ), - } + }; MonkeyWish [int] aftercoreWishes = { new MonkeyWish( @@ -55075,7 +55076,7 @@ void IOTMCursedMonkeysPawGenerateResource(ChecklistEntry [int] resource_entries) locationAvailable($location[The Ice Hotel]), true ) - } + }; // Rejecting bad wishes for CS, Goo, and Sea path boolean inNonQuestPath = (my_path().id == PATH_COMMUNITY_SERVICE || my_path().id == PATH_GREY_GOO || my_path().id == PATH_SEA); From e4cfc44784c69c8bff7ce24e1837c4958e092aee Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 19 Aug 2025 16:26:23 +0000 Subject: [PATCH 21/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 82 ++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 0b8747d1..20ae3d10 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -54488,6 +54488,17 @@ void IOTMRockGardenGenerateResource(ChecklistEntry [int] resource_entries) { } resource_entries.listAppend(ChecklistEntryMake("__item rock garden guide", url, ChecklistSubentryMake("Rock garden resources", "", description)).ChecklistEntrySetIDTag("rock garden resource")); + + // Groveling Gravel: item-crunching instakill + boolean instakills_usable = my_path().id != PATH_G_LOVER && my_path().id != PATH_POCKET_FAMILIARS && my_path().id != 52; // avant guard + + if (instakills_usable && availableGravels > 0) + { + string [int] gravelDescription; + gravelDescription.listAppend("Use groveling gravel for a no-drop freekill."); + resource_entries.listAppend(ChecklistEntryMake("__item groveling gravel", "", ChecklistSubentryMake(pluralise(availableGravels, "groveling gravel", "groveling gravels"), "", gravelDescription), 0).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("groveling gravel free kill")); + + } } boolean hasAnySkillOf(string [int] skillNames) { @@ -56292,11 +56303,10 @@ void IOTMCandyCaneSwordGenerateTasks(ChecklistEntry [int] task_entries, Checklis // - Community Service & Grey Goo: irrelevant // - Avatar of Boris: cannot wield a weapon other than trusty or use a familiar // - 11,037 Leagues Under the Sea: irrelevant - boolean pathCheck = true; - pathCheck = my_path().id == PATH_SEA ? false : true; - pathCheck = my_path().id == PATH_COMMUNITY_SERVICE ? false : true; - pathCheck = my_path().id == PATH_GREY_GOO ? false : true; - pathCheck = my_path().id == PATH_AVATAR_OF_BORIS ? false : true; + if (my_path().id == PATH_SEA) return; + if (my_path().id == PATH_COMMUNITY_SERVICE) return; + if (my_path().id == PATH_GREY_GOO) return; + if (my_path().id == PATH_AVATAR_OF_BORIS) return; // Only show when in run, for obvious reasons. if (__misc_state["in run"] && pathCheck) @@ -56993,46 +57003,49 @@ void IOTMVIPPhotoBoothGenerateResource(ChecklistEntry [int] resource_entries) return; string [int] description; - string url = "inventory.php?ftext=sheriff"; + string url = "clan_viplounge.php?action=photobooth"; int photosLeft = clampi(3 - get_property_int("_photoBoothEffects"), 0, 3); if (photosLeft > 0) { description.listAppend(HTMLGenerateSpanFont("Get your photo taken:", "black")); - description.listAppend(HTMLGenerateSpanFont("photobooth west: +50% init, +noncom%", "black")); - description.listAppend(HTMLGenerateSpanFont("photobooth tower: +com%", "black")); - description.listAppend(HTMLGenerateSpanFont("photobooth space: this sucks", "black")); + description.listAppend(HTMLGenerateSpanFont("|*photobooth west: +50% init, +noncom%", "black")); + description.listAppend(HTMLGenerateSpanFont("|*photobooth tower: +com%", "black")); + description.listAppend(HTMLGenerateSpanFont("|*photobooth space: this sucks", "black")); resource_entries.listAppend(ChecklistEntryMake("__item expensive camera", url, ChecklistSubentryMake(photosLeft + " clan photos takeable", description), 8)); } - //this here town ain't big enough for the two of us - int sheriffings = clampi(3 - get_property_int("_assertYourAuthorityCast"), 0, 3); - if (sheriffings > 0) - { - if (lookupItem("sheriff badge").equipped_amount() == 1 && lookupItem("sheriff moustache").equipped_amount() == 1 && lookupItem("sheriff pistol").equipped_amount() == 1) - { - description.listAppend(HTMLGenerateSpanFont("Assert your authority!", "blue")); - } - else - { - description.listAppend(HTMLGenerateSpanFont("Equip your sheriff gear first.", "red")); - } - resource_entries.listAppend(ChecklistEntryMake("__item badge of authority", url, ChecklistSubentryMake(sheriffings + " Sheriff Authority free kill(s)", description), 5)); - } -} + //Assert Your Authority: item-crunching instakill + // "this here town ain't big enough for the two of us" + + int sheriffings_left = clampi(3 - get_property_int("_assertYourAuthorityCast"), 0, 3); + boolean you_are_the_sheriff = (lookupItem("sheriff badge").available_amount() > 0 && lookupItem("sheriff moustache").available_amount() > 0 && lookupItem("sheriff pistol").available_amount() > 0); + boolean instakills_usable = my_path().id != PATH_G_LOVER && my_path().id != PATH_POCKET_FAMILIARS && my_path().id != 52; // avant guard + + if (sheriffings_left > 0 && instakills_usable && you_are_the_sheriff) + { + string [int] authorityDescription; + authorityDescription.listAppend("Assert Your Authority for a no-drop freekill."); + + if (lookupItem("sheriff badge").equipped_amount() != 1 && lookupItem("sheriff moustache").equipped_amount() != 1 && lookupItem("sheriff pistol").equipped_amount() != 1) + { + authorityDescription.listAppend(HTMLGenerateSpanFont("Equip your sheriff gear first.", "red")); + url = "inventory.php?ftext=sheriff"; + } + resource_entries.listAppend(ChecklistEntryMake("__item badge of authority", url, ChecklistSubentryMake(pluralise(sheriffings_left, "authority assertion", "authority assertions"), "", authorityDescription), 0).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("assert your authority free kill")); + + } +} RegisterResourceGenerationFunction("IOTMPeaceTurkeyGenerateResource"); void IOTMPeaceTurkeyGenerateResource(ChecklistEntry [int] resource_entries) { if (!lookupFamiliar("Peace Turkey").familiar_is_usable()) return; // Purkey Title -//still needs a fix for famwt when not active (currently returns 0 but still functions) int turkeyProc = 24; - if (my_familiar() == lookupFamiliar("peace turkey")); - { - int turkeyProc = 24 + sqrt(effective_familiar_weight($familiar[peace turkey]) + weight_adjustment()); - } + turkeyProc = 24 + square_root(effective_familiar_weight($familiar[peace turkey]) + weight_adjustment()); + int PeasCount = available_amount($item[whirled peas]); int PeaSoupCount = available_amount($item[handful of split pea soup]); string [int] description; @@ -57245,11 +57258,11 @@ void IOTMSkiSetGenerateResource(ChecklistEntry [int] resource_entries) //fixme: currently not supported by sneako tile if (lookupItem("McHugeLarge left ski").equipped_amount() == 1) { - description.listAppend(HTMLGenerateSpanFont("|*LEFT SKI equipped!", "blue")+""); + description.listAppend("|*"+HTMLGenerateSpanFont("LEFT SKI", "blue")+" equipped."); } else if (lookupItem("McHugeLarge left ski").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT SKI first.", "red")+""); + description.listAppend("|*Equip the "+HTMLGenerateSpanFont("LEFT SKI", "red")+" first."); } } if (skiSlashesLeft > 0) @@ -57257,16 +57270,15 @@ void IOTMSkiSetGenerateResource(ChecklistEntry [int] resource_entries) description.listAppend(HTMLGenerateSpanOfClass(skiSlashesLeft + " slashes", "r_bold") + " left. Track a monster."); if (lookupItem("McHugeLarge left pole").equipped_amount() == 1) { - description.listAppend(HTMLGenerateSpanFont("|*LEFT POLE equipped!", "blue")+""); + description.listAppend("|*"+HTMLGenerateSpanFont("LEFT POLE", "blue")+" equipped."); } else if (lookupItem("McHugeLarge left pole").equipped_amount() == 0) { - description.listAppend(HTMLGenerateSpanFont("|*Equip the LEFT POLE first.", "red")+""); + description.listAppend("|*Equip the "+HTMLGenerateSpanFont("LEFT POLE", "red")+" first."); } } resource_entries.listAppend(ChecklistEntryMake("__item McHugeLarge duffel bag", url, ChecklistSubentryMake("McHugeLarge ski set skills", description), 1)); } - //leprecondo RegisterTaskGenerationFunction("IOTMLeprecondoGenerateTasks"); void IOTMLeprecondoGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) @@ -57547,7 +57559,7 @@ void IOTMMobiusRingGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt string url = "inventory.php?ftext=bius+ring"; string [int] copDescription; string copSubTitle = "Forecast is "+currentTimeCopRate+"% chance of cops"; - string copTitle = HTMLGenerateSpanFont(pluralise(max(11-countTimeCops, 0), "free Time Cops fought today", "free Time Cops fought today"), "black"); + string copTitle = HTMLGenerateSpanFont(pluralise(min(countTimeCops, 11), "free Time Cops fought today", "free Time Cops fought today"), "black"); boolean copsNoLongerFree = countTimeCops > 11; int priority = 10; From 852a140da74b3c5075a366be7244329565e04080 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 19 Aug 2025 16:30:02 +0000 Subject: [PATCH 22/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 20ae3d10..de676b9f 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -20229,13 +20229,13 @@ void QSeaInit() return; } - if (my_path().id == PATH_SEA) QuestStateParseMafiaQuestPropertyValue(state, "started"); if (true) { QuestState state; state.state_string["path"] = get_property("merkinQuestPath"); + if (state.state_string["path"] == "done") QuestStateParseMafiaQuestPropertyValue(state, "finished"); else @@ -56309,7 +56309,7 @@ void IOTMCandyCaneSwordGenerateTasks(ChecklistEntry [int] task_entries, Checklis if (my_path().id == PATH_AVATAR_OF_BORIS) return; // Only show when in run, for obvious reasons. - if (__misc_state["in run"] && pathCheck) + if (__misc_state["in run"]) { string url = "inventory.php?ftext=candy+cane+sword+cane"; // This is the description for the supernag. The supernag is in the task_entries, buried within conditional ifs and only shows up if you're in the zone. From 617a0d8e442ca34fd46a185a7acaa4381508535d Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 20 Aug 2025 13:03:42 +0000 Subject: [PATCH 23/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 131 ++++++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 12 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index de676b9f..5a0d211c 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -1,8 +1,8 @@ //This script and its support scripts are in the public domain. -since r28562; // fix: names for base hippy camp, frat house, video game dungeons +since r28660; // fix: lots and lots of sea stuff //These settings are for development. Don't worry about editing them. -string __version = "2.2.2"; // pushed to 2.2.1 on jill/leaves tiles +string __version = "2.3.1"; // pushed to 2.2.1 on jill/leaves tiles, 2.3.1 on sea path upgrades //Path and name of the .js file. In case you change either. string __javascript = "TourGuide/TourGuide.js"; @@ -4904,6 +4904,8 @@ void initialiseIOTMsUsable() __iotms_usable[lookupItem("cold medicine cabinet")] = true; if (__campground[lookupItem("model train set")] > 0) __iotms_usable[lookupItem("model train set")] = true; + if (__campground[lookupItem("TakerSpace letter of Marque")] > 0) + __iotms_usable[lookupItem("TakerSpace letter of Marque")] = true; // This didn't appear in my LoL test run; I am making this more explicit and hopefully this works. if (__campground[lookupItem("Little Geneticist DNA-Splicing Lab")] > 0) @@ -5030,7 +5032,42 @@ void initialiseIOTMsUsable() if (lookupItem("tearaway pants").available_amount() > 0) //Aug 2024 __iotms_usable[lookupItem("tearaway pants")] = true; + + if (lookupItem("sept-ember censer").available_amount() > 0) //Sep 2024 + __iotms_usable[lookupItem("sept-ember censer")] = true; + + if (lookupItem("bat wings").available_amount() > 0) //Oct 2024 + __iotms_usable[lookupItem("bat wings")] = true; + + // Nov 2024 -- peace turkey, unneedded + // Dec 2024 -- takerspace, in campground above + + if (lookupItem("McHugeLarge duffel bag").available_amount() > 0) //Jan 2025 + __iotms_usable[lookupItem("McHugeLarge duffel bag")] = true; + + if (lookupItem("toy Cupid bow").available_amount() > 0) //Feb 2025 + __iotms_usable[lookupItem("toy Cupid bow")] = true; + + if (lookupItem("Leprecondo").available_amount() > 0) //Mar 2025 + __iotms_usable[lookupItem("Leprecondo")] = true; + if (lookupItem("April Shower Thoughts shield").available_amount() > 0) //Apr 2024 + __iotms_usable[lookupItem("April Shower Thoughts shield")] = true; + + if (lookupItem("Peridot of Peril").available_amount() > 0) //May 2024 + __iotms_usable[lookupItem("Peridot of Peril")] = true; + + if (lookupItem("prismatic beret").available_amount() > 0) //Jun 2024 + __iotms_usable[lookupItem("prismatic beret")] = true; + + // july 2025 -- yeti, familiar, unneeded + + if (lookupItem("Möbius ring").available_amount() > 0) //Aug 2024 + __iotms_usable[lookupItem("Möbius ring")] = true; + + if (lookupItem("allied radio backpack").available_amount() > 0) //Aug 2024 + __iotms_usable[lookupItem("allied radio backpack")] = true; + //Can't use many things in G-Lover if (my_path().id == PATH_G_LOVER) //Path 33 { @@ -26484,7 +26521,9 @@ void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) skills_to_urls[$skill[Summon Confiscated Things]] = "campground.php?action=bookshelf"; } property_summons_to_skills["_candySummons"] = listMake($skill[Summon Crimbo Candy]); - property_summons_to_skills["_summonResortPassesUsed"] = listMake($skill[Summon Kokomo Resort Pass]); + + // _summonResortPassUsed is boolean, _summonResortPassesUsed (the old one) is 1/0 + property_summons_to_skills["_summonResortPassUsed"] = listMake($skill[Summon Kokomo Resort Pass]); property_summons_to_skills["_incredibleSelfEsteemCast"] = listMake(lookupSkill("Incredible Self-Esteem")); skills_to_details[lookupSkill("Incredible Self-Esteem")] = "Gives or extends affirmation buffs."; if (__misc_state["in run"] && lookupItem("Daily Affirmation: Always be Collecting").available_amount() > 0 && lookupItem("Daily Affirmation: Always be Collecting").to_effect().have_effect() == 0) @@ -33612,6 +33651,40 @@ void SocialDistanceGenerator(ChecklistEntry [int] resource_entries) return final; } + SneakSource getAlliedRadio() { + SneakSource final; + + final.sourceName = 'allied radio backpack'; + final.url = "inventory.php?action=requestdrop&pwd=" + my_hash(); + final.imageLookupName = "__item allied radio backpack"; + + int naturalRadiosLeft = clampi(3 - get_property_int("_alliedRadioDropsUsed"), 0, 3); + int handheldRadios = $item[handheld allied radio].available_amount(); + int totalRadios = naturalRadiosLeft + handheldRadios; + + final.sneakCondition = (__iotms_usable[$item[Allied Radio Backpack]] && naturalRadiosLeft > 0) || handheldRadios > 0; + final.sneakCount = totalRadios; + final.tileDescription = `{totalRadios}x allied radio snipers left`; + return final; + + } + + SneakSource getTubas() { + SneakSource final; + + final.sourceName = 'apriling tuba'; + final.url = "inventory.php?ftext=apriling+band+tuba"; + final.imageLookupName = "__item Apriling band tuba"; + + int aprilingBandTubaUsesLeft = clampi(3 - get_property_int("_aprilBandTubaUses"), 0, 3); + + final.sneakCondition = (aprilingBandTubaUsesLeft > 0 && available_amount($item[apriling band tuba]) > 0); + final.sneakCount = aprilingBandTubaUsesLeft; + final.tileDescription = `{spikosLeft}x apriling tuba oompa oompas left`; + return final; + + } + // Having generated these, we now get to generate a tile that combines them. SneakSource [string] sneakSources; @@ -33621,9 +33694,11 @@ void SocialDistanceGenerator(ChecklistEntry [int] resource_entries) sneakSources["jello"] = getStenchJellies(); sneakSources["pillo"] = getSneakisol(); sneakSources["claro"] = getClaras(); + sneakSources["tubao"] = getTubas(); + sneakSources["radio"] = getAlliedRadio(); // Making it use the order we want; almost most recent to oldest, but pills on the bottom. - string [int] sneakOrder = listMake("cinco","spiko","jello","claro","pillo"); + string [int] sneakOrder = listMake("radio","tubao","cinco","spiko","jello","claro","pillo"); ChecklistEntry entry; @@ -33829,7 +33904,7 @@ void SocialDistanceGenerator(ChecklistEntry [int] resource_entries) // Having done this, you now append the NCs remaining subentry to the end of the core entry, with an on_mouse_over bit as well. // However, I am going to be lazy, and not append either of these in the event the user is in CS/GG. - if (my_path().id != PATH_COMMUNITY_SERVICE && my_path().id != PATH_GREY_GOO) { + if (my_path().id != PATH_COMMUNITY_SERVICE && my_path().id != PATH_GREY_GOO && my_path().id != PATH_SEA) { entry.subentries.listAppend(ChecklistSubentryMake(pluralise(totalNCsRemaining, "NC remaining","NCs remaining"), "", HTMLGenerateSpanOfClass("Mouse over for the best sneaks!", "r_bold r_element_spooky_desaturated"))); entry.subentries_on_mouse_over.listAppend(ChecklistSubentryMake(pluralise(totalNCsRemaining, "NC remaining","NCs remaining"), "", table.HTMLGenerateSimpleTableLines(false))); } @@ -55938,9 +56013,6 @@ void IOTMBookofFactsGenerateResource(ChecklistEntry [int] resource_entries) // - Remind the user to get an LED candle. // - Recommend halloween monsters for habitation. -// CANNOT DO YET: -// - Add halloween fights to freebies combination tag; need better mafia tracking... - RegisterResourceGenerationFunction("IOTMJillv2GenerateResource"); void IOTMJillv2GenerateResource(ChecklistEntry [int] resource_entries) { @@ -55964,7 +56036,7 @@ void IOTMJillv2GenerateResource(ChecklistEntry [int] resource_entries) description.listAppend("You haven't gotten a map to halloween town yet! Try using your Jill for a map at ~"+round(estimatedMapProbability)+"% chance, or approximately "+round(turnsToMap,1)+" turns."); } else if (mapsDropped < 2) { // The third map drop chance is less than 1 in a thousand - not something that is particularly useful to hunt for - description.listAppend("You have a map; the next map is at a ~"+round(estimatedMapProbability)+"% chance, or approximately "+round(turnsToMap,1)+" turns."); + description.listAppend("You already got a map; the next map is at a ~"+round(estimatedMapProbability)+"% chance, or approximately "+round(turnsToMap,1)+" turns."); } int habitatRecallsLeft = clampi(3 - get_property_int("_monsterHabitatsRecalled"), 0, 3); @@ -55977,6 +56049,17 @@ void IOTMJillv2GenerateResource(ChecklistEntry [int] resource_entries) description.listAppend("Fight a dude for an LED candle, to tune your Jill!"); } + // Populate a free fights count of trick-or-treat fights. + string trickOrTreatMap = get_property("_trickOrTreatBlock"); + string[int] splitToT = split_string(trickOrTreatMap, ""); + int freeFightsLeft; + + foreach house in splitToT { + if (splitToT[house] == "D") {freeFightsLeft +=1;} + } + + if (freeFightsLeft > 0) {resource_entries.listAppend(ChecklistEntryMake("__familiar jill-of-all-trades", "place.php?whichplace=town&action=town_trickortreat", ChecklistSubentryMake(pluralise(freeFightsLeft, "Trick or Treat fight", "Trick or Treat fights"), "", ""), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("trick or treat free fights"));} + // If we have nothing to say, do not display the tile if (count(description) == 0) return; @@ -56054,7 +56137,7 @@ void IOTMBurningLeavesGenerateResource(ChecklistEntry [int] resource_entries) // Don't generate these tiles if they cannot actually use their leaves if (!__iotms_usable[$item[A Guide to Burning Leaves]]) return; - string url = "campground.php?preaction=burningleaves"; + string url = "campground.php?preaction=leaves"; // Make two tiles for spending leaves int leafCount = $item[inflammable leaf].item_amount(); @@ -56277,7 +56360,7 @@ void IOTMBurningLeavesGenerateResource(ChecklistEntry [int] resource_entries) description.listAppend("Have enough leaves, if you let the leaflets drop their bounty!"); } else { - description.listAppend(HTMLGenerateSpanFont("Can summon "+leafletsUserCanSummon+" of your "+fightsRemaining+" leaflets... get more leaves!", "orange")); + description.listAppend("Can summon "+leafletsUserCanSummon+" of your "+fightsRemaining+" leaflets... "+HTMLGenerateSpanFont("get more leaves!", "orange")); } subentries.listAppend(ChecklistSubentryMake(pluralise(fightsRemaining, "free flaming leaflet fight", "free flaming leaflet fights"), "", description)); @@ -56287,6 +56370,29 @@ void IOTMBurningLeavesGenerateResource(ChecklistEntry [int] resource_entries) resource_entries.listAppend(ChecklistEntryMake("__item tied-up flaming leaflet", url, subentries, tags, 0)); } } + +RegisterTaskGenerationFunction("BurningLeavesRakeReminder"); +void SneakActiveTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // Don't generate this tile if they cannot actually use their leaves + if (!__iotms_usable[$item[A Guide to Burning Leaves]]) return; + + string url = "campground.php?preaction=burningleaves"; + // Use the new preference to tell if there's an NC forcer active + if ($item[rake].available_amount() > 0) return; + + // If they don't have a rake, remind them to get one + ChecklistEntry entry; + + entry.url = "campground.php?preaction=leaves"; + entry.image_lookup_name = "__item Inflammable leaf"; + entry.tags.id = "Rake and Tiny Rake reminder"; + entry.importance_level = 7; + + entry.subentries.listAppend(ChecklistSubentryMake("It's mulch madness -- go get your rakes","","Visit your pile of burning leaves for rakes... for more leaves!")); + + optional_task_entries.listAppend(entry); +} // Candy Cane Sword Cane RegisterTaskGenerationFunction("IOTMCandyCaneSwordGenerateTasks"); void IOTMCandyCaneSwordGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) @@ -57116,10 +57222,11 @@ void IOTYCyberRealmGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt string url = "place.php?whichplace=CyberRealm"; string image_name = "__skill stats+++"; + // If in-run, do not show the FITMW nag. if ($item[familiar-in-the-middle wrapper].equipped_amount() == 1) { description.listAppend(HTMLGenerateSpanFont("FITMW equipped. Extra 1 per fight.", "blue")); } - else if ($item[familiar-in-the-middle wrapper].equipped_amount() == 0) { + else if ($item[familiar-in-the-middle wrapper].equipped_amount() == 0 && !__misc_state["in run"]) { description.listAppend(HTMLGenerateSpanFont("Equip your FITMW for an extra 1 per fight.", "red")); } From 820627aada674e89bedcd3776c13e862b6df2a4b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 20 Aug 2025 13:16:33 +0000 Subject: [PATCH 24/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 5a0d211c..9285c9c3 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -33680,7 +33680,7 @@ void SocialDistanceGenerator(ChecklistEntry [int] resource_entries) final.sneakCondition = (aprilingBandTubaUsesLeft > 0 && available_amount($item[apriling band tuba]) > 0); final.sneakCount = aprilingBandTubaUsesLeft; - final.tileDescription = `{spikosLeft}x apriling tuba oompa oompas left`; + final.tileDescription = `{aprilingBandTubaUsesLeft}x apriling tuba oompa oompas left`; return final; } @@ -56372,7 +56372,7 @@ void IOTMBurningLeavesGenerateResource(ChecklistEntry [int] resource_entries) } RegisterTaskGenerationFunction("BurningLeavesRakeReminder"); -void SneakActiveTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +void BurningLeavesRakeReminder(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { // Don't generate this tile if they cannot actually use their leaves if (!__iotms_usable[$item[A Guide to Burning Leaves]]) return; From ab169628b82cdfda8c22d00e9c100762a486d708 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 20 Aug 2025 13:26:04 +0000 Subject: [PATCH 25/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 9285c9c3..68c7b25a 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -26448,6 +26448,7 @@ void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) property_summon_limits["_grimoireGeekySummons"] = 1; property_summon_limits["_grimoireConfiscatorSummons"] = 1; property_summon_limits["_candySummons"] = 1; + property_summon_limits["_summonResortPassesUsed"] = 1; if ($skill[advanced saucecrafting].have_skill() && $skill[advanced saucecrafting].skill_is_usable()) property_summons_to_skills["reagentSummons"] = listMake($skill[advanced saucecrafting], $skill[the way of sauce]); @@ -26521,9 +26522,7 @@ void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) skills_to_urls[$skill[Summon Confiscated Things]] = "campground.php?action=bookshelf"; } property_summons_to_skills["_candySummons"] = listMake($skill[Summon Crimbo Candy]); - - // _summonResortPassUsed is boolean, _summonResortPassesUsed (the old one) is 1/0 - property_summons_to_skills["_summonResortPassUsed"] = listMake($skill[Summon Kokomo Resort Pass]); + property_summons_to_skills["_summonResortPassesUsed"] = listMake($skill[Summon Kokomo Resort Pass]); property_summons_to_skills["_incredibleSelfEsteemCast"] = listMake(lookupSkill("Incredible Self-Esteem")); skills_to_details[lookupSkill("Incredible Self-Esteem")] = "Gives or extends affirmation buffs."; if (__misc_state["in run"] && lookupItem("Daily Affirmation: Always be Collecting").available_amount() > 0 && lookupItem("Daily Affirmation: Always be Collecting").to_effect().have_effect() == 0) @@ -33669,6 +33668,22 @@ void SocialDistanceGenerator(ChecklistEntry [int] resource_entries) } + SneakSource getAvalanches() { + SneakSource final; + + final.sourceName = 'McHugeLarge Avalanche'; + final.url = "inventory.php?ftext=McHugeLarge+left+ski "; + final.imageLookupName = "__item McHugeLarge left ski"; + + int avalanchesLeft = clampi(3 - get_property_int("_mcHugeLargeAvalancheUses"), 0, 3); + + final.sneakCondition = (avalanchesLeft > 0 && available_amount($item[McHugeLarge duffel bag]) > 0); + final.sneakCount = avalanchesLeft; + final.tileDescription = `{avalanchesLeft}x McHugeLarge avalanches left`; + return final; + + } + SneakSource getTubas() { SneakSource final; @@ -33695,10 +33710,11 @@ void SocialDistanceGenerator(ChecklistEntry [int] resource_entries) sneakSources["pillo"] = getSneakisol(); sneakSources["claro"] = getClaras(); sneakSources["tubao"] = getTubas(); + sneakSources["mchgo"] = getAvalanches(); sneakSources["radio"] = getAlliedRadio(); // Making it use the order we want; almost most recent to oldest, but pills on the bottom. - string [int] sneakOrder = listMake("radio","tubao","cinco","spiko","jello","claro","pillo"); + string [int] sneakOrder = listMake("radio","mchgo","tubao","cinco","spiko","jello","claro","pillo"); ChecklistEntry entry; From 595bb1987f53e32f18763a283a6979992fbf0c82 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 21 Aug 2025 13:33:33 +0000 Subject: [PATCH 26/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 125 ++++++++++++++++++++++++++------------ 1 file changed, 85 insertions(+), 40 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 68c7b25a..95f560d3 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -20310,6 +20310,9 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name boolean can_fight_dad_sea_monkee = temple_quest_state.state_boolean["can fight dad sea monkee"]; boolean have_any_outfit = temple_quest_state.state_boolean["have one outfit"] || temple_quest_state.state_boolean["can fight dad sea monkee"]; + // Going to use a "in sea path" to turn off many pieces. + boolean inSeaPath = my_path().id == PATH_SEA; + if (!have_any_outfit) { subentry.entries.listAppend("Acquire crappy mer-kin disguise from grandma sea monkee."); return; @@ -20326,16 +20329,36 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name at_scholar_boss = true; } at_boss = at_gladiator_boss || at_scholar_boss; + + // Try to keep both tile halves up in sea path. + + boolean stillGottaKillShub = false; + boolean stillGottaKillYogurt = false; + + if (inSeaPath) { + stillGottaKillShub = true; + stillGottaKillYogurt = true; + + if (!get_property_boolean("shubJigguwattDefeated")) stillGottaKillShub = false; + if (!get_property_boolean("yogUrtDefeated")) stillGottaKillYogurt = false; + } - if (!at_boss || at_gladiator_boss) { + if (!at_boss || at_gladiator_boss || stillGottaKillShub) { string [int] description; string [int] modifiers; //gladiator: if (at_gladiator_boss) { + // Used to check passive damage for warning. + int famCanDamage = to_int(my_familiar().elemental_damage) + to_int(my_familiar().physical_damage); + int passiveDamage = to_int(numeric_modifier($modifier[thorns]) + numeric_modifier($modifier[damage aura]) + numeric_modifier($modifier[sporadic damage aura]) + numeric_modifier($modifier[sporadic thorns])); + description.listAppend("Buff muscle, equip a powerful weapon."); description.listAppend("Delevel him for a bit, then attack with your weapon."); if ($item[crayon shavings].available_amount() > 0) description.listAppend("|*Your crayon shavings are great for this!"); description.listAppend("Make sure not to have anything along that will attack him. (familiars, etc)"); + if (passiveDamage > 0) description.listAppend(HTMLGenerateSpanFont("WARNING: You have passive damage on. Remove it, he'll kill you!", "red")); + if (famCanDamage > 0) description.listAppend(HTMLGenerateSpanFont("WARNING: You have a damaging familiar equipped. Change your familiar!", "red")); + //umm... this probably won't be updated: string [int] things_to_do; foreach it in $items[hand in glove,MagiMechTech NanoMechaMech,bottle opener belt buckle,old school calculator watch,ant hoe,ant pick,ant pitchfork,ant rake,ant sickle,fishy wand,moveable feast,oversized fish scaler,replica plastic pumpkin bucket,plastic pumpkin bucket,tiny bowler,cup of infinite pencils,double-ice box,smirking shrunken head,mr. haggis,stapler bear,dubious loincloth,muddy skirt,bottle of Goldschnöckered,acid-squirting flower,ironic oversized sunglasses,hippy protest button,cannonball charrrm bracelet,groovy prism necklace,spiky turtle shoulderpads,double-ice cap,parasitic headgnawer,eelskin hat,balloon shield,hot plate,Ol' Scratch's stove door,Oscus's garbage can lid,eelskin shield,eelskin pants] { @@ -20349,7 +20372,7 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name if (things_to_do.count() > 0) description.listAppend(HTMLGenerateSpanFont(things_to_do.listJoinComponents(", ", "and").capitaliseFirstLetter() + ".", "red")); - if ($item[dark porquoise ring].equipped_amount() == 0) { + if (!inSeaPath && $item[dark porquoise ring].equipped_amount() == 0) { string line = "Possibly "; if ($item[dark porquoise ring].available_amount() == 0) line += "acquire and "; @@ -20378,6 +20401,8 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name shrap_suggestion += " (use your used copy of warbear metalworking primer)"; } else shrap_suggestion += " (from warbear metalworking primer)"; + // Cannot use shrap in sea path. Well, maybe when it's unrestricted. But do you even get whosits? + if (inSeaPath) shrap_suggestion = ""; } modifiers.listAppend("spell damage percent"); modifiers.listAppend("mysticality"); @@ -20434,28 +20459,40 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name if (description.count() > 0) subentry.entries.listAppend("Gladiator path" + HTMLGenerateIndentedText(modifier_string + description.listJoinComponents("
"))); } - if (!at_boss || at_scholar_boss) { + if (!at_boss || at_scholar_boss || stillGottaKillYogurt) { string [int] description; string [int] modifiers; //scholar: if (at_scholar_boss) { - description.listAppend("Wear several mer-kin prayerbeads and possibly a mer-kin gutgirdle."); - description.listAppend("Avoid wearing any +hp gear or buffs. Ideally, you want low HP."); + + // Used to check fam damage for warning. + int famCanDamage = to_int(my_familiar().elemental_damage) + to_int(my_familiar().physical_damage); + int passiveDamage = to_int(numeric_modifier($modifier[thorns]) + numeric_modifier($modifier[damage aura]) + numeric_modifier($modifier[sporadic damage aura]) + numeric_modifier($modifier[sporadic thorns])); + + int prayerbeadsEquipped = $item[mer-kin prayerbeads].equipped_amount(); + int prayerbeadsAvailable = clampi($item[mer-kin prayerbeads].item_amount(),0,3); + + description.listAppend("Wear mer-kin prayerbeads. "+HTMLGenerateSpanFont(prayerbeadsEquipped+"/"+prayerbeadsAvailable+" of your beads equipped.",(prayerbeadsEquipped == prayerbeadsAvailable ? "black" : "red"))+(!inSeaPath ? "" : " Consider a gutgirdle, too?")); + description.listAppend("Avoid wearing any +HP gear or buffs. Ideally, you want low HP."); + + if (passiveDamage > 0) description.listAppend(HTMLGenerateSpanFont("WARNING: You have passive damage on. Remove it, she'll kill you!", "red")); + if (famCanDamage > 0) description.listAppend(HTMLGenerateSpanFont("WARNING: You have a damaging familiar equipped. Change your familiar!", "red")); + description.listAppend("Each round, use a different healing item, until you lose the Suckrament effect.
After that, your stats are restored. Fully heal, then " + HTMLGenerateSpanOfClass("attack with elemental damage", "r_bold") + "."); string [item] potential_healers; potential_healers[$item[mer-kin healscroll]] = "mer-kin healscroll (full HP)"; - potential_healers[$item[scented massage oil]] = "scented massage oil (full HP)"; - potential_healers[$item[soggy used band-aid]] = "soggy used band-aid (full HP)"; + if (!inSeaPath) potential_healers[$item[scented massage oil]] = "scented massage oil (full HP)"; + if (!inSeaPath) potential_healers[$item[soggy used band-aid]] = "soggy used band-aid (full HP)"; potential_healers[$item[sea gel]] = "sea gel (+500 HP)"; potential_healers[$item[waterlogged scroll of healing]] = "waterlogged scroll of healing (+250 HP)"; - potential_healers[$item[extra-strength red potion]] = "extra-strength red potion (+200 HP)"; + if (!inSeaPath) potential_healers[$item[extra-strength red potion]] = "extra-strength red potion (+200 HP)"; potential_healers[$item[red pixel potion]] = "red pixel potion (+100-120 HP)"; - potential_healers[$item[red potion]] = "red potion (+100 HP)"; + if (!inSeaPath) potential_healers[$item[red potion]] = "red potion (+100 HP)"; potential_healers[$item[filthy poultice]] = "filthy poultice (+80-120 HP)"; potential_healers[$item[gauze garter]] = "gauze garter (+80-120 HP)"; potential_healers[$item[green pixel potion]] = "green pixel potion (+40-60 HP)"; - potential_healers[$item[cartoon heart]] = "cartoon heart (40-60 HP)"; - potential_healers[$item[red plastic oyster egg]] = "red plastic oyster egg (+35-40 HP)"; + if (!inSeaPath) potential_healers[$item[cartoon heart]] = "cartoon heart (40-60 HP)"; + if (!inSeaPath) potential_healers[$item[red plastic oyster egg]] = "red plastic oyster egg (+35-40 HP)"; string [int] description_healers; foreach it in potential_healers { @@ -20694,7 +20731,7 @@ void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] o if ($item[sea lasso].item_amount() == 0) line += HTMLGenerateSpanFont((in_ronin() ? "Acquire" : "Buy") + " and use a sea lasso in each combat.", "red"); else - line += "Use a sea lasso in each combat."; + line += "Use a sea lasso in each combat. (Currently at "+get_property_int("lassoTrainingCount")+"/21 lasso skill.)"; if ($item[sea cowboy hat].equipped_amount() == 0) line += "|*Wear a sea cowboy hat to improve roping."; if ($item[sea chaps].equipped_amount() == 0) @@ -20704,11 +20741,11 @@ void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] o professional_roper = true; string line; if ($item[sea lasso].item_amount() == 0) - line += "Buy a sea lasso."; + line += "Acquire a sea lasso."; if ($item[sea cowbell].item_amount() < 3) { int needed_amount = MAX(3 - $item[sea cowbell].item_amount(), 0); if (line != "") line += " "; - line += "Buy " + pluraliseWordy(needed_amount, "sea cowbell", "sea cowbells") + "."; + line += "Acquire " + pluraliseWordy(needed_amount, "sea cowbell", "sea cowbells") + "."; } if (line != "") temple_subentry.entries.listAppend(line); @@ -20765,8 +20802,10 @@ void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] o //Then stash box. Mention monster source. //Use trailmap. //Ask grandpa about currents. - if ($item[Mer-kin trailmap].available_amount() > 0) { - temple_subentry.entries.listAppend("Use Mer-kin trailmap."); + if (get_property_boolean("intenseCurrents") && !get_property_boolean("corralUnlocked")) { + temple_subentry.entries.listAppend("Ask Grandpa about "+HTMLGenerateSpanOfClass("currents", "r_bold")+" to unlock the corral."); + } else if ($item[Mer-kin trailmap].available_amount() > 0) { + temple_subentry.entries.listAppend("Use Mer-kin trailmap, then ask Grandpa about the Currents."); } else if ($item[Mer-kin stashbox].available_amount() > 0) { temple_subentry.entries.listAppend("Open stashbox."); } else if ($item[Mer-kin lockkey].available_amount() > 0) { @@ -20786,7 +20825,6 @@ void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] o int turns_spent = $location[The Mer-Kin Outpost].turns_spent; temple_subentry.entries.listAppend("Adventure in the Mer-Kin outpost to acquire a lockkey."); if (my_path().id == PATH_SEA && turns_spent < 26) temple_subentry.entries.listAppend((24 - turns_spent) +" to " + (26 - turns_spent) + " total delay remaining."); - temple_subentry.entries.listAppend("Unless you discovered the currents already (can't tell), in which case go ask grandpa about currents."); } } else if (monkees_quest_state.mafia_internal_step == 6 || grandpa_ncs_remaining == 0) { url = "monkeycastle.php?who=3"; @@ -20855,9 +20893,10 @@ void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] o if (should_output_sea_monkey_questline) { if (monkees_quest_state.mafia_internal_step == 13) { - //Have black glass; only need to find mom. No progress tracking yet (the progress mechanic for this zone is not yet fully understood...) + //Have black glass; only need to find mom. The NC requires 40 progress. + // You get 1 from fighting an abyss monster, and 1 each from comb/scale/jumper. 40 -> 10 turns! string line; - line += "Adventure in the Caliginous Abyss. Find Mom Sea Monkey."; + line += "Fight native Caliginous Abyss monsters to find " + HTMLGenerateSpanOfClass("Mom Sea Monkee.","r_bold"); if ($item[shark jumper].equipped_amount() == 0) line += "|*Wear a shark jumper to speed up area."; if ($item[scale-mail underwear].equipped_amount() == 0) @@ -20865,7 +20904,14 @@ void QSeaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] o if ($effect[Jelly Combed].have_effect() == 0) line += "|*Use a Comb jelly to speed up area."; + int perFightProgress = 1; + perFightProgress += to_int($item[shark jumper].equipped_amount()>0); + perFightProgress += to_int($item[scale-mail underwear].equipped_amount()>0); + perFightProgress += to_int($effect[Jelly Combed].have_effect() > 0); + string perFightProgressString = (perFightProgress == 4 ? "4" : HTMLGenerateSpanFont(perFightProgress,"red")); + sea_monkey_subentry.entries.listAppend(line); + sea_monkey_subentry.entries.listAppend("Currently at "+get_property_int("momSeaMonkeeProgress")+"/40 progress. Gain "+perFightProgressString+" per fight."); if ($item[black glass].equipped_amount() == 0) { url = "inventory.php?ftext=black+glass"; @@ -26596,10 +26642,10 @@ void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) if (lookupSkill("Evoke Eldritch Horror").skill_is_usable() && !get_property_boolean("_eldritchHorrorEvoked")) { - resource_entries.listAppend(ChecklistEntryMake("__skill Evoke Eldritch Horror", "skillz.php", ChecklistSubentryMake("Evoke Eldritch Horror", "", "Free fight."), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Evoke eldritch horror skill free fight")); + resource_entries.listAppend(ChecklistEntryMake("__skill Evoke Eldritch Horror", "skillz.php", ChecklistSubentryMake("Evoke Eldritch Horror", "", "Free fight."), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Evoke eldritch horror skill free fight")); } - if (!get_property_boolean("_eldritchTentacleFought") && my_path().id != PATH_EXPLOSIONS && my_path().id != PATH_COMMUNITY_SERVICE) { - resource_entries.listAppend(ChecklistEntryMake("__skill Evoke Eldritch Horror", "place.php?whichplace=forestvillage&action=fv_scientist", ChecklistSubentryMake("Science Tent Tentacle", "", "Free fight."), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Daily forest tentacle free fight")); + if (!get_property_boolean("_eldritchTentacleFought") && my_path().id != PATH_EXPLOSIONS && my_path().id != PATH_COMMUNITY_SERVICE && my_path().id != PATH_SEA) { + resource_entries.listAppend(ChecklistEntryMake("__skill Evoke Eldritch Horror", "place.php?whichplace=forestvillage&action=fv_scientist", ChecklistSubentryMake("Science Tent Tentacle", "", "Free fight."), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Daily forest tentacle free fight")); } } @@ -27481,17 +27527,17 @@ void SMiscItemsGenerateResource(ChecklistEntry [int] resource_entries) if ($item[bowl of scorpions].available_amount() > 0 && get_property_int("_drunkPygmyBanishes") < 11 && my_path().id != PATH_G_LOVER && get_property_ascension("hiddenTavernUnlock")) { int uses_remaining = MIN($item[bowl of scorpions].available_amount(), clampi(11 - get_property_int("_drunkPygmyBanishes"), 0, 11)); - resource_entries.listAppend(ChecklistEntryMake("__item bowl of scorpions", "inventory.php?which=3&ftext=bowl+of+scorpions", ChecklistSubentryMake(pluralise(uses_remaining,$item[bowl of scorpions]), "", "Free fight when brought to Bowling Alley."), importance_level_unimportant_item).ChecklistEntrySetIDTag("daily free fight")); + resource_entries.listAppend(ChecklistEntryMake("__item bowl of scorpions", "inventory.php?which=3&ftext=bowl+of+scorpions", ChecklistSubentryMake(pluralise(uses_remaining,$item[bowl of scorpions]), "", "Free fight when brought to Bowling Alley."), 5).ChecklistEntrySetIDTag("daily free fight")); } if ($item[glark cable].available_amount() > 0 && get_property_int("_glarkCableUses") < 5 && my_path().id != PATH_G_LOVER) { int uses_remaining = MIN($item[glark cable].available_amount(), clampi(5 - get_property_int("_glarkCableUses"), 0, 5)); - resource_entries.listAppend(ChecklistEntryMake("__item glark cable", "inventory.php?which=3&ftext=glark+cable", ChecklistSubentryMake(pluralise(uses_remaining,$item[glark cable]), "", "Free fight on the Red Zeppelin."), importance_level_unimportant_item).ChecklistEntrySetIDTag("daily free fight")); + resource_entries.listAppend(ChecklistEntryMake("__item glark cable", "inventory.php?which=3&ftext=glark+cable", ChecklistSubentryMake(pluralise(uses_remaining,$item[glark cable]), "", "Free fight on the Red Zeppelin."), 5).ChecklistEntrySetIDTag("daily free fight")); } if ($item[lynyrd snare].available_amount() > 0 && get_property_int("_lynyrdSnareUses") < 3 && $item[lynyrd snare].item_is_usable()) { // && in_run && __misc_state["need to level"]) int uses_remaining = MIN($item[lynyrd snare].available_amount(), clampi(3 - get_property_int("_lynyrdSnareUses"), 0, 3)); - resource_entries.listAppend(ChecklistEntryMake("__item lynyrd snare", "inventory.php?ftext=lynyrd+snare", ChecklistSubentryMake(pluralise(uses_remaining,$item[lynyrd snare]), "", "Free fight when used."), importance_level_unimportant_item).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Lynyrd snare free fight")); + resource_entries.listAppend(ChecklistEntryMake("__item lynyrd snare", "inventory.php?ftext=lynyrd+snare", ChecklistSubentryMake(pluralise(uses_remaining,$item[lynyrd snare]), "", "Free fight when used."), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Lynyrd snare free fight")); } if (in_run && $item[red box].available_amount() > 0 && $item[red box].item_is_usable()) { resource_entries.listAppend(ChecklistEntryMake("__item red box", "inventory.php?ftext=red+box", ChecklistSubentryMake(pluralise($item[red box]), "", "Open for stuff."), importance_level_unimportant_item).ChecklistEntrySetIDTag("Red box resource")); @@ -27865,7 +27911,7 @@ void SMiscItemsGenerateResource(ChecklistEntry [int] resource_entries) if (glitch_in_closet >= 1) description.listAppend("Uncloset " + (glitch_in_closet > 1 ? "some" : "one") + " to " + (glitch_amount > 1 ? "increase" : "multiply") + " its power and reward."); - resource_entries.listAppend(ChecklistEntryMake("__item [glitch season reward name]", "inventory.php?ftext=%5Bglitch+season+reward+name%5D", ChecklistSubentryMake("[glitch season reward name] free fight", "", description), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Glitch reward free fight")); + resource_entries.listAppend(ChecklistEntryMake("__item [glitch season reward name]", "inventory.php?ftext=%5Bglitch+season+reward+name%5D", ChecklistSubentryMake("[glitch season reward name] free fight", "", description), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Glitch reward free fight")); } } @@ -30950,7 +30996,7 @@ void SSealClubberInfernalSealsGenerateResource(ChecklistEntry [int] resource_ent resource_entries.listAppend(ChecklistEntryMake("__item figurine of an ancient seal", url, ChecklistSubentryMake(pluralise(summons_remaining, "seal summon", "seal summons"), "", description), 10).ChecklistEntrySetIDTag("Seal clubber summon resource")); - resource_entries.listAppend(ChecklistEntryMake("__item figurine of an ancient seal", url, ChecklistSubentryMake(pluralise(summons_remaining, "seal summon", "seal summons"), "", "See dedicated tile."), 10).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Seal clubber summon free fight")); //add an anchor to the dedicated tile?? + resource_entries.listAppend(ChecklistEntryMake("__item figurine of an ancient seal", url, ChecklistSubentryMake(pluralise(summons_remaining, "seal summon", "seal summons"), "", "See dedicated tile."), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Seal clubber summon free fight")); //add an anchor to the dedicated tile?? } void SSealClubberGenerateResource(ChecklistEntry [int] resource_entries) @@ -46732,7 +46778,7 @@ void IOTMMachineElfFamiliarGenerateResource(ChecklistEntry [int] resource_entrie description.listAppend("Possibly run the machine elf elsewhere first, for transmutable potions."); } //entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_fights_remaining, "free elf fight", "free elf fights"), modifiers, description)); - resource_entries.listAppend(ChecklistEntryMake(entry.image_lookup_name, entry.url, ChecklistSubentryMake(pluralise(free_fights_remaining, "free elf fight", "free elf fights"), modifiers, description)).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Machine elf free fights")); + resource_entries.listAppend(ChecklistEntryMake(entry.image_lookup_name, entry.url, ChecklistSubentryMake(pluralise(free_fights_remaining, "free elf fight", "free elf fights"), modifiers, description),0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Machine elf free fights")); } if (entry.subentries.count() > 0) { @@ -48666,7 +48712,7 @@ void IOTMWitchessGenerateResource(ChecklistEntry [int] resource_entries) image_name = "__itemsize __monster Witchess Pawn"; //subentries.listAppend(ChecklistSubentryMake(pluralise(fights_remaining, "witchess fight", "witchess fights"), "", description)); - resource_entries.listAppend(ChecklistEntryMake(image_name, "campground.php?action=witchess", ChecklistSubentryMake(pluralise(fights_remaining, "witchess fight", "witchess fights"), "", description)).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Witchess set free fights")); + resource_entries.listAppend(ChecklistEntryMake(image_name, "campground.php?action=witchess", ChecklistSubentryMake(pluralise(fights_remaining, "witchess fight", "witchess fights"), "", description),0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Witchess set free fights")); } if (!get_property_boolean("_witchessBuff") && mafiaIsPastRevision(16879) && !__misc_state["familiars temporarily blocked"] && $effect[puzzle champ].effect_is_usable()) { @@ -49695,7 +49741,7 @@ void IOTMGodLobsterGenerateResource(ChecklistEntry [int] resource_entries) if (other_equipment_to_switch_to.count() > 0) description.listAppend("Could switch equipment to " + other_equipment_to_switch_to.listJoinComponents(", ", "or") + "."); - resource_entries.listAppend(ChecklistEntryMake("__familiar god lobster", url, ChecklistSubentryMake(pluralise(free_fights_left, "free God Lobster fight", "free God Lobster fights"), "", description)).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("God lobster daily fights")); + resource_entries.listAppend(ChecklistEntryMake("__familiar god lobster", url, ChecklistSubentryMake(pluralise(free_fights_left, "free God Lobster fight", "free God Lobster fights"), "", description),0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("God lobster daily fights")); } //Songboom @@ -50093,7 +50139,7 @@ void IOTMNeverendingPartyGenerateResource(ChecklistEntry [int] resource_entries) description.listAppend("ML buff: " + listMake("Backyard", "Candle wax").listJoinComponents(__html_right_arrow_character)); } if (free_fights_left > 0) - resource_entries.listAppend(ChecklistEntryMake("__item party hat", "place.php?whichplace=town_wrong", ChecklistSubentryMake(pluralise(free_fights_left, "free party fight", "free party fights"), modifiers, description), lookupLocations("The Neverending Party")).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Neverending party free fights")); + resource_entries.listAppend(ChecklistEntryMake("__item party hat", "place.php?whichplace=town_wrong", ChecklistSubentryMake(pluralise(free_fights_left, "free party fight", "free party fights"), modifiers, description), 0, lookupLocations("The Neverending Party")).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Neverending party free fights")); } @@ -50239,7 +50285,7 @@ void IOTMVotingBootGenerateResource(ChecklistEntry [int] resource_entries) int vote_free_fights_left = 3 - get_property_int("_voteFreeFights"); if (get_property_int("_voteFreeFights") < 3) { - resource_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", "", ChecklistSubentryMake(pluralise(vote_free_fights_left, "voting monster", "voting monsters"), "", "Free fight."), 8).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Voting booth voting monster free fight")); + resource_entries.listAppend(ChecklistEntryMake("__item "I Voted!" sticker", "", ChecklistSubentryMake(pluralise(vote_free_fights_left, "voting monster", "voting monsters"), "", "Free fights with wandering activists."), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Voting booth voting monster free fight")); } } @@ -51783,7 +51829,7 @@ void IOTMBetterShroomsAndGardensGenerateResource(ChecklistEntry [int] resource_e if (piranhas.entries.count() > 0) { entry.subentries.listAppend(piranhas); // Want this part to appear both in the garden's tile, and the free fights tile, so making a new entry - resource_entries.listAppend(ChecklistEntryMake("__item Better Shrooms and Gardens catalog", "campground.php", piranhas).ChecklistEntrySetCombinationTag("daily free fight")); + resource_entries.listAppend(ChecklistEntryMake("__item Better Shrooms and Gardens catalog", "campground.php", piranhas, 0).ChecklistEntrySetCombinationTag("daily free fight")); } ChecklistSubentry shroom = getMushroomState(); @@ -53260,7 +53306,7 @@ void IOTYCursedMagnifyingGlassGenerateResource(ChecklistEntry [int] resource_ent url = invSearch("cursed magnifying glass"); description.listAppend((13 - cursedGlassCounter).pluralise("combat", "combats") + " until next void fight."); - resource_entries.listAppend(ChecklistEntryMake("__item void stone", "", ChecklistSubentryMake(pluralise(free_void_fights_left, "void glass monster", "void glass monsters"), "", description), 8).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Cursed magnifying glass free fight")); + resource_entries.listAppend(ChecklistEntryMake("__item void stone", "", ChecklistSubentryMake(pluralise(free_void_fights_left, "void glass monster", "void glass monsters"), "", description), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Cursed magnifying glass free fight")); } } //Cosmic Bowling Ball @@ -54275,8 +54321,7 @@ void IOTMOliversPlaceGenerateResource(ChecklistEntry [int] resource_entries) if (free_oliver_fights_left > 0) { description.listAppend("Consider dragging wanderers into the speakeasy."); - - resource_entries.listAppend(ChecklistEntryMake("__item Marltini", "", ChecklistSubentryMake(pluralise(free_oliver_fights_left, "Oliver's Tavern fight", "Oliver's Tavern fights"), "", description), 9).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Oliver's Tavern free fights")); + resource_entries.listAppend(ChecklistEntryMake("__item Marltini", "", ChecklistSubentryMake(pluralise(free_oliver_fights_left, "Oliver's Tavern fight", "Oliver's Tavern fights"), "", description), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Oliver's Tavern free fights")); } } string [string, string] stationDescriptions; @@ -54548,7 +54593,7 @@ void IOTMRockGardenGenerateResource(ChecklistEntry [int] resource_entries) { if (!get_property_boolean("_molehillMountainUsed") && available_amount($item[molehill mountain]) > 0) { - resource_entries.listAppend(ChecklistEntryMake("__item molehill mountain", url = "inventory.php?ftext=molehill+mountain", ChecklistSubentryMake("Molehill moleman", "", "Free scaling fight."), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Molehill free fight")); + resource_entries.listAppend(ChecklistEntryMake("__item molehill mountain", url = "inventory.php?ftext=molehill+mountain", ChecklistSubentryMake("Molehill moleman", "", "Free scaling fight. (Kinda hard.)"), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Molehill free fight")); } int availableGravels = available_amount($item[groveling gravel]); @@ -54829,7 +54874,7 @@ void IOTMClosedCircuitPayPhoneGenerateResource(ChecklistEntry [int] resource_ent if (!get_property_boolean("_shadowAffinityToday")) { string [int] affinityDescription; affinityDescription.listAppend("Call Rufus to get 11+ free Shadow Rift combats."); - resource_entries.listAppend(ChecklistEntryMake("__effect Shadow Affinity", url, ChecklistSubentryMake("Shadow Affinity free fights", "", affinityDescription), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Shadow affinity free fights")); + resource_entries.listAppend(ChecklistEntryMake("__effect Shadow Affinity", url, ChecklistSubentryMake("Shadow Affinity free fights", "", affinityDescription), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Shadow affinity free fights")); } } @@ -56074,7 +56119,7 @@ void IOTMJillv2GenerateResource(ChecklistEntry [int] resource_entries) if (splitToT[house] == "D") {freeFightsLeft +=1;} } - if (freeFightsLeft > 0) {resource_entries.listAppend(ChecklistEntryMake("__familiar jill-of-all-trades", "place.php?whichplace=town&action=town_trickortreat", ChecklistSubentryMake(pluralise(freeFightsLeft, "Trick or Treat fight", "Trick or Treat fights"), "", ""), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("trick or treat free fights"));} + if (freeFightsLeft > 0) {resource_entries.listAppend(ChecklistEntryMake("__familiar jill-of-all-trades", "place.php?whichplace=town&action=town_trickortreat", ChecklistSubentryMake(pluralise(freeFightsLeft, "Trick or Treat fight", "Trick or Treat fights"), "", "Equip an outfit and mess with some halloweenies."), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("trick or treat free fights"));} // If we have nothing to say, do not display the tile if (count(description) == 0) return; @@ -57347,7 +57392,7 @@ void IOTYCyberRealmGenerateResource(ChecklistEntry [int] resource_entries) if (get_property_int("_cyberFreeFights") < 10 && lookupSkill("OVERCLOCK(10)").have_skill()) { string url = "place.php?whichplace=CyberRealm"; description.listAppend("Hack into the system!"); - resource_entries.listAppend(ChecklistEntryMake("__skill stats+++", url, ChecklistSubentryMake(pluralise(CyberFree, "CyberRealm fight", "CyberRealm fights"), "", description), 8).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("CyberRealm free fight")); + resource_entries.listAppend(ChecklistEntryMake("__skill stats+++", url, ChecklistSubentryMake(pluralise(CyberFree, "CyberRealm fight", "CyberRealm fights"), "", description), 0).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("CyberRealm free fight")); } } From 367f3fb3f8298cd2185e5d884b7e7ff1507a8822 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 21 Aug 2025 16:23:12 +0000 Subject: [PATCH 27/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 47 ++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 95f560d3..3efc315e 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -56560,6 +56560,24 @@ void IOTMCandyCaneSwordGenerateTasks(ChecklistEntry [int] task_entries, Checklis // Wardrobe-o-Matic +void GenerateWardrobeDescription(slot currSlot, int tier) { + + // Helper function to translate the wardrobe mods to useful strings. + string entry = ""; + string [modifier] allWardrobeMods = futuristic_wardrobe(currSlot, tier); + + // Only displaying useful equipment mods. + foreach mod, value in allWardrobeMods { + if (mod == $modifier[Item Drop]) entry += value+"% +item "; + if (mod == $modifier[Monster Level]) entry += value+" +ML "; + if (mod == $modifier[Meat Drop]) entry += value+"% +meat "; + if (mod == $modifier[Familiar Weight]) entry += value+" +fam wt "; + if (mod == $modifier[Familiar Experience]) entry += value+" +fam xp "; + } + + return entry; +} + RegisterTaskGenerationFunction("IOTMWardrobeOMaticGenerateTasks"); void IOTMWardrobeOMaticGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { // Don't generate a tile if the user doesn't have the wardrobe. @@ -56573,24 +56591,41 @@ void IOTMWardrobeOMaticGenerateTasks(ChecklistEntry [int] task_entries, Checklis string [int] description; string url = "inventory.php?ftext=drobe-o-matic"; - string main_title = "Open your Wardrobe-O-Matic"; + string main_title = "Open your Wardrobe-O-Matic."; string subtitle; int priority = 11; boolean isMainTask = false; + // Grab general wardrobe properties + int currentTier = clampi(( my_level()/5 ) + 1, 0, 5); + // If they're > 15, promote to tasks. If they're >20, promote to supernag. if (my_level() >= 15) isMainTask = true; if (my_level() >= 20) priority = -11; // Level needed for your next wardrobe tier - if (my_level() < 5) subtitle = "advances @ level 5"; - if (my_level() < 10) subtitle = "advances @ level 10"; - if (my_level() < 15) subtitle = "advances @ level 15... with new mods!"; - if (my_level() < 20) subtitle = "advances @ level 20"; + if (currentTier == 1) {subtitle = "advances @ level 5";} + if (currentTier == 2) {subtitle = "advances @ level 10";} + if (currentTier == 3) {subtitle = "advances @ level 15... with new mods!";} + if (currentTier == 4) {subtitle = "advances @ level 20";} + if (currentTier == 5) {subtitle = "as good as it gets!";} + + // Grab useful mods via the helper function + string hatMods = GenerateWardrobeDescription($slot[hat], currentTier); + string shirtMods = GenerateWardrobeDescription($slot[shirt], currentTier); + string famEquipMods = GenerateWardrobeDescription($slot[familiar], currentTier); + + foreach it in [hatMods, shirtMods, famEquipMods] { + if (it == "") it += HTMLGenerateSpanFont("no useful modifiers", "gray"); + } // Add a little note if you've maxed it. description.listAppend("Acquire some questionably useful clothing!"); - if (my_level() < 20) description.listAppend(HTMLGenerateSpanFont("You're level "+my_level()+"? It can't get any better, open it!", "blue")); + if (my_level() > 19) description.listAppend(HTMLGenerateSpanFont("You're level "+my_level()+"? It can't get any better, open it!", "blue")); + + description.listAppend(HTMLGenerateSpanOfClass("Hat: ", "r_bold")+hatMods); + description.listAppend(HTMLGenerateSpanOfClass("Shirt: ", "r_bold")+shirtMods); + description.listAppend(HTMLGenerateSpanOfClass("Fam Equip: ", "r_bold")+famEquipMods); if (isMainTask) task_entries.listAppend(ChecklistEntryMake("__item wardrobe-o-matic", url, ChecklistSubentryMake(main_title, subtitle, description), -11).ChecklistEntrySetIDTag("Wardrobe-o-Matic")); if (!isMainTask) optional_task_entries.listAppend(ChecklistEntryMake("__item wardrobe-o-matic", url, ChecklistSubentryMake(main_title, subtitle, description), -11).ChecklistEntrySetIDTag("Wardrobe-o-Matic")); From 9d67f339dbaae50ff7475d06584e77531b80389c Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 21 Aug 2025 16:36:11 +0000 Subject: [PATCH 28/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 3efc315e..b149cb00 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -56560,14 +56560,13 @@ void IOTMCandyCaneSwordGenerateTasks(ChecklistEntry [int] task_entries, Checklis // Wardrobe-o-Matic -void GenerateWardrobeDescription(slot currSlot, int tier) { +string GenerateWardrobeDescription(slot currSlot, int tier) { // Helper function to translate the wardrobe mods to useful strings. string entry = ""; - string [modifier] allWardrobeMods = futuristic_wardrobe(currSlot, tier); // Only displaying useful equipment mods. - foreach mod, value in allWardrobeMods { + foreach mod, value in futuristic_wardrobe(currSlot, tier) { if (mod == $modifier[Item Drop]) entry += value+"% +item "; if (mod == $modifier[Monster Level]) entry += value+" +ML "; if (mod == $modifier[Meat Drop]) entry += value+"% +meat "; From 65a174383c085afbbc866f70afc984cfb96042d5 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 21 Aug 2025 18:27:40 +0000 Subject: [PATCH 29/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index b149cb00..6da8644c 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -56609,22 +56609,22 @@ void IOTMWardrobeOMaticGenerateTasks(ChecklistEntry [int] task_entries, Checklis if (currentTier == 4) {subtitle = "advances @ level 20";} if (currentTier == 5) {subtitle = "as good as it gets!";} - // Grab useful mods via the helper function - string hatMods = GenerateWardrobeDescription($slot[hat], currentTier); - string shirtMods = GenerateWardrobeDescription($slot[shirt], currentTier); - string famEquipMods = GenerateWardrobeDescription($slot[familiar], currentTier); + // // Grab useful mods via the helper function + // string hatMods = GenerateWardrobeDescription($slot[hat], currentTier); + // string shirtMods = GenerateWardrobeDescription($slot[shirt], currentTier); + // string famEquipMods = GenerateWardrobeDescription($slot[familiar], currentTier); - foreach it in [hatMods, shirtMods, famEquipMods] { - if (it == "") it += HTMLGenerateSpanFont("no useful modifiers", "gray"); - } + // foreach it in [hatMods, shirtMods, famEquipMods] { + // if (it == "") it += HTMLGenerateSpanFont("no useful modifiers", "gray"); + // } // Add a little note if you've maxed it. description.listAppend("Acquire some questionably useful clothing!"); if (my_level() > 19) description.listAppend(HTMLGenerateSpanFont("You're level "+my_level()+"? It can't get any better, open it!", "blue")); - description.listAppend(HTMLGenerateSpanOfClass("Hat: ", "r_bold")+hatMods); - description.listAppend(HTMLGenerateSpanOfClass("Shirt: ", "r_bold")+shirtMods); - description.listAppend(HTMLGenerateSpanOfClass("Fam Equip: ", "r_bold")+famEquipMods); + // description.listAppend(HTMLGenerateSpanOfClass("Hat: ", "r_bold")+hatMods); + // description.listAppend(HTMLGenerateSpanOfClass("Shirt: ", "r_bold")+shirtMods); + // description.listAppend(HTMLGenerateSpanOfClass("Fam Equip: ", "r_bold")+famEquipMods); if (isMainTask) task_entries.listAppend(ChecklistEntryMake("__item wardrobe-o-matic", url, ChecklistSubentryMake(main_title, subtitle, description), -11).ChecklistEntrySetIDTag("Wardrobe-o-Matic")); if (!isMainTask) optional_task_entries.listAppend(ChecklistEntryMake("__item wardrobe-o-matic", url, ChecklistSubentryMake(main_title, subtitle, description), -11).ChecklistEntrySetIDTag("Wardrobe-o-Matic")); From bb8227d8c556f66b3c9c3865012def1afe5f56f0 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 21 Aug 2025 23:39:05 +0000 Subject: [PATCH 30/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 91 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 6da8644c..65906213 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -26730,6 +26730,50 @@ void SMiscItemsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [ } } } + + // New optional task noting the user should use a workshed. Recommends IOTM worksheds in inventory. + if (!get_property_boolean("_workshedItemUsed")) { + string url = "inventory.php"; + string [int] description; + string [int] shed_options; + string main_title = "Consider changing your workshed"; + + // IOTM Workshed Descriptions + string [item] shedDesc = { + $item[Asdon Martin keyfob (on ring)]:"banishes & buffs", + $item[diabolic pizza cube]:"3-fullness pizza boons", + $item[cold medicine cabinet]:"25 freekills in exchange for your sanity", + $item[model train set]:"bridge parts, stats, and meat", + $item[TakerSpace letter of Marque]:"island access", + }; + + // FIXME: Add new worksheds as time goes on. + item [int] iotmWorksheds = $items[Asdon Martin keyfob (on ring),diabolic pizza cube,cold medicine cabinet,model train set,TakerSpace letter of Marque]; + item workshedInCampground = $item[none]; + + foreach it in iotmWorkshed { + if (__campground[it] > 0) { + workshedInCampground = it; + description.listAppend("Currently have "+HTMLGenerateSpanOfClass(it.name,"r_bold")+" in your shed, for "+shedDesc[it]); + } else if (it.available_amount() > 0) { + shed_options.listAppend(HTMLGenerateSpanOfClass(it.name,"r_bold")+", for "+shedDesc[it]); + } + } + + // return if user has no other options, no need to generate the tile + if (shed_options.length() == 0) return; + + if (workshedInCampground == $item[none]) { + description.listAppend(HTMLGenerateSpanFont("No workshed currently installed!")); + main_title = "Install a useful workshed"; + } + + description.listAppend("Potential IOTM worksheds:|*" + shed_options.listJoinComponents("|*")); + + optional_task_entries.listAppend(ChecklistEntryMake("__item tiny house", url, ChecklistSubentryMake(main_title, "", description), 2).ChecklistEntrySetIDTag("Workshed installation reminder")); + + + } } void SMiscItemsGenerateResource(ChecklistEntry [int] resource_entries) @@ -56069,6 +56113,53 @@ void IOTMBookofFactsGenerateResource(ChecklistEntry [int] resource_entries) resource_entries.listAppend(ChecklistEntryMake("__item book of facts", "", ChecklistSubentryMake(("Miscellaneous valuable BOFA drops"), "", BOFAdropsDescription), 8).ChecklistEntrySetIDTag("bofa tatters")); } +RegisterTaskGenerationFunction("IOTMJillMapGenerateTask"); +void IOTMJillMapGenerateTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { + + boolean mapAvailable = ($item[map to a candy-rich block].available_amount() > 0); + + // Don't generate a tile if the user doesn't have a map. + if (!mapAvailable) return; + + boolean usedMap = get_property_boolean("_mapToACandyRichBlockUsed"); + + // Populate a free fights count of trick-or-treat fights. + string trickOrTreatMap = get_property("_trickOrTreatBlock"); + string[int] splitToT = split_string(trickOrTreatMap, ""); + + int fightsParsed; + + foreach house in splitToT { + if (splitToT[house] == "D") {fightsParsed +=1;} + if (splitToT[house] == "d") {fightsParsed +=1;} + } + + string [int] description; + string url = "inventory.php?ftext=candy-rich"; + string main_title = "Use your Map to a Candy-Rich Block."; + + // Do not generate the tile if the user has access to trick-or-treat zones because it's Halloween + if (getHolidaysToday()["Halloween"]) return; + + // Do not generate the tile if the user has access to trick-or-treat zones and has visited it + if (fightsParsed > 0 && usedMap) return; + + // Still generate it even if they've used the map because mafia needs one T&T visit to generate the pref for the freefight tile + if (fightsParsed == 0 && usedMap) { + main_title = "Visit your Trick-or-Treat block!"; + string url = "place.php?whichplace=town&action=town_trickortreat"; + description.append("Might have a star house... 👀"); + } + + if (fightsParsed == 0 && !usedMap) { + description.append("Use your map for five free fights & some candy!"); + } + + optional_task_entries.listAppend(ChecklistEntryMake("__item plastic pumpkin bucket", url, ChecklistSubentryMake(main_title, "", description), 7).ChecklistEntrySetIDTag("map to a candy-rich block")); + + +} + // TILE SPEC: // - Remind the user to get a halloween map. // - Remind the user to get an LED candle. From c6ef4f51212c3d9d20811347b5224deed0f84354 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 21 Aug 2025 23:45:31 +0000 Subject: [PATCH 31/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 65906213..e6fbe0d0 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -26748,15 +26748,21 @@ void SMiscItemsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [ }; // FIXME: Add new worksheds as time goes on. - item [int] iotmWorksheds = $items[Asdon Martin keyfob (on ring),diabolic pizza cube,cold medicine cabinet,model train set,TakerSpace letter of Marque]; + item [int] iotmWorksheds; + iotmWorksheds.listAppend($item[Asdon Martin keyfob (on ring)]); + iotmWorksheds.listAppend($item[diabolic pizza cube]); + iotmWorksheds.listAppend($item[cold medicine cabinet]); + iotmWorksheds.listAppend($item[model train set]); + iotmWorksheds.listAppend($item[TakerSpace letter of Marque]); + item workshedInCampground = $item[none]; foreach it in iotmWorkshed { if (__campground[it] > 0) { workshedInCampground = it; - description.listAppend("Currently have "+HTMLGenerateSpanOfClass(it.name,"r_bold")+" in your shed, for "+shedDesc[it]); + description.listAppend("Currently have "+HTMLGenerateSpanOfClass(it.to_string(),"r_bold")+" in your shed, for "+shedDesc[it]); } else if (it.available_amount() > 0) { - shed_options.listAppend(HTMLGenerateSpanOfClass(it.name,"r_bold")+", for "+shedDesc[it]); + shed_options.listAppend(HTMLGenerateSpanOfClass(it.to_string(),"r_bold")+", for "+shedDesc[it]); } } @@ -26764,7 +26770,7 @@ void SMiscItemsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [ if (shed_options.length() == 0) return; if (workshedInCampground == $item[none]) { - description.listAppend(HTMLGenerateSpanFont("No workshed currently installed!")); + description.listAppend(HTMLGenerateSpanFont("No workshed currently installed!", "red")); main_title = "Install a useful workshed"; } From 79f716b75fa5cffee81d4fe0464d3b1d1a62a5fd Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 21 Aug 2025 23:48:24 +0000 Subject: [PATCH 32/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index e6fbe0d0..b9d9b055 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -26754,10 +26754,10 @@ void SMiscItemsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [ iotmWorksheds.listAppend($item[cold medicine cabinet]); iotmWorksheds.listAppend($item[model train set]); iotmWorksheds.listAppend($item[TakerSpace letter of Marque]); - + item workshedInCampground = $item[none]; - foreach it in iotmWorkshed { + foreach it in iotmWorksheds { if (__campground[it] > 0) { workshedInCampground = it; description.listAppend("Currently have "+HTMLGenerateSpanOfClass(it.to_string(),"r_bold")+" in your shed, for "+shedDesc[it]); @@ -56154,11 +56154,11 @@ void IOTMJillMapGenerateTask(ChecklistEntry [int] task_entries, ChecklistEntry [ if (fightsParsed == 0 && usedMap) { main_title = "Visit your Trick-or-Treat block!"; string url = "place.php?whichplace=town&action=town_trickortreat"; - description.append("Might have a star house... 👀"); + description.listAppend("Might have a star house... 👀"); } if (fightsParsed == 0 && !usedMap) { - description.append("Use your map for five free fights & some candy!"); + description.listAppend("Use your map for five free fights & some candy!"); } optional_task_entries.listAppend(ChecklistEntryMake("__item plastic pumpkin bucket", url, ChecklistSubentryMake(main_title, "", description), 7).ChecklistEntrySetIDTag("map to a candy-rich block")); From 0b9f4eb9ef6e955509f55b5fb6f95a2dbee8547f Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Thu, 21 Aug 2025 23:51:19 +0000 Subject: [PATCH 33/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index b9d9b055..9771018b 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -26757,7 +26757,7 @@ void SMiscItemsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [ item workshedInCampground = $item[none]; - foreach it in iotmWorksheds { + foreach key, it in iotmWorksheds { if (__campground[it] > 0) { workshedInCampground = it; description.listAppend("Currently have "+HTMLGenerateSpanOfClass(it.to_string(),"r_bold")+" in your shed, for "+shedDesc[it]); From f81fc8a7bf6221be872b7ffc1a3dbd764275a6d0 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 23 Aug 2025 18:42:40 +0000 Subject: [PATCH 34/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 92 +++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 19 deletions(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 9771018b..9e4946d8 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -20470,7 +20470,7 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name int passiveDamage = to_int(numeric_modifier($modifier[thorns]) + numeric_modifier($modifier[damage aura]) + numeric_modifier($modifier[sporadic damage aura]) + numeric_modifier($modifier[sporadic thorns])); int prayerbeadsEquipped = $item[mer-kin prayerbeads].equipped_amount(); - int prayerbeadsAvailable = clampi($item[mer-kin prayerbeads].item_amount(),0,3); + int prayerbeadsAvailable = clampi($item[mer-kin prayerbeads].item_amount()+prayerbeadsEquipped,0,3); description.listAppend("Wear mer-kin prayerbeads. "+HTMLGenerateSpanFont(prayerbeadsEquipped+"/"+prayerbeadsAvailable+" of your beads equipped.",(prayerbeadsEquipped == prayerbeadsAvailable ? "black" : "red"))+(!inSeaPath ? "" : " Consider a gutgirdle, too?")); description.listAppend("Avoid wearing any +HP gear or buffs. Ideally, you want low HP."); @@ -20509,6 +20509,7 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name } else { if ($item[Mer-kin dreadscroll].available_amount() == 0) { description.listAppend("Adventure in the library. Find the dreadscroll."); + description.listAppend(pluralise(clampi(5-$location[The Mer-Kin Library].turns_spent,0,5),"turn","turns")+" of delay remaining."); modifiers.listAppend("-combat"); } else { if ($effect[deep-tainted mind].have_effect() > 0) @@ -26769,6 +26770,9 @@ void SMiscItemsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [ // return if user has no other options, no need to generate the tile if (shed_options.length() == 0) return; + // do not generate if user has just one workshed and has installed it. + if (shed_options.length() == 1 && workshedInCampground != $item[none]) return; + if (workshedInCampground == $item[none]) { description.listAppend(HTMLGenerateSpanFont("No workshed currently installed!", "red")); main_title = "Install a useful workshed"; @@ -37654,7 +37658,7 @@ void generateDailyResources(Checklist [int] checklists) options.listAppend(generateHotDogLine("One with everything", "+50% mysticality, 50 turns.", 2)); if (my_primestat() == $stat[moxie]) options.listAppend(generateHotDogLine("Sly Dog", "+50% moxie, 50 turns.", 2)); - if (__misc_state["Chateau Mantegna available"] && !$skill[Dog Tired].have_skill()) + if (!$skill[Dog Tired].have_skill()) options.listAppend(generateHotDogLine("Sleeping dog", "5 free rests/day (stats at chateau or cinch rests)", 2)); } @@ -37665,8 +37669,10 @@ void generateDailyResources(Checklist [int] checklists) if (!get_property_boolean("_olympicSwimmingPoolItemFound") && __misc_state["VIP available"] && $item[Olympic-sized Clan crate].is_unrestricted()) resource_entries.listAppend(ChecklistEntryMake("__item inflatable duck", "", ChecklistSubentryMake("Dive for swimming pool item", "", "\"swim item\" in GCLI"), 5).ChecklistEntrySetIDTag("VIP swimming pool item")); + if (!get_property_boolean("_olympicSwimmingPool") && __misc_state["VIP available"] && $item[Olympic-sized Clan crate].is_unrestricted()) resource_entries.listAppend(ChecklistEntryMake("__item inflatable duck", "clan_viplounge.php?action=swimmingpool", ChecklistSubentryMake("Swim in VIP pool", "50 turns", listMake("+20 ML, +30% init", "Or -combat")), 5).ChecklistEntrySetIDTag("VIP swimming pool buff")); + if (!get_property_boolean("_aprilShower") && __misc_state["VIP available"] && $item[Clan shower].is_unrestricted()) { string [int] description; if (__misc_state["need to level"]) @@ -37698,7 +37704,7 @@ void generateDailyResources(Checklist [int] checklists) description.listAppend("Or +10% item, +50% init. (stylishly)"); resource_entries.listAppend(ChecklistEntryMake("__item pool cue", "clan_viplounge.php?action=pooltable", ChecklistSubentryMake(pluralise(games_available, "pool table game", "pool table games"), "10 turns", description), 5).ChecklistEntrySetIDTag("VIP table pool resource")); } - if (__quest_state["Level 6"].finished && !get_property_boolean("friarsBlessingReceived") && my_path().id != PATH_COMMUNITY_SERVICE && !__misc_state["in CS aftercore"]) { + if (__quest_state["Level 6"].finished && !get_property_boolean("friarsBlessingReceived") && my_path().id != PATH_SEA && my_path().id != PATH_COMMUNITY_SERVICE && !__misc_state["in CS aftercore"]) { string [int] description; if (!__misc_state["familiars temporarily blocked"]) { description.listAppend("+Familiar experience."); @@ -37716,15 +37722,14 @@ void generateDailyResources(Checklist [int] checklists) description.listAppend("+Familiar experience."); should_output = true; } + // trying to get this stupid thing to not show in the sea + if (my_path().id == PATH_SEA) { + should_output == false; + } if (should_output) resource_entries.listAppend(ChecklistEntryMake("Monk", "friars.php", ChecklistSubentryMake("Forest Friars buff", "20 turns", description), 10).ChecklistEntrySetIDTag("Friars blessing resource")); } - - - - - if (!get_property_boolean("_madTeaParty") && __misc_state["VIP available"] && $item[Clan looking glass].is_unrestricted() && $item["DRINK ME" potion].item_is_usable()){ string [int] description; string line = "Various effects."; @@ -57162,11 +57167,19 @@ void IOTMSeptemberCenserGenerateResource(ChecklistEntry [int] resource_entries) if ($item[Sept-Ember Censer].available_amount() == 0) return; int septEmbers = get_property_int("availableSeptEmbers"); - string [int] description; + + // Tile is unnecessary if you don't have embers remaining. + if (septEmbers == 0) return; + + string [int] description; + string url = "shop.php?whichshop=september"; + string title = "Spend your "+pluralise(septEmbers,"ember","embers"); + + // Math for the statgain from spading float coldResistance = numeric_modifier("cold resistance"); int mainstatGain = (7 * (coldResistance) ** 1.7) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); - string url = "shop.php?whichshop=september"; - string title = "Sept-Ember Censer"; + + // General amount counts int bembershootCount = $item[bembershoot].available_amount(); int mouthwashCount = $item[Mmm-brr! brand mouthwash].available_amount(); int structureCount = $item[structural ember].available_amount(); @@ -57176,29 +57189,70 @@ void IOTMSeptemberCenserGenerateResource(ChecklistEntry [int] resource_entries) if (septEmbers > 0) { - description.listAppend(`Have {HTMLGenerateSpanFont(septEmbers, "red")} Sept-Embers to make stuff with!`); + description.listAppend("Stoke the embers in your Sept-Ember Censer"); } - description.listAppend(`1 embers: +5 cold res accessory (You have {HTMLGenerateSpanFont(bembershootCount, "red")})`); - description.listAppend(`2 embers: mmm-brr! mouthwash for {HTMLGenerateSpanFont(mainstatGain, "blue")} mainstat. (You have {HTMLGenerateSpanFont(mouthwashCount, "red")})`); + description.listAppend(`|*1 embers: +5 cold res accessory (You have {HTMLGenerateSpanFont(bembershootCount, "red")})`); + description.listAppend(`|*2 embers: mmm-brr! mouthwash for {HTMLGenerateSpanFont(mainstatGain, "blue")} mainstat. (You have {HTMLGenerateSpanFont(mouthwashCount, "red")})`); if (structureUsed) { - description.listAppend((HTMLGenerateSpanFont("Already used structural ember today", "red"))); + description.listAppend((HTMLGenerateSpanFont("|*Already used structural ember today", "blue"))); } else { - description.listAppend("4 embers: +5/5 bridge parts (1/day)"); + description.listAppend("|*4 embers: +5/5 bridge parts (1/day)"); } if (hulkFought) { - description.listAppend((HTMLGenerateSpanFont("Already fought embering hulk today", "red"))); + description.listAppend((HTMLGenerateSpanFont("|*Already fought embering hulk today", "blue"))); } else { - description.listAppend("6 embers: embering hulk (1/day)"); + description.listAppend("|*6 embers: embering hulk (1/day)"); } - description.listAppend(`(You have {HTMLGenerateSpanFont(hunkCount, "red")} hunks)`); + if (!__misc_state["in run"]) description.listAppend(`(You have {HTMLGenerateSpanFont(hunkCount, "blue")} hunks)`); resource_entries.listAppend(ChecklistEntryMake("__item sept-ember censer", url, ChecklistSubentryMake(title, "", description), 8)); } +// Helper function on the KoLmafia wiki that I just decided to use for this +float roundFloat(float number, int place) { + float value = round(number*10.00**-place)*10.0**place; + return value; +} + +RegisterTaskGenerationFunction("MmmBrrMouthwashGenerateTask"); +void MmmBrrMouthwashGenerateTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { + + // Check a few things. Don't need this tile over level 11. + int mouthwashCount = $item[Mmm-brr! brand mouthwash].available_amount(); + boolean doNotNeedToLevel = my_level() > 11; + + if (mouthwashCount == 0 || doNotNeedToLevel) return; + + string [int] description; + string url = "inventory.php?ftext=brand+mouthwash"; + string main_title = "Level up with your Mmm-brr Mouthwash"; + string subtitle; + + // Math for the statgain from spading + float coldResistance = numeric_modifier("cold resistance"); + int mainstatGain = (7 * (coldResistance) ** 1.7) * (1.0 + numeric_modifier(my_primestat().to_string() + " Experience Percent") / 100.0); + float levelFromMouthwash = roundFloat(square_root(my_basestat(my_primestat()) + mainstatGain*mouthwashCount),2); + + subtitle="currently @ " + coldResistance + " cold res"; + + description.listAppend("You currently have "+pluralise(mouthwashCount, "mouthwash","mouthwashes")+" at "+mainstatGain+" mainstat apiece"); + description.listAppend("|*Will gain "+(mainstatGain*mouthwashCount)+" stats when used"); + description.listAppend("|*This will get you to level "+levelFromMouthwash); + + if (levelFromMouthwash < 12) { + description.listAppend("Consider stacking more "+HTMLGenerateSpanOfClass("cold resistance", "r_element_cold")+" for a higher level"); + } + + // FIXME: add possible recommendations for obvious sources? probably a nice hoverover thing... + + optional_task_entries.listAppend(ChecklistEntryMake("__item mmm-brr mouthwash", url, ChecklistSubentryMake(main_title, subtitle, description), 8).ChecklistEntrySetIDTag("mmm brr mouthwash math")); + + +} // Bat Wings RegisterTaskGenerationFunction("IOTMRomanBatWingsTasks"); void IOTMRomanBatWingsTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) From f426c5abc6d0fad0b4efed95d9796ecf3692442b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 23 Aug 2025 18:48:55 +0000 Subject: [PATCH 35/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index 9e4946d8..c3d057a1 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -20509,7 +20509,7 @@ void QSeaGenerateTempleEntry(ChecklistSubentry subentry, StringHandle image_name } else { if ($item[Mer-kin dreadscroll].available_amount() == 0) { description.listAppend("Adventure in the library. Find the dreadscroll."); - description.listAppend(pluralise(clampi(5-$location[The Mer-Kin Library].turns_spent,0,5),"turn","turns")+" of delay remaining."); + description.listAppend(pluralise(clampi(5-$location[Mer-Kin Library].turns_spent,0,5),"turn","turns")+" of delay remaining."); modifiers.listAppend("-combat"); } else { if ($effect[deep-tainted mind].have_effect() > 0) From cd4af89d27bb4007d60f314f86fe505251c9f00f Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Sat, 23 Aug 2025 20:51:51 +0000 Subject: [PATCH 36/36] Import changes from refs/heads/under-the-sea --- relay/relay_TourGuide.ash | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/relay/relay_TourGuide.ash b/relay/relay_TourGuide.ash index c3d057a1..3cbb045b 100644 --- a/relay/relay_TourGuide.ash +++ b/relay/relay_TourGuide.ash @@ -37712,20 +37712,25 @@ void generateDailyResources(Checklist [int] checklists) } else description.listAppend("+30% food drop."); + description.listAppend("Or +30% booze drop."); boolean should_output = true; + if (!__misc_state["in run"]) { should_output = false; } + if (!should_output && familiar_weight(my_familiar()) < 20 && my_familiar() != $familiar[none]) { description.listClear(); description.listAppend("+Familiar experience."); should_output = true; } + // trying to get this stupid thing to not show in the sea if (my_path().id == PATH_SEA) { - should_output == false; + should_output = false; } + if (should_output) resource_entries.listAppend(ChecklistEntryMake("Monk", "friars.php", ChecklistSubentryMake("Forest Friars buff", "20 turns", description), 10).ChecklistEntrySetIDTag("Friars blessing resource")); }