From 0c2525a28a447c81d3cb298cfe71d23ff80208ad Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Wed, 8 Apr 2026 10:03:38 -0400 Subject: [PATCH 01/26] bcz tiles --- .../2025/Blood Cubic Zirconia.ash | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 Source/relay/TourGuide/Items of the Month/2025/Blood Cubic Zirconia.ash diff --git a/Source/relay/TourGuide/Items of the Month/2025/Blood Cubic Zirconia.ash b/Source/relay/TourGuide/Items of the Month/2025/Blood Cubic Zirconia.ash new file mode 100644 index 00000000..060fb64b --- /dev/null +++ b/Source/relay/TourGuide/Items of the Month/2025/Blood Cubic Zirconia.ash @@ -0,0 +1,112 @@ +//blood cubic zirconia +RegisterTaskGenerationFunction("IOTMBloodCubicZirconiaGenerateTasks"); +void IOTMBloodCubicZirconiaGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // TODO: reorganize/update tile; obvious changes include: + // - maybe update the cost matrix structure, seems a lil silly + // - add refract recommendation system + // - shorten resource tile by switching the less-useful uses into a hoverover + // - small wording tweaks + // - match pheromone styling to other banishes + + + if ($item[blood cubic zirconia].available_amount() == 0) return; + string url = "inventory.php?ftext=blood+cubic+zirconia"; + string [int] description; + int bczRefracts = get_property_int("_bczRefractedGazeCasts"); + int bczBullets = get_property_int("_bczSweatBulletsCasts"); + int bczEquitys = get_property_int("_bczSweatEquityCasts"); + + int [int] bloodCast = { + 0:11, 1:23, 2:37, 3:110, 4:230, + 5:370, 6:1100, 7:2300, 8:3700, 9:11000, + 10:23000, 11:37000, 12:420000, 13:1100000, 14:2300000, + 15:3700000}; + int refractCost = bloodCast[min(bczRefracts, 15)]; + int bulletCost = bloodCast[min(bczBullets, 15)]; + int equityCost = bloodCast[min(bczEquitys, 15)]; + + if (lookupItem("blood cubic zirconia").equipped_amount() > 0) + { + if (bczRefracts < 13) { + description.listAppend("Next Refract costs " + HTMLGenerateSpanFont(refractCost + "", "red") + " mys"); + } + else if (bczRefracts >= 13) { + description.listAppend(HTMLGenerateSpanFont("Next Refract costs " + refractCost + " mys. EXPENSIVE!", "red") + ""); + } + if (lookupItem("monodent of the sea").equipped_amount() == 0) + { + description.listAppend(HTMLGenerateSpanFont("Seadent not equipped", "red")); + } + else if (lookupItem("monodent of the sea").equipped_amount() > 0) + { + description.listAppend(HTMLGenerateSpanFont("Seadent FLEESH ok!", "blue")); + } + if (bczBullets < 13) { + description.listAppend("Next Bullet costs " + HTMLGenerateSpanFont(bulletCost + "", "red") + " mox"); + } + else if (bczBullets >= 13) { + description.listAppend(HTMLGenerateSpanFont("Next Bullet costs " + bulletCost + " mox. EXPENSIVE!", "red") + ""); + } + if (bczEquitys < 13) { + description.listAppend("Next Equity costs " + HTMLGenerateSpanFont(equityCost + "", "red") + " mox"); + } + else if (bczEquitys >= 13) { + description.listAppend(HTMLGenerateSpanFont("Next Equity costs " + equityCost + " mox. EXPENSIVE!", "red") + ""); + } + task_entries.listAppend(ChecklistEntryMake("__item blood cubic zirconia", url, ChecklistSubentryMake(HTMLGenerateSpanFont("BCZ: Blood Cubic Zirconia skills", "brown"), description), -11).ChecklistEntrySetIDTag("bcz important skills")); + } +} + +RegisterResourceGenerationFunction("IOTMBloodCubicZirconiaGenerateResource"); +void IOTMBloodCubicZirconiaGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[blood cubic zirconia].available_amount() == 0) return; + string url = "inventory.php?ftext=blood+cubic+zirconia"; + string [int] description; + int bczBaths = get_property_int("_bczBloodBathCasts"); + int bczThinners = get_property_int("_bczBloodThinnerCasts"); + int bczDials = get_property_int("_bczDialitupCasts"); + int bczPheromones = get_property_int("_bczPheromoneCocktailCasts"); + int bczSpinalTapas = get_property_int("_bczSpinalTapasCasts"); + int bczGeysers = get_property_int("_bczBloodGeyserCasts"); + int bczRefracts = get_property_int("_bczRefractedGazeCasts"); + int bczBullets = get_property_int("_bczSweatBulletsCasts"); + int bczEquitys = get_property_int("_bczSweatEquityCasts"); + + int [int] bloodCast = { + 0:11, 1:23, 2:37, 3:110, 4:230, + 5:370, 6:1100, 7:2300, 8:3700, 9:11000, + 10:23000, 11:37000, 12:420000, 13:1100000, 14:2300000, + 15:3700000}; + int bathCost = bloodCast[min(bczBaths, 15)]; + int thinnerCost = bloodCast[min(bczThinners, 15)]; + int dialCost = bloodCast[min(bczDials, 15)]; + int pheromoneCost = bloodCast[min(bczPheromones, 15)]; + int tapasCost = bloodCast[min(bczSpinalTapas, 15)]; + int geyserCost = bloodCast[min(bczGeysers, 15)]; + int refractCost = bloodCast[min(bczRefracts, 15)]; + int bulletCost = bloodCast[min(bczBullets, 15)]; + int equityCost = bloodCast[min(bczEquitys, 15)]; + + description.listAppend("Next Refract costs " + HTMLGenerateSpanFont(refractCost + "", "red") + " mys"); + description.listAppend("Next Bullet costs " + HTMLGenerateSpanFont(bulletCost + "", "red") + " mox"); + description.listAppend("Next Equity costs " + HTMLGenerateSpanFont(equityCost + "", "red") + " mox"); + + description.listAppend("Next Geyser costs " + HTMLGenerateSpanFont(geyserCost + "", "brown") + " mus"); + description.listAppend("Next Bath costs " + HTMLGenerateSpanFont(bathCost + "", "brown") + " mus"); + description.listAppend("Next Dial costs " + HTMLGenerateSpanFont(dialCost + "", "brown") + " mys"); + description.listAppend("Next Thinner costs " + HTMLGenerateSpanFont(thinnerCost + "", "brown") + " mus"); + description.listAppend("Next Tapas costs " + HTMLGenerateSpanFont(tapasCost + "", "brown") + " mys"); + description.listAppend("Next Pheromone costs " + HTMLGenerateSpanFont(pheromoneCost + "", "brown") + " mox"); + + resource_entries.listAppend(ChecklistEntryMake("__item blood cubic zirconia", url, ChecklistSubentryMake(HTMLGenerateSpanFont("BCZ: Blood Cubic Zirconia skills", "brown"), description), 11).ChecklistEntrySetIDTag("bcz important skills")); + + int pheromoneBlasts = get_property_int("markYourTerritoryCharges"); + if (pheromoneBlasts > 0) + { + string [int] description2; + description2.listAppend("Instakill no items/meat"); + resource_entries.listAppend(ChecklistEntryMake("__skill mark your territory", "", ChecklistSubentryMake(pluralise(pheromoneBlasts, "BCZ pheromone", "BCZ pheromones"), "", description2), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("BCZ pheromone banish")); + } +} \ No newline at end of file From 7c9e339e14228ba1e04d448866ba0c5dc2097522 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Wed, 8 Apr 2026 10:07:25 -0400 Subject: [PATCH 02/26] seadent tiles --- .../Items of the Month/2025/Seadent.ash | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Source/relay/TourGuide/Items of the Month/2025/Seadent.ash diff --git a/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash b/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash new file mode 100644 index 00000000..bf6447f5 --- /dev/null +++ b/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash @@ -0,0 +1,46 @@ +//monodent of the sea +RegisterResourceGenerationFunction("IOTMMonodentGenerateResource"); +void IOTMMonodentGenerateResource(ChecklistEntry [int] resource_entries) +{ + // TODO: tile updates: + // - remove indigo/blue, no need for color on this + + + if ($item[monodent of the sea].available_amount() == 0) return; + + string url = "inventory.php?ftext=dent+of+the+sea"; + int monodentLightningsLeft = clampi(11 - get_property_int("_seadentLightningUsed"), 0, 11); + boolean monodentWaveUsed = get_property_boolean("_seadentWaveUsed"); + string monodentWaveZone = get_property("_seadentWaveZone"); + string [int] description; + string title = "Monodent/Seadent powers"; + + if (!monodentWaveUsed) { + description.listAppend(HTMLGenerateSpanFont("Flood a zone for +30% item/meat", "blue")); + } + else if (monodentWaveUsed) { + description.listAppend(HTMLGenerateSpanFont(monodentWaveZone + " flooded, +30 item/meat", "indigo")); + if ($effect[fishy].have_effect() < 1 && lookupItem("monodent of the sea").equipped_amount() == 0) { + description.listAppend(HTMLGenerateSpanFont("Equip Monodent for Fishy?", "red")); + } + } + if (monodentLightningsLeft > 0) { + description.listAppend("Killbanish, preserves drops. " + monodentLightningsLeft + " left."); + } + + int monodentUpgrades = get_property_int("seadentConstructKills"); + if (monodentUpgrades < 100) { + int constructsNeededForNextPerk = floor(sqrt(monodentUpgrades) + 1) ** 2 - monodentUpgrades; + description.listAppend("Current upgrades: " + monodentUpgrades + "/100"); + description.listAppend((HTMLGenerateSpanFont(constructsNeededForNextPerk, "blue")) + " constructs needed for upgrade"); + } + if (lookupItem("monodent of the sea").equipped_amount() == 0) + { + description.listAppend(HTMLGenerateSpanFont("Equip the Seadent first", "red")); + } + if (lookupItem("monodent of the sea").equipped_amount() > 0) + { + description.listAppend(HTMLGenerateSpanFont("Seadent lightning ready!", "blue")); + } + resource_entries.listAppend(ChecklistEntryMake("__item monodent of the sea", url, ChecklistSubentryMake(title, "", description))); +} \ No newline at end of file From 85f3e85339e4b82d3975254c3dfc18dfcb65cf56 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Wed, 8 Apr 2026 10:37:11 -0400 Subject: [PATCH 03/26] a few new tiles --- .../Items of the Month/2025/Shrunken Head.ash | 28 +++++ .../2025/Skeleton of Crimbo Past.ash | 54 +++++++++ .../2026/Baseball Diamond.ash | 0 .../2026/Eternity Codpiece.ash | 0 .../Items of the Month/2026/Heartstone.ash | 0 .../2026/Legendary Seal-Clubbing Club.ash | 105 ++++++++++++++++++ 6 files changed, 187 insertions(+) create mode 100644 Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash create mode 100644 Source/relay/TourGuide/Items of the Month/2025/Skeleton of Crimbo Past.ash create mode 100644 Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash create mode 100644 Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash create mode 100644 Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash create mode 100644 Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash diff --git a/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash b/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash new file mode 100644 index 00000000..3e18028d --- /dev/null +++ b/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash @@ -0,0 +1,28 @@ +//shrunken head +RegisterTaskGenerationFunction("IOTMShrunkenHeadGenerateTasks"); +void IOTMShrunkenHeadGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // TODO: improve task tile for shrunken head. items to make include: + // - if active monster, item drop chance for the active items on your head monster + // - if head equipped, what enchantment the monster you're fighting gives you + // - convert current targets to hoverover recommendations w/ filtering + + if ($item[shrunken head].available_amount() == 0) return; + string url = "inventory.php?ftext=shrunken+head"; + string [int] description; + + if (lookupItem("shrunken head").equipped_amount() > 0) + { + description.listAppend("Consider reanimating one of the following foes:"); + description.listAppend("|*dairy goat"+HTMLGenerateSpanFont("(40%)", "gray", "0.9em")); + description.listAppend("|*pygmy bowler"+HTMLGenerateSpanFont("(40%)", "gray", "0.9em")); + description.listAppend("|*baa-relief sheep"+HTMLGenerateSpanFont("(25%)", "gray", "0.9em")); + description.listAppend("|*pygmy janitor"+HTMLGenerateSpanFont("(20%)", "gray", "0.9em")); + description.listAppend("|*Spiny or Toothy skeletons"+HTMLGenerateSpanFont("(20%)", "gray", "0.9em")); + description.listAppend("|*banshee librarian"+HTMLGenerateSpanFont("(10%)", "gray", "0.9em")); + description.listAppend("|*mountain man"+HTMLGenerateSpanFont("(10%)", "gray", "0.9em")); + description.listAppend("|*One of the Smut Orcs"+HTMLGenerateSpanFont("(10%)", "gray", "0.9em")); + + task_entries.listAppend(ChecklistEntryMake("__item shrunken head", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Shrunken head equipped", "blue"), description), -11).ChecklistEntrySetIDTag("shrunken head")); + } +} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2025/Skeleton of Crimbo Past.ash b/Source/relay/TourGuide/Items of the Month/2025/Skeleton of Crimbo Past.ash new file mode 100644 index 00000000..268662f4 --- /dev/null +++ b/Source/relay/TourGuide/Items of the Month/2025/Skeleton of Crimbo Past.ash @@ -0,0 +1,54 @@ +//crimbo skeleton +RegisterTaskGenerationFunction("IOTMSkeletonOfCrimboPastGenerateTasks"); +// TODO: minor clean-up +// - add conditional URL to send to familiar if not equipped w/in resource +// - keep the % phylum table in a hoverover but if they have skellies left just point to skellies + +void IOTMSkeletonOfCrimboPastGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if (!lookupFamiliar("skeleton of crimbo past").familiar_is_usable()) return; + string url = "main.php?talktosocp=1"; + string [int] description; + + int fightKnucklebones = get_property_int("_knuckleboneDrops"); + int restKnucklebones = get_property_int("_knuckleboneRests"); + int totalKnucklebonesLeft = clampi(100 - (fightKnucklebones), 0, 100); + description.listAppend(5 - restKnucklebones + " rest knucklebones available."); + + if (totalKnucklebonesLeft == 0 && my_familiar() == lookupFamiliar("skeleton of crimbo past")) { + task_entries.listAppend(ChecklistEntryMake("__familiar skeleton of crimbo past", url, ChecklistSubentryMake(HTMLGenerateSpanFont("No more knucklebone drops", "red"), description), -11).ChecklistEntrySetIDTag("crimbo skeleton knucklebones")); + } + else if (totalKnucklebonesLeft > 0 && my_familiar() == lookupFamiliar("skeleton of crimbo past")) { + task_entries.listAppend(ChecklistEntryMake("__familiar skeleton of crimbo past", url, ChecklistSubentryMake(HTMLGenerateSpanFont(totalKnucklebonesLeft + " knucklebone drops left", "green"), description), -11).ChecklistEntrySetIDTag("crimbo skeleton knucklebones")); + } +} + +RegisterResourceGenerationFunction("IOTMSkeletonOfCrimboPastGenerateResource"); +void IOTMSkeletonOfCrimboPastGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!lookupFamiliar("skeleton of crimbo past").familiar_is_usable()) return; + string url = "main.php?talktosocp=1"; + string [int] description; + string title; + + int fightKnucklebones = get_property_int("_knuckleboneDrops"); + int restKnucklebones = get_property_int("_knuckleboneRests"); + int totalKnucklebonesLeft = clampi(100 - (fightKnucklebones), 0, 100); + + description.listAppend(5 - restKnucklebones + " rest knucklebones available."); + + if (totalKnucklebonesLeft == 0) { + title = (HTMLGenerateSpanFont("No more knucklebone drops", "red")); + } + else if (totalKnucklebonesLeft > 0) { + title = (HTMLGenerateSpanFont(totalKnucklebonesLeft + " knucklebone drops left", "green")); + description.listAppend("|*90% - skeleton"); + description.listAppend("|*70% - orc / pirate"); + description.listAppend("|*50% - dude / elf / hobo"); + description.listAppend("|*30% - beast / demon / goblin / humanoid / undead"); + description.listAppend("|*20% - fish / penguin / weird"); + description.listAppend("|*10% - construct / bug"); + description.listAppend("|*0% - constellation / elemental / hippy / horror / mer-kin / plant / slime"); + } + resource_entries.listAppend(ChecklistEntryMake("__familiar skeleton of crimbo past", url, ChecklistSubentryMake(title, description), 11)); +} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash new file mode 100644 index 00000000..e69de29b diff --git a/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash b/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash new file mode 100644 index 00000000..e69de29b diff --git a/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash b/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash new file mode 100644 index 00000000..e69de29b diff --git a/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash b/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash new file mode 100644 index 00000000..f2456be0 --- /dev/null +++ b/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash @@ -0,0 +1,105 @@ +//legendary seal-clubbing club +RegisterTaskGenerationFunction("IOTMLegendaryClubGenerateTasks"); + +// TODO: this is totally fine for now but two small notes i may address in the future: +// - overall wanderer logic is kind of janky on all tiles and maybe could stand to be managed in one central spot +// - probably decrease colors ever-so-slightly + +void IOTMLegendaryClubGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + if ($item[legendary seal-clubbing club].available_amount() == 0) return; + string url = "inventory.php?ftext=legendary+seal-clubbing+club"; + string [int] description; + string title; + + { int nextWeekTurn = get_property_int("clubEmNextWeekMonsterTurn") + 8; + int nextWeekTimer = (nextWeekTurn - total_turns_played()); + + string image_name = get_property("clubEmNextWeekMonster"); + 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 Legendary club wanderer!'; + } + + if (nextWeekTurn <= total_turns_played() && (image_name != "")) + { + description.listAppend(HTMLGenerateSpanFont("Wandering monster", "orange")); + + // 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("Legendary club: " + get_property("clubEmNextWeekMonster") + HTMLGenerateSpanFont(" now", "red"), "", description), -11)); + } + else if (nextWeekTurn -1 == total_turns_played() && (image_name != "")) + { + description.listAppend(HTMLGenerateSpanFont("Wandering monster", "orange")); + task_entries.listAppend(ChecklistEntryMake("__monster " + image_name, "", ChecklistSubentryMake("Legendary club: " + get_property("clubEmNextWeekMonster") + HTMLGenerateSpanFont(" in 1 more adv", "blue"), "", description), -11)); + } + else if (image_name != "") + { + description.listAppend(nextWeekTimer + " advs until Next Week fight."); + optional_task_entries.listAppend(ChecklistEntryMake("__monster " + image_name, "", ChecklistSubentryMake("Legendary club: " + get_property("clubEmNextWeekMonster") + "", "", description), 10)); + } + } + + if (lookupItem("legendary seal-clubbing club").equipped_amount() > 0) + { + int clubBattlefieldsLeft = clampi(5 - get_property_int("_clubEmBattlefieldUsed"), 0, 5); + int clubNextWeeksLeft = clampi(5 - get_property_int("_clubEmNextWeekUsed"), 0, 5); + int clubBackwardsLeft = clampi(5 - get_property_int("_clubEmTimeUsed"), 0, 5); + + if (clubBattlefieldsLeft == 0) { + description.listAppend(HTMLGenerateSpanFont("No Battlefield Clubs left.", "red")); + } else { + description.listAppend(clubBattlefieldsLeft + " Battlefield Clubs. Weird Saber Force."); + } + if (clubNextWeeksLeft == 0) { + description.listAppend(HTMLGenerateSpanFont("No Next Week Clubs left.", "red")); + } else { + description.listAppend(clubNextWeeksLeft + " Next Week Clubs. 7-turn Wanderer."); + } + if (clubBackwardsLeft == 0) { + description.listAppend(HTMLGenerateSpanFont("No Backwards Clubs left.", "red")); + } else { + description.listAppend(clubBackwardsLeft + " Backwards Clubs. Free kill NO ITEMS."); + } + task_entries.listAppend(ChecklistEntryMake("__item legendary seal-clubbing club", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Legendary seal-clubbing club skills", "orange"), description), -11).ChecklistEntrySetIDTag("LSSC skills")); + } +} + +RegisterResourceGenerationFunction("IOTMLegendaryClubGenerateResource"); +void IOTMLegendaryClubGenerateResource(ChecklistEntry [int] resource_entries) +{ + if ($item[legendary seal-clubbing club].available_amount() == 0) return; + string url = "inventory.php?ftext=legendary+seal-clubbing+club"; + string [int] description; + string title; + + int clubBattlefieldsLeft = clampi(5 - get_property_int("_clubEmBattlefieldUsed"), 0, 5); + int clubNextWeeksLeft = clampi(5 - get_property_int("_clubEmNextWeekUsed"), 0, 5); + int clubBackwardsLeft = clampi(5 - get_property_int("_clubEmTimeUsed"), 0, 5); + + if (clubBattlefieldsLeft == 0) { + description.listAppend(HTMLGenerateSpanFont("No Battlefield Clubs left.", "red")); + } else { + description.listAppend(clubBattlefieldsLeft + " Battlefield Clubs. Weird Saber Force."); + } + if (clubNextWeeksLeft == 0) { + description.listAppend(HTMLGenerateSpanFont("No Next Week Clubs left.", "red")); + } else { + description.listAppend(clubNextWeeksLeft + " Next Week Clubs. 7-turn Wanderer."); + } + if (clubBackwardsLeft == 0) { + description.listAppend(HTMLGenerateSpanFont("No Backwards Clubs left.", "red")); + } else { + description.listAppend(clubBackwardsLeft + " Backwards Clubs. Free kill NO ITEMS."); + } + + resource_entries.listAppend(ChecklistEntryMake("__item legendary seal-clubbing club", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Legendary seal-clubbing club skills", "orange"), description), 1).ChecklistEntrySetIDTag("LSSC skills")); +} \ No newline at end of file From a6a322a079d28b4076cb920eea030e5a8d7b992d Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Wed, 8 Apr 2026 10:58:31 -0400 Subject: [PATCH 04/26] committing some tile specs --- .../Items of the Month/2025/Shrunken Head.ash | 1 + .../2026/Baseball Diamond.ash | 24 +++++++++++++++++++ .../2026/Eternity Codpiece.ash | 9 +++++++ .../Items of the Month/2026/Heartstone.ash | 18 ++++++++++++++ .../Items of the Month import.ash | 14 +++++++++-- 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash b/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash index 3e18028d..357d5185 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash @@ -6,6 +6,7 @@ void IOTMShrunkenHeadGenerateTasks(ChecklistEntry [int] task_entries, ChecklistE // - if active monster, item drop chance for the active items on your head monster // - if head equipped, what enchantment the monster you're fighting gives you // - convert current targets to hoverover recommendations w/ filtering + // - add shrunken head combo to location bar if ($item[shrunken head].available_amount() == 0) return; string url = "inventory.php?ftext=shrunken+head"; diff --git a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash index e69de29b..4dd2bffb 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash @@ -0,0 +1,24 @@ +// baseball diamond +// TODO: make the tile lol. things that would help this tile: +// - abstract out a "here's your lineup" popout box +// - if mafia has a limit_mode(), add task entries for each pitch so you know what pitches are ready + +RegisterTaskGenerationFunction("IOTMBaseballDiamondGenerateTasks"); +void IOTMBaseballDiamondGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // tasks should include + // - recruit monsters for your baseball lineup if <9 + // - current lineup hoverover + // - maybe a supernag if you have a useful freekill + YR in the last 3 monsters? +} + +RegisterResourceGenerationFunction("IOTMBaseballDiamondGenerateResource"); +void IOTMBaseballDiamondGenerateResource(ChecklistEntry [int] resource_entries) +{ + // resource should include + // - number of ball games remaining + // - monsters to consider + // => use shrunken head for YR + // => repeated nonfree monsters for freekill + // => feesh for ML +} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash b/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash index e69de29b..25b89fbc 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash @@ -0,0 +1,9 @@ +// eternity codpiece + +RegisterResourceGenerationFunction("IOTMEternityCodpieceGenerateResource"); +void IOTMEternityCodpieceGenerateResource(ChecklistEntry [int] resource_entries) { + // TODO: include following info: + // - current enchantment + // - alternate available gems + their enchantments + // - remind user about BCZ/heartstone in codpiece, maybe note that peridot/baseball can be there too but might not be recommended? +} \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash b/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash index e69de29b..e6de8ffa 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash @@ -0,0 +1,18 @@ +// heartstone +// TODO: make the tile. also: +// - add some letter callout to location bar + +RegisterTaskGenerationFunction("IOTMHeartstoneGenerateTasks"); +void IOTMHeartstoneGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +{ + // tasks should include + // - recommended monster for next letter you should try to get (if T, A; if A, P; etc) + // - jesus this is going to suck ass i hate this lol +} + +RegisterResourceGenerationFunction("IOTMHeartstoneGenerateResource"); +void IOTMHeartstoneGenerateResource(ChecklistEntry [int] resource_entries) +{ + // resource should include + // - better VHS tape tile; banishes will be in banish zone, but VHS tapes should get its own tile outside of 2002 now +} \ 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 index b1c8cc63..ac65c043 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 @@ -159,7 +159,7 @@ 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 +// 2025 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"; @@ -168,4 +168,14 @@ 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 +import "relay/TourGuide/Items of the Month/2025/Mobius Ring.ash"; +import "relay/TourGuide/Items of the Month/2025/Seadent.ash"; +import "relay/TourGuide/Items of the Month/2025/Blood Cubic Zirconia.ash"; +import "relay/TourGuide/Items of the Month/2025/Shrunken Head.ash"; +import "relay/TourGuide/Items of the Month/2025/Skeleton of Crimbo Past.ash"; + +// 2026 +import "relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash"; +import "relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash"; +import "relay/TourGuide/Items of the Month/2026/Heartstone.ash"; +import "relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash"; \ No newline at end of file From 813de997cb79d89c46656257072dffe928984993 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Wed, 8 Apr 2026 12:23:03 -0400 Subject: [PATCH 05/26] fast forward to main + proper __iotms_usable[] usage --- .../2025/Allied Radio Backpack.ash | 2 +- .../2025/Blood Cubic Zirconia.ash | 2 +- .../Items of the Month/2025/Peridot.ash | 2 +- .../2025/Prismatic Beret.ash | 2 +- .../Items of the Month/2025/Seadent.ash | 2 +- .../Items of the Month/2025/Shrunken Head.ash | 7 +++- .../2026/Baseball Diamond.ash | 5 +++ .../2026/Eternity Codpiece.ash | 13 ++++++- .../Items of the Month/2026/Heartstone.ash | 7 ++++ .../2026/Legendary Seal-Clubbing Club.ash | 2 +- Source/relay/TourGuide/Support/IOTMs.ash | 37 ++++++++++++++++--- 11 files changed, 68 insertions(+), 13 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 383b0c1b..3a62635d 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 @@ -2,7 +2,7 @@ RegisterResourceGenerationFunction("IOTTAlliedRadioBackpackGenerateResource"); void IOTTAlliedRadioBackpackGenerateResource(ChecklistEntry [int] resource_entries) { - if ($item[allied radio backpack].available_amount() == 0) return; + if (__iotms_usable[lookupItem("allied radio backpack")]) return; string url = "inventory.php?action=requestdrop&pwd=" + my_hash(); int radioDropsLeft = clampi(3 - get_property_int("_alliedRadioDropsUsed"), 0, 3); diff --git a/Source/relay/TourGuide/Items of the Month/2025/Blood Cubic Zirconia.ash b/Source/relay/TourGuide/Items of the Month/2025/Blood Cubic Zirconia.ash index 060fb64b..9d43eab0 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Blood Cubic Zirconia.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Blood Cubic Zirconia.ash @@ -10,7 +10,7 @@ void IOTMBloodCubicZirconiaGenerateTasks(ChecklistEntry [int] task_entries, Chec // - match pheromone styling to other banishes - if ($item[blood cubic zirconia].available_amount() == 0) return; + if (__iotms_usable[lookupItem("blood cubic zirconia")]) return; string url = "inventory.php?ftext=blood+cubic+zirconia"; string [int] description; int bczRefracts = get_property_int("_bczRefractedGazeCasts"); diff --git a/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash b/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash index c2da9ce6..c9ee35e5 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash @@ -2,7 +2,7 @@ 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; + if (__iotms_usable[lookupItem("Peridot of Peril")]) return; string url = "inventory.php?ftext=peridot+of+peril"; string [int] description; 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 822f85e2..b88c271d 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 @@ -2,7 +2,7 @@ RegisterResourceGenerationFunction("IOTMPrismaticBeretGenerateResource"); void IOTMPrismaticBeretGenerateResource(ChecklistEntry [int] resource_entries) { - if ($item[prismatic beret].available_amount() == 0) return; + if (__iotms_usable[lookupItem("prismatic beret")]) return; string url = "inventory.php?ftext=prismatic+beret"; int busksLeft = clampi(5 - get_property_int("_beretBuskingUses"), 0, 5); diff --git a/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash b/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash index bf6447f5..66cd53c3 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash @@ -6,7 +6,7 @@ void IOTMMonodentGenerateResource(ChecklistEntry [int] resource_entries) // - remove indigo/blue, no need for color on this - if ($item[monodent of the sea].available_amount() == 0) return; + if (__iotms_usable[lookupItem("monodent of the sea")]) return; string url = "inventory.php?ftext=dent+of+the+sea"; int monodentLightningsLeft = clampi(11 - get_property_int("_seadentLightningUsed"), 0, 11); diff --git a/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash b/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash index 357d5185..2956aa77 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash @@ -8,10 +8,15 @@ void IOTMShrunkenHeadGenerateTasks(ChecklistEntry [int] task_entries, ChecklistE // - convert current targets to hoverover recommendations w/ filtering // - add shrunken head combo to location bar - if ($item[shrunken head].available_amount() == 0) return; + if (__iotms_usable[lookupItem("Shrunken Head")]) return; + + monster headZombie = get_property("shrunkenHeadZombieMonster").to_monster(); + int headZombieHP = get_property_int("shrunkenHeadZombieHP"); + string url = "inventory.php?ftext=shrunken+head"; string [int] description; + // Generate a task if head is equipped that shares possible good reanimations if (lookupItem("shrunken head").equipped_amount() > 0) { description.listAppend("Consider reanimating one of the following foes:"); diff --git a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash index 4dd2bffb..db52fd3e 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash @@ -10,6 +10,8 @@ void IOTMBaseballDiamondGenerateTasks(ChecklistEntry [int] task_entries, Checkli // - recruit monsters for your baseball lineup if <9 // - current lineup hoverover // - maybe a supernag if you have a useful freekill + YR in the last 3 monsters? + + if (__iotms_usable[lookupItem("Baseball Diamond")]) return; } RegisterResourceGenerationFunction("IOTMBaseballDiamondGenerateResource"); @@ -21,4 +23,7 @@ void IOTMBaseballDiamondGenerateResource(ChecklistEntry [int] resource_entries) // => use shrunken head for YR // => repeated nonfree monsters for freekill // => feesh for ML + + if (__iotms_usable[lookupItem("Baseball Diamond")]) return; + } \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash b/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash index 25b89fbc..440ae424 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash @@ -1,4 +1,4 @@ -// eternity codpiece +// the eternity codpiece RegisterResourceGenerationFunction("IOTMEternityCodpieceGenerateResource"); void IOTMEternityCodpieceGenerateResource(ChecklistEntry [int] resource_entries) { @@ -6,4 +6,15 @@ void IOTMEternityCodpieceGenerateResource(ChecklistEntry [int] resource_entries) // - current enchantment // - alternate available gems + their enchantments // - remind user about BCZ/heartstone in codpiece, maybe note that peridot/baseball can be there too but might not be recommended? + // - use Pantogram slot structure maybe + + // Detect current gems via slot + item cod1 = equipped_item($slot[codpiece1]); + item cod2 = equipped_item($slot[codpiece2]); + item cod3 = equipped_item($slot[codpiece3]); + item cod4 = equipped_item($slot[codpiece4]); + item cod5 = equipped_item($slot[codpiece5]); + + if (__iotms_usable[lookupItem("The Eternity Codpiece")]) return; + } \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash b/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash index e6de8ffa..f51c52de 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash @@ -5,6 +5,9 @@ RegisterTaskGenerationFunction("IOTMHeartstoneGenerateTasks"); void IOTMHeartstoneGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { + // the heart must go on + if (__iotms_usable[lookupItem("Heartstone")]) return; + // tasks should include // - recommended monster for next letter you should try to get (if T, A; if A, P; etc) // - jesus this is going to suck ass i hate this lol @@ -13,6 +16,10 @@ void IOTMHeartstoneGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEnt RegisterResourceGenerationFunction("IOTMHeartstoneGenerateResource"); void IOTMHeartstoneGenerateResource(ChecklistEntry [int] resource_entries) { + // the heart must go on + if (__iotms_usable[lookupItem("Heartstone")]) return; + // resource should include // - better VHS tape tile; banishes will be in banish zone, but VHS tapes should get its own tile outside of 2002 now + // - skills tile for the useful skills; include banish as resource in banishes combination tag } \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash b/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash index f2456be0..39a129b6 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash @@ -7,7 +7,7 @@ RegisterTaskGenerationFunction("IOTMLegendaryClubGenerateTasks"); void IOTMLegendaryClubGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - if ($item[legendary seal-clubbing club].available_amount() == 0) return; + if (__iotms_usable[lookupItem("legendary seal-clubbing club")]) return; string url = "inventory.php?ftext=legendary+seal-clubbing+club"; string [int] description; string title; diff --git a/Source/relay/TourGuide/Support/IOTMs.ash b/Source/relay/TourGuide/Support/IOTMs.ash index 4e8ca3a3..ba48824a 100644 --- a/Source/relay/TourGuide/Support/IOTMs.ash +++ b/Source/relay/TourGuide/Support/IOTMs.ash @@ -193,22 +193,49 @@ void initialiseIOTMsUsable() if (lookupItem("Leprecondo").available_amount() > 0) //Mar 2025 __iotms_usable[lookupItem("Leprecondo")] = true; - if (lookupItem("April Shower Thoughts shield").available_amount() > 0) //Apr 2024 + if (lookupItem("April Shower Thoughts shield").available_amount() > 0) //Apr 2025 __iotms_usable[lookupItem("April Shower Thoughts shield")] = true; - if (lookupItem("Peridot of Peril").available_amount() > 0) //May 2024 + if (lookupItem("Peridot of Peril").available_amount() > 0) //May 2025 __iotms_usable[lookupItem("Peridot of Peril")] = true; - if (lookupItem("prismatic beret").available_amount() > 0) //Jun 2024 + if (lookupItem("prismatic beret").available_amount() > 0) //Jun 2025 __iotms_usable[lookupItem("prismatic beret")] = true; // july 2025 -- yeti, familiar, unneeded - if (lookupItem("Möbius ring").available_amount() > 0) //Aug 2024 + if (lookupItem("Möbius ring").available_amount() > 0) //Aug 2025 __iotms_usable[lookupItem("Möbius ring")] = true; - if (lookupItem("allied radio backpack").available_amount() > 0) //Aug 2024 + if (lookupItem("allied radio backpack").available_amount() > 0) //Aug 2025 __iotms_usable[lookupItem("allied radio backpack")] = true; + + if (lookupItem("monodent of the sea").available_amount() > 0) //Sep 2025 + __iotms_usable[lookupItem("monodent of the sea")] = true; + + if (lookupItem("blood cubic zirconia").available_amount() > 0) //Oct 2025 + __iotms_usable[lookupItem("blood cubic zirconia")] = true; + + if (get_property_boolean("hasShrunkenHead")) //nov 2025 + __iotms_usable[lookupItem("shrunken head")] = true; + + // Dec 2025 -- crimbo skeleton, unneeded + + if (lookupItem("the eternity codpiece").available_amount() > 0) //Jan 2026 + __iotms_usable[lookupItem("the eternity codpiece")] = true; + + if (lookupItem("legendary seal-clubbing club").available_amount() > 0) //Jan 2026 + __iotms_usable[lookupItem("legendary seal-clubbing club")] = true; + + if (lookupItem("Heartstone").available_amount() > 0) //Feb 2026 + __iotms_usable[lookupItem("Heartstone")] = true; + + if (lookupItem("archaeologist's spade").available_amount() > 0) //Mar 2026 + __iotms_usable[lookupItem("archaeologist's spade")] = true; + + if (lookupItem("Baseball Diamond").available_amount() > 0) //Apr 2026 + __iotms_usable[lookupItem("Baseball Diamond")] = true; + //Can't use many things in G-Lover if (my_path().id == PATH_G_LOVER) //Path 33 From cac69bddd6ee0686816573f566a568acc2415266 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Wed, 8 Apr 2026 12:50:31 -0400 Subject: [PATCH 06/26] few new todos --- .../relay/TourGuide/Items of the Month/2025/Peridot.ash | 3 +++ .../Items of the Month/2025/Prismatic Beret.ash | 4 ++++ Source/relay/TourGuide/Sections/Location Bar Popup.ash | 9 ++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash b/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash index c9ee35e5..6a33de6e 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash @@ -2,6 +2,9 @@ RegisterTaskGenerationFunction("IOTMPeridotGenerateTasks"); void IOTMPeridotGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { + // TODO: tile additions + // - add a resource tile outlining useful monsters currently accessible w/ peridot + if (__iotms_usable[lookupItem("Peridot of Peril")]) return; string url = "inventory.php?ftext=peridot+of+peril"; string [int] description; 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 b88c271d..c0bf9178 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 @@ -2,6 +2,10 @@ RegisterResourceGenerationFunction("IOTMPrismaticBeretGenerateResource"); void IOTMPrismaticBeretGenerateResource(ChecklistEntry [int] resource_entries) { + // TODO: tile additions + // - add beret busk you will get here + // - maybe add easily accessible hats/pants too + if (__iotms_usable[lookupItem("prismatic beret")]) return; string url = "inventory.php?ftext=prismatic+beret"; diff --git a/Source/relay/TourGuide/Sections/Location Bar Popup.ash b/Source/relay/TourGuide/Sections/Location Bar Popup.ash index 33ce6898..1b41058d 100644 --- a/Source/relay/TourGuide/Sections/Location Bar Popup.ash +++ b/Source/relay/TourGuide/Sections/Location Bar Popup.ash @@ -997,7 +997,14 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca style = "font-size:1.2em;"; style += "text-align:left;padding-top:2px;"; - fl_entries.listAppend(m.capitaliseFirstLetter()); + string mHeart = heartstone_middle_letter(m); + string mHeartText = mHeart.length() ? "("+mHeart+")" : ""; + + // This is where monstername is printed. Ergo... + if (if (__iotms_usable[lookupItem("Heartstone")])) + fl_entries.listAppend(m.capitaliseFirstLetter()+mHeartText); + else + 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; From 156b839dd53947773c16199ded87a3b29948782d Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Wed, 8 Apr 2026 12:55:23 -0400 Subject: [PATCH 07/26] attempting to add shrunken head to location bar --- .../TourGuide/Items of the Month/2016/Snojo.ash | 8 ++++---- .../TourGuide/Sections/Location Bar Popup.ash | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash b/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash index 2b5e8580..515d41d0 100644 --- a/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash +++ b/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash @@ -7,7 +7,7 @@ void IOTMSnojoGenerateResource(ChecklistEntry [int] resource_entries) int punches_left = clampi(3 - get_property_int("_shatteringPunchUsed"), 0, 3); if (punches_left > 0) { - string [int] description; + description; description.listAppend("Win a fight without taking a turn."); @@ -122,12 +122,12 @@ void IOTMSnojoGenerateResource(ChecklistEntry [int] resource_entries) } //Output in order of upcoming appearance: - string [int] winnings_order; + winnings_order; foreach winning in winnings winnings_order.listAppend(winning); sort winnings_order by winnings[value]; - string [int] various_winnings_upcoming; + various_winnings_upcoming; foreach key, winning in winnings_order { int timing = winnings[winning]; @@ -146,7 +146,7 @@ void IOTMSnojoGenerateResource(ChecklistEntry [int] resource_entries) if (setting != "TOURNAMENT" && (!__misc_state["in run"] || wins >= 50)) { //Skill scrolls: - string [int] switchables; + switchables; if (get_property_int("snojoMuscleWins") < 50 && setting != "MUSCLE") switchables.listAppend("muscle"); if (get_property_int("snojoMoxieWins") < 50 && setting != "MOXIE") diff --git a/Source/relay/TourGuide/Sections/Location Bar Popup.ash b/Source/relay/TourGuide/Sections/Location Bar Popup.ash index 1b41058d..ad30af22 100644 --- a/Source/relay/TourGuide/Sections/Location Bar Popup.ash +++ b/Source/relay/TourGuide/Sections/Location Bar Popup.ash @@ -1001,7 +1001,7 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca string mHeartText = mHeart.length() ? "("+mHeart+")" : ""; // This is where monstername is printed. Ergo... - if (if (__iotms_usable[lookupItem("Heartstone")])) + if (__iotms_usable[lookupItem("Heartstone")]) fl_entries.listAppend(m.capitaliseFirstLetter()+mHeartText); else fl_entries.listAppend(m.capitaliseFirstLetter()); @@ -1037,7 +1037,17 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca fl_entry_styles[fl_entries.count() - 1] = "text-align:left;font-size:0.8em"; } } - + + // ----------- NEW BIT FROM SCOTCH ABOUT SHRUNKEN HEAD ------------- + if (true) + { + if (__iotms_usable[lookupItem("Shrunken Head")]) { + string headEffects = shrunken_Head_Zombie(m).listJoinComponents(", "); + fl_entries.listAppend(headEffects); + 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")) From 77dd0c595eadfa719d1480ba0c15463f22ebdb63 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Wed, 8 Apr 2026 12:57:26 -0400 Subject: [PATCH 08/26] fat fingered a dumb find/replace to snojo --- Source/relay/TourGuide/Items of the Month/2016/Snojo.ash | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash b/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash index 515d41d0..2b5e8580 100644 --- a/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash +++ b/Source/relay/TourGuide/Items of the Month/2016/Snojo.ash @@ -7,7 +7,7 @@ void IOTMSnojoGenerateResource(ChecklistEntry [int] resource_entries) int punches_left = clampi(3 - get_property_int("_shatteringPunchUsed"), 0, 3); if (punches_left > 0) { - description; + string [int] description; description.listAppend("Win a fight without taking a turn."); @@ -122,12 +122,12 @@ void IOTMSnojoGenerateResource(ChecklistEntry [int] resource_entries) } //Output in order of upcoming appearance: - winnings_order; + string [int] winnings_order; foreach winning in winnings winnings_order.listAppend(winning); sort winnings_order by winnings[value]; - various_winnings_upcoming; + string [int] various_winnings_upcoming; foreach key, winning in winnings_order { int timing = winnings[winning]; @@ -146,7 +146,7 @@ void IOTMSnojoGenerateResource(ChecklistEntry [int] resource_entries) if (setting != "TOURNAMENT" && (!__misc_state["in run"] || wins >= 50)) { //Skill scrolls: - switchables; + string [int] switchables; if (get_property_int("snojoMuscleWins") < 50 && setting != "MUSCLE") switchables.listAppend("muscle"); if (get_property_int("snojoMoxieWins") < 50 && setting != "MOXIE") From 101972b3004763c3290eeeff21dd8b33ac21e446 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Thu, 9 Apr 2026 16:26:26 -0400 Subject: [PATCH 09/26] location bar upgrade; bofa/zombie -> item table --- .../2026/Archaeologist's Spade.ash | 0 .../Items of the Month import.ash | 1 + .../TourGuide/Sections/Location Bar Popup.ash | 128 +++++++++++------- 3 files changed, 80 insertions(+), 49 deletions(-) create mode 100644 Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash diff --git a/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash b/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash new file mode 100644 index 00000000..e69de29b 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 95f51816..ecacba97 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 @@ -179,4 +179,5 @@ import "relay/TourGuide/Items of the Month/2025/Skeleton of Crimbo Past.ash"; import "relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash"; import "relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash"; import "relay/TourGuide/Items of the Month/2026/Heartstone.ash"; +import "relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash"; import "relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash"; \ 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 index ad30af22..d07c7a66 100644 --- a/Source/relay/TourGuide/Sections/Location Bar Popup.ash +++ b/Source/relay/TourGuide/Sections/Location Bar Popup.ash @@ -405,6 +405,76 @@ buffer generateItemInformationMethod2(location l, monster m, boolean try_for_min items_presenting.listAppend(info); } + // ----------- NEW BIT FROM SCOTCH ABOUT BOFA ------------- + if ($skill[just the facts].have_skill()) + { + // Adding BOFA items/effects to the item table this time + LBPItemInformation info; + + info.image_url = "images/itemimages/" + $item[book of facts].smallimage; + + string bofaText; + string bofaType = m.fact_type().to_lower_case(); + string fact; + boolean displayBOFA = true; + + // Setting return conditions for things that we don't need to add to the table + if (bofaType == "none") displayBOFA = false; + if (bofaType == "stats") displayBOFA = false; + if (bofaType == "hp") displayBOFA = false; + if (bofaType == "mp") displayBOFA = false; + if (bofaType == "meat") displayBOFA = false; + if (bofaType == "modifier") displayBOFA = false; + + // TODO: filter out junk results + if (bofaType == "item") { + info.item_name = HTMLGenerateSpanFont(m.item_fact().name,"r_element_spooky_desaturated"); + info.image_url = "images/itemimages/" + m.item_fact().smallimage; + } + if (bofaType == "effect") info.item_name = HTMLGenerateSpanFont(`{m.effect_fact().name} ({m.numeric_fact()})`,"r_element_spooky_desaturated"); + + info.tags.listAppend("Book of Facts ("+bofaType+")"); + + // If the user has already gotten their pocket wishes or scraps, don't append it. + if (bofaType == "item" && m.item_fact().name == "pocket wish" && get_property_int("_bookOfFactsWishes") > 2) displayBOFA = false; + if (bofaType == "item" && m.item_fact().name == "tattered scrap of paper" && get_property_int("_bookOfFactsWishes") > 10) displayBOFA = false; + + if (displayBOFA) items_presenting.listAppend(info); + + } + + // ----------- NEW BIT FROM SCOTCH ABOUT SHRUNKEN HEAD ------------- + if (lookupItem("shrunken head").equipped_amount() > 0 && get_property_int("shrunkenHeadZombieHP") == 0) + { + // Adding a table element for shrunken head effects + LBPItemInformation info; + + string headEffects = shrunken_Head_Zombie(m).listJoinComponents(", "); + string [string] abilityCompression = { + "Item Drop Bonus":"item%", + "Meat Drop Bonus":"meat%", + "Physical Attack":"atk", + "Hot Attack": HTMLGenerateSpanFont("atk","r_element_hot_desaturated"), + "Cold Attack": HTMLGenerateSpanFont("atk","r_element_cold_desaturated"), + "Sleaze Attack": HTMLGenerateSpanFont("atk","r_element_sleaze_desaturated"), + "Stench Attack": HTMLGenerateSpanFont("atk","r_element_stench_desaturated"), + "Spooky Attack": HTMLGenerateSpanFont("atk","r_element_spooky_desaturated"), + "MP Regen": "mp", + "HP Regen": "hp", + }; + + foreach key,value in abilityCompression + { + headEffects = headEffects.replace_string(key, value); + } + info.image_url = "images/itemimages/" + $item[shrunken head].smallimage; + info.item_name = "Zombie Powers"; + + info.tags.listAppend(headEffects); + items_presenting.listAppend(info); + + } + int columns = 3; if (items_presenting.count() % 2 == 0 && items_presenting.count() % 3 != 0 && items_presenting.count() < 8) @@ -997,56 +1067,11 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca style = "font-size:1.2em;"; style += "text-align:left;padding-top:2px;"; - string mHeart = heartstone_middle_letter(m); - string mHeartText = mHeart.length() ? "("+mHeart+")" : ""; - - // This is where monstername is printed. Ergo... - if (__iotms_usable[lookupItem("Heartstone")]) - fl_entries.listAppend(m.capitaliseFirstLetter()+mHeartText); - else - fl_entries.listAppend(m.capitaliseFirstLetter()); + 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"; - } - } - - // ----------- NEW BIT FROM SCOTCH ABOUT SHRUNKEN HEAD ------------- - if (true) - { - if (__iotms_usable[lookupItem("Shrunken Head")]) { - string headEffects = shrunken_Head_Zombie(m).listJoinComponents(", "); - fl_entries.listAppend(headEffects); - fl_entry_styles[fl_entries.count() - 1] = "text-align:left;font-size:0.8em"; - } - } //FIXME handle canceling NC buffer rate_buffer; @@ -1137,9 +1162,6 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca - - - int item_count_displaying = m.item_drops_array().count(); if (item_count_displaying > 0 && try_for_minimal_display && !monster_cannot_be_encountered) { @@ -1149,6 +1171,7 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca if (!monster_cannot_be_encountered) { + string [int] stats_l1; string [int] stats_l2; //if (m.base_hp > 0) @@ -1181,10 +1204,17 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca stats_l1.listAppend(average_meat.round() + " meat"); } } + + // Add heart to the phyla row + if (__iotms_usable[lookupItem("Heartstone")]) + stats_l1.listAppend("♡ = "+heartstone_middle_letter(m)); + 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); From ce679ef212b0723bc52d4dd979c65e37a5660148 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Thu, 9 Apr 2026 16:27:34 -0400 Subject: [PATCH 10/26] iotm usability display fix --- .../Items of the Month/2025/Peridot.ash | 2 +- .../2025/Prismatic Beret.ash | 2 +- .../Items of the Month/2025/Seadent.ash | 2 +- .../Items of the Month/2025/Shrunken Head.ash | 2 +- .../2026/Baseball Diamond.ash | 4 +-- .../2026/Eternity Codpiece.ash | 2 +- .../Items of the Month/2026/Heartstone.ash | 26 ++++++++++++++++--- .../2026/Legendary Seal-Clubbing Club.ash | 2 +- 8 files changed, 31 insertions(+), 11 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash b/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash index 6a33de6e..af8f9c43 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash @@ -5,7 +5,7 @@ void IOTMPeridotGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry // TODO: tile additions // - add a resource tile outlining useful monsters currently accessible w/ peridot - if (__iotms_usable[lookupItem("Peridot of Peril")]) return; + if (!__iotms_usable[lookupItem("Peridot of Peril")]) return; string url = "inventory.php?ftext=peridot+of+peril"; string [int] description; 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 c0bf9178..af628ddd 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 @@ -6,7 +6,7 @@ void IOTMPrismaticBeretGenerateResource(ChecklistEntry [int] resource_entries) // - add beret busk you will get here // - maybe add easily accessible hats/pants too - if (__iotms_usable[lookupItem("prismatic beret")]) return; + if (!__iotms_usable[lookupItem("prismatic beret")]) return; string url = "inventory.php?ftext=prismatic+beret"; int busksLeft = clampi(5 - get_property_int("_beretBuskingUses"), 0, 5); diff --git a/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash b/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash index 66cd53c3..f9b4fc50 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Seadent.ash @@ -6,7 +6,7 @@ void IOTMMonodentGenerateResource(ChecklistEntry [int] resource_entries) // - remove indigo/blue, no need for color on this - if (__iotms_usable[lookupItem("monodent of the sea")]) return; + if (!__iotms_usable[lookupItem("monodent of the sea")]) return; string url = "inventory.php?ftext=dent+of+the+sea"; int monodentLightningsLeft = clampi(11 - get_property_int("_seadentLightningUsed"), 0, 11); diff --git a/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash b/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash index 2956aa77..3cc42bbc 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash @@ -8,7 +8,7 @@ void IOTMShrunkenHeadGenerateTasks(ChecklistEntry [int] task_entries, ChecklistE // - convert current targets to hoverover recommendations w/ filtering // - add shrunken head combo to location bar - if (__iotms_usable[lookupItem("Shrunken Head")]) return; + if (!__iotms_usable[lookupItem("Shrunken Head")]) return; monster headZombie = get_property("shrunkenHeadZombieMonster").to_monster(); int headZombieHP = get_property_int("shrunkenHeadZombieHP"); diff --git a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash index db52fd3e..f39b703b 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash @@ -11,7 +11,7 @@ void IOTMBaseballDiamondGenerateTasks(ChecklistEntry [int] task_entries, Checkli // - current lineup hoverover // - maybe a supernag if you have a useful freekill + YR in the last 3 monsters? - if (__iotms_usable[lookupItem("Baseball Diamond")]) return; + if (!__iotms_usable[lookupItem("Baseball Diamond")]) return; } RegisterResourceGenerationFunction("IOTMBaseballDiamondGenerateResource"); @@ -24,6 +24,6 @@ void IOTMBaseballDiamondGenerateResource(ChecklistEntry [int] resource_entries) // => repeated nonfree monsters for freekill // => feesh for ML - if (__iotms_usable[lookupItem("Baseball Diamond")]) return; + if (!__iotms_usable[lookupItem("Baseball Diamond")]) return; } \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash b/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash index 440ae424..a4076310 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Eternity Codpiece.ash @@ -15,6 +15,6 @@ void IOTMEternityCodpieceGenerateResource(ChecklistEntry [int] resource_entries) item cod4 = equipped_item($slot[codpiece4]); item cod5 = equipped_item($slot[codpiece5]); - if (__iotms_usable[lookupItem("The Eternity Codpiece")]) return; + if (!__iotms_usable[lookupItem("The Eternity Codpiece")]) return; } \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash b/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash index f51c52de..ae9ec20d 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash @@ -6,7 +6,7 @@ RegisterTaskGenerationFunction("IOTMHeartstoneGenerateTasks"); void IOTMHeartstoneGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { // the heart must go on - if (__iotms_usable[lookupItem("Heartstone")]) return; + if (!__iotms_usable[lookupItem("Heartstone")]) return; // tasks should include // - recommended monster for next letter you should try to get (if T, A; if A, P; etc) @@ -17,9 +17,29 @@ RegisterResourceGenerationFunction("IOTMHeartstoneGenerateResource"); void IOTMHeartstoneGenerateResource(ChecklistEntry [int] resource_entries) { // the heart must go on - if (__iotms_usable[lookupItem("Heartstone")]) return; - + if (!__iotms_usable[lookupItem("Heartstone")]) return; + + // What are the heartstone's letters? + string heartLetters = get_property("heartstoneLetters"); + // resource should include // - better VHS tape tile; banishes will be in banish zone, but VHS tapes should get its own tile outside of 2002 now // - skills tile for the useful skills; include banish as resource in banishes combination tag + + // Can the user access the skills? + boolean accessBOOM = get_property_boolean("heartstoneKillUnlocked"); + boolean accessGONE = get_property_boolean("heartstoneBanishUnlocked"); + boolean accessSTUN = get_property_boolean("heartstoneStunUnlocked"); + boolean accessBUDS = get_property_boolean("heartstonePalsUnlocked"); + boolean accessBUFF = get_property_boolean("heartstoneBuffUnlocked"); + boolean accessLUCK = get_property_boolean("heartstoneLuckUnlocked"); + + // How many times has the user used the skills? + int usesBOOM = get_property_int("heartstoneKillUsed"); + int usesGONE = get_property_int("heartstoneBanishUsed"); + int usesSTUN = get_property_int("heartstoneStunUsed"); + int usesBUDS = get_property_int("heartstonePalsUsed"); + int usesBUFF = get_property_int("heartstoneBuffUsed"); + int usesLUCK = get_property_int("heartstoneLuckUsed"); + } \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash b/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash index 39a129b6..73718ed4 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Legendary Seal-Clubbing Club.ash @@ -7,7 +7,7 @@ RegisterTaskGenerationFunction("IOTMLegendaryClubGenerateTasks"); void IOTMLegendaryClubGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - if (__iotms_usable[lookupItem("legendary seal-clubbing club")]) return; + if (!__iotms_usable[lookupItem("legendary seal-clubbing club")]) return; string url = "inventory.php?ftext=legendary+seal-clubbing+club"; string [int] description; string title; From f34771d1e656a77bd6bafd9477444028848c097d Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Thu, 9 Apr 2026 16:30:32 -0400 Subject: [PATCH 11/26] spade tile spec --- .../Items of the Month/2026/Archaeologist's Spade.ash | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash b/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash index e69de29b..a154a312 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash @@ -0,0 +1,11 @@ +// archaeologist's spade + +RegisterResourceGenerationFunction("IOTMArchaeologistSpadeGenerateResource"); +void IOTMArchaeologistSpadeGenerateResource(ChecklistEntry [int] resource_entries) { + // TODO: include following info: + // - digs left + // - dig suggestions (maybe w/ "is this relevant" piece?) + + if (!__iotms_usable[lookupItem("Archaeologist's Spade")]) return; + +} \ No newline at end of file From 1076d51ab9de80ad3cfb9bbe5617d1cfbd05289f Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Thu, 9 Apr 2026 16:52:10 -0400 Subject: [PATCH 12/26] few last location bar tweaks... --- Source/relay/TourGuide/Sections/Location Bar Popup.ash | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Source/relay/TourGuide/Sections/Location Bar Popup.ash b/Source/relay/TourGuide/Sections/Location Bar Popup.ash index d07c7a66..52ac8d6e 100644 --- a/Source/relay/TourGuide/Sections/Location Bar Popup.ash +++ b/Source/relay/TourGuide/Sections/Location Bar Popup.ash @@ -415,7 +415,6 @@ buffer generateItemInformationMethod2(location l, monster m, boolean try_for_min string bofaText; string bofaType = m.fact_type().to_lower_case(); - string fact; boolean displayBOFA = true; // Setting return conditions for things that we don't need to add to the table @@ -428,10 +427,10 @@ buffer generateItemInformationMethod2(location l, monster m, boolean try_for_min // TODO: filter out junk results if (bofaType == "item") { - info.item_name = HTMLGenerateSpanFont(m.item_fact().name,"r_element_spooky_desaturated"); + info.item_name = m.item_fact().name; info.image_url = "images/itemimages/" + m.item_fact().smallimage; } - if (bofaType == "effect") info.item_name = HTMLGenerateSpanFont(`{m.effect_fact().name} ({m.numeric_fact()})`,"r_element_spooky_desaturated"); + if (bofaType == "effect") info.item_name = `{m.effect_fact().name} ({m.numeric_fact()})`; info.tags.listAppend("Book of Facts ("+bofaType+")"); @@ -469,7 +468,7 @@ buffer generateItemInformationMethod2(location l, monster m, boolean try_for_min } info.image_url = "images/itemimages/" + $item[shrunken head].smallimage; info.item_name = "Zombie Powers"; - + info.tags.listAppend(headEffects); items_presenting.listAppend(info); @@ -1206,7 +1205,7 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca } // Add heart to the phyla row - if (__iotms_usable[lookupItem("Heartstone")]) + if (__iotms_usable[lookupItem("Heartstone")] && heartstone_middle_letter(m) != "") stats_l1.listAppend("♡ = "+heartstone_middle_letter(m)); if (m.base_attack > 0) From 75effdc4982d4167297132c3dde86dc82bfe19c5 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Fri, 10 Apr 2026 11:04:49 -0400 Subject: [PATCH 13/26] heartstone tile --- .../Items of the Month/2026/Heartstone.ash | 143 +++++++++++++++++- .../TourGuide/Sections/Location Bar Popup.ash | 4 +- 2 files changed, 138 insertions(+), 9 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash b/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash index ae9ec20d..2706aeb0 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Heartstone.ash @@ -1,16 +1,105 @@ -// heartstone -// TODO: make the tile. also: -// - add some letter callout to location bar +// heartstone RegisterTaskGenerationFunction("IOTMHeartstoneGenerateTasks"); void IOTMHeartstoneGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - // the heart must go on + // This is a TAPE-helper optional task tile. if (!__iotms_usable[lookupItem("Heartstone")]) return; - // tasks should include - // - recommended monster for next letter you should try to get (if T, A; if A, P; etc) - // - jesus this is going to suck ass i hate this lol + // What are the heartstone's letters? + string heartLetters = get_property("heartstoneLetters"); + if (heartLetters.length() > 3) heartLetters = ""; + string hackerToday = ""; + + // Is the heartstone equipped? + boolean heartstoneEquipped = lookupItem("Heartstone").equipped_amount() > 0; + + // Generate boolean flags for accessibility of each monster + // --- T MONSTERS ---------------- + boolean nightstandsDone = $item[Lady Spookyraven's finest gown].available_amount() > 0 || get_property("questM21Dance") == "finished"; + string eightBitColor = get_property("8BitColor"); // and A/E + boolean fratGearDone = have_outfit_components("Frat Warrior Fatigues"); + int shenDay = get_property_int("shenInitiationDay"); + boolean hospitalDone = get_property("questL11Doctor") == "finished"; + if ($item[server room key].available_amount() > 0 && get_property_int("_cyberFreeFights") < 10 && lookupSkill("OVERCLOCK(10)").have_skill()) hackerToday = get_property("_cyberZone1Hacker"); + // --- A MONSTERS ---------------- + boolean forestDone = get_property_ascension("lastTempleUnlock") && get_property("questL02Larva") == "finished"; + boolean oilPeakDone = get_property_boolean("oilPeakLit"); + boolean tombRatsDone = "step3,finished".contains_text(get_property("questL11Pyramid")); + boolean oresDone = __quest_state["Level 8"].state_boolean["Past mine"]; + // --- P MONSTERS ---------------- + boolean warDone = __quest_state["Level 12"].finished; + // --- E MONSTERS ---------------- + boolean castleDone = __quest_state["Castle"].mafia_internal_step > 8; + boolean zeppelinDone = __quest_state["Level 11 Ron"].mafia_internal_step > 4; + boolean copperheadDone = get_property("questL11Shen") == "finished"; + boolean haveMobiusRing = $item[Möbius ring].available_amount() > 0; + // --- MISCELLANEOUS ------------- + boolean chestMimicAccessible = lookupFamiliar("Chest Mimic").familiar_is_usable(); + + // Only generate tile if TAPE is achievable in this cycle + string nextLetter; + string title; + string subtitle; + string url; + string [int] description; + string [int] monsterList; + + if (heartLetters == "") { + nextLetter = "T"; + title = "Heartstone: Spell TAPE"; + subtitle = "give me a T!"; + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("elegant animated nightstand", !nightstandsDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("tektite", eightBitColor == "green")); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("War Frat 151st Infantryman", !fratGearDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("The Frattlesnake", shenDay == 2)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("Pygmy Witch Nurse", !hospitalDone)); + if (hackerToday.contains_text("blue")) monsterList.listAppend("Bluehat Hacker (zone 1!)"); + if (hackerToday.contains_text("grey")) monsterList.listAppend("Greyhat Hacker (zone 1!)"); + } else if (heartLetters == "T") { + nextLetter = "A"; + title = "Heartstone: Spell "+HTMLGenerateSpanFont("T","r_element_stench")+"APE"; + subtitle = "give me an A!"; + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("bar", !forestDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("fleaman", eightBitColor == "black")); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("oil cartel", !oilPeakDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("tomb rat king", !tombRatsDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("mountain man", !oresDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("Black Crayon Fish", chestMimicAccessible)); + + } else if (heartLetters == "TA") { + nextLetter = "P"; + title = "Heartstone: Spell "+HTMLGenerateSpanFont("TA","r_element_stench")+"PE"; + subtitle = "give me a P!"; + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("War Hippy Baker", !warDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("War Hippy Naturopathic Homeopath", !warDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("Black Crayon Spiraling Shape", chestMimicAccessible)); + } else if (heartLetters == "TAP") { + nextLetter = "E"; + title = "Heartstone: Spell "+HTMLGenerateSpanFont("TAP","r_element_stench")+"E"; + subtitle = "give me an E!"; + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("met", eightBitColor == "blue")); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("Foodie Giant", !castleDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("red skeleton", !zeppelinDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("tomb servant", !tombRatsDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("Keese", eightBitColor == "green")); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("ninja dressed as a waiter", !copperheadDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("Mobile Armored Sweat Lodge", !warDone)); + monsterList.listAppend(HTMLGreyOutTextUnlessTrue("time cop", haveMobiusRing)); + } else { + return; + } + + // If unequipped, go to heartstone in inventory. Else, no URL. + if (!heartstoneEquipped) url = invSearch("heartstone"); + + // Generate tile description + description.listAppend("You need "+nextLetter+"; look for these monsters:|*"); + description.listAppend("
|*"+monsterList.listJoinComponents("
|*")); + if (!heartstoneEquipped) description.listAppend(HTMLGenerateSpanFont("Equip your Heartstone!","red")); + + optional_task_entries.listAppend(ChecklistEntryMake("__item heartstone", url, ChecklistSubentryMake(title, subtitle, description)).ChecklistEntrySetIDTag("Heartstone spell TAPE")); + } RegisterResourceGenerationFunction("IOTMHeartstoneGenerateResource"); @@ -18,9 +107,14 @@ void IOTMHeartstoneGenerateResource(ChecklistEntry [int] resource_entries) { // the heart must go on if (!__iotms_usable[lookupItem("Heartstone")]) return; + boolean heartstoneEquipped = lookupItem("Heartstone").equipped_amount() > 0; // What are the heartstone's letters? string heartLetters = get_property("heartstoneLetters"); + if (heartLetters.length() > 3) heartLetters = ""; + string url = heartstoneEquipped ? "" : invSearch("heartstone"); + string [int] description; + string title = heartLetters != "" ? "Heartstone ("+heartLetters.to_upper_case()+")" : "Heartstone (no letters!)"; // resource should include // - better VHS tape tile; banishes will be in banish zone, but VHS tapes should get its own tile outside of 2002 now @@ -42,4 +136,39 @@ void IOTMHeartstoneGenerateResource(ChecklistEntry [int] resource_entries) int usesBUFF = get_property_int("heartstoneBuffUsed"); int usesLUCK = get_property_int("heartstoneLuckUsed"); + // Banish combination tag for GONE. + if (accessGONE && usesGONE < 5) { + string [int] banishDesc; + banishDesc.listAppend("Turn-taking banish, 50-turn duration."); + if (!heartstoneEquipped) banishDesc.listAppend("Equip your Heartstone."); + resource_entries.listAppend(ChecklistEntryMake("__item Heartstone", "", ChecklistSubentryMake(pluralise(5-usesGONE,"cast","casts")+" of Heartstone: GONE", url, banishDesc), 0).ChecklistEntrySetCombinationTag("banish").ChecklistEntrySetIDTag("Heartstone banish")); + } + + description.listAppend("Steal Monster Hearts for useful items."); + if (usesLUCK + usesBUDS + usesGONE + usesBOOM < 16) { + description.listAppend("Also, use some cool skills:"); + if (accessBOOM && usesBOOM < 5) description.listAppend("|*"+pluralise(5-usesBOOM,"BOOM","BOOMs")+": Instakill with ~150 substats"); + if (accessGONE && usesGONE < 5) description.listAppend("|*"+pluralise(5-usesGONE,"GONE","GONEs")+": Turn-taking banish"); + if (accessBUDS && usesBUDS < 5) description.listAppend("|*"+pluralise(5-usesBUDS,"BUDS","BUDS")+": 25 turns of +5 famwt, +1 famxp"); + if (accessLUCK && usesLUCK < 1) description.listAppend("|*"+pluralise(1-usesLUCK,"LUCK","LUCK")+": A shot of "+HTMLGenerateSpanFont("Lucky!","green")); + + // Remind user to pick up new heartstone skills if needed + if (!accessBOOM || !accessGONE || !accessSTUN || !accessBUDS || !accessBUFF || !accessLUCK) { + string [int] skillsNeeded; + if (!accessBOOM) skillsNeeded.listAppend("BOOM"); + if (!accessGONE) skillsNeeded.listAppend("GONE"); + if (!accessSTUN) skillsNeeded.listAppend("STUN"); + if (!accessBUDS) skillsNeeded.listAppend("BUDS"); + if (!accessBUFF) skillsNeeded.listAppend("BUFF"); + if (!accessLUCK) skillsNeeded.listAppend("LUCK"); + + description.listAppend("Consider spelling the following words to unlock new skills: "+listJoinComponents(skillsNeeded, ", ")); + } + + if (!heartstoneEquipped) description.listAppend(HTMLGenerateSpanFont("Equip your Heartstone!","red")); + resource_entries.listAppend(ChecklistEntryMake("__item Heartstone", url, ChecklistSubentryMake(title, "", description)).ChecklistEntrySetIDTag("Heartstone skills")); + + + } + } \ 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 index 52ac8d6e..df216633 100644 --- a/Source/relay/TourGuide/Sections/Location Bar Popup.ash +++ b/Source/relay/TourGuide/Sections/Location Bar Popup.ash @@ -1204,9 +1204,9 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca } } - // Add heart to the phyla row + // Add heart to the phyla row; coloring pink for TES if (__iotms_usable[lookupItem("Heartstone")] && heartstone_middle_letter(m) != "") - stats_l1.listAppend("♡ = "+heartstone_middle_letter(m)); + stats_l1.listAppend(HTMLGenerateSpanOfClass("♡ = "+heartstone_middle_letter(m), "#ce538c")); if (m.base_attack > 0) stats_l2.listAppend(m.base_attack + " ML"); From c72015b457d124666689cda11db1d9a3477e5a41 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Fri, 10 Apr 2026 11:59:24 -0400 Subject: [PATCH 14/26] archaeologist spade tile --- .../2026/Archaeologist's Spade.ash | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash b/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash index a154a312..3a95535a 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash @@ -1,11 +1,42 @@ // archaeologist's spade - RegisterResourceGenerationFunction("IOTMArchaeologistSpadeGenerateResource"); void IOTMArchaeologistSpadeGenerateResource(ChecklistEntry [int] resource_entries) { - // TODO: include following info: - // - digs left - // - dig suggestions (maybe w/ "is this relevant" piece?) if (!__iotms_usable[lookupItem("Archaeologist's Spade")]) return; + // end if no digs left + int digsLeft = clampi(11 - get_property_int("_archSpadeDigs"), 0, 11); + if (digsLeft == 0) return; + + string title; + string url; + string [int] description; + + url = "inv_use.php?pwd=" + my_hash() + "&whichitem=12184"; + title = pluralise(digsLeft, "Archaeologist's Spade dig","Archaeologist's Spade digs"); + + // freekill combination tag for skelly digs + resource_entries.listAppend(ChecklistEntryMake("__item Archaeologist's Spade", url, ChecklistSubentryMake(title, "", "Free kill a skeleton"), 0).ChecklistEntrySetCombinationTag("free instakill").ChecklistEntrySetIDTag("Archaeologist's Spade free kill")); + + // general resource tile, near end of the line probably + description.listAppend("Excavate free skeletons!"); + + // how many useful skeletons do you have left? + int approxKitchenTurnsLeft = ceil(MAX(0, 21 - get_property_int("manorDrawerCount")) / 4) + 1; + if (approxKitchenTurnsLeft > 0) description.listAppend("|*"+pluralise(approxKitchenTurnsLeft,"skelly","skellies")+" in the Haunted Kitchen"); + + int approxNookTurnsLeft = ceil(max(0,get_property_int("cyrptNookEvilness")-13-$item[evil eye].available_amount() * 3) / 3); + if (approxNookTurnsLeft > 0) description.listAppend("|*"+pluralise(approxNookTurnsLeft,"skelly","skellies")+" in the Defiled Nook"); + + // only generate if you actually have a possibility of doing the garves snake + if (__shen_items_to_locations[get_property_item("shenQuestItem")] == $location[The VERY Unquiet Garves] || get_property_int("shenInitiationDay") == 0 || get_property("questL11Shen") != "finished") { + int approxGarvesTurnsLeft = ceil(max(0,5-$location[the unquiet garves].turns_spent)); + if (approxGarvesTurnsLeft > 0) { + description.listAppend("|*"+pluralise(approxGarvesTurnsLeft,"skelly","skellies")+" in the Unquiet Garves"); + if (get_property_int("shenInitiationDay") != 1) description.listAppend("|*(Start Shen on D2 for Garve skellies)"); + } + } + + resource_entries.listAppend(ChecklistEntryMake("__item Archaeologist's Spade", url, ChecklistSubentryMake(title, "", description)).ChecklistEntrySetIDTag("Archaeologist Spade skellies")); + } \ No newline at end of file From 108c05bf011ca8ad5f7fe01ff859869a59bcd462 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Fri, 10 Apr 2026 13:51:40 -0400 Subject: [PATCH 15/26] add ballroom to spade tile --- .../Items of the Month/2026/Archaeologist's Spade.ash | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash b/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash index 3a95535a..790be11a 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Archaeologist's Spade.ash @@ -22,9 +22,12 @@ void IOTMArchaeologistSpadeGenerateResource(ChecklistEntry [int] resource_entrie description.listAppend("Excavate free skeletons!"); // how many useful skeletons do you have left? - int approxKitchenTurnsLeft = ceil(MAX(0, 21 - get_property_int("manorDrawerCount")) / 4) + 1; + int approxKitchenTurnsLeft = ceil(MAX(0, 21 - get_property_int("manorDrawerCount")) / 4) + to_int(lookupItem("Spookyraven billiards room key").available_amount() < 1); if (approxKitchenTurnsLeft > 0) description.listAppend("|*"+pluralise(approxKitchenTurnsLeft,"skelly","skellies")+" in the Haunted Kitchen"); + int approxBallroomTurnsLeft = delayRemainingInLocation($location[the haunted ballroom]); + if (approxBallroomTurnsLeft > 0) description.listAppend("|*"+pluralise(approxBallroomTurnsLeft,"skelly","skellies")+" in the Haunted Ballroom"); + int approxNookTurnsLeft = ceil(max(0,get_property_int("cyrptNookEvilness")-13-$item[evil eye].available_amount() * 3) / 3); if (approxNookTurnsLeft > 0) description.listAppend("|*"+pluralise(approxNookTurnsLeft,"skelly","skellies")+" in the Defiled Nook"); From 42903a00db2bc08eb4c3b8f5f746f624663d4627 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Fri, 10 Apr 2026 15:18:01 -0400 Subject: [PATCH 16/26] peridot tile + location bar peridot usage indicator --- .../Items of the Month/2025/Peridot.ash | 101 ++++++++++++++++++ .../relay/TourGuide/Sections/Location Bar.ash | 13 ++- 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash b/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash index af8f9c43..31f6a5c9 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Peridot.ash @@ -4,6 +4,7 @@ void IOTMPeridotGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry { // TODO: tile additions // - add a resource tile outlining useful monsters currently accessible w/ peridot + // - not a tile addition, but add a peridot icon to location bar if you can use peridot in the zone if (!__iotms_usable[lookupItem("Peridot of Peril")]) return; string url = "inventory.php?ftext=peridot+of+peril"; @@ -20,4 +21,104 @@ void IOTMPeridotGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry 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")); } +} + +Record PeriFight +{ + location zone; + monster target; + boolean useful; + boolean canAdv; + boolean periUsed; +}; + +PeriFight makePeriFight(string z, string mon, boolean useful) { + PeriFight final; + + final.zone = lookupLocation(z); + final.target = lookupMonster(mon); + final.useful = useful; + final.canAdv = can_adventure(final.zone); + final.periUsed = false; + + foreach key,place in get_property("_perilLocations").split_string(",") { + if (place.to_int() == final.zone.to_int()) final.periUsed = true; + } + + return final; +} + +void listAppend(PeriFight [int] list, PeriFight entry) +{ + int position = list.count(); + while (list contains position) + position += 1; + list[position] = entry; +} + +string stringPeriFight (PeriFight entry) { + return entry.target.to_string()+" "+HTMLGenerateSpanFont("("+entry.zone.to_string()+")", "0.5em"); +} + +RegisterResourceGenerationFunction("IOTMPeridotGenerateResource"); +void IOTMPeridotGenerateResource(ChecklistEntry [int] resource_entries) { + if (!__iotms_usable[lookupItem("Peridot of Peril")]) return; + + boolean peridotEquipped = lookupItem("peridot of peril").equipped_amount() > 0; + string [int] perilLocations = get_property("_perilLocations").split_string(","); + + string title = "Use your Peridot of Peril"; + string subtitle = "once a day in every zone"; + string url = peridotEquipped ? "main.php" : "inventory.php?ftext=peridot+of+peril"; + string [int] description; + PeriFight [int] periFolks; + string [int] peridotPicks; + string pp = HTMLGenerateSpanFont("❖ ","green"); + + // Populate periFolks, level by level... + // Level 5 (none for 2, 3, 4...) + periFolks.listAppend(makePeriFight("Cobb's Knob Harem","Knob Goblin Harem Girl",!have_outfit_components("Knob Goblin Harem Girl Disguise"))); + // Level 7 (none for 6...) + periFolks.listAppend(makePeriFight("The Defiled Niche","dirty old lihc",!__quest_state["Cyrpt"].state_boolean["niche finished"])); + periFolks.listAppend(makePeriFight("The Defiled Nook","toothy sklelton",!__quest_state["Cyrpt"].state_boolean["nook finished"])); + // Level 9 (none for 8...) + periFolks.listAppend(makePeriFight("Twin Peak","bearpig topiary animal",get_property_int("twinPeakProgress") < 14)); + // Level 10 + periFolks.listAppend(makePeriFight("The Beanbat Chamber","beanbat",!__quest_state["Level 10"].state_boolean["beanstalk grown"] && $item[enchanted bean].available_amount() == 0)); + periFolks.listAppend(makePeriFight("The Penultimate Fantasy Airship","quiet healer",__quest_state["Castle"].mafia_internal_step < 7)); + // Level 11 (unlocks) + periFolks.listAppend(makePeriFight("The Hidden Temple","baa-relief sheep",!get_property_ascension("lastTempleUnlock"))); + // Level 11 (spookyraven) + periFolks.listAppend(makePeriFight("The Haunted Library","writing desk",!get_property_ascension("lastSecondFloorUnlock"))); + periFolks.listAppend(makePeriFight("The Haunted Bedroom","animated ornate nightstand",$location[the haunted ballroom].turnsAttemptedInLocation() == 0 && $item[Lady Spookyraven's finest gown].available_amount() == 0)); + periFolks.listAppend(makePeriFight("The Haunted Wine Cellar","possessed wine rack",__quest_state["Level 11 Manor"].mafia_internal_step < 4 && $items[wine bomb, unstable fulminate, bottle of Chateau de Vinegar].available_amount() == 0)); + periFolks.listAppend(makePeriFight("The Haunted Laundry Room","cabinet of Dr. Limpieza",__quest_state["Level 11 Manor"].mafia_internal_step < 4 && $items[wine bomb, unstable fulminate, blasting soda].available_amount() == 0)); + periFolks.listAppend(makePeriFight("The Haunted Boiler Room","monstrous boiler",__quest_state["Level 11 Manor"].mafia_internal_step < 4 && $item[wine bomb].available_amount() != 0)); + // Level 11 (hidden city) + periFolks.listAppend(makePeriFight("The Hidden Bowling Alley","pygmy bowler",get_property_int("hiddenBowlingAlleyProgress") < 6)); + periFolks.listAppend(makePeriFight("The Hidden Hospital","pygmy witch surgeon",get_property_int("hiddenHospitalProgress") < 6)); + periFolks.listAppend(makePeriFight("The Hidden Office Building","pygmy witch accountant",get_property_int("hiddenOfficeProgress") < 6)); + // Level 11 (zeppelin) + // todo: red butler + // Level 11 (palindome) + periFolks.listAppend(makePeriFight("Inside the Palindome","racecar bob",!__quest_state["Level 11 Palindome"].finished)); + // Level 12 + // todo: gremlins + + foreach key,entry in periFolks { + if (entry.useful && entry.canadv) { + string color = entry.periUsed ? "gray" : "black"; + peridotPicks.listAppend(HTMLGenerateSpanFont(stringPeriFight(entry),color, "0.9em")); + } + } + + // If no Peridot Picks, no resource tile + if (peridotPicks.count() == 0) return; + + description.listAppend("Select relevant, available monsters!"); + if (!peridotEquipped) description.listAppend(HTMLGenerateSpanFont("Equip your Peridot of Peril","red")); + description.listAppend("
|*"+pp+peridotPicks.listJoinComponents("
|*"+pp)); + + resource_entries.listAppend(ChecklistEntryMake("__item Peridot of Peril", url, ChecklistSubentryMake(title, subtitle, description), 14).ChecklistEntrySetIDTag("peridot picking helper")); + } \ No newline at end of file diff --git a/Source/relay/TourGuide/Sections/Location Bar.ash b/Source/relay/TourGuide/Sections/Location Bar.ash index f3dfd389..7eb0d74b 100644 --- a/Source/relay/TourGuide/Sections/Location Bar.ash +++ b/Source/relay/TourGuide/Sections/Location Bar.ash @@ -578,7 +578,18 @@ buffer generateLocationBar(boolean displaying_navbar) //style.append("white-space:nowrap;"); //style.append("text-overflow:clip;"); - string l_name = l.to_string(); + // If user has peridot and peridot has not been used yet, add a diamond + string pp = "❖ "; + boolean peridotUsed = false; + + foreach key,place in get_property("_perilLocations").split_string(",") { + if (l.to_int() == place.to_int()) peridotUsed = true; + } + + // Do not display if user does not have peridot + if (!__iotms_usable[lookupItem("Peridot of Peril")]) peridotUsed = true; + + string l_name = peridotUsed ? l.to_string() : pp+l.to_string(); if (__setting_location_bar_fixed_layout) l_name = HTMLGenerateDivOfClass(l_name, "r_location_bar_ellipsis_entry"); From 3fabf0e1ed2e8fb681aabab769b9e38b87c12fb4 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Sat, 11 Apr 2026 01:10:53 -0400 Subject: [PATCH 17/26] shrunken head tile revamp w/ optional task --- .../Items of the Month/2025/Shrunken Head.ash | 171 ++++++++++++++++-- .../2026/Baseball Diamond.ash | 16 ++ 2 files changed, 170 insertions(+), 17 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash b/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash index 3cc42bbc..88ee540e 100644 --- a/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash +++ b/Source/relay/TourGuide/Items of the Month/2025/Shrunken Head.ash @@ -2,11 +2,8 @@ RegisterTaskGenerationFunction("IOTMShrunkenHeadGenerateTasks"); void IOTMShrunkenHeadGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - // TODO: improve task tile for shrunken head. items to make include: - // - if active monster, item drop chance for the active items on your head monster - // - if head equipped, what enchantment the monster you're fighting gives you + // TODO: last optional thing i don't really want to do rn but could do later: // - convert current targets to hoverover recommendations w/ filtering - // - add shrunken head combo to location bar if (!__iotms_usable[lookupItem("Shrunken Head")]) return; @@ -14,21 +11,161 @@ void IOTMShrunkenHeadGenerateTasks(ChecklistEntry [int] task_entries, ChecklistE int headZombieHP = get_property_int("shrunkenHeadZombieHP"); string url = "inventory.php?ftext=shrunken+head"; - string [int] description; + string [int] supernagDescription; - // Generate a task if head is equipped that shares possible good reanimations + // Generate a supernag task if head is equipped that inspires the user to toss it at a monster if (lookupItem("shrunken head").equipped_amount() > 0) { - description.listAppend("Consider reanimating one of the following foes:"); - description.listAppend("|*dairy goat"+HTMLGenerateSpanFont("(40%)", "gray", "0.9em")); - description.listAppend("|*pygmy bowler"+HTMLGenerateSpanFont("(40%)", "gray", "0.9em")); - description.listAppend("|*baa-relief sheep"+HTMLGenerateSpanFont("(25%)", "gray", "0.9em")); - description.listAppend("|*pygmy janitor"+HTMLGenerateSpanFont("(20%)", "gray", "0.9em")); - description.listAppend("|*Spiny or Toothy skeletons"+HTMLGenerateSpanFont("(20%)", "gray", "0.9em")); - description.listAppend("|*banshee librarian"+HTMLGenerateSpanFont("(10%)", "gray", "0.9em")); - description.listAppend("|*mountain man"+HTMLGenerateSpanFont("(10%)", "gray", "0.9em")); - description.listAppend("|*One of the Smut Orcs"+HTMLGenerateSpanFont("(10%)", "gray", "0.9em")); - - task_entries.listAppend(ChecklistEntryMake("__item shrunken head", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Shrunken head equipped", "blue"), description), -11).ChecklistEntrySetIDTag("shrunken head")); + supernagDescription.listAppend("Throw it at a monster for a zombified friend!"); + task_entries.listAppend(ChecklistEntryMake("__item shrunken head", url, ChecklistSubentryMake(HTMLGenerateSpanFont("Shrunken Head equipped", "blue"), supernagDescription), -11).ChecklistEntrySetIDTag("shrunken head")); } + + string [int] description; + string [int] itemList; + string title; + string subtitle; + + // Generate an optional task for killing your zombie + if (headZombieHP > 0) { + title = "Current Zombie: "+headZombie.name; + subtitle = headZombieHP+" HP remaining"; + + string headEffects = shrunken_Head_Zombie(headZombie).listJoinComponents(", "); + string [string] abilityCompression = { + "Item Drop Bonus":"item%", + "Meat Drop Bonus":"meat%", + "Physical Attack":"atk", + "Hot Attack": HTMLGenerateSpanFont("atk","r_element_hot_desaturated"), + "Cold Attack": HTMLGenerateSpanFont("atk","r_element_cold_desaturated"), + "Sleaze Attack": HTMLGenerateSpanFont("atk","r_element_sleaze_desaturated"), + "Stench Attack": HTMLGenerateSpanFont("atk","r_element_stench_desaturated"), + "Spooky Attack": HTMLGenerateSpanFont("atk","r_element_spooky_desaturated"), + "MP Regen": "mp", + "HP Regen": "hp", + }; + + foreach key,value in abilityCompression + { + headEffects = headEffects.replace_string(key, value); + } + + // parse through item drops array, only grabbing things that might drop + foreach key, r in headZombie.item_drops_array() { + item it = r.drop; + int base_drop_rate = r.rate; + + // ignore items that are: + // n = not pickpocketable + // p = pickpocket-only + // b = bounty item + // a = accordion + if (!r.type.contains_text("n") && !r.type.contains_text("p") && !r.type.contains_text("a") && !r.type.contains_text("b")) { + string [int] item_drop_modifiers_to_display; + if (base_drop_rate > 0 && base_drop_rate < 100) { + float effective_drop_rate = base_drop_rate; + float item_modifier = item_drop_modifier(); + if (it.fullness > 0 || it.cookable) + { + item_modifier += numeric_modifier("Food Drop"); + item_drop_modifiers_to_display.listAppend("+food"); + } + if (it.inebriety > 0 || it.mixable) + { + 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")); + } + + // subtract familiar item drop modifier because of reasons + 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()); + + effective_drop_rate *= 1.0 + (item_modifier-familiar_item_drop) / 100.0; + effective_drop_rate = clampf(floor(effective_drop_rate), 0.0, 100.0); + + itemList.listAppend(to_string(effective_drop_rate)+"% "+it.name+HTMLGenerateSpanFont(" ( "+to_string(to_int(base_drop_rate))+"% "+item_drop_modifiers_to_display.listJoinComponents(", ")+")","gray","0.8em")); + } + } + } + + description.listAppend("Active Effects: "+headEffects); + + if (itemList.count() > 0) { + description.listAppend("If your zombie dies next turn, here's the % chance you get each item in the drop table!"); + description.listAppend("
|*"+itemList.listJoinComponents("
|*")); + } + + optional_task_entries.listAppend(ChecklistEntryMake("__item shrunken head", url, ChecklistSubentryMake(title, subtitle, description), 9).ChecklistEntrySetIDTag("Shrunken Head zombie")); + + } +} + + +RegisterResourceGenerationFunction("IOTMShrunkenHeadGenerateResource"); +void IOTMShrunkenHeadGenerateResource(ChecklistEntry [int] resource_entries) +{ + if (!__iotms_usable[lookupItem("Shrunken Head")]) return; + + monster headZombie = get_property("shrunkenHeadZombieMonster").to_monster(); + int headZombieHP = get_property_int("shrunkenHeadZombieHP"); + + string title = "Shrunken Head targets"; + string url = "inventory.php?ftext=shrunken+head"; + string [int] description; + + description.listAppend("Consider reanimating these monsters for their items:"); + description.listAppend("|*dairy goat"+HTMLGenerateSpanFont(" (40%)", "gray", "0.8em")); + description.listAppend("|*pygmy bowler"+HTMLGenerateSpanFont(" (40%)", "gray", "0.8em")); + description.listAppend("|*baa-relief sheep"+HTMLGenerateSpanFont(" (25%)", "gray", "0.8em")); + description.listAppend("|*pygmy janitor"+HTMLGenerateSpanFont(" (20%)", "gray", "0.8em")); + description.listAppend("|*spiny or toothy skeletons"+HTMLGenerateSpanFont(" (20%)", "gray", "0.8em")); + description.listAppend("|*banshee librarian"+HTMLGenerateSpanFont(" (10%)", "gray", "0.8em")); + description.listAppend("|*mountain man"+HTMLGenerateSpanFont(" (10%)", "gray", "0.8em")); + description.listAppend("|*Any ol' Smut Orc"+HTMLGenerateSpanFont(" (10%)", "gray", "0.8em")); + + resource_entries.listAppend(ChecklistEntryMake("__item shrunken head", url, ChecklistSubentryMake(title, "", description), 9).ChecklistEntrySetIDTag("Shrunken Head Targets")); } \ No newline at end of file diff --git a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash index f39b703b..cc5ccf14 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash @@ -3,6 +3,18 @@ // - abstract out a "here's your lineup" popout box // - if mafia has a limit_mode(), add task entries for each pitch so you know what pitches are ready +// helper function to generate monster lineup +monster [int] baseballBuddies() { + monster [int] finalTeam; + string [int] rawTeam = get_property("baseballTeam").split_string(", "); + + foreach i, playerID in rawTeam { + finalTeam[i] = to_monster(to_int(playerID)); + } + + return finalTeam; +} + RegisterTaskGenerationFunction("IOTMBaseballDiamondGenerateTasks"); void IOTMBaseballDiamondGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { @@ -12,6 +24,8 @@ void IOTMBaseballDiamondGenerateTasks(ChecklistEntry [int] task_entries, Checkli // - maybe a supernag if you have a useful freekill + YR in the last 3 monsters? if (!__iotms_usable[lookupItem("Baseball Diamond")]) return; + monster [int] myTeam = baseballBuddies(); + boolean baseballEquipped = lookupItem("Baseball Diamond").equipped_amount() > 0; } RegisterResourceGenerationFunction("IOTMBaseballDiamondGenerateResource"); @@ -25,5 +39,7 @@ void IOTMBaseballDiamondGenerateResource(ChecklistEntry [int] resource_entries) // => feesh for ML if (!__iotms_usable[lookupItem("Baseball Diamond")]) return; + monster [int] myTeam = baseballBuddies(); + boolean baseballEquipped = lookupItem("Baseball Diamond").equipped_amount() > 0; } \ No newline at end of file From 8e027600a9247fdb47bd0d4c8c3c67219ea970e9 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Mon, 13 Apr 2026 11:37:21 -0400 Subject: [PATCH 18/26] baseball tile + updated banisher support --- .../2026/Baseball Diamond.ash | 117 +++++++++++++++--- Source/relay/TourGuide/Support/Banishers.ash | 9 ++ 2 files changed, 109 insertions(+), 17 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash index cc5ccf14..ba561ca6 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash @@ -1,12 +1,8 @@ // baseball diamond -// TODO: make the tile lol. things that would help this tile: -// - abstract out a "here's your lineup" popout box -// - if mafia has a limit_mode(), add task entries for each pitch so you know what pitches are ready - // helper function to generate monster lineup monster [int] baseballBuddies() { monster [int] finalTeam; - string [int] rawTeam = get_property("baseballTeam").split_string(", "); + string [int] rawTeam = get_property("baseballTeam").split_string(","); foreach i, playerID in rawTeam { finalTeam[i] = to_monster(to_int(playerID)); @@ -15,18 +11,25 @@ monster [int] baseballBuddies() { return finalTeam; } -RegisterTaskGenerationFunction("IOTMBaseballDiamondGenerateTasks"); -void IOTMBaseballDiamondGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ - // tasks should include - // - recruit monsters for your baseball lineup if <9 - // - current lineup hoverover - // - maybe a supernag if you have a useful freekill + YR in the last 3 monsters? +// Currently, most of what I wanted to do in tasks is already handled in the resource tiles. I may someday add some task coverage but for right now this is just a TODO. +// RegisterTaskGenerationFunction("IOTMBaseballDiamondGenerateTasks"); +// void IOTMBaseballDiamondGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +// { +// // tasks should include +// // - recruit monsters for your baseball lineup if < 9 +// // - current lineup hoverover +// // - maybe a supernag if you have a useful freekill + YR in the last 3 monsters? +// // - supernag up top w/ what the pitch sequences do + - if (!__iotms_usable[lookupItem("Baseball Diamond")]) return; - monster [int] myTeam = baseballBuddies(); - boolean baseballEquipped = lookupItem("Baseball Diamond").equipped_amount() > 0; -} +// if (!__iotms_usable[lookupItem("Baseball Diamond")]) return; +// monster [int] myTeam = baseballBuddies(); +// int inningsPlayed = get_property_int("_baseballInnings"); +// monster curveballMonster = to_monster(get_property("_curveballMonster")); +// int curveballFightsLeft = get_property_int("_curveballFightsLeft"); +// boolean baseballEquipped = lookupItem("Baseball Diamond").equipped_amount() > 0; +// boolean currentlyPlayingBaseball = get_property("lastEncounter") == "Play Ball!" && get_property("baseballTeam") != ""; +// } RegisterResourceGenerationFunction("IOTMBaseballDiamondGenerateResource"); void IOTMBaseballDiamondGenerateResource(ChecklistEntry [int] resource_entries) @@ -39,7 +42,87 @@ void IOTMBaseballDiamondGenerateResource(ChecklistEntry [int] resource_entries) // => feesh for ML if (!__iotms_usable[lookupItem("Baseball Diamond")]) return; - monster [int] myTeam = baseballBuddies(); + + ChecklistSubentry [int] subentries; + boolean baseballEquipped = lookupItem("Baseball Diamond").equipped_amount() > 0; + string url = baseballEquipped ? "inventory.php?which=2" : "inventory.php?ftext=baseball+diamond"; + int inningsPlayed = get_property_int("_baseballInnings"); + monster [int] myTeam = baseballBuddies(); + int monstersNeededToPlayBall = clampi(9-myTeam.count(),0,9); + + // For this tile, we'll start with an overall "what should you use your remaining ballgames on" and transition into "what -have- you used these things on, currently" + + // Generate recommendations with your upcoming innings + if (inningsPlayed < 3) { + string title = "Play "+pluralise(clampi(3-inningsPlayed, 0, 3),"more inning","more innings")+" of Baseball"; + string [int] description; + if (myTeam.count() < 9) { + if (baseballEquipped) description.listAppend("Collect "+pluralise(monstersNeededToPlayBall,"more monster","more monsters")+" with your Baseball Diamond to play another inning."); + if (!baseballEquipped) description.listAppend("Equip your Baseball Diamond to collect "+pluralise(monstersNeededToPlayBall,"more monster","more monsters")+" to play another inning."); + } + + if (myTeam.count() == 9) { + description.listAppend("You've collected enough monsters -- you can play your next inning whenever you want. Remember, try to have your curveball and scorcher targets in the last 3-4 monster slots!"); + } + buffer tooltip; + tooltip.append(HTMLGenerateTagWrap("div","Baseball Diamond Lineup",mapMake("class","r_bold r_centre", "style", "padding-bottom:0.25em;"))); + + foreach key, mon in baseballBuddies() { + tooltip.append("#"+(key+1)+": "+mon.name+"
"); + } + + string fullTooltip = HTMLGenerateSpanOfClass(HTMLGenerateSpanOfClass(tooltip,"r_tooltip_inner_class r_tooltip_inner_class_margin")+"View your current lineup.","r_tooltip_outer_class"); + description.listAppend(fullTooltip); + + + subentries.listAppend(ChecklistSubentryMake(title, description)); + } + + // Non-Euclidian Curveball sub-tile + monster curveballMonster = to_monster(get_property("_curveballMonster")); + int curveballFightsLeft = get_property_int("_curveballFightsLeft"); + + if (curveballMonster != $monster[none]) { + subentries.listAppend(ChecklistSubentryMake(pluralise(curveballFightsLeft, "free copy of", "free copies of") + " "+HTMLGenerateSpanOfClass(curveballMonster.name,"r_element_spooky")+" remaining", "naturally free fights!","")); + } + + // Some Cheddar sub-tile; annoying because I've never abstracted tracked monsters... + // TODO: make a tracked monster olfaction management tile lol + monster cheddarMonster = $monster[none]; + string [int] trackedMonstersSplit = get_property("trackedMonsters").split_string(":"); + foreach key, str in trackedMonstersSplit { + if (str == "Baseball Diamond") cheddarMonster = to_monster(trackedMonstersSplit[key-1]); + } + if (cheddarMonster != $monster[none]) { + subentries.listAppend(ChecklistSubentryMake(HTMLGenerateSpanOfClass(curveballMonster.name,"r_element_stench")+" tracked by a Cheddarball", "an olfaction-esque tracker!","")); + } + + // Minor monster tracking sub-tile + monster screwballMonster = to_monster(get_property("_screwballMonster")); + monster beanballMonster = to_monster(get_property("_beanballMonster")); + monster skullballMonster = to_monster(get_property("_skullballMonster")); + + string [int] minorTracking; + string minorSize = "0.9em"; + + if (screwballMonster != $monster[none]) { + minorTracking.listAppend(HTMLGenerateSpanFont("+ML: "+screwballMonster+")", "r_element_sleaze_desaturated", minorSize)); + } + + if (beanballMonster != $monster[none]) { + minorTracking.listAppend(HTMLGenerateSpanFont("Passive Stench: "+beanballMonster, "r_element_stench_desaturated", minorSize)); + } + + if (skullballMonster != $monster[none]) { + minorTracking.listAppend(HTMLGenerateSpanFont("Deleveled: "+skullballMonster, "r_element_spooky_desaturated", minorSize)); + + } + + if (minorTracking.count() > 0) subentries.listAppend(ChecklistSubentryMake("Baseball Modified Monsters","",minorTracking)); + + // The iceball banish is tracked in the banish combo tile. + if (subentries.count() > 0) + resource_entries.listAppend(ChecklistEntryMake("__item baseball diamond", url, subentries, 12).ChecklistEntrySetIDTag("Baseball Diamond resource")); } \ No newline at end of file diff --git a/Source/relay/TourGuide/Support/Banishers.ash b/Source/relay/TourGuide/Support/Banishers.ash index 3d3d470e..199f8030 100644 --- a/Source/relay/TourGuide/Support/Banishers.ash +++ b/Source/relay/TourGuide/Support/Banishers.ash @@ -107,6 +107,15 @@ static __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; + __banish_source_length["stuffed yam stinkbomb"] = 15; + __banish_source_length["throwin' ember"] = 30; + __banish_source_length["anchor bomb"] = 30; + __banish_source_length["handful of split pea soup"] = 30; + __banish_source_length["punch out your foe"] = 20; + __banish_source_length["sea *dent"] = -1; + __banish_source_length["mark your territory"] = -1; + __banish_source_length["heartstone: gone"] = 50; + __banish_source_length["baseball diamond"] = -1; int [string] __banish_simultaneous_limit; __banish_simultaneous_limit["beancannon"] = 5; From e5bee870e893d8c16dcb619338ec25d369225c03 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Mon, 13 Apr 2026 12:26:43 -0400 Subject: [PATCH 19/26] unrestricted clutter reduction --- .../Items of the Month/2016/Intergnat.ash | 80 ++++++++++--------- .../Items of the Month/2018/BoomBox.ash | 4 +- .../Items of the Month/2020/Box O Ghosts.ash | 9 ++- .../2021/Daylight Shavings Helmet.ash | 4 +- .../2026/Baseball Diamond.ash | 37 ++++----- Source/relay/TourGuide/Quests/Airport.ash | 6 +- 6 files changed, 78 insertions(+), 62 deletions(-) diff --git a/Source/relay/TourGuide/Items of the Month/2016/Intergnat.ash b/Source/relay/TourGuide/Items of the Month/2016/Intergnat.ash index 7b30d505..b14884b3 100644 --- a/Source/relay/TourGuide/Items of the Month/2016/Intergnat.ash +++ b/Source/relay/TourGuide/Items of the Month/2016/Intergnat.ash @@ -1,43 +1,45 @@ -RegisterTaskGenerationFunction("IOTMIntergnatGenerateTasks"); -void IOTMIntergnatGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) -{ +// Commenting out demon-finding intergnat task. +// TODO: refactor into new task that only generates if you happen to have the items needed for demon summoning in-run +// 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")); - } - } -} +// 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) diff --git a/Source/relay/TourGuide/Items of the Month/2018/BoomBox.ash b/Source/relay/TourGuide/Items of the Month/2018/BoomBox.ash index b8759259..04cd5258 100644 --- a/Source/relay/TourGuide/Items of the Month/2018/BoomBox.ash +++ b/Source/relay/TourGuide/Items of the Month/2018/BoomBox.ash @@ -3,7 +3,9 @@ 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; - + + // leaving this for aftercore because TES likes this tile, but it is not needed in-run + if (__misc_state["in run"]) 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 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 index c3540cf8..2671b085 100644 --- 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 @@ -7,7 +7,14 @@ void IOTMCommerceGhostGenerateTasks(ChecklistEntry [int] task_entries, Checklist 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) + // reduce clutter by not showing this tile if user does not need it + if (!$familiar[Ghost of Crimbo Commerce].familiar_is_usable()) return; + if (my_level() > 12) return; + if (__iotms_usable[lookupItem("Neverending Party invitation envelope")]) return; + if ($item[Sept-Ember Censer].available_amount() > 0) return; + + // only show if in-run + if (__misc_state["in run"] && !in_grey_you) { // Title string url = "familiar.php"; 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 index 206bbd82..168a550e 100644 --- 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 @@ -78,7 +78,9 @@ void IOTMDaylightShavingsHelmetGenerateTasks(ChecklistEntry [int] task_entries, nextBeardBuffDescription = nextBeardBuff[nextBeardBuffName]; nextBeardBuffEffect = boldIfValuable(nextBeardBuffName) + ", " + to_buffer(nextBeardBuffDescription); } - description.listAppend("Next shavings effect:
" + nextBeardBuffEffect); + + // Commenting out because you can always use the tooltip. + // description.listAppend("Next shavings effect:
" + nextBeardBuffEffect); string [int][int] tooltip_table; for i from lastBeardIndex() + 1 to lastBeardIndex() + 11 { diff --git a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash index ba561ca6..d1662d31 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash @@ -58,8 +58,8 @@ void IOTMBaseballDiamondGenerateResource(ChecklistEntry [int] resource_entries) string title = "Play "+pluralise(clampi(3-inningsPlayed, 0, 3),"more inning","more innings")+" of Baseball"; string [int] description; if (myTeam.count() < 9) { - if (baseballEquipped) description.listAppend("Collect "+pluralise(monstersNeededToPlayBall,"more monster","more monsters")+" with your Baseball Diamond to play another inning."); - if (!baseballEquipped) description.listAppend("Equip your Baseball Diamond to collect "+pluralise(monstersNeededToPlayBall,"more monster","more monsters")+" to play another inning."); + if (baseballEquipped) description.listAppend("Find "+pluralise(monstersNeededToPlayBall,"more monster","more monsters")+" to play ball!"); + if (!baseballEquipped) description.listAppend(HTMLGenerateSpanOfClass("Equip your Baseball Diamond","r_element_hot")+" to find "+pluralise(monstersNeededToPlayBall,"more monster","more monsters")+" to play ball!"); } if (myTeam.count() == 9) { @@ -84,7 +84,7 @@ void IOTMBaseballDiamondGenerateResource(ChecklistEntry [int] resource_entries) int curveballFightsLeft = get_property_int("_curveballFightsLeft"); if (curveballMonster != $monster[none]) { - subentries.listAppend(ChecklistSubentryMake(pluralise(curveballFightsLeft, "free copy of", "free copies of") + " "+HTMLGenerateSpanOfClass(curveballMonster.name,"r_element_spooky")+" remaining", "naturally free fights!","")); + subentries.listAppend(ChecklistSubentryMake(pluralise(curveballFightsLeft, "free copy of", "free copies of") + " "+HTMLGenerateSpanOfClass(curveballMonster.name, "r_element_epic")+" remaining", "naturally free fights!","")); } // Some Cheddar sub-tile; annoying because I've never abstracted tracked monsters... @@ -99,27 +99,28 @@ void IOTMBaseballDiamondGenerateResource(ChecklistEntry [int] resource_entries) } // Minor monster tracking sub-tile - monster screwballMonster = to_monster(get_property("_screwballMonster")); - monster beanballMonster = to_monster(get_property("_beanballMonster")); - monster skullballMonster = to_monster(get_property("_skullballMonster")); + // Currently commented out because we don't really need it + // monster screwballMonster = to_monster(get_property("_screwballMonster")); + // monster beanballMonster = to_monster(get_property("_beanballMonster")); + // monster skullballMonster = to_monster(get_property("_skullballMonster")); - string [int] minorTracking; - string minorSize = "0.9em"; + // string [int] minorTracking; + // string minorSize = "0.9em"; - if (screwballMonster != $monster[none]) { - minorTracking.listAppend(HTMLGenerateSpanFont("+ML: "+screwballMonster+")", "r_element_sleaze_desaturated", minorSize)); - } + // if (screwballMonster != $monster[none]) { + // minorTracking.listAppend(HTMLGenerateSpanFont("+ML: "+screwballMonster+")", "r_element_sleaze_desaturated", minorSize)); + // } - if (beanballMonster != $monster[none]) { - minorTracking.listAppend(HTMLGenerateSpanFont("Passive Stench: "+beanballMonster, "r_element_stench_desaturated", minorSize)); - } + // if (beanballMonster != $monster[none]) { + // minorTracking.listAppend(HTMLGenerateSpanFont("Passive Stench: "+beanballMonster, "r_element_stench_desaturated", minorSize)); + // } - if (skullballMonster != $monster[none]) { - minorTracking.listAppend(HTMLGenerateSpanFont("Deleveled: "+skullballMonster, "r_element_spooky_desaturated", minorSize)); + // if (skullballMonster != $monster[none]) { + // minorTracking.listAppend(HTMLGenerateSpanFont("Deleveled: "+skullballMonster, "r_element_spooky_desaturated", minorSize)); - } + // } - if (minorTracking.count() > 0) subentries.listAppend(ChecklistSubentryMake("Baseball Modified Monsters","",minorTracking)); + // if (minorTracking.count() > 0) subentries.listAppend(ChecklistSubentryMake("Baseball Modified Monsters","",minorTracking)); // The iceball banish is tracked in the banish combo tile. diff --git a/Source/relay/TourGuide/Quests/Airport.ash b/Source/relay/TourGuide/Quests/Airport.ash index 2587cd45..1d498f3d 100644 --- a/Source/relay/TourGuide/Quests/Airport.ash +++ b/Source/relay/TourGuide/Quests/Airport.ash @@ -1029,8 +1029,10 @@ void QStenchAirportGiveMeFuelGenerateTasks(ChecklistEntry [int] task_entries) void QStenchAirportGarbageGenerateTasks(ChecklistEntry [int] task_entries) { - if (get_property_boolean("_dinseyGarbageDisposed")) - return; + // Do not need this task in-run + if (get_property_boolean("_dinseyGarbageDisposed")) return; + if (__misc_state["in run"]) return; + ChecklistSubentry subentry; subentry.header = "Turn in garbage"; subentry.entries.listAppend("Maintenance Tunnels Access" + __html_right_arrow_character + "Waste Disposal."); From 8fd6ef21539f1dff2f105badc576ad6977ca0bd5 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Mon, 13 Apr 2026 13:53:43 -0400 Subject: [PATCH 20/26] resolving multiple git issues --- .../2011/Plastic Vampire Fangs.ash | 12 +++++------- .../Items of the Month/2017/Tunnel of Love.ash | 5 +++++ Source/relay/TourGuide/Sets/Daily Dungeon.ash | 8 +++++++- Source/relay/TourGuide/Sets/Pulverise.ash | 1 + 4 files changed, 18 insertions(+), 8 deletions(-) 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 index b377da83..0616565b 100644 --- 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 @@ -20,18 +20,16 @@ void IOTMPlasticVampireFangsGenerateResource(ChecklistEntry [int] resource_entri 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 { + else if ($item[plastic vampire fangs].available_amount() > 0) { url = "place.php?whichplace=town"; if ($item[plastic vampire fangs].equipped_amount() == 0) { url = "inventory.php?ftext=plastic+vampire+fangs"; } } + else ($item[Interview With You (a Vampire)].available_amount() > 0) { + fang_source = $item[Interview With You (a Vampire)]; + url = "inventory.php?ftext=interview+with+you"; + } // Show the Isabella interview option if it is valid for the user. 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 index 850c45fe..62eb0545 100644 --- 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 @@ -49,6 +49,11 @@ void IOTMTunnelOfLoveGenerateTasks(ChecklistEntry [int] task_entries, ChecklistE RegisterResourceGenerationFunction("IOTMTunnelOfLoveGenerateResource"); void IOTMTunnelOfLoveGenerateResource(ChecklistEntry [int] resource_entries) { + + if (!get_property_boolean("_loveTunnelUsed")) { + resource_entries.listAppend(ChecklistEntryMake("__item pink candy heart", "place.php?whichplace=town_wrong", ChecklistSubentryMake("3 free L.O.V. dudes", "", "Free fights and useful items/buffs."), 5).ChecklistEntrySetCombinationTag("daily free fight").ChecklistEntrySetIDTag("Love tunnel free fights")); + } + //mostly the boomerang //what does sokka throw? a boomeraang! diff --git a/Source/relay/TourGuide/Sets/Daily Dungeon.ash b/Source/relay/TourGuide/Sets/Daily Dungeon.ash index 5005965f..1a351bd8 100644 --- a/Source/relay/TourGuide/Sets/Daily Dungeon.ash +++ b/Source/relay/TourGuide/Sets/Daily Dungeon.ash @@ -236,7 +236,13 @@ void SDailyDungeonGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntr 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")); + if (rooms_left == 14) { + description.listAppend(pluraliseWordy(rooms_left, "room", "rooms").capitaliseFirstLetter() + " left."); + description.listAppend(HTMLGenerateSpanOfClass("Last room; claim your loot token!","r_element_hot")); + task_entries.listAppend(ChecklistEntryMake("daily dungeon", url, ChecklistSubentryMake("Daily Dungeon", "", description), -11).ChecklistEntrySetIDTag("Daily dungeon last-room supernag")); + } else { + optional_task_entries.listAppend(ChecklistEntryMake("daily dungeon", url, ChecklistSubentryMake("Daily Dungeon", "", description), $locations[the daily dungeon]).ChecklistEntrySetIDTag("Daily dungeon today")); + } } } diff --git a/Source/relay/TourGuide/Sets/Pulverise.ash b/Source/relay/TourGuide/Sets/Pulverise.ash index 93e17559..39586729 100644 --- a/Source/relay/TourGuide/Sets/Pulverise.ash +++ b/Source/relay/TourGuide/Sets/Pulverise.ash @@ -195,6 +195,7 @@ void SPulveriseGenerateResource(ChecklistEntry [int] resource_entries) pulveriseAppendOutputListForProducts(details, "handful of smithereens", $items[handful of smithereens], blacklist); //Elemental powder, for +1 resistances? + pulveriseAppendOutputListForProducts(details, "cold powder", $items[cold powder], blacklist); //Elemental nuggets, for +3 tower test? (very marginal) if (details.count() > 0) From 8208ba2981e5e7d3c0c15ff3542eb1fab7cafff9 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Mon, 13 Apr 2026 15:44:22 -0400 Subject: [PATCH 21/26] fixing bug identified on discord (wrong monster reference in cheddarMonster) --- .../TourGuide/Items of the Month/2026/Baseball Diamond.ash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash index d1662d31..cf4c889f 100644 --- a/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash +++ b/Source/relay/TourGuide/Items of the Month/2026/Baseball Diamond.ash @@ -95,7 +95,7 @@ void IOTMBaseballDiamondGenerateResource(ChecklistEntry [int] resource_entries) if (str == "Baseball Diamond") cheddarMonster = to_monster(trackedMonstersSplit[key-1]); } if (cheddarMonster != $monster[none]) { - subentries.listAppend(ChecklistSubentryMake(HTMLGenerateSpanOfClass(curveballMonster.name,"r_element_stench")+" tracked by a Cheddarball", "an olfaction-esque tracker!","")); + subentries.listAppend(ChecklistSubentryMake(HTMLGenerateSpanOfClass(cheddarMonster.name,"r_element_stench")+" tracked by a Cheddarball", "an olfaction-esque tracker!","")); } // Minor monster tracking sub-tile From f3cc26ade7217854385da1d5c9deaf6030242d8b Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Mon, 13 Apr 2026 15:49:06 -0400 Subject: [PATCH 22/26] forgot to remove last condition on vampfangs --- .../TourGuide/Items of the Month/2011/Plastic Vampire Fangs.ash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 0616565b..3ce389d3 100644 --- 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 @@ -26,7 +26,7 @@ void IOTMPlasticVampireFangsGenerateResource(ChecklistEntry [int] resource_entri url = "inventory.php?ftext=plastic+vampire+fangs"; } } - else ($item[Interview With You (a Vampire)].available_amount() > 0) { + else { fang_source = $item[Interview With You (a Vampire)]; url = "inventory.php?ftext=interview+with+you"; } From 94cb65954eed5de09ec0cda2f1322983167de92c Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Mon, 13 Apr 2026 17:04:19 -0400 Subject: [PATCH 23/26] brand new lucky combination tile --- Source/relay/TourGuide/Sets/Familiars.ash | 4 +- Source/relay/TourGuide/Sets/Lucky.ash | 212 +++++++++++++++++++++- Source/relay/TourGuide/Sets/Sneaks.ash | 2 +- 3 files changed, 211 insertions(+), 7 deletions(-) diff --git a/Source/relay/TourGuide/Sets/Familiars.ash b/Source/relay/TourGuide/Sets/Familiars.ash index cbed9d17..55ee5855 100644 --- a/Source/relay/TourGuide/Sets/Familiars.ash +++ b/Source/relay/TourGuide/Sets/Familiars.ash @@ -454,10 +454,10 @@ void SFamiliarsGenerateResource(ChecklistEntry [int] resource_entries) 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)) + if (my_familiar() == $familiar[none] && !__misc_state["single familiar run"] && lookupItem("FantasyRealm G. E. M.").equipped_amount() > 0 && !__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")); + task_entries.listAppend(ChecklistEntryMake(image_name, "familiar.php", ChecklistSubentryMake("Bring along a familiar", "", "It's dangerous to go alone!", -11)).ChecklistEntrySetIDTag("Bring familiar reminder")); } if ($familiar[Crimbo Shrub].familiar_is_usable() && my_path().id != PATH_G_LOVER) diff --git a/Source/relay/TourGuide/Sets/Lucky.ash b/Source/relay/TourGuide/Sets/Lucky.ash index 41005c12..16f7a63a 100644 --- a/Source/relay/TourGuide/Sets/Lucky.ash +++ b/Source/relay/TourGuide/Sets/Lucky.ash @@ -55,6 +55,8 @@ string [int] luckyOptions(int cloversAvailable) { if (protestorsRemaining > 10 && protestorsPerClover > 15) allTheLuckyStuff.listAppend("Zeppelin Mob (x"+projectedZeppClovers+")"); cloversAdjusted = MAX(cloversAdjusted - projectedZeppClovers, 3); + if (my_path().id == 56) //adventurer meats world + allTheLuckyStuff.listAppend("Knob Goblin Embezzler"); if (__misc_state["wand of nagamar needed"] && lettersStillNeeded > 0) allTheLuckyStuff.listAppend("Wand of Nagamar"); if (roughUHTurnsNeeded > 5) @@ -73,21 +75,223 @@ string [int] luckyOptions(int cloversAvailable) { return selectedOptions; } - + //Clovers and Lucky RegisterResourceGenerationFunction("LuckyGenerateResource"); void LuckyGenerateResource(ChecklistEntry [int] resource_entries) { - if (!__misc_state["in run"]) return; + + // SYNTAX FOR NEW LUCKY SOURCES + // In order to centralize, we are using the SneakSource concept from the sneaks megatile. + + record LuckySource { + string sourceName; + string url; + string imageLookupName; + boolean luckyCondition; + int luckyCount; + string tileDescription; + }; + + // Refactoring lucky to reflect/use TES megatile suggestion + // if (!__misc_state["in run"]) return; + + // useful state variables + int spleenRemaining = spleen_limit() - my_spleen_use(); + int stomachLeft = availableFullness(); + + // Build out all the lucky sources. + + // EVERGREEN: 11-leaf clovers + LuckySource getClovers() { + LuckySource final; + final.sourceName = "clover"; + final.url = invSearch("11-leaf clover"); + final.imageLookupName = "__item 11-leaf clover"; + + // # of clovers available + int cloversAvailable = clampi(3 - get_property_int("_cloversPurchased"), 0, 3); + if (my_path().id == PATH_ZOMBIE_SLAYER) cloversAvailable = 0; + if (my_path().id == PATH_NUCLEAR_AUTUMN) cloversAvailable = 0; + int cloversPossible = $item[11-leaf clover].available_amount() + cloversAvailable; + + // usable if we have any clovers available/possible + final.luckyCondition = cloversPossible > 0; + + final.luckyCount = cloversPossible; + final.tileDescription = `{cloversPossible}x clovers left`; + final.tileDescription = cloversAvailable > 0 ? final.tileDescription + `, with {cloversAvailable}x at the Hermit`; + + return final; + } + + // EVERGREEN: Astral Energy Drinks + LuckySource getAEDs() { + LuckySource final; + final.sourceName = "astral energy drink"; + final.url = invSearch("astral energy"); + final.imageLookupName = "__item astral energy drink"; + + // # of AEDs available or possible + int availableAEDs = available_amount($item[[10883]astral energy drink]) + available_amount($item[carton of astral energy drinks])*6; + int spleenFitsThisManyAEDs = min(floor(spleenRemaining / 5),availableAEDs); + + // usable if we have any clovers available/possible + final.luckyCondition = availableAEDs > 0 && spleenFitsThisManyAEDs > 0; + + final.luckyCount = spleenFitsThisManyAEDs; + final.tileDescription = `{spleenFitsThisManyAEDs}x AEDs to consume`; + final.tileDescription = availableAEDs - spleenFitsThisManyAEDs > 0 ? final.tileDescription + `, with {availableAEDs - spleenFitsThisManyAEDs}x ready for tomorrow`; + + return final; + } + + // 2026: Cast 1x "Heartstone: LUCK" + LuckySource getHeartstone() { + LuckySource final; + + final.sourceName = `august scepter`; + final.url = 'skillz.php'; + final.imageLookupName = "__item heartstone"; + + final.luckyCondition = __iotms_usable[$item[August Scepter]]; + final.luckyCount = get_property_boolean("_aug2Cast") ? 0 : 1; + final.tileDescription = `{final.sneakCount}x August Scepter cast left (Aug. 2)`; + + return final; + } + + // 2024: 3x plays of the apriling band saxophone + LuckySource getSaxophones() { + LuckySource final; + + final.sourceName = 'apriling tuba'; + final.url = "inventory.php?ftext=apriling+band+tuba"; + final.imageLookupName = "__item Apriling band tuba"; + + int aprilingBandSaxUsesLeft = clampi(3 - get_property_int("_aprilBandSaxUses"), 0, 3); + + final.luckyCondition = (aprilingBandSaxUsesLeft > 0 && available_amount($item[apriling band tuba]) > 0); + final.luckyCount = aprilingBandSaxUsesLeft; + final.tileDescription = `{aprilingBandSaxUsesLeft}x apriling sax solos left`; + return final; + + } + // 2024: moai statues (cool); no clovermint tho, no thank you + LuckySource getMoaiStatues() { + LuckySource final; + + final.sourceName = `moai statuette`; + final.url = invSearch("lucky moai statuette"); + final.imageLookupName = "__item lucky moai statuette"; + + final.luckyCondition = available_amount($item[lucky moai statuette]) > 0; + final.luckyCount = available_amount($item[lucky moai statuette])*3; + final.tileDescription = `{final.sneakCount}x clovers via lucky moai`; + + return final; + } + + // 2023: Cast 1x "Aug. 2nd: Find an Eleven-Leaf Clover Day" + LuckySource getScepter() { + LuckySource final; + + final.sourceName = `august scepter`; + final.url = 'skillz.php'; + final.imageLookupName = "__item august scepter"; + + final.luckyCondition = __iotms_usable[$item[August Scepter]]; + final.luckyCount = get_property_boolean("_aug2Cast") ? 0 : 1; + final.tileDescription = `{final.sneakCount}x August Scepter cast left (Aug. 2)`; + + return final; + } + + // 2019: Select "Surprise Me" from the Eight Days a Week Pill Keeper + LuckySource getPillkeeper() { + LuckySource final; + + final.sourceName = "pillkeeper"; + final.url = "main.php?eowkeeper=1"; + final.imageLookupName = "__item Eight Days a Week Pill Keeper"; + + // see # of free pillkeeepers remaining + int freeLuckLeft = get_property_boolean("_freePillKeeperUsed") ? 0 : 1; + + // calculate possible spleen-based sneaks + int spleenLucks = floor(spleenRemaining / 3); + + // usable if we have pill keeper plus free sneaks or spleen sneaks available + final.luckyCondition = __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.luckyCount = freeLuckLeft + spleenLucks; + final.tileDescription = get_property_boolean("_freePillKeeperUsed") ? "" : `1x PillKeeper free lucky, `; + final.tileDescription = final.tileDescription + `and {spleenSneaks}x more for 3 spleen each`; + return final; + } + + // 2014: 1x Lucky Lindy -- not including to start, too old + // 2013: 1x optimal dog -- not including to start, too old + + // Populate a list of lucky sources with our cool functions + LuckySource [string] luckySources; + + luckySources["clovo"] = getClovers(); + luckySources["astro"] = getAEDs(); + luckySources["stono"] = getHeartstone(); + luckySources["saxxo"] = getSaxophones(); + luckySources["mohio"] = getMoaiStatues(); + luckySources["scepo"] = getScepter(); + luckySources["pillo"] = getPillkeeper(); + + // For order, I am starting from things that are daily refresh -> can be saved + string [int] luckyOrder = listMake("stono","scepo","saxxo","pillo","clovo","astro","mohio"); + + ChecklistEntry entry; + + entry.url = ""; + entry.image_lookup_name = "__item 11-leaf clover"; + entry.tags.id = "Lucky sources available"; + entry.importance_level = -1; + + string [int] description; + int totalLuckyCharges = 0; + string line = HTMLGenerateSpanOfClass("Get a Lucky! adventure", "r_bold r_element_stench_desaturated"); + string ll = HTMLGenerateSpanOfClass("✾", "r_element_stench"); + string luckyText = HTMLGenerateSpanOfClass("Lucky!", "r_element_stench_desaturated"); + + foreach it, luckyType in sneakOrder + { + LuckySource lucko = luckySources[luckyType]; + if (lucko.luckyCount > 0 && lucko.luckyCondition) { + if (totalLuckyCharges == 0) entry.url = lucko.url; + totalLuckyCharges += lucko.luckyCount; + + line += "|*"+ll+lucko.tileDescription; + } + + } + + if (totalSneaks == 0) return; + + // Append all the lines to a description + description.listAppend(line); + + // Add a description that falls away when you hoverover + entry.subentries.listAppend(ChecklistSubentryMake(pluralise(totalLuckyCharges, luckyText+" charge available", luckyText+" charges available"), "", description)); + + if (entry.subentries.count() > 0) resource_entries.listAppend(entry); + + // do not run old tile + if (false) { 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(", ")); diff --git a/Source/relay/TourGuide/Sets/Sneaks.ash b/Source/relay/TourGuide/Sets/Sneaks.ash index 66e928c4..43c38b02 100644 --- a/Source/relay/TourGuide/Sets/Sneaks.ash +++ b/Source/relay/TourGuide/Sets/Sneaks.ash @@ -225,7 +225,7 @@ void SocialDistanceGenerator(ChecklistEntry [int] resource_entries) string [int] description; int totalSneaks = 0; - string line = HTMLGenerateSpanOfClass("Force an NC with sneaky tricks!", "r_bold r_element_stench_desaturated"); + string line = HTMLGenerateSpanOfClass("Force an NC with sneaky tricks!", "r_bold r_element_cold_desaturated"); foreach it, sneakType in sneakOrder { From ef56255838bc88e06d53612547576da58b1bd29b Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Mon, 13 Apr 2026 17:36:44 -0400 Subject: [PATCH 24/26] version push + fix to crafting tile --- Source/relay/TourGuide/Sets/Skills.ash | 31 +++++++++++++++----------- Source/relay/TourGuide/Settings.ash | 5 ++++- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Source/relay/TourGuide/Sets/Skills.ash b/Source/relay/TourGuide/Sets/Skills.ash index 74093b19..c2fe6f1a 100644 --- a/Source/relay/TourGuide/Sets/Skills.ash +++ b/Source/relay/TourGuide/Sets/Skills.ash @@ -41,42 +41,44 @@ void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) } 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")); } + if (get_property_int("craftingPlansCharges") >0) { + free_crafts_left += (get_property_int("craftingPlansCharges")); + } + // 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)); - } } + 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)); + } + 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); @@ -105,8 +107,11 @@ void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) 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(); + int crafting_plans = $item[crafting plans].available_amount(); + if (free_crafts_left > 0 || crafting_plans > 0) { + string [int] description; + description.listAppend(SSkillsPotentialCraftingOptions().listJoinComponents(", ").capitaliseFirstLetter()); + if (crafting_plans > 0) description.listAppend("Also, "+pluralise($item[crafting plans])+" for more free crafts.") 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)); } diff --git a/Source/relay/TourGuide/Settings.ash b/Source/relay/TourGuide/Settings.ash index 1b8083c3..45357a22 100644 --- a/Source/relay/TourGuide/Settings.ash +++ b/Source/relay/TourGuide/Settings.ash @@ -1,5 +1,8 @@ //These settings are for development. Don't worry about editing them. -string __version = "2.3.1"; // pushed to 2.2.1 on jill/leaves tiles, 2.3.1 on sea path upgrades +string __version = "2.3.2"; +// pushed to 2.2.1 on jill/leaves tiles +// 2.3.1 on sea path upgrades +// 2.3.2 on the lucky refactor ++ in spring 2026 //Path and name of the .js file. In case you change either. string __javascript = "TourGuide/TourGuide.js"; From 8f3b54bbbc27393fc4b4580cf292affb9db44c25 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Mon, 13 Apr 2026 17:48:40 -0400 Subject: [PATCH 25/26] bug sweep --- Source/relay/TourGuide/Sets/Familiars.ash | 2 +- Source/relay/TourGuide/Sets/Lucky.ash | 49 ++++++----------------- Source/relay/TourGuide/Sets/Skills.ash | 12 +++--- 3 files changed, 19 insertions(+), 44 deletions(-) diff --git a/Source/relay/TourGuide/Sets/Familiars.ash b/Source/relay/TourGuide/Sets/Familiars.ash index 55ee5855..1875e4e8 100644 --- a/Source/relay/TourGuide/Sets/Familiars.ash +++ b/Source/relay/TourGuide/Sets/Familiars.ash @@ -457,7 +457,7 @@ void SFamiliarsGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [ if (my_familiar() == $familiar[none] && !__misc_state["single familiar run"] && lookupItem("FantasyRealm G. E. M.").equipped_amount() > 0 && !__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"; - task_entries.listAppend(ChecklistEntryMake(image_name, "familiar.php", ChecklistSubentryMake("Bring along a familiar", "", "It's dangerous to go alone!", -11)).ChecklistEntrySetIDTag("Bring familiar reminder")); + task_entries.listAppend(ChecklistEntryMake(image_name, "familiar.php", ChecklistSubentryMake("Bring along a familiar", "", "It's dangerous to go alone!"), -11).ChecklistEntrySetIDTag("Bring familiar reminder")); } if ($familiar[Crimbo Shrub].familiar_is_usable() && my_path().id != PATH_G_LOVER) diff --git a/Source/relay/TourGuide/Sets/Lucky.ash b/Source/relay/TourGuide/Sets/Lucky.ash index 16f7a63a..47d9dd09 100644 --- a/Source/relay/TourGuide/Sets/Lucky.ash +++ b/Source/relay/TourGuide/Sets/Lucky.ash @@ -121,7 +121,7 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) final.luckyCount = cloversPossible; final.tileDescription = `{cloversPossible}x clovers left`; - final.tileDescription = cloversAvailable > 0 ? final.tileDescription + `, with {cloversAvailable}x at the Hermit`; + final.tileDescription = cloversAvailable > 0 ? final.tileDescription + `, with {cloversAvailable}x at the Hermit` : final.tileDescription; return final; } @@ -142,7 +142,7 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) final.luckyCount = spleenFitsThisManyAEDs; final.tileDescription = `{spleenFitsThisManyAEDs}x AEDs to consume`; - final.tileDescription = availableAEDs - spleenFitsThisManyAEDs > 0 ? final.tileDescription + `, with {availableAEDs - spleenFitsThisManyAEDs}x ready for tomorrow`; + final.tileDescription = availableAEDs - spleenFitsThisManyAEDs > 0 ? final.tileDescription + `, with {availableAEDs - spleenFitsThisManyAEDs}x ready for tomorrow` : final.tileDescription; return final; } @@ -157,7 +157,7 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) final.luckyCondition = __iotms_usable[$item[August Scepter]]; final.luckyCount = get_property_boolean("_aug2Cast") ? 0 : 1; - final.tileDescription = `{final.sneakCount}x August Scepter cast left (Aug. 2)`; + final.tileDescription = `{final.luckyCount}x August Scepter cast left (Aug. 2)`; return final; } @@ -188,7 +188,7 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) final.luckyCondition = available_amount($item[lucky moai statuette]) > 0; final.luckyCount = available_amount($item[lucky moai statuette])*3; - final.tileDescription = `{final.sneakCount}x clovers via lucky moai`; + final.tileDescription = `{final.luckyCount}x clovers via lucky moai`; return final; } @@ -203,7 +203,7 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) final.luckyCondition = __iotms_usable[$item[August Scepter]]; final.luckyCount = get_property_boolean("_aug2Cast") ? 0 : 1; - final.tileDescription = `{final.sneakCount}x August Scepter cast left (Aug. 2)`; + final.tileDescription = `{final.luckyCount}x August Scepter cast left (Aug. 2)`; return final; } @@ -219,16 +219,16 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) // see # of free pillkeeepers remaining int freeLuckLeft = get_property_boolean("_freePillKeeperUsed") ? 0 : 1; - // calculate possible spleen-based sneaks + // calculate possible spleen-based lucky int spleenLucks = floor(spleenRemaining / 3); - // usable if we have pill keeper plus free sneaks or spleen sneaks available - final.luckyCondition = __iotms_usable[lookupItem("Eight Days a Week Pill Keeper")] && (freeSneakLeft + spleenSneaks > 0); + // usable if we have pill keeper plus free lucky or spleen lucky available + final.luckyCondition = __iotms_usable[lookupItem("Eight Days a Week Pill Keeper")] && (freeLuckLeft + spleenLucks > 0); // never noticed I didn't explicitly say this was pillkeeper in the tile lol final.luckyCount = freeLuckLeft + spleenLucks; final.tileDescription = get_property_boolean("_freePillKeeperUsed") ? "" : `1x PillKeeper free lucky, `; - final.tileDescription = final.tileDescription + `and {spleenSneaks}x more for 3 spleen each`; + final.tileDescription = final.tileDescription + `and {spleenLucks}x more for 3 spleen each`; return final; } @@ -262,7 +262,7 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) string ll = HTMLGenerateSpanOfClass("✾", "r_element_stench"); string luckyText = HTMLGenerateSpanOfClass("Lucky!", "r_element_stench_desaturated"); - foreach it, luckyType in sneakOrder + foreach it, luckyType in luckyOrder { LuckySource lucko = luckySources[luckyType]; if (lucko.luckyCount > 0 && lucko.luckyCondition) { @@ -274,7 +274,7 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) } - if (totalSneaks == 0) return; + if (totalLuckyCharges == 0) return; // Append all the lines to a description description.listAppend(line); @@ -283,37 +283,14 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) entry.subentries.listAppend(ChecklistSubentryMake(pluralise(totalLuckyCharges, luckyText+" charge available", luckyText+" charges available"), "", description)); if (entry.subentries.count() > 0) resource_entries.listAppend(entry); - + // do not run old tile if (false) { - 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 - 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; + int cloversAvailable = clampi(3 - get_property_int("_cloversPurchased"), 0, 3); if (cloversAvailable > 0) { url = "hermit.php"; diff --git a/Source/relay/TourGuide/Sets/Skills.ash b/Source/relay/TourGuide/Sets/Skills.ash index c2fe6f1a..3cb30530 100644 --- a/Source/relay/TourGuide/Sets/Skills.ash +++ b/Source/relay/TourGuide/Sets/Skills.ash @@ -51,9 +51,7 @@ void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) // 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"; } // holiday multitasking if (lookupSkill("Holiday Multitasking").skill_is_usable()) { @@ -61,21 +59,21 @@ void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) } // 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"; } // 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_cooks_left > 0) { + string [int] description; + string title = "free cooking"; craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_cooks_left, title, title + "s") + " remaining", free_crafts_left > 0 ? "COOKING only" : "", description)); } if (free_mixes_left > 0) { + string [int] description; + string title = "free mixing"; craft_entry.subentries.listAppend(ChecklistSubentryMake(pluralise(free_mixes_left, title, title + "s") + " remaining", free_crafts_left > 0 ? "MIXING only" : "", description)); } @@ -111,7 +109,7 @@ void SSkillsGenerateResource(ChecklistEntry [int] resource_entries) if (free_crafts_left > 0 || crafting_plans > 0) { string [int] description; description.listAppend(SSkillsPotentialCraftingOptions().listJoinComponents(", ").capitaliseFirstLetter()); - if (crafting_plans > 0) description.listAppend("Also, "+pluralise($item[crafting plans])+" for more free crafts.") + if (crafting_plans > 0) description.listAppend("Also, "+pluralise($item[crafting plans])+" for more free crafts."); 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)); } From 475cab0cdc2335fabbdf247447635279633fad16 Mon Sep 17 00:00:00 2001 From: Aaron McGuire Date: Mon, 13 Apr 2026 17:52:01 -0400 Subject: [PATCH 26/26] final bug sweep (?) --- Source/relay/TourGuide/Sets/Lucky.ash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/relay/TourGuide/Sets/Lucky.ash b/Source/relay/TourGuide/Sets/Lucky.ash index 47d9dd09..19138596 100644 --- a/Source/relay/TourGuide/Sets/Lucky.ash +++ b/Source/relay/TourGuide/Sets/Lucky.ash @@ -134,7 +134,7 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) final.imageLookupName = "__item astral energy drink"; // # of AEDs available or possible - int availableAEDs = available_amount($item[[10883]astral energy drink]) + available_amount($item[carton of astral energy drinks])*6; + int availableAEDs = available_amount($item[[10883]astral energy drink]) + available_amount($item[[10882]carton of astral energy drinks])*6; int spleenFitsThisManyAEDs = min(floor(spleenRemaining / 5),availableAEDs); // usable if we have any clovers available/possible @@ -293,7 +293,7 @@ void LuckyGenerateResource(ChecklistEntry [int] resource_entries) int cloversAvailable = clampi(3 - get_property_int("_cloversPurchased"), 0, 3); if (cloversAvailable > 0) { - url = "hermit.php"; + string 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"));