Skip to content

Commit e63094d

Browse files
authored
Merge pull request #2945 from UmedMuzl/nefarious
2 parents 389ac17 + 695e075 commit e63094d

File tree

17 files changed

+1114
-105
lines changed

17 files changed

+1114
-105
lines changed

__init__.py

Lines changed: 486 additions & 17 deletions
Large diffs are not rendered by default.

archipelago.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"minimum_ap_version": "0.6.4",
3-
"world_version": "1.4.16",
3+
"world_version": "1.4.17",
44
"authors": ["2dos", "AlmostSeagull", "Ballaam", "Green Bean", "Killklli", "Lrauq", "PoryGone", "Umed"],
55
"version": 7,
66
"compatible_version": 7,

archipelago/FillSettings.py

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
from randomizer.Enums.SwitchTypes import SwitchType
5757
from randomizer.Enums.Switches import Switches
5858
from randomizer.Lists.Switches import SwitchInfo
59-
from archipelago.Options import Goal, SwitchSanity, SelectStartingKong
59+
from archipelago.Options import Goal, SwitchSanity, SelectStartingKong, GalleonWaterLevel
6060
from archipelago.Goals import GOAL_MAPPING, QUANTITY_GOALS, calculate_quantity
6161
from archipelago.Logic import logic_item_name_to_id
6262

@@ -128,7 +128,6 @@ def get_default_settings() -> dict:
128128
"filler_items_selected": [ItemRandoFiller.junkitem],
129129
"free_trade_setting": True,
130130
"fungi_time": FungiTimeSetting.dusk,
131-
"galleon_water": GalleonWaterSetting.raised,
132131
"generate_spoilerlog": True,
133132
"hard_bosses_selected": [],
134133
"hard_mode_selected": [],
@@ -194,7 +193,6 @@ def get_default_settings() -> dict:
194193
"krool_phase_order_rando": True,
195194
"krool_random": False,
196195
"less_fragile_boulders": True,
197-
"level_randomization": LevelRandomization.level_order_complex,
198196
"logic_type": LogicType.glitchless,
199197
"maximize_helm_blocker": True,
200198
"medal_cb_req": 40,
@@ -317,6 +315,7 @@ def apply_archipelago_settings(settings_dict: dict, options, multiworld) -> None
317315
settings_dict["krool_in_boss_pool"] = options.krool_in_boss_pool.value
318316
settings_dict["helm_phase_count"] = options.helm_phase_count.value
319317
settings_dict["krool_phase_count"] = options.krool_phase_count.value
318+
settings_dict["level_randomization"] = LevelRandomization.loadingzone if options.loading_zone_rando.value else LevelRandomization.level_order_complex
320319

321320
# Medal distribution settings
322321
if options.medal_distribution.value == 0: # pre_selected
@@ -337,6 +336,12 @@ def apply_archipelago_settings(settings_dict: dict, options, multiworld) -> None
337336
if options.enable_cutscenes.value:
338337
settings_dict["more_cutscene_skips"] = ExtraCutsceneSkips.press
339338
settings_dict["alt_minecart_mayhem"] = options.alternate_minecart_mayhem.value
339+
if options.galleon_water_level == GalleonWaterLevel.option_lowered:
340+
settings_dict["galleon_water"] = GalleonWaterSetting.lowered
341+
elif options.galleon_water_level == GalleonWaterLevel.option_raised:
342+
settings_dict["galleon_water"] = GalleonWaterSetting.raised
343+
else:
344+
settings_dict["galleon_water"] = GalleonWaterSetting.vanilla
340345

341346

342347
def apply_blocker_settings(settings_dict: dict, options) -> None:
@@ -741,6 +746,66 @@ def apply_minigame_settings(settings_dict: dict, options, multiworld) -> None:
741746
settings_dict["bonus_barrel_auto_complete"] = options.auto_complete_bonus_barrels.value and options.goal.value != Goal.option_bonuses
742747
settings_dict["helm_room_bonus_count"] = HelmBonuses(options.helm_room_bonus_count.value)
743748

