Initial work on new pottery modes

This commit is contained in:
aerinon
2022-04-19 13:56:39 -06:00
parent c560e0d275
commit 26e8e23fce
19 changed files with 1049 additions and 362 deletions

View File

@@ -16,6 +16,7 @@ from EntranceShuffle import door_addresses, indirect_connections
from Utils import int16_as_bytes from Utils import int16_as_bytes
from Tables import normal_offset_table, spiral_offset_table, multiply_lookup, divisor_lookup from Tables import normal_offset_table, spiral_offset_table, multiply_lookup, divisor_lookup
from RoomData import Room from RoomData import Room
from source.dungeon.RoomObject import RoomObject
class World(object): class World(object):
@@ -139,6 +140,8 @@ class World(object):
set_player_attr('pot_contents', None) set_player_attr('pot_contents', None)
set_player_attr('pseudoboots', False) set_player_attr('pseudoboots', False)
set_player_attr('collection_rate', False) set_player_attr('collection_rate', False)
set_player_attr('colorizepots', False)
set_player_attr('pot_pool', {})
set_player_attr('shopsanity', False) set_player_attr('shopsanity', False)
set_player_attr('mixed_travel', 'prevent') set_player_attr('mixed_travel', 'prevent')
@@ -2709,7 +2712,7 @@ class PotFlags(FastEnum):
class Pot(object): class Pot(object):
def __init__(self, x, y, item, room, flags = PotFlags.Normal): def __init__(self, x, y, item, room, flags=PotFlags.Normal, obj=None):
self.x = x self.x = x
self.y = y self.y = y
self.item = item self.item = item
@@ -2717,9 +2720,12 @@ class Pot(object):
self.flags = flags self.flags = flags
self.indicator = None # 0x80 for standing item, 0xC0 multiworld item self.indicator = None # 0x80 for standing item, 0xC0 multiworld item
self.standing_item_code = None # standing item code if nay self.standing_item_code = None # standing item code if nay
self.obj_ref = obj
self.location = None # location back ref
def copy(self): def copy(self):
return Pot(self.x, self.y, self.item, self.room, self.flags) obj_ref = RoomObject(self.obj_ref.address, self.obj_ref.data) if self.obj_ref else None
return Pot(self.x, self.y, self.item, self.room, self.flags, obj_ref)
def pot_data(self): def pot_data(self):
high_byte = self.y high_byte = self.y
@@ -2730,6 +2736,12 @@ class Pot(object):
item = self.item if not self.indicator else self.standing_item_code item = self.item if not self.indicator else self.standing_item_code
return [self.x, high_byte, item] return [self.x, high_byte, item]
def __eq__(self, other):
return self.x == other.x and self.y == other.y and self.room == other.room
def __hash__(self):
return hash((self.x, self.y, self.room))
# byte 0: DDDE EEEE (DR, ER) # byte 0: DDDE EEEE (DR, ER)
dr_mode = {"basic": 1, "crossed": 2, "vanilla": 0} dr_mode = {"basic": 1, "crossed": 2, "vanilla": 0}
@@ -2753,7 +2765,8 @@ mixed_travel_mode = {"prevent": 0, "allow": 1, "force": 2}
# new byte 4: ?DDD PPPP (unused, drop, pottery) # new byte 4: ?DDD PPPP (unused, drop, pottery)
# dropshuffle reserves 2 bits, pottery needs 2 but reserves 2 for future modes) # dropshuffle reserves 2 bits, pottery needs 2 but reserves 2 for future modes)
pottery_mode = {"none": 0, "shuffle": 1, "keys": 2, "lottery": 3, 'dungeon': 4, 'cave': 5} pottery_mode = {'none': 0, 'keys': 2, 'lottery': 3, 'dungeon': 4, 'cave': 5, 'cavekeys': 6, 'reduced': 7,
'clustered': 8, 'nonempty': 9}
# byte 5: CCCC CTTX (crystals gt, ctr2, experimental) # byte 5: CCCC CTTX (crystals gt, ctr2, experimental)
counter_mode = {"default": 0, "off": 1, "on": 2, "pickup": 3} counter_mode = {"default": 0, "off": 1, "on": 2, "pickup": 3}

