diff --git a/MMBN3Client.py b/MMBN3Client.py index 4945d492..bdf14274 100644 --- a/MMBN3Client.py +++ b/MMBN3Client.py @@ -290,12 +290,9 @@ async def gba_sync_task(ctx: MMBN3Context): async def run_game(romfile): - options = Utils.get_options().get("mmbn3_options", None) - if options is None: - auto_start = True - else: - auto_start = options.get("rom_start", True) - if auto_start: + from worlds.mmbn3 import MMBN3World + auto_start = MMBN3World.settings.rom_start + if auto_start is True: import webbrowser webbrowser.open(romfile) elif os.path.isfile(auto_start): diff --git a/data/lua/connector_mmbn3.lua b/data/lua/connector_mmbn3.lua index fce38a4c..c89f428f 100644 --- a/data/lua/connector_mmbn3.lua +++ b/data/lua/connector_mmbn3.lua @@ -477,7 +477,7 @@ function main() elseif (curstate == STATE_UNINITIALIZED) then -- If we're uninitialized, attempt to make the connection. if (frame % 120 == 0) then - server:settimeout(2) + server:settimeout(120) local client, timeout = server:accept() if timeout == nil then print('Initial Connection Made') diff --git a/worlds/mmbn3/Rom.py b/worlds/mmbn3/Rom.py index 79da50e5..347375c5 100644 --- a/worlds/mmbn3/Rom.py +++ b/worlds/mmbn3/Rom.py @@ -185,7 +185,7 @@ class TextArchive: # As far as I know, this should literally not be possible. # Every script I've looked at has dozens of unused indices, so finding 9 (8 plus one "ending" script) # should be no problem. We re-use these so we don't have to worry about an area getting tons of these - raise AssertionError("Error in generation -- not enough room for progressive undernet in archive "+self.startOffset) + raise AssertionError(f"Error in generation -- not enough room for progressive undernet in archive {self.startOffset} ({hex(self.startOffset)})") for i in range(9): # There are 8 progressive undernet ranks new_script_index = self.unused_indices[i] new_script = ArchiveScript(new_script_index, generate_progressive_undernet(i, self.unused_indices[i+1])) @@ -319,15 +319,16 @@ class MMBN3DeltaPatch(APDeltaPatch): def get_base_rom_path(file_name: str = "") -> str: - options = Utils.get_options() if not file_name: - bn3_options = options.get("mmbn3_options", None) + from worlds.mmbn3 import MMBN3World + bn3_options = MMBN3World.settings + if bn3_options is None: file_name = "Mega Man Battle Network 3 - Blue Version (USA).gba" else: file_name = bn3_options["rom_file"] if not os.path.exists(file_name): - file_name = Utils.local_path(file_name) + file_name = Utils.user_path(file_name) return file_name diff --git a/worlds/mmbn3/__init__.py b/worlds/mmbn3/__init__.py index 507ddbc2..80716977 100644 --- a/worlds/mmbn3/__init__.py +++ b/worlds/mmbn3/__init__.py @@ -1,7 +1,6 @@ import os import settings import typing -import threading from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification, Region, Entrance, \ LocationProgressType @@ -16,7 +15,7 @@ from .Options import MMBN3Options from .Regions import regions, RegionName from .Names.ItemName import ItemName from .Names.LocationName import LocationName -from worlds.generic.Rules import add_item_rule, add_rule +from worlds.generic.Rules import add_item_rule, add_rule, forbid_item class MMBN3Settings(settings.Group): @@ -26,8 +25,15 @@ class MMBN3Settings(settings.Group): description = "MMBN3 ROM File" md5s = [MMBN3DeltaPatch.hash] + class RomStart(str): + """ + Set this to false to never autostart a rom (such as after patching), + true for operating system default program + Alternatively, a path to a program to open the .gba file with + """ + rom_file: RomFile = RomFile(RomFile.copy_to) - rom_start: bool = True + rom_start: RomStart | bool = True class MMBN3Web(WebWorld): @@ -203,134 +209,134 @@ class MMBN3World(World): # Set WWW ID requirements def has_www_id(state): return state.has(ItemName.WWW_ID, self.player) - add_rule(self.multiworld.get_location(LocationName.ACDC_1_PMD, self.player), has_www_id) - add_rule(self.multiworld.get_location(LocationName.SciLab_1_WWW_BMD, self.player), has_www_id) - add_rule(self.multiworld.get_location(LocationName.Yoka_1_WWW_BMD, self.player), has_www_id) - add_rule(self.multiworld.get_location(LocationName.Undernet_1_WWW_BMD, self.player), has_www_id) + add_rule(self.get_location(LocationName.ACDC_1_PMD), has_www_id) + add_rule(self.get_location(LocationName.SciLab_1_WWW_BMD), has_www_id) + add_rule(self.get_location(LocationName.Yoka_1_WWW_BMD), has_www_id) + add_rule(self.get_location(LocationName.Undernet_1_WWW_BMD), has_www_id) # Set Press Program requirements def has_press(state): return state.has(ItemName.Press, self.player) - add_rule(self.multiworld.get_location(LocationName.Yoka_1_PMD, self.player), has_press) - add_rule(self.multiworld.get_location(LocationName.Yoka_2_Upper_BMD, self.player), has_press) - add_rule(self.multiworld.get_location(LocationName.Beach_2_East_BMD, self.player), has_press) - add_rule(self.multiworld.get_location(LocationName.Hades_South_BMD, self.player), has_press) - add_rule(self.multiworld.get_location(LocationName.Secret_3_BugFrag_BMD, self.player), has_press) - add_rule(self.multiworld.get_location(LocationName.Secret_3_Island_BMD, self.player), has_press) + add_rule(self.get_location(LocationName.Yoka_1_PMD), has_press) + add_rule(self.get_location(LocationName.Yoka_2_Upper_BMD), has_press) + add_rule(self.get_location(LocationName.Beach_2_East_BMD), has_press) + add_rule(self.get_location(LocationName.Hades_South_BMD), has_press) + add_rule(self.get_location(LocationName.Secret_3_BugFrag_BMD), has_press) + add_rule(self.get_location(LocationName.Secret_3_Island_BMD), has_press) # Set Purple Mystery Data Unlocker access def can_unlock(state): return state.can_reach_region(RegionName.SciLab_Overworld, self.player) or \ state.can_reach_region(RegionName.SciLab_Cyberworld, self.player) or \ state.can_reach_region(RegionName.Yoka_Cyberworld, self.player) or \ state.has(ItemName.Unlocker, self.player, 8) # There are 8 PMDs that aren't in one of the above areas - add_rule(self.multiworld.get_location(LocationName.ACDC_1_PMD, self.player), can_unlock) - add_rule(self.multiworld.get_location(LocationName.Yoka_1_PMD, self.player), can_unlock) - add_rule(self.multiworld.get_location(LocationName.Beach_1_PMD, self.player), can_unlock) - add_rule(self.multiworld.get_location(LocationName.Undernet_7_PMD, self.player), can_unlock) - add_rule(self.multiworld.get_location(LocationName.Mayls_HP_PMD, self.player), can_unlock) - add_rule(self.multiworld.get_location(LocationName.SciLab_Dads_Computer_PMD, self.player), can_unlock) - add_rule(self.multiworld.get_location(LocationName.Zoo_Panda_PMD, self.player), can_unlock) - add_rule(self.multiworld.get_location(LocationName.Beach_DNN_Security_Panel_PMD, self.player), can_unlock) - add_rule(self.multiworld.get_location(LocationName.Beach_DNN_Main_Console_PMD, self.player), can_unlock) - add_rule(self.multiworld.get_location(LocationName.Tamakos_HP_PMD, self.player), can_unlock) + add_rule(self.get_location(LocationName.ACDC_1_PMD), can_unlock) + add_rule(self.get_location(LocationName.Yoka_1_PMD), can_unlock) + add_rule(self.get_location(LocationName.Beach_1_PMD), can_unlock) + add_rule(self.get_location(LocationName.Undernet_7_PMD), can_unlock) + add_rule(self.get_location(LocationName.Mayls_HP_PMD), can_unlock) + add_rule(self.get_location(LocationName.SciLab_Dads_Computer_PMD), can_unlock) + add_rule(self.get_location(LocationName.Zoo_Panda_PMD), can_unlock) + add_rule(self.get_location(LocationName.Beach_DNN_Security_Panel_PMD), can_unlock) + add_rule(self.get_location(LocationName.Beach_DNN_Main_Console_PMD), can_unlock) + add_rule(self.get_location(LocationName.Tamakos_HP_PMD), can_unlock) # Set Job additional area access - self.multiworld.get_location(LocationName.Please_deliver_this, self.player).access_rule = \ + self.get_location(LocationName.Please_deliver_this).access_rule = \ lambda state: \ state.can_reach_region(RegionName.ACDC_Overworld, self.player) and \ state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) - self.multiworld.get_location(LocationName.My_Navi_is_sick, self.player).access_rule =\ + self.get_location(LocationName.My_Navi_is_sick).access_rule =\ lambda state: \ state.has(ItemName.Recov30_star, self.player) - self.multiworld.get_location(LocationName.Help_me_with_my_son, self.player).access_rule =\ + self.get_location(LocationName.Help_me_with_my_son).access_rule =\ lambda state:\ state.can_reach_region(RegionName.Yoka_Overworld, self.player) and \ state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) - self.multiworld.get_location(LocationName.Transmission_error, self.player).access_rule = \ + self.get_location(LocationName.Transmission_error).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Yoka_Overworld, self.player) - self.multiworld.get_location(LocationName.Chip_Prices, self.player).access_rule = \ + self.get_location(LocationName.Chip_Prices).access_rule = \ lambda state: \ state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) and \ state.can_reach_region(RegionName.SciLab_Cyberworld, self.player) - self.multiworld.get_location(LocationName.Im_broke, self.player).access_rule = \ + self.get_location(LocationName.Im_broke).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Yoka_Overworld, self.player) and \ state.can_reach_region(RegionName.Yoka_Cyberworld, self.player) - self.multiworld.get_location(LocationName.Rare_chips_for_cheap, self.player).access_rule = \ + self.get_location(LocationName.Rare_chips_for_cheap).access_rule = \ lambda state: \ state.can_reach_region(RegionName.ACDC_Overworld, self.player) - self.multiworld.get_location(LocationName.Be_my_boyfriend, self.player).access_rule =\ + self.get_location(LocationName.Be_my_boyfriend).access_rule =\ lambda state: \ state.can_reach_region(RegionName.Beach_Cyberworld, self.player) - self.multiworld.get_location(LocationName.Will_you_deliver, self.player).access_rule=\ + self.get_location(LocationName.Will_you_deliver).access_rule=\ lambda state: \ state.can_reach_region(RegionName.Yoka_Overworld, self.player) and \ state.can_reach_region(RegionName.Beach_Overworld, self.player) and \ state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) - self.multiworld.get_location(LocationName.Somebody_please_help, self.player).access_rule = \ + self.get_location(LocationName.Somebody_please_help).access_rule = \ lambda state: \ state.can_reach_region(RegionName.ACDC_Overworld, self.player) - self.multiworld.get_location(LocationName.Looking_for_condor, self.player).access_rule = \ + self.get_location(LocationName.Looking_for_condor).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Yoka_Overworld, self.player) and \ state.can_reach_region(RegionName.Beach_Overworld, self.player) and \ state.can_reach_region(RegionName.ACDC_Overworld, self.player) - self.multiworld.get_location(LocationName.Help_with_rehab, self.player).access_rule = \ + self.get_location(LocationName.Help_with_rehab).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Beach_Overworld, self.player) - self.multiworld.get_location(LocationName.Help_with_rehab_bonus, self.player).access_rule = \ + self.get_location(LocationName.Help_with_rehab_bonus).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Beach_Overworld, self.player) - self.multiworld.get_location(LocationName.Old_Master, self.player).access_rule = \ + self.get_location(LocationName.Old_Master).access_rule = \ lambda state: \ state.can_reach_region(RegionName.ACDC_Overworld, self.player) and \ state.can_reach_region(RegionName.Beach_Overworld, self.player) - self.multiworld.get_location(LocationName.Catching_gang_members, self.player).access_rule = \ + self.get_location(LocationName.Catching_gang_members).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Yoka_Cyberworld, self.player) and \ state.has(ItemName.Press, self.player) - self.multiworld.get_location(LocationName.Please_adopt_a_virus, self.player).access_rule = \ + self.get_location(LocationName.Please_adopt_a_virus).access_rule = \ lambda state: \ state.can_reach_region(RegionName.SciLab_Cyberworld, self.player) - self.multiworld.get_location(LocationName.Legendary_Tomes, self.player).access_rule = \ + self.get_location(LocationName.Legendary_Tomes).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Beach_Overworld, self.player) and \ state.can_reach_region(RegionName.Undernet, self.player) and \ state.can_reach_region(RegionName.Deep_Undernet, self.player) and \ state.has_all({ItemName.Press, ItemName.Magnum1_A}, self.player) - self.multiworld.get_location(LocationName.Legendary_Tomes_Treasure, self.player).access_rule = \ + self.get_location(LocationName.Legendary_Tomes_Treasure).access_rule = \ lambda state: \ state.can_reach_region(RegionName.ACDC_Overworld, self.player) and \ state.can_reach_location(LocationName.Legendary_Tomes, self.player) - self.multiworld.get_location(LocationName.Hide_and_seek_First_Child, self.player).access_rule = \ + self.get_location(LocationName.Hide_and_seek_First_Child).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Yoka_Overworld, self.player) - self.multiworld.get_location(LocationName.Hide_and_seek_Second_Child, self.player).access_rule = \ + self.get_location(LocationName.Hide_and_seek_Second_Child).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Yoka_Overworld, self.player) - self.multiworld.get_location(LocationName.Hide_and_seek_Third_Child, self.player).access_rule = \ + self.get_location(LocationName.Hide_and_seek_Third_Child).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Yoka_Overworld, self.player) - self.multiworld.get_location(LocationName.Hide_and_seek_Fourth_Child, self.player).access_rule = \ + self.get_location(LocationName.Hide_and_seek_Fourth_Child).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Yoka_Overworld, self.player) - self.multiworld.get_location(LocationName.Hide_and_seek_Completion, self.player).access_rule = \ + self.get_location(LocationName.Hide_and_seek_Completion).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Yoka_Overworld, self.player) - self.multiworld.get_location(LocationName.Finding_the_blue_Navi, self.player).access_rule = \ + self.get_location(LocationName.Finding_the_blue_Navi).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Undernet, self.player) - self.multiworld.get_location(LocationName.Give_your_support, self.player).access_rule = \ + self.get_location(LocationName.Give_your_support).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Beach_Overworld, self.player) - self.multiworld.get_location(LocationName.Stamp_collecting, self.player).access_rule = \ + self.get_location(LocationName.Stamp_collecting).access_rule = \ lambda state: \ state.can_reach_region(RegionName.Beach_Overworld, self.player) and \ state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) and \ state.can_reach_region(RegionName.SciLab_Cyberworld, self.player) and \ state.can_reach_region(RegionName.Yoka_Cyberworld, self.player) and \ state.can_reach_region(RegionName.Beach_Cyberworld, self.player) - self.multiworld.get_location(LocationName.Help_with_a_will, self.player).access_rule = \ + self.get_location(LocationName.Help_with_a_will).access_rule = \ lambda state: \ state.can_reach_region(RegionName.ACDC_Overworld, self.player) and \ state.can_reach_region(RegionName.ACDC_Cyberworld, self.player) and \ @@ -340,100 +346,115 @@ class MMBN3World(World): state.can_reach_region(RegionName.Undernet, self.player) # Set Trade quests - self.multiworld.get_location(LocationName.ACDC_SonicWav_W_Trade, self.player).access_rule =\ + self.get_location(LocationName.ACDC_SonicWav_W_Trade).access_rule =\ lambda state: state.has(ItemName.SonicWav_W, self.player) - self.multiworld.get_location(LocationName.ACDC_Bubbler_C_Trade, self.player).access_rule =\ + self.get_location(LocationName.ACDC_Bubbler_C_Trade).access_rule =\ lambda state: state.has(ItemName.Bubbler_C, self.player) - self.multiworld.get_location(LocationName.ACDC_Recov120_S_Trade, self.player).access_rule =\ + self.get_location(LocationName.ACDC_Recov120_S_Trade).access_rule =\ lambda state: state.has(ItemName.Recov120_S, self.player) - self.multiworld.get_location(LocationName.SciLab_Shake1_S_Trade, self.player).access_rule =\ + self.get_location(LocationName.SciLab_Shake1_S_Trade).access_rule =\ lambda state: state.has(ItemName.Shake1_S, self.player) - self.multiworld.get_location(LocationName.Yoka_FireSwrd_P_Trade, self.player).access_rule =\ + self.get_location(LocationName.Yoka_FireSwrd_P_Trade).access_rule =\ lambda state: state.has(ItemName.FireSwrd_P, self.player) - self.multiworld.get_location(LocationName.Hospital_DynaWav_V_Trade, self.player).access_rule =\ + self.get_location(LocationName.Hospital_DynaWav_V_Trade).access_rule =\ lambda state: state.has(ItemName.DynaWave_V, self.player) - self.multiworld.get_location(LocationName.Beach_DNN_WideSwrd_C_Trade, self.player).access_rule =\ + self.get_location(LocationName.Beach_DNN_WideSwrd_C_Trade).access_rule =\ lambda state: state.has(ItemName.WideSwrd_C, self.player) - self.multiworld.get_location(LocationName.Beach_DNN_HoleMetr_H_Trade, self.player).access_rule =\ + self.get_location(LocationName.Beach_DNN_HoleMetr_H_Trade).access_rule =\ lambda state: state.has(ItemName.HoleMetr_H, self.player) - self.multiworld.get_location(LocationName.Beach_DNN_Shadow_J_Trade, self.player).access_rule =\ + self.get_location(LocationName.Beach_DNN_Shadow_J_Trade).access_rule =\ lambda state: state.has(ItemName.Shadow_J, self.player) - self.multiworld.get_location(LocationName.Hades_GrabBack_K_Trade, self.player).access_rule =\ + self.get_location(LocationName.Hades_GrabBack_K_Trade).access_rule =\ lambda state: state.has(ItemName.GrabBack_K, self.player) # Set Number Traders # The first 8 are considered cheap enough to grind for in ACDC. Protip: Try grinding in the tank - self.multiworld.get_location(LocationName.Numberman_Code_09, self.player).access_rule = \ + self.get_location(LocationName.Numberman_Code_09).access_rule = \ lambda state: self.explore_score(state) > 2 - self.multiworld.get_location(LocationName.Numberman_Code_10, self.player).access_rule = \ + self.get_location(LocationName.Numberman_Code_10).access_rule = \ lambda state: self.explore_score(state) > 2 - self.multiworld.get_location(LocationName.Numberman_Code_11, self.player).access_rule = \ + self.get_location(LocationName.Numberman_Code_11).access_rule = \ lambda state: self.explore_score(state) > 2 - self.multiworld.get_location(LocationName.Numberman_Code_12, self.player).access_rule = \ + self.get_location(LocationName.Numberman_Code_12).access_rule = \ lambda state: self.explore_score(state) > 2 - self.multiworld.get_location(LocationName.Numberman_Code_13, self.player).access_rule = \ + self.get_location(LocationName.Numberman_Code_13).access_rule = \ lambda state: self.explore_score(state) > 2 - self.multiworld.get_location(LocationName.Numberman_Code_14, self.player).access_rule = \ + self.get_location(LocationName.Numberman_Code_14).access_rule = \ lambda state: self.explore_score(state) > 2 - self.multiworld.get_location(LocationName.Numberman_Code_15, self.player).access_rule = \ + self.get_location(LocationName.Numberman_Code_15).access_rule = \ lambda state: self.explore_score(state) > 2 - self.multiworld.get_location(LocationName.Numberman_Code_16, self.player).access_rule = \ + self.get_location(LocationName.Numberman_Code_16).access_rule = \ lambda state: self.explore_score(state) > 2 - self.multiworld.get_location(LocationName.Numberman_Code_17, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_17).access_rule =\ lambda state: self.explore_score(state) > 4 - self.multiworld.get_location(LocationName.Numberman_Code_18, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_18).access_rule =\ lambda state: self.explore_score(state) > 4 - self.multiworld.get_location(LocationName.Numberman_Code_19, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_19).access_rule =\ lambda state: self.explore_score(state) > 4 - self.multiworld.get_location(LocationName.Numberman_Code_20, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_20).access_rule =\ lambda state: self.explore_score(state) > 4 - self.multiworld.get_location(LocationName.Numberman_Code_21, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_21).access_rule =\ lambda state: self.explore_score(state) > 4 - self.multiworld.get_location(LocationName.Numberman_Code_22, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_22).access_rule =\ lambda state: self.explore_score(state) > 4 - self.multiworld.get_location(LocationName.Numberman_Code_23, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_23).access_rule =\ lambda state: self.explore_score(state) > 4 - self.multiworld.get_location(LocationName.Numberman_Code_24, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_24).access_rule =\ lambda state: self.explore_score(state) > 4 - self.multiworld.get_location(LocationName.Numberman_Code_25, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_25).access_rule =\ lambda state: self.explore_score(state) > 8 - self.multiworld.get_location(LocationName.Numberman_Code_26, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_26).access_rule =\ lambda state: self.explore_score(state) > 8 - self.multiworld.get_location(LocationName.Numberman_Code_27, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_27).access_rule =\ lambda state: self.explore_score(state) > 8 - self.multiworld.get_location(LocationName.Numberman_Code_28, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_28).access_rule =\ lambda state: self.explore_score(state) > 8 - self.multiworld.get_location(LocationName.Numberman_Code_29, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_29).access_rule =\ lambda state: self.explore_score(state) > 10 - self.multiworld.get_location(LocationName.Numberman_Code_30, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_30).access_rule =\ lambda state: self.explore_score(state) > 10 - self.multiworld.get_location(LocationName.Numberman_Code_31, self.player).access_rule =\ + self.get_location(LocationName.Numberman_Code_31).access_rule =\ lambda state: self.explore_score(state) > 10 #miscellaneous locations with extra requirements - add_rule(self.multiworld.get_location(LocationName.Comedian, self.player), + add_rule(self.get_location(LocationName.Comedian), lambda state: state.has(ItemName.Humor, self.player)) - add_rule(self.multiworld.get_location(LocationName.Villain, self.player), + add_rule(self.get_location(LocationName.Villain), lambda state: state.has(ItemName.BlckMnd, self.player)) - def not_undernet(item): return item.code != item_table[ItemName.Progressive_Undernet_Rank].code or item.player != self.player - self.multiworld.get_location(LocationName.WWW_1_Central_BMD, self.player).item_rule = not_undernet - self.multiworld.get_location(LocationName.WWW_1_East_BMD, self.player).item_rule = not_undernet - self.multiworld.get_location(LocationName.WWW_2_East_BMD, self.player).item_rule = not_undernet - self.multiworld.get_location(LocationName.WWW_2_Northwest_BMD, self.player).item_rule = not_undernet - self.multiworld.get_location(LocationName.WWW_3_East_BMD, self.player).item_rule = not_undernet - self.multiworld.get_location(LocationName.WWW_3_North_BMD, self.player).item_rule = not_undernet - self.multiworld.get_location(LocationName.WWW_4_Northwest_BMD, self.player).item_rule = not_undernet - self.multiworld.get_location(LocationName.WWW_4_Central_BMD, self.player).item_rule = not_undernet - self.multiworld.get_location(LocationName.WWW_Wall_BMD, self.player).item_rule = not_undernet - self.multiworld.get_location(LocationName.WWW_Control_Room_1_Screen, self.player).item_rule = not_undernet - self.multiworld.get_location(LocationName.WWW_Wilys_Desk, self.player).item_rule = not_undernet + forbid_item(self.get_location(LocationName.WWW_1_Central_BMD), + ItemName.Progressive_Undernet_Rank, self.player) + forbid_item(self.get_location(LocationName.WWW_1_East_BMD), + ItemName.Progressive_Undernet_Rank, self.player) + forbid_item(self.get_location(LocationName.WWW_2_East_BMD), + ItemName.Progressive_Undernet_Rank, self.player) + forbid_item(self.get_location(LocationName.WWW_2_Northwest_BMD), + ItemName.Progressive_Undernet_Rank, self.player) + forbid_item(self.get_location(LocationName.WWW_3_East_BMD), + ItemName.Progressive_Undernet_Rank, self.player) + forbid_item(self.get_location(LocationName.WWW_3_North_BMD), + ItemName.Progressive_Undernet_Rank, self.player) + forbid_item(self.get_location(LocationName.WWW_4_Northwest_BMD), + ItemName.Progressive_Undernet_Rank, self.player) + forbid_item(self.get_location(LocationName.WWW_4_Central_BMD), + ItemName.Progressive_Undernet_Rank, self.player) + forbid_item(self.get_location(LocationName.WWW_Wall_BMD), + ItemName.Progressive_Undernet_Rank, self.player) + forbid_item(self.get_location(LocationName.WWW_Control_Room_1_Screen), + ItemName.Progressive_Undernet_Rank, self.player) + forbid_item(self.get_location(LocationName.WWW_Wilys_Desk), + ItemName.Progressive_Undernet_Rank, self.player) + + # I have no fuckin clue why this specific location shits the bed on a progressive undernet rank. + # If you ever figure it out I will buy you a pizza. + forbid_item(self.get_location(LocationName.Chocolate_Shop_07), + ItemName.Progressive_Undernet_Rank, self.player) # place "Victory" at "Final Boss" and set collection as win condition - self.multiworld.get_location(LocationName.Alpha_Defeated, self.player) \ + self.get_location(LocationName.Alpha_Defeated) \ .place_locked_item(self.create_event(ItemName.Victory)) self.multiworld.completion_condition[self.player] = \ lambda state: state.has(ItemName.Victory, self.player) diff --git a/worlds/mmbn3/data/bn3-ap-patch.bsdiff b/worlds/mmbn3/data/bn3-ap-patch.bsdiff index d55fecad..43ace91b 100644 Binary files a/worlds/mmbn3/data/bn3-ap-patch.bsdiff and b/worlds/mmbn3/data/bn3-ap-patch.bsdiff differ