Skip to content

Commit

Permalink
SMW: v1.1 Content Update (ArchipelagoMW#1344)
Browse files Browse the repository at this point in the history
* Make Bowser unkillable on Egg Hunt

* Increment Data Package version

Changed a location name.

* Baseline for Bowser Rooms shuffling

* Add boss shuffle

* Remove extra space

* Overworld Palette Shuffle

* Fix Literature Trap typo

* Handle Queuing traps and new Timer Trap

* Fix trap name and actually create them

* Early Climb and Overworld Speed

* Add correct tooltip for Early Climb

* Tooltip text edit

* Address unconnected regions

* Add option to fully exclude Special Zone levels from the seed

* Fix Chocolate Island 4 Dragon Coins logic

* Update worlds/smw/Client.py to use `getattr`
  • Loading branch information
PoryGone authored Jan 30, 2023
1 parent 428344b commit dc2aa5f
Show file tree
Hide file tree
Showing 11 changed files with 423 additions and 56 deletions.
15 changes: 15 additions & 0 deletions worlds/smw/Aesthetics.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,15 @@
0xFFF45A: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07], # Castle
}

valid_ow_palettes = {
0x2D1E: [0x00, 0x01, 0x03], # Main OW
0x2D1F: [0x00, 0x03, 0x04], # Yoshi's Island
0x2D20: [0x00, 0x01, 0x03, 0x04], # Vanilla Dome
0x2D21: [0x00, 0x02, 0x03, 0x04], # Forest of Illusion
0x2D22: [0x00, 0x01, 0x03, 0x04], # Valley of Bowser
0x2D24: [0x00, 0x02, 0x03], # Star Road
}

def generate_shuffled_level_music(world, player):
shuffled_level_music = level_music_value_data.copy()

Expand All @@ -158,6 +167,12 @@ def generate_shuffled_ow_music(world, player):

return shuffled_ow_music

def generate_shuffled_ow_palettes(rom, world, player):
if world.overworld_palette_shuffle[player]:
for address, valid_palettes in valid_ow_palettes.items():
chosen_palette = world.random.choice(valid_palettes)
rom.write_byte(address, chosen_palette)

def generate_shuffled_header_data(rom, world, player):
if world.music_shuffle[player] != "full" and not world.foreground_palette_shuffle[player] and not world.background_palette_shuffle[player]:
return
Expand Down
82 changes: 78 additions & 4 deletions worlds/smw/Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,74 @@ async def handle_message_queue(self, ctx):

await snes_flush_writes(ctx)

return

def add_trap_to_queue(self, trap_item, trap_msg):
self.trap_queue = getattr(self, "trap_queue", [])

self.trap_queue.append((trap_item, trap_msg))


async def handle_trap_queue(self, ctx):
from SNIClient import snes_buffered_write, snes_flush_writes, snes_read

if not hasattr(self, "trap_queue") or len(self.trap_queue) == 0:
return

game_state = await snes_read(ctx, SMW_GAME_STATE_ADDR, 0x1)
if game_state[0] != 0x14:
return

mario_state = await snes_read(ctx, SMW_MARIO_STATE_ADDR, 0x1)
if mario_state[0] != 0x00:
return

pause_state = await snes_read(ctx, SMW_PAUSE_ADDR, 0x1)
if pause_state[0] != 0x00:
return

next_trap, message = self.trap_queue.pop(0)

from worlds.smw.Rom import trap_rom_data
if next_trap.item in trap_rom_data:
trap_active = await snes_read(ctx, WRAM_START + trap_rom_data[next_trap.item][0], 0x3)

if next_trap.item == 0xBC0016:
# Timer Trap
if trap_active[0] == 0 or (trap_active[0] == 1 and trap_active[1] == 0 and trap_active[2] == 0):
# Trap already active
self.add_trap_to_queue(next_trap, message)
return
else:
snes_buffered_write(ctx, WRAM_START + trap_rom_data[next_trap.item][0], bytes([0x01]))
snes_buffered_write(ctx, WRAM_START + trap_rom_data[next_trap.item][0] + 1, bytes([0x00]))
snes_buffered_write(ctx, WRAM_START + trap_rom_data[next_trap.item][0] + 2, bytes([0x00]))
else:
if trap_active[0] > 0:
# Trap already active
self.add_trap_to_queue(next_trap, message)
return
else:
verify_game_state = await snes_read(ctx, SMW_GAME_STATE_ADDR, 0x1)
if verify_game_state[0] == 0x14 and len(trap_rom_data[next_trap.item]) > 2:
snes_buffered_write(ctx, SMW_SFX_ADDR, bytes([trap_rom_data[next_trap.item][2]]))

new_item_count = trap_rom_data[next_trap.item][1]
snes_buffered_write(ctx, WRAM_START + trap_rom_data[next_trap.item][0], bytes([new_item_count]))

current_level = await snes_read(ctx, SMW_CURRENT_LEVEL_ADDR, 0x1)
if current_level[0] in SMW_BAD_TEXT_BOX_LEVELS:
return

