Skip to content

Commit

Permalink
initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
TheLX5 committed Nov 9, 2024
1 parent e362fc7 commit 028ebea
Show file tree
Hide file tree
Showing 12 changed files with 623 additions and 128 deletions.
125 changes: 111 additions & 14 deletions worlds/dkc2/Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,27 @@
WRAM_SIZE = 0x20000
SRAM_START = 0xE00000

STARTING_ID = 0xBE0800
STARTING_ID = 0xBF0000

DKC2_SETTINGS = ROM_START + 0x3DFF80

DKC2_MISC_FLAGS = WRAM_START + 0x08D2
DKC2_GAME_FLAGS = WRAM_START + 0x59B2

DKC2_EFFECT_BUFFER = WRAM_START + 0x0619
DKC2_SOUND_BUFFER = WRAM_START + 0x0622
DKC2_SPC_NEXT_INDEX = WRAM_START + 0x0634
DKC2_SPC_INDEX = WRAM_START + 0x0632
DKC2_SPC_CHANNEL_BUSY = WRAM_START + 0x0621

DKC2_SRAM = SRAM_START + 0x800
DKC2_RECV_INDEX = DKC2_SRAM + 0x020
DKC2_INIT_FLAG = DKC2_SRAM + 0x022

DKC2_GAME_TIME = WRAM_START + 0x00D5
DKC2_IN_LEVEL = WRAM_START + 0x01FF
DKC2_CURRENT_LEVEL = WRAM_START + 0x00D3
DKC2_CURRENT_MODE = WRAM_START + 0x00D0

DKC2_CRANKY_FLAGS = WRAM_START + 0x08D2
DKC2_WRINKLY_FLAGS = WRAM_START + 0x08E0
Expand All @@ -37,7 +47,7 @@
DKC2_DK_COIN_FLAGS = WRAM_START + 0x59D2
DKC2_STAGE_FLAGS = WRAM_START + 0x59F2

DKC2_ROMHASH_START = 0x7FC0
DKC2_ROMHASH_START = 0xFFC0
ROMHASH_SIZE = 0x15

class DKC2SNIClient(SNIClient):
Expand Down Expand Up @@ -83,24 +93,29 @@ async def validate_rom(self, ctx):
async def game_watcher(self, ctx):
from SNIClient import snes_buffered_write, snes_flush_writes, snes_read

in_level = await snes_read(ctx, DKC2_IN_LEVEL, 0x01)
if in_level[0] != 0x80:
self.game_state = False
setting_data = await snes_read(ctx, DKC2_SETTINGS, 0x40)
general_data = await snes_read(ctx, WRAM_START + 0x00D0, 0x0F)
game_flags = await snes_read(ctx, DKC2_GAME_FLAGS, 0x60)
misc_flags = await snes_read(ctx, DKC2_MISC_FLAGS, 0x80)

if general_data is None or game_flags is None or misc_flags is None or setting_data is None:
return


loaded_save = int.from_bytes(general_data[0x05:0x07], "little")
if loaded_save == 0:
return

validation = int.from_bytes(await snes_read(ctx, DKC2_INIT_FLAG, 0x2), "little")
if validation != 0xDEAD:
snes_logger.info(f'ROM not properly validated.')
self.game_state = False
return

from .Levels import location_id_to_level_id
from worlds import AutoWorldRegister

new_checks = []
current_level = int.from_bytes(await snes_read(ctx, DKC2_CURRENT_LEVEL, 0x01))
game_flags = await snes_read(ctx, DKC2_GAME_FLAGS, 0x60)
misc_flags = await snes_read(ctx, DKC2_MISC_FLAGS, 0x80)
kong_flags = misc_flags[0x30]
stage_flags = game_flags[0x40:0x60]
bonus_flags = list(game_flags[0x00:0x20])
Expand Down Expand Up @@ -132,7 +147,32 @@ async def game_watcher(self, ctx):
level_data = int.from_bytes(bonus_flags[level_offset:level_offset+2], "little")
if level_data & level_bit:
new_checks.append(loc_id)


# Check goals
goal_check = 0
selected_goal = setting_data[0x01]

level_num = 0x61
level_offset = (level_num >> 3) & 0x1E
level_bit = 1 << (level_num & 0x0F)
level_data = int.from_bytes(bonus_flags[level_offset:level_offset+2], "little")
if level_data & level_bit:
goal_check |= 1

level_num = 0x6B
level_offset = (level_num >> 3) & 0x1E
level_bit = 1 << (level_num & 0x0F)
level_data = int.from_bytes(dk_coin_flags[level_offset:level_offset+2], "little")
if level_data & level_bit:
goal_check |= 2

if goal_check & selected_goal == selected_goal:
if not ctx.finished_game:
await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
ctx.finished_game = True
return

# Receive items
rom = await snes_read(ctx, DKC2_ROMHASH_START, ROMHASH_SIZE)
if rom != ctx.rom:
ctx.rom = None
Expand All @@ -151,7 +191,8 @@ async def game_watcher(self, ctx):
# Add a small failsafe in case we get a None. Other SNI games do this...
return

