Merge branch 'shop-fill' into multishop-all

This commit is contained in:
pepperpow 2020-12-15 02:36:48 -06:00
commit 767c84a581
8 changed files with 63 additions and 28 deletions

View File

@ -342,27 +342,6 @@ class World(object):
if collect:
self.state.collect(item, location.event, location)
# TODO: Prevents fast_filling certain items. Move this to a proper filter.
if location.parent_region.shop is not None and location.name != 'Potion Shop': # includes potion shop slots but not potion shop powder
slot_num = int(location.name[-1]) - 1
my_item = location.parent_region.shop.inventory[slot_num]
if (my_item is not None and my_item['item'] == item.name) or 'Rupee' in item.name or ('Bee' in item.name and 'Trap' not in item.name):
# this will filter items that match the item in the shop or Rupees, or single bees
# really not a way for the player to know a renewable item from a player pool item
# bombs can be sitting on top of arrows or a potion refill, but dunno if that's a big deal
logging.debug('skipping item shop {}'.format(item.name))
else:
if my_item is None:
location.parent_region.shop.add_inventory(slot_num, 'None', 0)
my_item = location.parent_region.shop.inventory[slot_num]
else:
my_item['replacement'] = my_item['item']
my_item['replacement_price'] = my_item['price']
my_item['item'] = item.name
my_item['price'] = self.random.randrange(1, 61) * 5 # can probably replace this with a price chart
my_item['max'] = 1
my_item['player'] = item.player if item.player != location.player else 0
logging.debug('Placed %s at %s', item, location)
else:
raise RuntimeError('Cannot assign item %s to location %s.' % (item, location))

View File

@ -470,7 +470,11 @@ def create_dynamic_shop_locations(world, player):
if item is None:
continue
if item['create_location']:
<<<<<<< HEAD
loc = Location(player, "{} Slot Item {}".format(shop.region.name, i+1), parent=shop.region)
=======
loc = Location(player, "{} Shop Slot {}".format(shop.region.name, i+1), parent=shop.region)
>>>>>>> ffe5b4b1a1d806c09a1be91a283dd3a6cdbcaafa
shop.region.locations.append(loc)
world.dynamic_locations.append(loc)

View File

@ -306,6 +306,7 @@ def main(args, seed=None):
main_entrance = get_entrance_to_region(region)
for location in region.locations:
if type(location.address) == int: # skips events and crystals
if location.address >= 0x400000: continue
if lookup_vanilla_location_to_entrance[location.address] != main_entrance.name:
er_hint_data[region.player][location.address] = main_entrance.name

View File