boss_state = await snes_read(ctx, SMW_BOSS_STATE_ADDR, 0x1)
if boss_state[0] in SMW_BOSS_STATES:
return

active_boss = await snes_read(ctx, SMW_ACTIVE_BOSS_ADDR, 0x1)
if active_boss[0] != 0x00:
return

if ctx.receive_option == 1 or (ctx.receive_option == 2 and ((next_trap.flags & 1) != 0)):
self.add_message_to_queue(message)


async def game_watcher(self, ctx):
Expand Down Expand Up @@ -229,13 +296,14 @@ async def game_watcher(self, ctx):
await snes_flush_writes(ctx)

await self.handle_message_queue(ctx)
await self.handle_trap_queue(ctx)

new_checks = []
event_data = await snes_read(ctx, SMW_EVENT_ROM_DATA, 0x60)
progress_data = bytearray(await snes_read(ctx, SMW_PROGRESS_DATA, 0x0F))
dragon_coins_data = bytearray(await snes_read(ctx, SMW_DRAGON_COINS_DATA, 0x0C))
dragon_coins_active = await snes_read(ctx, SMW_DRAGON_COINS_ACTIVE_ADDR, 0x1)
from worlds.smw.Rom import item_rom_data, ability_rom_data
from worlds.smw.Rom import item_rom_data, ability_rom_data, trap_rom_data
from worlds.smw.Levels import location_id_to_level_id, level_info_dict
from worlds import AutoWorldRegister
for loc_name, level_data in location_id_to_level_id.items():
Expand Down Expand Up @@ -307,7 +375,7 @@ async def game_watcher(self, ctx):
ctx.location_names[item.location], recv_index, len(ctx.items_received)))

if ctx.receive_option == 1 or (ctx.receive_option == 2 and ((item.flags & 1) != 0)):
if item.item != 0xBC0012:
if item.item != 0xBC0012 and item.item not in trap_rom_data:
# Don't send messages for Boss Tokens
item_name = ctx.item_names[item.item]
player_name = ctx.player_names[item.player]
Expand All @@ -316,7 +384,13 @@ async def game_watcher(self, ctx):
self.add_message_to_queue(receive_message)

snes_buffered_write(ctx, SMW_RECV_PROGRESS_ADDR, bytes([recv_index]))
if item.item in item_rom_data:
if item.item in trap_rom_data:
item_name = ctx.item_names[item.item]
player_name = ctx.player_names[item.player]

receive_message = generate_received_text(item_name, player_name)
self.add_trap_to_queue(item, receive_message)
elif item.item in item_rom_data:
item_count = await snes_read(ctx, WRAM_START + item_rom_data[item.item][0], 0x1)
increment = item_rom_data[item.item][1]

Expand Down
1 change: 1 addition & 0 deletions worlds/smw/Items.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class SMWItem(Item):
ItemName.ice_trap: ItemData(0xBC0013, False, True),
ItemName.stun_trap: ItemData(0xBC0014, False, True),
ItemName.literature_trap: ItemData(0xBC0015, False, True),
ItemName.timer_trap: ItemData(0xBC0016, False, True),
}

