Fixes to clients/servers for shop checks
This commit is contained in:
parent
360fcbea9e
commit
ffe5b4b1a1
|
@ -341,27 +341,6 @@ class World(object):
|
||||||
if collect:
|
if collect:
|
||||||
self.state.collect(item, location.event, location)
|
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)
|
logging.debug('Placed %s at %s', item, location)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('Cannot assign item %s to location %s.' % (item, location))
|
raise RuntimeError('Cannot assign item %s to location %s.' % (item, location))
|
||||||
|
|
|
@ -464,7 +464,7 @@ def create_dynamic_shop_locations(world, player):
|
||||||
if item is None:
|
if item is None:
|
||||||
continue
|
continue
|
||||||
if item['create_location']:
|
if item['create_location']:
|
||||||
loc = Location(player, "{} Item {}".format(shop.region.name, i+1), parent=shop.region)
|
loc = Location(player, "{} Shop Slot {}".format(shop.region.name, i+1), parent=shop.region)
|
||||||
shop.region.locations.append(loc)
|
shop.region.locations.append(loc)
|
||||||
world.dynamic_locations.append(loc)
|
world.dynamic_locations.append(loc)
|
||||||
|
|
||||||
|
|
1
Main.py
1
Main.py
|
@ -305,6 +305,7 @@ def main(args, seed=None):
|
||||||
main_entrance = get_entrance_to_region(region)
|
main_entrance = get_entrance_to_region(region)
|
||||||
for location in region.locations:
|
for location in region.locations:
|
||||||
if type(location.address) == int: # skips events and crystals
|
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:
|
if lookup_vanilla_location_to_entrance[location.address] != main_entrance.name:
|
||||||
er_hint_data[region.player][location.address] = main_entrance.name
|
er_hint_data[region.player][location.address] = main_entrance.name
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,11 @@ SCOUT_LOCATION_ADDR = SAVEDATA_START + 0x4D7 # 1 byte
|
||||||
SCOUTREPLY_LOCATION_ADDR = SAVEDATA_START + 0x4D8 # 1 byte
|
SCOUTREPLY_LOCATION_ADDR = SAVEDATA_START + 0x4D8 # 1 byte
|
||||||
SCOUTREPLY_ITEM_ADDR = SAVEDATA_START + 0x4D9 # 1 byte
|
SCOUTREPLY_ITEM_ADDR = SAVEDATA_START + 0x4D9 # 1 byte
|
||||||
SCOUTREPLY_PLAYER_ADDR = SAVEDATA_START + 0x4DA # 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),
|
location_table_uw = {"Blind's Hideout - Top": (0x11d, 0x10),
|
||||||
"Blind's Hideout - Left": (0x11d, 0x20),
|
"Blind's Hideout - Left": (0x11d, 0x20),
|
||||||
|
@ -1117,6 +1122,18 @@ async def track_locations(ctx : Context, roomid, roomdata):
|
||||||
ctx.ui_node.log_info("New check: %s (%d/216)" % (location, len(ctx.unsafe_locations_checked)))
|
ctx.ui_node.log_info("New check: %s (%d/216)" % (location, len(ctx.unsafe_locations_checked)))
|
||||||
ctx.ui_node.send_location_check(ctx, location)
|
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():
|
for location, (loc_roomid, loc_mask) in location_table_uw.items():
|
||||||
try:
|
try:
|
||||||
if location not in ctx.unsafe_locations_checked and loc_roomid == roomid and (roomdata << 4) & loc_mask != 0:
|
if location not in ctx.unsafe_locations_checked and loc_roomid == roomid and (roomdata << 4) & loc_mask != 0:
|
||||||
|
@ -1175,7 +1192,13 @@ async def track_locations(ctx : Context, roomid, roomdata):
|
||||||
for location in ctx.unsafe_locations_checked:
|
for location in ctx.unsafe_locations_checked:
|
||||||
if (location in ctx.items_missing and location not in ctx.locations_checked) or ctx.send_unsafe:
|
if (location in ctx.items_missing and location not in ctx.locations_checked) or ctx.send_unsafe:
|
||||||
ctx.locations_checked.add(location)
|
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]])
|
await ctx.send_msgs([['LocationChecks', new_locations]])
|
||||||
|
|
||||||
|
|
|
@ -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]:
|
#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]:
|
# 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}'))
|
# 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:
|
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)
|
locations.append(location_name)
|
||||||
return locations
|
return locations
|
||||||
|
|
16
Regions.py
16
Regions.py
|
@ -396,7 +396,8 @@ def create_shops(world, player: int):
|
||||||
if my_shop_slots.pop():
|
if my_shop_slots.pop():
|
||||||
additional_item = world.random.choice(['Rupees (20)', 'Rupees (50)', 'Rupees (100)'])
|
additional_item = world.random.choice(['Rupees (20)', 'Rupees (50)', 'Rupees (100)'])
|
||||||
world.itempool.append(ItemFactory(additional_item, player))
|
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)
|
shop.region.locations.append(loc)
|
||||||
world.dynamic_locations.append(loc)
|
world.dynamic_locations.append(loc)
|
||||||
|
|
||||||
|
@ -420,6 +421,17 @@ shop_table = {
|
||||||
'Capacity Upgrade': (0x0115, ShopType.UpgradeShop, 0x04, True, True, [('Bomb Upgrade (+5)', 100, 7), ('Arrow Upgrade (+5)', 100, 7)])
|
'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)],
|
||||||
|
'discount_potion': [('Red Potion', 120), ('Green Potion', 60), ('Blue Potion', 160)],
|
||||||
|
'bottle': [('Bee', 10)],
|
||||||
|
'time': [('Red Clock', 100), ('Blue Clock', 200), ('Green Clock', 300)],
|
||||||
|
}
|
||||||
|
|
||||||
old_location_address_to_new_location_address = {
|
old_location_address_to_new_location_address = {
|
||||||
0x2eb18: 0x18001b, # Bottle Merchant
|
0x2eb18: 0x18001b, # Bottle Merchant
|
||||||
0x33d68: 0x18001a, # Purple Chest
|
0x33d68: 0x18001a, # Purple Chest
|
||||||
|
@ -717,8 +729,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 = {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 = {**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 = {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 = {**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',
|
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',
|
1573194: 'Kings Grave Inner Rocks', 1573189: 'Kings Grave Inner Rocks',
|
||||||
|
|
22
Rom.py
22
Rom.py
|
@ -638,6 +638,28 @@ def patch_rom(world, rom, player, team, enemized):
|
||||||
if location.address is None:
|
if location.address is None:
|
||||||
continue
|
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 not location.crystal:
|
||||||
if location.item is not None:
|
if location.item is not None:
|
||||||
# Keys in their native dungeon should use the orignal item code for keys
|
# Keys in their native dungeon should use the orignal item code for keys
|
||||||
|
|
|
@ -13,13 +13,13 @@ general_options:
|
||||||
# Null means nothing, for the server this means to default the value
|
# Null means nothing, for the server this means to default the value
|
||||||
# These overwrite command line arguments!
|
# These overwrite command line arguments!
|
||||||
server_options:
|
server_options:
|
||||||
host: null
|
host: 0.0.0.0
|
||||||
port: 38281
|
port: 38281
|
||||||
password: null
|
password: null
|
||||||
multidata: null
|
multidata: null
|
||||||
savefile: null
|
savefile: null
|
||||||
disable_save: false
|
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.
|
# Allows for clients to log on and manage the server. If this is null, no remote administration is possible.
|
||||||
server_password: null
|
server_password: null
|
||||||
# Automatically forward the port that is used, then close that port after 24 hours
|
# Automatically forward the port that is used, then close that port after 24 hours
|
||||||
|
@ -28,9 +28,9 @@ server_options:
|
||||||
disable_item_cheat: false
|
disable_item_cheat: false
|
||||||
# Client hint system
|
# Client hint system
|
||||||
# Points given to a player for each acquired item in their world
|
# 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
|
# 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
|
# Forfeit modes
|
||||||
# "disabled" -> clients can't forfeit,
|
# "disabled" -> clients can't forfeit,
|
||||||
# "enabled" -> clients can always forfeit
|
# "enabled" -> clients can always forfeit
|
||||||
|
|
Loading…
Reference in New Issue