@ -157,6 +157,11 @@ SCOUT_LOCATION_ADDR = SAVEDATA_START + 0x4D7 # 1 byte
SCOUTREPLY_LOCATION_ADDR = SAVEDATA_START + 0x4D8 # 1 byte
SCOUTREPLY_ITEM_ADDR = SAVEDATA_START + 0x4D9 # 1 byte
SCOUTREPLY_PLAYER_ADDR = SAVEDATA_START + 0x4DA # 1 byte
SHOP_ADDR = SAVEDATA_START + 0x302 # 2 bytes
location_shop_order = [ name for name, info in Regions.shop_table.items() ] # probably don't leave this here. This relies on python 3.6+ dictionary keys having defined order
location_shop_ids = set([info[0] for name, info in Regions.shop_table.items()])
location_table_uw = {"Blind's Hideout - Top": (0x11d, 0x10),
"Blind's Hideout - Left": (0x11d, 0x20),
@ -1116,6 +1121,18 @@ async def track_locations(ctx : Context, roomid, roomdata):
ctx.unsafe_locations_checked.add(location)
ctx.ui_node.log_info("New check: %s (%d/216)" % (location, len(ctx.unsafe_locations_checked)))
ctx.ui_node.send_location_check(ctx, location)
try:
if roomid in location_shop_ids:
misc_data = await snes_read(ctx, SHOP_ADDR, len(location_shop_order)*3)
for cnt, b in enumerate(misc_data):
my_check = Regions.shop_table_by_location_id[0x400000 + cnt]
if int(b) > 0 and my_check not in ctx.unsafe_locations_checked:
new_check(my_check)
except Exception as e:
print(e)
ctx.ui_node.log_info(f"Exception: {e}")
for location, (loc_roomid, loc_mask) in location_table_uw.items():
try:
@ -1175,7 +1192,13 @@ async def track_locations(ctx : Context, roomid, roomdata):
for location in ctx.unsafe_locations_checked:
if (location in ctx.items_missing and location not in ctx.locations_checked) or ctx.send_unsafe:
ctx.locations_checked.add(location)
new_locations.append(Regions.lookup_name_to_id[location])
try:
my_id = Regions.lookup_name_to_id.get(location, Regions.shop_table_by_location.get(location, -1))
new_locations.append(my_id)
except Exception as e:
print(e)
ctx.ui_node.log_info(f"Exception: {e}")
await ctx.send_msgs([['LocationChecks', new_locations]])

View File

@ -950,7 +950,7 @@ def get_missing_checks(ctx: Context, client: Client) -> list:
#for location_id in [k[0] for k, v in ctx.locations if k[1] == client.slot]:
# if location_id not in ctx.location_checks[client.team, client.slot]:
# locations.append(Regions.lookup_id_to_name.get(location_id, f'Unknown Location ID: {location_id}'))
for location_id, location_name in Regions.lookup_id_to_name.items(): # cheat console is -1, keep in mind
for location_id, location_name in {**Regions.lookup_id_to_name, **Regions.shop_table_by_location_id}.items(): # cheat console is -1, keep in mind
if location_id != -1 and location_id not in ctx.location_checks[client.team, client.slot] and (location_id, client.slot) in ctx.locations:
locations.append(location_name)
return locations

View File

@ -418,7 +418,8 @@ def create_shops(world, player: int):
if my_shop_slots.pop():
additional_item = world.random.choice(['Rupees (20)', 'Rupees (50)', 'Rupees (100)'])
world.itempool.append(ItemFactory(additional_item, player))
loc = Location(player, "{} Slot Item {}".format(shop.region.name, index+1), parent=shop.region)
slot_name = "{} Shop Slot {}".format(shop.region.name, index+1)
loc = Location(player, slot_name, address=shop_table_by_location[slot_name], parent=shop.region)
shop.region.locations.append(loc)
world.dynamic_locations.append(loc)
@ -443,6 +444,9 @@ shop_table = {
'Capacity Upgrade': (0x0115, ShopType.UpgradeShop, 0x04, True, True, [('Bomb Upgrade (+5)', 100, 7), ('Arrow Upgrade (+5)', 100, 7)])
}
shop_table_by_location_id = {0x400000 + cnt: s for cnt, s in enumerate( [item for sublist in [ ["{} Shop Slot {}".format(name, num + 1) for num in range(3)] for name in shop_table ] for item in sublist])}
shop_table_by_location = {y:x for x,y in shop_table_by_location_id.items()}
shop_generation_types = {
'default': _basic_shop_defaults + [('Bombs (3)', 20), ('Green Potion', 90), ('Blue Potion', 190), ('Bee', 10), ('Single Arrow', 5)] + [('Red Shield', 500), ('Blue Shield', 50)],
'potion': [('Red Potion', 150), ('Green Potion', 90), ('Blue Potion', 190)],
@ -748,8 +752,10 @@ location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'),
lookup_id_to_name = {data[0]: name for name, data in location_table.items() if type(data[0]) == int}
lookup_id_to_name = {**lookup_id_to_name, **{data[1]: name for name, data in key_drop_data.items()}, -1: "cheat console"}
lookup_id_to_name.update(shop_table_by_location_id)
lookup_name_to_id = {name: data[0] for name, data in location_table.items() if type(data[0]) == int}
lookup_name_to_id = {**lookup_name_to_id, **{name: data[1] for name, data in key_drop_data.items()}, "cheat console": -1}
lookup_name_to_id.update(shop_table_by_location)
lookup_vanilla_location_to_entrance = {1572883: 'Kings Grave Inner Rocks', 191256: 'Kings Grave Inner Rocks',
1573194: 'Kings Grave Inner Rocks', 1573189: 'Kings Grave Inner Rocks',

22
Rom.py
View File

@ -642,6 +642,28 @@ def patch_rom(world, rom, player, team, enemized):
if location.address is None:
continue
if 'Shop Slot' in location.name and location.parent_region.shop is not None:
slot_num = int(location.name[-1]) - 1
my_item = location.parent_region.shop.inventory[slot_num]
item = location.item
if (my_item is not None and my_item['item'] == item.name) or 'Rupee' in item.name or (item.name in ['Bee']):
# this will filter items that match the item in the shop or Rupees, or single bees
# really not a way for the player to know a renewable item from a player pool item
# bombs can be sitting on top of arrows or a potion refill, but dunno if that's a big deal
logging.debug('skipping item shop {}'.format(item.name))
else:
if my_item is None:
location.parent_region.shop.add_inventory(slot_num, 'None', 0)
my_item = location.parent_region.shop.inventory[slot_num]
else:
my_item['replacement'] = my_item['item']
my_item['replacement_price'] = my_item['price']
my_item['item'] = item.name
my_item['price'] = world.random.randrange(1, 61) * 5 # can probably replace this with a price chart
my_item['max'] = 1
my_item['player'] = item.player if item.player != location.player else 0
continue
if not location.crystal:
if location.item is not None:
# Keys in their native dungeon should use the orignal item code for keys

View File

@ -13,13 +13,13 @@ general_options:
# Null means nothing, for the server this means to default the value
# These overwrite command line arguments!
server_options:
host: null
host: 0.0.0.0
port: 38281
password: null
multidata: null
savefile: null
disable_save: false
loglevel: "info"
loglevel: "debug"
# Allows for clients to log on and manage the server. If this is null, no remote administration is possible.
server_password: null
# Automatically forward the port that is used, then close that port after 24 hours
@ -28,9 +28,9 @@ server_options:
disable_item_cheat: false
# Client hint system
# Points given to a player for each acquired item in their world
location_check_points: 1
location_check_points: 50
# Point cost to receive a hint via !hint for players
hint_cost: 1000 # Set to 0 if you want free hints
hint_cost: 0 # Set to 0 if you want free hints
# Forfeit modes
# "disabled" -> clients can't forfeit,
# "enabled" -> clients can always forfeit