event_table = {
Expand Down
99 changes: 91 additions & 8 deletions worlds/smw/Levels.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,80 @@

from .Names import LocationName


class BowserRoom():
name: str
exitAddress: int
roomID: int

def __init__(self, name: str, exitAddress: int, roomID: int):
self.name = name
self.exitAddress = exitAddress
self.roomID = roomID

full_bowser_rooms = [
BowserRoom("Hallway 1 - Door 1", 0x3A680, 0x0D),
BowserRoom("Hallway 1 - Door 2", 0x3A684, 0x0D),
BowserRoom("Hallway 1 - Door 3", 0x3A688, 0x0D),
BowserRoom("Hallway 1 - Door 4", 0x3A68C, 0x0D),
BowserRoom("Hallway 2 - Door 1", 0x3A8CB, 0xD0),
BowserRoom("Hallway 2 - Door 2", 0x3A8CF, 0xD0),
BowserRoom("Hallway 2 - Door 3", 0x3A8D3, 0xD0),
BowserRoom("Hallway 2 - Door 4", 0x3A8D7, 0xD0),

BowserRoom("Room 1", 0x3A705, 0xD4),
BowserRoom("Room 2", 0x3A763, 0xD3),
BowserRoom("Room 3", 0x3A800, 0xD2),
BowserRoom("Room 4", 0x3A83D, 0xD1),
BowserRoom("Room 5", 0x3A932, 0xCF),
BowserRoom("Room 6", 0x3A9E1, 0xCE),
BowserRoom("Room 7", 0x3AA75, 0xCD),
BowserRoom("Room 8", 0x3AAC7, 0xCC),
]

standard_bowser_rooms = [
BowserRoom("Room 1", 0x3A705, 0xD4),
BowserRoom("Room 2", 0x3A763, 0xD3),
BowserRoom("Room 3", 0x3A800, 0xD2),
BowserRoom("Room 4", 0x3A83D, 0xD1),
BowserRoom("Room 5", 0x3A932, 0xCF),
BowserRoom("Room 6", 0x3A9E1, 0xCE),
BowserRoom("Room 7", 0x3AA75, 0xCD),
BowserRoom("Room 8", 0x3AAC7, 0xCC),
]


class BossRoom():
name: str
exitAddress: int
exitAddressAlt: int
roomID: int

def __init__(self, name: str, exitAddress: int, roomID: int, exitAddressAlt=None):
self.name = name
self.exitAddress = exitAddress
self.roomID = roomID
self.exitAddressAlt = exitAddressAlt


submap_boss_rooms = [
BossRoom("#1 Lemmy Koopa", 0x311E3, 0xF6), # Submap 0x1F6
BossRoom("#3 Lemmy Koopa", 0x33749, 0xF2), # Submap 0x1F2
BossRoom("Valley Reznor", 0x3A132, 0xDE), # Submap 0x1DE
BossRoom("#7 Larry Koopa", 0x3A026, 0xEB), # Submap 0x1EB
]

ow_boss_rooms = [
BossRoom("#2 Morton Koopa Jr.", 0x3209B, 0xE5), # OW 0x0E5
BossRoom("Vanilla Reznor", 0x33EAB, 0xDF), # OW 0x0DF
BossRoom("#4 Ludwig von Koopa", 0x346EA, 0xD9), # OW 0x0D9
BossRoom("Forest Reznor", 0x3643E, 0xD5, 0x36442), # OW 0x0D5
BossRoom("#5 Roy Koopa", 0x35ABC, 0xCC), # OW 0x0CC
BossRoom("Chocolate Reznor", 0x3705B, 0xE2), # OW 0x0E2
BossRoom("#6 Wendy O. Koopa", 0x38BB5, 0xD3), # OW 0x0D3
]


class SMWPath():
thisEndDirection: int
otherLevelID: int
Expand Down Expand Up @@ -203,6 +277,9 @@ def __init__(self, levelName: str, levelIDAddress: int, eventIDValue: int, exit1
0x3B,
0x3A,
0x37,
]

special_zone_levels = [
0x4E,
0x4F,
0x50,
Expand Down Expand Up @@ -443,6 +520,7 @@ def generate_level_list(world, player):
world.random.shuffle(easy_single_levels_copy)
hard_single_levels_copy = hard_single_levels.copy()
world.random.shuffle(hard_single_levels_copy)
special_zone_levels_copy = special_zone_levels.copy()
easy_double_levels_copy = easy_double_levels.copy()
world.random.shuffle(easy_double_levels_copy)
hard_double_levels_copy = hard_double_levels.copy()
Expand Down Expand Up @@ -474,6 +552,8 @@ def generate_level_list(world, player):
shuffled_level_list.append(0x16)

single_levels_copy = (easy_single_levels_copy.copy() + hard_single_levels_copy.copy())
if not world.exclude_special_zone[player]:
single_levels_copy.extend(special_zone_levels_copy)
world.random.shuffle(single_levels_copy)

castle_fortress_levels_copy = (easy_castle_fortress_levels_copy.copy() + hard_castle_fortress_levels_copy.copy())
Expand Down Expand Up @@ -566,14 +646,17 @@ def generate_level_list(world, player):

# Special Zone
shuffled_level_list.append(0x4D)
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
if not world.exclude_special_zone[player]:
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
shuffled_level_list.append(single_levels_copy.pop(0))
else:
shuffled_level_list.extend(special_zone_levels_copy)
shuffled_level_list.append(0x48)

return shuffled_level_list
22 changes: 22 additions & 0 deletions worlds/smw/Locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,28 @@ def __init__(self, player: int, name: str = '', address: int = None, parent=None
**yoshi_house_location_table,
}

special_zone_level_names = [
LocationName.special_zone_1_exit_1,
LocationName.special_zone_2_exit_1,
LocationName.special_zone_3_exit_1,
LocationName.special_zone_4_exit_1,
LocationName.special_zone_5_exit_1,
LocationName.special_zone_6_exit_1,
LocationName.special_zone_7_exit_1,
LocationName.special_zone_8_exit_1,
]

special_zone_dragon_coin_names = [
LocationName.special_zone_1_dragon,
LocationName.special_zone_2_dragon,
LocationName.special_zone_3_dragon,
LocationName.special_zone_4_dragon,
LocationName.special_zone_5_dragon,
LocationName.special_zone_6_dragon,
LocationName.special_zone_7_dragon,
LocationName.special_zone_8_dragon,
]

location_table = {}


Expand Down
1 change: 1 addition & 0 deletions worlds/smw/Names/ItemName.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
ice_trap = "Ice Trap"
stun_trap = "Stun Trap"
literature_trap = "Literature Trap"
timer_trap = "Timer Trap"

# Other Definitions
victory = "The Princess"
Expand Down
Loading

0 comments on commit dc2aa5f

Please sign in to comment.