From a074d16297f906763bdbc9019f1bb0f8671907d3 Mon Sep 17 00:00:00 2001 From: PoryGone <98504756+PoryGone@users.noreply.github.com> Date: Sat, 20 Aug 2022 10:46:44 -0400 Subject: [PATCH] DKC3 v1.1.0 (#938) Features: * KONGsanity option (Collect all KONG letters in each level for a check) * Autosave option * Difficulty option * MERRY option * Handle collected/co-op locations Bugfixes: * Fixed Mekanos softlock * Prevent Brothers Bear giving extra Banana Birds * Fixed Banana Bird Mother check sending prematurely * Fix Logic bug with Krematoa level costs --- worlds/dkc3/Client.py | 52 ++++++--- worlds/dkc3/Locations.py | 53 +++++++++ worlds/dkc3/Names/LocationName.py | 47 +++++++- worlds/dkc3/Options.py | 48 +++++++- worlds/dkc3/Regions.py | 121 +++++++++++++++----- worlds/dkc3/Rom.py | 181 +++++++++++++++++++++++++++++- worlds/dkc3/__init__.py | 15 ++- 7 files changed, 463 insertions(+), 54 deletions(-) diff --git a/worlds/dkc3/Client.py b/worlds/dkc3/Client.py index 8ac20131f3..7ab82187b0 100644 --- a/worlds/dkc3/Client.py +++ b/worlds/dkc3/Client.py @@ -66,7 +66,7 @@ async def dkc3_game_watcher(ctx: Context): return new_checks = [] - from worlds.dkc3.Rom import location_rom_data, item_rom_data + from worlds.dkc3.Rom import location_rom_data, item_rom_data, boss_location_ids, level_unlock_map for loc_id, loc_data in location_rom_data.items(): if loc_id not in ctx.locations_checked: data = await snes_read(ctx, WRAM_START + loc_data[0], 1) @@ -186,22 +186,40 @@ async def dkc3_game_watcher(ctx: Context): # DKC3_TODO: This method of collect should work, however it does not unlock the next level correctly when previous is flagged # Handle Collected Locations - #for loc_id in ctx.checked_locations: - # if loc_id not in ctx.locations_checked: - # loc_data = location_rom_data[loc_id] - # data = await snes_read(ctx, WRAM_START + loc_data[0], 1) - # invert_bit = ((len(loc_data) >= 3) and loc_data[2]) - # if not invert_bit: - # masked_data = data[0] | (1 << loc_data[1]) - # print("Collected Location: ", hex(loc_data[0]), " | ", loc_data[1]) - # snes_buffered_write(ctx, WRAM_START + loc_data[0], bytes([masked_data])) - # await snes_flush_writes(ctx) - # else: - # masked_data = data[0] & ~(1 << loc_data[1]) - # print("Collected Inverted Location: ", hex(loc_data[0]), " | ", loc_data[1]) - # snes_buffered_write(ctx, WRAM_START + loc_data[0], bytes([masked_data])) - # await snes_flush_writes(ctx) - # ctx.locations_checked.add(loc_id) + for loc_id in ctx.checked_locations: + if loc_id not in ctx.locations_checked and loc_id not in boss_location_ids: + loc_data = location_rom_data[loc_id] + data = await snes_read(ctx, WRAM_START + loc_data[0], 1) + invert_bit = ((len(loc_data) >= 3) and loc_data[2]) + if not invert_bit: + masked_data = data[0] | (1 << loc_data[1]) + #print("Collected Location: ", hex(loc_data[0]), " | ", loc_data[1]) + snes_buffered_write(ctx, WRAM_START + loc_data[0], bytes([masked_data])) + + if (loc_data[1] == 1): + # Make the next levels accessible + level_id = loc_data[0] - 0x632 + levels_to_tiles = await snes_read(ctx, ROM_START + 0x3FF800, 0x60) + tiles_to_levels = await snes_read(ctx, ROM_START + 0x3FF860, 0x60) + tile_id = levels_to_tiles[level_id] if levels_to_tiles[level_id] != 0xFF else level_id + tile_id = tile_id + 0x632 + #print("Tile ID: ", hex(tile_id)) + if tile_id in level_unlock_map: + for next_level_address in level_unlock_map[tile_id]: + next_level_id = next_level_address - 0x632 + next_tile_id = tiles_to_levels[next_level_id] if tiles_to_levels[next_level_id] != 0xFF else next_level_id + next_tile_id = next_tile_id + 0x632 + #print("Next Level ID: ", hex(next_tile_id)) + next_data = await snes_read(ctx, WRAM_START + next_tile_id, 1) + snes_buffered_write(ctx, WRAM_START + next_tile_id, bytes([next_data[0] | 0x01])) + + await snes_flush_writes(ctx) + else: + masked_data = data[0] & ~(1 << loc_data[1]) + print("Collected Inverted Location: ", hex(loc_data[0]), " | ", loc_data[1]) + snes_buffered_write(ctx, WRAM_START + loc_data[0], bytes([masked_data])) + await snes_flush_writes(ctx) + ctx.locations_checked.add(loc_id) # Calculate Boomer Cost Text boomer_cost_text = await snes_read(ctx, WRAM_START + 0xAAFD, 2) diff --git a/worlds/dkc3/Locations.py b/worlds/dkc3/Locations.py index aa8acf729a..e8d5409b15 100644 --- a/worlds/dkc3/Locations.py +++ b/worlds/dkc3/Locations.py @@ -221,6 +221,55 @@ level_location_table = { LocationName.rocket_rush_dk: 0xDC30A0, } +kong_location_table = { + LocationName.lakeside_limbo_kong: 0xDC3100, + LocationName.doorstop_dash_kong: 0xDC3104, + LocationName.tidal_trouble_kong: 0xDC3108, + LocationName.skiddas_row_kong: 0xDC310C, + LocationName.murky_mill_kong: 0xDC3110, + + LocationName.barrel_shield_bust_up_kong: 0xDC3114, + LocationName.riverside_race_kong: 0xDC3118, + LocationName.squeals_on_wheels_kong: 0xDC311C, + LocationName.springin_spiders_kong: 0xDC3120, + LocationName.bobbing_barrel_brawl_kong: 0xDC3124, + + LocationName.bazzas_blockade_kong: 0xDC3128, + LocationName.rocket_barrel_ride_kong: 0xDC312C, + LocationName.kreeping_klasps_kong: 0xDC3130, + LocationName.tracker_barrel_trek_kong: 0xDC3134, + LocationName.fish_food_frenzy_kong: 0xDC3138, + + LocationName.fire_ball_frenzy_kong: 0xDC313C, + LocationName.demolition_drain_pipe_kong: 0xDC3140, + LocationName.ripsaw_rage_kong: 0xDC3144, + LocationName.blazing_bazookas_kong: 0xDC3148, + LocationName.low_g_labyrinth_kong: 0xDC314C, + + LocationName.krevice_kreepers_kong: 0xDC3150, + LocationName.tearaway_toboggan_kong: 0xDC3154, + LocationName.barrel_drop_bounce_kong: 0xDC3158, + LocationName.krack_shot_kroc_kong: 0xDC315C, + LocationName.lemguin_lunge_kong: 0xDC3160, + + LocationName.buzzer_barrage_kong: 0xDC3164, + LocationName.kong_fused_cliffs_kong: 0xDC3168, + LocationName.floodlit_fish_kong: 0xDC316C, + LocationName.pothole_panic_kong: 0xDC3170, + LocationName.ropey_rumpus_kong: 0xDC3174, + + LocationName.konveyor_rope_clash_kong: 0xDC3178, + LocationName.creepy_caverns_kong: 0xDC317C, + LocationName.lightning_lookout_kong: 0xDC3180, + LocationName.koindozer_klamber_kong: 0xDC3184, + LocationName.poisonous_pipeline_kong: 0xDC3188, + + LocationName.stampede_sprint_kong: 0xDC318C, + LocationName.criss_cross_cliffs_kong: 0xDC3191, + LocationName.tyrant_twin_tussle_kong: 0xDC3195, + LocationName.swoopy_salvo_kong: 0xDC319A, +} + boss_location_table = { LocationName.belchas_barn: 0xDC30A1, @@ -266,6 +315,7 @@ all_locations = { **boss_location_table, **secret_cave_location_table, **brothers_bear_location_table, + **kong_location_table, } location_table = {} @@ -277,6 +327,9 @@ def setup_locations(world, player: int): if False:#world.include_trade_sequence[player].value: location_table.update({**brothers_bear_location_table}) + if world.kongsanity[player].value: + location_table.update({**kong_location_table}) + return location_table diff --git a/worlds/dkc3/Names/LocationName.py b/worlds/dkc3/Names/LocationName.py index b3aca3b0f1..f79a25f143 100644 --- a/worlds/dkc3/Names/LocationName.py +++ b/worlds/dkc3/Names/LocationName.py @@ -1,197 +1,236 @@ # Level Definitions lakeside_limbo_flag = "Lakeside Limbo - Flag" +lakeside_limbo_kong = "Lakeside Limbo - KONG" lakeside_limbo_bonus_1 = "Lakeside Limbo - Bonus 1" lakeside_limbo_bonus_2 = "Lakeside Limbo - Bonus 2" lakeside_limbo_dk = "Lakeside Limbo - DK Coin" doorstop_dash_flag = "Doorstop Dash - Flag" +doorstop_dash_kong = "Doorstop Dash - KONG" doorstop_dash_bonus_1 = "Doorstop Dash - Bonus 1" doorstop_dash_bonus_2 = "Doorstop Dash - Bonus 2" doorstop_dash_dk = "Doorstop Dash - DK Coin" tidal_trouble_flag = "Tidal Trouble - Flag" +tidal_trouble_kong = "Tidal Trouble - KONG" tidal_trouble_bonus_1 = "Tidal Trouble - Bonus 1" tidal_trouble_bonus_2 = "Tidal Trouble - Bonus 2" tidal_trouble_dk = "Tidal Trouble - DK Coin" skiddas_row_flag = "Skidda's Row - Flag" +skiddas_row_kong = "Skidda's Row - KONG" skiddas_row_bonus_1 = "Skidda's Row - Bonus 1" skiddas_row_bonus_2 = "Skidda's Row - Bonus 2" skiddas_row_dk = "Skidda's Row - DK Coin" murky_mill_flag = "Murky Mill - Flag" +murky_mill_kong = "Murky Mill - KONG" murky_mill_bonus_1 = "Murky Mill - Bonus 1" murky_mill_bonus_2 = "Murky Mill - Bonus 2" murky_mill_dk = "Murky Mill - DK Coin" barrel_shield_bust_up_flag = "Barrel Shield Bust-Up - Flag" +barrel_shield_bust_up_kong = "Barrel Shield Bust-Up - KONG" barrel_shield_bust_up_bonus_1 = "Barrel Shield Bust-Up - Bonus 1" barrel_shield_bust_up_bonus_2 = "Barrel Shield Bust-Up - Bonus 2" barrel_shield_bust_up_dk = "Barrel Shield Bust-Up - DK Coin" riverside_race_flag = "Riverside Race - Flag" +riverside_race_kong = "Riverside Race - KONG" riverside_race_bonus_1 = "Riverside Race - Bonus 1" riverside_race_bonus_2 = "Riverside Race - Bonus 2" riverside_race_dk = "Riverside Race - DK Coin" squeals_on_wheels_flag = "Squeals On Wheels - Flag" +squeals_on_wheels_kong = "Squeals On Wheels - KONG" squeals_on_wheels_bonus_1 = "Squeals On Wheels - Bonus 1" squeals_on_wheels_bonus_2 = "Squeals On Wheels - Bonus 2" squeals_on_wheels_dk = "Squeals On Wheels - DK Coin" springin_spiders_flag = "Springin' Spiders - Flag" +springin_spiders_kong = "Springin' Spiders - KONG" springin_spiders_bonus_1 = "Springin' Spiders - Bonus 1" springin_spiders_bonus_2 = "Springin' Spiders - Bonus 2" springin_spiders_dk = "Springin' Spiders - DK Coin" bobbing_barrel_brawl_flag = "Bobbing Barrel Brawl - Flag" +bobbing_barrel_brawl_kong = "Bobbing Barrel Brawl - KONG" bobbing_barrel_brawl_bonus_1 = "Bobbing Barrel Brawl - Bonus 1" bobbing_barrel_brawl_bonus_2 = "Bobbing Barrel Brawl - Bonus 2" bobbing_barrel_brawl_dk = "Bobbing Barrel Brawl - DK Coin" bazzas_blockade_flag = "Bazza's Blockade - Flag" +bazzas_blockade_kong = "Bazza's Blockade - KONG" bazzas_blockade_bonus_1 = "Bazza's Blockade - Bonus 1" bazzas_blockade_bonus_2 = "Bazza's Blockade - Bonus 2" bazzas_blockade_dk = "Bazza's Blockade - DK Coin" rocket_barrel_ride_flag = "Rocket Barrel Ride - Flag" +rocket_barrel_ride_kong = "Rocket Barrel Ride - KONG" rocket_barrel_ride_bonus_1 = "Rocket Barrel Ride - Bonus 1" rocket_barrel_ride_bonus_2 = "Rocket Barrel Ride - Bonus 2" rocket_barrel_ride_dk = "Rocket Barrel Ride - DK Coin" kreeping_klasps_flag = "Kreeping Klasps - Flag" +kreeping_klasps_kong = "Kreeping Klasps - KONG" kreeping_klasps_bonus_1 = "Kreeping Klasps - Bonus 1" kreeping_klasps_bonus_2 = "Kreeping Klasps - Bonus 2" kreeping_klasps_dk = "Kreeping Klasps - DK Coin" tracker_barrel_trek_flag = "Tracker Barrel Trek - Flag" +tracker_barrel_trek_kong = "Tracker Barrel Trek - KONG" tracker_barrel_trek_bonus_1 = "Tracker Barrel Trek - Bonus 1" tracker_barrel_trek_bonus_2 = "Tracker Barrel Trek - Bonus 2" tracker_barrel_trek_dk = "Tracker Barrel Trek - DK Coin" fish_food_frenzy_flag = "Fish Food Frenzy - Flag" +fish_food_frenzy_kong = "Fish Food Frenzy - KONG" fish_food_frenzy_bonus_1 = "Fish Food Frenzy - Bonus 1" fish_food_frenzy_bonus_2 = "Fish Food Frenzy - Bonus 2" fish_food_frenzy_dk = "Fish Food Frenzy - DK Coin" fire_ball_frenzy_flag = "Fire-Ball Frenzy - Flag" +fire_ball_frenzy_kong = "Fire-Ball Frenzy - KONG" fire_ball_frenzy_bonus_1 = "Fire-Ball Frenzy - Bonus 1" fire_ball_frenzy_bonus_2 = "Fire-Ball Frenzy - Bonus 2" fire_ball_frenzy_dk = "Fire-Ball Frenzy - DK Coin" demolition_drain_pipe_flag = "Demolition Drain-Pipe - Flag" +demolition_drain_pipe_kong = "Demolition Drain-Pipe - KONG" demolition_drain_pipe_bonus_1 = "Demolition Drain-Pipe - Bonus 1" demolition_drain_pipe_bonus_2 = "Demolition Drain-Pipe - Bonus 2" demolition_drain_pipe_dk = "Demolition Drain-Pipe - DK Coin" ripsaw_rage_flag = "Ripsaw Rage - Flag" +ripsaw_rage_kong = "Ripsaw Rage - KONG" ripsaw_rage_bonus_1 = "Ripsaw Rage - Bonus 1" ripsaw_rage_bonus_2 = "Ripsaw Rage - Bonus 2" ripsaw_rage_dk = "Ripsaw Rage - DK Coin" -blazing_bazookas_flag = "Blazing Bazookas - Flag" -blazing_bazookas_bonus_1 = "Blazing Bazookas - Bonus 1" -blazing_bazookas_bonus_2 = "Blazing Bazookas - Bonus 2" -blazing_bazookas_dk = "Blazing Bazookas - DK Coin" +blazing_bazookas_flag = "Blazing Bazukas - Flag" +blazing_bazookas_kong = "Blazing Bazukas - KONG" +blazing_bazookas_bonus_1 = "Blazing Bazukas - Bonus 1" +blazing_bazookas_bonus_2 = "Blazing Bazukas - Bonus 2" +blazing_bazookas_dk = "Blazing Bazukas - DK Coin" low_g_labyrinth_flag = "Low-G Labyrinth - Flag" +low_g_labyrinth_kong = "Low-G Labyrinth - KONG" low_g_labyrinth_bonus_1 = "Low-G Labyrinth - Bonus 1" low_g_labyrinth_bonus_2 = "Low-G Labyrinth - Bonus 2" low_g_labyrinth_dk = "Low-G Labyrinth - DK Coin" krevice_kreepers_flag = "Krevice Kreepers - Flag" +krevice_kreepers_kong = "Krevice Kreepers - KONG" krevice_kreepers_bonus_1 = "Krevice Kreepers - Bonus 1" krevice_kreepers_bonus_2 = "Krevice Kreepers - Bonus 2" krevice_kreepers_dk = "Krevice Kreepers - DK Coin" tearaway_toboggan_flag = "Tearaway Toboggan - Flag" +tearaway_toboggan_kong = "Tearaway Toboggan - KONG" tearaway_toboggan_bonus_1 = "Tearaway Toboggan - Bonus 1" tearaway_toboggan_bonus_2 = "Tearaway Toboggan - Bonus 2" tearaway_toboggan_dk = "Tearaway Toboggan - DK Coin" barrel_drop_bounce_flag = "Barrel Drop Bounce - Flag" +barrel_drop_bounce_kong = "Barrel Drop Bounce - KONG" barrel_drop_bounce_bonus_1 = "Barrel Drop Bounce - Bonus 1" barrel_drop_bounce_bonus_2 = "Barrel Drop Bounce - Bonus 2" barrel_drop_bounce_dk = "Barrel Drop Bounce - DK Coin" krack_shot_kroc_flag = "Krack-Shot Kroc - Flag" +krack_shot_kroc_kong = "Krack-Shot Kroc - KONG" krack_shot_kroc_bonus_1 = "Krack-Shot Kroc - Bonus 1" krack_shot_kroc_bonus_2 = "Krack-Shot Kroc - Bonus 2" krack_shot_kroc_dk = "Krack-Shot Kroc - DK Coin" lemguin_lunge_flag = "Lemguin Lunge - Flag" +lemguin_lunge_kong = "Lemguin Lunge - KONG" lemguin_lunge_bonus_1 = "Lemguin Lunge - Bonus 1" lemguin_lunge_bonus_2 = "Lemguin Lunge - Bonus 2" lemguin_lunge_dk = "Lemguin Lunge - DK Coin" buzzer_barrage_flag = "Buzzer Barrage - Flag" +buzzer_barrage_kong = "Buzzer Barrage - KONG" buzzer_barrage_bonus_1 = "Buzzer Barrage - Bonus 1" buzzer_barrage_bonus_2 = "Buzzer Barrage - Bonus 2" buzzer_barrage_dk = "Buzzer Barrage - DK Coin" kong_fused_cliffs_flag = "Kong-Fused Cliffs - Flag" +kong_fused_cliffs_kong = "Kong-Fused Cliffs - KONG" kong_fused_cliffs_bonus_1 = "Kong-Fused Cliffs - Bonus 1" kong_fused_cliffs_bonus_2 = "Kong-Fused Cliffs - Bonus 2" kong_fused_cliffs_dk = "Kong-Fused Cliffs - DK Coin" floodlit_fish_flag = "Floodlit Fish - Flag" +floodlit_fish_kong = "Floodlit Fish - KONG" floodlit_fish_bonus_1 = "Floodlit Fish - Bonus 1" floodlit_fish_bonus_2 = "Floodlit Fish - Bonus 2" floodlit_fish_dk = "Floodlit Fish - DK Coin" pothole_panic_flag = "Pothole Panic - Flag" +pothole_panic_kong = "Pothole Panic - KONG" pothole_panic_bonus_1 = "Pothole Panic - Bonus 1" pothole_panic_bonus_2 = "Pothole Panic - Bonus 2" pothole_panic_dk = "Pothole Panic - DK Coin" ropey_rumpus_flag = "Ropey Rumpus - Flag" +ropey_rumpus_kong = "Ropey Rumpus - KONG" ropey_rumpus_bonus_1 = "Ropey Rumpus - Bonus 1" ropey_rumpus_bonus_2 = "Ropey Rumpus - Bonus 2" ropey_rumpus_dk = "Ropey Rumpus - DK Coin" konveyor_rope_clash_flag = "Konveyor Rope Klash - Flag" +konveyor_rope_clash_kong = "Konveyor Rope Klash - KONG" konveyor_rope_clash_bonus_1 = "Konveyor Rope Klash - Bonus 1" konveyor_rope_clash_bonus_2 = "Konveyor Rope Klash - Bonus 2" konveyor_rope_clash_dk = "Konveyor Rope Klash - DK Coin" creepy_caverns_flag = "Creepy Caverns - Flag" +creepy_caverns_kong = "Creepy Caverns - KONG" creepy_caverns_bonus_1 = "Creepy Caverns - Bonus 1" creepy_caverns_bonus_2 = "Creepy Caverns - Bonus 2" creepy_caverns_dk = "Creepy Caverns - DK Coin" lightning_lookout_flag = "Lightning Lookout - Flag" +lightning_lookout_kong = "Lightning Lookout - KONG" lightning_lookout_bonus_1 = "Lightning Lookout - Bonus 1" lightning_lookout_bonus_2 = "Lightning Lookout - Bonus 2" lightning_lookout_dk = "Lightning Lookout - DK Coin" koindozer_klamber_flag = "Koindozer Klamber - Flag" +koindozer_klamber_kong = "Koindozer Klamber - KONG" koindozer_klamber_bonus_1 = "Koindozer Klamber - Bonus 1" koindozer_klamber_bonus_2 = "Koindozer Klamber - Bonus 2" koindozer_klamber_dk = "Koindozer Klamber - DK Coin" poisonous_pipeline_flag = "Poisonous Pipeline - Flag" +poisonous_pipeline_kong = "Poisonous Pipeline - KONG" poisonous_pipeline_bonus_1 = "Poisonous Pipeline - Bonus 1" poisonous_pipeline_bonus_2 = "Poisonous Pipeline - Bonus 2" poisonous_pipeline_dk = "Poisonous Pipeline - DK Coin" stampede_sprint_flag = "Stampede Sprint - Flag" +stampede_sprint_kong = "Stampede Sprint - KONG" stampede_sprint_bonus_1 = "Stampede Sprint - Bonus 1" stampede_sprint_bonus_2 = "Stampede Sprint - Bonus 2" stampede_sprint_bonus_3 = "Stampede Sprint - Bonus 3" stampede_sprint_dk = "Stampede Sprint - DK Coin" criss_cross_cliffs_flag = "Criss Kross Cliffs - Flag" +criss_cross_cliffs_kong = "Criss Kross Cliffs - KONG" criss_cross_cliffs_bonus_1 = "Criss Kross Cliffs - Bonus 1" criss_cross_cliffs_bonus_2 = "Criss Kross Cliffs - Bonus 2" criss_cross_cliffs_dk = "Criss Kross Cliffs - DK Coin" tyrant_twin_tussle_flag = "Tyrant Twin Tussle - Flag" +tyrant_twin_tussle_kong = "Tyrant Twin Tussle - KONG" tyrant_twin_tussle_bonus_1 = "Tyrant Twin Tussle - Bonus 1" tyrant_twin_tussle_bonus_2 = "Tyrant Twin Tussle - Bonus 2" tyrant_twin_tussle_bonus_3 = "Tyrant Twin Tussle - Bonus 3" tyrant_twin_tussle_dk = "Tyrant Twin Tussle - DK Coin" swoopy_salvo_flag = "Swoopy Salvo - Flag" +swoopy_salvo_kong = "Swoopy Salvo - KONG" swoopy_salvo_bonus_1 = "Swoopy Salvo - Bonus 1" swoopy_salvo_bonus_2 = "Swoopy Salvo - Bonus 2" swoopy_salvo_bonus_3 = "Swoopy Salvo - Bonus 3" diff --git a/worlds/dkc3/Options.py b/worlds/dkc3/Options.py index 9e00014933..7c0f532cfc 100644 --- a/worlds/dkc3/Options.py +++ b/worlds/dkc3/Options.py @@ -6,7 +6,7 @@ from Options import Choice, Range, Option, Toggle, DeathLink, DefaultOnToggle, O class Goal(Choice): """ Determines the goal of the seed - Knautilus: Reach the Knautilus and defeat Baron K. Roolenstein + Knautilus: Scuttle the Knautilus in Krematoa and defeat Baron K. Roolenstein Banana Bird Hunt: Find a certain number of Banana Birds and rescue their mother """ display_name = "Goal" @@ -75,6 +75,13 @@ class PercentageOfBananaBirds(Range): default = 100 +class KONGsanity(Toggle): + """ + Whether collecting all four KONG letters in each level grants a check + """ + display_name = "KONGsanity" + + class LevelShuffle(Toggle): """ Whether levels are shuffled @@ -82,6 +89,41 @@ class LevelShuffle(Toggle): display_name = "Level Shuffle" +class Difficulty(Choice): + """ + Which Difficulty Level to use + NORML: The Normal Difficulty + HARDR: Many DK Barrels are removed + TUFST: Most DK Barrels and all Midway Barrels are removed + """ + display_name = "Difficulty" + option_norml = 0 + option_hardr = 1 + option_tufst = 2 + default = 0 + + @classmethod + def get_option_name(cls, value) -> str: + if cls.auto_display_name: + return cls.name_lookup[value].upper() + else: + return cls.name_lookup[value] + + +class Autosave(DefaultOnToggle): + """ + Whether the game should autosave after each level + """ + display_name = "Autosave" + + +class MERRY(Toggle): + """ + Whether the Bonus Barrels will be Christmas-themed + """ + display_name = "MERRY" + + class MusicShuffle(Toggle): """ Whether music is shuffled @@ -125,7 +167,11 @@ dkc3_options: typing.Dict[str, type(Option)] = { "percentage_of_extra_bonus_coins": PercentageOfExtraBonusCoins, "number_of_banana_birds": NumberOfBananaBirds, "percentage_of_banana_birds": PercentageOfBananaBirds, + "kongsanity": KONGsanity, "level_shuffle": LevelShuffle, + "difficulty": Difficulty, + "autosave": Autosave, + "merry": MERRY, "music_shuffle": MusicShuffle, "kong_palette_swap": KongPaletteSwap, "starting_life_count": StartingLifeCount, diff --git a/worlds/dkc3/Regions.py b/worlds/dkc3/Regions.py index 501f1a0ea4..e33ff38c15 100644 --- a/worlds/dkc3/Regions.py +++ b/worlds/dkc3/Regions.py @@ -44,6 +44,8 @@ def create_regions(world, player: int, active_locations): LocationName.lakeside_limbo_bonus_2 : [0x657, 3], LocationName.lakeside_limbo_dk : [0x657, 5], } + if world.kongsanity[player]: + lakeside_limbo_region_locations[LocationName.lakeside_limbo_kong] = [] lakeside_limbo_region = create_region(world, player, active_locations, LocationName.lakeside_limbo_region, lakeside_limbo_region_locations, None) @@ -53,6 +55,8 @@ def create_regions(world, player: int, active_locations): LocationName.doorstop_dash_bonus_2 : [0x65A, 3], LocationName.doorstop_dash_dk : [0x65A, 5], } + if world.kongsanity[player]: + doorstop_dash_region_locations[LocationName.doorstop_dash_kong] = [] doorstop_dash_region = create_region(world, player, active_locations, LocationName.doorstop_dash_region, doorstop_dash_region_locations, None) @@ -62,6 +66,8 @@ def create_regions(world, player: int, active_locations): LocationName.tidal_trouble_bonus_2 : [0x659, 3], LocationName.tidal_trouble_dk : [0x659, 5], } + if world.kongsanity[player]: + tidal_trouble_region_locations[LocationName.tidal_trouble_kong] = [] tidal_trouble_region = create_region(world, player, active_locations, LocationName.tidal_trouble_region, tidal_trouble_region_locations, None) @@ -71,6 +77,8 @@ def create_regions(world, player: int, active_locations): LocationName.skiddas_row_bonus_2 : [0x65D, 3], LocationName.skiddas_row_dk : [0x65D, 5], } + if world.kongsanity[player]: + skiddas_row_region_locations[LocationName.skiddas_row_kong] = [] skiddas_row_region = create_region(world, player, active_locations, LocationName.skiddas_row_region, skiddas_row_region_locations, None) @@ -80,6 +88,8 @@ def create_regions(world, player: int, active_locations): LocationName.murky_mill_bonus_2 : [0x65C, 3], LocationName.murky_mill_dk : [0x65C, 5], } + if world.kongsanity[player]: + murky_mill_region_locations[LocationName.murky_mill_kong] = [] murky_mill_region = create_region(world, player, active_locations, LocationName.murky_mill_region, murky_mill_region_locations, None) @@ -89,6 +99,8 @@ def create_regions(world, player: int, active_locations): LocationName.barrel_shield_bust_up_bonus_2 : [0x662, 3], LocationName.barrel_shield_bust_up_dk : [0x662, 5], } + if world.kongsanity[player]: + barrel_shield_bust_up_region_locations[LocationName.barrel_shield_bust_up_kong] = [] barrel_shield_bust_up_region = create_region(world, player, active_locations, LocationName.barrel_shield_bust_up_region, barrel_shield_bust_up_region_locations, None) @@ -98,6 +110,8 @@ def create_regions(world, player: int, active_locations): LocationName.riverside_race_bonus_2 : [0x664, 3], LocationName.riverside_race_dk : [0x664, 5], } + if world.kongsanity[player]: + riverside_race_region_locations[LocationName.riverside_race_kong] = [] riverside_race_region = create_region(world, player, active_locations, LocationName.riverside_race_region, riverside_race_region_locations, None) @@ -107,6 +121,8 @@ def create_regions(world, player: int, active_locations): LocationName.squeals_on_wheels_bonus_2 : [0x65B, 3], LocationName.squeals_on_wheels_dk : [0x65B, 5], } + if world.kongsanity[player]: + squeals_on_wheels_region_locations[LocationName.squeals_on_wheels_kong] = [] squeals_on_wheels_region = create_region(world, player, active_locations, LocationName.squeals_on_wheels_region, squeals_on_wheels_region_locations, None) @@ -116,6 +132,8 @@ def create_regions(world, player: int, active_locations): LocationName.springin_spiders_bonus_2 : [0x661, 3], LocationName.springin_spiders_dk : [0x661, 5], } + if world.kongsanity[player]: + springin_spiders_region_locations[LocationName.springin_spiders_kong] = [] springin_spiders_region = create_region(world, player, active_locations, LocationName.springin_spiders_region, springin_spiders_region_locations, None) @@ -125,6 +143,8 @@ def create_regions(world, player: int, active_locations): LocationName.bobbing_barrel_brawl_bonus_2 : [0x666, 3], LocationName.bobbing_barrel_brawl_dk : [0x666, 5], } + if world.kongsanity[player]: + bobbing_barrel_brawl_region_locations[LocationName.bobbing_barrel_brawl_kong] = [] bobbing_barrel_brawl_region = create_region(world, player, active_locations, LocationName.bobbing_barrel_brawl_region, bobbing_barrel_brawl_region_locations, None) @@ -134,6 +154,8 @@ def create_regions(world, player: int, active_locations): LocationName.bazzas_blockade_bonus_2 : [0x667, 3], LocationName.bazzas_blockade_dk : [0x667, 5], } + if world.kongsanity[player]: + bazzas_blockade_region_locations[LocationName.bazzas_blockade_kong] = [] bazzas_blockade_region = create_region(world, player, active_locations, LocationName.bazzas_blockade_region, bazzas_blockade_region_locations, None) @@ -143,6 +165,8 @@ def create_regions(world, player: int, active_locations): LocationName.rocket_barrel_ride_bonus_2 : [0x66A, 3], LocationName.rocket_barrel_ride_dk : [0x66A, 5], } + if world.kongsanity[player]: + rocket_barrel_ride_region_locations[LocationName.rocket_barrel_ride_kong] = [] rocket_barrel_ride_region = create_region(world, player, active_locations, LocationName.rocket_barrel_ride_region, rocket_barrel_ride_region_locations, None) @@ -152,6 +176,8 @@ def create_regions(world, player: int, active_locations): LocationName.kreeping_klasps_bonus_2 : [0x658, 3], LocationName.kreeping_klasps_dk : [0x658, 5], } + if world.kongsanity[player]: + kreeping_klasps_region_locations[LocationName.kreeping_klasps_kong] = [] kreeping_klasps_region = create_region(world, player, active_locations, LocationName.kreeping_klasps_region, kreeping_klasps_region_locations, None) @@ -161,6 +187,8 @@ def create_regions(world, player: int, active_locations): LocationName.tracker_barrel_trek_bonus_2 : [0x66B, 3], LocationName.tracker_barrel_trek_dk : [0x66B, 5], } + if world.kongsanity[player]: + tracker_barrel_trek_region_locations[LocationName.tracker_barrel_trek_kong] = [] tracker_barrel_trek_region = create_region(world, player, active_locations, LocationName.tracker_barrel_trek_region, tracker_barrel_trek_region_locations, None) @@ -170,6 +198,8 @@ def create_regions(world, player: int, active_locations): LocationName.fish_food_frenzy_bonus_2 : [0x668, 3], LocationName.fish_food_frenzy_dk : [0x668, 5], } + if world.kongsanity[player]: + fish_food_frenzy_region_locations[LocationName.fish_food_frenzy_kong] = [] fish_food_frenzy_region = create_region(world, player, active_locations, LocationName.fish_food_frenzy_region, fish_food_frenzy_region_locations, None) @@ -179,6 +209,8 @@ def create_regions(world, player: int, active_locations): LocationName.fire_ball_frenzy_bonus_2 : [0x66D, 3], LocationName.fire_ball_frenzy_dk : [0x66D, 5], } + if world.kongsanity[player]: + fire_ball_frenzy_region_locations[LocationName.fire_ball_frenzy_kong] = [] fire_ball_frenzy_region = create_region(world, player, active_locations, LocationName.fire_ball_frenzy_region, fire_ball_frenzy_region_locations, None) @@ -188,6 +220,8 @@ def create_regions(world, player: int, active_locations): LocationName.demolition_drain_pipe_bonus_2 : [0x672, 3], LocationName.demolition_drain_pipe_dk : [0x672, 5], } + if world.kongsanity[player]: + demolition_drain_pipe_region_locations[LocationName.demolition_drain_pipe_kong] = [] demolition_drain_pipe_region = create_region(world, player, active_locations, LocationName.demolition_drain_pipe_region, demolition_drain_pipe_region_locations, None) @@ -197,6 +231,8 @@ def create_regions(world, player: int, active_locations): LocationName.ripsaw_rage_bonus_2 : [0x660, 3], LocationName.ripsaw_rage_dk : [0x660, 5], } + if world.kongsanity[player]: + ripsaw_rage_region_locations[LocationName.ripsaw_rage_kong] = [] ripsaw_rage_region = create_region(world, player, active_locations, LocationName.ripsaw_rage_region, ripsaw_rage_region_locations, None) @@ -206,6 +242,8 @@ def create_regions(world, player: int, active_locations): LocationName.blazing_bazookas_bonus_2 : [0x66E, 3], LocationName.blazing_bazookas_dk : [0x66E, 5], } + if world.kongsanity[player]: + blazing_bazookas_region_locations[LocationName.blazing_bazookas_kong] = [] blazing_bazookas_region = create_region(world, player, active_locations, LocationName.blazing_bazookas_region, blazing_bazookas_region_locations, None) @@ -215,6 +253,8 @@ def create_regions(world, player: int, active_locations): LocationName.low_g_labyrinth_bonus_2 : [0x670, 3], LocationName.low_g_labyrinth_dk : [0x670, 5], } + if world.kongsanity[player]: + low_g_labyrinth_region_locations[LocationName.low_g_labyrinth_kong] = [] low_g_labyrinth_region = create_region(world, player, active_locations, LocationName.low_g_labyrinth_region, low_g_labyrinth_region_locations, None) @@ -224,6 +264,8 @@ def create_regions(world, player: int, active_locations): LocationName.krevice_kreepers_bonus_2 : [0x673, 3], LocationName.krevice_kreepers_dk : [0x673, 5], } + if world.kongsanity[player]: + krevice_kreepers_region_locations[LocationName.krevice_kreepers_kong] = [] krevice_kreepers_region = create_region(world, player, active_locations, LocationName.krevice_kreepers_region, krevice_kreepers_region_locations, None) @@ -233,6 +275,8 @@ def create_regions(world, player: int, active_locations): LocationName.tearaway_toboggan_bonus_2 : [0x65F, 3], LocationName.tearaway_toboggan_dk : [0x65F, 5], } + if world.kongsanity[player]: + tearaway_toboggan_region_locations[LocationName.tearaway_toboggan_kong] = [] tearaway_toboggan_region = create_region(world, player, active_locations, LocationName.tearaway_toboggan_region, tearaway_toboggan_region_locations, None) @@ -242,6 +286,8 @@ def create_regions(world, player: int, active_locations): LocationName.barrel_drop_bounce_bonus_2 : [0x66C, 3], LocationName.barrel_drop_bounce_dk : [0x66C, 5], } + if world.kongsanity[player]: + barrel_drop_bounce_region_locations[LocationName.barrel_drop_bounce_kong] = [] barrel_drop_bounce_region = create_region(world, player, active_locations, LocationName.barrel_drop_bounce_region, barrel_drop_bounce_region_locations, None) @@ -251,6 +297,8 @@ def create_regions(world, player: int, active_locations): LocationName.krack_shot_kroc_bonus_2 : [0x66F, 3], LocationName.krack_shot_kroc_dk : [0x66F, 5], } + if world.kongsanity[player]: + krack_shot_kroc_region_locations[LocationName.krack_shot_kroc_kong] = [] krack_shot_kroc_region = create_region(world, player, active_locations, LocationName.krack_shot_kroc_region, krack_shot_kroc_region_locations, None) @@ -260,6 +308,8 @@ def create_regions(world, player: int, active_locations): LocationName.lemguin_lunge_bonus_2 : [0x65E, 3], LocationName.lemguin_lunge_dk : [0x65E, 5], } + if world.kongsanity[player]: + lemguin_lunge_region_locations[LocationName.lemguin_lunge_kong] = [] lemguin_lunge_region = create_region(world, player, active_locations, LocationName.lemguin_lunge_region, lemguin_lunge_region_locations, None) @@ -269,6 +319,8 @@ def create_regions(world, player: int, active_locations): LocationName.buzzer_barrage_bonus_2 : [0x676, 3], LocationName.buzzer_barrage_dk : [0x676, 5], } + if world.kongsanity[player]: + buzzer_barrage_region_locations[LocationName.buzzer_barrage_kong] = [] buzzer_barrage_region = create_region(world, player, active_locations, LocationName.buzzer_barrage_region, buzzer_barrage_region_locations, None) @@ -278,6 +330,8 @@ def create_regions(world, player: int, active_locations): LocationName.kong_fused_cliffs_bonus_2 : [0x674, 3], LocationName.kong_fused_cliffs_dk : [0x674, 5], } + if world.kongsanity[player]: + kong_fused_cliffs_region_locations[LocationName.kong_fused_cliffs_kong] = [] kong_fused_cliffs_region = create_region(world, player, active_locations, LocationName.kong_fused_cliffs_region, kong_fused_cliffs_region_locations, None) @@ -287,6 +341,8 @@ def create_regions(world, player: int, active_locations): LocationName.floodlit_fish_bonus_2 : [0x669, 3], LocationName.floodlit_fish_dk : [0x669, 5], } + if world.kongsanity[player]: + floodlit_fish_region_locations[LocationName.floodlit_fish_kong] = [] floodlit_fish_region = create_region(world, player, active_locations, LocationName.floodlit_fish_region, floodlit_fish_region_locations, None) @@ -296,6 +352,8 @@ def create_regions(world, player: int, active_locations): LocationName.pothole_panic_bonus_2 : [0x677, 3], LocationName.pothole_panic_dk : [0x677, 5], } + if world.kongsanity[player]: + pothole_panic_region_locations[LocationName.pothole_panic_kong] = [] pothole_panic_region = create_region(world, player, active_locations, LocationName.pothole_panic_region, pothole_panic_region_locations, None) @@ -305,6 +363,8 @@ def create_regions(world, player: int, active_locations): LocationName.ropey_rumpus_bonus_2 : [0x675, 3], LocationName.ropey_rumpus_dk : [0x675, 5], } + if world.kongsanity[player]: + ropey_rumpus_region_locations[LocationName.ropey_rumpus_kong] = [] ropey_rumpus_region = create_region(world, player, active_locations, LocationName.ropey_rumpus_region, ropey_rumpus_region_locations, None) @@ -314,6 +374,8 @@ def create_regions(world, player: int, active_locations): LocationName.konveyor_rope_clash_bonus_2 : [0x657, 3], LocationName.konveyor_rope_clash_dk : [0x657, 5], } + if world.kongsanity[player]: + konveyor_rope_clash_region_locations[LocationName.konveyor_rope_clash_kong] = [] konveyor_rope_clash_region = create_region(world, player, active_locations, LocationName.konveyor_rope_clash_region, konveyor_rope_clash_region_locations, None) @@ -323,6 +385,8 @@ def create_regions(world, player: int, active_locations): LocationName.creepy_caverns_bonus_2 : [0x678, 3], LocationName.creepy_caverns_dk : [0x678, 5], } + if world.kongsanity[player]: + creepy_caverns_region_locations[LocationName.creepy_caverns_kong] = [] creepy_caverns_region = create_region(world, player, active_locations, LocationName.creepy_caverns_region, creepy_caverns_region_locations, None) @@ -332,6 +396,8 @@ def create_regions(world, player: int, active_locations): LocationName.lightning_lookout_bonus_2 : [0x665, 3], LocationName.lightning_lookout_dk : [0x665, 5], } + if world.kongsanity[player]: + lightning_lookout_region_locations[LocationName.lightning_lookout_kong] = [] lightning_lookout_region = create_region(world, player, active_locations, LocationName.lightning_lookout_region, lightning_lookout_region_locations, None) @@ -341,6 +407,8 @@ def create_regions(world, player: int, active_locations): LocationName.koindozer_klamber_bonus_2 : [0x679, 3], LocationName.koindozer_klamber_dk : [0x679, 5], } + if world.kongsanity[player]: + koindozer_klamber_region_locations[LocationName.koindozer_klamber_kong] = [] koindozer_klamber_region = create_region(world, player, active_locations, LocationName.koindozer_klamber_region, koindozer_klamber_region_locations, None) @@ -350,6 +418,8 @@ def create_regions(world, player: int, active_locations): LocationName.poisonous_pipeline_bonus_2 : [0x671, 3], LocationName.poisonous_pipeline_dk : [0x671, 5], } + if world.kongsanity[player]: + poisonous_pipeline_region_locations[LocationName.poisonous_pipeline_kong] = [] poisonous_pipeline_region = create_region(world, player, active_locations, LocationName.poisonous_pipeline_region, poisonous_pipeline_region_locations, None) @@ -360,6 +430,8 @@ def create_regions(world, player: int, active_locations): LocationName.stampede_sprint_bonus_3 : [0x67B, 4], LocationName.stampede_sprint_dk : [0x67B, 5], } + if world.kongsanity[player]: + stampede_sprint_region_locations[LocationName.stampede_sprint_kong] = [] stampede_sprint_region = create_region(world, player, active_locations, LocationName.stampede_sprint_region, stampede_sprint_region_locations, None) @@ -369,6 +441,8 @@ def create_regions(world, player: int, active_locations): LocationName.criss_cross_cliffs_bonus_2 : [0x67C, 3], LocationName.criss_cross_cliffs_dk : [0x67C, 5], } + if world.kongsanity[player]: + criss_cross_cliffs_region_locations[LocationName.criss_cross_cliffs_kong] = [] criss_cross_cliffs_region = create_region(world, player, active_locations, LocationName.criss_cross_cliffs_region, criss_cross_cliffs_region_locations, None) @@ -379,6 +453,8 @@ def create_regions(world, player: int, active_locations): LocationName.tyrant_twin_tussle_bonus_3 : [0x67D, 4], LocationName.tyrant_twin_tussle_dk : [0x67D, 5], } + if world.kongsanity[player]: + tyrant_twin_tussle_region_locations[LocationName.tyrant_twin_tussle_kong] = [] tyrant_twin_tussle_region = create_region(world, player, active_locations, LocationName.tyrant_twin_tussle_region, tyrant_twin_tussle_region_locations, None) @@ -389,6 +465,8 @@ def create_regions(world, player: int, active_locations): LocationName.swoopy_salvo_bonus_3 : [0x663, 4], LocationName.swoopy_salvo_dk : [0x663, 5], } + if world.kongsanity[player]: + swoopy_salvo_region_locations[LocationName.swoopy_salvo_kong] = [] swoopy_salvo_region = create_region(world, player, active_locations, LocationName.swoopy_salvo_region, swoopy_salvo_region_locations, None) @@ -503,9 +581,7 @@ def create_regions(world, player: int, active_locations): sky_high_secret_region_locations = {} if False:#world.include_trade_sequence[player]: - sky_high_secret_region_locations.update({ - LocationName.sky_high_secret: [0x64B, 1], - }) + sky_high_secret_region_locations[LocationName.sky_high_secret] = [0x64B, 1] sky_high_secret_region = create_region(world, player, active_locations, LocationName.sky_high_secret_region, sky_high_secret_region_locations, None) @@ -517,9 +593,7 @@ def create_regions(world, player: int, active_locations): cifftop_cache_region_locations = {} if False:#world.include_trade_sequence[player]: - cifftop_cache_region_locations.update({ - LocationName.cifftop_cache: [0x64D, 1], - }) + cifftop_cache_region_locations[LocationName.cifftop_cache] = [0x64D, 1] cifftop_cache_region = create_region(world, player, active_locations, LocationName.cifftop_cache_region, cifftop_cache_region_locations, None) @@ -622,29 +696,19 @@ def create_regions(world, player: int, active_locations): LocationName.bazaars_general_store_2: [0x615, 3, True], }) - bramble_region_locations.update({ - LocationName.brambles_bungalow: [0x619, 2], - }) + bramble_region_locations[LocationName.brambles_bungalow] = [0x619, 2] #flower_spot_region_locations.update({ # LocationName.flower_spot: [0x615, 3, True], #}) - barter_region_locations.update({ - LocationName.barters_swap_shop: [0x61B, 3], - }) + barter_region_locations[LocationName.barters_swap_shop] = [0x61B, 3] - barnacle_region_locations.update({ - LocationName.barnacles_island: [0x61D, 2], - }) + barnacle_region_locations[LocationName.barnacles_island] = [0x61D, 2] - blue_region_locations.update({ - LocationName.blues_beach_hut: [0x621, 4], - }) + blue_region_locations[LocationName.blues_beach_hut] = [0x621, 4] - blizzard_region_locations.update({ - LocationName.blizzards_basecamp: [0x625, 4, True], - }) + blizzard_region_locations[LocationName.blizzards_basecamp] = [0x625, 4, True] bazaar_region = create_region(world, player, active_locations, LocationName.bazaar_region, bazaar_region_locations, None) @@ -817,7 +881,6 @@ def connect_regions(world, player, level_list): level_list[32], level_list[33], level_list[34], - LocationName.kastle_kaos_region, LocationName.sewer_stockpile_region, ] @@ -835,10 +898,16 @@ def connect_regions(world, player, level_list): for i in range(0, len(krematoa_levels)): connect(world, player, names, LocationName.krematoa_region, krematoa_levels[i], - lambda state: (state.has(ItemName.bonus_coin, player, world.krematoa_bonus_coin_cost[player].value * (i+1)))) - - connect(world, player, names, LocationName.krematoa_region, LocationName.knautilus_region, - lambda state: (state.has(ItemName.krematoa_cog, player, 5))) + lambda state, i=i: (state.has(ItemName.bonus_coin, player, world.krematoa_bonus_coin_cost[player].value * (i+1)))) + + if world.goal[player] == "knautilus": + connect(world, player, names, LocationName.kaos_kore_region, LocationName.knautilus_region) + connect(world, player, names, LocationName.krematoa_region, LocationName.kastle_kaos_region, + lambda state: (state.has(ItemName.krematoa_cog, player, 5))) + else: + connect(world, player, names, LocationName.kaos_kore_region, LocationName.kastle_kaos_region) + connect(world, player, names, LocationName.krematoa_region, LocationName.knautilus_region, + lambda state: (state.has(ItemName.krematoa_cog, player, 5))) def create_region(world: MultiWorld, player: int, active_locations, name: str, locations=None, exits=None): diff --git a/worlds/dkc3/Rom.py b/worlds/dkc3/Rom.py index 7e83589ffa..90c4507e44 100644 --- a/worlds/dkc3/Rom.py +++ b/worlds/dkc3/Rom.py @@ -11,187 +11,270 @@ import os import math +level_unlock_map = { + 0x657: [0x65A], + 0x65A: [0x680, 0x639, 0x659], + 0x659: [0x65D], + 0x65D: [0x65C], + 0x65C: [0x688, 0x64F], + + 0x662: [0x681, 0x664], + 0x664: [0x65B], + 0x65B: [0x689, 0x661], + 0x661: [0x63A, 0x666], + 0x666: [0x650, 0x649], + + 0x667: [0x66A], + 0x66A: [0x682, 0x658], + 0x658: [0x68A, 0x66B], + 0x66B: [0x668], + 0x668: [0x651], + + 0x66D: [0x63C, 0x672], + 0x672: [0x68B, 0x660], + 0x660: [0x683, 0x66E], + 0x66E: [0x670], + 0x670: [0x652], + + 0x673: [0x684, 0x65F], + 0x65F: [0x66C], + 0x66C: [0x66F], + 0x66F: [0x65E], + 0x65E: [0x63D, 0x653, 0x68C, 0x64C], + + 0x676: [0x63E, 0x674, 0x685], + 0x674: [0x63F, 0x669], + 0x669: [0x677], + 0x677: [0x68D, 0x675], + 0x675: [0x654], + + 0x67A: [0x640, 0x678], + 0x678: [0x665], + 0x665: [0x686, 0x679], + 0x679: [0x68E, 0x671], + + 0x67B: [0x67C], + 0x67C: [0x67D], + 0x67D: [0x663], + 0x663: [0x67E], +} + location_rom_data = { 0xDC3000: [0x657, 1], # Lakeside Limbo 0xDC3001: [0x657, 2], 0xDC3002: [0x657, 3], 0xDC3003: [0x657, 5], + 0xDC3100: [0x657, 7], 0xDC3004: [0x65A, 1], # Doorstop Dash 0xDC3005: [0x65A, 2], 0xDC3006: [0x65A, 3], 0xDC3007: [0x65A, 5], + 0xDC3104: [0x65A, 7], 0xDC3008: [0x659, 1], # Tidal Trouble 0xDC3009: [0x659, 2], 0xDC300A: [0x659, 3], 0xDC300B: [0x659, 5], + 0xDC3108: [0x659, 7], 0xDC300C: [0x65D, 1], # Skidda's Row 0xDC300D: [0x65D, 2], 0xDC300E: [0x65D, 3], 0xDC300F: [0x65D, 5], + 0xDC310C: [0x65D, 7], 0xDC3010: [0x65C, 1], # Murky Mill 0xDC3011: [0x65C, 2], 0xDC3012: [0x65C, 3], 0xDC3013: [0x65C, 5], + 0xDC3110: [0x65C, 7], 0xDC3014: [0x662, 1], # Barrel Shield Bust-Up 0xDC3015: [0x662, 2], 0xDC3016: [0x662, 3], 0xDC3017: [0x662, 5], + 0xDC3114: [0x662, 7], 0xDC3018: [0x664, 1], # Riverside Race 0xDC3019: [0x664, 2], 0xDC301A: [0x664, 3], 0xDC301B: [0x664, 5], + 0xDC3118: [0x664, 7], 0xDC301C: [0x65B, 1], # Squeals on Wheels 0xDC301D: [0x65B, 2], 0xDC301E: [0x65B, 3], 0xDC301F: [0x65B, 5], + 0xDC311C: [0x65B, 7], 0xDC3020: [0x661, 1], # Springin' Spiders 0xDC3021: [0x661, 2], 0xDC3022: [0x661, 3], 0xDC3023: [0x661, 5], + 0xDC3120: [0x661, 7], 0xDC3024: [0x666, 1], # Bobbing Barrel Brawl 0xDC3025: [0x666, 2], 0xDC3026: [0x666, 3], 0xDC3027: [0x666, 5], + 0xDC3124: [0x666, 7], 0xDC3028: [0x667, 1], # Bazza's Blockade 0xDC3029: [0x667, 2], 0xDC302A: [0x667, 3], 0xDC302B: [0x667, 5], + 0xDC3128: [0x667, 7], 0xDC302C: [0x66A, 1], # Rocket Barrel Ride 0xDC302D: [0x66A, 2], 0xDC302E: [0x66A, 3], 0xDC302F: [0x66A, 5], + 0xDC312C: [0x66A, 7], 0xDC3030: [0x658, 1], # Kreeping Klasps 0xDC3031: [0x658, 2], 0xDC3032: [0x658, 3], 0xDC3033: [0x658, 5], + 0xDC3130: [0x658, 7], 0xDC3034: [0x66B, 1], # Tracker Barrel Trek 0xDC3035: [0x66B, 2], 0xDC3036: [0x66B, 3], 0xDC3037: [0x66B, 5], + 0xDC3134: [0x66B, 7], 0xDC3038: [0x668, 1], # Fish Food Frenzy 0xDC3039: [0x668, 2], 0xDC303A: [0x668, 3], 0xDC303B: [0x668, 5], + 0xDC3138: [0x668, 7], 0xDC303C: [0x66D, 1], # Fire-ball Frenzy 0xDC303D: [0x66D, 2], 0xDC303E: [0x66D, 3], 0xDC303F: [0x66D, 5], + 0xDC313C: [0x66D, 7], 0xDC3040: [0x672, 1], # Demolition Drainpipe 0xDC3041: [0x672, 2], 0xDC3042: [0x672, 3], 0xDC3043: [0x672, 5], + 0xDC3140: [0x672, 7], 0xDC3044: [0x660, 1], # Ripsaw Rage 0xDC3045: [0x660, 2], 0xDC3046: [0x660, 3], 0xDC3047: [0x660, 5], + 0xDC3144: [0x660, 7], 0xDC3048: [0x66E, 1], # Blazing Bazukas 0xDC3049: [0x66E, 2], 0xDC304A: [0x66E, 3], 0xDC304B: [0x66E, 5], + 0xDC3148: [0x66E, 7], 0xDC304C: [0x670, 1], # Low-G Labyrinth 0xDC304D: [0x670, 2], 0xDC304E: [0x670, 3], 0xDC304F: [0x670, 5], + 0xDC314C: [0x670, 7], 0xDC3050: [0x673, 1], # Krevice Kreepers 0xDC3051: [0x673, 2], 0xDC3052: [0x673, 3], 0xDC3053: [0x673, 5], + 0xDC3150: [0x673, 7], 0xDC3054: [0x65F, 1], # Tearaway Toboggan 0xDC3055: [0x65F, 2], 0xDC3056: [0x65F, 3], 0xDC3057: [0x65F, 5], + 0xDC3154: [0x65F, 7], 0xDC3058: [0x66C, 1], # Barrel Drop Bounce 0xDC3059: [0x66C, 2], 0xDC305A: [0x66C, 3], 0xDC305B: [0x66C, 5], + 0xDC3158: [0x66C, 7], 0xDC305C: [0x66F, 1], # Krack-Shot Kroc 0xDC305D: [0x66F, 2], 0xDC305E: [0x66F, 3], 0xDC305F: [0x66F, 5], + 0xDC315C: [0x66F, 7], 0xDC3060: [0x65E, 1], # Lemguin Lunge 0xDC3061: [0x65E, 2], 0xDC3062: [0x65E, 3], 0xDC3063: [0x65E, 5], + 0xDC3160: [0x65E, 7], 0xDC3064: [0x676, 1], # Buzzer Barrage 0xDC3065: [0x676, 2], 0xDC3066: [0x676, 3], 0xDC3067: [0x676, 5], + 0xDC3164: [0x676, 7], 0xDC3068: [0x674, 1], # Kong-Fused Cliffs 0xDC3069: [0x674, 2], 0xDC306A: [0x674, 3], 0xDC306B: [0x674, 5], + 0xDC3168: [0x674, 7], 0xDC306C: [0x669, 1], # Floodlit Fish 0xDC306D: [0x669, 2], 0xDC306E: [0x669, 3], 0xDC306F: [0x669, 5], + 0xDC316C: [0x669, 7], 0xDC3070: [0x677, 1], # Pothole Panic 0xDC3071: [0x677, 2], 0xDC3072: [0x677, 3], 0xDC3073: [0x677, 5], + 0xDC3170: [0x677, 7], 0xDC3074: [0x675, 1], # Ropey Rumpus 0xDC3075: [0x675, 2], 0xDC3076: [0x675, 3], 0xDC3077: [0x675, 5], + 0xDC3174: [0x675, 7], 0xDC3078: [0x67A, 1], # Konveyor Rope Klash 0xDC3079: [0x67A, 2], 0xDC307A: [0x67A, 3], 0xDC307B: [0x67A, 5], + 0xDC3178: [0x67A, 7], 0xDC307C: [0x678, 1], # Creepy Caverns 0xDC307D: [0x678, 2], 0xDC307E: [0x678, 3], 0xDC307F: [0x678, 5], + 0xDC317C: [0x678, 7], 0xDC3080: [0x665, 1], # Lightning Lookout 0xDC3081: [0x665, 2], 0xDC3082: [0x665, 3], 0xDC3083: [0x665, 5], + 0xDC3180: [0x665, 7], 0xDC3084: [0x679, 1], # Koindozer Klamber 0xDC3085: [0x679, 2], 0xDC3086: [0x679, 3], 0xDC3087: [0x679, 5], + 0xDC3184: [0x679, 7], 0xDC3088: [0x671, 1], # Poisonous Pipeline 0xDC3089: [0x671, 2], 0xDC308A: [0x671, 3], 0xDC308B: [0x671, 5], + 0xDC3188: [0x671, 7], 0xDC308C: [0x67B, 1], # Stampede Sprint @@ -199,23 +282,27 @@ location_rom_data = { 0xDC308E: [0x67B, 3], 0xDC308F: [0x67B, 4], 0xDC3090: [0x67B, 5], + 0xDC318C: [0x67B, 7], 0xDC3091: [0x67C, 1], # Criss Kross Cliffs 0xDC3092: [0x67C, 2], 0xDC3093: [0x67C, 3], 0xDC3094: [0x67C, 5], + 0xDC3191: [0x67C, 7], 0xDC3095: [0x67D, 1], # Tyrant Twin Tussle 0xDC3096: [0x67D, 2], 0xDC3097: [0x67D, 3], 0xDC3098: [0x67D, 4], 0xDC3099: [0x67D, 5], + 0xDC3195: [0x67D, 7], 0xDC309A: [0x663, 1], # Swoopy Salvo 0xDC309B: [0x663, 2], 0xDC309C: [0x663, 3], 0xDC309D: [0x663, 4], 0xDC309E: [0x663, 5], + 0xDC319A: [0x663, 7], 0xDC309F: [0x67E, 1], # Rocket Rush 0xDC30A0: [0x67E, 5], @@ -243,7 +330,7 @@ location_rom_data = { #0xDC30B4: [0x64D, 1], # Disabled until Trade Sequence 0xDC30B5: [0x64E, 1], - 0xDC30B6: [0x5FD, 4], # Banana Bird Mother + 0xDC30B6: [0x5FE, 4], # Banana Bird Mother # DKC3_TODO: Disabled until Trade Sequence #0xDC30B7: [0x615, 2, True], @@ -256,6 +343,18 @@ location_rom_data = { #0xDC30BE: [0x625, 4, True], } +boss_location_ids = [ + 0xDC30A1, + 0xDC30A2, + 0xDC30A3, + 0xDC30A4, + 0xDC30A5, + 0xDC30A6, + 0xDC30A7, + 0xDC30A8, + 0xDC30B6, +] + item_rom_data = { 0xDC3001: [0x5D5], # 1-Up Balloon @@ -400,7 +499,6 @@ def patch_rom(world, rom, player, active_level_list): rom.write_byte(0x3484DE, 0xEA) rom.write_byte(0x348528, 0x80) # Prevent Single-Ski Lock - # Make Swanky free rom.write_byte(0x348C48, 0x00) @@ -462,6 +560,25 @@ def patch_rom(world, rom, player, active_level_list): rom.write_byte(0x9130, world.starting_life_count[player].value) rom.write_byte(0x913B, world.starting_life_count[player].value) + # Cheat options + cheat_bytes = [0x00, 0x00] + + if world.merry[player]: + cheat_bytes[0] |= 0x01 + + if world.autosave[player]: + cheat_bytes[0] |= 0x02 + + if world.difficulty[player] == "tufst": + cheat_bytes[0] |= 0x80 + cheat_bytes[1] |= 0x80 + elif world.difficulty[player] == "hardr": + cheat_bytes[0] |= 0x00 + cheat_bytes[1] |= 0x00 + elif world.difficulty[player] == "norml": + cheat_bytes[1] |= 0x40 + + rom.write_bytes(0x8303, bytearray(cheat_bytes)) # Handle Level Shuffle Here if world.level_shuffle[player]: @@ -469,6 +586,9 @@ def patch_rom(world, rom, player, active_level_list): rom.write_byte(level_dict[level_list[i]].nameIDAddress, level_dict[active_level_list[i]].nameID) rom.write_byte(level_dict[level_list[i]].levelIDAddress, level_dict[active_level_list[i]].levelID) + rom.write_byte(0x3FF800 + level_dict[active_level_list[i]].levelID, level_dict[level_list[i]].levelID) + rom.write_byte(0x3FF860 + level_dict[level_list[i]].levelID, level_dict[active_level_list[i]].levelID) + # First levels of each world rom.write_byte(0x34BC3E, (0x32 + level_dict[active_level_list[0]].levelID)) rom.write_byte(0x34BC47, (0x32 + level_dict[active_level_list[5]].levelID)) @@ -495,6 +615,52 @@ def patch_rom(world, rom, player, active_level_list): rom.write_byte(0x32F339, 0x55) + # Handle KONGsanity Here + if world.kongsanity[player]: + # Arich's Hoard KONGsanity fix + rom.write_bytes(0x34BA8C, bytearray([0xEA, 0xEA])) + + # Don't hide the level flag if the 0x80 bit is set + rom.write_bytes(0x34CE92, bytearray([0x80])) + + # Use the `!` next to level name for indicating KONG letters + rom.write_bytes(0x34B8F0, bytearray([0x80])) + rom.write_bytes(0x34B8F3, bytearray([0x80])) + + # Hijack to code to set the 0x80 flag for the level when you complete KONG + rom.write_bytes(0x3BCD4B, bytearray([0x22, 0x80, 0xFA, 0XB8])) # JSL $B8FA80 + + rom.write_bytes(0x38FA80, bytearray([0xDA])) # PHX + rom.write_bytes(0x38FA81, bytearray([0x48])) # PHA + rom.write_bytes(0x38FA82, bytearray([0x08])) # PHP + rom.write_bytes(0x38FA83, bytearray([0xE2, 0x20])) # SEP #20 + rom.write_bytes(0x38FA85, bytearray([0x48])) # PHA + rom.write_bytes(0x38FA86, bytearray([0x18])) # CLC + rom.write_bytes(0x38FA87, bytearray([0x6D, 0xD3, 0x18])) # ADC $18D3 + rom.write_bytes(0x38FA8A, bytearray([0x8D, 0xD3, 0x18])) # STA $18D3 + rom.write_bytes(0x38FA8D, bytearray([0x68])) # PLA + rom.write_bytes(0x38FA8E, bytearray([0xC2, 0x20])) # REP 20 + rom.write_bytes(0x38FA90, bytearray([0X18])) # CLC + rom.write_bytes(0x38FA91, bytearray([0x6D, 0xD5, 0x05])) # ADC $05D5 + rom.write_bytes(0x38FA94, bytearray([0x8D, 0xD5, 0x05])) # STA $05D5 + rom.write_bytes(0x38FA97, bytearray([0xAE, 0xB9, 0x05])) # LDX $05B9 + rom.write_bytes(0x38FA9A, bytearray([0xBD, 0x32, 0x06])) # LDA $0632, X + rom.write_bytes(0x38FA9D, bytearray([0x09, 0x80, 0x00])) # ORA #8000 + rom.write_bytes(0x38FAA0, bytearray([0x9D, 0x32, 0x06])) # STA $0632, X + rom.write_bytes(0x38FAA3, bytearray([0xAD, 0xD5, 0x18])) # LDA $18D5 + rom.write_bytes(0x38FAA6, bytearray([0xD0, 0x03])) # BNE $80EA + rom.write_bytes(0x38FAA8, bytearray([0x9C, 0xD9, 0x18])) # STZ $18D9 + rom.write_bytes(0x38FAAB, bytearray([0xA9, 0x78, 0x00])) # LDA #0078 + rom.write_bytes(0x38FAAE, bytearray([0x8D, 0xD5, 0x18])) # STA $18D5 + rom.write_bytes(0x38FAB1, bytearray([0x28])) # PLP + rom.write_bytes(0x38FAB2, bytearray([0x68])) # PLA + rom.write_bytes(0x38FAB3, bytearray([0xFA])) # PLX + rom.write_bytes(0x38FAB4, bytearray([0x6B])) # RTL + # End Handle KONGsanity + + # Handle Credits + rom.write_bytes(0x32A5DF, bytearray([0x41, 0x52, 0x43, 0x48, 0x49, 0x50, 0x45, 0x4C, 0x41, 0x47, 0x4F, 0x20, 0x4D, 0x4F, 0xC4])) # "ARCHIPELAGO MOD" + rom.write_bytes(0x32A5EE, bytearray([0x00, 0x03, 0x50, 0x4F, 0x52, 0x59, 0x47, 0x4F, 0x4E, 0xC5])) # "PORYGONE" from Main import __version__ rom.name = bytearray(f'D3{__version__.replace(".", "")[0:3]}_{player}_{world.seed:11}\0', 'utf8')[:21] @@ -516,6 +682,17 @@ def patch_rom(world, rom, player, active_level_list): rom.write_byte(0x32DD63, 0xEA) rom.write_byte(0x32DD64, 0xEA) + # Don't grant Banana Birds at Bears + rom.write_byte(0x3492DB, 0xEA) + rom.write_byte(0x3492DC, 0xEA) + rom.write_byte(0x3492DD, 0xEA) + rom.write_byte(0x3493F4, 0xEA) + rom.write_byte(0x3493F5, 0xEA) + rom.write_byte(0x3493F6, 0xEA) + + # Don't grant present at Blizzard + rom.write_byte(0x8454, 0x00) + # Don't grant Patch and Skis from their bosses rom.write_byte(0x3F3762, 0x00) rom.write_byte(0x3F377B, 0x00) diff --git a/worlds/dkc3/__init__.py b/worlds/dkc3/__init__.py index f5b01ff723..5c575b85b5 100644 --- a/worlds/dkc3/__init__.py +++ b/worlds/dkc3/__init__.py @@ -4,7 +4,7 @@ import math import threading from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification -from .Items import DKC3Item, ItemData, item_table, inventory_table +from .Items import DKC3Item, ItemData, item_table, inventory_table, junk_table from .Locations import DKC3Location, all_locations, setup_locations from .Options import dkc3_options from .Regions import create_regions, connect_regions @@ -40,7 +40,7 @@ class DKC3World(World): game: str = "Donkey Kong Country 3" option_definitions = dkc3_options topology_present = False - data_version = 1 + data_version = 2 #hint_blacklist = {LocationName.rocket_rush_flag} item_name_to_id = {name: data.code for name, data in item_table.items()} @@ -99,10 +99,13 @@ class DKC3World(World): # Bosses total_required_locations += number_of_bosses - + # Secret Caves total_required_locations += 13 + if self.world.kongsanity[self.player]: + total_required_locations += 39 + ## Brothers Bear if False:#self.world.include_trade_sequence[self.player]: total_required_locations += 10 @@ -118,7 +121,11 @@ class DKC3World(World): total_junk_count = total_required_locations - len(itempool) - itempool += [self.create_item(ItemName.bear_coin)] * total_junk_count + junk_pool = [] + for item_name in self.world.random.choices(list(junk_table.keys()), k=total_junk_count): + junk_pool += [self.create_item(item_name)] + + itempool += junk_pool self.active_level_list = level_list.copy()