3
CLI.py
View File

@@ -108,7 +108,7 @@ def parse_cli(argv, no_defaults=False):
'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor', 'ow_palettes', 'uw_palettes', 'sprite', 'disablemusic', 'quickswap', 'fastmenu', 'heartcolor',
'heartbeep', 'remote_items', 'shopsanity', 'dropshuffle', 'pottery', 'keydropshuffle', 'heartbeep', 'remote_items', 'shopsanity', 'dropshuffle', 'pottery', 'keydropshuffle',
'mixed_travel', 'standardize_palettes', 'code', 'reduce_flashing', 'shuffle_sfx', 'mixed_travel', 'standardize_palettes', 'code', 'reduce_flashing', 'shuffle_sfx',
'msu_resume', 'collection_rate']: 'msu_resume', 'collection_rate', 'colorizepots']:
value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name) value = getattr(defaults, name) if getattr(playerargs, name) is None else getattr(playerargs, name)
if player == 1: if player == 1:
setattr(ret, name, {1: value}) setattr(ret, name, {1: value})
@@ -165,6 +165,7 @@ def parse_settings():
'keydropshuffle': False, 'keydropshuffle': False,
'dropshuffle': False, 'dropshuffle': False,
'pottery': 'none', 'pottery': 'none',
'colorizepots': False,
'shufflepots': False, 'shufflepots': False,
"mapshuffle": False, "mapshuffle": False,
"compassshuffle": False, "compassshuffle": False,

View File

@@ -764,7 +764,7 @@ def add_pot_contents(world, player):
for super_tile, pot_list in vanilla_pots.items(): for super_tile, pot_list in vanilla_pots.items():
for pot in pot_list: for pot in pot_list:
if pot.item not in [PotItem.Hole, PotItem.Key, PotItem.Switch]: if pot.item not in [PotItem.Hole, PotItem.Key, PotItem.Switch]:
if valid_pot_location(pot, world, player): if valid_pot_location(pot, world.pot_pool[player], world, player):
world.itempool.append(ItemFactory(pot_items[pot.item], player)) world.itempool.append(ItemFactory(pot_items[pot.item], player))

View File

@@ -110,6 +110,7 @@ def main(args, seed=None, fish=None):
world.overworld_map = args.overworld_map.copy() world.overworld_map = args.overworld_map.copy()
world.restrict_boss_items = args.restrict_boss_items.copy() world.restrict_boss_items = args.restrict_boss_items.copy()
world.collection_rate = args.collection_rate.copy() world.collection_rate = args.collection_rate.copy()
world.colorizepots = args.colorizepots.copy()
world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)} world.rom_seeds = {player: random.randint(0, 999999999) for player in range(1, world.players + 1)}
@@ -160,7 +161,7 @@ def main(args, seed=None, fish=None):
logger.info(world.fish.translate("cli", "cli", "shuffling.pots")) logger.info(world.fish.translate("cli", "cli", "shuffling.pots"))
for player in range(1, world.players + 1): for player in range(1, world.players + 1):
if world.potshuffle[player]: if world.potshuffle[player]:
if world.pottery[player] not in ['lottery', 'dungeon']: if world.pottery[player] in ['none', 'cave', 'keys', 'cavekeys']:
shuffle_pots(world, player) shuffle_pots(world, player)
else: else:
shuffle_pot_switches(world, player) shuffle_pot_switches(world, player)

View File

