Donkey Kong Country 3 Implementation (#798)
* Baseline patching and logic for DKC3 * Client can send, but not yet receive * Alpha Test Baseline * Bug Fixes and Starting Lives Option * Finish BBH, add world hints * Add music shuffle * Boomer Costs Text * Stubbed in Collect behaviour * Adjust Gyrocopter option * Add Bonus Coin junk replacement and tracker support * Delete bad logs * Undo host.yaml change * Refactored SNIClient * Make Swanky Free * Fix Typo * Undo SNIClient run_game hack * Fix Typo * Remove Bosses from Level Shuffle * Remove duplicate kivy Data * Add DKC3 Docs and increment Data version * Remove dead code * Fix mislabeled region * Add Dark Souls 3 to README * Always force Cog on Rocket Rush Flag * Fix Single Ski lock and too many DK Coins * Update Retroarch version number * Don't send DKC3 through LttP Adjuster * Comment Location ROM Table * Change ROM Hash prefix to D3 * Remove redundant constructor * Add ROM Change Safeguards * Properly mark WRAM accesses * Remove outdated region connect * Fix syntax error * Fix Game description * Fix SNES Bank Access * Add isso_setup for DKC3 * Double Quote strings * Escape single quotes I guess
This commit is contained in:
parent
a7787d87f9
commit
cabbe0aaf6
|
@ -126,7 +126,7 @@ components: Iterable[Component] = (
|
|||
Component('Text Client', 'CommonClient', 'ArchipelagoTextClient'),
|
||||
# SNI
|
||||
Component('SNI Client', 'SNIClient',
|
||||
file_identifier=SuffixIdentifier('.apz3', '.apm3', '.apsoe', '.aplttp', '.apsm', '.apsmz3')),
|
||||
file_identifier=SuffixIdentifier('.apz3', '.apm3', '.apsoe', '.aplttp', '.apsm', '.apsmz3', '.apdkc3')),
|
||||
Component('LttP Adjuster', 'LttPAdjuster'),
|
||||
# Factorio
|
||||
Component('Factorio Client', 'FactorioClient'),
|
||||
|
|
26
Patch.py
26
Patch.py
|
@ -166,13 +166,15 @@ GAME_ALTTP = "A Link to the Past"
|
|||
GAME_SM = "Super Metroid"
|
||||
GAME_SOE = "Secret of Evermore"
|
||||
GAME_SMZ3 = "SMZ3"
|
||||
supported_games = {"A Link to the Past", "Super Metroid", "Secret of Evermore", "SMZ3"}
|
||||
GAME_DKC3 = "Donkey Kong Country 3"
|
||||
supported_games = {"A Link to the Past", "Super Metroid", "Secret of Evermore", "SMZ3", "Donkey Kong Country 3"}
|
||||
|
||||
preferred_endings = {
|
||||
GAME_ALTTP: "apbp",
|
||||
GAME_SM: "apm3",
|
||||
GAME_SOE: "apsoe",
|
||||
GAME_SMZ3: "apsmz"
|
||||
GAME_SMZ3: "apsmz",
|
||||
GAME_DKC3: "apdkc3"
|
||||
}
|
||||
|
||||
|
||||
|
@ -187,6 +189,8 @@ def generate_yaml(patch: bytes, metadata: Optional[dict] = None, game: str = GAM
|
|||
from worlds.alttp.Rom import LTTPJPN10HASH as ALTTPHASH
|
||||
from worlds.sm.Rom import SMJUHASH as SMHASH
|
||||
HASH = ALTTPHASH + SMHASH
|
||||
elif game == GAME_DKC3:
|
||||
from worlds.dkc3.Rom import USHASH as HASH
|
||||
else:
|
||||
raise RuntimeError(f"Selected game {game} for base rom not found.")
|
||||
|
||||
|
@ -216,7 +220,10 @@ def create_patch_file(rom_file_to_patch: str, server: str = "", destination: str
|
|||
meta,
|
||||
game)
|
||||
target = destination if destination else os.path.splitext(rom_file_to_patch)[0] + (
|
||||
".apbp" if game == GAME_ALTTP else ".apsmz" if game == GAME_SMZ3 else ".apm3")
|
||||
".apbp" if game == GAME_ALTTP
|
||||
else ".apsmz" if game == GAME_SMZ3
|
||||
else ".apdkc3" if game == GAME_DKC3
|
||||
else ".apm3")
|
||||
write_lzma(bytes, target)
|
||||
return target
|
||||
|
||||
|
@ -245,6 +252,8 @@ def get_base_rom_data(game: str):
|
|||
get_base_rom_bytes = lambda: bytes(read_rom(open(get_base_rom_path(), "rb")))
|
||||
elif game == GAME_SMZ3:
|
||||
from worlds.smz3.Rom import get_base_rom_bytes
|
||||
elif game == GAME_DKC3:
|
||||
from worlds.dkc3.Rom import get_base_rom_bytes
|
||||
else:
|
||||
raise RuntimeError("Selected game for base rom not found.")
|
||||
return get_base_rom_bytes()
|
||||
|
@ -389,6 +398,13 @@ if __name__ == "__main__":
|
|||
if 'server' in data:
|
||||
Utils.persistent_store("servers", data['hash'], data['server'])
|
||||
print(f"Host is {data['server']}")
|
||||
elif rom.endswith(".apdkc3"):
|
||||
print(f"Applying patch {rom}")
|
||||
data, target = create_rom_file(rom)
|
||||
print(f"Created rom {target}.")
|
||||
if 'server' in data:
|
||||
Utils.persistent_store("servers", data['hash'], data['server'])
|
||||
print(f"Host is {data['server']}")
|
||||
|
||||
elif rom.endswith(".zip"):
|
||||
print(f"Updating host in patch files contained in {rom}")
|
||||
|
@ -396,7 +412,9 @@ if __name__ == "__main__":
|
|||
|
||||
def _handle_zip_file_entry(zfinfo: zipfile.ZipInfo, server: str):
|
||||
data = zfr.read(zfinfo)
|
||||
if zfinfo.filename.endswith(".apbp") or zfinfo.filename.endswith(".apm3"):
|
||||
if zfinfo.filename.endswith(".apbp") or \
|
||||
zfinfo.filename.endswith(".apm3") or \
|
||||
zfinfo.filename.endswith(".apdkc3"):
|
||||
data = update_patch_data(data, server)
|
||||
with ziplock:
|
||||
zfw.writestr(zfinfo, data)
|
||||
|
|
|
@ -26,6 +26,8 @@ Currently, the following games are supported:
|
|||
* The Witness
|
||||
* Sonic Adventure 2: Battle
|
||||
* Starcraft 2: Wings of Liberty
|
||||
* Donkey Kong Country 3
|
||||
* Dark Souls 3
|
||||
|
||||
For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
|
||||
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled
|
||||
|
|
84
SNIClient.py
84
SNIClient.py
|
@ -33,7 +33,7 @@ from worlds.sm.Rom import ROM_PLAYER_LIMIT as SM_ROM_PLAYER_LIMIT
|
|||
from worlds.smz3.Rom import ROM_PLAYER_LIMIT as SMZ3_ROM_PLAYER_LIMIT
|
||||
import Utils
|
||||
from CommonClient import CommonContext, server_loop, ClientCommandProcessor, gui_enabled, get_base_parser
|
||||
from Patch import GAME_ALTTP, GAME_SM, GAME_SMZ3
|
||||
from Patch import GAME_ALTTP, GAME_SM, GAME_SMZ3, GAME_DKC3
|
||||
|
||||
snes_logger = logging.getLogger("SNES")
|
||||
|
||||
|
@ -251,6 +251,9 @@ async def deathlink_kill_player(ctx: Context):
|
|||
if not gamemode or gamemode[0] in SM_DEATH_MODES or (
|
||||
ctx.death_link_allow_survive and health is not None and health > 0):
|
||||
ctx.death_state = DeathState.dead
|
||||
elif ctx.game == GAME_DKC3:
|
||||
from worlds.dkc3.Client import deathlink_kill_player as dkc3_deathlink_kill_player
|
||||
await dkc3_deathlink_kill_player(ctx)
|
||||
ctx.last_death_link = time.time()
|
||||
|
||||
|
||||
|
@ -1034,44 +1037,48 @@ async def game_watcher(ctx: Context):
|
|||
if not ctx.rom:
|
||||
ctx.finished_game = False
|
||||
ctx.death_link_allow_survive = False
|
||||
game_name = await snes_read(ctx, SM_ROMNAME_START, 5)
|
||||
if game_name is None:
|
||||
continue
|
||||
elif game_name[:2] == b"SM":
|
||||
ctx.game = GAME_SM
|
||||
# versions lower than 0.3.0 dont have item handling flag nor remote item support
|
||||
romVersion = int(game_name[2:5].decode('UTF-8'))
|
||||
if romVersion < 30:
|
||||
ctx.items_handling = 0b001 # full local
|
||||
else:
|
||||
item_handling = await snes_read(ctx, SM_REMOTE_ITEM_FLAG_ADDR, 1)
|
||||
ctx.items_handling = 0b001 if item_handling is None else item_handling[0]
|
||||
else:
|
||||
game_name = await snes_read(ctx, SMZ3_ROMNAME_START, 3)
|
||||
if game_name == b"ZSM":
|
||||
ctx.game = GAME_SMZ3
|
||||
ctx.items_handling = 0b101 # local items and remote start inventory
|
||||
else:
|
||||
ctx.game = GAME_ALTTP
|
||||
ctx.items_handling = 0b001 # full local
|
||||
|
||||
rom = await snes_read(ctx, SM_ROMNAME_START if ctx.game == GAME_SM else SMZ3_ROMNAME_START if ctx.game == GAME_SMZ3 else ROMNAME_START, ROMNAME_SIZE)
|
||||
if rom is None or rom == bytes([0] * ROMNAME_SIZE):
|
||||
continue
|
||||
from worlds.dkc3.Client import dkc3_rom_init
|
||||
init_handled = await dkc3_rom_init(ctx)
|
||||
if not init_handled:
|
||||
game_name = await snes_read(ctx, SM_ROMNAME_START, 5)
|
||||
if game_name is None:
|
||||
continue
|
||||
elif game_name[:2] == b"SM":
|
||||
ctx.game = GAME_SM
|
||||
# versions lower than 0.3.0 dont have item handling flag nor remote item support
|
||||
romVersion = int(game_name[2:5].decode('UTF-8'))
|
||||
if romVersion < 30:
|
||||
ctx.items_handling = 0b001 # full local
|
||||
else:
|
||||
item_handling = await snes_read(ctx, SM_REMOTE_ITEM_FLAG_ADDR, 1)
|
||||
ctx.items_handling = 0b001 if item_handling is None else item_handling[0]
|
||||
else:
|
||||
game_name = await snes_read(ctx, SMZ3_ROMNAME_START, 3)
|
||||
if game_name == b"ZSM":
|
||||
ctx.game = GAME_SMZ3
|
||||
ctx.items_handling = 0b101 # local items and remote start inventory
|
||||
else:
|
||||
ctx.game = GAME_ALTTP
|
||||
ctx.items_handling = 0b001 # full local
|
||||
|
||||
ctx.rom = rom
|
||||
if ctx.game != GAME_SMZ3:
|
||||
death_link = await snes_read(ctx, DEATH_LINK_ACTIVE_ADDR if ctx.game == GAME_ALTTP else
|
||||
SM_DEATH_LINK_ACTIVE_ADDR, 1)
|
||||
if death_link:
|
||||
ctx.allow_collect = bool(death_link[0] & 0b100)
|
||||
ctx.death_link_allow_survive = bool(death_link[0] & 0b10)
|
||||
await ctx.update_death_link(bool(death_link[0] & 0b1))
|
||||
if not ctx.prev_rom or ctx.prev_rom != ctx.rom:
|
||||
ctx.locations_checked = set()
|
||||
ctx.locations_scouted = set()
|
||||
ctx.locations_info = {}
|
||||
ctx.prev_rom = ctx.rom
|
||||
rom = await snes_read(ctx, SM_ROMNAME_START if ctx.game == GAME_SM else SMZ3_ROMNAME_START if ctx.game == GAME_SMZ3 else ROMNAME_START, ROMNAME_SIZE)
|
||||
if rom is None or rom == bytes([0] * ROMNAME_SIZE):
|
||||
continue
|
||||
|
||||
ctx.rom = rom
|
||||
if ctx.game != GAME_SMZ3:
|
||||
death_link = await snes_read(ctx, DEATH_LINK_ACTIVE_ADDR if ctx.game == GAME_ALTTP else
|
||||
SM_DEATH_LINK_ACTIVE_ADDR, 1)
|
||||
if death_link:
|
||||
ctx.allow_collect = bool(death_link[0] & 0b100)
|
||||
ctx.death_link_allow_survive = bool(death_link[0] & 0b10)
|
||||
await ctx.update_death_link(bool(death_link[0] & 0b1))
|
||||
if not ctx.prev_rom or ctx.prev_rom != ctx.rom:
|
||||
ctx.locations_checked = set()
|
||||
ctx.locations_scouted = set()
|
||||
ctx.locations_info = {}
|
||||
ctx.prev_rom = ctx.rom
|
||||
|
||||
if ctx.awaiting_rom:
|
||||
await ctx.server_auth(False)
|
||||
|
@ -1279,6 +1286,9 @@ async def game_watcher(ctx: Context):
|
|||
color(ctx.item_names[item.item], 'red', 'bold'), color(ctx.player_names[item.player], 'yellow'),
|
||||
ctx.location_names[item.location], itemOutPtr, len(ctx.items_received)))
|
||||
await snes_flush_writes(ctx)
|
||||
elif ctx.game == GAME_DKC3:
|
||||
from worlds.dkc3.Client import dkc3_game_watcher
|
||||
await dkc3_game_watcher(ctx)
|
||||
|
||||
|
||||
async def run_game(romfile):
|
||||
|
|
|
@ -127,3 +127,12 @@ smz3_options:
|
|||
# True for operating system default program
|
||||
# Alternatively, a path to a program to open the .sfc file with
|
||||
rom_start: true
|
||||
dkc3_options:
|
||||
# File name of the DKC3 US rom
|
||||
rom_file: "Donkey Kong Country 3 - Dixie Kong's Double Trouble! (USA) (En,Fr).sfc"
|
||||
# Set this to your SNI folder location if you want the MultiClient to attempt an auto start, does nothing if not found
|
||||
sni: "SNI"
|
||||
# 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 .sfc file with
|
||||
rom_start: true
|
||||
|
|
|
@ -54,6 +54,7 @@ Name: "custom"; Description: "Custom installation"; Flags: iscustom
|
|||
Name: "core"; Description: "Core Files"; Types: full hosting playing custom; Flags: fixed
|
||||
Name: "generator"; Description: "Generator"; Types: full hosting
|
||||
Name: "generator/sm"; Description: "Super Metroid ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 3145728; Flags: disablenouninstallwarning
|
||||
Name: "generator/dkc3"; Description: "Donkey Kong Country 3 ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 3145728; Flags: disablenouninstallwarning
|
||||
Name: "generator/soe"; Description: "Secret of Evermore ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 3145728; Flags: disablenouninstallwarning
|
||||
Name: "generator/lttp"; Description: "A Link to the Past ROM Setup and Enemizer"; Types: full hosting; ExtraDiskSpaceRequired: 5191680
|
||||
Name: "generator/oot"; Description: "Ocarina of Time ROM Setup"; Types: full hosting; ExtraDiskSpaceRequired: 100663296; Flags: disablenouninstallwarning
|
||||
|
@ -62,6 +63,7 @@ Name: "client"; Description: "Clients"; Types: full playing
|
|||
Name: "client/sni"; Description: "SNI Client"; Types: full playing
|
||||
Name: "client/sni/lttp"; Description: "SNI Client - A Link to the Past Patch Setup"; Types: full playing; Flags: disablenouninstallwarning
|
||||
Name: "client/sni/sm"; Description: "SNI Client - Super Metroid Patch Setup"; Types: full playing; Flags: disablenouninstallwarning
|
||||
Name: "client/sni/dkc3"; Description: "SNI Client - Donkey Kong Country 3 Patch Setup"; Types: full playing; Flags: disablenouninstallwarning
|
||||
Name: "client/factorio"; Description: "Factorio"; Types: full playing
|
||||
Name: "client/minecraft"; Description: "Minecraft"; Types: full playing; ExtraDiskSpaceRequired: 226894278
|
||||
Name: "client/oot"; Description: "Ocarina of Time"; Types: full playing
|
||||
|
@ -76,6 +78,7 @@ NAME: "{app}"; Flags: setntfscompression; Permissions: everyone-modify users-mod
|
|||
[Files]
|
||||
Source: "{code:GetROMPath}"; DestDir: "{app}"; DestName: "Zelda no Densetsu - Kamigami no Triforce (Japan).sfc"; Flags: external; Components: client/sni/lttp or generator/lttp
|
||||
Source: "{code:GetSMROMPath}"; DestDir: "{app}"; DestName: "Super Metroid (JU).sfc"; Flags: external; Components: client/sni/sm or generator/sm
|
||||
Source: "{code:GetDKC3ROMPath}"; DestDir: "{app}"; DestName: "Donkey Kong Country 3 - Dixie Kong's Double Trouble! (USA) (En,Fr).sfc"; Flags: external; Components: client/sni/dkc3 or generator/dkc3
|
||||
Source: "{code:GetSoEROMPath}"; DestDir: "{app}"; DestName: "Secret of Evermore (USA).sfc"; Flags: external; Components: generator/soe
|
||||
Source: "{code:GetOoTROMPath}"; DestDir: "{app}"; DestName: "The Legend of Zelda - Ocarina of Time.z64"; Flags: external; Components: client/oot or generator/oot
|
||||
Source: "{#source_path}\*"; Excludes: "*.sfc, *.log, data\sprites\alttpr, SNI, EnemizerCLI, Archipelago*.exe"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
@ -143,6 +146,11 @@ Root: HKCR; Subkey: "{#MyAppName}smpatch"; ValueData: "Archi
|
|||
Root: HKCR; Subkey: "{#MyAppName}smpatch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}smpatch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: ""; Components: client/sni
|
||||
|
||||
Root: HKCR; Subkey: ".apdkc3"; ValueData: "{#MyAppName}dkc3patch"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}dkc3patch"; ValueData: "Archipelago Donkey Kong Country 3 Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}dkc3patch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}dkc3patch\shell\open\command"; ValueData: """{app}\ArchipelagoSNIClient.exe"" ""%1"""; ValueType: string; ValueName: ""; Components: client/sni
|
||||
|
||||
Root: HKCR; Subkey: ".apsmz3"; ValueData: "{#MyAppName}smz3patch"; Flags: uninsdeletevalue; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}smz3patch"; ValueData: "Archipelago SMZ3 Patch"; Flags: uninsdeletekey; ValueType: string; ValueName: ""; Components: client/sni
|
||||
Root: HKCR; Subkey: "{#MyAppName}smz3patch\DefaultIcon"; ValueData: "{app}\ArchipelagoSNIClient.exe,0"; ValueType: string; ValueName: ""; Components: client/sni
|
||||
|
@ -206,6 +214,9 @@ var LttPROMFilePage: TInputFileWizardPage;
|
|||
var smrom: string;
|
||||
var SMRomFilePage: TInputFileWizardPage;
|
||||
|
||||
var dkc3rom: string;
|
||||
var DKC3RomFilePage: TInputFileWizardPage;
|
||||
|
||||
var soerom: string;
|
||||
var SoERomFilePage: TInputFileWizardPage;
|
||||
|
||||
|
@ -295,6 +306,8 @@ begin
|
|||
Result := not (LttPROMFilePage.Values[0] = '')
|
||||
else if (assigned(SMROMFilePage)) and (CurPageID = SMROMFilePage.ID) then
|
||||
Result := not (SMROMFilePage.Values[0] = '')
|
||||
else if (assigned(DKC3ROMFilePage)) and (CurPageID = DKC3ROMFilePage.ID) then
|
||||
Result := not (DKC3ROMFilePage.Values[0] = '')
|
||||
else if (assigned(SoEROMFilePage)) and (CurPageID = SoEROMFilePage.ID) then
|
||||
Result := not (SoEROMFilePage.Values[0] = '')
|
||||
else if (assigned(OoTROMFilePage)) and (CurPageID = OoTROMFilePage.ID) then
|
||||
|
@ -335,6 +348,22 @@ begin
|
|||
Result := '';
|
||||
end;
|
||||
|
||||
function GetDKC3ROMPath(Param: string): string;
|
||||
begin
|
||||
if Length(dkc3rom) > 0 then
|
||||
Result := dkc3rom
|
||||
else if Assigned(DKC3RomFilePage) then
|
||||
begin
|
||||
R := CompareStr(GetSNESMD5OfFile(DKC3ROMFilePage.Values[0]), '120abf304f0c40fe059f6a192ed4f947')
|
||||
if R <> 0 then
|
||||
MsgBox('Donkey Kong Country 3 ROM validation failed. Very likely wrong file.', mbInformation, MB_OK);
|
||||
|
||||
Result := DKC3ROMFilePage.Values[0]
|
||||
end
|
||||
else
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function GetSoEROMPath(Param: string): string;
|
||||
begin
|
||||
if Length(soerom) > 0 then
|
||||
|
@ -379,6 +408,10 @@ begin
|
|||
if Length(smrom) = 0 then
|
||||
SMRomFilePage:= AddRomPage('Super Metroid (JU).sfc');
|
||||
|
||||
dkc3rom := CheckRom('Donkey Kong Country 3 - Dixie Kong''s Double Trouble! (USA) (En,Fr).sfc', '120abf304f0c40fe059f6a192ed4f947');
|
||||
if Length(dkc3rom) = 0 then
|
||||
DKC3RomFilePage:= AddRomPage('Donkey Kong Country 3 - Dixie Kong''s Double Trouble! (USA) (En,Fr).sfc');
|
||||
|
||||
soerom := CheckRom('Secret of Evermore (USA).sfc', '6e9c94511d04fac6e0a1e582c170be3a');
|
||||
if Length(soerom) = 0 then
|
||||
SoEROMFilePage:= AddRomPage('Secret of Evermore (USA).sfc');
|
||||
|
@ -392,6 +425,8 @@ begin
|
|||
Result := not (WizardIsComponentSelected('client/sni/lttp') or WizardIsComponentSelected('generator/lttp'));
|
||||
if (assigned(SMROMFilePage)) and (PageID = SMROMFilePage.ID) then
|
||||
Result := not (WizardIsComponentSelected('client/sni/sm') or WizardIsComponentSelected('generator/sm'));
|
||||
if (assigned(DKC3ROMFilePage)) and (PageID = DKC3ROMFilePage.ID) then
|
||||
Result := not (WizardIsComponentSelected('client/sni/dkc3') or WizardIsComponentSelected('generator/dkc3'));
|
||||
if (assigned(SoEROMFilePage)) and (PageID = SoEROMFilePage.ID) then
|
||||
Result := not (WizardIsComponentSelected('generator/soe'));
|
||||
if (assigned(OoTROMFilePage)) and (PageID = OoTROMFilePage.ID) then
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
import logging
|
||||
import asyncio
|
||||
|
||||
from NetUtils import ClientStatus, color
|
||||
from SNIClient import Context, snes_buffered_write, snes_flush_writes, snes_read
|
||||
from Patch import GAME_DKC3
|
||||
|
||||
snes_logger = logging.getLogger("SNES")
|
||||
|
||||
# DKC3 - DKC3_TODO: Check these values
|
||||
ROM_START = 0x000000
|
||||
WRAM_START = 0xF50000
|
||||
WRAM_SIZE = 0x20000
|
||||
SRAM_START = 0xE00000
|
||||
|
||||
SAVEDATA_START = WRAM_START + 0xF000
|
||||
SAVEDATA_SIZE = 0x500
|
||||
|
||||
DKC3_ROMNAME_START = 0x00FFC0
|
||||
DKC3_ROMHASH_START = 0x7FC0
|
||||
ROMNAME_SIZE = 0x15
|
||||
ROMHASH_SIZE = 0x15
|
||||
|
||||
DKC3_RECV_PROGRESS_ADDR = WRAM_START + 0x632 # DKC3_TODO: Find a permanent home for this
|
||||
DKC3_FILE_NAME_ADDR = WRAM_START + 0x5D9
|
||||
DEATH_LINK_ACTIVE_ADDR = DKC3_ROMNAME_START + 0x15 # DKC3_TODO: Find a permanent home for this
|
||||
|
||||
|
||||
async def deathlink_kill_player(ctx: Context):
|
||||
pass
|
||||
#if ctx.game == GAME_DKC3:
|
||||
# DKC3_TODO: Handle Receiving Deathlink
|
||||
|
||||
|
||||
async def dkc3_rom_init(ctx: Context):
|
||||
if not ctx.rom:
|
||||
ctx.finished_game = False
|
||||
ctx.death_link_allow_survive = False
|
||||
game_name = await snes_read(ctx, DKC3_ROMNAME_START, 0x15)
|
||||
if game_name is None or game_name != b"DONKEY KONG COUNTRY 3":
|
||||
return False
|
||||
else:
|
||||
ctx.game = GAME_DKC3
|
||||
ctx.items_handling = 0b111 # remote items
|
||||
|
||||
rom = await snes_read(ctx, DKC3_ROMHASH_START, ROMHASH_SIZE)
|
||||
if rom is None or rom == bytes([0] * ROMHASH_SIZE):
|
||||
return False
|
||||
|
||||
ctx.rom = rom
|
||||
|
||||
#death_link = await snes_read(ctx, DEATH_LINK_ACTIVE_ADDR, 1)
|
||||
## DKC3_TODO: Handle Deathlink
|
||||
#if death_link:
|
||||
# ctx.allow_collect = bool(death_link[0] & 0b100)
|
||||
# await ctx.update_death_link(bool(death_link[0] & 0b1))
|
||||
return True
|
||||
|
||||
|
||||
async def dkc3_game_watcher(ctx: Context):
|
||||
if ctx.game == GAME_DKC3:
|
||||
# DKC3_TODO: Handle Deathlink
|
||||
save_file_name = await snes_read(ctx, DKC3_FILE_NAME_ADDR, 0x5)
|
||||
if save_file_name is None or save_file_name[0] == 0x00:
|
||||
# We haven't loaded a save file
|
||||
return
|
||||
|
||||
new_checks = []
|
||||
from worlds.dkc3.Rom import location_rom_data, item_rom_data
|
||||
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)
|
||||
masked_data = data[0] & (1 << loc_data[1])
|
||||
bit_set = (masked_data != 0)
|
||||
invert_bit = ((len(loc_data) >= 3) and loc_data[2])
|
||||
if bit_set != invert_bit:
|
||||
# DKC3_TODO: Handle non-included checks
|
||||
new_checks.append(loc_id)
|
||||
|
||||
save_file_name = await snes_read(ctx, DKC3_FILE_NAME_ADDR, 0x5)
|
||||
if save_file_name is None or save_file_name[0] == 0x00:
|
||||
# We have somehow exited the save file
|
||||
return
|
||||
|
||||
rom = await snes_read(ctx, DKC3_ROMHASH_START, ROMHASH_SIZE)
|
||||
if rom != ctx.rom:
|
||||
ctx.rom = None
|
||||
# We have somehow loaded a different ROM
|
||||
return
|
||||
|
||||
for new_check_id in new_checks:
|
||||
ctx.locations_checked.add(new_check_id)
|
||||
location = ctx.location_names[new_check_id]
|
||||
snes_logger.info(
|
||||
f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})')
|
||||
await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": [new_check_id]}])
|
||||
|
||||
# DKC3_TODO: Make this actually visually display new things received (ASM Hook required)
|
||||
recv_count = await snes_read(ctx, DKC3_RECV_PROGRESS_ADDR, 1)
|
||||
recv_index = recv_count[0]
|
||||
|
||||
if recv_index < len(ctx.items_received):
|
||||
item = ctx.items_received[recv_index]
|
||||
recv_index += 1
|
||||
logging.info('Received %s from %s (%s) (%d/%d in list)' % (
|
||||
color(ctx.item_names[item.item], 'red', 'bold'),
|
||||
color(ctx.player_names[item.player], 'yellow'),
|
||||
ctx.location_names[item.location], recv_index, len(ctx.items_received)))
|
||||
|
||||
snes_buffered_write(ctx, DKC3_RECV_PROGRESS_ADDR, bytes([recv_index]))
|
||||
if item.item in item_rom_data:
|
||||
item_count = await snes_read(ctx, WRAM_START + item_rom_data[item.item][0], 0x1)
|
||||
new_item_count = item_count[0] + 1
|
||||
for address in item_rom_data[item.item]:
|
||||
snes_buffered_write(ctx, WRAM_START + address, bytes([new_item_count]))
|
||||
|
||||
# Handle Coin Displays
|
||||
current_level = await snes_read(ctx, WRAM_START + 0x5E3, 0x5)
|
||||
if item.item == 0xDC3002 and (current_level[0] == 0x0A and current_level[2] == 0x00 and current_level[4] == 0x03):
|
||||
# Bazaar and Barter
|
||||
item_count = await snes_read(ctx, WRAM_START + 0xB02, 0x1)
|
||||
new_item_count = item_count[0] + 1
|
||||
snes_buffered_write(ctx, WRAM_START + 0xB02, bytes([new_item_count]))
|
||||
elif item.item == 0xDC3002 and current_level[0] == 0x04:
|
||||
# Swanky
|
||||
item_count = await snes_read(ctx, WRAM_START + 0xA26, 0x1)
|
||||
new_item_count = item_count[0] + 1
|
||||
snes_buffered_write(ctx, WRAM_START + 0xA26, bytes([new_item_count]))
|
||||
elif item.item == 0xDC3003 and (current_level[0] == 0x0A and current_level[2] == 0x08 and current_level[4] == 0x01):
|
||||
# Boomer
|
||||
item_count = await snes_read(ctx, WRAM_START + 0xB02, 0x1)
|
||||
new_item_count = item_count[0] + 1
|
||||
snes_buffered_write(ctx, WRAM_START + 0xB02, bytes([new_item_count]))
|
||||
else:
|
||||
# Handle Patch and Skis
|
||||
if item.item == 0xDC3007:
|
||||
num_upgrades = 1
|
||||
inventory = await snes_read(ctx, WRAM_START + 0x605, 0xF)
|
||||
|
||||
if (inventory[0] & 0x02):
|
||||
num_upgrades = 3
|
||||
elif (inventory[13] & 0x08) or (inventory[0] & 0x01):
|
||||
num_upgrades = 2
|
||||
|
||||
if num_upgrades == 1:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x605, bytes([inventory[0] | 0x01]))
|
||||
if inventory[4] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x609, bytes([0x01]))
|
||||
elif inventory[6] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60B, bytes([0x01]))
|
||||
elif inventory[8] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60D, bytes([0x01]))
|
||||
elif inventory[10] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60F, bytes([0x01]))
|
||||
|
||||
cove_mekanos_progress = await snes_read(ctx, WRAM_START + 0x691, 0x2)
|
||||
snes_buffered_write(ctx, WRAM_START + 0x691, bytes([cove_mekanos_progress[0] | 0x01]))
|
||||
snes_buffered_write(ctx, WRAM_START + 0x692, bytes([cove_mekanos_progress[1] | 0x01]))
|
||||
elif num_upgrades == 2:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x605, bytes([inventory[0] | 0x02]))
|
||||
if inventory[4] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x609, bytes([0x02]))
|
||||
elif inventory[6] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60B, bytes([0x02]))
|
||||
elif inventory[8] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60D, bytes([0x02]))
|
||||
elif inventory[10] == 0:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x60F, bytes([0x02]))
|
||||
elif num_upgrades == 3:
|
||||
snes_buffered_write(ctx, WRAM_START + 0x606, bytes([inventory[1] | 0x20]))
|
||||
|
||||
k3_ridge_progress = await snes_read(ctx, WRAM_START + 0x693, 0x2)
|
||||
snes_buffered_write(ctx, WRAM_START + 0x693, bytes([k3_ridge_progress[0] | 0x01]))
|
||||
snes_buffered_write(ctx, WRAM_START + 0x694, bytes([k3_ridge_progress[1] | 0x01]))
|
||||
elif item.item == 0xDC3000:
|
||||
# Handle Victory
|
||||
if not ctx.finished_game:
|
||||
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
|
||||
ctx.finished_game = True
|
||||
else:
|
||||
print("Item Not Recognized: ", item.item)
|
||||
pass
|
||||
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
# 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)
|
||||
|
||||
# Calculate Boomer Cost Text
|
||||
boomer_cost_text = await snes_read(ctx, WRAM_START + 0xAAFD, 2)
|
||||
if boomer_cost_text[0] == 0x31 and boomer_cost_text[1] == 0x35:
|
||||
boomer_cost = await snes_read(ctx, ROM_START + 0x349857, 1)
|
||||
boomer_cost_tens = int(boomer_cost[0]) // 10
|
||||
boomer_cost_ones = int(boomer_cost[0]) % 10
|
||||
snes_buffered_write(ctx, WRAM_START + 0xAAFD, bytes([0x30 + boomer_cost_tens, 0x30 + boomer_cost_ones]))
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
boomer_final_cost_text = await snes_read(ctx, WRAM_START + 0xAB9B, 2)
|
||||
if boomer_final_cost_text[0] == 0x32 and boomer_final_cost_text[1] == 0x35:
|
||||
boomer_cost = await snes_read(ctx, ROM_START + 0x349857, 1)
|
||||
boomer_cost_tens = boomer_cost[0] // 10
|
||||
boomer_cost_ones = boomer_cost[0] % 10
|
||||
snes_buffered_write(ctx, WRAM_START + 0xAB9B, bytes([0x30 + boomer_cost_tens, 0x30 + boomer_cost_ones]))
|
||||
await snes_flush_writes(ctx)
|
|
@ -0,0 +1,52 @@
|
|||
import typing
|
||||
|
||||
from BaseClasses import Item, ItemClassification
|
||||
from .Names import ItemName
|
||||
|
||||
|
||||
class ItemData(typing.NamedTuple):
|
||||
code: typing.Optional[int]
|
||||
progression: bool
|
||||
quantity: int = 1
|
||||
event: bool = False
|
||||
|
||||
|
||||
class DKC3Item(Item):
|
||||
game: str = "Donkey Kong Country 3"
|
||||
|
||||
|
||||
# Separate tables for each type of item.
|
||||
junk_table = {
|
||||
ItemName.one_up_balloon: ItemData(0xDC3001, False),
|
||||
ItemName.bear_coin: ItemData(0xDC3002, False),
|
||||
}
|
||||
|
||||
collectable_table = {
|
||||
ItemName.bonus_coin: ItemData(0xDC3003, True),
|
||||
ItemName.dk_coin: ItemData(0xDC3004, True),
|
||||
ItemName.banana_bird: ItemData(0xDC3005, True),
|
||||
ItemName.krematoa_cog: ItemData(0xDC3006, True),
|
||||
ItemName.progressive_boat: ItemData(0xDC3007, True),
|
||||
}
|
||||
|
||||
inventory_table = {
|
||||
ItemName.present: ItemData(0xDC3008, True),
|
||||
ItemName.bowling_ball: ItemData(0xDC3009, True),
|
||||
ItemName.shell: ItemData(0xDC300A, True),
|
||||
ItemName.mirror: ItemData(0xDC300B, True),
|
||||
ItemName.flower: ItemData(0xDC300C, True),
|
||||
ItemName.wrench: ItemData(0xDC300D, True),
|
||||
}
|
||||
|
||||
event_table = {
|
||||
ItemName.victory: ItemData(0xDC3000, True),
|
||||
}
|
||||
|
||||
# Complete item table.
|
||||
item_table = {
|
||||
**junk_table,
|
||||
**collectable_table,
|
||||
**event_table,
|
||||
}
|
||||
|
||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
|
@ -0,0 +1,115 @@
|
|||
|
||||
from .Names import LocationName
|
||||
|
||||
class DKC3Level():
|
||||
nameIDAddress: int
|
||||
levelIDAddress: int
|
||||
nameID: int
|
||||
levelID: int
|
||||
|
||||
def __init__(self, nameIDAddress: int, levelIDAddress: int, nameID: int, levelID: int):
|
||||
self.nameIDAddress = nameIDAddress
|
||||
self.levelIDAddress = levelIDAddress
|
||||
self.nameID = nameID
|
||||
self.levelID = levelID
|
||||
|
||||
|
||||
level_dict = {
|
||||
LocationName.lakeside_limbo_region: DKC3Level(0x34D19C, 0x34D19D, 0x01, 0x25),
|
||||
LocationName.doorstop_dash_region: DKC3Level(0x34D1A7, 0x34D1A8, 0x02, 0x28),
|
||||
LocationName.tidal_trouble_region: DKC3Level(0x34D1BD, 0x34D1BE, 0x04, 0x27),
|
||||
LocationName.skiddas_row_region: DKC3Level(0x34D1C8, 0x34D1C9, 0x05, 0x2B),
|
||||
LocationName.murky_mill_region: DKC3Level(0x34D1D3, 0x34D1D4, 0x0D, 0x2A),
|
||||
|
||||
LocationName.barrel_shield_bust_up_region: DKC3Level(0x34D217, 0x34D218, 0x0B, 0x30),
|
||||
LocationName.riverside_race_region: DKC3Level(0x34D22D, 0x34D22E, 0x0C, 0x32),
|
||||
LocationName.squeals_on_wheels_region: DKC3Level(0x34D238, 0x34D239, 0x06, 0x29),
|
||||
LocationName.springin_spiders_region: DKC3Level(0x34D24E, 0x34D24F, 0x0E, 0x2F),
|
||||
LocationName.bobbing_barrel_brawl_region: DKC3Level(0x34D264, 0x34D265, 0x37, 0x34),
|
||||
|
||||
LocationName.bazzas_blockade_region: DKC3Level(0x34D29D, 0x34D29E, 0x14, 0x35),
|
||||
LocationName.rocket_barrel_ride_region: DKC3Level(0x34D2A8, 0x34D2A9, 0x15, 0x38),
|
||||
LocationName.kreeping_klasps_region: DKC3Level(0x34D2BE, 0x34D2BF, 0x16, 0x26),
|
||||
LocationName.tracker_barrel_trek_region: DKC3Level(0x34D2D4, 0x34D2D5, 0x17, 0x39),
|
||||
LocationName.fish_food_frenzy_region: DKC3Level(0x34D2DF, 0x34D2E0, 0x18, 0x36),
|
||||
|
||||
LocationName.fire_ball_frenzy_region: DKC3Level(0x34D30D, 0x34D30E, 0x1B, 0x3B),
|
||||
LocationName.demolition_drain_pipe_region: DKC3Level(0x34D323, 0x34D324, 0x1D, 0x40),
|
||||
LocationName.ripsaw_rage_region: DKC3Level(0x34D339, 0x34D33A, 0x1E, 0x2E),
|
||||
LocationName.blazing_bazookas_region: DKC3Level(0x34D34F, 0x34D350, 0x1F, 0x3C),
|
||||
LocationName.low_g_labyrinth_region: DKC3Level(0x34D35A, 0x34D35B, 0x20, 0x3E),
|
||||
|
||||
LocationName.krevice_kreepers_region: DKC3Level(0x34D388, 0x34D389, 0x23, 0x41),
|
||||
LocationName.tearaway_toboggan_region: DKC3Level(0x34D393, 0x34D394, 0x24, 0x2D),
|
||||
LocationName.barrel_drop_bounce_region: DKC3Level(0x34D39E, 0x34D39F, 0x25, 0x3A),
|
||||
LocationName.krack_shot_kroc_region: DKC3Level(0x34D3A9, 0x34D3AA, 0x26, 0x3D),
|
||||
LocationName.lemguin_lunge_region: DKC3Level(0x34D3B4, 0x34D3B5, 0x27, 0x2C),
|
||||
|
||||
LocationName.buzzer_barrage_region: DKC3Level(0x34D40E, 0x34D40F, 0x2B, 0x44),
|
||||
LocationName.kong_fused_cliffs_region: DKC3Level(0x34D424, 0x34D425, 0x2D, 0x42),
|
||||
LocationName.floodlit_fish_region: DKC3Level(0x34D42F, 0x34D430, 0x2E, 0x37),
|
||||
LocationName.pothole_panic_region: DKC3Level(0x34D43A, 0x34D43B, 0x2F, 0x45),
|
||||
LocationName.ropey_rumpus_region: DKC3Level(0x34D450, 0x34D451, 0x30, 0x43),
|
||||
|
||||
LocationName.konveyor_rope_clash_region: DKC3Level(0x34D489, 0x34D48A, 0x38, 0x48),
|
||||
LocationName.creepy_caverns_region: DKC3Level(0x34D49F, 0x34D4A0, 0x36, 0x46),
|
||||
LocationName.lightning_lookout_region: DKC3Level(0x34D4AA, 0x34D4AB, 0x10, 0x33),
|
||||
LocationName.koindozer_klamber_region: DKC3Level(0x34D4C0, 0x34D4C1, 0x34, 0x47),
|
||||
LocationName.poisonous_pipeline_region: DKC3Level(0x34D4D6, 0x34D4D7, 0x39, 0x3F),
|
||||
|
||||
LocationName.stampede_sprint_region: DKC3Level(0x34D51A, 0x34D51B, 0x3D, 0x49),
|
||||
LocationName.criss_cross_cliffs_region: DKC3Level(0x34D525, 0x34D526, 0x3E, 0x4A),
|
||||
LocationName.tyrant_twin_tussle_region: DKC3Level(0x34D530, 0x34D531, 0x3F, 0x4B),
|
||||
LocationName.swoopy_salvo_region: DKC3Level(0x34D53B, 0x34D53C, 0x40, 0x31),
|
||||
#LocationName.rocket_rush_region: DKC3Level(0x34D546, 0x34D547, 0x05, 0x4C), # Rocket Rush is not getting shuffled
|
||||
}
|
||||
|
||||
level_list = [
|
||||
LocationName.lakeside_limbo_region,
|
||||
LocationName.doorstop_dash_region,
|
||||
LocationName.tidal_trouble_region,
|
||||
LocationName.skiddas_row_region,
|
||||
LocationName.murky_mill_region,
|
||||
|
||||
LocationName.barrel_shield_bust_up_region,
|
||||
LocationName.riverside_race_region,
|
||||
LocationName.squeals_on_wheels_region,
|
||||
LocationName.springin_spiders_region,
|
||||
LocationName.bobbing_barrel_brawl_region,
|
||||
|
||||
LocationName.bazzas_blockade_region,
|
||||
LocationName.rocket_barrel_ride_region,
|
||||
LocationName.kreeping_klasps_region,
|
||||
LocationName.tracker_barrel_trek_region,
|
||||
LocationName.fish_food_frenzy_region,
|
||||
|
||||
LocationName.fire_ball_frenzy_region,
|
||||
LocationName.demolition_drain_pipe_region,
|
||||
LocationName.ripsaw_rage_region,
|
||||
LocationName.blazing_bazookas_region,
|
||||
LocationName.low_g_labyrinth_region,
|
||||
|
||||
LocationName.krevice_kreepers_region,
|
||||
LocationName.tearaway_toboggan_region,
|
||||
LocationName.barrel_drop_bounce_region,
|
||||
LocationName.krack_shot_kroc_region,
|
||||
LocationName.lemguin_lunge_region,
|
||||
|
||||
LocationName.buzzer_barrage_region,
|
||||
LocationName.kong_fused_cliffs_region,
|
||||
LocationName.floodlit_fish_region,
|
||||
LocationName.pothole_panic_region,
|
||||
LocationName.ropey_rumpus_region,
|
||||
|
||||
LocationName.konveyor_rope_clash_region,
|
||||
LocationName.creepy_caverns_region,
|
||||
LocationName.lightning_lookout_region,
|
||||
LocationName.koindozer_klamber_region,
|
||||
LocationName.poisonous_pipeline_region,
|
||||
|
||||
LocationName.stampede_sprint_region,
|
||||
LocationName.criss_cross_cliffs_region,
|
||||
LocationName.tyrant_twin_tussle_region,
|
||||
LocationName.swoopy_salvo_region,
|
||||
#LocationName.rocket_rush_region,
|
||||
]
|
|
@ -0,0 +1,283 @@
|
|||
import typing
|
||||
|
||||
from BaseClasses import Location
|
||||
from .Names import LocationName
|
||||
|
||||
|
||||
class DKC3Location(Location):
|
||||
game: str = "Donkey Kong Country 3"
|
||||
|
||||
progress_byte: int = 0x000000
|
||||
progress_bit: int = 0
|
||||
inverted_bit: bool = False
|
||||
|
||||
def __init__(self, player: int, name: str = '', address: int = None, parent=None, prog_byte: int = None, prog_bit: int = None, invert: bool = False):
|
||||
super().__init__(player, name, address, parent)
|
||||
self.progress_byte = prog_byte
|
||||
self.progress_bit = prog_bit
|
||||
self.inverted_bit = invert
|
||||
|
||||
|
||||
level_location_table = {
|
||||
LocationName.lakeside_limbo_flag: 0xDC3000,
|
||||
LocationName.lakeside_limbo_bonus_1: 0xDC3001,
|
||||
LocationName.lakeside_limbo_bonus_2: 0xDC3002,
|
||||
LocationName.lakeside_limbo_dk: 0xDC3003,
|
||||
|
||||
LocationName.doorstop_dash_flag: 0xDC3004,
|
||||
LocationName.doorstop_dash_bonus_1: 0xDC3005,
|
||||
LocationName.doorstop_dash_bonus_2: 0xDC3006,
|
||||
LocationName.doorstop_dash_dk: 0xDC3007,
|
||||
|
||||
LocationName.tidal_trouble_flag: 0xDC3008,
|
||||
LocationName.tidal_trouble_bonus_1: 0xDC3009,
|
||||
LocationName.tidal_trouble_bonus_2: 0xDC300A,
|
||||
LocationName.tidal_trouble_dk: 0xDC300B,
|
||||
|
||||
LocationName.skiddas_row_flag: 0xDC300C,
|
||||
LocationName.skiddas_row_bonus_1: 0xDC300D,
|
||||
LocationName.skiddas_row_bonus_2: 0xDC300E,
|
||||
LocationName.skiddas_row_dk: 0xDC300F,
|
||||
|
||||
LocationName.murky_mill_flag: 0xDC3010,
|
||||
LocationName.murky_mill_bonus_1: 0xDC3011,
|
||||
LocationName.murky_mill_bonus_2: 0xDC3012,
|
||||
LocationName.murky_mill_dk: 0xDC3013,
|
||||
|
||||
LocationName.barrel_shield_bust_up_flag: 0xDC3014,
|
||||
LocationName.barrel_shield_bust_up_bonus_1: 0xDC3015,
|
||||
LocationName.barrel_shield_bust_up_bonus_2: 0xDC3016,
|
||||
LocationName.barrel_shield_bust_up_dk: 0xDC3017,
|
||||
|
||||
LocationName.riverside_race_flag: 0xDC3018,
|
||||
LocationName.riverside_race_bonus_1: 0xDC3019,
|
||||
LocationName.riverside_race_bonus_2: 0xDC301A,
|
||||
LocationName.riverside_race_dk: 0xDC301B,
|
||||
|
||||
LocationName.squeals_on_wheels_flag: 0xDC301C,
|
||||
LocationName.squeals_on_wheels_bonus_1: 0xDC301D,
|
||||
LocationName.squeals_on_wheels_bonus_2: 0xDC301E,
|
||||
LocationName.squeals_on_wheels_dk: 0xDC301F,
|
||||
|
||||
LocationName.springin_spiders_flag: 0xDC3020,
|
||||
LocationName.springin_spiders_bonus_1: 0xDC3021,
|
||||
LocationName.springin_spiders_bonus_2: 0xDC3022,
|
||||
LocationName.springin_spiders_dk: 0xDC3023,
|
||||
|
||||
LocationName.bobbing_barrel_brawl_flag: 0xDC3024,
|
||||
LocationName.bobbing_barrel_brawl_bonus_1: 0xDC3025,
|
||||
LocationName.bobbing_barrel_brawl_bonus_2: 0xDC3026,
|
||||
LocationName.bobbing_barrel_brawl_dk: 0xDC3027,
|
||||
|
||||
LocationName.bazzas_blockade_flag: 0xDC3028,
|
||||
LocationName.bazzas_blockade_bonus_1: 0xDC3029,
|
||||
LocationName.bazzas_blockade_bonus_2: 0xDC302A,
|
||||
LocationName.bazzas_blockade_dk: 0xDC302B,
|
||||
|
||||
LocationName.rocket_barrel_ride_flag: 0xDC302C,
|
||||
LocationName.rocket_barrel_ride_bonus_1: 0xDC302D,
|
||||
LocationName.rocket_barrel_ride_bonus_2: 0xDC302E,
|
||||
LocationName.rocket_barrel_ride_dk: 0xDC302F,
|
||||
|
||||
LocationName.kreeping_klasps_flag: 0xDC3030,
|
||||
LocationName.kreeping_klasps_bonus_1: 0xDC3031,
|
||||
LocationName.kreeping_klasps_bonus_2: 0xDC3032,
|
||||
LocationName.kreeping_klasps_dk: 0xDC3033,
|
||||
|
||||
LocationName.tracker_barrel_trek_flag: 0xDC3034,
|
||||
LocationName.tracker_barrel_trek_bonus_1: 0xDC3035,
|
||||
LocationName.tracker_barrel_trek_bonus_2: 0xDC3036,
|
||||
LocationName.tracker_barrel_trek_dk: 0xDC3037,
|
||||
|
||||
LocationName.fish_food_frenzy_flag: 0xDC3038,
|
||||
LocationName.fish_food_frenzy_bonus_1: 0xDC3039,
|
||||
LocationName.fish_food_frenzy_bonus_2: 0xDC303A,
|
||||
LocationName.fish_food_frenzy_dk: 0xDC303B,
|
||||
|
||||
LocationName.fire_ball_frenzy_flag: 0xDC303C,
|
||||
LocationName.fire_ball_frenzy_bonus_1: 0xDC303D,
|
||||
LocationName.fire_ball_frenzy_bonus_2: 0xDC303E,
|
||||
LocationName.fire_ball_frenzy_dk: 0xDC303F,
|
||||
|
||||
LocationName.demolition_drain_pipe_flag: 0xDC3040,
|
||||
LocationName.demolition_drain_pipe_bonus_1: 0xDC3041,
|
||||
LocationName.demolition_drain_pipe_bonus_2: 0xDC3042,
|
||||
LocationName.demolition_drain_pipe_dk: 0xDC3043,
|
||||
|
||||
LocationName.ripsaw_rage_flag: 0xDC3044,
|
||||
LocationName.ripsaw_rage_bonus_1: 0xDC3045,
|
||||
LocationName.ripsaw_rage_bonus_2: 0xDC3046,
|
||||
LocationName.ripsaw_rage_dk: 0xDC3047,
|
||||
|
||||
LocationName.blazing_bazookas_flag: 0xDC3048,
|
||||
LocationName.blazing_bazookas_bonus_1: 0xDC3049,
|
||||
LocationName.blazing_bazookas_bonus_2: 0xDC304A,
|
||||
LocationName.blazing_bazookas_dk: 0xDC304B,
|
||||
|
||||
LocationName.low_g_labyrinth_flag: 0xDC304C,
|
||||
LocationName.low_g_labyrinth_bonus_1: 0xDC304D,
|
||||
LocationName.low_g_labyrinth_bonus_2: 0xDC304E,
|
||||
LocationName.low_g_labyrinth_dk: 0xDC304F,
|
||||
|
||||
LocationName.krevice_kreepers_flag: 0xDC3050,
|
||||
LocationName.krevice_kreepers_bonus_1: 0xDC3051,
|
||||
LocationName.krevice_kreepers_bonus_2: 0xDC3052,
|
||||
LocationName.krevice_kreepers_dk: 0xDC3053,
|
||||
|
||||
LocationName.tearaway_toboggan_flag: 0xDC3054,
|
||||
LocationName.tearaway_toboggan_bonus_1: 0xDC3055,
|
||||
LocationName.tearaway_toboggan_bonus_2: 0xDC3056,
|
||||
LocationName.tearaway_toboggan_dk: 0xDC3057,
|
||||
|
||||
LocationName.barrel_drop_bounce_flag: 0xDC3058,
|
||||
LocationName.barrel_drop_bounce_bonus_1: 0xDC3059,
|
||||
LocationName.barrel_drop_bounce_bonus_2: 0xDC305A,
|
||||
LocationName.barrel_drop_bounce_dk: 0xDC305B,
|
||||
|
||||
LocationName.krack_shot_kroc_flag: 0xDC305C,
|
||||
LocationName.krack_shot_kroc_bonus_1: 0xDC305D,
|
||||
LocationName.krack_shot_kroc_bonus_2: 0xDC305E,
|
||||
LocationName.krack_shot_kroc_dk: 0xDC305F,
|
||||
|
||||
LocationName.lemguin_lunge_flag: 0xDC3060,
|
||||
LocationName.lemguin_lunge_bonus_1: 0xDC3061,
|
||||
LocationName.lemguin_lunge_bonus_2: 0xDC3062,
|
||||
LocationName.lemguin_lunge_dk: 0xDC3063,
|
||||
|
||||
LocationName.buzzer_barrage_flag: 0xDC3064,
|
||||
LocationName.buzzer_barrage_bonus_1: 0xDC3065,
|
||||
LocationName.buzzer_barrage_bonus_2: 0xDC3066,
|
||||
LocationName.buzzer_barrage_dk: 0xDC3067,
|
||||
|
||||
LocationName.kong_fused_cliffs_flag: 0xDC3068,
|
||||
LocationName.kong_fused_cliffs_bonus_1: 0xDC3069,
|
||||
LocationName.kong_fused_cliffs_bonus_2: 0xDC306A,
|
||||
LocationName.kong_fused_cliffs_dk: 0xDC306B,
|
||||
|
||||
LocationName.floodlit_fish_flag: 0xDC306C,
|
||||
LocationName.floodlit_fish_bonus_1: 0xDC306D,
|
||||
LocationName.floodlit_fish_bonus_2: 0xDC306E,
|
||||
LocationName.floodlit_fish_dk: 0xDC306F,
|
||||
|
||||
LocationName.pothole_panic_flag: 0xDC3070,
|
||||
LocationName.pothole_panic_bonus_1: 0xDC3071,
|
||||
LocationName.pothole_panic_bonus_2: 0xDC3072,
|
||||
LocationName.pothole_panic_dk: 0xDC3073,
|
||||
|
||||
LocationName.ropey_rumpus_flag: 0xDC3074,
|
||||
LocationName.ropey_rumpus_bonus_1: 0xDC3075,
|
||||
LocationName.ropey_rumpus_bonus_2: 0xDC3076,
|
||||
LocationName.ropey_rumpus_dk: 0xDC3077,
|
||||
|
||||
LocationName.konveyor_rope_clash_flag: 0xDC3078,
|
||||
LocationName.konveyor_rope_clash_bonus_1: 0xDC3079,
|
||||
LocationName.konveyor_rope_clash_bonus_2: 0xDC307A,
|
||||
LocationName.konveyor_rope_clash_dk: 0xDC307B,
|
||||
|
||||
LocationName.creepy_caverns_flag: 0xDC307C,
|
||||
LocationName.creepy_caverns_bonus_1: 0xDC307D,
|
||||
LocationName.creepy_caverns_bonus_2: 0xDC307E,
|
||||
LocationName.creepy_caverns_dk: 0xDC307F,
|
||||
|
||||
LocationName.lightning_lookout_flag: 0xDC3080,
|
||||
LocationName.lightning_lookout_bonus_1: 0xDC3081,
|
||||
LocationName.lightning_lookout_bonus_2: 0xDC3082,
|
||||
LocationName.lightning_lookout_dk: 0xDC3083,
|
||||
|
||||
LocationName.koindozer_klamber_flag: 0xDC3084,
|
||||
LocationName.koindozer_klamber_bonus_1: 0xDC3085,
|
||||
LocationName.koindozer_klamber_bonus_2: 0xDC3086,
|
||||
LocationName.koindozer_klamber_dk: 0xDC3087,
|
||||
|
||||
LocationName.poisonous_pipeline_flag: 0xDC3088,
|
||||
LocationName.poisonous_pipeline_bonus_1: 0xDC3089,
|
||||
LocationName.poisonous_pipeline_bonus_2: 0xDC308A,
|
||||
LocationName.poisonous_pipeline_dk: 0xDC308B,
|
||||
|
||||
LocationName.stampede_sprint_flag: 0xDC308C,
|
||||
LocationName.stampede_sprint_bonus_1: 0xDC308D,
|
||||
LocationName.stampede_sprint_bonus_2: 0xDC308E,
|
||||
LocationName.stampede_sprint_bonus_3: 0xDC308F,
|
||||
LocationName.stampede_sprint_dk: 0xDC3090,
|
||||
|
||||
LocationName.criss_cross_cliffs_flag: 0xDC3091,
|
||||
LocationName.criss_cross_cliffs_bonus_1: 0xDC3092,
|
||||
LocationName.criss_cross_cliffs_bonus_2: 0xDC3093,
|
||||
LocationName.criss_cross_cliffs_dk: 0xDC3094,
|
||||
|
||||
LocationName.tyrant_twin_tussle_flag: 0xDC3095,
|
||||
LocationName.tyrant_twin_tussle_bonus_1: 0xDC3096,
|
||||
LocationName.tyrant_twin_tussle_bonus_2: 0xDC3097,
|
||||
LocationName.tyrant_twin_tussle_bonus_3: 0xDC3098,
|
||||
LocationName.tyrant_twin_tussle_dk: 0xDC3099,
|
||||
|
||||
LocationName.swoopy_salvo_flag: 0xDC309A,
|
||||
LocationName.swoopy_salvo_bonus_1: 0xDC309B,
|
||||
LocationName.swoopy_salvo_bonus_2: 0xDC309C,
|
||||
LocationName.swoopy_salvo_bonus_3: 0xDC309D,
|
||||
LocationName.swoopy_salvo_dk: 0xDC309E,
|
||||
|
||||
LocationName.rocket_rush_flag: 0xDC309F,
|
||||
LocationName.rocket_rush_dk: 0xDC30A0,
|
||||
}
|
||||
|
||||
|
||||
boss_location_table = {
|
||||
LocationName.belchas_barn: 0xDC30A1,
|
||||
LocationName.arichs_ambush: 0xDC30A2,
|
||||
LocationName.squirts_showdown: 0xDC30A3,
|
||||
LocationName.kaos_karnage: 0xDC30A4,
|
||||
LocationName.bleaks_house: 0xDC30A5,
|
||||
LocationName.barboss_barrier: 0xDC30A6,
|
||||
LocationName.kastle_kaos: 0xDC30A7,
|
||||
LocationName.knautilus: 0xDC30A8,
|
||||
}
|
||||
|
||||
secret_cave_location_table = {
|
||||
LocationName.belchas_burrow: 0xDC30A9,
|
||||
LocationName.kong_cave: 0xDC30AA,
|
||||
LocationName.undercover_cove: 0xDC30AB,
|
||||
LocationName.ks_cache: 0xDC30AC,
|
||||
LocationName.hill_top_hoard: 0xDC30AD,
|
||||
LocationName.bounty_beach: 0xDC30AE,
|
||||
LocationName.smugglers_cove: 0xDC30AF,
|
||||
LocationName.arichs_hoard: 0xDC30B0,
|
||||
LocationName.bounty_bay: 0xDC30B1,
|
||||
LocationName.sky_high_secret: 0xDC30B2,
|
||||
LocationName.glacial_grotto: 0xDC30B3,
|
||||
LocationName.cifftop_cache: 0xDC30B4,
|
||||
LocationName.sewer_stockpile: 0xDC30B5,
|
||||
LocationName.banana_bird_mother: 0xDC30B6,
|
||||
}
|
||||
|
||||
brothers_bear_location_table = {
|
||||
LocationName.bazaars_general_store_1: 0xDC30B7,
|
||||
LocationName.bazaars_general_store_2: 0xDC30B8,
|
||||
LocationName.brambles_bungalow: 0xDC30B9,
|
||||
LocationName.flower_spot: 0xDC30BA,
|
||||
LocationName.barters_swap_shop: 0xDC30BB,
|
||||
LocationName.barnacles_island: 0xDC30BC,
|
||||
LocationName.blues_beach_hut: 0xDC30BD,
|
||||
LocationName.blizzards_basecamp: 0xDC30BE,
|
||||
}
|
||||
|
||||
all_locations = {
|
||||
**level_location_table,
|
||||
**boss_location_table,
|
||||
**secret_cave_location_table,
|
||||
**brothers_bear_location_table,
|
||||
}
|
||||
|
||||
location_table = {}
|
||||
|
||||
|
||||
def setup_locations(world, player: int):
|
||||
location_table = {**level_location_table, **boss_location_table, **secret_cave_location_table}
|
||||
|
||||
if False:#world.include_trade_sequence[player].value:
|
||||
location_table.update({**brothers_bear_location_table})
|
||||
|
||||
return location_table
|
||||
|
||||
|
||||
lookup_id_to_name: typing.Dict[int, str] = {id: name for name, _ in all_locations.items()}
|
|
@ -0,0 +1,21 @@
|
|||
# Junk Definitions
|
||||
one_up_balloon = "1-Up Balloon"
|
||||
bear_coin = "Bear Coin"
|
||||
|
||||
# Collectable Definitions
|
||||
bonus_coin = "Bonus Coin"
|
||||
dk_coin = "DK Coin"
|
||||
banana_bird = "Banana Bird"
|
||||
krematoa_cog = "Krematoa Cog"
|
||||
|
||||
# Inventory Definitions
|
||||
progressive_boat = "Progressive Boat Upgrade"
|
||||
present = "Present"
|
||||
bowling_ball = "Bowling Ball"
|
||||
shell = "Shell"
|
||||
mirror = "Mirror"
|
||||
flower = "Flupperius Petallus Pongus"
|
||||
wrench = "No. 6 Wrench"
|
||||
|
||||
# Other Definitions
|
||||
victory = "Donkey Kong"
|
|
@ -0,0 +1,336 @@
|
|||
# Level Definitions
|
||||
lakeside_limbo_flag = "Lakeside Limbo - Flag"
|
||||
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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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"
|
||||
|
||||
low_g_labyrinth_flag = "Low-G Labyrinth - Flag"
|
||||
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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_bonus_1 = "Swoopy Salvo - Bonus 1"
|
||||
swoopy_salvo_bonus_2 = "Swoopy Salvo - Bonus 2"
|
||||
swoopy_salvo_bonus_3 = "Swoopy Salvo - Bonus 3"
|
||||
swoopy_salvo_dk = "Swoopy Salvo - DK Coin"
|
||||
|
||||
rocket_rush_flag = "Rocket Rush - Flag"
|
||||
rocket_rush_dk = "Rocket Rush - DK Coin"
|
||||
|
||||
# Boss Definitions
|
||||
belchas_barn = "Belcha's Barn"
|
||||
arichs_ambush = "Arich's Ambush"
|
||||
squirts_showdown = "Squirt's Showdown"
|
||||
kaos_karnage = "KAOS Karnage"
|
||||
bleaks_house = "Bleak's House"
|
||||
barboss_barrier = "Barbos's Barrier"
|
||||
kastle_kaos = "Kastle KAOS"
|
||||
knautilus = "Knautilus"
|
||||
|
||||
|
||||
# Banana Bird Cave Definitions
|
||||
belchas_burrow = "Belcha's Burrow"
|
||||
kong_cave = "Kong Cave"
|
||||
undercover_cove = "Undercover Cove"
|
||||
ks_cache = "K's Cache"
|
||||
hill_top_hoard = "Hill-Top Hoard"
|
||||
bounty_beach = "Bounty Beach"
|
||||
smugglers_cove = "Smuggler's Cove"
|
||||
arichs_hoard = "Arich's Hoard"
|
||||
bounty_bay = "Bounty Bay"
|
||||
sky_high_secret = "Sky-High Secret"
|
||||
glacial_grotto = "Glacial Grotto"
|
||||
cifftop_cache = "Clifftop Cache"
|
||||
sewer_stockpile = "Sewer Stockpile"
|
||||
|
||||
banana_bird_mother = "Banana Bird Mother"
|
||||
|
||||
|
||||
# Brothers Bear Definitions
|
||||
bazaars_general_store_1 = "Bazaar's General Store - 1"
|
||||
bazaars_general_store_2 = "Bazaar's General Store - 2"
|
||||
brambles_bungalow = "Bramble's Bungalow"
|
||||
flower_spot = "Flower Spot"
|
||||
barters_swap_shop = "Barter's Swap Shop"
|
||||
barnacles_island = "Barnacle's Island"
|
||||
blues_beach_hut = "Blue's Beach Hut"
|
||||
blizzards_basecamp = "Bizzard's Basecamp"
|
||||
|
||||
|
||||
# Region Definitions
|
||||
menu_region = "Menu"
|
||||
overworld_1_region = "Overworld 1"
|
||||
overworld_2_region = "Overworld 2"
|
||||
overworld_3_region = "Overworld 3"
|
||||
overworld_4_region = "Overworld 4"
|
||||
|
||||
bazaar_region = "Bazaar's General Store Region"
|
||||
bramble_region = "Bramble's Bungalow Region"
|
||||
flower_spot_region = "Flower Spot Region"
|
||||
barter_region = "Barter's Swap Shop Region"
|
||||
barnacle_region = "Barnacle's Island Region"
|
||||
blue_region = "Blue's Beach Hut Region"
|
||||
blizzard_region = "Bizzard's Basecamp Region"
|
||||
|
||||
lake_orangatanga_region = "Lake_Orangatanga"
|
||||
kremwood_forest_region = "Kremwood Forest"
|
||||
cotton_top_cove_region = "Cotton-Top Cove"
|
||||
mekanos_region = "Mekanos"
|
||||
k3_region = "K3"
|
||||
razor_ridge_region = "Razor Ridge"
|
||||
kaos_kore_region = "KAOS Kore"
|
||||
krematoa_region = "Krematoa"
|
||||
|
||||
belchas_barn_region = "Belcha's Barn Region"
|
||||
arichs_ambush_region = "Arich's Ambush Region"
|
||||
squirts_showdown_region = "Squirt's Showdown Region"
|
||||
kaos_karnage_region = "KAOS Karnage Region"
|
||||
bleaks_house_region = "Bleak's House Region"
|
||||
barboss_barrier_region = "Barbos's Barrier Region"
|
||||
kastle_kaos_region = "Kastle KAOS Region"
|
||||
knautilus_region = "Knautilus Region"
|
||||
|
||||
belchas_burrow_region = "Belcha's Burrow Region"
|
||||
kong_cave_region = "Kong Cave Region"
|
||||
undercover_cove_region = "Undercover Cove Region"
|
||||
ks_cache_region = "K's Cache Region"
|
||||
hill_top_hoard_region = "Hill-Top Hoard Region"
|
||||
bounty_beach_region = "Bounty Beach Region"
|
||||
smugglers_cove_region = "Smuggler's Cove Region"
|
||||
arichs_hoard_region = "Arich's Hoard Region"
|
||||
bounty_bay_region = "Bounty Bay Region"
|
||||
sky_high_secret_region = "Sky-High Secret Region"
|
||||
glacial_grotto_region = "Glacial Grotto Region"
|
||||
cifftop_cache_region = "Clifftop Cache Region"
|
||||
sewer_stockpile_region = "Sewer Stockpile Region"
|
||||
|
||||
lakeside_limbo_region = "Lakeside Limbo"
|
||||
doorstop_dash_region = "Doorstop Dash"
|
||||
tidal_trouble_region = "Tidal Trouble"
|
||||
skiddas_row_region = "Skidda's Row"
|
||||
murky_mill_region = "Murky Mill"
|
||||
|
||||
barrel_shield_bust_up_region = "Barrel Shield Bust-Up"
|
||||
riverside_race_region = "Riverside Race"
|
||||
squeals_on_wheels_region = "Squeals On Wheels"
|
||||
springin_spiders_region = "Springin' Spiders"
|
||||
bobbing_barrel_brawl_region = "Bobbing Barrel Brawl"
|
||||
|
||||
bazzas_blockade_region = "Bazza's Blockade"
|
||||
rocket_barrel_ride_region = "Rocket Barrel Ride"
|
||||
kreeping_klasps_region = "Kreeping Klasps"
|
||||
tracker_barrel_trek_region = "Tracker Barrel Trek"
|
||||
fish_food_frenzy_region = "Fish Food Frenzy"
|
||||
|
||||
fire_ball_frenzy_region = "Fire-Ball Frenzy"
|
||||
demolition_drain_pipe_region = "Demolition Drain-Pipe"
|
||||
ripsaw_rage_region = "Ripsaw Rage"
|
||||
blazing_bazookas_region = "Blazing Bazukas"
|
||||
low_g_labyrinth_region = "Low-G Labyrinth"
|
||||
|
||||
krevice_kreepers_region = "Krevice Kreepers"
|
||||
tearaway_toboggan_region = "Tearaway Toboggan"
|
||||
barrel_drop_bounce_region = "Barrel Drop Bounce"
|
||||
krack_shot_kroc_region = "Krack-Shot Kroc"
|
||||
lemguin_lunge_region = "Lemguin Lunge"
|
||||
|
||||
buzzer_barrage_region = "Buzzer Barrage"
|
||||
kong_fused_cliffs_region = "Kong-Fused Cliffs"
|
||||
floodlit_fish_region = "Floodlit Fish"
|
||||
pothole_panic_region = "Pothole Panic"
|
||||
ropey_rumpus_region = "Ropey Rumpus"
|
||||
|
||||
konveyor_rope_clash_region = "Konveyor Rope Klash"
|
||||
creepy_caverns_region = "Creepy Caverns"
|
||||
lightning_lookout_region = "Lightning Lookout"
|
||||
koindozer_klamber_region = "Koindozer Klamber"
|
||||
poisonous_pipeline_region = "Poisonous Pipeline"
|
||||
|
||||
stampede_sprint_region = "Stampede Sprint"
|
||||
criss_cross_cliffs_region = "Criss Kross Cliffs"
|
||||
tyrant_twin_tussle_region = "Tyrant Twin Tussle"
|
||||
swoopy_salvo_region = "Swoopy Salvo"
|
||||
rocket_rush_region = "Rocket Rush"
|
|
@ -0,0 +1,132 @@
|
|||
import typing
|
||||
|
||||
from Options import Choice, Range, Option, Toggle, DeathLink, DefaultOnToggle, OptionList
|
||||
|
||||
|
||||
class Goal(Choice):
|
||||
"""
|
||||
Determines the goal of the seed
|
||||
Knautilus: Reach the Knautilus and defeat Baron K. Roolenstein
|
||||
Banana Bird Hunt: Find a certain number of Banana Birds and rescue their mother
|
||||
"""
|
||||
display_name = "Goal"
|
||||
option_knautilus = 0
|
||||
option_banana_bird_hunt = 1
|
||||
default = 0
|
||||
|
||||
|
||||
class IncludeTradeSequence(Toggle):
|
||||
"""
|
||||
Allows logic to place items at the various steps of the trade sequence
|
||||
"""
|
||||
display_name = "Include Trade Sequence"
|
||||
|
||||
|
||||
class DKCoinsForGyrocopter(Range):
|
||||
"""
|
||||
How many DK Coins are needed to unlock the Gyrocopter
|
||||
Note: Achieving this number before unlocking the Turbo Ski will cause the game to grant you a
|
||||
one-time upgrade to the next non-unlocked boat, until you return to Funky. Logic does not assume
|
||||
that you will use this.
|
||||
"""
|
||||
display_name = "DK Coins for Gyrocopter"
|
||||
range_start = 10
|
||||
range_end = 41
|
||||
default = 30
|
||||
|
||||
|
||||
class KrematoaBonusCoinCost(Range):
|
||||
"""
|
||||
How many Bonus Coins are needed to unlock each level in Krematoa
|
||||
"""
|
||||
display_name = "Krematoa Bonus Coins Cost"
|
||||
range_start = 1
|
||||
range_end = 17
|
||||
default = 15
|
||||
|
||||
|
||||
class PercentageOfExtraBonusCoins(Range):
|
||||
"""
|
||||
What Percentage of unneeded Bonus Coins are included in the item pool
|
||||
"""
|
||||
display_name = "Percentage of Extra Bonus Coins"
|
||||
range_start = 0
|
||||
range_end = 100
|
||||
default = 100
|
||||
|
||||
|
||||
class NumberOfBananaBirds(Range):
|
||||
"""
|
||||
How many Banana Birds are put into the item pool
|
||||
"""
|
||||
display_name = "Number of Banana Birds"
|
||||
range_start = 5
|
||||
range_end = 15
|
||||
default = 15
|
||||
|
||||
|
||||
class PercentageOfBananaBirds(Range):
|
||||
"""
|
||||
What Percentage of Banana Birds in the item pool are required for Banana Bird Hunt
|
||||
"""
|
||||
display_name = "Percentage of Banana Birds"
|
||||
range_start = 20
|
||||
range_end = 100
|
||||
default = 100
|
||||
|
||||
|
||||
class LevelShuffle(Toggle):
|
||||
"""
|
||||
Whether levels are shuffled
|
||||
"""
|
||||
display_name = "Level Shuffle"
|
||||
|
||||
|
||||
class MusicShuffle(Toggle):
|
||||
"""
|
||||
Whether music is shuffled
|
||||
"""
|
||||
display_name = "Music Shuffle"
|
||||
|
||||
|
||||
class KongPaletteSwap(Choice):
|
||||
"""
|
||||
Which Palette to use for the Kongs
|
||||
"""
|
||||
display_name = "Kong Palette Swap"
|
||||
option_default = 0
|
||||
option_purple = 1
|
||||
option_spooky = 2
|
||||
option_dark = 3
|
||||
option_chocolate = 4
|
||||
option_shadow = 5
|
||||
option_red_gold = 6
|
||||
option_gbc = 7
|
||||
option_halloween = 8
|
||||
default = 0
|
||||
|
||||
|
||||
class StartingLifeCount(Range):
|
||||
"""
|
||||
How many extra lives to start the game with
|
||||
"""
|
||||
display_name = "Starting Life Count"
|
||||
range_start = 1
|
||||
range_end = 99
|
||||
default = 5
|
||||
|
||||
|
||||
dkc3_options: typing.Dict[str, type(Option)] = {
|
||||
#"death_link": DeathLink, # Disabled
|
||||
"goal": Goal,
|
||||
#"include_trade_sequence": IncludeTradeSequence, # Disabled
|
||||
"dk_coins_for_gyrocopter": DKCoinsForGyrocopter,
|
||||
"krematoa_bonus_coin_cost": KrematoaBonusCoinCost,
|
||||
"percentage_of_extra_bonus_coins": PercentageOfExtraBonusCoins,
|
||||
"number_of_banana_birds": NumberOfBananaBirds,
|
||||
"percentage_of_banana_birds": PercentageOfBananaBirds,
|
||||
"level_shuffle": LevelShuffle,
|
||||
"music_shuffle": MusicShuffle,
|
||||
"kong_palette_swap": KongPaletteSwap,
|
||||
"starting_life_count": StartingLifeCount,
|
||||
}
|
|
@ -0,0 +1,879 @@
|
|||
import typing
|
||||
|
||||
from BaseClasses import MultiWorld, Region, Entrance
|
||||
from .Items import DKC3Item
|
||||
from .Locations import DKC3Location
|
||||
from .Names import LocationName, ItemName
|
||||
|
||||
|
||||
def create_regions(world, player: int, active_locations):
|
||||
menu_region = create_region(world, player, active_locations, 'Menu', None, None)
|
||||
|
||||
overworld_1_region_locations = {}
|
||||
if world.goal[player] != "knautilus":
|
||||
overworld_1_region_locations.update({LocationName.banana_bird_mother: []})
|
||||
overworld_1_region = create_region(world, player, active_locations, LocationName.overworld_1_region,
|
||||
overworld_1_region_locations, None)
|
||||
|
||||
overworld_2_region_locations = {}
|
||||
overworld_2_region = create_region(world, player, active_locations, LocationName.overworld_2_region,
|
||||
overworld_2_region_locations, None)
|
||||
|
||||
overworld_3_region_locations = {}
|
||||
overworld_3_region = create_region(world, player, active_locations, LocationName.overworld_3_region,
|
||||
overworld_3_region_locations, None)
|
||||
|
||||
overworld_4_region_locations = {}
|
||||
overworld_4_region = create_region(world, player, active_locations, LocationName.overworld_4_region,
|
||||
overworld_4_region_locations, None)
|
||||
|
||||
|
||||
lake_orangatanga_region = create_region(world, player, active_locations, LocationName.lake_orangatanga_region, None, None)
|
||||
kremwood_forest_region = create_region(world, player, active_locations, LocationName.kremwood_forest_region, None, None)
|
||||
cotton_top_cove_region = create_region(world, player, active_locations, LocationName.cotton_top_cove_region, None, None)
|
||||
mekanos_region = create_region(world, player, active_locations, LocationName.mekanos_region, None, None)
|
||||
k3_region = create_region(world, player, active_locations, LocationName.k3_region, None, None)
|
||||
razor_ridge_region = create_region(world, player, active_locations, LocationName.razor_ridge_region, None, None)
|
||||
kaos_kore_region = create_region(world, player, active_locations, LocationName.kaos_kore_region, None, None)
|
||||
krematoa_region = create_region(world, player, active_locations, LocationName.krematoa_region, None, None)
|
||||
|
||||
|
||||
lakeside_limbo_region_locations = {
|
||||
LocationName.lakeside_limbo_flag : [0x657, 1],
|
||||
LocationName.lakeside_limbo_bonus_1 : [0x657, 2],
|
||||
LocationName.lakeside_limbo_bonus_2 : [0x657, 3],
|
||||
LocationName.lakeside_limbo_dk : [0x657, 5],
|
||||
}
|
||||
lakeside_limbo_region = create_region(world, player, active_locations, LocationName.lakeside_limbo_region,
|
||||
lakeside_limbo_region_locations, None)
|
||||
|
||||
doorstop_dash_region_locations = {
|
||||
LocationName.doorstop_dash_flag : [0x65A, 1],
|
||||
LocationName.doorstop_dash_bonus_1 : [0x65A, 2],
|
||||
LocationName.doorstop_dash_bonus_2 : [0x65A, 3],
|
||||
LocationName.doorstop_dash_dk : [0x65A, 5],
|
||||
}
|
||||
doorstop_dash_region = create_region(world, player, active_locations, LocationName.doorstop_dash_region,
|
||||
doorstop_dash_region_locations, None)
|
||||
|
||||
tidal_trouble_region_locations = {
|
||||
LocationName.tidal_trouble_flag : [0x659, 1],
|
||||
LocationName.tidal_trouble_bonus_1 : [0x659, 2],
|
||||
LocationName.tidal_trouble_bonus_2 : [0x659, 3],
|
||||
LocationName.tidal_trouble_dk : [0x659, 5],
|
||||
}
|
||||
tidal_trouble_region = create_region(world, player, active_locations, LocationName.tidal_trouble_region,
|
||||
tidal_trouble_region_locations, None)
|
||||
|
||||
skiddas_row_region_locations = {
|
||||
LocationName.skiddas_row_flag : [0x65D, 1],
|
||||
LocationName.skiddas_row_bonus_1 : [0x65D, 2],
|
||||
LocationName.skiddas_row_bonus_2 : [0x65D, 3],
|
||||
LocationName.skiddas_row_dk : [0x65D, 5],
|
||||
}
|
||||
skiddas_row_region = create_region(world, player, active_locations, LocationName.skiddas_row_region,
|
||||
skiddas_row_region_locations, None)
|
||||
|
||||
murky_mill_region_locations = {
|
||||
LocationName.murky_mill_flag : [0x65C, 1],
|
||||
LocationName.murky_mill_bonus_1 : [0x65C, 2],
|
||||
LocationName.murky_mill_bonus_2 : [0x65C, 3],
|
||||
LocationName.murky_mill_dk : [0x65C, 5],
|
||||
}
|
||||
murky_mill_region = create_region(world, player, active_locations, LocationName.murky_mill_region,
|
||||
murky_mill_region_locations, None)
|
||||
|
||||
barrel_shield_bust_up_region_locations = {
|
||||
LocationName.barrel_shield_bust_up_flag : [0x662, 1],
|
||||
LocationName.barrel_shield_bust_up_bonus_1 : [0x662, 2],
|
||||
LocationName.barrel_shield_bust_up_bonus_2 : [0x662, 3],
|
||||
LocationName.barrel_shield_bust_up_dk : [0x662, 5],
|
||||
}
|
||||
barrel_shield_bust_up_region = create_region(world, player, active_locations, LocationName.barrel_shield_bust_up_region,
|
||||
barrel_shield_bust_up_region_locations, None)
|
||||
|
||||
riverside_race_region_locations = {
|
||||
LocationName.riverside_race_flag : [0x664, 1],
|
||||
LocationName.riverside_race_bonus_1 : [0x664, 2],
|
||||
LocationName.riverside_race_bonus_2 : [0x664, 3],
|
||||
LocationName.riverside_race_dk : [0x664, 5],
|
||||
}
|
||||
riverside_race_region = create_region(world, player, active_locations, LocationName.riverside_race_region,
|
||||
riverside_race_region_locations, None)
|
||||
|
||||
squeals_on_wheels_region_locations = {
|
||||
LocationName.squeals_on_wheels_flag : [0x65B, 1],
|
||||
LocationName.squeals_on_wheels_bonus_1 : [0x65B, 2],
|
||||
LocationName.squeals_on_wheels_bonus_2 : [0x65B, 3],
|
||||
LocationName.squeals_on_wheels_dk : [0x65B, 5],
|
||||
}
|
||||
squeals_on_wheels_region = create_region(world, player, active_locations, LocationName.squeals_on_wheels_region,
|
||||
squeals_on_wheels_region_locations, None)
|
||||
|
||||
springin_spiders_region_locations = {
|
||||
LocationName.springin_spiders_flag : [0x661, 1],
|
||||
LocationName.springin_spiders_bonus_1 : [0x661, 2],
|
||||
LocationName.springin_spiders_bonus_2 : [0x661, 3],
|
||||
LocationName.springin_spiders_dk : [0x661, 5],
|
||||
}
|
||||
springin_spiders_region = create_region(world, player, active_locations, LocationName.springin_spiders_region,
|
||||
springin_spiders_region_locations, None)
|
||||
|
||||
bobbing_barrel_brawl_region_locations = {
|
||||
LocationName.bobbing_barrel_brawl_flag : [0x666, 1],
|
||||
LocationName.bobbing_barrel_brawl_bonus_1 : [0x666, 2],
|
||||
LocationName.bobbing_barrel_brawl_bonus_2 : [0x666, 3],
|
||||
LocationName.bobbing_barrel_brawl_dk : [0x666, 5],
|
||||
}
|
||||
bobbing_barrel_brawl_region = create_region(world, player, active_locations, LocationName.bobbing_barrel_brawl_region,
|
||||
bobbing_barrel_brawl_region_locations, None)
|
||||
|
||||
bazzas_blockade_region_locations = {
|
||||
LocationName.bazzas_blockade_flag : [0x667, 1],
|
||||
LocationName.bazzas_blockade_bonus_1 : [0x667, 2],
|
||||
LocationName.bazzas_blockade_bonus_2 : [0x667, 3],
|
||||
LocationName.bazzas_blockade_dk : [0x667, 5],
|
||||
}
|
||||
bazzas_blockade_region = create_region(world, player, active_locations, LocationName.bazzas_blockade_region,
|
||||
bazzas_blockade_region_locations, None)
|
||||
|
||||
rocket_barrel_ride_region_locations = {
|
||||
LocationName.rocket_barrel_ride_flag : [0x66A, 1],
|
||||
LocationName.rocket_barrel_ride_bonus_1 : [0x66A, 2],
|
||||
LocationName.rocket_barrel_ride_bonus_2 : [0x66A, 3],
|
||||
LocationName.rocket_barrel_ride_dk : [0x66A, 5],
|
||||
}
|
||||
rocket_barrel_ride_region = create_region(world, player, active_locations, LocationName.rocket_barrel_ride_region,
|
||||
rocket_barrel_ride_region_locations, None)
|
||||
|
||||
kreeping_klasps_region_locations = {
|
||||
LocationName.kreeping_klasps_flag : [0x658, 1],
|
||||
LocationName.kreeping_klasps_bonus_1 : [0x658, 2],
|
||||
LocationName.kreeping_klasps_bonus_2 : [0x658, 3],
|
||||
LocationName.kreeping_klasps_dk : [0x658, 5],
|
||||
}
|
||||
kreeping_klasps_region = create_region(world, player, active_locations, LocationName.kreeping_klasps_region,
|
||||
kreeping_klasps_region_locations, None)
|
||||
|
||||
tracker_barrel_trek_region_locations = {
|
||||
LocationName.tracker_barrel_trek_flag : [0x66B, 1],
|
||||
LocationName.tracker_barrel_trek_bonus_1 : [0x66B, 2],
|
||||
LocationName.tracker_barrel_trek_bonus_2 : [0x66B, 3],
|
||||
LocationName.tracker_barrel_trek_dk : [0x66B, 5],
|
||||
}
|
||||
tracker_barrel_trek_region = create_region(world, player, active_locations, LocationName.tracker_barrel_trek_region,
|
||||
tracker_barrel_trek_region_locations, None)
|
||||
|
||||
fish_food_frenzy_region_locations = {
|
||||
LocationName.fish_food_frenzy_flag : [0x668, 1],
|
||||
LocationName.fish_food_frenzy_bonus_1 : [0x668, 2],
|
||||
LocationName.fish_food_frenzy_bonus_2 : [0x668, 3],
|
||||
LocationName.fish_food_frenzy_dk : [0x668, 5],
|
||||
}
|
||||
fish_food_frenzy_region = create_region(world, player, active_locations, LocationName.fish_food_frenzy_region,
|
||||
fish_food_frenzy_region_locations, None)
|
||||
|
||||
fire_ball_frenzy_region_locations = {
|
||||
LocationName.fire_ball_frenzy_flag : [0x66D, 1],
|
||||
LocationName.fire_ball_frenzy_bonus_1 : [0x66D, 2],
|
||||
LocationName.fire_ball_frenzy_bonus_2 : [0x66D, 3],
|
||||
LocationName.fire_ball_frenzy_dk : [0x66D, 5],
|
||||
}
|
||||
fire_ball_frenzy_region = create_region(world, player, active_locations, LocationName.fire_ball_frenzy_region,
|
||||
fire_ball_frenzy_region_locations, None)
|
||||
|
||||
demolition_drain_pipe_region_locations = {
|
||||
LocationName.demolition_drain_pipe_flag : [0x672, 1],
|
||||
LocationName.demolition_drain_pipe_bonus_1 : [0x672, 2],
|
||||
LocationName.demolition_drain_pipe_bonus_2 : [0x672, 3],
|
||||
LocationName.demolition_drain_pipe_dk : [0x672, 5],
|
||||
}
|
||||
demolition_drain_pipe_region = create_region(world, player, active_locations, LocationName.demolition_drain_pipe_region,
|
||||
demolition_drain_pipe_region_locations, None)
|
||||
|
||||
ripsaw_rage_region_locations = {
|
||||
LocationName.ripsaw_rage_flag : [0x660, 1],
|
||||
LocationName.ripsaw_rage_bonus_1 : [0x660, 2],
|
||||
LocationName.ripsaw_rage_bonus_2 : [0x660, 3],
|
||||
LocationName.ripsaw_rage_dk : [0x660, 5],
|
||||
}
|
||||
ripsaw_rage_region = create_region(world, player, active_locations, LocationName.ripsaw_rage_region,
|
||||
ripsaw_rage_region_locations, None)
|
||||
|
||||
blazing_bazookas_region_locations = {
|
||||
LocationName.blazing_bazookas_flag : [0x66E, 1],
|
||||
LocationName.blazing_bazookas_bonus_1 : [0x66E, 2],
|
||||
LocationName.blazing_bazookas_bonus_2 : [0x66E, 3],
|
||||
LocationName.blazing_bazookas_dk : [0x66E, 5],
|
||||
}
|
||||
blazing_bazookas_region = create_region(world, player, active_locations, LocationName.blazing_bazookas_region,
|
||||
blazing_bazookas_region_locations, None)
|
||||
|
||||
low_g_labyrinth_region_locations = {
|
||||
LocationName.low_g_labyrinth_flag : [0x670, 1],
|
||||
LocationName.low_g_labyrinth_bonus_1 : [0x670, 2],
|
||||
LocationName.low_g_labyrinth_bonus_2 : [0x670, 3],
|
||||
LocationName.low_g_labyrinth_dk : [0x670, 5],
|
||||
}
|
||||
low_g_labyrinth_region = create_region(world, player, active_locations, LocationName.low_g_labyrinth_region,
|
||||
low_g_labyrinth_region_locations, None)
|
||||
|
||||
krevice_kreepers_region_locations = {
|
||||
LocationName.krevice_kreepers_flag : [0x673, 1],
|
||||
LocationName.krevice_kreepers_bonus_1 : [0x673, 2],
|
||||
LocationName.krevice_kreepers_bonus_2 : [0x673, 3],
|
||||
LocationName.krevice_kreepers_dk : [0x673, 5],
|
||||
}
|
||||
krevice_kreepers_region = create_region(world, player, active_locations, LocationName.krevice_kreepers_region,
|
||||
krevice_kreepers_region_locations, None)
|
||||
|
||||
tearaway_toboggan_region_locations = {
|
||||
LocationName.tearaway_toboggan_flag : [0x65F, 1],
|
||||
LocationName.tearaway_toboggan_bonus_1 : [0x65F, 2],
|
||||
LocationName.tearaway_toboggan_bonus_2 : [0x65F, 3],
|
||||
LocationName.tearaway_toboggan_dk : [0x65F, 5],
|
||||
}
|
||||
tearaway_toboggan_region = create_region(world, player, active_locations, LocationName.tearaway_toboggan_region,
|
||||
tearaway_toboggan_region_locations, None)
|
||||
|
||||
barrel_drop_bounce_region_locations = {
|
||||
LocationName.barrel_drop_bounce_flag : [0x66C, 1],
|
||||
LocationName.barrel_drop_bounce_bonus_1 : [0x66C, 2],
|
||||
LocationName.barrel_drop_bounce_bonus_2 : [0x66C, 3],
|
||||
LocationName.barrel_drop_bounce_dk : [0x66C, 5],
|
||||
}
|
||||
barrel_drop_bounce_region = create_region(world, player, active_locations, LocationName.barrel_drop_bounce_region,
|
||||
barrel_drop_bounce_region_locations, None)
|
||||
|
||||
krack_shot_kroc_region_locations = {
|
||||
LocationName.krack_shot_kroc_flag : [0x66F, 1],
|
||||
LocationName.krack_shot_kroc_bonus_1 : [0x66F, 2],
|
||||
LocationName.krack_shot_kroc_bonus_2 : [0x66F, 3],
|
||||
LocationName.krack_shot_kroc_dk : [0x66F, 5],
|
||||
}
|
||||
krack_shot_kroc_region = create_region(world, player, active_locations, LocationName.krack_shot_kroc_region,
|
||||
krack_shot_kroc_region_locations, None)
|
||||
|
||||
lemguin_lunge_region_locations = {
|
||||
LocationName.lemguin_lunge_flag : [0x65E, 1],
|
||||
LocationName.lemguin_lunge_bonus_1 : [0x65E, 2],
|
||||
LocationName.lemguin_lunge_bonus_2 : [0x65E, 3],
|
||||
LocationName.lemguin_lunge_dk : [0x65E, 5],
|
||||
}
|
||||
lemguin_lunge_region = create_region(world, player, active_locations, LocationName.lemguin_lunge_region,
|
||||
lemguin_lunge_region_locations, None)
|
||||
|
||||
buzzer_barrage_region_locations = {
|
||||
LocationName.buzzer_barrage_flag : [0x676, 1],
|
||||
LocationName.buzzer_barrage_bonus_1 : [0x676, 2],
|
||||
LocationName.buzzer_barrage_bonus_2 : [0x676, 3],
|
||||
LocationName.buzzer_barrage_dk : [0x676, 5],
|
||||
}
|
||||
buzzer_barrage_region = create_region(world, player, active_locations, LocationName.buzzer_barrage_region,
|
||||
buzzer_barrage_region_locations, None)
|
||||
|
||||
kong_fused_cliffs_region_locations = {
|
||||
LocationName.kong_fused_cliffs_flag : [0x674, 1],
|
||||
LocationName.kong_fused_cliffs_bonus_1 : [0x674, 2],
|
||||
LocationName.kong_fused_cliffs_bonus_2 : [0x674, 3],
|
||||
LocationName.kong_fused_cliffs_dk : [0x674, 5],
|
||||
}
|
||||
kong_fused_cliffs_region = create_region(world, player, active_locations, LocationName.kong_fused_cliffs_region,
|
||||
kong_fused_cliffs_region_locations, None)
|
||||
|
||||
floodlit_fish_region_locations = {
|
||||
LocationName.floodlit_fish_flag : [0x669, 1],
|
||||
LocationName.floodlit_fish_bonus_1 : [0x669, 2],
|
||||
LocationName.floodlit_fish_bonus_2 : [0x669, 3],
|
||||
LocationName.floodlit_fish_dk : [0x669, 5],
|
||||
}
|
||||
floodlit_fish_region = create_region(world, player, active_locations, LocationName.floodlit_fish_region,
|
||||
floodlit_fish_region_locations, None)
|
||||
|
||||
pothole_panic_region_locations = {
|
||||
LocationName.pothole_panic_flag : [0x677, 1],
|
||||
LocationName.pothole_panic_bonus_1 : [0x677, 2],
|
||||
LocationName.pothole_panic_bonus_2 : [0x677, 3],
|
||||
LocationName.pothole_panic_dk : [0x677, 5],
|
||||
}
|
||||
pothole_panic_region = create_region(world, player, active_locations, LocationName.pothole_panic_region,
|
||||
pothole_panic_region_locations, None)
|
||||
|
||||
ropey_rumpus_region_locations = {
|
||||
LocationName.ropey_rumpus_flag : [0x675, 1],
|
||||
LocationName.ropey_rumpus_bonus_1 : [0x675, 2],
|
||||
LocationName.ropey_rumpus_bonus_2 : [0x675, 3],
|
||||
LocationName.ropey_rumpus_dk : [0x675, 5],
|
||||
}
|
||||
ropey_rumpus_region = create_region(world, player, active_locations, LocationName.ropey_rumpus_region,
|
||||
ropey_rumpus_region_locations, None)
|
||||
|
||||
konveyor_rope_clash_region_locations = {
|
||||
LocationName.konveyor_rope_clash_flag : [0x657, 1],
|
||||
LocationName.konveyor_rope_clash_bonus_1 : [0x657, 2],
|
||||
LocationName.konveyor_rope_clash_bonus_2 : [0x657, 3],
|
||||
LocationName.konveyor_rope_clash_dk : [0x657, 5],
|
||||
}
|
||||
konveyor_rope_clash_region = create_region(world, player, active_locations, LocationName.konveyor_rope_clash_region,
|
||||
konveyor_rope_clash_region_locations, None)
|
||||
|
||||
creepy_caverns_region_locations = {
|
||||
LocationName.creepy_caverns_flag : [0x678, 1],
|
||||
LocationName.creepy_caverns_bonus_1 : [0x678, 2],
|
||||
LocationName.creepy_caverns_bonus_2 : [0x678, 3],
|
||||
LocationName.creepy_caverns_dk : [0x678, 5],
|
||||
}
|
||||
creepy_caverns_region = create_region(world, player, active_locations, LocationName.creepy_caverns_region,
|
||||
creepy_caverns_region_locations, None)
|
||||
|
||||
lightning_lookout_region_locations = {
|
||||
LocationName.lightning_lookout_flag : [0x665, 1],
|
||||
LocationName.lightning_lookout_bonus_1 : [0x665, 2],
|
||||
LocationName.lightning_lookout_bonus_2 : [0x665, 3],
|
||||
LocationName.lightning_lookout_dk : [0x665, 5],
|
||||
}
|
||||
lightning_lookout_region = create_region(world, player, active_locations, LocationName.lightning_lookout_region,
|
||||
lightning_lookout_region_locations, None)
|
||||
|
||||
koindozer_klamber_region_locations = {
|
||||
LocationName.koindozer_klamber_flag : [0x679, 1],
|
||||
LocationName.koindozer_klamber_bonus_1 : [0x679, 2],
|
||||
LocationName.koindozer_klamber_bonus_2 : [0x679, 3],
|
||||
LocationName.koindozer_klamber_dk : [0x679, 5],
|
||||
}
|
||||
koindozer_klamber_region = create_region(world, player, active_locations, LocationName.koindozer_klamber_region,
|
||||
koindozer_klamber_region_locations, None)
|
||||
|
||||
poisonous_pipeline_region_locations = {
|
||||
LocationName.poisonous_pipeline_flag : [0x671, 1],
|
||||
LocationName.poisonous_pipeline_bonus_1 : [0x671, 2],
|
||||
LocationName.poisonous_pipeline_bonus_2 : [0x671, 3],
|
||||
LocationName.poisonous_pipeline_dk : [0x671, 5],
|
||||
}
|
||||
poisonous_pipeline_region = create_region(world, player, active_locations, LocationName.poisonous_pipeline_region,
|
||||
poisonous_pipeline_region_locations, None)
|
||||
|
||||
stampede_sprint_region_locations = {
|
||||
LocationName.stampede_sprint_flag : [0x67B, 1],
|
||||
LocationName.stampede_sprint_bonus_1 : [0x67B, 2],
|
||||
LocationName.stampede_sprint_bonus_2 : [0x67B, 3],
|
||||
LocationName.stampede_sprint_bonus_3 : [0x67B, 4],
|
||||
LocationName.stampede_sprint_dk : [0x67B, 5],
|
||||
}
|
||||
stampede_sprint_region = create_region(world, player, active_locations, LocationName.stampede_sprint_region,
|
||||
stampede_sprint_region_locations, None)
|
||||
|
||||
criss_cross_cliffs_region_locations = {
|
||||
LocationName.criss_cross_cliffs_flag : [0x67C, 1],
|
||||
LocationName.criss_cross_cliffs_bonus_1 : [0x67C, 2],
|
||||
LocationName.criss_cross_cliffs_bonus_2 : [0x67C, 3],
|
||||
LocationName.criss_cross_cliffs_dk : [0x67C, 5],
|
||||
}
|
||||
criss_cross_cliffs_region = create_region(world, player, active_locations, LocationName.criss_cross_cliffs_region,
|
||||
criss_cross_cliffs_region_locations, None)
|
||||
|
||||
tyrant_twin_tussle_region_locations = {
|
||||
LocationName.tyrant_twin_tussle_flag : [0x67D, 1],
|
||||
LocationName.tyrant_twin_tussle_bonus_1 : [0x67D, 2],
|
||||
LocationName.tyrant_twin_tussle_bonus_2 : [0x67D, 3],
|
||||
LocationName.tyrant_twin_tussle_bonus_3 : [0x67D, 4],
|
||||
LocationName.tyrant_twin_tussle_dk : [0x67D, 5],
|
||||
}
|
||||
tyrant_twin_tussle_region = create_region(world, player, active_locations, LocationName.tyrant_twin_tussle_region,
|
||||
tyrant_twin_tussle_region_locations, None)
|
||||
|
||||
swoopy_salvo_region_locations = {
|
||||
LocationName.swoopy_salvo_flag : [0x663, 1],
|
||||
LocationName.swoopy_salvo_bonus_1 : [0x663, 2],
|
||||
LocationName.swoopy_salvo_bonus_2 : [0x663, 3],
|
||||
LocationName.swoopy_salvo_bonus_3 : [0x663, 4],
|
||||
LocationName.swoopy_salvo_dk : [0x663, 5],
|
||||
}
|
||||
swoopy_salvo_region = create_region(world, player, active_locations, LocationName.swoopy_salvo_region,
|
||||
swoopy_salvo_region_locations, None)
|
||||
|
||||
rocket_rush_region_locations = {
|
||||
LocationName.rocket_rush_flag : [0x67E, 1],
|
||||
LocationName.rocket_rush_dk : [0x67E, 5],
|
||||
}
|
||||
rocket_rush_region = create_region(world, player, active_locations, LocationName.rocket_rush_region,
|
||||
rocket_rush_region_locations, None)
|
||||
|
||||
belchas_barn_region_locations = {
|
||||
LocationName.belchas_barn: [0x64F, 1],
|
||||
}
|
||||
belchas_barn_region = create_region(world, player, active_locations, LocationName.belchas_barn_region,
|
||||
belchas_barn_region_locations, None)
|
||||
|
||||
arichs_ambush_region_locations = {
|
||||
LocationName.arichs_ambush: [0x650, 1],
|
||||
}
|
||||
arichs_ambush_region = create_region(world, player, active_locations, LocationName.arichs_ambush_region,
|
||||
arichs_ambush_region_locations, None)
|
||||
|
||||
squirts_showdown_region_locations = {
|
||||
LocationName.squirts_showdown: [0x651, 1],
|
||||
}
|
||||
squirts_showdown_region = create_region(world, player, active_locations, LocationName.squirts_showdown_region,
|
||||
squirts_showdown_region_locations, None)
|
||||
|
||||
kaos_karnage_region_locations = {
|
||||
LocationName.kaos_karnage: [0x652, 1],
|
||||
}
|
||||
kaos_karnage_region = create_region(world, player, active_locations, LocationName.kaos_karnage_region,
|
||||
kaos_karnage_region_locations, None)
|
||||
|
||||
bleaks_house_region_locations = {
|
||||
LocationName.bleaks_house: [0x653, 1],
|
||||
}
|
||||
bleaks_house_region = create_region(world, player, active_locations, LocationName.bleaks_house_region,
|
||||
bleaks_house_region_locations, None)
|
||||
|
||||
barboss_barrier_region_locations = {
|
||||
LocationName.barboss_barrier: [0x654, 1],
|
||||
}
|
||||
barboss_barrier_region = create_region(world, player, active_locations, LocationName.barboss_barrier_region,
|
||||
barboss_barrier_region_locations, None)
|
||||
|
||||
kastle_kaos_region_locations = {
|
||||
LocationName.kastle_kaos: [0x655, 1],
|
||||
}
|
||||
kastle_kaos_region = create_region(world, player, active_locations, LocationName.kastle_kaos_region,
|
||||
kastle_kaos_region_locations, None)
|
||||
|
||||
knautilus_region_locations = {
|
||||
LocationName.knautilus: [0x656, 1],
|
||||
}
|
||||
knautilus_region = create_region(world, player, active_locations, LocationName.knautilus_region,
|
||||
knautilus_region_locations, None)
|
||||
|
||||
belchas_burrow_region_locations = {
|
||||
LocationName.belchas_burrow: [0x647, 1],
|
||||
}
|
||||
belchas_burrow_region = create_region(world, player, active_locations, LocationName.belchas_burrow_region,
|
||||
belchas_burrow_region_locations, None)
|
||||
|
||||
kong_cave_region_locations = {
|
||||
LocationName.kong_cave: [0x645, 1],
|
||||
}
|
||||
kong_cave_region = create_region(world, player, active_locations, LocationName.kong_cave_region,
|
||||
kong_cave_region_locations, None)
|
||||
|
||||
undercover_cove_region_locations = {
|
||||
LocationName.undercover_cove: [0x644, 1],
|
||||
}
|
||||
undercover_cove_region = create_region(world, player, active_locations, LocationName.undercover_cove_region,
|
||||
undercover_cove_region_locations, None)
|
||||
|
||||
ks_cache_region_locations = {
|
||||
LocationName.ks_cache: [0x642, 1],
|
||||
}
|
||||
ks_cache_region = create_region(world, player, active_locations, LocationName.ks_cache_region,
|
||||
ks_cache_region_locations, None)
|
||||
|
||||
hill_top_hoard_region_locations = {
|
||||
LocationName.hill_top_hoard: [0x643, 1],
|
||||
}
|
||||
hill_top_hoard_region = create_region(world, player, active_locations, LocationName.hill_top_hoard_region,
|
||||
hill_top_hoard_region_locations, None)
|
||||
|
||||
bounty_beach_region_locations = {
|
||||
LocationName.bounty_beach: [0x646, 1],
|
||||
}
|
||||
bounty_beach_region = create_region(world, player, active_locations, LocationName.bounty_beach_region,
|
||||
bounty_beach_region_locations, None)
|
||||
|
||||
smugglers_cove_region_locations = {
|
||||
LocationName.smugglers_cove: [0x648, 1],
|
||||
}
|
||||
smugglers_cove_region = create_region(world, player, active_locations, LocationName.smugglers_cove_region,
|
||||
smugglers_cove_region_locations, None)
|
||||
|
||||
arichs_hoard_region_locations = {
|
||||
LocationName.arichs_hoard: [0x649, 1],
|
||||
}
|
||||
arichs_hoard_region = create_region(world, player, active_locations, LocationName.arichs_hoard_region,
|
||||
arichs_hoard_region_locations, None)
|
||||
|
||||
bounty_bay_region_locations = {
|
||||
LocationName.bounty_bay: [0x64A, 1],
|
||||
}
|
||||
bounty_bay_region = create_region(world, player, active_locations, LocationName.bounty_bay_region,
|
||||
bounty_bay_region_locations, None)
|
||||
|
||||
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)
|
||||
|
||||
glacial_grotto_region_locations = {
|
||||
LocationName.glacial_grotto: [0x64C, 1],
|
||||
}
|
||||
glacial_grotto_region = create_region(world, player, active_locations, LocationName.glacial_grotto_region,
|
||||
glacial_grotto_region_locations, None)
|
||||
|
||||
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)
|
||||
|
||||
sewer_stockpile_region_locations = {
|
||||
LocationName.sewer_stockpile: [0x64E, 1],
|
||||
}
|
||||
sewer_stockpile_region = create_region(world, player, active_locations, LocationName.sewer_stockpile_region,
|
||||
sewer_stockpile_region_locations, None)
|
||||
|
||||
|
||||
# Set up the regions correctly.
|
||||
world.regions += [
|
||||
menu_region,
|
||||
overworld_1_region,
|
||||
overworld_2_region,
|
||||
overworld_3_region,
|
||||
overworld_4_region,
|
||||
lake_orangatanga_region,
|
||||
kremwood_forest_region,
|
||||
cotton_top_cove_region,
|
||||
mekanos_region,
|
||||
k3_region,
|
||||
razor_ridge_region,
|
||||
kaos_kore_region,
|
||||
krematoa_region,
|
||||
lakeside_limbo_region,
|
||||
doorstop_dash_region,
|
||||
tidal_trouble_region,
|
||||
skiddas_row_region,
|
||||
murky_mill_region,
|
||||
barrel_shield_bust_up_region,
|
||||
riverside_race_region,
|
||||
squeals_on_wheels_region,
|
||||
springin_spiders_region,
|
||||
bobbing_barrel_brawl_region,
|
||||
bazzas_blockade_region,
|
||||
rocket_barrel_ride_region,
|
||||
kreeping_klasps_region,
|
||||
tracker_barrel_trek_region,
|
||||
fish_food_frenzy_region,
|
||||
fire_ball_frenzy_region,
|
||||
demolition_drain_pipe_region,
|
||||
ripsaw_rage_region,
|
||||
blazing_bazookas_region,
|
||||
low_g_labyrinth_region,
|
||||
krevice_kreepers_region,
|
||||
tearaway_toboggan_region,
|
||||
barrel_drop_bounce_region,
|
||||
krack_shot_kroc_region,
|
||||
lemguin_lunge_region,
|
||||
buzzer_barrage_region,
|
||||
kong_fused_cliffs_region,
|
||||
floodlit_fish_region,
|
||||
pothole_panic_region,
|
||||
ropey_rumpus_region,
|
||||
konveyor_rope_clash_region,
|
||||
creepy_caverns_region,
|
||||
lightning_lookout_region,
|
||||
koindozer_klamber_region,
|
||||
poisonous_pipeline_region,
|
||||
stampede_sprint_region,
|
||||
criss_cross_cliffs_region,
|
||||
tyrant_twin_tussle_region,
|
||||
swoopy_salvo_region,
|
||||
rocket_rush_region,
|
||||
belchas_barn_region,
|
||||
arichs_ambush_region,
|
||||
squirts_showdown_region,
|
||||
kaos_karnage_region,
|
||||
bleaks_house_region,
|
||||
barboss_barrier_region,
|
||||
kastle_kaos_region,
|
||||
knautilus_region,
|
||||
belchas_burrow_region,
|
||||
kong_cave_region,
|
||||
undercover_cove_region,
|
||||
ks_cache_region,
|
||||
hill_top_hoard_region,
|
||||
bounty_beach_region,
|
||||
smugglers_cove_region,
|
||||
arichs_hoard_region,
|
||||
bounty_bay_region,
|
||||
sky_high_secret_region,
|
||||
glacial_grotto_region,
|
||||
cifftop_cache_region,
|
||||
sewer_stockpile_region,
|
||||
]
|
||||
|
||||
bazaar_region_locations = {}
|
||||
bramble_region_locations = {}
|
||||
flower_spot_region_locations = {}
|
||||
barter_region_locations = {}
|
||||
barnacle_region_locations = {}
|
||||
blue_region_locations = {}
|
||||
blizzard_region_locations = {}
|
||||
|
||||
if False:#world.include_trade_sequence[player]:
|
||||
bazaar_region_locations.update({
|
||||
LocationName.bazaars_general_store_1: [0x615, 2, True],
|
||||
LocationName.bazaars_general_store_2: [0x615, 3, True],
|
||||
})
|
||||
|
||||
bramble_region_locations.update({
|
||||
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],
|
||||
})
|
||||
|
||||
barnacle_region_locations.update({
|
||||
LocationName.barnacles_island: [0x61D, 2],
|
||||
})
|
||||
|
||||
blue_region_locations.update({
|
||||
LocationName.blues_beach_hut: [0x621, 4],
|
||||
})
|
||||
|
||||
blizzard_region_locations.update({
|
||||
LocationName.blizzards_basecamp: [0x625, 4, True],
|
||||
})
|
||||
|
||||
bazaar_region = create_region(world, player, active_locations, LocationName.bazaar_region,
|
||||
bazaar_region_locations, None)
|
||||
bramble_region = create_region(world, player, active_locations, LocationName.bramble_region,
|
||||
bramble_region_locations, None)
|
||||
flower_spot_region = create_region(world, player, active_locations, LocationName.flower_spot_region,
|
||||
flower_spot_region_locations, None)
|
||||
barter_region = create_region(world, player, active_locations, LocationName.barter_region,
|
||||
barter_region_locations, None)
|
||||
barnacle_region = create_region(world, player, active_locations, LocationName.barnacle_region,
|
||||
barnacle_region_locations, None)
|
||||
blue_region = create_region(world, player, active_locations, LocationName.blue_region,
|
||||
blue_region_locations, None)
|
||||
blizzard_region = create_region(world, player, active_locations, LocationName.blizzard_region,
|
||||
blizzard_region_locations, None)
|
||||
|
||||
world.regions += [
|
||||
bazaar_region,
|
||||
bramble_region,
|
||||
flower_spot_region,
|
||||
barter_region,
|
||||
barnacle_region,
|
||||
blue_region,
|
||||
blizzard_region,
|
||||
]
|
||||
|
||||
|
||||
def connect_regions(world, player, level_list):
|
||||
names: typing.Dict[str, int] = {}
|
||||
|
||||
# Overworld
|
||||
connect(world, player, names, 'Menu', LocationName.overworld_1_region)
|
||||
connect(world, player, names, LocationName.overworld_1_region, LocationName.overworld_2_region,
|
||||
lambda state: (state.has(ItemName.progressive_boat, player, 1)))
|
||||
connect(world, player, names, LocationName.overworld_2_region, LocationName.overworld_3_region,
|
||||
lambda state: (state.has(ItemName.progressive_boat, player, 3)))
|
||||
connect(world, player, names, LocationName.overworld_1_region, LocationName.overworld_4_region,
|
||||
lambda state: (state.has(ItemName.dk_coin, player, world.dk_coins_for_gyrocopter[player].value) and
|
||||
state.has(ItemName.progressive_boat, player, 3)))
|
||||
|
||||
# World Connections
|
||||
connect(world, player, names, LocationName.overworld_1_region, LocationName.lake_orangatanga_region)
|
||||
connect(world, player, names, LocationName.overworld_1_region, LocationName.kremwood_forest_region)
|
||||
connect(world, player, names, LocationName.overworld_1_region, LocationName.bounty_beach_region)
|
||||
connect(world, player, names, LocationName.overworld_1_region, LocationName.bazaar_region)
|
||||
|
||||
connect(world, player, names, LocationName.overworld_2_region, LocationName.cotton_top_cove_region)
|
||||
connect(world, player, names, LocationName.overworld_2_region, LocationName.mekanos_region)
|
||||
connect(world, player, names, LocationName.overworld_2_region, LocationName.kong_cave_region)
|
||||
connect(world, player, names, LocationName.overworld_2_region, LocationName.bramble_region)
|
||||
|
||||
connect(world, player, names, LocationName.overworld_3_region, LocationName.k3_region)
|
||||
connect(world, player, names, LocationName.overworld_3_region, LocationName.razor_ridge_region)
|
||||
connect(world, player, names, LocationName.overworld_3_region, LocationName.kaos_kore_region)
|
||||
connect(world, player, names, LocationName.overworld_3_region, LocationName.krematoa_region)
|
||||
connect(world, player, names, LocationName.overworld_3_region, LocationName.undercover_cove_region)
|
||||
connect(world, player, names, LocationName.overworld_3_region, LocationName.flower_spot_region)
|
||||
connect(world, player, names, LocationName.overworld_3_region, LocationName.barter_region)
|
||||
|
||||
connect(world, player, names, LocationName.overworld_4_region, LocationName.belchas_burrow_region)
|
||||
connect(world, player, names, LocationName.overworld_4_region, LocationName.ks_cache_region)
|
||||
connect(world, player, names, LocationName.overworld_4_region, LocationName.hill_top_hoard_region)
|
||||
|
||||
|
||||
# Lake Orangatanga Connections
|
||||
lake_orangatanga_levels = [
|
||||
level_list[0],
|
||||
level_list[1],
|
||||
level_list[2],
|
||||
level_list[3],
|
||||
level_list[4],
|
||||
LocationName.belchas_barn_region,
|
||||
LocationName.barnacle_region,
|
||||
LocationName.smugglers_cove_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(lake_orangatanga_levels)):
|
||||
connect(world, player, names, LocationName.lake_orangatanga_region, lake_orangatanga_levels[i])
|
||||
|
||||
# Kremwood Forest Connections
|
||||
kremwood_forest_levels = [
|
||||
level_list[5],
|
||||
level_list[6],
|
||||
level_list[7],
|
||||
level_list[8],
|
||||
level_list[9],
|
||||
LocationName.arichs_ambush_region,
|
||||
LocationName.arichs_hoard_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(kremwood_forest_levels) - 1):
|
||||
connect(world, player, names, LocationName.kremwood_forest_region, kremwood_forest_levels[i])
|
||||
|
||||
connect(world, player, names, LocationName.kremwood_forest_region, kremwood_forest_levels[-1],
|
||||
lambda state: (state.can_reach(LocationName.riverside_race_flag, "Location", player)))
|
||||
|
||||
# Cotton-Top Cove Connections
|
||||
cotton_top_cove_levels = [
|
||||
LocationName.blue_region,
|
||||
level_list[10],
|
||||
level_list[11],
|
||||
level_list[12],
|
||||
level_list[13],
|
||||
level_list[14],
|
||||
LocationName.squirts_showdown_region,
|
||||
LocationName.bounty_bay_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(cotton_top_cove_levels)):
|
||||
connect(world, player, names, LocationName.cotton_top_cove_region, cotton_top_cove_levels[i])
|
||||
|
||||
# Mekanos Connections
|
||||
mekanos_levels = [
|
||||
level_list[15],
|
||||
level_list[16],
|
||||
level_list[17],
|
||||
level_list[18],
|
||||
level_list[19],
|
||||
LocationName.kaos_karnage_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(mekanos_levels)):
|
||||
connect(world, player, names, LocationName.mekanos_region, mekanos_levels[i])
|
||||
|
||||
if False:#world.include_trade_sequence[player]:
|
||||
connect(world, player, names, LocationName.mekanos_region, LocationName.sky_high_secret_region,
|
||||
lambda state: (state.has(ItemName.bowling_ball, player, 1)))
|
||||
else:
|
||||
connect(world, player, names, LocationName.mekanos_region, LocationName.sky_high_secret_region,
|
||||
lambda state: (state.can_reach(LocationName.bleaks_house, "Location", player)))
|
||||
|
||||
# K3 Connections
|
||||
k3_levels = [
|
||||
level_list[20],
|
||||
level_list[21],
|
||||
level_list[22],
|
||||
level_list[23],
|
||||
level_list[24],
|
||||
LocationName.bleaks_house_region,
|
||||
LocationName.blizzard_region,
|
||||
LocationName.glacial_grotto_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(k3_levels)):
|
||||
connect(world, player, names, LocationName.k3_region, k3_levels[i])
|
||||
|
||||
# Razor Ridge Connections
|
||||
razor_ridge_levels = [
|
||||
level_list[25],
|
||||
level_list[26],
|
||||
level_list[27],
|
||||
level_list[28],
|
||||
level_list[29],
|
||||
LocationName.barboss_barrier_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(razor_ridge_levels)):
|
||||
connect(world, player, names, LocationName.razor_ridge_region, razor_ridge_levels[i])
|
||||
|
||||
if False:#world.include_trade_sequence[player]:
|
||||
connect(world, player, names, LocationName.razor_ridge_region, LocationName.cifftop_cache_region,
|
||||
lambda state: (state.has(ItemName.wrench, player, 1)))
|
||||
else:
|
||||
connect(world, player, names, LocationName.razor_ridge_region, LocationName.cifftop_cache_region)
|
||||
|
||||
# KAOS Kore Connections
|
||||
kaos_kore_levels = [
|
||||
level_list[30],
|
||||
level_list[31],
|
||||
level_list[32],
|
||||
level_list[33],
|
||||
level_list[34],
|
||||
LocationName.kastle_kaos_region,
|
||||
LocationName.sewer_stockpile_region,
|
||||
]
|
||||
|
||||
for i in range(0, len(kaos_kore_levels)):
|
||||
connect(world, player, names, LocationName.kaos_kore_region, kaos_kore_levels[i])
|
||||
|
||||
# Krematoa Connections
|
||||
krematoa_levels = [
|
||||
level_list[35],
|
||||
level_list[36],
|
||||
level_list[37],
|
||||
level_list[38],
|
||||
LocationName.rocket_rush_region,
|
||||
]
|
||||
|
||||
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)))
|
||||
|
||||
|
||||
def create_region(world: MultiWorld, player: int, active_locations, name: str, locations=None, exits=None):
|
||||
# Shamelessly stolen from the ROR2 definition
|
||||
ret = Region(name, None, name, player)
|
||||
ret.world = world
|
||||
if locations:
|
||||
for locationName, locationData in locations.items():
|
||||
loc_id = active_locations.get(locationName, 0)
|
||||
if loc_id:
|
||||
loc_byte = locationData[0] if (len(locationData) > 0) else 0
|
||||
loc_bit = locationData[1] if (len(locationData) > 1) else 0
|
||||
loc_invert = locationData[2] if (len(locationData) > 2) else False
|
||||
|
||||
location = DKC3Location(player, locationName, loc_id, ret, loc_byte, loc_bit, loc_invert)
|
||||
ret.locations.append(location)
|
||||
if exits:
|
||||
for exit in exits:
|
||||
ret.exits.append(Entrance(player, exit, ret))
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def connect(world: MultiWorld, player: int, used_names: typing.Dict[str, int], source: str, target: str,
|
||||
rule: typing.Optional[typing.Callable] = None):
|
||||
source_region = world.get_region(source, player)
|
||||
target_region = world.get_region(target, player)
|
||||
|
||||
if target not in used_names:
|
||||
used_names[target] = 1
|
||||
name = target
|
||||
else:
|
||||
used_names[target] += 1
|
||||
name = target + (' ' * used_names[target])
|
||||
|
||||
connection = Entrance(player, name, source_region)
|
||||
|
||||
if rule:
|
||||
connection.access_rule = rule
|
||||
|
||||
source_region.exits.append(connection)
|
||||
connection.connect(target_region)
|
|
@ -0,0 +1,553 @@
|
|||
import Utils
|
||||
from Patch import read_rom
|
||||
from .Locations import lookup_id_to_name, all_locations
|
||||
from .Levels import level_list, level_dict
|
||||
|
||||
USHASH = '120abf304f0c40fe059f6a192ed4f947'
|
||||
ROM_PLAYER_LIMIT = 65535
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import math
|
||||
|
||||
|
||||
location_rom_data = {
|
||||
0xDC3000: [0x657, 1], # Lakeside Limbo
|
||||
0xDC3001: [0x657, 2],
|
||||
0xDC3002: [0x657, 3],
|
||||
0xDC3003: [0x657, 5],
|
||||
|
||||
0xDC3004: [0x65A, 1], # Doorstop Dash
|
||||
0xDC3005: [0x65A, 2],
|
||||
0xDC3006: [0x65A, 3],
|
||||
0xDC3007: [0x65A, 5],
|
||||
|
||||
0xDC3008: [0x659, 1], # Tidal Trouble
|
||||
0xDC3009: [0x659, 2],
|
||||
0xDC300A: [0x659, 3],
|
||||
0xDC300B: [0x659, 5],
|
||||
|
||||
0xDC300C: [0x65D, 1], # Skidda's Row
|
||||
0xDC300D: [0x65D, 2],
|
||||
0xDC300E: [0x65D, 3],
|
||||
0xDC300F: [0x65D, 5],
|
||||
|
||||
0xDC3010: [0x65C, 1], # Murky Mill
|
||||
0xDC3011: [0x65C, 2],
|
||||
0xDC3012: [0x65C, 3],
|
||||
0xDC3013: [0x65C, 5],
|
||||
|
||||
|
||||
0xDC3014: [0x662, 1], # Barrel Shield Bust-Up
|
||||
0xDC3015: [0x662, 2],
|
||||
0xDC3016: [0x662, 3],
|
||||
0xDC3017: [0x662, 5],
|
||||
|
||||
0xDC3018: [0x664, 1], # Riverside Race
|
||||
0xDC3019: [0x664, 2],
|
||||
0xDC301A: [0x664, 3],
|
||||
0xDC301B: [0x664, 5],
|
||||
|
||||
0xDC301C: [0x65B, 1], # Squeals on Wheels
|
||||
0xDC301D: [0x65B, 2],
|
||||
0xDC301E: [0x65B, 3],
|
||||
0xDC301F: [0x65B, 5],
|
||||
|
||||
0xDC3020: [0x661, 1], # Springin' Spiders
|
||||
0xDC3021: [0x661, 2],
|
||||
0xDC3022: [0x661, 3],
|
||||
0xDC3023: [0x661, 5],
|
||||
|
||||
0xDC3024: [0x666, 1], # Bobbing Barrel Brawl
|
||||
0xDC3025: [0x666, 2],
|
||||
0xDC3026: [0x666, 3],
|
||||
0xDC3027: [0x666, 5],
|
||||
|
||||
|
||||
0xDC3028: [0x667, 1], # Bazza's Blockade
|
||||
0xDC3029: [0x667, 2],
|
||||
0xDC302A: [0x667, 3],
|
||||
0xDC302B: [0x667, 5],
|
||||
|
||||
0xDC302C: [0x66A, 1], # Rocket Barrel Ride
|
||||
0xDC302D: [0x66A, 2],
|
||||
0xDC302E: [0x66A, 3],
|
||||
0xDC302F: [0x66A, 5],
|
||||
|
||||
0xDC3030: [0x658, 1], # Kreeping Klasps
|
||||
0xDC3031: [0x658, 2],
|
||||
0xDC3032: [0x658, 3],
|
||||
0xDC3033: [0x658, 5],
|
||||
|
||||
0xDC3034: [0x66B, 1], # Tracker Barrel Trek
|
||||
0xDC3035: [0x66B, 2],
|
||||
0xDC3036: [0x66B, 3],
|
||||
0xDC3037: [0x66B, 5],
|
||||
|
||||
0xDC3038: [0x668, 1], # Fish Food Frenzy
|
||||
0xDC3039: [0x668, 2],
|
||||
0xDC303A: [0x668, 3],
|
||||
0xDC303B: [0x668, 5],
|
||||
|
||||
|
||||
0xDC303C: [0x66D, 1], # Fire-ball Frenzy
|
||||
0xDC303D: [0x66D, 2],
|
||||
0xDC303E: [0x66D, 3],
|
||||
0xDC303F: [0x66D, 5],
|
||||
|
||||
0xDC3040: [0x672, 1], # Demolition Drainpipe
|
||||
0xDC3041: [0x672, 2],
|
||||
0xDC3042: [0x672, 3],
|
||||
0xDC3043: [0x672, 5],
|
||||
|
||||
0xDC3044: [0x660, 1], # Ripsaw Rage
|
||||
0xDC3045: [0x660, 2],
|
||||
0xDC3046: [0x660, 3],
|
||||
0xDC3047: [0x660, 5],
|
||||
|
||||
0xDC3048: [0x66E, 1], # Blazing Bazukas
|
||||
0xDC3049: [0x66E, 2],
|
||||
0xDC304A: [0x66E, 3],
|
||||
0xDC304B: [0x66E, 5],
|
||||
|
||||
0xDC304C: [0x670, 1], # Low-G Labyrinth
|
||||
0xDC304D: [0x670, 2],
|
||||
0xDC304E: [0x670, 3],
|
||||
0xDC304F: [0x670, 5],
|
||||
|
||||
|
||||
0xDC3050: [0x673, 1], # Krevice Kreepers
|
||||
0xDC3051: [0x673, 2],
|
||||
0xDC3052: [0x673, 3],
|
||||
0xDC3053: [0x673, 5],
|
||||
|
||||
0xDC3054: [0x65F, 1], # Tearaway Toboggan
|
||||
0xDC3055: [0x65F, 2],
|
||||
0xDC3056: [0x65F, 3],
|
||||
0xDC3057: [0x65F, 5],
|
||||
|
||||
0xDC3058: [0x66C, 1], # Barrel Drop Bounce
|
||||
0xDC3059: [0x66C, 2],
|
||||
0xDC305A: [0x66C, 3],
|
||||
0xDC305B: [0x66C, 5],
|
||||
|
||||
0xDC305C: [0x66F, 1], # Krack-Shot Kroc
|
||||
0xDC305D: [0x66F, 2],
|
||||
0xDC305E: [0x66F, 3],
|
||||
0xDC305F: [0x66F, 5],
|
||||
|
||||
0xDC3060: [0x65E, 1], # Lemguin Lunge
|
||||
0xDC3061: [0x65E, 2],
|
||||
0xDC3062: [0x65E, 3],
|
||||
0xDC3063: [0x65E, 5],
|
||||
|
||||
|
||||
0xDC3064: [0x676, 1], # Buzzer Barrage
|
||||
0xDC3065: [0x676, 2],
|
||||
0xDC3066: [0x676, 3],
|
||||
0xDC3067: [0x676, 5],
|
||||
|
||||
0xDC3068: [0x674, 1], # Kong-Fused Cliffs
|
||||
0xDC3069: [0x674, 2],
|
||||
0xDC306A: [0x674, 3],
|
||||
0xDC306B: [0x674, 5],
|
||||
|
||||
0xDC306C: [0x669, 1], # Floodlit Fish
|
||||
0xDC306D: [0x669, 2],
|
||||
0xDC306E: [0x669, 3],
|
||||
0xDC306F: [0x669, 5],
|
||||
|
||||
0xDC3070: [0x677, 1], # Pothole Panic
|
||||
0xDC3071: [0x677, 2],
|
||||
0xDC3072: [0x677, 3],
|
||||
0xDC3073: [0x677, 5],
|
||||
|
||||
0xDC3074: [0x675, 1], # Ropey Rumpus
|
||||
0xDC3075: [0x675, 2],
|
||||
0xDC3076: [0x675, 3],
|
||||
0xDC3077: [0x675, 5],
|
||||
|
||||
|
||||
0xDC3078: [0x67A, 1], # Konveyor Rope Klash
|
||||
0xDC3079: [0x67A, 2],
|
||||
0xDC307A: [0x67A, 3],
|
||||
0xDC307B: [0x67A, 5],
|
||||
|
||||
0xDC307C: [0x678, 1], # Creepy Caverns
|
||||
0xDC307D: [0x678, 2],
|
||||
0xDC307E: [0x678, 3],
|
||||
0xDC307F: [0x678, 5],
|
||||
|
||||
0xDC3080: [0x665, 1], # Lightning Lookout
|
||||
0xDC3081: [0x665, 2],
|
||||
0xDC3082: [0x665, 3],
|
||||
0xDC3083: [0x665, 5],
|
||||
|
||||
0xDC3084: [0x679, 1], # Koindozer Klamber
|
||||
0xDC3085: [0x679, 2],
|
||||
0xDC3086: [0x679, 3],
|
||||
0xDC3087: [0x679, 5],
|
||||
|
||||
0xDC3088: [0x671, 1], # Poisonous Pipeline
|
||||
0xDC3089: [0x671, 2],
|
||||
0xDC308A: [0x671, 3],
|
||||
0xDC308B: [0x671, 5],
|
||||
|
||||
|
||||
0xDC308C: [0x67B, 1], # Stampede Sprint
|
||||
0xDC308D: [0x67B, 2],
|
||||
0xDC308E: [0x67B, 3],
|
||||
0xDC308F: [0x67B, 4],
|
||||
0xDC3090: [0x67B, 5],
|
||||
|
||||
0xDC3091: [0x67C, 1], # Criss Kross Cliffs
|
||||
0xDC3092: [0x67C, 2],
|
||||
0xDC3093: [0x67C, 3],
|
||||
0xDC3094: [0x67C, 5],
|
||||
|
||||
0xDC3095: [0x67D, 1], # Tyrant Twin Tussle
|
||||
0xDC3096: [0x67D, 2],
|
||||
0xDC3097: [0x67D, 3],
|
||||
0xDC3098: [0x67D, 4],
|
||||
0xDC3099: [0x67D, 5],
|
||||
|
||||
0xDC309A: [0x663, 1], # Swoopy Salvo
|
||||
0xDC309B: [0x663, 2],
|
||||
0xDC309C: [0x663, 3],
|
||||
0xDC309D: [0x663, 4],
|
||||
0xDC309E: [0x663, 5],
|
||||
|
||||
0xDC309F: [0x67E, 1], # Rocket Rush
|
||||
0xDC30A0: [0x67E, 5],
|
||||
|
||||
0xDC30A1: [0x64F, 1], # Bosses
|
||||
0xDC30A2: [0x650, 1],
|
||||
0xDC30A3: [0x651, 1],
|
||||
0xDC30A4: [0x652, 1],
|
||||
0xDC30A5: [0x653, 1],
|
||||
0xDC30A6: [0x654, 1],
|
||||
0xDC30A7: [0x655, 1],
|
||||
0xDC30A8: [0x656, 1],
|
||||
|
||||
0xDC30A9: [0x647, 1], # Banana Bird Caves
|
||||
0xDC30AA: [0x645, 1],
|
||||
0xDC30AB: [0x644, 1],
|
||||
0xDC30AC: [0x642, 1],
|
||||
0xDC30AD: [0x643, 1],
|
||||
0xDC30AE: [0x646, 1],
|
||||
0xDC30AF: [0x648, 1],
|
||||
0xDC30B0: [0x649, 1],
|
||||
0xDC30B1: [0x64A, 1],
|
||||
0xDC30B2: [0x64B, 1],
|
||||
0xDC30B3: [0x64C, 1],
|
||||
0xDC30B4: [0x64D, 1],
|
||||
0xDC30B5: [0x64E, 1],
|
||||
|
||||
0xDC30B6: [0x5FD, 4], # Banana Bird Mother
|
||||
|
||||
# DKC3_TODO: Disabled until Trade Sequence
|
||||
#0xDC30B7: [0x615, 2, True],
|
||||
#0xDC30B8: [0x615, 3, True],
|
||||
#0xDC30B9: [0x619, 2],
|
||||
##0xDC30BA:
|
||||
#0xDC30BB: [0x61B, 3],
|
||||
#0xDC30BC: [0x61D, 2],
|
||||
#0xDC30BD: [0x621, 4],
|
||||
#0xDC30BE: [0x625, 4, True],
|
||||
}
|
||||
|
||||
|
||||
item_rom_data = {
|
||||
0xDC3001: [0x5D5], # 1-Up Balloon
|
||||
0xDC3002: [0x5C9], # Bear Coin
|
||||
0xDC3003: [0x5CB], # Bonus Coin
|
||||
0xDC3004: [0x5CF], # DK Coin
|
||||
0xDC3005: [0x5CD], # Banana Bird
|
||||
0xDC3006: [0x5D1, 0x603], # Cog
|
||||
}
|
||||
|
||||
music_rom_data = [
|
||||
0x3D06B1,
|
||||
0x3D0753,
|
||||
0x3D071D,
|
||||
0x3D07FA,
|
||||
0x3D07C4,
|
||||
|
||||
0x3D08FE,
|
||||
0x3D096C,
|
||||
0x3D078E,
|
||||
0x3D08CD,
|
||||
0x3D09DD,
|
||||
|
||||
0x3D0A0E,
|
||||
0x3D0AB3,
|
||||
0x3D06E7,
|
||||
0x3D0AE4,
|
||||
0x3D0A45,
|
||||
|
||||
0x3D0B46,
|
||||
0x3D0C40,
|
||||
0x3D0897,
|
||||
0x3D0B77,
|
||||
0x3D0BD9,
|
||||
|
||||
0x3D0C71,
|
||||
0x3D0866,
|
||||
0x3D0B15,
|
||||
0x3D0BA8,
|
||||
0x3D0830,
|
||||
|
||||
0x3D0D04,
|
||||
0x3D0CA2,
|
||||
0x3D0A7C,
|
||||
0x3D0D35,
|
||||
0x3D0CD3,
|
||||
|
||||
0x3D0DC8,
|
||||
0x3D0D66,
|
||||
0x3D09AC,
|
||||
0x3D0D97,
|
||||
0x3D0C0F,
|
||||
|
||||
0x3D0DF9,
|
||||
0x3D0E31,
|
||||
0x3D0E62,
|
||||
0x3D0934,
|
||||
0x3D0E9A,
|
||||
]
|
||||
|
||||
level_music_ids = [
|
||||
0x06,
|
||||
0x07,
|
||||
0x08,
|
||||
0x0A,
|
||||
0x0B,
|
||||
0x0E,
|
||||
0x0F,
|
||||
0x10,
|
||||
0x17,
|
||||
0x19,
|
||||
0x1C,
|
||||
0x1D,
|
||||
0x1E,
|
||||
0x21,
|
||||
]
|
||||
|
||||
class LocalRom(object):
|
||||
|
||||
def __init__(self, file, patch=True, vanillaRom=None, name=None, hash=None):
|
||||
self.name = name
|
||||
self.hash = hash
|
||||
self.orig_buffer = None
|
||||
|
||||
with open(file, 'rb') as stream:
|
||||
self.buffer = read_rom(stream)
|
||||
#if patch:
|
||||
# self.patch_rom()
|
||||
# self.orig_buffer = self.buffer.copy()
|
||||
#if vanillaRom:
|
||||
# with open(vanillaRom, 'rb') as vanillaStream:
|
||||
# self.orig_buffer = read_rom(vanillaStream)
|
||||
|
||||
def read_bit(self, address: int, bit_number: int) -> bool:
|
||||
bitflag = (1 << bit_number)
|
||||
return ((self.buffer[address] & bitflag) != 0)
|
||||
|
||||
def read_byte(self, address: int) -> int:
|
||||
return self.buffer[address]
|
||||
|
||||
def read_bytes(self, startaddress: int, length: int) -> bytes:
|
||||
return self.buffer[startaddress:startaddress + length]
|
||||
|
||||
def write_byte(self, address: int, value: int):
|
||||
self.buffer[address] = value
|
||||
|
||||
def write_bytes(self, startaddress: int, values):
|
||||
self.buffer[startaddress:startaddress + len(values)] = values
|
||||
|
||||
def write_to_file(self, file):
|
||||
with open(file, 'wb') as outfile:
|
||||
outfile.write(self.buffer)
|
||||
|
||||
def read_from_file(self, file):
|
||||
with open(file, 'rb') as stream:
|
||||
self.buffer = bytearray(stream.read())
|
||||
|
||||
|
||||
|
||||
def patch_rom(world, rom, player, active_level_list):
|
||||
local_random = world.slot_seeds[player]
|
||||
|
||||
# Boomer Costs
|
||||
bonus_coin_cost = world.krematoa_bonus_coin_cost[player]
|
||||
inverted_bonus_coin_cost = 0x100 - bonus_coin_cost
|
||||
rom.write_byte(0x3498B9, inverted_bonus_coin_cost)
|
||||
rom.write_byte(0x3498BA, inverted_bonus_coin_cost)
|
||||
rom.write_byte(0x3498BB, inverted_bonus_coin_cost)
|
||||
rom.write_byte(0x3498BC, inverted_bonus_coin_cost)
|
||||
rom.write_byte(0x3498BD, inverted_bonus_coin_cost)
|
||||
|
||||
rom.write_byte(0x349857, bonus_coin_cost)
|
||||
rom.write_byte(0x349862, bonus_coin_cost)
|
||||
|
||||
# Gyrocopter Costs
|
||||
dk_coin_cost = world.dk_coins_for_gyrocopter[player]
|
||||
rom.write_byte(0x3484A6, dk_coin_cost)
|
||||
rom.write_byte(0x3484D5, dk_coin_cost)
|
||||
rom.write_byte(0x3484D7, 0x90)
|
||||
rom.write_byte(0x3484DC, 0xEA)
|
||||
rom.write_byte(0x3484DD, 0xEA)
|
||||
rom.write_byte(0x3484DE, 0xEA)
|
||||
rom.write_byte(0x348528, 0x80) # Prevent Single-Ski Lock
|
||||
|
||||
|
||||
# Make Swanky free
|
||||
rom.write_byte(0x348C48, 0x00)
|
||||
|
||||
# Banana Bird Costs
|
||||
if world.goal[player] == "banana_bird_hunt":
|
||||
banana_bird_cost = math.floor(world.number_of_banana_birds[player] * world.percentage_of_banana_birds[player] / 100.0)
|
||||
rom.write_byte(0x34AB85, banana_bird_cost)
|
||||
rom.write_byte(0x329FD8, banana_bird_cost)
|
||||
rom.write_byte(0x32A025, banana_bird_cost)
|
||||
rom.write_byte(0x329FDA, 0xB0)
|
||||
else:
|
||||
# rom.write_byte(0x34AB84, 0x20) # These cause hangs at Wrinkly's
|
||||
# rom.write_byte(0x329FD8, 0x20)
|
||||
# rom.write_byte(0x32A025, 0x20)
|
||||
rom.write_byte(0x329FDA, 0xB0)
|
||||
|
||||
# Baffle Mirror Fix
|
||||
rom.write_byte(0x9133, 0x08)
|
||||
rom.write_byte(0x9135, 0x0C)
|
||||
rom.write_byte(0x9136, 0x2B)
|
||||
rom.write_byte(0x9137, 0x06)
|
||||
|
||||
# Palette Swap
|
||||
rom.write_byte(0x3B96A5, 0xD0)
|
||||
if world.kong_palette_swap[player] == "default":
|
||||
rom.write_byte(0x3B96A9, 0x00)
|
||||
rom.write_byte(0x3B96A8, 0x00)
|
||||
elif world.kong_palette_swap[player] == "purple":
|
||||
rom.write_byte(0x3B96A9, 0x00)
|
||||
rom.write_byte(0x3B96A8, 0x3C)
|
||||
elif world.kong_palette_swap[player] == "spooky":
|
||||
rom.write_byte(0x3B96A9, 0x00)
|
||||
rom.write_byte(0x3B96A8, 0xA0)
|
||||
elif world.kong_palette_swap[player] == "dark":
|
||||
rom.write_byte(0x3B96A9, 0x05)
|
||||
rom.write_byte(0x3B96A8, 0xA0)
|
||||
elif world.kong_palette_swap[player] == "chocolate":
|
||||
rom.write_byte(0x3B96A9, 0x1D)
|
||||
rom.write_byte(0x3B96A8, 0xA0)
|
||||
elif world.kong_palette_swap[player] == "shadow":
|
||||
rom.write_byte(0x3B96A9, 0x45)
|
||||
rom.write_byte(0x3B96A8, 0xA0)
|
||||
elif world.kong_palette_swap[player] == "red_gold":
|
||||
rom.write_byte(0x3B96A9, 0x5D)
|
||||
rom.write_byte(0x3B96A8, 0xA0)
|
||||
elif world.kong_palette_swap[player] == "gbc":
|
||||
rom.write_byte(0x3B96A9, 0x20)
|
||||
rom.write_byte(0x3B96A8, 0x3C)
|
||||
elif world.kong_palette_swap[player] == "halloween":
|
||||
rom.write_byte(0x3B96A9, 0x70)
|
||||
rom.write_byte(0x3B96A8, 0x3C)
|
||||
|
||||
if world.music_shuffle[player]:
|
||||
for address in music_rom_data:
|
||||
rand_song = local_random.choice(level_music_ids)
|
||||
rom.write_byte(address, rand_song)
|
||||
|
||||
# Starting Lives
|
||||
rom.write_byte(0x9130, world.starting_life_count[player].value)
|
||||
rom.write_byte(0x913B, world.starting_life_count[player].value)
|
||||
|
||||
|
||||
# Handle Level Shuffle Here
|
||||
if world.level_shuffle[player]:
|
||||
for i in range(len(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)
|
||||
|
||||
# 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))
|
||||
rom.write_byte(0x34BC4A, (0x32 + level_dict[active_level_list[10]].levelID))
|
||||
rom.write_byte(0x34BC53, (0x32 + level_dict[active_level_list[15]].levelID))
|
||||
rom.write_byte(0x34BC59, (0x32 + level_dict[active_level_list[20]].levelID))
|
||||
rom.write_byte(0x34BC5C, (0x32 + level_dict[active_level_list[25]].levelID))
|
||||
rom.write_byte(0x34BC65, (0x32 + level_dict[active_level_list[30]].levelID))
|
||||
rom.write_byte(0x34BC6E, (0x32 + level_dict[active_level_list[35]].levelID))
|
||||
|
||||
# Cotton-Top Cove Boss Unlock
|
||||
rom.write_byte(0x34C02A, (0x32 + level_dict[active_level_list[14]].levelID))
|
||||
|
||||
# Kong-Fused Cliffs Unlock
|
||||
rom.write_byte(0x34C213, (0x32 + level_dict[active_level_list[25]].levelID))
|
||||
rom.write_byte(0x34C21B, (0x32 + level_dict[active_level_list[26]].levelID))
|
||||
|
||||
if world.goal[player] == "knautilus":
|
||||
# Swap Kastle KAOS and Knautilus
|
||||
rom.write_byte(0x34D4E1, 0xC2)
|
||||
rom.write_byte(0x34D4E2, 0x24)
|
||||
rom.write_byte(0x34D551, 0xBA)
|
||||
rom.write_byte(0x34D552, 0x23)
|
||||
|
||||
rom.write_byte(0x32F339, 0x55)
|
||||
|
||||
|
||||
from Main import __version__
|
||||
rom.name = bytearray(f'D3{__version__.replace(".", "")[0:3]}_{player}_{world.seed:11}\0', 'utf8')[:21]
|
||||
rom.name.extend([0] * (21 - len(rom.name)))
|
||||
rom.write_bytes(0x7FC0, rom.name)
|
||||
|
||||
# DKC3_TODO: This is a hack, reconsider
|
||||
# Don't grant (DK, Bonus, Bear) Coins
|
||||
rom.write_byte(0x3BD454, 0xEA)
|
||||
rom.write_byte(0x3BD455, 0xEA)
|
||||
|
||||
# Don't grant Cogs
|
||||
rom.write_byte(0x3BD574, 0xEA)
|
||||
rom.write_byte(0x3BD575, 0xEA)
|
||||
rom.write_byte(0x3BD576, 0xEA)
|
||||
|
||||
# Don't grant Banana Birds at their caves
|
||||
rom.write_byte(0x32DD62, 0xEA)
|
||||
rom.write_byte(0x32DD63, 0xEA)
|
||||
rom.write_byte(0x32DD64, 0xEA)
|
||||
|
||||
# Don't grant Patch and Skis from their bosses
|
||||
rom.write_byte(0x3F3762, 0x00)
|
||||
rom.write_byte(0x3F377B, 0x00)
|
||||
rom.write_byte(0x3F3797, 0x00)
|
||||
|
||||
# Always allow Start+Select
|
||||
rom.write_byte(0x8BAB, 0x01)
|
||||
|
||||
# Handle Alt Palettes in Krematoa
|
||||
rom.write_byte(0x3B97E9, 0x80)
|
||||
rom.write_byte(0x3B97EA, 0xEA)
|
||||
|
||||
|
||||
|
||||
def get_base_rom_bytes(file_name: str = "") -> bytes:
|
||||
base_rom_bytes = getattr(get_base_rom_bytes, "base_rom_bytes", None)
|
||||
if not base_rom_bytes:
|
||||
file_name = get_base_rom_path(file_name)
|
||||
base_rom_bytes = bytes(read_rom(open(file_name, "rb")))
|
||||
|
||||
basemd5 = hashlib.md5()
|
||||
basemd5.update(base_rom_bytes)
|
||||
if USHASH != basemd5.hexdigest():
|
||||
raise Exception('Supplied Base Rom does not match known MD5 for US(1.0) release. '
|
||||
'Get the correct game and version, then dump it')
|
||||
get_base_rom_bytes.base_rom_bytes = base_rom_bytes
|
||||
return base_rom_bytes
|
||||
|
||||
def get_base_rom_path(file_name: str = "") -> str:
|
||||
options = Utils.get_options()
|
||||
if not file_name:
|
||||
file_name = options["dkc3_options"]["rom_file"]
|
||||
if not os.path.exists(file_name):
|
||||
file_name = Utils.local_path(file_name)
|
||||
return file_name
|
|
@ -0,0 +1,32 @@
|
|||
import math
|
||||
|
||||
from BaseClasses import MultiWorld
|
||||
from .Names import LocationName, ItemName
|
||||
from ..AutoWorld import LogicMixin
|
||||
from ..generic.Rules import add_rule, set_rule
|
||||
|
||||
|
||||
def set_rules(world: MultiWorld, player: int):
|
||||
|
||||
if False:#world.include_trade_sequence[player]:
|
||||
add_rule(world.get_location(LocationName.barnacles_island, player),
|
||||
lambda state: state.has(ItemName.shell, player))
|
||||
|
||||
add_rule(world.get_location(LocationName.blues_beach_hut, player),
|
||||
lambda state: state.has(ItemName.present, player))
|
||||
|
||||
add_rule(world.get_location(LocationName.brambles_bungalow, player),
|
||||
lambda state: state.has(ItemName.flower, player))
|
||||
|
||||
add_rule(world.get_location(LocationName.barters_swap_shop, player),
|
||||
lambda state: state.has(ItemName.mirror, player))
|
||||
|
||||
|
||||
if world.goal[player] != "knautilus":
|
||||
required_banana_birds = math.floor(
|
||||
world.number_of_banana_birds[player].value * (world.percentage_of_banana_birds[player].value / 100.0))
|
||||
|
||||
add_rule(world.get_location(LocationName.banana_bird_mother, player),
|
||||
lambda state: state.has(ItemName.banana_bird, player, required_banana_birds))
|
||||
|
||||
world.completion_condition[player] = lambda state: state.has(ItemName.victory, player)
|
|
@ -0,0 +1,204 @@
|
|||
import os
|
||||
import typing
|
||||
import math
|
||||
import threading
|
||||
|
||||
from BaseClasses import Item, MultiWorld, Tutorial, ItemClassification
|
||||
from .Items import DKC3Item, ItemData, item_table, inventory_table
|
||||
from .Locations import DKC3Location, all_locations, setup_locations
|
||||
from .Options import dkc3_options
|
||||
from .Regions import create_regions, connect_regions
|
||||
from .Levels import level_list
|
||||
from .Rules import set_rules
|
||||
from .Names import ItemName, LocationName
|
||||
from ..AutoWorld import WebWorld, World
|
||||
from .Rom import LocalRom, patch_rom, get_base_rom_path
|
||||
import Patch
|
||||
|
||||
|
||||
class DKC3Web(WebWorld):
|
||||
theme = "jungle"
|
||||
|
||||
setup_en = Tutorial(
|
||||
"Multiworld Setup Guide",
|
||||
"A guide to setting up the Donkey Kong Country 3 randomizer connected to an Archipelago Multiworld.",
|
||||
"English",
|
||||
"setup_en.md",
|
||||
"setup/en",
|
||||
["PoryGone"]
|
||||
)
|
||||
|
||||
tutorials = [setup_en]
|
||||
|
||||
|
||||
class DKC3World(World):
|
||||
"""
|
||||
Donkey Kong Country 3 is an action platforming game.
|
||||
Play as Dixie Kong and her baby cousin Kiddy as they try to solve the
|
||||
mystery of why Donkey Kong and Diddy disappeared while on vacation.
|
||||
"""
|
||||
game: str = "Donkey Kong Country 3"
|
||||
options = dkc3_options
|
||||
topology_present = False
|
||||
data_version = 1
|
||||
#hint_blacklist = {LocationName.rocket_rush_flag}
|
||||
|
||||
item_name_to_id = {name: data.code for name, data in item_table.items()}
|
||||
location_name_to_id = all_locations
|
||||
|
||||
active_level_list: typing.List[str]
|
||||
web = DKC3Web()
|
||||
|
||||
def __init__(self, world: MultiWorld, player: int):
|
||||
self.rom_name_available_event = threading.Event()
|
||||
super().__init__(world, player)
|
||||
|
||||
@classmethod
|
||||
def stage_assert_generate(cls, world):
|
||||
rom_file = get_base_rom_path()
|
||||
if not os.path.exists(rom_file):
|
||||
raise FileNotFoundError(rom_file)
|
||||
|
||||
def _get_slot_data(self):
|
||||
return {
|
||||
#"death_link": self.world.death_link[self.player].value,
|
||||
"active_levels": self.active_level_list,
|
||||
}
|
||||
|
||||
def _create_items(self, name: str):
|
||||
data = item_table[name]
|
||||
return [self.create_item(name)] * data.quantity
|
||||
|
||||
def fill_slot_data(self) -> dict:
|
||||
slot_data = self._get_slot_data()
|
||||
for option_name in dkc3_options:
|
||||
option = getattr(self.world, option_name)[self.player]
|
||||
slot_data[option_name] = option.value
|
||||
|
||||
return slot_data
|
||||
|
||||
def generate_basic(self):
|
||||
self.topology_present = self.world.level_shuffle[self.player].value
|
||||
itempool: typing.List[DKC3Item] = []
|
||||
|
||||
# Levels
|
||||
total_required_locations = 161
|
||||
|
||||
number_of_banana_birds = 0
|
||||
# Rocket Rush Cog
|
||||
total_required_locations -= 1
|
||||
number_of_cogs = 4
|
||||
self.world.get_location(LocationName.rocket_rush_flag, self.player).place_locked_item(self.create_item(ItemName.krematoa_cog))
|
||||
number_of_bosses = 8
|
||||
if self.world.goal[self.player] == "knautilus":
|
||||
self.world.get_location(LocationName.kastle_kaos, self.player).place_locked_item(self.create_item(ItemName.victory))
|
||||
number_of_bosses = 7
|
||||
else:
|
||||
self.world.get_location(LocationName.banana_bird_mother, self.player).place_locked_item(self.create_item(ItemName.victory))
|
||||
number_of_banana_birds = self.world.number_of_banana_birds[self.player]
|
||||
|
||||
# Bosses
|
||||
total_required_locations += number_of_bosses
|
||||
|
||||
# Secret Caves
|
||||
total_required_locations += 13
|
||||
|
||||
## Brothers Bear
|
||||
if False:#self.world.include_trade_sequence[self.player]:
|
||||
total_required_locations += 8
|
||||
|
||||
number_of_bonus_coins = (self.world.krematoa_bonus_coin_cost[self.player] * 5)
|
||||
number_of_bonus_coins += math.ceil((85 - number_of_bonus_coins) * self.world.percentage_of_extra_bonus_coins[self.player] / 100)
|
||||
|
||||
itempool += [self.create_item(ItemName.bonus_coin)] * number_of_bonus_coins
|
||||
itempool += [self.create_item(ItemName.dk_coin)] * 41
|
||||
itempool += [self.create_item(ItemName.banana_bird)] * number_of_banana_birds
|
||||
itempool += [self.create_item(ItemName.krematoa_cog)] * number_of_cogs
|
||||
itempool += [self.create_item(ItemName.progressive_boat)] * 3
|
||||
|
||||
total_junk_count = total_required_locations - len(itempool)
|
||||
|
||||
itempool += [self.create_item(ItemName.bear_coin)] * total_junk_count
|
||||
|
||||
self.active_level_list = level_list.copy()
|
||||
|
||||
if self.world.level_shuffle[self.player]:
|
||||
self.world.random.shuffle(self.active_level_list)
|
||||
|
||||
connect_regions(self.world, self.player, self.active_level_list)
|
||||
|
||||
self.world.itempool += itempool
|
||||
|
||||
def generate_output(self, output_directory: str):
|
||||
try:
|
||||
world = self.world
|
||||
player = self.player
|
||||
|
||||
rom = LocalRom(get_base_rom_path())
|
||||
patch_rom(self.world, rom, self.player, self.active_level_list)
|
||||
|
||||
self.active_level_list.append(LocationName.rocket_rush_region)
|
||||
|
||||
outfilepname = f'_P{player}'
|
||||
outfilepname += f"_{world.player_name[player].replace(' ', '_')}" \
|
||||
if world.player_name[player] != 'Player%d' % player else ''
|
||||
|
||||
rompath = os.path.join(output_directory, f'AP_{world.seed_name}{outfilepname}.sfc')
|
||||
rom.write_to_file(rompath)
|
||||
Patch.create_patch_file(rompath, player=player, player_name=world.player_name[player], game=Patch.GAME_DKC3)
|
||||
os.unlink(rompath)
|
||||
self.rom_name = rom.name
|
||||
except:
|
||||
raise
|
||||
finally:
|
||||
self.rom_name_available_event.set() # make sure threading continues and errors are collected
|
||||
|
||||
def modify_multidata(self, multidata: dict):
|
||||
import base64
|
||||
# wait for self.rom_name to be available.
|
||||
self.rom_name_available_event.wait()
|
||||
rom_name = getattr(self, "rom_name", None)
|
||||
# we skip in case of error, so that the original error in the output thread is the one that gets raised
|
||||
if rom_name:
|
||||
new_name = base64.b64encode(bytes(self.rom_name)).decode()
|
||||
multidata["connect_names"][new_name] = multidata["connect_names"][self.world.player_name[self.player]]
|
||||
|
||||
if self.topology_present:
|
||||
world_names = [
|
||||
LocationName.lake_orangatanga_region,
|
||||
LocationName.kremwood_forest_region,
|
||||
LocationName.cotton_top_cove_region,
|
||||
LocationName.mekanos_region,
|
||||
LocationName.k3_region,
|
||||
LocationName.razor_ridge_region,
|
||||
LocationName.kaos_kore_region,
|
||||
LocationName.krematoa_region,
|
||||
]
|
||||
er_hint_data = {}
|
||||
for world_index in range(len(world_names)):
|
||||
for level_index in range(5):
|
||||
level_region = self.world.get_region(self.active_level_list[world_index * 5 + level_index], self.player)
|
||||
for location in level_region.locations:
|
||||
er_hint_data[location.address] = world_names[world_index]
|
||||
multidata['er_hint_data'][self.player] = er_hint_data
|
||||
|
||||
def create_regions(self):
|
||||
location_table = setup_locations(self.world, self.player)
|
||||
create_regions(self.world, self.player, location_table)
|
||||
|
||||
def create_item(self, name: str, force_non_progression=False) -> Item:
|
||||
data = item_table[name]
|
||||
|
||||
if force_non_progression:
|
||||
classification = ItemClassification.filler
|
||||
elif data.progression:
|
||||
classification = ItemClassification.progression
|
||||
else:
|
||||
classification = ItemClassification.filler
|
||||
|
||||
created_item = DKC3Item(name, classification, data.code, self.player)
|
||||
|
||||
return created_item
|
||||
|
||||
def set_rules(self):
|
||||
set_rules(self.world, self.player)
|
|
@ -0,0 +1,35 @@
|
|||
# Donkey Kong Country 3
|
||||
|
||||
## Where is the settings page?
|
||||
|
||||
The [player settings page for this game](../player-settings) contains all the options you need to configure and export a config file.
|
||||
|
||||
## What does randomization do to this game?
|
||||
|
||||
Items which the player would normally acquire throughout the game have been moved around. Logic remains, so the game is
|
||||
always able to be completed, but because of the item shuffle the player may need to access certain areas before they
|
||||
would in the vanilla game.
|
||||
|
||||
## What is the goal of Donkey Kong Country 3 when randomized?
|
||||
|
||||
There are two goals which can be chosen:
|
||||
- `Knautilus`: Collect Bonus Coins and Krematoa Cogs to reach K. Rool's submarine in Krematoa
|
||||
- `Banana Bird Hunt`: Collect Banana Birds to free the Banana Bird Mother
|
||||
|
||||
## What items and locations get shuffled?
|
||||
|
||||
All Bonus Coins, DK Coins, and Banana Birds (if on a `Banana Bird Hunt` goal) are randomized. Additionally, level clears award a location check.
|
||||
The Patch and two Skis for upgrading the boat are included. Bear Coins are provided if additional items are needed for the item pool.
|
||||
Four of the Five Krematoa Cogs are randomized, but the final one is always in its vanilla location at the Flag of Rocket Rush in Krematoa
|
||||
|
||||
## Which items can be in another player's world?
|
||||
|
||||
Any shuffled item can be in other players' worlds.
|
||||
|
||||
## What does another world's item look like in Donkey Kong Country 3
|
||||
|
||||
Items pickups all retain their original appearance. You won't know if an item belongs to another player until you collect.
|
||||
|
||||
## When the player receives an item, what happens?
|
||||
|
||||
Currently, the items are silently added to the player's inventory, which can be seen when saving the game.
|
|
@ -0,0 +1,161 @@
|
|||
# Donkey Kong Country 3 Randomizer Setup Guide
|
||||
|
||||
## Required Software
|
||||
|
||||
- [Archipelago](https://github.com/ArchipelagoMW/Archipelago/releases). Make sure to check the box for `SNI Client - Donkey Kong Country 3 Patch Setup`
|
||||
|
||||
|
||||
- Hardware or software capable of loading and playing SNES ROM files
|
||||
- An emulator capable of connecting to SNI such as:
|
||||
- snes9x Multitroid
|
||||
from: [snes9x Multitroid Download](https://drive.google.com/drive/folders/1_ej-pwWtCAHYXIrvs5Hro16A1s9Hi3Jz),
|
||||
- BizHawk from: [BizHawk Website](http://tasvideos.org/BizHawk.html)
|
||||
- RetroArch 1.10.3 or newer from: [RetroArch Website](https://retroarch.com?page=platforms). Or,
|
||||
- An SD2SNES, FXPak Pro ([FXPak Pro Store Page](https://krikzz.com/store/home/54-fxpak-pro.html)), or other
|
||||
compatible hardware
|
||||
- Your legally obtained Donkey Kong Country 3 ROM file, probably named `Donkey Kong Country 3 - Dixie Kong's Double Trouble! (USA) (En,Fr).sfc`
|
||||
|
||||
## Installation Procedures
|
||||
|
||||
### Windows Setup
|
||||
|
||||
1. During the installation of Archipelago, you will have been asked to install the SNI Client. If you did not do this,
|
||||
or you are on an older version, you may run the installer again to install the SNI Client.
|
||||
2. During setup, you will be asked to locate your base ROM file. This is your Donkey Kong Country 3 ROM file.
|
||||
3. If you are using an emulator, you should assign your Lua capable emulator as your default program for launching ROM
|
||||
files.
|
||||
1. Extract your emulator's folder to your Desktop, or somewhere you will remember.
|
||||
2. Right-click on a ROM file and select **Open with...**
|
||||
3. Check the box next to **Always use this app to open .sfc files**
|
||||
4. Scroll to the bottom of the list and click the grey text **Look for another App on this PC**
|
||||
5. Browse for your emulator's `.exe` file and click **Open**. This file should be located inside the folder you
|
||||
extracted in step one.
|
||||
|
||||
## Create a Config (.yaml) File
|
||||
|
||||
### What is a config file and why do I need one?
|
||||
|
||||
See the guide on setting up a basic YAML at the Archipelago setup
|
||||
guide: [Basic Multiworld Setup Guide](/tutorial/Archipelago/setup/en)
|
||||
|
||||
### Where do I get a config file?
|
||||
|
||||
The Player Settings page on the website allows you to configure your personal settings and export a config file from
|
||||
them. Player settings page: [Donkey Kong Country 3 Player Settings Page](/games/Donkey%20Kong%20Country%203/player-settings)
|
||||
|
||||
### Verifying your config file
|
||||
|
||||
If you would like to validate your config file to make sure it works, you may do so on the YAML Validator page. YAML
|
||||
validator page: [YAML Validation page](/mysterycheck)
|
||||
|
||||
## Generating a Single-Player Game
|
||||
|
||||
1. Navigate to the Player Settings page, configure your options, and click the "Generate Game" button.
|
||||
- Player Settings page: [Donkey Kong Country 3 Player Settings Page](/games/Donkey%20Kong%20Country%203/player-settings)
|
||||
2. You will be presented with a "Seed Info" page.
|
||||
3. Click the "Create New Room" link.
|
||||
4. You will be presented with a server page, from which you can download your patch file.
|
||||
5. Double-click on your patch file, and the Donkey Kong Country 3 Client will launch automatically, create your ROM from the
|
||||
patch file, and open your emulator for you.
|
||||
6. Since this is a single-player game, you will no longer need the client, so feel free to close it.
|
||||
|
||||
## Joining a MultiWorld Game
|
||||
|
||||
### Obtain your patch file and create your ROM
|
||||
|
||||
When you join a multiworld game, you will be asked to provide your config file to whoever is hosting. Once that is done,
|
||||
the host will provide you with either a link to download your patch file, or with a zip file containing everyone's patch
|
||||
files. Your patch file should have a `.apsm` extension.
|
||||
|
||||
Put your patch file on your desktop or somewhere convenient, and double click it. This should automatically launch the
|
||||
client, and will also create your ROM in the same place as your patch file.
|
||||
|
||||
### Connect to the client
|
||||
|
||||
#### With an emulator
|
||||
|
||||
When the client launched automatically, SNI should have also automatically launched in the background. If this is its
|
||||
first time launching, you may be prompted to allow it to communicate through the Windows Firewall.
|
||||
|
||||
##### snes9x Multitroid
|
||||
|
||||
1. Load your ROM file if it hasn't already been loaded.
|
||||
2. Click on the File menu and hover on **Lua Scripting**
|
||||
3. Click on **New Lua Script Window...**
|
||||
4. In the new window, click **Browse...**
|
||||
5. Select the connector lua file included with your client
|
||||
- Look in the Archipelago folder for `/SNI/lua/x64` or `/SNI/lua/x86` depending on if the
|
||||
emulator is 64-bit or 32-bit.
|
||||
6. If you see an error while loading the script that states `socket.dll missing` or similar, navigate to the folder of
|
||||
the lua you are using in your file explorer and copy the `socket.dll` to the base folder of your snes9x install.
|
||||
|
||||
##### BizHawk
|
||||
|
||||
1. Ensure you have the BSNES core loaded. You may do this by clicking on the Tools menu in BizHawk and following these
|
||||
menu options:
|
||||
`Config --> Cores --> SNES --> BSNES`
|
||||
Once you have changed the loaded core, you must restart BizHawk.
|
||||
2. Load your ROM file if it hasn't already been loaded.
|
||||
3. Click on the Tools menu and click on **Lua Console**
|
||||
4. Click the button to open a new Lua script.
|
||||
5. Select the `Connector.lua` file included with your client
|
||||
- Look in the Archipelago folder for `/SNI/lua/x64` or `/SNI/lua/x86` depending on if the
|
||||
emulator is 64-bit or 32-bit. Please note the most recent versions of BizHawk are 64-bit only.
|
||||
|
||||
##### RetroArch 1.10.3 or newer
|
||||
|
||||
You only have to do these steps once. Note, RetroArch 1.9.x will not work as it is older than 1.10.3.
|
||||
|
||||
1. Enter the RetroArch main menu screen.
|
||||
2. Go to Settings --> User Interface. Set "Show Advanced Settings" to ON.
|
||||
3. Go to Settings --> Network. Set "Network Commands" to ON. (It is found below Request Device 16.) Leave the default
|
||||
Network Command Port at 55355.
|
||||
|
||||

|
||||
4. Go to Main Menu --> Online Updater --> Core Downloader. Scroll down and select "Nintendo - SNES / SFC (bsnes-mercury
|
||||
Performance)".
|
||||
|
||||
When loading a ROM, be sure to select a **bsnes-mercury** core. These are the only cores that allow external tools to
|
||||
read ROM data.
|
||||
|
||||
#### With hardware
|
||||
|
||||
This guide assumes you have downloaded the correct firmware for your device. If you have not done so already, please do
|
||||
this now. SD2SNES and FXPak Pro users may download the appropriate firmware on the SD2SNES releases page. SD2SNES
|
||||
releases page: [SD2SNES Releases Page](https://github.com/RedGuyyyy/sd2snes/releases)
|
||||
|
||||
Other hardware may find helpful information on the usb2snes platforms
|
||||
page: [usb2snes Supported Platforms Page](http://usb2snes.com/#supported-platforms)
|
||||
|
||||
1. Close your emulator, which may have auto-launched.
|
||||
2. Power on your device and load the ROM.
|
||||
|
||||
### Connect to the Archipelago Server
|
||||
|
||||
The patch file which launched your client should have automatically connected you to the AP Server. There are a few
|
||||
reasons this may not happen however, including if the game is hosted on the website but was generated elsewhere. If the
|
||||
client window shows "Server Status: Not Connected", simply ask the host for the address of the server, and copy/paste it
|
||||
into the "Server" input field then press enter.
|
||||
|
||||
The client will attempt to reconnect to the new server address, and should momentarily show "Server Status: Connected".
|
||||
|
||||
### Play the game
|
||||
|
||||
When the client shows both SNES Device and Server as connected, you're ready to begin playing. Congratulations on
|
||||
successfully joining a multiworld game!
|
||||
|
||||
## Hosting a MultiWorld game
|
||||
|
||||
The recommended way to host a game is to use our hosting service. The process is relatively simple:
|
||||
|
||||
1. Collect config files from your players.
|
||||
2. Create a zip file containing your players' config files.
|
||||
3. Upload that zip file to the Generate page above.
|
||||
- Generate page: [WebHost Seed Generation Page](/generate)
|
||||
4. Wait a moment while the seed is generated.
|
||||
5. When the seed is generated, you will be redirected to a "Seed Info" page.
|
||||
6. Click "Create New Room". This will take you to the server page. Provide the link to this page to your players, so
|
||||
they may download their patch files from there.
|
||||
7. Note that a link to a MultiWorld Tracker is at the top of the room page. The tracker shows the progress of all
|
||||
players in the game. Any observers may also be given the link to this page.
|
||||
8. Once all players have joined, you may begin playing.
|
Loading…
Reference in New Issue