749+
# Map crown door and coin door settings
750+
crown_door_mapping = {
751+
0: HelmDoorItem.vanilla,
752+
1: HelmDoorItem.opened,
753+
2: HelmDoorItem.medium_random,
754+
3: HelmDoorItem.req_gb,
755+
4: HelmDoorItem.req_bp,
756+
5: HelmDoorItem.req_companycoins,
757+
6: HelmDoorItem.req_key,
758+
7: HelmDoorItem.req_medal,
759+
8: HelmDoorItem.req_crown,
760+
9: HelmDoorItem.req_fairy,
761+
10: HelmDoorItem.req_rainbowcoin,
762+
11: HelmDoorItem.req_bean,
763+
12: HelmDoorItem.req_pearl,
764+
13: HelmDoorItem.easy_random,
765+
14: HelmDoorItem.hard_random,
766+
}
767+
768+
coin_door_mapping = {
769+
0: HelmDoorItem.vanilla,
770+
1: HelmDoorItem.opened,
771+
2: HelmDoorItem.medium_random,
772+
3: HelmDoorItem.req_gb,
773+
4: HelmDoorItem.req_bp,
774+
6: HelmDoorItem.req_key,
775+
7: HelmDoorItem.req_medal,
776+
8: HelmDoorItem.req_crown,
777+
9: HelmDoorItem.req_fairy,
778+
10: HelmDoorItem.req_rainbowcoin,
779+
11: HelmDoorItem.req_bean,
780+
12: HelmDoorItem.req_pearl,
781+
13: HelmDoorItem.easy_random,
782+
14: HelmDoorItem.hard_random,
783+
}
784+
785+
# Map door item type to the key name in helm_door_item_count dict
786+
door_item_to_key = {
787+
3: "golden_bananas", # req_gb
788+
4: "blueprints", # req_bp
789+
5: "company_coins", # req_companycoins
790+
6: "keys", # req_key
791+
7: "medals", # req_medal
792+
8: "crowns", # req_crown
793+
9: "fairies", # req_fairy
794+
10: "rainbow_coins", # req_rainbowcoin
795+
11: "bean", # req_bean
796+
12: "pearls", # req_pearl
797+
}
798+
799+
settings_dict["crown_door_item"] = crown_door_mapping.get(options.crown_door_item.value, HelmDoorItem.opened)
800+
# Get count from dict based on selected item, default to 1 if not found
801+
crown_item_key = door_item_to_key.get(options.crown_door_item.value)
802+
settings_dict["crown_door_item_count"] = options.helm_door_item_count.value.get(crown_item_key, 1) if crown_item_key else 1
803+
804+
settings_dict["coin_door_item"] = coin_door_mapping.get(options.coin_door_item.value, HelmDoorItem.opened)
805+
# Get count from dict based on selected item, default to 1 if not found
806+
coin_item_key = door_item_to_key.get(options.coin_door_item.value)
807+
settings_dict["coin_door_item_count"] = options.helm_door_item_count.value.get(coin_item_key, 1) if coin_item_key else 1
808+
744809
if hasattr(multiworld, "generation_is_fake"):
745810
if hasattr(multiworld, "re_gen_passthrough"):
746811
if "Donkey Kong 64" in multiworld.re_gen_passthrough:
@@ -759,10 +824,8 @@ def handle_fake_generation_settings(settings: Settings, multiworld) -> None:
759824

760825
# Switch logic lifted out of level shuffle due to static levels for UT
761826
if settings.alter_switch_allocation:
762-
allocation = [1, 1, 1, 1, 2, 2, 3, 3]
763827
for x in range(8):
764-
level = settings.level_order[x + 1]
765-
settings.switch_allocation[level] = allocation[x]
828+
settings.switch_allocation[x] = passthrough["SlamLevels"][x]
766829

767830
settings.starting_kong_list = passthrough["StartingKongs"]
768831
settings.starting_kong = settings.starting_kong_list[0] # fake a starting kong so that we don't force a different kong

archipelago/Hints.py

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
from randomizer.Enums.Maps import Maps
66
from randomizer.Enums.Kongs import Kongs
77
from randomizer.Enums.Levels import Levels
8+
from randomizer.Enums.Transitions import Transitions
9+
from randomizer.Enums.Types import BarrierItems
10+
from randomizer.Lists.ShufflableExit import ShufflableExits
811
from randomizer.Lists.WrinklyHints import UpdateHint
912