@@ -180,6 +180,7 @@ def roll_settings(weights):
ret.shopsanity = get_choice('shopsanity') == 'on' ret.shopsanity = get_choice('shopsanity') == 'on'
ret.dropshuffle = get_choice('dropshuffle') == 'on' ret.dropshuffle = get_choice('dropshuffle') == 'on'
ret.pottery = get_choice('pottery') if 'pottery' in weights else 'none' ret.pottery = get_choice('pottery') if 'pottery' in weights else 'none'
ret.colorizepots = get_choice('colorizepots') == 'on'
ret.shufflepots = get_choice('pot_shuffle') == 'on' ret.shufflepots = get_choice('pot_shuffle') == 'on'
ret.mixed_travel = get_choice('mixed_travel') if 'mixed_travel' in weights else 'prevent' ret.mixed_travel = get_choice('mixed_travel') if 'mixed_travel' in weights else 'prevent'
ret.standardize_palettes = get_choice('standardize_palettes') if 'standardize_palettes' in weights else 'standardize' ret.standardize_palettes = get_choice('standardize_palettes') if 'standardize_palettes' in weights else 'standardize'

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
import collections import collections
from Items import ItemFactory from Items import ItemFactory
from BaseClasses import Region, Location, Entrance, RegionType, Shop, ShopType, LocationType, PotItem, PotFlags from BaseClasses import Region, Location, Entrance, RegionType, Shop, ShopType, LocationType, PotItem, PotFlags
from PotShuffle import key_drop_data, vanilla_pots, PotSecretTable from PotShuffle import key_drop_data, vanilla_pots, choose_pots, PotSecretTable
def create_regions(world, player): def create_regions(world, player):
@@ -1007,6 +1007,7 @@ def adjust_locations(world, player):
pot = pot.copy() pot = pot.copy()
loc.address = pot_address(pot_index, datum[1]) loc.address = pot_address(pot_index, datum[1])
loc.pot = pot loc.pot = pot
pot.location = loc
if (not world.dropshuffle[player] and drop_location)\ if (not world.dropshuffle[player] and drop_location)\
or (not drop_location and world.pottery[player] in ['none', 'cave']): or (not drop_location and world.pottery[player] in ['none', 'cave']):
loc.skip = True loc.skip = True
@@ -1023,6 +1024,7 @@ def adjust_locations(world, player):
dungeon.small_keys.append(key_item) dungeon.small_keys.append(key_item)
elif key_item.bigkey: elif key_item.bigkey:
dungeon.big_key = key_item dungeon.big_key = key_item
world.pot_pool[player] = choose_pots(world, player)
for super_tile, pot_list in vanilla_pots.items(): for super_tile, pot_list in vanilla_pots.items():
for pot_index, pot_orig in enumerate(pot_list): for pot_index, pot_orig in enumerate(pot_list):
if pot_orig.item == PotItem.Key: if pot_orig.item == PotItem.Key:
@@ -1032,7 +1034,7 @@ def adjust_locations(world, player):
pot = pot_orig.copy() pot = pot_orig.copy()
world.pot_contents[player].room_map[super_tile].append(pot) world.pot_contents[player].room_map[super_tile].append(pot)
if valid_pot_location(pot, world, player): if valid_pot_location(pot, world.pot_pool[player], world, player):
create_pot_location(pot, pot_index, super_tile, world, player) create_pot_location(pot, pot_index, super_tile, world, player)
if world.shopsanity[player]: if world.shopsanity[player]:
index = 0 index = 0
@@ -1055,12 +1057,16 @@ def adjust_locations(world, player):
location.skip = True location.skip = True
def valid_pot_location(pot, world, player): def valid_pot_location(pot, pot_set, world, player):
if world.pottery[player] == 'lottery': if world.pottery[player] == 'lottery':
return True return True
if world.pottery[player] == 'nonempty' and pot.item != PotItem.Nothing:
return True
if world.pottery[player] in ['reduced', 'clustered'] and pot in pot_set:
return True
if world.pottery[player] == 'dungeon' and world.get_region(pot.room, player).type == RegionType.Dungeon: if world.pottery[player] == 'dungeon' and world.get_region(pot.room, player).type == RegionType.Dungeon:
return True return True
if world.pottery[player] == 'cave' and world.get_region(pot.room, player).type == RegionType.Cave: if world.pottery[player] in ['cave', 'cavekeys'] and world.get_region(pot.room, player).type == RegionType.Cave:
return True return True
return False return False
@@ -1068,7 +1074,7 @@ def valid_pot_location(pot, world, player):
def create_pot_location(pot, pot_index, super_tile, world, player): def create_pot_location(pot, pot_index, super_tile, world, player):
if (pot.item not in [PotItem.Key, PotItem.Hole] if (pot.item not in [PotItem.Key, PotItem.Hole]
and (pot.item != PotItem.Switch or (world.potshuffle[player] and (pot.item != PotItem.Switch or (world.potshuffle[player]
and world.pottery[player] in ['lottery', 'dungeon']))): and world.pottery[player] not in ['none', 'cave', 'keys', 'cavekeys']))):
address = pot_address(pot_index, super_tile) address = pot_address(pot_index, super_tile)
region = pot.room region = pot.room
if world.mode[player] == 'inverted': if world.mode[player] == 'inverted':
@@ -1084,6 +1090,7 @@ def create_pot_location(pot, pot_index, super_tile, world, player):
parent=parent) parent=parent)
world.dynamic_locations.append(pot_location) world.dynamic_locations.append(pot_location)
pot_location.pot = pot pot_location.pot = pot
pot.location = pot_location
pot_location.type = LocationType.Pot pot_location.type = LocationType.Pot
parent.locations.append(pot_location) parent.locations.append(pot_location)

