Initial work on new pottery modes
This commit is contained in:
@@ -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
3
CLI.py
@@ -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,
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
3
Main.py
3
Main.py
@@ -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)
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
1208
PotShuffle.py
1208
PotShuffle.py
File diff suppressed because it is too large
Load Diff
17
Regions.py
17
Regions.py
@@ -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
20
Rom.py
@@ -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:
|
||||||
|
|||||||
4
Rules.py
4
Rules.py
@@ -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))
|
||||||
|
|||||||
15
Utils.py
15
Utils.py
@@ -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.
@@ -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"
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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" },
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
58
source/dungeon/RoomList.py
Normal file
58
source/dungeon/RoomList.py
Normal 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)])
|
||||||
34
source/dungeon/RoomObject.py
Normal file
34
source/dungeon/RoomObject.py
Normal 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]
|
||||||
|
|
||||||
@@ -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']:
|
||||||
|
|||||||
Reference in New Issue
Block a user