Mark LttP items as collected in game if item is not owned by player.
This commit is contained in:
parent
c204fb9b14
commit
2c884e2ca5
82
SNIClient.py
82
SNIClient.py
|
@ -171,6 +171,16 @@ class Context(CommonContext):
|
|||
if not currently_dead:
|
||||
self.death_state = DeathState.alive
|
||||
|
||||
def on_package(self, cmd: str, args: dict):
|
||||
if cmd in {"Connected", "RoomUpdate"}:
|
||||
if "checked_locations" in args and args["checked_locations"]:
|
||||
new_locations = set(args["checked_locations"])
|
||||
self.checked_locations |= new_locations
|
||||
self.locations_scouted |= new_locations
|
||||
# Items belonging to the player should not be marked as checked in game, since the player will likely need that item.
|
||||
# Once the games handled by SNIClient gets made to be remote items, this will no longer be needed.
|
||||
asyncio.create_task(self.send_msgs([{"cmd": "LocationScouts", "locations": list(new_locations)}]))
|
||||
|
||||
|
||||
async def deathlink_kill_player(ctx: Context):
|
||||
ctx.death_state = DeathState.killing_player
|
||||
|
@ -239,6 +249,7 @@ 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
|
||||
SHOP_LEN = (len(Shops.shop_table) * 3) + 5
|
||||
|
||||
DEATH_LINK_ACTIVE_ADDR = ROMNAME_START + 0x15 # 1 byte
|
||||
|
||||
|
@ -820,19 +831,28 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
|||
f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})')
|
||||
|
||||
try:
|
||||
if roomid in location_shop_ids:
|
||||
misc_data = await snes_read(ctx, SHOP_ADDR, (len(Shops.shop_table) * 3) + 5)
|
||||
for cnt, b in enumerate(misc_data):
|
||||
if int(b) and (Shops.SHOP_ID_START + cnt) not in ctx.locations_checked:
|
||||
new_check(Shops.SHOP_ID_START + cnt)
|
||||
shop_data = await snes_read(ctx, SHOP_ADDR, SHOP_LEN)
|
||||
shop_data_changed = False
|
||||
shop_data = list(shop_data)
|
||||
for cnt, b in enumerate(shop_data):
|
||||
location = Shops.SHOP_ID_START + cnt
|
||||
if int(b) and location not in ctx.locations_checked:
|
||||
new_check(location)
|
||||
if location in ctx.checked_locations and location not in ctx.locations_checked \
|
||||
and location in ctx.locations_info and ctx.locations_info[location][1] != ctx.slot:
|
||||
if not int(b):
|
||||
shop_data[cnt] += 1
|
||||
shop_data_changed = True
|
||||
new_check(location)
|
||||
if shop_data_changed:
|
||||
snes_buffered_write(ctx, SHOP_ADDR, bytes(shop_data))
|
||||
except Exception as e:
|
||||
snes_logger.info(f"Exception: {e}")
|
||||
|
||||
for location_id, (loc_roomid, loc_mask) in location_table_uw_id.items():
|
||||
try:
|
||||
|
||||
if location_id not in ctx.locations_checked and loc_roomid == roomid and (
|
||||
roomdata << 4) & loc_mask != 0:
|
||||
if location_id not in ctx.locations_checked and loc_roomid == roomid and \
|
||||
(roomdata << 4) & loc_mask != 0:
|
||||
new_check(location_id)
|
||||
except Exception as e:
|
||||
snes_logger.exception(f"Exception: {e}")
|
||||
|
@ -840,12 +860,18 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
|||
uw_begin = 0x129
|
||||
ow_end = uw_end = 0
|
||||
uw_unchecked = {}
|
||||
uw_checked = {}
|
||||
for location, (roomid, mask) in location_table_uw.items():
|
||||
location_id = Regions.lookup_name_to_id[location]
|
||||
if location_id not in ctx.locations_checked:
|
||||
uw_unchecked[location_id] = (roomid, mask)
|
||||
uw_begin = min(uw_begin, roomid)
|
||||
uw_end = max(uw_end, roomid + 1)
|
||||
if location_id in ctx.checked_locations and location_id not in ctx.locations_checked and \
|
||||
location_id in ctx.locations_info and ctx.locations_info[location_id][1] != ctx.slot:
|
||||
uw_begin = min(uw_begin, roomid)
|
||||
uw_end = max(uw_end, roomid + 1)
|
||||
uw_checked[location_id] = (roomid, mask)
|
||||
|
||||
if uw_begin < uw_end:
|
||||
uw_data = await snes_read(ctx, SAVEDATA_START + (uw_begin * 2), (uw_end - uw_begin) * 2)
|
||||
|
@ -855,14 +881,28 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
|||
roomdata = uw_data[offset] | (uw_data[offset + 1] << 8)
|
||||
if roomdata & mask != 0:
|
||||
new_check(location_id)
|
||||
if uw_checked:
|
||||
uw_data = list(uw_data)
|
||||
for location_id, (roomid, mask) in uw_checked.items():
|
||||
offset = (roomid - uw_begin) * 2
|
||||
roomdata = uw_data[offset] | (uw_data[offset + 1] << 8)
|
||||
roomdata |= mask
|
||||
uw_data[offset] = roomdata & 0xFF
|
||||
uw_data[offset + 1] = roomdata >> 8
|
||||
new_check(location_id)
|
||||
snes_buffered_write(ctx, SAVEDATA_START + (uw_begin * 2), bytes(uw_data))
|
||||
|
||||
ow_begin = 0x82
|
||||
ow_unchecked = {}
|
||||
ow_checked = {}
|
||||
for location_id, screenid in location_table_ow_id.items():
|
||||
if location_id not in ctx.locations_checked:
|
||||
ow_unchecked[location_id] = screenid
|
||||
ow_begin = min(ow_begin, screenid)
|
||||
ow_end = max(ow_end, screenid + 1)
|
||||
if location_id is ctx.checked_locations and location_id in ctx.locations_info \
|
||||
and ctx.locations_info[location_id][1] != ctx.slot:
|
||||
ow_checked[location_id] = screenid
|
||||
|
||||
if ow_begin < ow_end:
|
||||
ow_data = await snes_read(ctx, SAVEDATA_START + 0x280 + ow_begin, ow_end - ow_begin)
|
||||
|
@ -870,25 +910,50 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
|||
for location_id, screenid in ow_unchecked.items():
|
||||
if ow_data[screenid - ow_begin] & 0x40 != 0:
|
||||
new_check(location_id)
|
||||
if ow_checked:
|
||||
ow_data = list(ow_data)
|
||||
for location_id, screenid in ow_checked.items():
|
||||
ow_data[screenid - ow_begin] |= 0x40
|
||||
snes_buffered_write(ctx, SAVEDATA_START + 0x280 + ow_begin, bytes(ow_data))
|
||||
|
||||
if not ctx.locations_checked.issuperset(location_table_npc_id):
|
||||
npc_data = await snes_read(ctx, SAVEDATA_START + 0x410, 2)
|
||||
if npc_data is not None:
|
||||
npc_value_changed = False
|
||||
npc_value = npc_data[0] | (npc_data[1] << 8)
|
||||
for location_id, mask in location_table_npc_id.items():
|
||||
if npc_value & mask != 0 and location_id not in ctx.locations_checked:
|
||||
new_check(location_id)
|
||||
if location_id in ctx.checked_locations and location_id not in ctx.locations_checked \
|
||||
and location_id in ctx.locations_info and ctx.locations_info[location_id][1] != ctx.slot:
|
||||
new_check(location_id)
|
||||
npc_value |= mask
|
||||
npc_value_changed = True
|
||||
if npc_value_changed:
|
||||
npc_data = bytes([npc_value & 0xFF, npc_value >> 8])
|
||||
snes_buffered_write(ctx, SAVEDATA_START + 0x410, npc_data)
|
||||
|
||||
if not ctx.locations_checked.issuperset(location_table_misc_id):
|
||||
misc_data = await snes_read(ctx, SAVEDATA_START + 0x3c6, 4)
|
||||
if misc_data is not None:
|
||||
misc_data = list(misc_data)
|
||||
misc_data_changed = False
|
||||
for location_id, (offset, mask) in location_table_misc_id.items():
|
||||
assert (0x3c6 <= offset <= 0x3c9)
|
||||
if misc_data[offset - 0x3c6] & mask != 0 and location_id not in ctx.locations_checked:
|
||||
new_check(location_id)
|
||||
if location_id in ctx.checked_locations and location_id not in ctx.locations_checked \
|
||||
and location_id in ctx.locations_info and ctx.locations_info[location_id][1] != ctx.slot:
|
||||
misc_data_changed = True
|
||||
misc_data[offset - 0x3c6] |= mask
|
||||
new_check(location_id)
|
||||
if misc_data_changed:
|
||||
snes_buffered_write(ctx, SAVEDATA_START + 0x3c6, bytes(misc_data))
|
||||
|
||||
|
||||
if new_locations:
|
||||
await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": new_locations}])
|
||||
await snes_flush_writes(ctx)
|
||||
|
||||
|
||||
async def game_watcher(ctx: Context):
|
||||
|
@ -927,6 +992,7 @@ async def game_watcher(ctx: Context):
|
|||
if not ctx.prev_rom or ctx.prev_rom != ctx.rom:
|
||||
ctx.locations_checked = set()
|
||||
ctx.locations_scouted = set()
|
||||
ctx.locations_info = {}
|
||||
ctx.prev_rom = ctx.rom
|
||||
|
||||
if ctx.awaiting_rom:
|
||||
|
|
Loading…
Reference in New Issue