20
Rom.py
View File

@@ -32,10 +32,11 @@ from EntranceShuffle import door_addresses, exit_ids, ow_prize_table
from source.classes.SFX import randomize_sfx from source.classes.SFX import randomize_sfx
from source.item.FillUtil import valid_pot_items from source.item.FillUtil import valid_pot_items
from source.dungeon.RoomList import Room0127
JAP10HASH = '03a63945398191337e896e5771f77173' JAP10HASH = '03a63945398191337e896e5771f77173'
RANDOMIZERBASEHASH = '8d196e8024faebbbbe1304032158ccea' RANDOMIZERBASEHASH = 'eb982135bdfe95a23b9068bd9cac4449'
class JsonRom(object): class JsonRom(object):
@@ -651,9 +652,11 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
rom.write_byte(0x155C9, random.choice([0x11, 0x16])) # Randomize GT music too with map shuffle rom.write_byte(0x155C9, random.choice([0x11, 0x16])) # Randomize GT music too with map shuffle
if world.pot_contents[player]: if world.pot_contents[player]:
colorize_pots = (world.pottery[player] not in ['vanilla', 'lottery']
and (world.colorizepots[player] or world.pottery[player] in ['reduced', 'clustered']))
if world.pot_contents[player].size() > 0x2800: if world.pot_contents[player].size() > 0x2800:
raise Exception('Pot table is too big for current area') raise Exception('Pot table is too big for current area')
world.pot_contents[player].write_pot_data_to_rom(rom) world.pot_contents[player].write_pot_data_to_rom(rom, colorize_pots)
# fix for swamp drains if necessary # fix for swamp drains if necessary
swamp1location = world.get_location('Swamp Palace - Trench 1 Pot Key', player) swamp1location = world.get_location('Swamp Palace - Trench 1 Pot Key', player)
if not swamp1location.pot.indicator: if not swamp1location.pot.indicator:
@@ -893,14 +896,11 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
if world.pottery[player] not in ['none', 'keys']: if world.pottery[player] not in ['none', 'keys']:
# Cuccos should not prevent kill rooms from opening # Cuccos should not prevent kill rooms from opening
rom.write_byte(snes_to_pc(0x0DB457), 0x40) rom.write_byte(snes_to_pc(0x0DB457), 0x40)
if world.pottery[player] in ['none', 'keys']: rom.write_byte(snes_to_pc(0x28AA56), 0 if world.pottery[player] == 'none' else 1)
rom.write_byte(snes_to_pc(0x28AA56), 0) if world.pottery[player] not in ['none']:
elif world.pottery[player] == 'cave': rom.write_bytes(snes_to_pc(0x1F8375), int32_as_bytes(0x2A8000))
rom.write_byte(snes_to_pc(0x28AA56), 1) # make hammer pegs use different tiles
elif world.pottery[player] == 'dungeon': Room0127.write_to_rom(snes_to_pc(0x2A8000), rom)
rom.write_byte(snes_to_pc(0x28AA56), 2)
elif world.pottery[player] == 'lottery':
rom.write_byte(snes_to_pc(0x28AA56), 3)
write_int16(rom, 0x187010, credits_total) # dynamic credits write_int16(rom, 0x187010, credits_total) # dynamic credits
if credits_total != 216: if credits_total != 216:

View File

@@ -721,7 +721,7 @@ def bomb_rules(world, player):
def pot_rules(world, player): def pot_rules(world, player):
if world.pottery[player] in ['lottery', 'cave']: if world.pottery[player] != 'none':
blocks = [l for l in world.get_locations() if l.type == LocationType.Pot and l.pot.flags & PotFlags.Block] blocks = [l for l in world.get_locations() if l.type == LocationType.Pot and l.pot.flags & PotFlags.Block]
for block_pot in blocks: for block_pot in blocks:
add_rule(block_pot, lambda state: state.can_lift_rocks(player)) add_rule(block_pot, lambda state: state.can_lift_rocks(player))
@@ -748,8 +748,6 @@ def pot_rules(world, player):
or state.has('Cape', player) or state.has('Cape', player)
or (state.has('Cane of Byrna', player) or (state.has('Cane of Byrna', player)
and state.world.difficulty_adjustments[player] == 'normal')) and state.world.difficulty_adjustments[player] == 'normal'))
if world.pottery[player] in ['lottery', 'dungeon']:
for l in world.get_region('Ice Hammer Block', player).locations: for l in world.get_region('Ice Hammer Block', player).locations:
if l.type == LocationType.Pot: if l.type == LocationType.Pot:
add_rule(l, lambda state: state.has('Hammer', player) and state.can_lift_rocks(player)) add_rule(l, lambda state: state.has('Hammer', player) and state.can_lift_rocks(player))

View File

@@ -679,9 +679,22 @@ def extract_data_from_jp_rom(rom):
# print() # print()
def check_pots():
from PotShuffle import vanilla_pots
for supertile, pot_list in vanilla_pots.items():
for i,pot in enumerate(pot_list):
if pot.obj_ref:
r = pot.obj_ref
secret_vram = pot.x | (pot.y << 8)
tile_vram = ((r.data[1] & 0xFC) << 5) | ((r.data[0] & 0xFC) >> 1)
if secret_vram != tile_vram:
print(f'{pot.room}#{i+1} secret: {hex(secret_vram)} tile: {hex(tile_vram)}')
if __name__ == '__main__': if __name__ == '__main__':
# make_new_base2current() # make_new_base2current()
# read_entrance_data(old_rom=sys.argv[1]) # read_entrance_data(old_rom=sys.argv[1])
# room_palette_data(old_rom=sys.argv[1]) # room_palette_data(old_rom=sys.argv[1])
# extract_data_from_us_rom(sys.argv[1]) # extract_data_from_us_rom(sys.argv[1])
extract_data_from_jp_rom(sys.argv[1]) # extract_data_from_jp_rom(sys.argv[1])
check_pots()

Binary file not shown.

View File

