diff --git a/Source/relay/Guide/Items of the Month/Red Nosed Snapper.ash b/Source/relay/Guide/Items of the Month/Red Nosed Snapper.ash index 6a3ae72e..bbd43ee8 100644 --- a/Source/relay/Guide/Items of the Month/Red Nosed Snapper.ash +++ b/Source/relay/Guide/Items of the Month/Red Nosed Snapper.ash @@ -1,112 +1,380 @@ -RegisterResourceGenerationFunction("IOTMRedNosedSnapperResource"); -void IOTMRedNosedSnapperResource(ChecklistEntry [int] resource_entries) + +RegisterTaskGenerationFunction("IOTMRedNosedSnapperTask"); +void IOTMRedNosedSnapperTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - ChecklistSubentry getPhylumRewards() { - // Title - string redSnapperPhylum = get_property("redSnapperPhylum"); - int redSnapperProgress = get_property_int("redSnapperProgress"); - string main_title = "Track monsters"; - - // Subtitle - string subtitle = ""; - - // Entries - string [int] description; - if (redSnapperPhylum != "") { - description.listAppend(HTMLGenerateSpanOfClass("Dudes:", "r_bold") + " Free banish item"); - description.listAppend(HTMLGenerateSpanOfClass("Goblins:", "r_bold") + " 3-size " + HTMLGenerateSpanOfClass("awesome", "r_element_awesome") + " food"); - description.listAppend(HTMLGenerateSpanOfClass("Orcs:", "r_bold") + " 3-size " + HTMLGenerateSpanOfClass("awesome", "r_element_awesome") + " booze"); - description.listAppend(HTMLGenerateSpanOfClass("Undead:", "r_bold") + " +5 " + HTMLGenerateSpanOfClass("spooky", "r_element_spooky") + " res potion"); - description.listAppend(HTMLGenerateSpanOfClass("Constellations:", "r_bold") + " Yellow ray"); - } + if (!lookupFamiliar("Red Nosed Snapper").familiar_is_usable()) return; + if (my_familiar() != lookupFamiliar("Red Nosed Snapper")) return; - return ChecklistSubentryMake(main_title, subtitle, description); + phylum current_snapper_phylum = get_property("redSnapperPhylum").to_phylum(); + + if (current_snapper_phylum == $phylum[none]) { + optional_task_entries.listAppend(ChecklistEntryMake("__familiar red-nosed snapper", "familiar.php?action=guideme&pwd=" + my_hash(), ChecklistSubentryMake("Track monsters", "+ of them and gives items", "Choose a phylum".HTMLGenerateSpanOfClass("r_element_important")), 8)); + return; } - if (!lookupFamiliar("Red Nosed Snapper").familiar_is_usable()) return; - ChecklistEntry entry; - entry.image_lookup_name = "__familiar red-nosed snapper"; + //Check if the currently tracked phylum is undoing a banish + location l = __last_adventure_location; + if (!__setting_location_bar_uses_last_location && !get_property_boolean("_relay_guide_setting_ignore_next_adventure_for_location_bar") && get_property_location("nextAdventure") != $location[none]) //want to mimic location bar popup, so they can look at it for information + l = get_property_location("nextAdventure"); - ChecklistSubentry rewards = getPhylumRewards(); - if (rewards.entries.count() > 0) { - entry.subentries.listAppend(rewards); - } + monster [int] banishes_undone_by_snapper; + foreach index, monstr in l.get_monsters() + if (monstr.phylum == current_snapper_phylum && monstr.is_banished()) + banishes_undone_by_snapper.listAppend(monstr); - if (entry.subentries.count() > 0) { - resource_entries.listAppend(entry); + if (banishes_undone_by_snapper.count() > 0) { + string title = "Your Snapper is undoing a banish".HTMLGenerateSpanOfClass("r_element_important"); + task_entries.listAppend(ChecklistEntryMake("__familiar red-nosed snapper", "familiar.php?action=guideme&pwd=" + my_hash(), ChecklistSubentryMake(title, "Change tracked phylum or switch familiar", "Bringing your snapper while it is tracking " + current_snapper_phylum + " is unbanishing " + banishes_undone_by_snapper.listJoinComponents(", ", "and")), -10)); + + ChecklistEntry pop_up_reminder_entry = ChecklistEntryMake("__familiar red-nosed snapper", "", ChecklistSubentryMake(title), -11); + pop_up_reminder_entry.only_show_as_extra_important_pop_up = true; + pop_up_reminder_entry.container_div_attributes["onclick"] = "navbarClick(0, 'Tasks_checklist_container')"; + pop_up_reminder_entry.container_div_attributes["class"] = "r_clickable"; + task_entries.listAppend(pop_up_reminder_entry); } } -RegisterTaskGenerationFunction("IOTMRedNosedSnapperTask"); -void IOTMRedNosedSnapperTask(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) +RegisterResourceGenerationFunction("IOTMRedNosedSnapperResource"); +void IOTMRedNosedSnapperResource(ChecklistEntry [int] resource_entries) { - ChecklistSubentry getChoosePhylum() { - // Title - string redSnapperPhylum = get_property("redSnapperPhylum"); - int redSnapperProgress = get_property_int("redSnapperProgress"); - string main_title = "Track monsters"; - - // Subtitle - string subtitle = ""; - - // Entries - string [int] description; - if (redSnapperPhylum == "" && my_familiar() == $familiar[Red-Nosed Snapper]) { - description.listAppend(HTMLGenerateSpanOfClass("Choose a phylum", "r_element_important")); + if (!lookupFamiliar("Red Nosed Snapper").familiar_is_usable()) return; + + boolean always_display = false; //user-preference + + if (my_familiar() != lookupFamiliar("Red Nosed Snapper") && !__misc_state["in run"] && !always_display) return; + + //beast = +5 cold res (not a lot of places to go for those, esp. since it's for a quite optional effect...) + //bug = +100% HP, 8-10 HP regen (spleen) (not really... useful enough to mention those outside of the zones having them..?) + //constellation = Yellow ray + //construct = +150% init (spleen) + //demon = +5 hot res (suggested in a zone that already has one (haunted kitchen)) (there's some hellseals, though..?) + //dude = All-day free (3x/day) banish item + //elemental = +50% MP, 3-5 MP regen (spleen) (would recommend the snowman ninja lair, but we can't know if they chose hippy route instead; we know when they ARE there...) + //elf = +50% candy (not encountered in-run, nor has... any... use?) + //fish = Fishy (spleen) + //goblin = 3-size food + //hippy = +5 stench res + //hobo = +100% meat (spleen) (only seen in overgrown lot, sleazy back alley, or hobopolis) + //horror = 5x/day free kill + //humanoid = +50% muscle stats (spleen) + //mer-kin = +30% underwater items + //orc = 3-size booze + //penguin = gives meat (never useful, nor encountered in run, really) + //pirate = +50% moxie stats (spleen) + //plant = Full HP restore in combat + //slime = +5 sleaze res (would be good for bridge, but there's very few slimes before that...) + //undead = +5 spooky res + //weird = +50% myst stats (spleen) (way too rare in-run to recommend) + + boolean going_in_Degrassi_Knoll = !knoll_available() && my_path_id() != PATH_NUCLEAR_AUTUMN && !__misc_state["desert beach available"] && __misc_state["guild open"]; + boolean making_Junk_Junk = !__misc_state["mysterious island available"] && __quest_state["Old Landfill"].in_progress; + boolean Azazel_quest_is_in_progress = __quest_state["Azazel"].in_progress && !in_bad_moon() && $locations[The Laugh Floor, Infernal Rackets Backstage].turnsAttemptedInLocation() > 0; + boolean nemesis_quest_at_clown_house = __quest_state["Nemesis"].mafia_internal_step == 6; + boolean nemesis_quest_at_Fungal_Nethers = $ints[13,14,15] contains __quest_state["Nemesis"].mafia_internal_step; + boolean cyrpt_modern_zmobies_are_appreciated = !__quest_state["Cyrpt"].state_boolean["alcove finished"] && __quest_state["Cyrpt"].state_int["alcove evilness"] > 1; + boolean at_chasm_bridge = __quest_state["Highland Lord"].mafia_internal_step == 1; + boolean past_chasm_bridge = __quest_state["Highland Lord"].mafia_internal_step > 1; + boolean want_more_rusty_hedge_trimmers = __quest_state["Highland Lord"].state_boolean["can complete twin peaks quest quickly"] && __quest_state["Highland Lord"].state_int["twin peak progress"] < 15 && $item[rusty hedge trimmers].available_amount() < __quest_state["Highland Lord"].state_int["peak tests remaining"]; + boolean looking_for_mining_gear = __quest_state["Trapper"].in_progress && !__quest_state["Trapper"].state_boolean["Past mine"] && __quest_state["Trapper"].state_string["ore needed"].to_item().available_amount() < 3 && !have_outfit_components("Mining Gear") && my_path_id() != PATH_AVATAR_OF_BORIS && my_path_id() != PATH_WAY_OF_THE_SURPRISING_FIST; + boolean they_may_be_ninjas = __quest_state["Trapper"].state_boolean["Past mine"] && ($location[lair of the ninja snowmen].turns_spent > 0 || $location[the extreme slope].turns_spent == 0); + boolean have_some_pirating_to_do = __misc_state["mysterious island available"] && __quest_state["Pirate Quest"].state_boolean["valid"] && !__quest_state["Island War"].state_boolean["War in progress"]; + boolean have_access_to_giant_castle = $item[s.o.c.k.].available_amount() > 0 || my_path_id() == PATH_EXPLOSION; + boolean top_floor_done = __quest_state["Castle"].mafia_internal_step > 10 && $location[the hole in the sky].locationAvailable(); + boolean going_in_the_HITS = $location[the hole in the sky].locationAvailable() && $item[richard\'s star key].available_amount() == 0 && !__quest_state["Level 13"].state_boolean["Richard's star key used"]; + boolean exploring_desert = __quest_state["Level 11"].in_progress && !__quest_state["Level 11 Desert"].state_boolean["Desert Explored"]; + boolean at_hidden_city = __quest_state["Hidden Temple Unlock"].finished && __quest_state["Level 11 Hidden City"].in_progress; + boolean have_more_dense_lianas_to_fight = at_hidden_city && __quest_state["Level 11 Hidden City"].state_int["lianas left"] > 0; + boolean making_wine_bomb = __quest_state["Level 11 Manor"].mafia_internal_step == 3 && get_property("spookyravenRecipeUsed") == "with_glasses"; + boolean helping_Yossarian = __quest_state["Island War"].state_boolean["War in progress"] && !__quest_state["Island War"].state_boolean["Junkyard Finished"]; + boolean fighting_filthworms = __quest_state["Island War"].state_boolean["War in progress"] && !__quest_state["Island War"].state_boolean["Orchard Finished"] && my_path_id() != PATH_2CRS; + boolean CS_need_to_pass_hot_res_test = my_path_id() == PATH_COMMUNITY_SERVICE && !(get_property("csServicesPerformed").split_string_alternate(",").listInvert() contains "Clean Steam Tunnels"); + + + string [int] currentlyReachableInstancesOfPhylum(phylum phyl) { + string [int] reachable_instances; + if (phyl == $phylum[constellation] && !$location[the hole in the sky].locationAvailable()) + reachable_instances.listAppend("Unreachable"); + + switch (phyl) { + case $phylum[beast]: //twin peak topiary animals (is that really all there is to "good" beasts locations?) + if (past_chasm_bridge && want_more_rusty_hedge_trimmers) + reachable_instances.listAppend("twin peak topiary animals"); + break; + + case $phylum[bug]: //desert and filthworms + if (exploring_desert) + reachable_instances.listAppend("arid, extra-dry desert"); + if (fighting_filthworms) + reachable_instances.listAppend("filthworms"); + break; + + case $phylum[constellation]: //Hole in the Sky, and nothing else + if (going_in_the_HITS) + reachable_instances.listAppend("hole in the sky"); + break; + + case $phylum[construct]: //monstrous boiler and wine rack + if (making_wine_bomb) { + if ($item[unstable fulminate].available_amount() == 0 && $item[bottle of Chateau de Vinegar].available_amount() == 0) + reachable_instances.listAppend("wine rack"); + reachable_instances.listAppend("monstrous boiler"); + } + break; + + case $phylum[demon]: //(some) hellseals and demons from friars and hey-deze + if (my_class() == $class[seal clubber] && my_level() >= 5) + reachable_instances.listAppend("figurine of " + (my_level() >= 6 ? "ancient" : "cute baby") + " seal"); + if (__quest_state["Friars"].in_progress) + reachable_instances.listAppend("dark X of the woods (friars)"); + if (Azazel_quest_is_in_progress) + reachable_instances.listAppend("Hey Deze"); + break; + + case $phylum[dude]: //they're everywhere!!!! (I'm not even gonna TRY to do anything past that.) + reachable_instances.listAppend("too many to count"); + break; + + case $phylum[elemental]: //ninja snowmen, not really worth it, though..? + if (they_may_be_ninjas && !__quest_state["Trapper"].state_boolean["Mountain climbed"]) + reachable_instances.listAppend("ninja snowmen"); + break; + + case $phylum[elf]: //can't reach, nor want, in-run + break; + + case $phylum[fish]: //can't reach, nor want, in-run + break; + + case $phylum[goblin]: //kramco & cobbs knob + if (lookupItem("Kramco Sausage-o-Matic™").available_amount() > 0) + reachable_instances.listAppend("kramco sausage goblins"); + if (!__quest_state["Knob Goblin King"].finished) + reachable_instances.listAppend("cobbs knob"); + break; + + case $phylum[hippy]: //hippy camp + if (__misc_state["mysterious island available"] && __quest_state["Island War"].state_string["Side seemingly fighting for"] != "hippy") + reachable_instances.listAppend(__quest_state["Island War"].state_boolean["War in progress"] ? "war hippies" : "hippy camp"); + break; + + case $phylum[hobo]: //no hobos in one's normal path. There's some in the wrong side of the track, but we don't recommend they go there for that. + break; + + case $phylum[horror]: //(some) hellseals and clowns + if (my_class() == $class[seal clubber]) + reachable_instances.listAppend("figurine of wretched-looking" + (my_level() >= 9 ? "/armored" : "") + " seal"); + if (nemesis_quest_at_clown_house) + reachable_instances.listAppend("clown fun house"); + break; + + case $phylum[humanoid]: //Degrassi Knoll, castle giants, old landfill, 7-foot dwarves, Junkyard gremlins + if (going_in_Degrassi_Knoll) + reachable_instances.listAppend("Degrassi Knoll"); + if (have_access_to_giant_castle && !top_floor_done) + reachable_instances.listAppend("castle giants"); + if (making_Junk_Junk) + reachable_instances.listAppend("old landfill"); + if (looking_for_mining_gear) + reachable_instances.listAppend("7-foot dwarves"); + if (helping_Yossarian) + reachable_instances.listAppend("island junkyard"); + break; + + case $phylum[mer-kin]: //can't reach, nor want, in-run + break; + + case $phylum[orc]: //smut orc logging camp and frat boys/warriors + if (at_chasm_bridge) + reachable_instances.listAppend("smut orcs"); + if (__misc_state["mysterious island available"] && __quest_state["Island War"].state_string["Side seemingly fighting for"] != "frat boys") + reachable_instances.listAppend("frat " + (__quest_state["Island War"].state_boolean["War in progress"] ? "warriors" : "boys")); + break; + + case $phylum[penguin]: //can't reach, nor want, in-run + break; + + case $phylum[pirate]: //pirate cove + if (have_some_pirating_to_do) + reachable_instances.listAppend("pirate cove"); + break; + + case $phylum[plant]: //fungal nethers and dense lianas + if (nemesis_quest_at_Fungal_Nethers) + reachable_instances.listAppend("fungal nethers"); + if (have_more_dense_lianas_to_fight) + reachable_instances.listAppend("dense lianas"); + break; + + case $phylum[slime]: //oil peak (yes, I KNOW that the +5 sleaze res is supposed to be for the BRIDGE BUILDING, but there's just no consistent source of slimes before that; go cry me a river won't you) + if (past_chasm_bridge && __quest_state["Highland Lord"].state_float["oil peak pressure"] > 0.0) + reachable_instances.listAppend("oil peak"); + break; + + case $phylum[undead]: //The whole spookyraven manor, or the cyrpt + if (__quest_state["Manor Unlock"].in_progress) + reachable_instances.listAppend("Spookyraven manor"); + if (__quest_state["Cyrpt"].in_progress) + reachable_instances.listAppend("Cyrpt"); + break; + + case $phylum[weird]: //I've got nuthin', they are too rare in-run + break; } + return reachable_instances; + } + + + boolean [phylum] want_phylum_drop; + if (true) { //always up for those if available: + want_phylum_drop[$phylum[constellation]] = true; //yellow-ray + want_phylum_drop[$phylum[dude]] = true; //banish + want_phylum_drop[$phylum[horror]] = true; //free kill + want_phylum_drop[$phylum[hobo]] = true; //+100% meat + } - return ChecklistSubentryMake(main_title, subtitle, description); + if (false) { //those just... don't have an use + want_phylum_drop[$phylum[elf]] = true; //+50% candy drop + want_phylum_drop[$phylum[penguin]] = true; //an envelope which gives some meat... + want_phylum_drop[$phylum[bug]] = true; //+100% HP, ~9HP regen (not really worth it...) } - if (!lookupFamiliar("Red Nosed Snapper").familiar_is_usable()) return; + if (__misc_state["in run"]) { + if (__misc_state["need to level"]) + switch (my_primestat()) { //+50% gains + case $stat[muscle]: + want_phylum_drop[$phylum[humanoid]] = true; break; + case $stat[mysticality]: + want_phylum_drop[$phylum[weird]] = true; break; + case $stat[moxie]: + want_phylum_drop[$phylum[pirate]] = true; break; + } + + if (!__quest_state["Level 13"].state_boolean["Init race completed"] || cyrpt_modern_zmobies_are_appreciated) + want_phylum_drop[$phylum[construct]] = true; //+150% initiative + + if (my_path_id() != PATH_COMMUNITY_SERVICE && $item[Spookyraven billiards room key].available_amount() == 0 && get_property_int("manorDrawerCount") < 20) { + if (numeric_modifier("hot resistance") < 7) + want_phylum_drop[$phylum[demon]] = true; //+5 hot res + if (numeric_modifier("stench resistance") < 7) + want_phylum_drop[$phylum[hippy]] = true; //+5 stench res + } else if (CS_need_to_pass_hot_res_test) + want_phylum_drop[$phylum[demon]] = true; //demon again; +5 hot res + + if (past_chasm_bridge) { + if (__quest_state["Highland Lord"].state_boolean["can complete twin peaks quest quickly"] && !__quest_state["Highland Lord"].state_boolean["Peak Stench Completed"] && numeric_modifier("stench resistance") <= 1.0) //if they have 2 or 3, they don't need a plus-FIVE + want_phylum_drop[$phylum[hippy]] = true; //hippy again; +5 stench res + + if (__quest_state["Highland Lord"].state_int["a-boo peak hauntedness"] > 2) { + want_phylum_drop[$phylum[beast]] = true; //+5 cold res + want_phylum_drop[$phylum[undead]] = true; //+5 spooky res + } + } else if (at_chasm_bridge) + want_phylum_drop[$phylum[slime]] = true; //+5 sleaze res - ChecklistEntry entry; - entry.image_lookup_name = "__familiar red-nosed snapper"; - entry.importance_level = -10; + if (they_may_be_ninjas && !__quest_state["Trapper"].state_boolean["Groar defeated"] && numeric_modifier("cold resistance") < 3.0) //if they have 3 or 4, they don't need a plus-FIVE + want_phylum_drop[$phylum[beast]] = true; //beast again; +5 cold res - ChecklistSubentry choosePhylum = getChoosePhylum(); - if (choosePhylum.entries.count() > 0) { - entry.subentries.listAppend(choosePhylum); + if (!lookupItem("Eight Days a Week Pill Keeper").have()) + want_phylum_drop[$phylum[elemental]] = true; //+50% MP, ~4MP regen + + if (__quest_state["Lair"].state_boolean["shadow will need to be defeated"]) + want_phylum_drop[$phylum[plant]] = true; + } else if (__quest_state["Sea Monkees"].in_progress || __quest_state["Sea Temple"].in_progress || __quest_state["Sea Monkees"].state_string["skate park status"] == "war") { + want_phylum_drop[$phylum[fish]] = true; //fishy + want_phylum_drop[$phylum[mer-kin]] = true; //+30% underwater items (meh...) } - if (entry.subentries.count() > 0) { - task_entries.listAppend(entry); + if (in_ronin() && my_path_id() != PATH_NUCLEAR_AUTUMN) { + if (fullness_limit() >= 3) + want_phylum_drop[$phylum[goblin]] = true; //size 3 awesome food + if (inebriety_limit() >= 3) + want_phylum_drop[$phylum[orc]] = true; //size 3 awesome booze } -} -RegisterResourceGenerationFunction("IOTMHumanMuskBanish"); -void IOTMHumanMuskBanish(ChecklistEntry [int] resource_entries) { - ChecklistSubentry gerResource() { - int humanMuskUses = get_property_int("_humanMuskUses"); - int humanMuskUsesLeft = MAX(0, 3 - humanMuskUses); - int availableHumanMusks = MIN(humanMuskUsesLeft, $item[human musk].available_amount()); - // Title - string main_title = availableHumanMusks + " human musks"; + boolean [phylum] current_location_phylums; + foreach index, monstr in __last_adventure_location.get_monsters() + current_location_phylums[monstr.phylum] = true; - // Subtitle - string subtitle = ""; + phylum current_snapper_phylum = get_property("redSnapperPhylum").to_phylum(); - // Entries - string [int] description; - if (availableHumanMusks > 0) { - description.listAppend("Free run/banish. Consumes item."); - } + //The selection presented to the player. The currently tracked phylum and those present in the current locations will always be in there + //This is meant to inform the player on the DROPS they can get, NOT on which phylum they could track to help progress (at least it's not the focus here) + boolean [phylum] phylum_display_list; + string [phylum] [int] reachable_options; - return ChecklistSubentryMake(main_title, subtitle, description); - } + foreach phyl in $phylums[] { + string [int] options = currentlyReachableInstancesOfPhylum(phyl); - ChecklistEntry entry; - entry.ChecklistEntryTagEntry("banish"); - entry.image_lookup_name = "__item human musk"; + if (phyl == current_snapper_phylum) //obviously show the one they are tracking + phylum_display_list[phyl] = true; + else if (current_location_phylums contains phyl) //show those in the current location + phylum_display_list[phyl] = true; + else if (want_phylum_drop[phyl] && (options.count() > 0 || !__misc_state["in run"]) && options[0] != "Unreachable") + phylum_display_list[phyl] = true; - ChecklistSubentry resource = gerResource(); - if (resource.entries.count() > 0) { - entry.subentries.listAppend(resource); + reachable_options[phyl] = options; } - if (entry.subentries.count() > 0) { - resource_entries.listAppend(entry); + int progress = get_property_int("redSnapperProgress"); + + string title = "Track monsters"; + if (current_snapper_phylum != $phylum[none]) + title = (11 - progress).pluralise(current_snapper_phylum + " kill", current_snapper_phylum + " kills") + " until next Snapper drop"; + + string [int] description; + + if (progress > 0) + description.listAppend("Changing phylum resets progress."); + + string [phylum] snapper_drop = { + $phylum[beast]:"+5 " + "cold".HTMLGenerateSpanOfClass("r_element_cold") + " res (20 turns)", + $phylum[bug]:"+100% HP, 8-10 HP regen (1 spleen, 60 turns)", + $phylum[constellation]:"Yellow ray item (150 turns of Ev. Looks Yellow)", + $phylum[construct]:"+150% init (1 spleen, 30 turns)", + $phylum[demon]:"+5 " + "hot".HTMLGenerateSpanOfClass("r_element_hot") + " res (20 turns)", + $phylum[dude]:"All-day free (3x/day) banish item", + $phylum[elemental]:"+50% MP, 3-5 MP regen (1 spleen, 60 turns)", + $phylum[elf]:"+50% candy (20 turns)", + $phylum[fish]:"Fishy (1 spleen, 30 turns)", + $phylum[goblin]:"3-size " + "awesome".HTMLGenerateSpanOfClass("r_element_awesome") + " food", + $phylum[hippy]:"+5 " + "stench".HTMLGenerateSpanOfClass("r_element_stench") + " res (20 turns)", + $phylum[hobo]:"+100% meat (1 spleen, 60 turns)", + $phylum[horror]:"5x/day free kill item", + $phylum[humanoid]:"+50% muscle stats (1 spleen, 30 turns)", + $phylum[mer-kin]:"+30% underwater items (20 turns)", + $phylum[orc]:"3-size " + "awesome".HTMLGenerateSpanOfClass("r_element_awesome") + " booze", + $phylum[penguin]:"(500 + 500 * +meat%) meat item", + $phylum[pirate]:"+50% moxie stats (1 spleen, 30 turns)", + $phylum[plant]:"Full HP restore combat item", + $phylum[slime]:"+5 " + "sleaze".HTMLGenerateSpanOfClass("r_element_sleaze") + " res (20 turns)", + $phylum[undead]:"+5 " + "spooky".HTMLGenerateSpanOfClass("r_element_spooky") + " res (20 turns)", + $phylum[weird]:"+50% myst stats (1 spleen, 30 turns)" + }; + + foreach phyl in phylum_display_list { + string line; + if (current_location_phylums contains phyl) + line += "• "; + if (current_snapper_phylum == phyl) + line += __html_right_arrow_character; + line += capitaliseFirstLetter(phyl + ": ").HTMLGenerateSpanOfClass("r_bold"); + line += snapper_drop[phyl]; + + + //FIXME Is there a "good" way to add reachable_options to this? + + //remember to add a string HTMLGenerateSimpleTableLines(string [int] lines) to page.ash if ending up using this + /*if (reachable_options[phyl].count() > 0 && false) { + buffer tooltip; + tooltip.append(reachable_options[phyl].HTMLGenerateSimpleTableLines().HTMLGenerateSpanOfClass("r_tooltip_inner_class r_tooltip_inner_class_margin")); + tooltip.append(line); + line = tooltip.HTMLGenerateSpanOfClass("r_tooltip_outer_class"); + }*/ + + description.listAppend(line); } -} \ No newline at end of file + + resource_entries.listAppend(ChecklistEntryMake("__familiar red-nosed snapper", "familiar.php?action=guideme&pwd=" + my_hash(), ChecklistSubentryMake(title, "+1 item / 11 kills of tracked phylum", description))); +} diff --git a/Source/relay/Guide/Main.ash b/Source/relay/Guide/Main.ash index 6f54f373..aecab8e2 100644 --- a/Source/relay/Guide/Main.ash +++ b/Source/relay/Guide/Main.ash @@ -51,7 +51,6 @@ void runMain(string relay_filename) print_html("Form fields: " + form_fields.to_json()); - locationCompatibilityInit(); PageInit(); ChecklistInit(); setUpCSSStyles(); diff --git a/Source/relay/Guide/Quests/Azazel.ash b/Source/relay/Guide/Quests/Azazel.ash index 53c5f12c..a3d36a50 100644 --- a/Source/relay/Guide/Quests/Azazel.ash +++ b/Source/relay/Guide/Quests/Azazel.ash @@ -244,7 +244,7 @@ void QAzazelGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int entry.subentries.listAppend(subentry); } - if ((my_path_id() == PATH_TEETOTALER || my_path_id() == PATH_AVATAR_OF_BORIS || my_path_id() == PATH_ZOMBIE_SLAYER) && availableFullness() < 5) + if ((my_path_id() == PATH_TEETOTALER || my_path_id() == PATH_AVATAR_OF_BORIS || my_path_id() == PATH_ZOMBIE_SLAYER || my_path_id() == PATH_OF_THE_PLUMBER) && availableFullness() < 5) entry.subentries.listAppend(ChecklistSubentryMake(HTMLGenerateSpanFont("Won't work, need five fullness to eat lasagna.", "red"), "", "")); if (my_path_id() == PATH_OXYGENARIAN && availableSpleen() < 5) diff --git a/Source/relay/Guide/Quests/Level 11 - Hidden City.ash b/Source/relay/Guide/Quests/Level 11 - Hidden City.ash index d9b8431a..852ac62e 100644 --- a/Source/relay/Guide/Quests/Level 11 - Hidden City.ash +++ b/Source/relay/Guide/Quests/Level 11 - Hidden City.ash @@ -33,7 +33,16 @@ void QLevel11HiddenCityInit() { } } + int lianas_left; + foreach shrine in $locations[a massive ziggurat,an overgrown shrine (northwest),an overgrown shrine (southwest),an overgrown shrine (northeast),an overgrown shrine (southeast)] { + lianas_left += 3 - shrine.numberOfDenseLianaFoughtInShrine(); + } + state.state_int["lianas left"] = lianas_left; + if (get_property_int("hiddenBowlingAlleyProgress") >= 1 && get_property_int("hiddenHospitalProgress") >= 1 && get_property_int("hiddenApartmentProgress") >= 1 && get_property_int("hiddenOfficeProgress") >= 1 && $location[a massive Ziggurat].numberOfDenseLianaFoughtInShrine() >= 3 && state.mafia_internal_step >= 4) + state.state_int["lianas left"] = 0; + + if (state.state_int["lianas left"] == 0) state.state_boolean["need machete for liana"] = false; if (!__misc_state["can equip just about any weapon"]) { diff --git a/Source/relay/Guide/Quests/Level 12.ash b/Source/relay/Guide/Quests/Level 12.ash index c40047ba..6b306fbf 100644 --- a/Source/relay/Guide/Quests/Level 12.ash +++ b/Source/relay/Guide/Quests/Level 12.ash @@ -96,7 +96,7 @@ void QLevel12Init() void QLevel12GenerateTasksSidequests(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { QuestState base_quest_state = __quest_state["Level 12"]; - if (!base_quest_state.state_boolean["Orchard Finished"]) + if (!base_quest_state.state_boolean["Orchard Finished"] && my_path_id() != PATH_2CRS) { string [int] details; string [int] modifiers; @@ -202,7 +202,7 @@ void QLevel12GenerateTasksSidequests(ChecklistEntry [int] task_entries, Checklis } optional_task_entries.listAppend(ChecklistEntryMake("Island War Farm", "bigisland.php?place=farm", ChecklistSubentryMake("Island War Farm Quest", modifiers, details), $locations[mcmillicancuddy's farm,mcmillicancuddy's barn,mcmillicancuddy's pond,mcmillicancuddy's back 40,mcmillicancuddy's other back 40,mcmillicancuddy's granary,mcmillicancuddy's bog,mcmillicancuddy's family plot,mcmillicancuddy's shady thicket])); } - if (!base_quest_state.state_boolean["Nuns Finished"]) + if (!base_quest_state.state_boolean["Nuns Finished"] && my_path_id() != PATH_2CRS) { string [int] details; int meat_gotten = get_property_int("currentNunneryMeat"); diff --git a/Source/relay/Guide/Quests/Manor.ash b/Source/relay/Guide/Quests/Manor.ash index cb05022c..4ef5adba 100644 --- a/Source/relay/Guide/Quests/Manor.ash +++ b/Source/relay/Guide/Quests/Manor.ash @@ -1,7 +1,7 @@ void QManorInit() { - QuestState state; + QuestState state; state.state_boolean["need ballroom song set"] = false; @@ -50,49 +50,49 @@ void QManorInit() - if (locationAvailable($location[the haunted ballroom]) && !(state.state_boolean["need ballroom song set"] || state.state_boolean["ballroom needs delay burned"])) - QuestStateParseMafiaQuestPropertyValue(state, "finished"); - else + if (locationAvailable($location[the haunted ballroom]) && !(state.state_boolean["need ballroom song set"] || state.state_boolean["ballroom needs delay burned"])) + QuestStateParseMafiaQuestPropertyValue(state, "finished"); + else { - QuestStateParseMafiaQuestPropertyValue(state, "started"); + QuestStateParseMafiaQuestPropertyValue(state, "started"); } if (my_path_id() == PATH_COMMUNITY_SERVICE) QuestStateParseMafiaQuestPropertyValue(state, "finished"); - state.quest_name = "Spookyraven Manor Unlock"; - state.image_name = "Spookyraven Manor"; + state.quest_name = "Spookyraven Manor Unlock"; + state.image_name = "Spookyraven Manor"; - - /*location zone_to_work_on = $location[none]; - if (!locationAvailable($location[the haunted billiards room])) - { - zone_to_work_on = $location[the haunted billiards room]; - } - else if (!locationAvailable($location[the haunted library])) - { - zone_to_work_on = $location[the haunted library]; - } - else if (!locationAvailable($location[the haunted bedroom])) - { - zone_to_work_on = $location[the haunted bedroom]; - } - else if (!locationAvailable($location[the haunted ballroom])) - { - zone_to_work_on = $location[the haunted ballroom]; - } - state.state_string["zone to work on"] = zone_to_work_on;*/ - - __quest_state["Manor Unlock"] = state; + + /*location zone_to_work_on = $location[none]; + if (!locationAvailable($location[the haunted billiards room])) + { + zone_to_work_on = $location[the haunted billiards room]; + } + else if (!locationAvailable($location[the haunted library])) + { + zone_to_work_on = $location[the haunted library]; + } + else if (!locationAvailable($location[the haunted bedroom])) + { + zone_to_work_on = $location[the haunted bedroom]; + } + else if (!locationAvailable($location[the haunted ballroom])) + { + zone_to_work_on = $location[the haunted ballroom]; + } + state.state_string["zone to work on"] = zone_to_work_on;*/ + + __quest_state["Manor Unlock"] = state; } void QManorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { - if (!__quest_state["Manor Unlock"].in_progress && __misc_state["in run"]) - return; + if (!__quest_state["Manor Unlock"].in_progress && __misc_state["in run"]) + return; if (my_level() < 5 && my_ascensions() == 0 && !QuestState("questM21Dance").in_progress) return; //not yet possible boolean should_output_optionally = false; boolean should_output_futurally = false; - QuestState base_quest_state = __quest_state["Manor Unlock"]; + QuestState base_quest_state = __quest_state["Manor Unlock"]; boolean [location] relevant_locations = $locations[the haunted kitchen, the haunted library, the haunted billiards room, the haunted bedroom, the haunted ballroom, the haunted gallery, the haunted bathroom]; //$locations[the haunted kitchen, the haunted library, the haunted billiards room, the haunted bedroom, the haunted ballroom]; @@ -100,14 +100,14 @@ void QManorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] if (!__misc_state["in run"] && !(relevant_locations contains __last_adventure_location)) return; - ChecklistSubentry subentry; - //subentry.header = "Unlock Spookyraven Manor"; + ChecklistSubentry subentry; + //subentry.header = "Unlock Spookyraven Manor"; //This is currently very incomplete, sorry. - - string url = ""; - - string image_name; + + string url = ""; + + string image_name; boolean ballroom_probably_open = false; if ($location[the haunted ballroom].turnsAttemptedInLocation() > 0) @@ -354,12 +354,11 @@ void QManorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] should_output_futurally = true; }*/ - float drawers_per_turn = 0.0; - float hot_resistance = numeric_modifier("hot resistance"); - float stench_resistance = numeric_modifier("stench resistance"); + float hot_resistance = MIN(numeric_modifier("hot resistance"), 9.0); + float stench_resistance = MIN(numeric_modifier("stench resistance"), 9.0); - int more_hot_needed = MAX(0, 9 - hot_resistance.to_int()); - int more_stench_needed = MAX(0, 9 - stench_resistance.to_int()); + int more_hot_needed = 9 - hot_resistance.to_int(); + int more_stench_needed = 9 - stench_resistance.to_int(); string [int] needed_resists; @@ -370,29 +369,40 @@ void QManorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] //subentry.entries.listAppend("Run 9 " + HTMLGenerateSpanOfClass("hot", "r_element_hot") + " resistance and " + HTMLGenerateSpanOfClass("stench", "r_element_stench") + " resistance to search faster."); - drawers_per_turn = 0.5 * MIN(4.0, MAX(1.0, 1.0 + hot_resistance / 3.0)) + 0.5 * MIN(4.0, MAX(1.0, 1.0 + stench_resistance / 3.0)); - drawers_per_turn = MAX(1.0, drawers_per_turn); //zero-divide safety backup + float drawers_per_turn = 1.0 + MAX(hot_resistance / 6.0, 0.0) + MAX(stench_resistance / 6.0, 0.0); float drawers_needed = MAX(0, 21 - get_property_int("manorDrawerCount")); int total_turns = ceil(drawers_needed / drawers_per_turn) + 1; - if (needed_resists.count() > 0 && total_turns > 1) - subentry.entries.listAppend("Run " + needed_resists.listJoinComponents(", ", "and") + " to search faster."); - subentry.entries.listAppend(drawers_per_turn.roundForOutput(1) + " drawers searched per turn.|~" + pluralise(total_turns, "turn", "turns") + " remaining."); - - if (__misc_state["have hipster"]) - subentry.modifiers.listAppend(__misc_state_string["hipster name"]); - if (total_turns > 1) - { - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("hot res", "r_element_hot_desaturated")); - subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("stench res", "r_element_stench_desaturated")); + if (drawers_needed == 0.0) + subentry.entries.listAppend("Find the key next turn."); + else { + string line; + if (hot_resistance <= 0 && stench_resistance <= 0) + line = "1 drawer"; //roundForOutput returns a string, incompatible with pluralise() + else + line = drawers_per_turn.roundForOutput(1) + " drawers"; + line += " searched per turn.|"; + + if (drawers_needed > drawers_per_turn.floor()) { + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("hot res", "r_element_hot_desaturated")); + subentry.modifiers.listAppend(HTMLGenerateSpanOfClass("stench res", "r_element_stench_desaturated")); + + line += "~"; + if (needed_resists.count() > 0) { + subentry.entries.listAppend("Run " + needed_resists.listJoinComponents(", ", "and") + " to search faster."); + if (!__misc_state["familiars temporarily blocked"] && $familiar[exotic parrot].familiar_is_usable() && my_familiar() != $familiar[exotic parrot]) + subentry.entries.listAppend("Possibly bring along your exotic parrot."); + } + } + + line += total_turns + " turns remaining."; + subentry.entries.listAppend(line); } - if (!__misc_state["familiars temporarily blocked"] && $familiar[exotic parrot].familiar_is_usable() && my_familiar() != $familiar[exotic parrot] && (hot_resistance < 9.0 || stench_resistance < 9.0) && total_turns > 1) - { - subentry.entries.listAppend("Possibly bring along your exotic parrot."); - } + if (__misc_state["have hipster"]) + subentry.modifiers.listAppend(__misc_state_string["hipster name"]); if (inebriety_limit() > 10 && my_inebriety() < 10) subentry.entries.listAppend("Try not to drink past ten, the billiards room is next."); @@ -523,7 +533,7 @@ void QManorGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] } } - if (subentry.header != "") + if (subentry.header != "") { if (image_name.length() == 0) image_name = base_quest_state.image_name; diff --git a/Source/relay/Guide/Quests/Pirate.ash b/Source/relay/Guide/Quests/Pirate.ash index 9d5ab660..356e5ff6 100644 --- a/Source/relay/Guide/Quests/Pirate.ash +++ b/Source/relay/Guide/Quests/Pirate.ash @@ -50,6 +50,8 @@ void QPirateInit() void QPirateCoveGenerateTasks(ChecklistEntry [int] task_entries, ChecklistEntry [int] optional_task_entries, ChecklistEntry [int] future_task_entries) { + if (__quest_state["Island War"].state_boolean["War in progress"]) return; + QuestState base_quest_state = __quest_state["Pirate Quest"]; ChecklistSubentry subentry; subentry.header = base_quest_state.quest_name; diff --git a/Source/relay/Guide/Sections/API.ash b/Source/relay/Guide/Sections/API.ash index 6d3fb81b..83e7051c 100644 --- a/Source/relay/Guide/Sections/API.ash +++ b/Source/relay/Guide/Sections/API.ash @@ -140,7 +140,7 @@ string [string] generateAPIResponse() else if (true)*/ if (true) { - boolean [string] relevant_mafia_properties = $strings[merkinQuestPath,questF01Primordial,questF02Hyboria,questF03Future,questF04Elves,questF05Clancy,questG01Meatcar,questG02Whitecastle,questG03Ego,questG04Nemesis,questG05Dark,questG06Delivery,questI01Scapegoat,questI02Beat,questL02Larva,questL03Rat,questL04Bat,questL05Goblin,questL06Friar,questL07Cyrptic,questL08Trapper,questL09Topping,questL10Garbage,questL11MacGuffin,questL11Manor,questL11Palindome,questL11Pyramid,questL11Worship,questL12War,questL13Final,questM01Untinker,questM02Artist,questM03Bugbear,questM04Galaktic,questM05Toot,questM06Gourd,questM07Hammer,questM08Baker,questM09Rocks,questM10Azazel,questM11Postal,questM12Pirate,questM13Escape,questM14Bounty,questM15Lol,questS01OldGuy,questS02Monkees,sidequestArenaCompleted,sidequestFarmCompleted,sidequestJunkyardCompleted,sidequestLighthouseCompleted,sidequestNunsCompleted,sidequestOrchardCompleted,cyrptAlcoveEvilness,cyrptCrannyEvilness,cyrptNicheEvilness,cyrptNookEvilness,desertExploration,gnasirProgress,relayCounters,timesRested,currentEasyBountyItem,currentHardBountyItem,currentSpecialBountyItem,volcanoMaze1,_lastDailyDungeonRoom,seahorseName,chasmBridgeProgress,_aprilShower,lastAdventure,lastEncounter,_floristPlantsUsed,_fireStartingKitUsed,_psychoJarUsed,hiddenHospitalProgress,hiddenBowlingAlleyProgress,hiddenApartmentProgress,hiddenOfficeProgress,pyramidPosition,parasolUsed,_discoKnife,lastPlusSignUnlock,olfactedMonster,photocopyMonster,lastTempleUnlock,volcanoMaze1,blankOutUsed,peteMotorbikeCowling,peteMotorbikeGasTank,peteMotorbikeHeadlight,peteMotorbikeMuffler,peteMotorbikeSeat,peteMotorbikeTires,_petePeeledOut,_navelRunaways,_peteRiotIncited,_petePartyThrown,hiddenTavernUnlock,_dnaPotionsMade,_psychokineticHugUsed,dnaSyringe,_warbearGyrocopterUsed,questM20Necklace,questM21Dance,grimstoneMaskPath,cinderellaMinutesToMidnight,merkinVocabularyMastery,_pirateBellowUsed,questM21Dance,_defectiveTokenChecked,questG07Myst,questG08Moxie,questESpClipper,questESpGore,questESpJunglePun,questESpFakeMedium,questESlMushStash,questESlAudit,questESlBacteria,questESlCheeseburger,questESlCocktail,questESlSprinkles,questESlSalt,questESlFish,questESlDebt,_pickyTweezersUsed,_bittycar,questESpSerum,questESpOutOfOrder,_shrubDecorated,questESpEVE,questESpSmokes,questG09Muscle,_rapidPrototypingUsed,nsTowerDoorKeysUsed,_chateauDeskHarvested,lastGoofballBuy,nsChallenge1,nsChallenge2,nsContestants1,nsContestants2,nsContestants3,lastDesertUnlock,questM18Swamp,edPiece,warehouseProgress,questEStFishTrash,questEStNastyBears,questEStSocialJusticeI,questEStSocialJusticeII,questEStSuperLuber,questEStZippityDooDah,_summonAnnoyanceUsed,questEStWorkWithFood,questM24Doc,questEStGiveMeFuel,_mayoTankSoaked,_feastUsed,spelunkyNextNoncombat,spelunkySacrifices,spelunkyStatus,spelunkyUpgrades,spelunkyWinCount,_deckCardsDrawn,_glarkCableUses,_banderRunaways,questM25Armorer,pyramidBombUsed,_powerPillUses,nextAdventure,_volcanoItem1,_volcanoItem2,_volcanoItem3,_barrelPrayer,questECoBucket,_machineTunnelsAdv,_snojoFreeFights,snojoSetting,_lastCombatStarted,batmanZone,batmanUpgrades,batmanTimeLeft,batmanStats,questLTTQuestByWire,questM26Oracle,sourceTerminalEducate1,sourceTerminalEducate2,sourceTerminalEnquiry,_sourceTerminalDigitizeUses,_sourceTerminalEnhanceUses,_sourceTerminalExtrudes,_detectiveCasesCompleted,_pottedTeaTreeUsed,lastIslandUnlock,falloutShelterChronoUsed,_timeSpinnerMinutesUsed,_lynyrdSnareUses,_noobSkillCount,_universeCalculated,_horsery,_expertCornerCutterUsed,boomBoxSong,_questPartyFair,_questPartyFairQuest,_neverendingPartyFreeTurns,_latteRefillsUsed,_latteBanishUsed,_latteCopyUsed,_latteDrinkUsed,_kgbTranquilizerDartUses,banishedMonsters,lastLightsOutTurn,lastVoteMonsterTurn,_lastCombatStarted,_sausageFights,_saberMod,_saberForceMonster,_daycareRecruits,_daycareGymScavenges,_campAwayCloudBuffs,_campAwaySmileBuffs,moonTuned,zeppelinProtestors,questL11Ron,questL11Shen,_canSeekBirds,questGuzzlr]; + boolean [string] relevant_mafia_properties = $strings[merkinQuestPath,questF01Primordial,questF02Hyboria,questF03Future,questF04Elves,questF05Clancy,questG01Meatcar,questG02Whitecastle,questG03Ego,questG04Nemesis,questG05Dark,questG06Delivery,questI01Scapegoat,questI02Beat,questL02Larva,questL03Rat,questL04Bat,questL05Goblin,questL06Friar,questL07Cyrptic,questL08Trapper,questL09Topping,questL10Garbage,questL11MacGuffin,questL11Manor,questL11Palindome,questL11Pyramid,questL11Worship,questL12War,questL13Final,questM01Untinker,questM02Artist,questM03Bugbear,questM04Galaktic,questM05Toot,questM06Gourd,questM07Hammer,questM08Baker,questM09Rocks,questM10Azazel,questM11Postal,questM12Pirate,questM13Escape,questM14Bounty,questM15Lol,questS01OldGuy,questS02Monkees,sidequestArenaCompleted,sidequestFarmCompleted,sidequestJunkyardCompleted,sidequestLighthouseCompleted,sidequestNunsCompleted,sidequestOrchardCompleted,cyrptAlcoveEvilness,cyrptCrannyEvilness,cyrptNicheEvilness,cyrptNookEvilness,desertExploration,gnasirProgress,relayCounters,timesRested,currentEasyBountyItem,currentHardBountyItem,currentSpecialBountyItem,volcanoMaze1,_lastDailyDungeonRoom,seahorseName,chasmBridgeProgress,_aprilShower,lastAdventure,lastEncounter,_floristPlantsUsed,_fireStartingKitUsed,_psychoJarUsed,hiddenHospitalProgress,hiddenBowlingAlleyProgress,hiddenApartmentProgress,hiddenOfficeProgress,pyramidPosition,parasolUsed,_discoKnife,lastPlusSignUnlock,olfactedMonster,photocopyMonster,lastTempleUnlock,volcanoMaze1,blankOutUsed,peteMotorbikeCowling,peteMotorbikeGasTank,peteMotorbikeHeadlight,peteMotorbikeMuffler,peteMotorbikeSeat,peteMotorbikeTires,_petePeeledOut,_navelRunaways,_peteRiotIncited,_petePartyThrown,hiddenTavernUnlock,_dnaPotionsMade,_psychokineticHugUsed,dnaSyringe,_warbearGyrocopterUsed,questM20Necklace,questM21Dance,grimstoneMaskPath,cinderellaMinutesToMidnight,merkinVocabularyMastery,_pirateBellowUsed,questM21Dance,_defectiveTokenChecked,questG07Myst,questG08Moxie,questESpClipper,questESpGore,questESpJunglePun,questESpFakeMedium,questESlMushStash,questESlAudit,questESlBacteria,questESlCheeseburger,questESlCocktail,questESlSprinkles,questESlSalt,questESlFish,questESlDebt,_pickyTweezersUsed,_bittycar,questESpSerum,questESpOutOfOrder,_shrubDecorated,questESpEVE,questESpSmokes,questG09Muscle,_rapidPrototypingUsed,nsTowerDoorKeysUsed,_chateauDeskHarvested,lastGoofballBuy,nsChallenge1,nsChallenge2,nsContestants1,nsContestants2,nsContestants3,lastDesertUnlock,questM18Swamp,edPiece,warehouseProgress,questEStFishTrash,questEStNastyBears,questEStSocialJusticeI,questEStSocialJusticeII,questEStSuperLuber,questEStZippityDooDah,_summonAnnoyanceUsed,questEStWorkWithFood,questM24Doc,questEStGiveMeFuel,_mayoTankSoaked,_feastUsed,spelunkyNextNoncombat,spelunkySacrifices,spelunkyStatus,spelunkyUpgrades,spelunkyWinCount,_deckCardsDrawn,_glarkCableUses,_banderRunaways,questM25Armorer,pyramidBombUsed,_powerPillUses,nextAdventure,_volcanoItem1,_volcanoItem2,_volcanoItem3,_barrelPrayer,questECoBucket,_machineTunnelsAdv,_snojoFreeFights,snojoSetting,_lastCombatStarted,batmanZone,batmanUpgrades,batmanTimeLeft,batmanStats,questLTTQuestByWire,questM26Oracle,sourceTerminalEducate1,sourceTerminalEducate2,sourceTerminalEnquiry,_sourceTerminalDigitizeUses,_sourceTerminalEnhanceUses,_sourceTerminalExtrudes,_detectiveCasesCompleted,_pottedTeaTreeUsed,lastIslandUnlock,falloutShelterChronoUsed,_timeSpinnerMinutesUsed,_lynyrdSnareUses,_noobSkillCount,_universeCalculated,_horsery,_expertCornerCutterUsed,boomBoxSong,_questPartyFair,_questPartyFairQuest,_neverendingPartyFreeTurns,_latteRefillsUsed,_latteBanishUsed,_latteCopyUsed,_latteDrinkUsed,_kgbTranquilizerDartUses,banishedMonsters,lastLightsOutTurn,lastVoteMonsterTurn,_lastCombatStarted,_sausageFights,_saberMod,_saberForceMonster,_daycareRecruits,_daycareGymScavenges,_campAwayCloudBuffs,_campAwaySmileBuffs,moonTuned,zeppelinProtestors,questL11Ron,questL11Shen,redSnapperPhylum,_canSeekBirds,questGuzzlr]; if (false) { diff --git a/Source/relay/Guide/Sections/Location Bar Popup.ash b/Source/relay/Guide/Sections/Location Bar Popup.ash index c436b4c5..adc844f4 100644 --- a/Source/relay/Guide/Sections/Location Bar Popup.ash +++ b/Source/relay/Guide/Sections/Location Bar Popup.ash @@ -106,6 +106,7 @@ buffer createItemInformationTableMethod2(int columns, LBPItemInformation [int] i output_buffer.append(" "); } output_buffer.append(info.item_name); + output_buffer.append(""); string [int] secondary_line; if (info.should_display_drop_base) @@ -137,7 +138,6 @@ buffer createItemInformationTableMethod2(int columns, LBPItemInformation [int] i output_buffer.append(HTMLGenerateTagSuffix(wrap_type)); } - output_buffer.append(""); output_buffer.append(""); } output_buffer.append(""); //row @@ -219,6 +219,7 @@ buffer generateItemInformationMethod2(location l, monster m, boolean try_for_min float effective_drop_rate = adjusted_base_drop_rate; float item_modifier = l.item_drop_modifier_for_location(); + Error error; if (it.fullness > 0 || (__items_that_craft_food contains it)) { item_modifier += numeric_modifier("Food Drop"); @@ -273,6 +274,10 @@ buffer generateItemInformationMethod2(location l, monster m, boolean try_for_min { item_modifier += 20.0 * MAX(1, get_property_int("skillLevel134")); } + if (l.environment == "underwater") //FIXME underwater drops are complicated and I'd have to look deeply into this to verify + { + //item_modifier -= l.pressurePenaltyForLocation(error); //pressure is actually already included in item_drop_modifier_for_location() + } if (item_is_pickpockable_only) { if (__misc_state["can pickpocket"]) @@ -336,7 +341,7 @@ buffer generateItemInformationMethod2(location l, monster m, boolean try_for_min effective_drop_rate = clampf(floor(effective_drop_rate), 0.0, 100.0); adjusted_base_drop_rate = effective_drop_rate; - if (l.environment == "underwater") //FIXME underwater drops are complicated and I'd have to look deeply into this to verify, so we just list a ? for now + if (error.was_error) adjusted_base_drop_rate = -1; } @@ -359,7 +364,7 @@ buffer generateItemInformationMethod2(location l, monster m, boolean try_for_min else if (adjusted_base_drop_rate < 100 || base_drop_rate < 100) { info.should_display_drop_current = true; - if (drop_rate_is_guess) + if (drop_rate_is_guess || l.environment == "underwater") info.item_drop_current_information = adjusted_base_drop_rate + "?%"; else info.item_drop_current_information = adjusted_base_drop_rate + "%"; @@ -653,11 +658,11 @@ static buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_location_name_is_centre_aligned) { buffer buf; + if (!__setting_enable_location_popup_box) + return buf; location l = __last_adventure_location; if (!__setting_location_bar_uses_last_location && !get_property_boolean("_relay_guide_setting_ignore_next_adventure_for_location_bar") && get_property_location("nextAdventure") != $location[none]) l = get_property_location("nextAdventure"); - if (!__setting_enable_location_popup_box) - return buf; string transition_time = "0.5s"; buf.append(HTMLGenerateTagWrap("div", "", mapMake("id", "r_location_popup_blackout", "style", "position:fixed;z-index:5;width:100%;height:100%;background:rgba(0,0,0,0.5);opacity:0;pointer-events:none;visibility:hidden;"))); @@ -666,8 +671,8 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca buf.append(HTMLGenerateTagPrefix("div", mapMake("id", "r_location_popup_box", "style", "height:auto;transition:bottom " + transition_time + ";z-index:5;opacity:0;pointer-events:none;bottom:-10000px", "class", "r_bottom_outer_container"))); buf.append(HTMLGenerateTagPrefix("div", mapMake("class", "r_bottom_inner_container", "style", "background:white;height:auto;"))); - float [monster] appearance_rates_adjusted = l.appearance_rates_adjusted(); - float [monster] appearance_rates_next_turn = l.appearance_rates(true); + float [monster] appearance_rates_adjusted = l.appearance_rates_adjusted(false).appearance_rates_cancel_nc(); + float [monster] appearance_rates_next_turn = l.appearance_rates_adjusted(true).appearance_rates_cancel_nc(); string [monster] monsters_that_we_cannot_encounter; if ($effect[Ancient Annoying Serpent Poison].have_effect() == 0) @@ -720,7 +725,20 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca } else if (evilness > 0) { - foreach m in $monsters[spiny skelelton,toothy sklelton] + foreach m in $monsters[spiny skelelton,toothy sklelton,party skelteon] + monsters_that_we_cannot_encounter[m] = "boss up"; + } + } + else if (l == $location[the defiled alcove]) + { + int evilness = __quest_state["Level 7"].state_int["alcove evilness"]; + if (evilness > 25) + { + monsters_that_we_cannot_encounter[$monster[conjoined zmombie]] = "evilness too high"; + } + else if (evilness > 0) + { + foreach m in $monsters[grave rober zmobie,corpulent zobmie,modern zmobie] monsters_that_we_cannot_encounter[m] = "boss up"; } } @@ -742,7 +760,6 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca monsters_that_we_cannot_encounter[m] = "ML based"; } } - //FIXME other defileds boolean banishes_are_possible = true; if ($locations[the secret government laboratory,sloppy seconds diner] contains l) @@ -752,29 +769,9 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca foreach m in appearance_rates_next_turn { - if (monsters_that_we_cannot_encounter contains m)// || m.is_banished()) + if (monsters_that_we_cannot_encounter contains m) remove appearance_rates_next_turn[m]; } - //l.appearance_rates(true) doesn't seem to take into account banished monsters, so correct: - appearance_rates_next_turn[$monster[none]] = 0.0; //ignore - float arnt_sum = 0.0; - foreach m, rate in appearance_rates_next_turn - { - if (m.is_banished() && banishes_are_possible) - appearance_rates_next_turn[m] = MIN(appearance_rates_next_turn[m], 0.0); - else if (rate > 0.0) - arnt_sum += appearance_rates_next_turn[m]; - } - if (arnt_sum != 100.0 && arnt_sum != 0.0) - { - float inverse = 1.0 / (arnt_sum / 100.0); - - foreach m, rate in appearance_rates_next_turn - { - if (rate > 0.0) - appearance_rates_next_turn[m] *= inverse; - } - } monster [int] monster_display_order; boolean rates_are_equal = true; @@ -790,7 +787,7 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca if (rate <= 0.0 && l == $location[Investigating a Plaintive Telegram]) continue; monster_display_order.listAppend(m); - if (rate > 0.0 && m != $monster[none]) + if (rate > 0.0) { if (last_rate == -1.0) last_rate = rate; @@ -800,7 +797,7 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca } } - if (next_rate > 0.0 && m != $monster[none]) + if (next_rate > 0.0) { if (last_next_rate == -1.0) last_next_rate = next_rate; @@ -856,14 +853,6 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca } }*/ - float rate_nc_cancel_multiplier = 1.0; - if (appearance_rates_adjusted[$monster[none]] > 0.0) - { - float divisor = (1.0 - appearance_rates_adjusted[$monster[none]] / 100.0); - if (divisor != 0.0) - rate_nc_cancel_multiplier = 1.0 / divisor; - } - boolean [monster] monsters_to_display_items_minimally; int item_minimal_display_limit = 6; foreach key, m in monster_display_order @@ -894,8 +883,8 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca if (m.image.length() == 0) monster_image_url = ""; ServerImageStats monster_image_stats = ServerImageStatsOfImageURL(monster_image_url); - float rate = appearance_rates_adjusted[m] * rate_nc_cancel_multiplier; - float next_rate = appearance_rates_next_turn[m]; //already normalised for monsters + float rate = appearance_rates_adjusted[m]; + float next_rate = appearance_rates_next_turn[m]; if (entries_displayed > 0) buf.append(HTMLGenerateTagPrefix("hr", mapMake("style", "margin:0px;"))); entries_displayed += 1; @@ -904,9 +893,9 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca boolean avoid_outputting_conditional = false; boolean monster_cannot_be_encountered = false; string reason_monster_cannot_be_encountered = ""; - if (m.is_banished() && banishes_are_possible) + if (rate == -3.0 && banishes_are_possible) //-3.0 => is (properly) banished { - monster_cannot_be_encountered = m.is_banished(); + monster_cannot_be_encountered = true; reason_monster_cannot_be_encountered = "banished"; } else if (monsters_that_we_cannot_encounter contains m) @@ -1014,47 +1003,13 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca //FIXME handle canceling NC buffer rate_buffer; - if (m.is_banished() && banishes_are_possible) - { - rate_buffer.append("banished"); - Banish banish_information = m.BanishForMonster(); - if (banish_information.banish_source != "") - { - rate_buffer.append(" by "); - rate_buffer.append(banish_information.banish_source); - } - if (banish_information.custom_reset_conditions != "") - { - rate_buffer.append(" until "); - rate_buffer.append(banish_information.custom_reset_conditions); - } - else if (banish_information.banish_turn_length == -1) - rate_buffer.append(" forever"); - else if (banish_information.banish_turn_length > 0) - { - int turns_left = banish_information.BanishTurnsLeft(); - rate_buffer.append(" for "); - rate_buffer.append(pluralise(turns_left, "more turn", "more turns")); - } - rate_buffer.append(" "); - avoid_outputting_conditional = true; - } - else if (m.attributes.contains_text("SEMIRARE")) - { + if (m.attributes.contains_text("SEMIRARE")) rate_buffer.append("semi-rare "); - avoid_outputting_conditional = true; - } else if (m.attributes.contains_text("ULTRARARE")) - { rate_buffer.append("ultra rare "); - avoid_outputting_conditional = true; - } else if (m.boss) - { rate_buffer.append("boss "); - avoid_outputting_conditional = true; - } - if (rate > 0 && !(m.is_banished() && banishes_are_possible) && !monster_cannot_be_encountered) + else if (rate > 0 && !monster_cannot_be_encountered) { if (!rates_are_equal) { @@ -1071,7 +1026,7 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca rate_buffer.append("%"); } } - else if (rate <= 0) + else if (rate <= 0 && !(m.is_banished() && banishes_are_possible)) { if (possible_alien_monsters contains m) rate_buffer.append("elsewhere"); @@ -1081,6 +1036,50 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca //seen values for rate: //0.0 for bosses //-1.0 for ultra-rares + //-3.0 for (properly) banished + if (m.is_banished() && banishes_are_possible) + { + Banish banish_information = m.BanishForMonster(); + if (rate == -3.0) + { + rate_buffer.append("banished"); + if (banish_information.banish_source != "") + { + rate_buffer.append(" by "); + rate_buffer.append(banish_information.banish_source); + } + if (banish_information.custom_reset_conditions != "") + { + rate_buffer.append(" until "); + rate_buffer.append(banish_information.custom_reset_conditions); + } + else if (banish_information.banish_turn_length == -1) + rate_buffer.append(" forever"); + else if (banish_information.banish_turn_length > 0) + { + int turns_left = banish_information.BanishTurnsLeft(); + rate_buffer.append(" for "); + rate_buffer.append(pluralise(turns_left, "more turn", "more turns")); + } + } + else if (rate > 0.0) + { + //monster was banished, but they are olfacting it (only base copies of the monsters are removed by banishes) + if (!rates_are_equal || !next_rates_are_equal) + rate_buffer.append("
"); + rate_buffer.append("banished"); + if (banish_information.banish_source != "") + { + rate_buffer.append(" by "); + rate_buffer.append(banish_information.banish_source); + } + //want to avoid cluttering, so don't show until when + rate_buffer.append("
"); + rate_buffer.append("brought back by copies".HTMLGenerateSpanOfClass("r_element_important")); + + } + rate_buffer.append(" "); + } if (rate_buffer.length() > 0) { @@ -1126,10 +1125,12 @@ buffer generateLocationPopup(float bottom_coordinates, boolean location_bar_loca if (m.max_meat > 0) { float average_meat = (m.min_meat + m.max_meat) * 0.5; - average_meat *= (1.0 + meat_drop_modifier() / 100.0); + Error error; + // float pressure_penalty = l.environment == "underwater" ? -l.pressurePenaltyForLocation(error) : 0.0; //already accounted for in meat_drop_modifier() + average_meat *= 1.0 + meat_drop_modifier() / 100.0; if (average_meat >= 25) //ignore really low amounts { - if (l.environment == "underwater") //FIXME calculate this properly + if (error.was_error) stats_l1.listAppend("? meat"); else stats_l1.listAppend(average_meat.round() + " meat"); diff --git a/Source/relay/Guide/Sections/Location Bar.ash b/Source/relay/Guide/Sections/Location Bar.ash index d1a4caf0..a59370e5 100644 --- a/Source/relay/Guide/Sections/Location Bar.ash +++ b/Source/relay/Guide/Sections/Location Bar.ash @@ -121,22 +121,22 @@ buffer generateLocationBar(boolean displaying_navbar) if (l == $location[domed city of ronaldus]) { int ronald_phase = moon_phase() % 8; - if (ronald_phase == 4) - custom_location_information = "30% aliens"; - else if (ronald_phase < 2 || ronald_phase > 6) + int ronald_darkness = abs(ronald_phase - 4); + int ronald_light = 4 - ronald_darkness; + if (ronald_light < 2) custom_location_information = "No aliens"; else - custom_location_information = "15% aliens"; + custom_location_information = (ronald_light * 8) + "% aliens"; } else if (l == $location[domed city of grimacia]) { int grimace_phase = moon_phase() / 2; - if (grimace_phase == 4) - custom_location_information = "30% aliens"; - else if (grimace_phase < 2 || grimace_phase > 6) + int grimace_darkness = abs(grimace_phase - 4); + int grimace_light = 4 - grimace_darkness; + if (grimace_light < 2) custom_location_information = "No aliens"; else - custom_location_information = "15% aliens"; + custom_location_information = (grimace_light * 8) + "% aliens"; } else if (l == $location[a-boo peak]) { @@ -224,7 +224,7 @@ buffer generateLocationBar(boolean displaying_navbar) custom_location_information = pluralise(__quest_state["Level 12"].state_int["frat boys left on battlefield"], "frat boy", "frat boys"); else if (l == $location[the battlefield (frat uniform)]) custom_location_information = pluralise(__quest_state["Level 12"].state_int["hippies left on battlefield"], "hippy", "hippies"); - else if ($locations[The Briny Deeps,The Brinier Deepers,The Briniest Deepests,An Octopus's Garden,The Wreck of the Edgar Fitzsimmons,Madness Reef,The Mer-Kin Outpost,The Skate Park,The Coral Corral,Mer-kin Colosseum,Mer-kin Library,Mer-kin Gymnasium,Mer-kin Elementary School,The Marinara Trench,Anemone Mine,The Dive Bar,The Caliginous Abyss] contains l || (l == $location[The Ice Hole] && l != $location[none])) + else if (l.environment == "underwater") { Error error; float pressure_penalty = l.pressurePenaltyForLocation(error); @@ -358,10 +358,12 @@ buffer generateLocationBar(boolean displaying_navbar) location_data.listAppend(pluralise(turns_spent, "turn", "turns")); } - //easy list: - //FIXME just use that test instead? + //easy list: $locations[Pump Up Muscle,Pump Up Mysticality,Pump Up Moxie,The Shore\, Inc. Travel Agency,Goat Party,Pirate Party,Lemon Party,The Roulette Tables,The Poker Room,Anemone Mine (Mining),The Knob Shaft (Mining),Friar Ceremony Location,Itznotyerzitz Mine (in Disguise),The Prince's Restroom,The Prince's Dance Floor,The Prince's Kitchen,The Prince's Balcony,The Prince's Lounge,The Prince's Canapes table,Portal to Terrible Parents,fernswarthy's basement] //ashq foreach l in $locations[] if (l.appearance_rates().count() == 1 && l.appearance_rates()[$monster[none]] == 100.0) print(l); - boolean [location] nc_blacklist = $locations[Pump Up Muscle,Pump Up Mysticality,Pump Up Moxie,The Shore\, Inc. Travel Agency,Goat Party,Pirate Party,Lemon Party,The Roulette Tables,The Poker Room,Anemone Mine (Mining),The Knob Shaft (Mining),Friar Ceremony Location,Itznotyerzitz Mine (in Disguise),The Prince's Restroom,The Prince's Dance Floor,The Prince's Kitchen,The Prince's Balcony,The Prince's Lounge,The Prince's Canapes table,Portal to Terrible Parents,fernswarthy's basement]; + boolean [location] nc_blacklist = {$location[fernswarthy's basement]:true}; + foreach l in $locations[] + if (l.appearance_rates().count() == 1 && l.appearance_rates()[$monster[none]] == 100.0) + nc_blacklist[l] = true; if ((my_buffedstat($stat[moxie]) < average_ml || my_path_id() == PATH_AVATAR_OF_SNEAKY_PETE) && sample_count > 0 && __misc_state["in run"] && monster_level_adjustment() < 100) { diff --git a/Source/relay/Guide/Sets/Misc Items.ash b/Source/relay/Guide/Sets/Misc Items.ash index 2926e3c1..d5fccde6 100644 --- a/Source/relay/Guide/Sets/Misc Items.ash +++ b/Source/relay/Guide/Sets/Misc Items.ash @@ -607,9 +607,12 @@ void SMiscItemsGenerateResource(ChecklistEntry [int] resource_entries) line += "."; resource_entries.listAppend(ChecklistEntryMake("__item vitachoconutriment capsule", "inventory.php?ftext=vitachoconutriment+capsule", ChecklistSubentryMake(pluralise($item[vitachoconutriment capsule]), "", line), importance_level_unimportant_item)); } - if (__misc_state["in run"] && lookupItem("tryptophan dart").available_amount() > 0 && in_ronin() && lookupItem("tryptophan dart").item_is_usable()) { + if (in_run && lookupItem("tryptophan dart").available_amount() > 0 && in_ronin() && lookupItem("tryptophan dart").item_is_usable()) { resource_entries.listAppend(ChecklistEntryMake("__item tryptophan dart", "", ChecklistSubentryMake(pluralise(lookupItem("tryptophan dart")), "", "Free run/banish."), 6).ChecklistEntryTagEntry("banish")); } + if (in_run && __misc_state["free runs usable"] && get_property_int("_humanMuskUses") < 3 && lookupItem("human musk").available_amount() > 0 && lookupItem("human musk") != $item[none]) { + resource_entries.listAppend(ChecklistEntryMake("__item human musk", "", ChecklistSubentryMake(MIN(lookupItem("human musk").available_amount(), 3 - get_property_int("_humanMuskUses")).pluralise("human musk", "human musks"), "", "Free run/banish. Consumes item."), 6).ChecklistEntryTagEntry("banish")); + } if ($item[drum machine].available_amount() > 0 && in_run && (my_adventures() <= 1 || (availableDrunkenness() < 0 && availableDrunkenness() > -4 && my_adventures() >= 1)) && __quest_state["Level 11 Desert"].state_boolean["Desert Explored"] && $item[drum machine].item_is_usable()) { //Daycount strategy that never works, suggest: diff --git a/Source/relay/Guide/Support/LocationAvailable.ash b/Source/relay/Guide/Support/LocationAvailable.ash index 4203e3a9..ae626505 100644 --- a/Source/relay/Guide/Support/LocationAvailable.ash +++ b/Source/relay/Guide/Support/LocationAvailable.ash @@ -9,23 +9,6 @@ import "relay/Guide/Settings.ash" import "relay/Guide/QuestState.ash" -//Version compatibility locations: - -boolean __location_compatibility_inited = false; -//Should probably be called manually, as a backup: -void locationCompatibilityInit() -{ - //Different versions refer to locations by different names. - //For instance, pre-13878 versions refer to the palindome as "The Palindome". Versions after that refer it to "Inside the Palindome". - //This method provides correct lookups for both versions, without warnings. - if (__location_compatibility_inited) - return; - __location_compatibility_inited = true; - -} - -locationCompatibilityInit(); //not sure if calling functions like this is intended. may break in the future? - boolean [location] __la_location_is_available; boolean [string] __la_zone_is_unlocked; @@ -33,73 +16,29 @@ boolean __la_commons_were_inited = false; int __la_turncount_initialised_on = -1; -//Takes into account banishes and olfactions. -//Probably will be inaccurate in many corner cases, sorry. -//There's an appearance_rates() function that takes into account queue effects, which we may consider using in the future? -float [monster] appearance_rates_adjusted(location l) +float [monster] appearance_rates_adjusted(location l, boolean account_for_queue) { - boolean appearance_rates_has_changed = mafiaIsPastRevision(14740); //not sure on the revision, but after a certain revision, appearance_rates() takes into account olfaction - //FIXME domed city of ronald/grimacia doesn't take into account alien appearance rate - float [monster] source = l.appearance_rates(); - - if (l == $location[the sleazy back alley]) //FIXME is mafia's data files incorrect, or the wiki's? - source[$monster[none]] = MIN(MAX(0, 20 - combat_rate_modifier()), 100); - - float minimum_monster_appearance = 1000000000.0; - foreach m in source - { - if (m == $monster[none]) - continue; - float v = source[m]; - if (v > 0.0) - { - if (v < minimum_monster_appearance) - minimum_monster_appearance = v; - } - } - - float [monster] source_altered; - foreach m in source - { - float v = source[m]; - if (m == $monster[none]) - { - if (v < 0.0) - source_altered[m] = 0.0; - else - source_altered[m] = v; - } - else - source_altered[m] = v / minimum_monster_appearance; - } + float [monster] source = l.appearance_rates(account_for_queue); - // @todo Update this once mafia is fixed. - if (($locations[The Dark Elbow of the Woods,The Dark Heart of the Woods,The Dark Neck of the Woods] contains l)) { - source_altered[$monster[none]] = 0.05; - } - boolean lawyers_relocated = get_property_ascension("relocatePygmyLawyer"); boolean janitors_relocated = get_property_ascension("relocatePygmyJanitor"); if (l == $location[the hidden park]) { - if (janitors_relocated) - source_altered[$monster[pygmy janitor]] = 1.0; - else if (source_altered contains $monster[pygmy janitor]) - remove source_altered[$monster[pygmy janitor]]; - if (lawyers_relocated) - source_altered[$monster[pygmy witch lawyer]] = 1.0; - else if (source_altered contains $monster[pygmy witch lawyer]) - remove source_altered[$monster[pygmy witch lawyer]]; + if (!janitors_relocated && source contains $monster[pygmy janitor]) + remove source[$monster[pygmy janitor]]; + if (!lawyers_relocated && source contains $monster[pygmy witch lawyer]) + remove source[$monster[pygmy witch lawyer]]; } if (($locations[The Hidden Apartment Building,The Hidden Bowling Alley,The Hidden Hospital,The Hidden Office Building] contains l)) { - if (janitors_relocated && (source_altered contains $monster[pygmy janitor])) - remove source_altered[$monster[pygmy janitor]]; - if (lawyers_relocated && (source_altered contains $monster[pygmy witch lawyer])) - remove source_altered[$monster[pygmy witch lawyer]]; + if (janitors_relocated && (source contains $monster[pygmy janitor])) + remove source[$monster[pygmy janitor]]; + if (lawyers_relocated && (source contains $monster[pygmy witch lawyer])) + remove source[$monster[pygmy witch lawyer]]; } if ($locations[domed city of grimacia,domed city of ronaldus] contains l) { + //appearance_rates() currently doesn't handle the relation between aliens and moonlight boolean [monster] aliens; boolean [monster] survivors; float actual_percent_aliens = 0.0; @@ -110,63 +49,52 @@ float [monster] appearance_rates_adjusted(location l) aliens = $monsters[cat-alien,dog-alien,alielf]; survivors = $monsters[unhinged survivor,grizzled survivor,whiny survivor]; int grimace_phase = moon_phase() / 2; - if (grimace_phase == 4) - actual_percent_aliens = 0.3; - else if (grimace_phase < 2 || grimace_phase > 6) + int grimace_darkness = abs(grimace_phase - 4); + int grimace_light = 4 - grimace_darkness; + if (grimace_light < 2) actual_percent_aliens = 0.0; else - actual_percent_aliens = 0.15; + actual_percent_aliens = 8.0 * grimace_light; } else { aliens = $monsters[dogcat,hamsterpus,ferrelf]; survivors = $monsters[unlikely survivor,overarmed survivor,primitive survivor]; int ronald_phase = moon_phase() % 8; - if (ronald_phase == 4) - actual_percent_aliens = 0.3; - else if (ronald_phase < 2 || ronald_phase > 6) + int ronald_darkness = abs(ronald_phase - 4); + int ronald_light = 4 - ronald_darkness; + if (ronald_light < 2) actual_percent_aliens = 0.0; else - actual_percent_aliens = 0.15; + actual_percent_aliens = 8.0 * ronald_light; } //Readjust: - float source_percent_aliens = 0.0; - float source_percent_survivors = 0.0; - foreach m, rate in source_altered + if (actual_percent_aliens == 0.0) { - if (aliens contains m) + foreach m, rate in source { - if (actual_percent_aliens == 0.0) - remove source_altered[m]; - source_percent_aliens += rate; + if (aliens contains m) + remove source[m]; } - if (survivors contains m) - source_percent_survivors += rate; } - //Readjust: - - foreach m, rate in source_altered + else { - float adjusted_rate = rate; - if (aliens contains m) + float source_percent_aliens = 0.0; + float source_percent_survivors = 0.0; + foreach m, rate in source { - if (actual_percent_aliens == 0.0 || source_percent_aliens == 0.0) - { - adjusted_rate = 0.0; - } - else - { - adjusted_rate = rate / source_percent_aliens * actual_percent_aliens; - } + if (aliens contains m) + source_percent_aliens += rate; + if (survivors contains m) + source_percent_survivors += rate; } - if (survivors contains m) + foreach m, rate in source { - if (source_percent_survivors == 0.0) - adjusted_rate = rate; //bugged, but don't change anything - else - adjusted_rate = rate / source_percent_survivors * (1.0 - actual_percent_aliens); + if (aliens contains m && source_percent_aliens != 0.0) + source[m] = rate / source_percent_aliens * actual_percent_aliens; + if (survivors contains m && source_percent_survivors != 0.0) + source[m] = rate / source_percent_survivors * (100.0 - actual_percent_aliens); } - source_altered[m] = adjusted_rate; } } @@ -191,119 +119,127 @@ float [monster] appearance_rates_adjusted(location l) { if (monsters_not_to_remove contains m) continue; - remove source_altered[m]; + remove source[m]; } } - boolean banishes_are_possible = true; - if ($locations[the secret government laboratory,sloppy seconds diner] contains l) - banishes_are_possible = false; - if (banishes_are_possible) + + //change the NC rate manually when we suspect mafia got it wrong + float original_combat_rate = 100.0 - source[$monster[none]]; + float new_combat_rate = -1.0; + + if (l == $location[the sleazy back alley]) //FIXME is mafia's data files incorrect, or the wiki's? + new_combat_rate = clampf(80.0 + combat_rate_modifier(), 0, 100); + + // @todo Update this once mafia is fixed. + if ($locations[The Dark Elbow of the Woods,The Dark Heart of the Woods,The Dark Neck of the Woods] contains l) + new_combat_rate = clampf(95.0 + combat_rate_modifier(), 0, 100); + + if (l == $location[Inside the Palindome]) + if (!questPropertyPastInternalStepNumber("questL11Palindome", 3)) + new_combat_rate = 100.0; + + //Readjust: + if (new_combat_rate == 0.0) { - foreach m in source_altered - { - if (m.is_banished()) - source_altered[m] = 0.0; - } + foreach m, rate in source + if (rate > 0.0) + source[m] = 0.0; + source[$monster[none]] = 100.0; } - - //umm... I'm not sure if appearance_rates() takes into account olfact all the time or not - //in the palindome, it didn't for some reason? but in another area I think it did. can't remember - /* - > get olfactedMonster - bob racecar - > ash $effect[on the trail].have_effect() - Returned: 35 - > ash $location[inside the palindome].appearance_rates() - Returned: aggregate float [monster] - Bob Racecar => 9.0 - Dr. Awkward => 0.0 - Drab Bard => 9.0 - Evil Olive => -3.0 - Flock of Stab-Bats => 9.0 - none => 55.0 - Racecar Bob => 9.0 - Taco Cat => 9.0 - Tan Gnat => -3.0 - */ - //so, if appearance_rate() doesn't seem to be taking into account olfaction, force it? - if ($effect[on the trail].have_effect() > 0 && get_property("olfactedMonster").to_monster() != $monster[none]) + else if (original_combat_rate != new_combat_rate && new_combat_rate > 0.0 && original_combat_rate > 0.0) { - monster olfacted_monster = get_property("olfactedMonster").to_monster(); - if (source_altered contains olfacted_monster) + source[$monster[none]] = 100.0 - new_combat_rate; + + float ratio = new_combat_rate / original_combat_rate; + foreach m, rate in source { - if (fabs(source_altered[olfacted_monster] - 1.0) < 0.01) - appearance_rates_has_changed = false; + if (m == $monster[none]) + continue; + if (rate > 0.0) + source[m] = rate * ratio; } } - if ($effect[on the trail].have_effect() > 0 && !appearance_rates_has_changed) + //for monsters which always appear every X adventures, which mafia returns as 0 when not about to get them. + //Currently doesn't support cases when mafia is not aware that the encounter is periodically scheduled. Currently "peanut" from the calaginous abyss + void averagePediodicSuperlikely(monster superlikely_monster, int frequency) { - monster olfacted_monster = get_property("olfactedMonster").to_monster(); - if (olfacted_monster != $monster[none]) + float combat_rate = clampf(100.0 - source[$monster[none]], 0.0, 100.0); + if (combat_rate == 0.0) return; + if (source[superlikely_monster] != 0) return; + + float superlikely_average_occurence = 1.0 / frequency; + source[superlikely_monster] = superlikely_average_occurence * combat_rate; + //If, let's say, we have 4 monsters (25% occurence), with a superlikely occuring every 2 turns (1 / 2 = 50%) + //the 4 monsters' 25% (obviously giving 100%) + the SL's 50% give 150% combat chance: 3/2 the combat rate. + //if we divide the 4 monsters' rate by 3/2, we get 16.6. Not quite. + //To get them to 12.5% (which, when *4, gives 50%, which, when added the SL's rate, equals the combat rate), + //we say that the ratio is 1 + (1 / (x-1)) + //here this gives 1 + (1 / (2-1)) = 200% = 2/1 the combat rate + //25% (the 4 monsters' appearance rate) / (2/1) = 12.5% + float excess_ratio = 1.0 + 1.0 / (frequency - 1); + + foreach m, v in source { - if (source_altered contains olfacted_monster) - source_altered[olfacted_monster] += 3.0; //FIXME is this correct? + if (m == $monster[none] || m == superlikely_monster) + continue; + if (v > 0.0) + source[m] = v / excess_ratio * combat_rate / 100.0; } } + + if ($locations[Guano Junction,the Batrat and Ratbat Burrow,the Beanbat Chamber] contains l) + $monster[screambat].averagePediodicSuperlikely(8); + if (l == $location[kokomo resort]) + $monster[Brick Mulligan, the Bartender].averagePediodicSuperlikely(25); + + if (l == $location[The Post-Mall]) + $monster[sentient ATM].averagePediodicSuperlikely(11); - //Convert source_altered to source. - if (l == $location[Inside the Palindome]) - { - if (!questPropertyPastInternalStepNumber("questL11Palindome", 3)) - source_altered[$monster[none]] = 0.0; - } - float total = 0.0; - float nc_rate = clampf(source_altered[$monster[none]], 0.0, 100.0); - float combat_rate = clampf(100.0 - nc_rate, 0.0, 100.0); - foreach m in source_altered + return source; +} + +float [monster] appearance_rates_adjusted(location l) +{ + return appearance_rates_adjusted(l, false); +} + + +float [monster] appearance_rates_cancel_nc(float [monster] base_rates) +{ + if (base_rates[$monster[none]] == 100.0) return base_rates; + + float combat_rate_sum = 0.0; + foreach m, rate in base_rates { - float v = source_altered[m]; if (m == $monster[none]) continue; - if (v > 0) - total += v; - } - if ($locations[Guano Junction,the Batrat and Ratbat Burrow,the Beanbat Chamber] contains l) - { - //hacky, probably wrong: - float v = total / 8.0; - source_altered[$monster[screambat]] = v; - total += v; + if (rate > 0.0) + combat_rate_sum += rate; } - //oil peak goes here? - if (total > 0.0) + if (combat_rate_sum != 100.0 && combat_rate_sum != 0.0) { - foreach m in source_altered + float divisor = combat_rate_sum / 100.0; + + foreach m, rate in base_rates { if (m == $monster[none]) continue; - float v = source_altered[m]; - source_altered[m] = v / total * combat_rate; + if (rate > 0.0) + base_rates[m] /= divisor; } } - return source_altered; + return base_rates; } - float [monster] appearance_rates_adjusted_cancel_nc(location l) { float [monster] base_rates = appearance_rates_adjusted(l); - float nc_rate = base_rates[$monster[none]] / 100.0; - float nc_inverse_multiplier = 1.0; - if (nc_rate != 1.0) - nc_inverse_multiplier = 1.0 / (1.0 - nc_rate); - foreach m in base_rates - { - if (m == $monster[none]) - base_rates[m] = 0.0; - else - base_rates[m] *= nc_inverse_multiplier; - } - return base_rates; + return base_rates.appearance_rates_cancel_nc(); } //Do not call - internal implementation detail.