recv_index = recv_count[0] | (recv_count[1] << 8)
from .Rom import unlock_data, currency_data, trap_data
recv_index = int.from_bytes(recv_count, "little")

if recv_index < len(ctx.items_received):
item = ctx.items_received[recv_index]
Expand All @@ -162,11 +203,67 @@ async def game_watcher(self, ctx):
color(ctx.player_names[item.player], 'yellow'),
ctx.location_names.lookup_in_slot(item.location, item.player), recv_index, len(ctx.items_received)))

sfx = 0
# Give kongs
if item.item in {STARTING_ID + 0x0010, STARTING_ID + 0x0011}:
offset = unlock_data[item.item][0]
sfx = unlock_data[item.item][1]
count = await snes_read(ctx, DKC2_SRAM + offset, 0x02)
if count is None:
recv_index -= 1
return
count = int.from_bytes(count, "little")
if item.item == STARTING_ID + 0x0010:
count |= 0x0001
else:
count |= 0x0002
count &= 0x00FF
snes_buffered_write(ctx, DKC2_SRAM + offset, bytes([count]))

# Give items
elif item.item in unlock_data:
offset = unlock_data[item.item][0]
sfx = unlock_data[item.item][1]
snes_buffered_write(ctx, DKC2_SRAM + offset, bytearray([0x01]))

# Give currency-like items
elif item.item in currency_data:
offset = currency_data[item.item][0]
if offset & 0x8000 == 0x8000:
addr = DKC2_SRAM + (offset & 0x7FFF)
else:
addr = WRAM_START + offset
sfx = currency_data[item.item][1]
currency = await snes_read(ctx, addr, 0x02)
if currency is None:
recv_index -= 1
return
currency = int.from_bytes(currency, "little") + 1
currency &= 0x00FF
snes_buffered_write(ctx, addr, bytes([currency]))

# Give traps
elif item.item in trap_data:
print ("wea")
offset = trap_data[item.item][0]
sfx = trap_data[item.item][1]
traps = await snes_read(ctx, DKC2_SRAM + offset, 0x02)
if traps is None:
recv_index -= 1
return
traps = int.from_bytes(traps, "little") + 1
traps &= 0x00FF
snes_buffered_write(ctx, DKC2_SRAM + offset, bytes([traps]))

if sfx:
snes_buffered_write(ctx, DKC2_SOUND_BUFFER, bytearray([sfx, 0x05]))
snes_buffered_write(ctx, DKC2_EFFECT_BUFFER + 0x05, bytearray([sfx]))
snes_buffered_write(ctx, DKC2_SPC_INDEX, bytearray([0x00]))
snes_buffered_write(ctx, DKC2_SPC_NEXT_INDEX, bytearray([0x00]))

snes_buffered_write(ctx, DKC2_RECV_INDEX, bytes([recv_index]))

await snes_flush_writes(ctx)

if item.item in {0x0}:
pass

# Handle collected locations
i = 0
Expand Down
60 changes: 59 additions & 1 deletion worlds/dkc2/Items.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@ class DKC2Item(Item):
ItemName.the_flying_krock: ItemData(STARTING_ID + 0x0007, True),
}

mcguffin_table = {
ItemName.lost_world_rock: ItemData(STARTING_ID + 0x0008, True),
ItemName.dk_coin: ItemData(STARTING_ID + 0x0009, False),
ItemName.kremkoins: ItemData(STARTING_ID + 0x000A, False),
}

lost_world_table = {
ItemName.lost_world_cauldron: ItemData(STARTING_ID + 0x000B, True),
ItemName.lost_world_quay: ItemData(STARTING_ID + 0x000C, True),
ItemName.lost_world_kremland: ItemData(STARTING_ID + 0x000D, True),
ItemName.lost_world_gulch: ItemData(STARTING_ID + 0x000E, True),
ItemName.lost_world_keep: ItemData(STARTING_ID + 0x000F, True),
}

progression_table = {
ItemName.diddy: ItemData(STARTING_ID + 0x0010, True),
ItemName.dixie: ItemData(STARTING_ID + 0x0011, True),
Expand Down Expand Up @@ -60,19 +74,63 @@ class DKC2Item(Item):
ItemName.red_balloon: ItemData(STARTING_ID + 0x0031, False),
}

trap_table = {
ItemName.freeze_trap: ItemData(STARTING_ID + 0x0040, False, True),
ItemName.reverse_trap: ItemData(STARTING_ID + 0x0041, False, True),
}