1013
boss_names = {
@@ -139,6 +142,21 @@ def CompileArchipelagoHints(world, hint_data: list):
139142
hint_location_pairs.append((krool_hint, None)) # K. Rool hints don't have a specific location
140143
hints_remaining -= 1
141144

145+
# Isles to Helm transition hint (only if loading zone rando is enabled and Helm is shuffled)
146+
if world.options.loading_zone_rando != 0 and world.options.shuffle_helm_level_order:
147+
isles_to_helm_hint = parseIslesToHelmHint(world)
148+
compiled_hints.append(isles_to_helm_hint)
149+
hint_location_pairs.append((isles_to_helm_hint, None)) # Transition hints don't have a specific location
150+
hints_remaining -= 1
151+
152+
# Helm Door hints (only if one or both doors were set to random)
153+
if world.options.crown_door_item.value in [13, 2, 14] or world.options.coin_door_item.value in [13, 2, 14]:
154+
helm_door_hints = parseHelmDoorHint(world)
155+
for helm_door_hint in helm_door_hints:
156+
compiled_hints.append(helm_door_hint)
157+
hint_location_pairs.append((helm_door_hint, None)) # Helm door hints don't have a specific location
158+
hints_remaining -= 1
159+
142160
# Kong hints
143161
for kong_loc in kong_locations:
144162
kong_hint = parseKongHint(world, kong_loc)
@@ -194,7 +212,6 @@ def CompileArchipelagoHints(world, hint_data: list):
194212
# Sanity check that 35 hints were placed
195213
if hints_remaining > 0:
196214
# This part of the code should not be reached.
197-
print("Not enough hints. Please wait. stage_generate_output might be crashing.")
198215
while hints_remaining > 0:
199216
filler_hint = "no hint, sorry...".upper()
200217
compiled_hints.append(filler_hint)
@@ -319,3 +336,90 @@ def parseKRoolHint(world):
319336
if letter not in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?:;'S-()% \x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d":
320337
text = text.replace(letter, " ")
321338
return text
339+
340+
341+
def parseIslesToHelmHint(world):
342+
"""Write a hint for finding the transition that leads to Hideout Helm."""
343+
text = ""
344+
# Check if entrance randomization is enabled
345+
if hasattr(world.spoiler, "shuffled_exit_data") and world.spoiler.shuffled_exit_data:
346+
# Find which transition leads to Hideout Helm
347+
source_transition = None
348+
for transition, shuffled_back in world.spoiler.shuffled_exit_data.items():
349+
# Check if this transition's destination is Hideout Helm
350+
if shuffled_back.reverse == Transitions.HelmToIsles:
351+
source_transition = transition
352+
break
353+
354+
if source_transition and source_transition in ShufflableExits:
355+
pathToHint = source_transition
356+
# Don't hint entrances from connector rooms, follow the reverse pathway back until finding a non-connector
357+
while ShufflableExits[pathToHint].category is None:
358+
originPaths = [x for x, back in world.spoiler.shuffled_exit_data.items() if back.reverse == pathToHint]
359+
# In a few cases, there is no reverse loading zone. In this case we must keep the original path to hint
360+
if len(originPaths) == 0:
361+
break
362+
pathToHint = originPaths[0]
363+
364+
source_name = ShufflableExits[pathToHint].name
365+
text = f"Looking for \x04Hideout Helm\x04? Try going from \x08{source_name}\x08.".upper()
366+
367+
for letter in text:
368+
if letter not in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?:;'S-()% \x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d":
369+
text = text.replace(letter, " ")
370+
return text
371+
372+
373+
def parseHelmDoorHint(world):
374+
"""Write hints for the Helm door requirements if they're randomized."""
375+
# Map BarrierItems to display names (singular)
376+
item_names_singular = {
377+
BarrierItems.GoldenBanana: "Golden Banana",
378+
BarrierItems.Blueprint: "Blueprint",
379+
BarrierItems.CompanyCoin: "Special Coin",
380+
BarrierItems.Key: "Key",
381+
BarrierItems.Medal: "Medal",
382+
BarrierItems.Crown: "Crown",
383+
BarrierItems.Fairy: "Fairy",
384+
BarrierItems.RainbowCoin: "Rainbow Coin",
385+
BarrierItems.Bean: "Bean",
386+
BarrierItems.Pearl: "Pearl",
387+
}
388+
389+
crown_door_item = world.spoiler.settings.crown_door_item
390+
crown_door_count = world.spoiler.settings.crown_door_item_count
391+
coin_door_item = world.spoiler.settings.coin_door_item
392+
coin_door_count = world.spoiler.settings.coin_door_item_count
393+
394+
crown_door_randomized = world.options.crown_door_item.value in [13, 2, 14] # easy, medium, hard random
395+
coin_door_randomized = world.options.coin_door_item.value in [13, 2, 14]
396+
397+
hints = []
398+
399+
if crown_door_randomized:
400+
crown_name = item_names_singular.get(crown_door_item, "item")
401+
if crown_door_count > 1:
402+
if crown_door_item == BarrierItems.Fairy:
403+
crown_name = "Fairies"
404+
else:
405+
crown_name = crown_name + "s"
406+
text = f"There lies a \x05gate in Hideout Helm\x05 that requires \x04{crown_door_count} {crown_name}\x04.".upper()
407+
for letter in text:
408+
if letter not in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?:;'S-()% \x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d":
409+
text = text.replace(letter, " ")
410+
hints.append(text)
411+
412+
if coin_door_randomized:
413+
coin_name = item_names_singular.get(coin_door_item, "item")
414+
if coin_door_count > 1:
415+
if coin_door_item == BarrierItems.Fairy:
416+
coin_name = "Fairies"
417+
else:
418+
coin_name = coin_name + "s"
419+
coin_text = f"There lies a \x05gate in Hideout Helm\x05 that requires \x04{coin_door_count} {coin_name}\x04.".upper()
420+
for letter in coin_text:
421+
if letter not in "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?:;'S-()% \x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d":
422+
coin_text = coin_text.replace(letter, " ")
423+
hints.append(coin_text)
424+
425+
return hints

0 commit comments

Comments
 (0)