@@ -78,9 +78,17 @@
"keys", "keys",
"dungeon", "dungeon",
"cave", "cave",
"cavekeys",
"reduced",
"clustered",
"nonempty",
"lottery" "lottery"
] ]
}, },
"colorizepots" : {
"action": "store_true",
"type": "bool"
},
"shufflepots": { "shufflepots": {
"action": "store_true", "action": "store_true",
"type": "bool" "type": "bool"

View File

@@ -258,9 +258,15 @@
"None: No pots are changed", "None: No pots are changed",
"Keys: Key pots are included in the location pool and other items can take their place", "Keys: Key pots are included in the location pool and other items can take their place",
"Cave: Only pots in houses and caves are included in the location pool", "Cave: Only pots in houses and caves are included in the location pool",
"CaveKeys: Both pots in houses and caves and keys pots are included in the location pool",
"Reduced: Same as KeyCaves + 25% of Pots in dungeons (dynamic mode)",
"Clustered: Same as KeyCaves + 50% of Pots in dungeons, chosen by logical group (dynamic mode)",
"NonEmpty: All pots that are not originally empty are included in the location pool",
"Dungeon: Only pots in dungeons are included in the location pool", "Dungeon: Only pots in dungeons are included in the location pool",
"Lottery: All pots are part of the location pool" "Lottery: All pots are part of the location pool"
], ],
"colorizepots": ["All pots chosen to be in location pool by the pottery setting are different.",
"Forced on in dynamic modes. Forced off in lottery"],
"shufflepots": [ "Pots and switches are shuffled on the supertile (legacy potshuffle) (default: %(default)s)"], "shufflepots": [ "Pots and switches are shuffled on the supertile (legacy potshuffle) (default: %(default)s)"],
"mixed_travel": [ "mixed_travel": [
"How to handle potential traversal between dungeon in Crossed door shuffle", "How to handle potential traversal between dungeon in Crossed door shuffle",

View File

@@ -61,8 +61,13 @@
"randomizer.dungeon.pottery.none": "None", "randomizer.dungeon.pottery.none": "None",
"randomizer.dungeon.pottery.keys": "Key Pots", "randomizer.dungeon.pottery.keys": "Key Pots",
"randomizer.dungeon.pottery.cave": "Cave Pots", "randomizer.dungeon.pottery.cave": "Cave Pots",
"randomizer.dungeon.pottery.cavekeys": "Cave+Key Pots",
"randomizer.dungeon.pottery.reduced": "Reduced Dungeon Pots (Dynamic)",
"randomizer.dungeon.pottery.clustered": "Clustered Dungeon Pots (Dynamic)",
"randomizer.dungeon.pottery.nonempty": "Excludes Empty Pots",
"randomizer.dungeon.pottery.dungeon": "Dungeon Pots", "randomizer.dungeon.pottery.dungeon": "Dungeon Pots",
"randomizer.dungeon.pottery.lottery": "Lottery (All Pots and Large Blocks)", "randomizer.dungeon.pottery.lottery": "Lottery (All Pots and Large Blocks)",
"randomizer.dungeon.colorizepots": "Colorize Randomized Pots",
"randomizer.dungeon.dungeondoorshuffle": "Dungeon Door Shuffle", "randomizer.dungeon.dungeondoorshuffle": "Dungeon Door Shuffle",
"randomizer.dungeon.dungeondoorshuffle.vanilla": "Vanilla", "randomizer.dungeon.dungeondoorshuffle.vanilla": "Vanilla",

View File

@@ -30,6 +30,10 @@
"none", "none",
"keys", "keys",
"cave", "cave",
"cavekeys",
"reduced",
"clustered",
"nonempty",
"dungeon", "dungeon",
"lottery" "lottery"
], ],
@@ -37,6 +41,7 @@
"width": 35 "width": 35
} }
}, },
"colorizepots": { "type": "checkbox" },
"dropshuffle": { "type": "checkbox" }, "dropshuffle": { "type": "checkbox" },
"potshuffle": { "type": "checkbox" }, "potshuffle": { "type": "checkbox" },
"experimental": { "type": "checkbox" }, "experimental": { "type": "checkbox" },

View File

