Make multiclient/multiserver/tracker keydropshuffle aware
This commit is contained in:
parent
0c681c8903
commit
83db79815a
|
@ -342,7 +342,40 @@ location_table_uw = {"Blind's Hideout - Top": (0x11d, 0x10),
|
|||
'Ganons Tower - Mini Helmasaur Room - Left': (0x3d, 0x10),
|
||||
'Ganons Tower - Mini Helmasaur Room - Right': (0x3d, 0x20),
|
||||
'Ganons Tower - Pre-Moldorm Chest': (0x3d, 0x40),
|
||||
'Ganons Tower - Validation Chest': (0x4d, 0x10)}
|
||||
'Ganons Tower - Validation Chest': (0x4d, 0x10),
|
||||
'Hyrule Castle - Map Guard Key Drop': (0x72, 0x400),
|
||||
'Hyrule Castle - Boomerang Guard Key Drop': (0x71, 0x400),
|
||||
'Hyrule Castle - Key Rat Key Drop': (0x21, 0x400),
|
||||
'Hyrule Castle - Big Key Drop': (0x80, 0x400),
|
||||
'Eastern Palace - Dark Square Pot Key': (0xba, 0x400),
|
||||
'Eastern Palace - Dark Eyegore Key Drop': (0x99, 0x400),
|
||||
'Desert Palace - Desert Tiles 1 Pot Key': (0x63, 0x400),
|
||||
'Desert Palace - Beamos Hall Pot Key': (0x53, 0x400),
|
||||
'Desert Palace - Desert Tiles 2 Pot Key': (0x43, 0x400),
|
||||
'Castle Tower - Dark Archer Key Drop': (0xc0, 0x400),
|
||||
'Castle Tower - Circle of Pots Key Drop': (0xb0, 0x400),
|
||||
'Swamp Palace - Pot Row Pot Key': (0x38, 0x400),
|
||||
'Swamp Palace - Trench 1 Pot Key': (0x37, 0x400),
|
||||
'Swamp Palace - Hookshot Pot Key': (0x36, 0x400),
|
||||
'Swamp Palace - Trench 2 Pot Key': (0x35, 0x400),
|
||||
'Swamp Palace - Waterway Pot Key': (0x16, 0x400),
|
||||
'Skull Woods - West Lobby Pot Key': (0x56, 0x400),
|
||||
'Skull Woods - Spike Corner Key Drop': (0x39, 0x400),
|
||||
'Thieves\' Town - Hallway Pot Key': (0xbc, 0x400),
|
||||
'Thieves\' Town - Spike Switch Pot Key': (0xab, 0x400),
|
||||
'Ice Palace - Jelly Key Drop': (0x0e, 0x400),
|
||||
'Ice Palace - Conveyor Key Drop': (0x3e, 0x400),
|
||||
'Ice Palace - Hammer Block Key Drop': (0x3f, 0x400),
|
||||
'Ice Palace - Many Pots Pot Key': (0x9f, 0x400),
|
||||
'Misery Mire - Spikes Pot Key': (0xb3, 0x400),
|
||||
'Misery Mire - Fishbone Pot Key': (0xa1, 0x400),
|
||||
'Misery Mire - Conveyor Crystal Key Drop': (0xc1, 0x400),
|
||||
'Turtle Rock - Pokey 1 Key Drop': (0xb6, 0x400),
|
||||
'Turtle Rock - Pokey 2 Key Drop': (0x13, 0x400),
|
||||
'Ganons Tower - Conveyor Cross Pot Key': (0x8b, 0x400),
|
||||
'Ganons Tower - Double Switch Pot Key': (0x9b, 0x400),
|
||||
'Ganons Tower - Conveyor Star Pits Pot Key': (0x7b, 0x400),
|
||||
'Ganons Tower - Mini Helmasaur Key Drop': (0x3d, 0x400)}
|
||||
location_table_npc = {'Mushroom': 0x1000,
|
||||
'King Zora': 0x2,
|
||||
'Sahasrahla': 0x10,
|
||||
|
@ -822,7 +855,7 @@ async def process_server_cmd(ctx: Context, cmd, args):
|
|||
ctx.player_names = {p: n for p, n in args[1]}
|
||||
msgs = []
|
||||
if ctx.locations_checked:
|
||||
msgs.append(['LocationChecks', [Regions.location_table[loc][0] for loc in ctx.locations_checked]])
|
||||
msgs.append(['LocationChecks', [Regions.lookup_name_to_id[loc] for loc in ctx.locations_checked]])
|
||||
if ctx.locations_scouted:
|
||||
msgs.append(['LocationScouts', list(ctx.locations_scouted)])
|
||||
if msgs:
|
||||
|
@ -837,7 +870,7 @@ async def process_server_cmd(ctx: Context, cmd, args):
|
|||
elif start_index != len(ctx.items_received):
|
||||
sync_msg = [['Sync']]
|
||||
if ctx.locations_checked:
|
||||
sync_msg.append(['LocationChecks', [Regions.location_table[loc][0] for loc in ctx.locations_checked]])
|
||||
sync_msg.append(['LocationChecks', [Regions.lookup_name_to_id[loc] for loc in ctx.locations_checked]])
|
||||
await ctx.send_msgs(sync_msg)
|
||||
if start_index == len(ctx.items_received):
|
||||
for item in items:
|
||||
|
@ -1014,6 +1047,11 @@ class ClientCommandProcessor(CommandProcessor):
|
|||
self.output('Missing: ' + location)
|
||||
count += 1
|
||||
|
||||
for location in [k for k, v in Regions.key_drop_data.items()]:
|
||||
if location not in self.ctx.locations_checked:
|
||||
self.output('Missing: ' + location)
|
||||
count += 1
|
||||
|
||||
if count:
|
||||
self.output(f"Found {count} missing location checks")
|
||||
else:
|
||||
|
@ -1077,11 +1115,14 @@ async def track_locations(ctx : Context, roomid, roomdata):
|
|||
ctx.locations_checked.add(location)
|
||||
ctx.ui_node.log_info("New check: %s (%d/216)" % (location, len(ctx.locations_checked)))
|
||||
ctx.ui_node.send_location_check(ctx, location)
|
||||
new_locations.append(Regions.location_table[location][0])
|
||||
new_locations.append(Regions.lookup_name_to_id[location])
|
||||
|
||||
for location, (loc_roomid, loc_mask) in location_table_uw.items():
|
||||
if location not in ctx.locations_checked and loc_roomid == roomid and (roomdata << 4) & loc_mask != 0:
|
||||
new_check(location)
|
||||
try:
|
||||
if location not in ctx.locations_checked and loc_roomid == roomid and (roomdata << 4) & loc_mask != 0:
|
||||
new_check(location)
|
||||
except Exception as e:
|
||||
ctx.ui_node.log_info(f"Exception: {e}")
|
||||
|
||||
uw_begin = 0x129
|
||||
uw_end = 0
|
||||
|
|
|
@ -29,7 +29,7 @@ import Utils
|
|||
from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem, _version_tuple
|
||||
from NetUtils import Node, Endpoint
|
||||
|
||||
console_names = frozenset(set(Items.item_table) | set(Regions.location_table) | set(Items.item_name_groups))
|
||||
console_names = frozenset(set(Items.item_table) | set(Regions.location_table) | set(Items.item_name_groups) | set(Regions.key_drop_data))
|
||||
|
||||
CLIENT_PLAYING = 0
|
||||
CLIENT_GOAL = 1
|
||||
|
@ -439,6 +439,7 @@ def send_new_items(ctx: Context):
|
|||
|
||||
def forfeit_player(ctx: Context, team: int, slot: int):
|
||||
all_locations = {values[0] for values in Regions.location_table.values() if type(values[0]) is int}
|
||||
all_locations.update({values[1] for values in Regions.key_drop_data.values()})
|
||||
ctx.notify_all("%s (Team #%d) has forfeited" % (ctx.player_names[(team, slot)], team + 1))
|
||||
register_location_checks(ctx, team, slot, all_locations)
|
||||
|
||||
|
@ -514,7 +515,7 @@ def collect_hints(ctx: Context, team: int, slot: int, item: str) -> typing.List[
|
|||
|
||||
def collect_hints_location(ctx: Context, team: int, slot: int, location: str) -> typing.List[Utils.Hint]:
|
||||
hints = []
|
||||
seeked_location = Regions.location_table[location][0]
|
||||
seeked_location = Regions.lookup_name_to_id[location]
|
||||
for check, result in ctx.locations.items():
|
||||
location_id, finding_player = check
|
||||
if finding_player == slot and location_id == seeked_location:
|
||||
|
|
63
Regions.py
63
Regions.py
|
@ -397,6 +397,42 @@ shop_table = {
|
|||
'Capacity Upgrade': (0x0115, ShopType.UpgradeShop, 0x04, True, True, [('Bomb Upgrade (+5)', 100, 7), ('Arrow Upgrade (+5)', 100, 7)])
|
||||
}
|
||||
|
||||
key_drop_data = {
|
||||
'Hyrule Castle - Map Guard Key Drop': [0x140036, 0x140037],
|
||||
'Hyrule Castle - Boomerang Guard Key Drop': [0x140033, 0x140034],
|
||||
'Hyrule Castle - Key Rat Key Drop': [0x14000c, 0x14000d],
|
||||
'Hyrule Castle - Big Key Drop': [0x14003c, 0x14003d],
|
||||
'Eastern Palace - Dark Square Pot Key': [0x14005a, 0x14005b],
|
||||
'Eastern Palace - Dark Eyegore Key Drop': [0x140048, 0x140049],
|
||||
'Desert Palace - Desert Tiles 1 Pot Key': [0x140030, 0x140031],
|
||||
'Desert Palace - Beamos Hall Pot Key': [0x14002a, 0x14002b],
|
||||
'Desert Palace - Desert Tiles 2 Pot Key': [0x140027, 0x140028],
|
||||
'Castle Tower - Dark Archer Key Drop': [0x140060, 0x140061],
|
||||
'Castle Tower - Circle of Pots Key Drop': [0x140051, 0x140052],
|
||||
'Swamp Palace - Pot Row Pot Key': [0x140018, 0x140019],
|
||||
'Swamp Palace - Trench 1 Pot Key': [0x140015, 0x140016],
|
||||
'Swamp Palace - Hookshot Pot Key': [0x140012, 0x140013],
|
||||
'Swamp Palace - Trench 2 Pot Key': [0x14000f, 0x140010],
|
||||
'Swamp Palace - Waterway Pot Key': [0x140009, 0x14000a],
|
||||
'Skull Woods - West Lobby Pot Key': [0x14002d, 0x14002e],
|
||||
'Skull Woods - Spike Corner Key Drop': [0x14001b, 0x14001c],
|
||||
'Thieves\' Town - Hallway Pot Key': [0x14005d, 0x14005e],
|
||||
'Thieves\' Town - Spike Switch Pot Key': [0x14004e, 0x14004f],
|
||||
'Ice Palace - Jelly Key Drop': [0x140003, 0x140004],
|
||||
'Ice Palace - Conveyor Key Drop': [0x140021, 0x140022],
|
||||
'Ice Palace - Hammer Block Key Drop': [0x140024, 0x140025],
|
||||
'Ice Palace - Many Pots Pot Key': [0x140045, 0x140046],
|
||||
'Misery Mire - Spikes Pot Key': [0x140054, 0x140055],
|
||||
'Misery Mire - Fishbone Pot Key': [0x14004b, 0x14004c],
|
||||
'Misery Mire - Conveyor Crystal Key Drop': [0x140063, 0x140064],
|
||||
'Turtle Rock - Pokey 1 Key Drop': [0x140057, 0x140058],
|
||||
'Turtle Rock - Pokey 2 Key Drop': [0x140006, 0x140007],
|
||||
'Ganons Tower - Conveyor Cross Pot Key': [0x14003f, 0x140040],
|
||||
'Ganons Tower - Double Switch Pot Key': [0x140042, 0x140043],
|
||||
'Ganons Tower - Conveyor Star Pits Pot Key': [0x140039, 0x14003a],
|
||||
'Ganons Tower - Mini Helmasaur Key Drop': [0x14001e, 0x14001f]
|
||||
}
|
||||
|
||||
location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'),
|
||||
'Bottle Merchant': (0x2eb18, 0x186339, False, 'with a merchant'),
|
||||
'Flute Spot': (0x18014a, 0x18633d, False, 'underground'),
|
||||
|
@ -640,7 +676,9 @@ location_table = {'Mushroom': (0x180013, 0x186338, False, 'in the woods'),
|
|||
[0x120A7, 0x53F24, 0x53F25, 0x18005C, 0x180079, 0xC708], None, True, 'Turtle Rock')}
|
||||
|
||||
lookup_id_to_name = {data[0]: name for name, data in location_table.items() if type(data[0]) == int}
|
||||
lookup_id_to_name[-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_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_vanilla_location_to_entrance = {1572883: 'Kings Grave Inner Rocks', 191256: 'Kings Grave Inner Rocks',
|
||||
1573194: 'Kings Grave Inner Rocks', 1573189: 'Kings Grave Inner Rocks',
|
||||
|
@ -745,7 +783,28 @@ lookup_vanilla_location_to_entrance = {1572883: 'Kings Grave Inner Rocks', 19125
|
|||
60103: 'Ganons Tower', 60106: 'Ganons Tower', 60109: 'Ganons Tower',
|
||||
60127: 'Ganons Tower', 60118: 'Ganons Tower', 60148: 'Ganons Tower',
|
||||
60151: 'Ganons Tower', 60145: 'Ganons Tower', 60157: 'Ganons Tower',
|
||||
60160: 'Ganons Tower', 60163: 'Ganons Tower', 60166: 'Ganons Tower'}
|
||||
60160: 'Ganons Tower', 60163: 'Ganons Tower', 60166: 'Ganons Tower',
|
||||
0x140037: 'Hyrule Castle Entrance (South)',
|
||||
0x140034: 'Hyrule Castle Entrance (South)',
|
||||
0x14000d: 'Hyrule Castle Entrance (South)',
|
||||
0x14003d: 'Hyrule Castle Entrance (South)',
|
||||
0x14005b: 'Eastern Palace', 0x140049: 'Eastern Palace',
|
||||
0x140031: 'Desert Palace Entrance (North)',
|
||||
0x14002b: 'Desert Palace Entrance (North)',
|
||||
0x140028: 'Desert Palace Entrance (North)',
|
||||
0x140061: 'Agahnims Tower', 0x140052: 'Agahnims Tower',
|
||||
0x140019: 'Swamp Palace', 0x140016: 'Swamp Palace', 0x140013: 'Swamp Palace',
|
||||
0x140010: 'Swamp Palace', 0x14000a: 'Swamp Palace',
|
||||
0x14002e: 'Skull Woods Second Section Door (East)',
|
||||
0x14001c: 'Skull Woods Final Section',
|
||||
0x14005e: 'Thieves Town', 0x14004f: 'Thieves Town',
|
||||
0x140004: 'Ice Palace', 0x140022: 'Ice Palace',
|
||||
0x140025: 'Ice Palace', 0x140046: 'Ice Palace',
|
||||
0x140055: 'Misery Mire', 0x14004c: 'Misery Mire',
|
||||
0x140064: 'Misery Mire',
|
||||
0x140058: 'Turtle Rock', 0x140007: 'Dark Death Mountain Ledge (West)',
|
||||
0x140040: 'Ganons Tower', 0x140043: 'Ganons Tower',
|
||||
0x14003a: 'Ganons Tower', 0x14001f: 'Ganons Tower'}
|
||||
|
||||
lookup_prizes = {location for location in location_table if location.endswith(" - Prize")}
|
||||
lookup_boss_drops = {location for location in location_table if location.endswith(" - Boss")}
|
|
@ -180,6 +180,25 @@ default_locations = {
|
|||
60121, 60124, 60127, 1573217, 60130, 60133, 60136, 60139, 60142, 60145, 60148, 60151, 60157},
|
||||
'Total': set()}
|
||||
|
||||
key_only_locations = {
|
||||
'Light World': set(),
|
||||
'Dark World': set(),
|
||||
'Desert Palace': {0x140031, 0x14002b, 0x140061, 0x140028},
|
||||
'Eastern Palace': {0x14005b, 0x140049},
|
||||
'Hyrule Castle': {0x140037, 0x140034, 0x14000d, 0x14003d},
|
||||
'Agahnims Tower': {0x140061, 0x140052},
|
||||
'Tower of Hera': set(),
|
||||
'Swamp Palace': {0x140019, 0x140016, 0x140013, 0x140010, 0x14000a},
|
||||
'Thieves Town': {0x14005e, 0x14004f},
|
||||
'Skull Woods': {0x14002e, 0x14001c},
|
||||
'Ice Palace': {0x140004, 0x140022, 0x140025, 0x140046},
|
||||
'Misery Mire': {0x140055, 0x14004c, 0x140064},
|
||||
'Turtle Rock': {0x140058, 0x140007},
|
||||
'Palace of Darkness': set(),
|
||||
'Ganons Tower': {0x140040, 0x140043, 0x14003a, 0x14001f},
|
||||
'Total': set()
|
||||
}
|
||||
|
||||
key_locations = {"Desert Palace", "Eastern Palace", "Hyrule Castle", "Agahnims Tower", "Tower of Hera", "Swamp Palace",
|
||||
"Thieves Town", "Skull Woods", "Ice Palace", "Misery Mire", "Turtle Rock", "Palace of Darkness",
|
||||
"Ganons Tower"}
|
||||
|
@ -191,6 +210,10 @@ for area, locations in default_locations.items():
|
|||
for location in locations:
|
||||
location_to_area[location] = area
|
||||
|
||||
for area, locations in key_only_locations.items():
|
||||
for location in locations:
|
||||
location_to_area[location] = area
|
||||
|
||||
checks_in_area = {area: len(checks) for area, checks in default_locations.items()}
|
||||
checks_in_area["Total"] = 216
|
||||
|
||||
|
@ -244,11 +267,16 @@ def get_static_room_data(room: Room):
|
|||
# in > 100 players this can take a bit of time and is the main reason for the cache
|
||||
locations = {tuple(k): tuple(v) for k, v in multidata['locations']}
|
||||
names = multidata["names"]
|
||||
seed_checks_in_area = checks_in_area.copy()
|
||||
|
||||
use_door_tracker = False
|
||||
if "tags" in multidata:
|
||||
use_door_tracker = "DR" in multidata["tags"]
|
||||
result = locations, names, use_door_tracker
|
||||
if use_door_tracker:
|
||||
for area, checks in key_only_locations.items():
|
||||
seed_checks_in_area[area] += len(checks)
|
||||
seed_checks_in_area["Total"] = 249
|
||||
result = locations, names, use_door_tracker, seed_checks_in_area
|
||||
_multidata_cache[room.seed.id] = result
|
||||
return result
|
||||
|
||||
|
@ -259,7 +287,7 @@ def get_tracker(tracker: UUID):
|
|||
room = Room.get(tracker=tracker)
|
||||
if not room:
|
||||
abort(404)
|
||||
locations, names, use_door_tracker = get_static_room_data(room)
|
||||
locations, names, use_door_tracker, seed_checks_in_area = get_static_room_data(room)
|
||||
|
||||
inventory = {teamnumber: {playernumber: collections.Counter() for playernumber in range(1, len(team) + 1)}
|
||||
for teamnumber, team in enumerate(names)}
|
||||
|
@ -280,6 +308,9 @@ def get_tracker(tracker: UUID):
|
|||
for item_id in precollected:
|
||||
attribute_item(inventory, team, player, item_id)
|
||||
for location in locations_checked:
|
||||
if (location, player) not in locations or location not in location_to_area:
|
||||
continue
|
||||
|
||||
item, recipient = locations[location, player]
|
||||
attribute_item(inventory, team, recipient, item)
|
||||
checks_done[team][player][location_to_area[location]] += 1
|
||||
|
@ -311,7 +342,7 @@ def get_tracker(tracker: UUID):
|
|||
lookup_id_to_name=Items.lookup_id_to_name, player_names=player_names,
|
||||
tracking_names=tracking_names, tracking_ids=tracking_ids, room=room, icons=icons,
|
||||
multi_items=multi_items, checks_done=checks_done, ordered_areas=ordered_areas,
|
||||
checks_in_area=checks_in_area, activity_timers=activity_timers,
|
||||
checks_in_area=seed_checks_in_area, activity_timers=activity_timers,
|
||||
key_locations=key_locations, small_key_ids=small_key_ids, big_key_ids=big_key_ids,
|
||||
video=video, big_key_locations=key_locations if use_door_tracker else big_key_locations,
|
||||
hints=hints, long_player_names = long_player_names)
|
||||
|
|
Loading…
Reference in New Issue