item_groups = {
"Worlds": {
ItemName.gangplank_galleon,
ItemName.crocodile_cauldron,
ItemName.krem_quay,
ItemName.krazy_kremland,
ItemName.gloomy_gulch,
ItemName.krools_keep,
ItemName.the_flying_krock,
},
"Lost World": {
ItemName.lost_world_cauldron,
ItemName.lost_world_quay,
ItemName.lost_world_kremland,
ItemName.lost_world_gulch,
ItemName.lost_world_keep,
},
"Abilities": {
ItemName.carry,
ItemName.climb,
ItemName.cling,
ItemName.cartwheel,
ItemName.swim,
ItemName.team_attack,
ItemName.helicopter_spin,
},
"Animals": {
ItemName.rambi,
ItemName.squawks,
ItemName.enguarde,
ItemName.squitter,
ItemName.rattly,
ItemName.clapper,
ItemName.glimmer,
ItemName.skull_kart,
},
"Animal Buddies": {
"Barrels": {
ItemName.barrel_kannons,
ItemName.barrel_exclamation,
ItemName.barrel_kong,
ItemName.barrel_warp,
ItemName.barrel_control,
}
}

item_table = {
**event_table,
**mcguffin_table,
**worlds_table,
**lost_world_table,
**progression_table,
**trap_table,
**junk_table,
}

Expand Down
11 changes: 6 additions & 5 deletions worlds/dkc2/Levels.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
LocationName.clappers_cavern_clear: [0x00, 0x8F],
LocationName.chain_link_chamber_clear: [0x00, 0x6D],
LocationName.toxic_tower_clear: [0x00, 0x6E],
LocationName.stronghold_showdown_clear: [0x00, 0xB9],
LocationName.stronghold_showdown_clear: [0x03, 0xB9],
LocationName.screechs_sprint_clear: [0x00, 0x2F],
LocationName.jungle_jinx_clear: [0x00, 0x99],
LocationName.black_ice_battle_clear: [0x00, 0x96],
Expand Down Expand Up @@ -202,7 +202,7 @@
}

level_list = [
[RegionName.pirate_panic_level, 0x03],
#[RegionName.pirate_panic_level, 0x03],
[RegionName.mainbrace_mayhem_level, 0x0C],
[RegionName.gangplank_galley_level, 0x04],
[RegionName.lockjaws_locker_level, 0x15],
Expand Down Expand Up @@ -304,7 +304,7 @@
}

level_rom_data = {
#RegionName.pirate_panic_level: [0x34DD6F+9, 0x34DD7E],
RegionName.pirate_panic_level: [0x34DD6F+9, 0x34DD7E],
RegionName.mainbrace_mayhem_level: [0x34DD9C+9, 0x34DDB3],
RegionName.gangplank_galley_level: [0x34D24D+9, 0x34D260],
RegionName.lockjaws_locker_level: [0x34D2BA+9, 0x34D2CD],
Expand Down Expand Up @@ -360,16 +360,17 @@ def generate_level_list(world: World):
if world.options.shuffle_levels:
world.random.shuffle(shuffled_level_list)
world.random.shuffle(shuffled_boss_list)
#shuffled_level_list.insert(0, [RegionName.pirate_panic_level, 0x03])

for map_level, level in level_connections.items():
selected_level = shuffled_level_list.pop(0)
world.level_connections[map_level] = selected_level[0]
world.rom_connections[level] = selected_level[1]
world.rom_connections[level] = selected_level

for map_boss, boss in boss_connections.items():
selected_boss = shuffled_boss_list.pop(0)
world.level_connections[map_boss] = selected_boss[0]
world.rom_connections[boss] = selected_boss[1]
world.rom_connections[boss] = selected_boss

# Place locked levels
world.level_connections[RegionName.pirate_panic_map] = RegionName.pirate_panic_level
4 changes: 2 additions & 2 deletions worlds/dkc2/Locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ def __init__(self, player: int, name: str = '', address: int = None, parent=None
LocationName.toxic_tower_clear: STARTING_ID + 0x0026,
LocationName.stronghold_showdown_clear: STARTING_ID + 0x0027,
LocationName.screechs_sprint_clear: STARTING_ID + 0x0028,
LocationName.k_rool_duel_clear: STARTING_ID + 0x0029,
#LocationName.k_rool_duel_clear: STARTING_ID + 0x0029,
LocationName.jungle_jinx_clear: STARTING_ID + 0x002A,
LocationName.black_ice_battle_clear: STARTING_ID + 0x002B,
LocationName.klobber_karnage_clear: STARTING_ID + 0x002C,
LocationName.fiery_furnace_clear: STARTING_ID + 0x002D,
LocationName.animal_antics_clear: STARTING_ID + 0x002E,
LocationName.krocodile_core_clear: STARTING_ID + 0x002F,
#LocationName.krocodile_core_clear: STARTING_ID + 0x002F,
}

stage_kong = {
Expand Down
2 changes: 2 additions & 0 deletions worlds/dkc2/Names/EventName.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
k_rool_duel_clear = "Defeated K. Rool at The Flying Krock"
krocodile_core_clear = "Defeated K. Rool at Krocodile Kore"
Loading

0 comments on commit 028ebea

Please sign in to comment.