@@ -98,6 +98,7 @@ SETTINGSTOPROCESS = {
"keydropshuffle": "keydropshuffle", "keydropshuffle": "keydropshuffle",
"dropshuffle": "dropshuffle", "dropshuffle": "dropshuffle",
"pottery": "pottery", "pottery": "pottery",
"colorizepots": "colorizepots",
"potshuffle": "shufflepots", "potshuffle": "shufflepots",
"experimental": "experimental", "experimental": "experimental",
"dungeon_counters": "dungeon_counters", "dungeon_counters": "dungeon_counters",

View File

@@ -0,0 +1,58 @@
from RoomData import DoorKind, Position
from source.dungeon.RoomObject import RoomObject, DoorObject
class Room:
def __init__(self, layout, layer1, layer2, doors):
self.layout = layout
self.layer1 = layer1
self.layer2 = layer2
self.doors = doors
def write_to_rom(self, address, rom):
rom.write_bytes(address, self.layout)
address += 2
for obj in self.layer1:
rom.write_bytes(address, obj.data)
address += 3
rom.write_bytes(address, [0xFF, 0xFF])
address += 2
for obj in self.layer2:
rom.write_bytes(address, obj.data)
address += 3
rom.write_bytes(address, [0xFF, 0xFF, 0xF0, 0xFF])
address += 4
for door in self.doors:
rom.write_bytes(address, door.get_bytes())
address += 2
rom.write_bytes(address, [0xFF, 0xFF])
return address + 2 # where the data ended
Room0127 = Room([0xE1, 0x00],
[RoomObject(0x0AB600, [0xFE, 0x89, 0x00]),
RoomObject(0x0AB603, [0xA2, 0xA1, 0x61]),
RoomObject(0x0AB606, [0xFE, 0x8E, 0x81]),
RoomObject(0x0AB609, [0xFF, 0x49, 0x02]),
RoomObject(0x0AB60C, [0xD2, 0xA1, 0x62]),
RoomObject(0x0AB60F, [0xFF, 0x4E, 0x83]),
RoomObject(0x0AB612, [0x20, 0xB3, 0xDD]),
RoomObject(0x0AB615, [0x50, 0xB3, 0xDD]),
RoomObject(0x0AB618, [0x33, 0xCB, 0xFA]),
RoomObject(0x0AB61B, [0x3B, 0xCB, 0xFA]),
RoomObject(0x0AB61E, [0x43, 0xCB, 0xFA]),
RoomObject(0x0AB621, [0x4B, 0xCB, 0xFA]),
RoomObject(0x0AB624, [0xBF, 0x94, 0xF9]),
RoomObject(0x0AB627, [0xB3, 0xB3, 0xFA]),
RoomObject(0x0AB62A, [0xCB, 0xB3, 0xFA]),
RoomObject(0x0AB62D, [0xAD, 0xC8, 0xDF]),
RoomObject(0x0AB630, [0xC4, 0xC8, 0xDF]),
RoomObject(0x0AB633, [0xB3, 0xE3, 0xFA]),
RoomObject(0x0AB636, [0xCB, 0xE3, 0xFA]),
RoomObject(0x0AB639, [0x81, 0x93, 0xC0]),
RoomObject(0x0AB63C, [0x81, 0xD2, 0xC0]),
RoomObject(0x0AB63F, [0xE1, 0x93, 0xC0]),
RoomObject(0x0AB642, [0xE1, 0xD2, 0xC0])],
[], [DoorObject(Position.SouthW, DoorKind.CaveEntrance),
DoorObject(Position.SouthE, DoorKind.CaveEntrance)])

View File

@@ -0,0 +1,34 @@
from Utils import snes_to_pc
# Subtype 3 object (0x2xx by jpdasm id - see bank 01)
# B
Normal_Pot = (0xFA, 3, 3)
Shuffled_Pot = (0xFB, 0, 0) # formerly weird pot, or black diagonal thing
class RoomObject:
def __init__(self, address, data):
self.address = address
self.data = data
def change_type(self, new_type):
type_id, datum_a, datum_b = new_type
if 0xF8 <= type_id < 0xFC: # sub type 3
self.data = (self.data[0] & 0xFC) | datum_a, (self.data[1] & 0xFC) | datum_b, type_id
else:
pass # not yet implemented
def write_to_rom(self, rom):
rom.write_bytes(snes_to_pc(self.address), self.data)
class DoorObject:
def __init__(self, pos, kind):
self.pos = pos
self.kind = kind
def get_bytes(self):
return [self.pos.value, self.kind.value]

View File

@@ -70,7 +70,7 @@ def create_item_pool_config(world):
if world.dropshuffle[player]: if world.dropshuffle[player]:
for item, locs in keydrop_vanilla_mapping.items(): for item, locs in keydrop_vanilla_mapping.items():
config.static_placement[player][item].extend(locs) config.static_placement[player][item].extend(locs)
if world.pottery[player] != 'none': if world.pottery[player] not in ['none', 'cave']:
for item, locs in potkeys_vanilla_mapping.items(): for item, locs in potkeys_vanilla_mapping.items():
config.static_placement[player][item].extend(locs) config.static_placement[player][item].extend(locs)
if world.pottery[player] in ['lottery', 'cave', 'dungeon']: if world.pottery[player] in ['lottery', 'cave', 'dungeon']: