Merge branch 'DoorDevUnstable' into Synthesis

# Conflicts:
#	Bosses.py
#	Main.py
#	Rom.py
#	data/base2current.bps
This commit is contained in:
aerinon
2022-08-11 15:43:33 -06:00
6 changed files with 78 additions and 69 deletions

View File

@@ -223,12 +223,15 @@ def place_bosses(world, player):
for u, level in used_bosses: for u, level in used_bosses:
if not level: if not level:
bosses.remove(u) bosses.remove(u)
gt_bosses = []
for [loc, level] in boss_locations: for [loc, level] in boss_locations:
loc_text = loc + (' ('+level+')' if level else '') loc_text = loc + (' ('+level+')' if level else '')
try: try:
if level: if level:
boss = random.choice([b for b in placeable_bosses if can_place_boss(world, player, b, loc, level)]) boss = random.choice([b for b in placeable_bosses if can_place_boss(world, player, b, loc, level)
and b not in gt_bosses])
gt_bosses.append(boss)
else: else:
boss = random.choice([b for b in bosses if can_place_boss(world, player, b, loc, level)]) boss = random.choice([b for b in bosses if can_place_boss(world, player, b, loc, level)])
bosses.remove(boss) bosses.remove(boss)

85
Fill.py
View File

@@ -3,6 +3,7 @@ import collections
import itertools import itertools
import logging import logging
import math import math
from contextlib import suppress
from BaseClasses import CollectionState, FillError, LocationType from BaseClasses import CollectionState, FillError, LocationType
from Items import ItemFactory from Items import ItemFactory
@@ -35,17 +36,6 @@ def dungeon_tracking(world):
def fill_dungeons_restrictive(world, shuffled_locations): def fill_dungeons_restrictive(world, shuffled_locations):
dungeon_tracking(world) dungeon_tracking(world)
all_state_base = world.get_all_state()
# for player in range(1, world.players + 1):
# pinball_room = world.get_location('Skull Woods - Pinball Room', player)
# if world.retro[player]:
# world.push_item(pinball_room, ItemFactory('Small Key (Universal)', player), False)
# else:
# world.push_item(pinball_room, ItemFactory('Small Key (Skull Woods)', player), False)
# pinball_room.event = True
# pinball_room.locked = True
# shuffled_locations.remove(pinball_room)
# with shuffled dungeon items they are distributed as part of the normal item pool # with shuffled dungeon items they are distributed as part of the normal item pool
for item in world.get_items(): for item in world.get_items():
@@ -55,17 +45,28 @@ def fill_dungeons_restrictive(world, shuffled_locations):
item.priority = True item.priority = True
dungeon_items = [item for item in get_dungeon_item_pool(world) if item.is_inside_dungeon_item(world)] dungeon_items = [item for item in get_dungeon_item_pool(world) if item.is_inside_dungeon_item(world)]
bigs, smalls, others = [], [], []
for i in dungeon_items:
(bigs if i.bigkey else smalls if i.smallkey else others).append(i)
# sort in the order Big Key, Small Key, Other before placing dungeon items def fill(base_state, items, key_pool):
sort_order = {"BigKey": 3, "SmallKey": 2} fill_restrictive(world, base_state, shuffled_locations, items, key_pool, True)
dungeon_items.sort(key=lambda item: sort_order.get(item.type, 1))
fill_restrictive(world, all_state_base, shuffled_locations, dungeon_items, all_state_base = world.get_all_state()
keys_in_itempool={player: not world.keyshuffle[player] for player in range(1, world.players+1)}, big_state_base = all_state_base.copy()
single_player_placement=True) for x in smalls + others:
big_state_base.collect(x, True)
fill(big_state_base, bigs, smalls)
random.shuffle(shuffled_locations)
small_state_base = all_state_base.copy()
for x in others:
small_state_base.collect(x, True)
fill(small_state_base, smalls, smalls)
random.shuffle(shuffled_locations)
fill(all_state_base, others, None)
def fill_restrictive(world, base_state, locations, itempool, keys_in_itempool=None, single_player_placement=False, def fill_restrictive(world, base_state, locations, itempool, key_pool=None, single_player_placement=False,
vanilla=False): vanilla=False):
def sweep_from_pool(): def sweep_from_pool():
new_state = base_state.copy() new_state = base_state.copy()
@@ -101,8 +102,7 @@ def fill_restrictive(world, base_state, locations, itempool, keys_in_itempool=No
item_locations = filter_locations(item_to_place, locations, world, vanilla) item_locations = filter_locations(item_to_place, locations, world, vanilla)
for location in item_locations: for location in item_locations:
spot_to_fill = verify_spot_to_fill(location, item_to_place, maximum_exploration_state, spot_to_fill = verify_spot_to_fill(location, item_to_place, maximum_exploration_state,
single_player_placement, perform_access_check, itempool, single_player_placement, perform_access_check, key_pool, world)
keys_in_itempool, world)
if spot_to_fill: if spot_to_fill:
break break
if spot_to_fill is None: if spot_to_fill is None:
@@ -111,7 +111,7 @@ def fill_restrictive(world, base_state, locations, itempool, keys_in_itempool=No
continue continue
spot_to_fill = recovery_placement(item_to_place, locations, world, maximum_exploration_state, spot_to_fill = recovery_placement(item_to_place, locations, world, maximum_exploration_state,
base_state, itempool, perform_access_check, item_locations, base_state, itempool, perform_access_check, item_locations,
keys_in_itempool, single_player_placement) key_pool, single_player_placement)
if spot_to_fill is None: if spot_to_fill is None:
# we filled all reachable spots. Maybe the game can be beaten anyway? # we filled all reachable spots. Maybe the game can be beaten anyway?
unplaced_items.insert(0, item_to_place) unplaced_items.insert(0, item_to_place)
@@ -123,6 +123,10 @@ def fill_restrictive(world, base_state, locations, itempool, keys_in_itempool=No
raise FillError('No more spots to place %s' % item_to_place) raise FillError('No more spots to place %s' % item_to_place)
world.push_item(spot_to_fill, item_to_place, False) world.push_item(spot_to_fill, item_to_place, False)
# todo: remove key item from key_pool
if item_to_place.smallkey:
with suppress(ValueError):
key_pool.remove(item_to_place)
track_outside_keys(item_to_place, spot_to_fill, world) track_outside_keys(item_to_place, spot_to_fill, world)
track_dungeon_items(item_to_place, spot_to_fill, world) track_dungeon_items(item_to_place, spot_to_fill, world)
locations.remove(spot_to_fill) locations.remove(spot_to_fill)
@@ -132,7 +136,7 @@ def fill_restrictive(world, base_state, locations, itempool, keys_in_itempool=No
def verify_spot_to_fill(location, item_to_place, max_exp_state, single_player_placement, perform_access_check, def verify_spot_to_fill(location, item_to_place, max_exp_state, single_player_placement, perform_access_check,
itempool, keys_in_itempool, world): key_pool, world):
if item_to_place.smallkey or item_to_place.bigkey: # a better test to see if a key can go there if item_to_place.smallkey or item_to_place.bigkey: # a better test to see if a key can go there
location.item = item_to_place location.item = item_to_place
test_state = max_exp_state.copy() test_state = max_exp_state.copy()
@@ -141,8 +145,7 @@ def verify_spot_to_fill(location, item_to_place, max_exp_state, single_player_pl
test_state = max_exp_state test_state = max_exp_state
if not single_player_placement or location.player == item_to_place.player: if not single_player_placement or location.player == item_to_place.player:
if location.can_fill(test_state, item_to_place, perform_access_check): if location.can_fill(test_state, item_to_place, perform_access_check):
test_pool = itempool if (keys_in_itempool and keys_in_itempool[item_to_place.player]) else world.itempool if valid_key_placement(item_to_place, location, key_pool, world):
if valid_key_placement(item_to_place, location, test_pool, world):
if item_to_place.crystal or valid_dungeon_placement(item_to_place, location, world): if item_to_place.crystal or valid_dungeon_placement(item_to_place, location, world):
return location return location
if item_to_place.smallkey or item_to_place.bigkey: if item_to_place.smallkey or item_to_place.bigkey:
@@ -150,7 +153,7 @@ def verify_spot_to_fill(location, item_to_place, max_exp_state, single_player_pl
return None return None
def valid_key_placement(item, location, itempool, world): def valid_key_placement(item, location, key_pool, world):
if not valid_reserved_placement(item, location, world): if not valid_reserved_placement(item, location, world):
return False return False
if ((not item.smallkey and not item.bigkey) or item.player != location.player if ((not item.smallkey and not item.bigkey) or item.player != location.player
@@ -161,7 +164,7 @@ def valid_key_placement(item, location, itempool, world):
if dungeon.name not in item.name and (dungeon.name != 'Hyrule Castle' or 'Escape' not in item.name): if dungeon.name not in item.name and (dungeon.name != 'Hyrule Castle' or 'Escape' not in item.name):
return True return True
key_logic = world.key_logic[item.player][dungeon.name] key_logic = world.key_logic[item.player][dungeon.name]
unplaced_keys = len([x for x in itempool if x.name == key_logic.small_key_name and x.player == item.player]) unplaced_keys = len([x for x in key_pool if x.name == key_logic.small_key_name and x.player == item.player])
prize_loc = None prize_loc = None
if key_logic.prize_location: if key_logic.prize_location:
prize_loc = world.get_location(key_logic.prize_location, location.player) prize_loc = world.get_location(key_logic.prize_location, location.player)
@@ -216,16 +219,16 @@ def is_dungeon_item(item, world):
def recovery_placement(item_to_place, locations, world, state, base_state, itempool, perform_access_check, attempted, def recovery_placement(item_to_place, locations, world, state, base_state, itempool, perform_access_check, attempted,
keys_in_itempool=None, single_player_placement=False): key_pool=None, single_player_placement=False):
logging.getLogger('').debug(f'Could not place {item_to_place} attempting recovery') logging.getLogger('').debug(f'Could not place {item_to_place} attempting recovery')
if world.algorithm in ['balanced', 'equitable']: if world.algorithm in ['balanced', 'equitable']:
return last_ditch_placement(item_to_place, locations, world, state, base_state, itempool, keys_in_itempool, return last_ditch_placement(item_to_place, locations, world, state, base_state, itempool, key_pool,
single_player_placement) single_player_placement)
elif world.algorithm == 'vanilla_fill': elif world.algorithm == 'vanilla_fill':
if item_to_place.type == 'Crystal': if item_to_place.type == 'Crystal':
possible_swaps = [x for x in state.locations_checked if x.item.type == 'Crystal'] possible_swaps = [x for x in state.locations_checked if x.item.type == 'Crystal']
return try_possible_swaps(possible_swaps, item_to_place, locations, world, base_state, itempool, return try_possible_swaps(possible_swaps, item_to_place, locations, world, base_state, itempool,
keys_in_itempool, single_player_placement) key_pool, single_player_placement)
else: else:
i, config = 0, world.item_pool_config i, config = 0, world.item_pool_config
tried = set(attempted) tried = set(attempted)
@@ -235,7 +238,7 @@ def recovery_placement(item_to_place, locations, world, state, base_state, itemp
other_locs = [x for x in locations if x.name in fallback_locations] other_locs = [x for x in locations if x.name in fallback_locations]
for location in other_locs: for location in other_locs:
spot_to_fill = verify_spot_to_fill(location, item_to_place, state, single_player_placement, spot_to_fill = verify_spot_to_fill(location, item_to_place, state, single_player_placement,
perform_access_check, itempool, keys_in_itempool, world) perform_access_check, key_pool, world)
if spot_to_fill: if spot_to_fill:
return spot_to_fill return spot_to_fill
i += 1 i += 1
@@ -244,14 +247,14 @@ def recovery_placement(item_to_place, locations, world, state, base_state, itemp
other_locations = vanilla_fallback(item_to_place, locations, world) other_locations = vanilla_fallback(item_to_place, locations, world)
for location in other_locations: for location in other_locations:
spot_to_fill = verify_spot_to_fill(location, item_to_place, state, single_player_placement, spot_to_fill = verify_spot_to_fill(location, item_to_place, state, single_player_placement,
perform_access_check, itempool, keys_in_itempool, world) perform_access_check, key_pool, world)
if spot_to_fill: if spot_to_fill:
return spot_to_fill return spot_to_fill
tried.update(other_locations) tried.update(other_locations)
other_locations = [x for x in locations if x not in tried] other_locations = [x for x in locations if x not in tried]
for location in other_locations: for location in other_locations:
spot_to_fill = verify_spot_to_fill(location, item_to_place, state, single_player_placement, spot_to_fill = verify_spot_to_fill(location, item_to_place, state, single_player_placement,
perform_access_check, itempool, keys_in_itempool, world) perform_access_check, key_pool, world)
if spot_to_fill: if spot_to_fill:
return spot_to_fill return spot_to_fill
return None return None
@@ -259,14 +262,14 @@ def recovery_placement(item_to_place, locations, world, state, base_state, itemp
other_locations = [x for x in locations if x not in attempted] other_locations = [x for x in locations if x not in attempted]
for location in other_locations: for location in other_locations:
spot_to_fill = verify_spot_to_fill(location, item_to_place, state, single_player_placement, spot_to_fill = verify_spot_to_fill(location, item_to_place, state, single_player_placement,
perform_access_check, itempool, keys_in_itempool, world) perform_access_check, key_pool, world)
if spot_to_fill: if spot_to_fill:
return spot_to_fill return spot_to_fill
return None return None
def last_ditch_placement(item_to_place, locations, world, state, base_state, itempool, def last_ditch_placement(item_to_place, locations, world, state, base_state, itempool,
keys_in_itempool=None, single_player_placement=False): key_pool=None, single_player_placement=False):
def location_preference(loc): def location_preference(loc):
if not loc.item.advancement: if not loc.item.advancement:
return 1 return 1
@@ -284,21 +287,21 @@ def last_ditch_placement(item_to_place, locations, world, state, base_state, ite
if x.item.type not in ['Event', 'Crystal'] and not x.forced_item] if x.item.type not in ['Event', 'Crystal'] and not x.forced_item]
swap_locations = sorted(possible_swaps, key=location_preference) swap_locations = sorted(possible_swaps, key=location_preference)
return try_possible_swaps(swap_locations, item_to_place, locations, world, base_state, itempool, return try_possible_swaps(swap_locations, item_to_place, locations, world, base_state, itempool,
keys_in_itempool, single_player_placement) key_pool, single_player_placement)
def try_possible_swaps(swap_locations, item_to_place, locations, world, base_state, itempool, def try_possible_swaps(swap_locations, item_to_place, locations, world, base_state, itempool,
keys_in_itempool=None, single_player_placement=False): key_pool=None, single_player_placement=False):
for location in swap_locations: for location in swap_locations:
old_item = location.item old_item = location.item
new_pool = list(itempool) + [old_item] new_pool = list(itempool) + [old_item]
new_spot = find_spot_for_item(item_to_place, [location], world, base_state, new_pool, new_spot = find_spot_for_item(item_to_place, [location], world, base_state, new_pool,
keys_in_itempool, single_player_placement) key_pool, single_player_placement)
if new_spot: if new_spot:
restore_item = new_spot.item restore_item = new_spot.item
new_spot.item = item_to_place new_spot.item = item_to_place
swap_spot = find_spot_for_item(old_item, locations, world, base_state, itempool, swap_spot = find_spot_for_item(old_item, locations, world, base_state, itempool,
keys_in_itempool, single_player_placement) key_pool, single_player_placement)
if swap_spot: if swap_spot:
logging.getLogger('').debug(f'Swapping {old_item} for {item_to_place}') logging.getLogger('').debug(f'Swapping {old_item} for {item_to_place}')
world.push_item(swap_spot, old_item, False) world.push_item(swap_spot, old_item, False)
@@ -414,13 +417,13 @@ def distribute_items_restrictive(world, gftower_trash=False, fill_locations=None
# Make sure the escape small key is placed first in standard with key shuffle to prevent running out of spots # Make sure the escape small key is placed first in standard with key shuffle to prevent running out of spots
# todo: crossed # todo: crossed
progitempool.sort(key=lambda item: 1 if item.name == 'Small Key (Escape)' and world.keyshuffle[item.player] and world.mode[item.player] == 'standard' else 0) progitempool.sort(key=lambda item: 1 if item.name == 'Small Key (Escape)' and world.keyshuffle[item.player] and world.mode[item.player] == 'standard' else 0)
keys_in_pool = {player: world.keyshuffle[player] or world.algorithm != 'balanced' for player in range(1, world.players + 1)} key_pool = [x for x in progitempool if x.smallkey]
# sort maps and compasses to the back -- this may not be viable in equitable & ambrosia # sort maps and compasses to the back -- this may not be viable in equitable & ambrosia
progitempool.sort(key=lambda item: 0 if item.map or item.compass else 1) progitempool.sort(key=lambda item: 0 if item.map or item.compass else 1)
if world.algorithm == 'vanilla_fill': if world.algorithm == 'vanilla_fill':
fill_restrictive(world, world.state, fill_locations, progitempool, keys_in_pool, vanilla=True) fill_restrictive(world, world.state, fill_locations, progitempool, key_pool, vanilla=True)
fill_restrictive(world, world.state, fill_locations, progitempool, keys_in_pool) fill_restrictive(world, world.state, fill_locations, progitempool, key_pool)
random.shuffle(fill_locations) random.shuffle(fill_locations)
if world.algorithm == 'balanced': if world.algorithm == 'balanced':
fast_fill(world, prioitempool, fill_locations) fast_fill(world, prioitempool, fill_locations)

View File

@@ -33,7 +33,7 @@ from source.overworld.EntranceShuffle2 import link_entrances_new
from source.tools.BPS import create_bps_from_data from source.tools.BPS import create_bps_from_data
from source.classes.CustomSettings import CustomSettings from source.classes.CustomSettings import CustomSettings
__version__ = '1.0.1.0-x' __version__ = '1.0.1.1-x'
from source.classes.BabelFish import BabelFish from source.classes.BabelFish import BabelFish

View File

@@ -787,12 +787,13 @@ vanilla_pots = {
Pot(230, 27, PotItem.Bomb, 'Light World Bomb Hut', obj=RoomObject(0x03EF5E, [0xCF, 0xDF, 0xFA]))], Pot(230, 27, PotItem.Bomb, 'Light World Bomb Hut', obj=RoomObject(0x03EF5E, [0xCF, 0xDF, 0xFA]))],
0x108: [Pot(166, 19, PotItem.Chicken, 'Chicken House', obj=RoomObject(0x03EFA9, [0x4F, 0x9F, 0xFA]))], 0x108: [Pot(166, 19, PotItem.Chicken, 'Chicken House', obj=RoomObject(0x03EFA9, [0x4F, 0x9F, 0xFA]))],
0x10C: [Pot(88, 14, PotItem.Heart, 'Hookshot Fairy', obj=RoomObject(0x03F329, [0xB3, 0x73, 0xFA]))], 0x10C: [Pot(88, 14, PotItem.Heart, 'Hookshot Fairy', obj=RoomObject(0x03F329, [0xB3, 0x73, 0xFA]))],
0x114: [Pot(92, 4, PotItem.Heart, 'Dark Desert Hint', obj=RoomObject(0x03F7A0, [0xBB, 0x23, 0xFA])), # note: these addresses got moved thanks to waterfall fairy edit
Pot(96, 4, PotItem.Heart, 'Dark Desert Hint', obj=RoomObject(0x03F7A3, [0xC3, 0x23, 0xFA])), 0x114: [Pot(92, 4, PotItem.Heart, 'Dark Desert Hint', obj=RoomObject(0x03F79A, [0xBB, 0x23, 0xFA])),
Pot(92, 5, PotItem.Bomb, 'Dark Desert Hint', obj=RoomObject(0x03F7A6, [0xBB, 0x2B, 0xFA])), Pot(96, 4, PotItem.Heart, 'Dark Desert Hint', obj=RoomObject(0x03F79D, [0xC3, 0x23, 0xFA])),
Pot(96, 5, PotItem.Bomb, 'Dark Desert Hint', obj=RoomObject(0x03F7A9, [0xC3, 0x2B, 0xFA])), Pot(92, 5, PotItem.Bomb, 'Dark Desert Hint', obj=RoomObject(0x03F7A0, [0xBB, 0x2B, 0xFA])),
Pot(92, 10, PotItem.FiveArrows, 'Dark Desert Hint', obj=RoomObject(0x03F7AC, [0xBB, 0x53, 0xFA])), Pot(96, 5, PotItem.Bomb, 'Dark Desert Hint', obj=RoomObject(0x03F7A3, [0xC3, 0x2B, 0xFA])),
Pot(96, 10, PotItem.Heart, 'Dark Desert Hint', obj=RoomObject(0x03F7AF, [0xC3, 0x53, 0xFA]))], Pot(92, 10, PotItem.FiveArrows, 'Dark Desert Hint', obj=RoomObject(0x03F7A6, [0xBB, 0x53, 0xFA])),
Pot(96, 10, PotItem.Heart, 'Dark Desert Hint', obj=RoomObject(0x03F7A9, [0xC3, 0x53, 0xFA]))],
0x117: [Pot(138, 3, PotItem.Heart, 'Spike Cave', obj=RoomObject(0x03FCB2, [0x17, 0x1F, 0xFA])), # 0x38A -> 38A 0x117: [Pot(138, 3, PotItem.Heart, 'Spike Cave', obj=RoomObject(0x03FCB2, [0x17, 0x1F, 0xFA])), # 0x38A -> 38A
Pot(142, 3, PotItem.Heart, 'Spike Cave', obj=RoomObject(0x03FCB8, [0x1F, 0x1F, 0xFA])), Pot(142, 3, PotItem.Heart, 'Spike Cave', obj=RoomObject(0x03FCB8, [0x1F, 0x1F, 0xFA])),
Pot(166, 3, PotItem.Heart, 'Spike Cave', obj=RoomObject(0x03FCC1, [0x4F, 0x1F, 0xFA])), Pot(166, 3, PotItem.Heart, 'Spike Cave', obj=RoomObject(0x03FCC1, [0x4F, 0x1F, 0xFA])),

View File

@@ -207,6 +207,12 @@ Same as above but both small keys and bigs keys of the dungeon are not allowed o
#### Unstable #### Unstable
* 1.0.1.1
* Fixed the pots in Mire Storyteller/ Dark Desert Hint to be colorized when they should be
* Certain pot items no longer reload when reloading the supertile (matches original pot behavior better)
* Changed the key distribution that made small keys placement more random when keys are in their own dungeon
* Unique boss shuffle no longer allows repeat bosses in GT (e.g. only one Trinexx in GT, so exactly 3 bosses are repeated in the seed. This is a difference process than full which does affect the probability distribution.)
* Removed text color in hints due to vanilla bug
* 1.0.1.0 * 1.0.1.0
* Large features * Large features
* New pottery modes - see notes above * New pottery modes - see notes above
@@ -230,7 +236,6 @@ Same as above but both small keys and bigs keys of the dungeon are not allowed o
* Refactored spoiler to generate in stages for better error collection. A meta file will be generated additionally for mystery seeds. Some random settings moved later in the spoiler to have the meta section at the top not spoil certain things. (GT/Ganon requirements.) Thanks to codemann and OWR for most of this work. * Refactored spoiler to generate in stages for better error collection. A meta file will be generated additionally for mystery seeds. Some random settings moved later in the spoiler to have the meta section at the top not spoil certain things. (GT/Ganon requirements.) Thanks to codemann and OWR for most of this work.
* Updated tourney winners (included Doors Async League winners) * Updated tourney winners (included Doors Async League winners)
* Some textual changes for hints (capitalization standardization) * Some textual changes for hints (capitalization standardization)
* Item will be highlighted in red if experimental is on. This will likely be removed.
* Reworked GT Trash Fill. Base rate is 0-75% of locations fill with 7 crystals entrance requirements. Triforce hunt is 75%-100% of locations. The 75% number will decrease based on the crystal entrance requirement. Dungeon_only algorithm caps it based on how many items need to be placed in dungeons. Cross dungeon shuffle will now work with the trash fill. * Reworked GT Trash Fill. Base rate is 0-75% of locations fill with 7 crystals entrance requirements. Triforce hunt is 75%-100% of locations. The 75% number will decrease based on the crystal entrance requirement. Dungeon_only algorithm caps it based on how many items need to be placed in dungeons. Cross dungeon shuffle will now work with the trash fill.
* Expanded Mystery logic options (e.g. owglitches) * Expanded Mystery logic options (e.g. owglitches)
* Updated indicators on keysanity menu for overworld map option * Updated indicators on keysanity menu for overworld map option
@@ -259,7 +264,7 @@ Same as above but both small keys and bigs keys of the dungeon are not allowed o
* Fixed a bug with shopsanity + district algorithm where pre-placed potions messed up the placeholder count * Fixed a bug with shopsanity + district algorithm where pre-placed potions messed up the placeholder count
* Fixed usestartinventory flag (can be use on a per player basis) * Fixed usestartinventory flag (can be use on a per player basis)
* Sprite selector fix for systems with SSL issues * Sprite selector fix for systems with SSL issues
* Fix for Standard ER where locations in rain state could be in logic * Fix for Standard ER where locations in rain state could be in logic
* 1.0.0.3 * 1.0.0.3
* overworld_map=map mode fixed. Location of dungeons with maps are not shown until map is retrieved. (Dungeon that do not have map like Castle Tower are simply never shown) * overworld_map=map mode fixed. Location of dungeons with maps are not shown until map is retrieved. (Dungeon that do not have map like Castle Tower are simply never shown)
* Aga2 completion on overworld_map now tied to boss defeat flag instead of pyramid hole being opened (fast ganon fix) * Aga2 completion on overworld_map now tied to boss defeat flag instead of pyramid hole being opened (fast ganon fix)

33
Rom.py
View File

@@ -663,18 +663,6 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
if world.mapshuffle[player]: if world.mapshuffle[player]:
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.pottery[player] not in ['none']:
rom.write_bytes(snes_to_pc(0x1F8375), int32_as_bytes(0x2A8000))
# make hammer pegs use different tiles
Room0127.write_to_rom(snes_to_pc(0x2A8000), rom)
if world.pot_contents[player]:
colorize_pots = is_mystery or (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:
raise Exception('Pot table is too big for current area')
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:
@@ -1549,6 +1537,19 @@ def patch_rom(world, rom, player, team, enemized, is_mystery=False):
if room.player == player and room.modified: if room.player == player and room.modified:
rom.write_bytes(room.address(), room.rom_data()) rom.write_bytes(room.address(), room.rom_data())
if world.pottery[player] not in ['none']:
rom.write_bytes(snes_to_pc(0x1F8375), int32_as_bytes(0x2A8000))
# make hammer pegs use different tiles
Room0127.write_to_rom(snes_to_pc(0x2A8000), rom)
if world.pot_contents[player]:
colorize_pots = is_mystery or (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:
raise Exception('Pot table is too big for current area')
world.pot_contents[player].write_pot_data_to_rom(rom, colorize_pots)
write_strings(rom, world, player, team) write_strings(rom, world, player, team)
# write initial sram # write initial sram
@@ -1982,8 +1983,6 @@ def write_strings(rom, world, player, team):
else: else:
if isinstance(dest, Region) and dest.type == RegionType.Dungeon and dest.dungeon: if isinstance(dest, Region) and dest.type == RegionType.Dungeon and dest.dungeon:
hint = dest.dungeon.name hint = dest.dungeon.name
elif isinstance(dest, Item) and world.experimental[player]:
hint = f'{{C:RED}}{dest.hint_text}{{C:WHITE}}' if dest.hint_text else 'something'
else: else:
hint = dest.hint_text if dest.hint_text else "something" hint = dest.hint_text if dest.hint_text else "something"
if dest.player != player: if dest.player != player:
@@ -2162,8 +2161,7 @@ def write_strings(rom, world, player, team):
if this_location: if this_location:
item_name = this_location[0].item.hint_text item_name = this_location[0].item.hint_text
item_name = item_name[0].upper() + item_name[1:] item_name = item_name[0].upper() + item_name[1:]
item_format = f'{{C:RED}}{item_name}{{C:WHITE}}' if world.experimental[player] else item_name this_hint = f'{item_name} can be found {hint_text(this_location[0])}.'
this_hint = f'{item_format} can be found {hint_text(this_location[0])}.'
tt[hint_locations.pop(0)] = this_hint tt[hint_locations.pop(0)] = this_hint
hint_count -= 1 hint_count -= 1
@@ -2217,8 +2215,7 @@ def write_strings(rom, world, player, team):
elif hint_type == 'path': elif hint_type == 'path':
if item_count == 1: if item_count == 1:
the_item = text_for_item(next(iter(choice_set)), world, player, team) the_item = text_for_item(next(iter(choice_set)), world, player, team)
item_format = f'{{C:RED}}{the_item}{{C:WHITE}}' if world.experimental[player] else the_item hint_candidates.append((hint_type, f'{name} conceals only {the_item}'))
hint_candidates.append((hint_type, f'{name} conceals only {item_format}'))
else: else:
hint_candidates.append((hint_type, f'{name} conceals {item_count} {item_type} items')) hint_candidates.append((hint_type, f'{name} conceals {item_count} {item_type} items'))
district_hints = min(len(hint_candidates), len(hint_locations)) district_hints = min(len(hint_candidates), len(hint_locations))