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:
|
if not currently_dead:
|
||||||
self.death_state = DeathState.alive
|
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):
|
async def deathlink_kill_player(ctx: Context):
|
||||||
ctx.death_state = DeathState.killing_player
|
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_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
|
SHOP_ADDR = SAVEDATA_START + 0x302 # 2 bytes
|
||||||
|
SHOP_LEN = (len(Shops.shop_table) * 3) + 5
|
||||||
|
|
||||||
DEATH_LINK_ACTIVE_ADDR = ROMNAME_START + 0x15 # 1 byte
|
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)})')
|
f'New Check: {location} ({len(ctx.locations_checked)}/{len(ctx.missing_locations) + len(ctx.checked_locations)})')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if roomid in location_shop_ids:
|
shop_data = await snes_read(ctx, SHOP_ADDR, SHOP_LEN)
|
||||||
misc_data = await snes_read(ctx, SHOP_ADDR, (len(Shops.shop_table) * 3) + 5)
|
shop_data_changed = False
|
||||||
for cnt, b in enumerate(misc_data):
|
shop_data = list(shop_data)
|
||||||
if int(b) and (Shops.SHOP_ID_START + cnt) not in ctx.locations_checked:
|
for cnt, b in enumerate(shop_data):
|
||||||
new_check(Shops.SHOP_ID_START + cnt)
|
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:
|
except Exception as e:
|
||||||
snes_logger.info(f"Exception: {e}")
|
snes_logger.info(f"Exception: {e}")
|
||||||
|
|
||||||
for location_id, (loc_roomid, loc_mask) in location_table_uw_id.items():
|
for location_id, (loc_roomid, loc_mask) in location_table_uw_id.items():
|
||||||
try:
|
try:
|
||||||
|
if location_id not in ctx.locations_checked and loc_roomid == roomid and \
|
||||||
if location_id not in ctx.locations_checked and loc_roomid == roomid and (
|
(roomdata << 4) & loc_mask != 0:
|
||||||
roomdata << 4) & loc_mask != 0:
|
|
||||||
new_check(location_id)
|
new_check(location_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
snes_logger.exception(f"Exception: {e}")
|
snes_logger.exception(f"Exception: {e}")
|
||||||
|
@ -840,12 +860,18 @@ async def track_locations(ctx: Context, roomid, roomdata):
|
||||||
uw_begin = 0x129
|
uw_begin = 0x129
|
||||||
ow_end = uw_end = 0
|
ow_end = uw_end = 0
|
||||||
uw_unchecked = {}
|
uw_unchecked = {}
|
||||||
|
uw_checked = {}
|
||||||
for location, (roomid, mask) in location_table_uw.items():
|
for location, (roomid, mask) in location_table_uw.items():
|
||||||
location_id = Regions.lookup_name_to_id[location]
|
location_id = Regions.lookup_name_to_id[location]
|
||||||
if location_id not in ctx.locations_checked:
|
if location_id not in ctx.locations_checked:
|
||||||
uw_unchecked[location_id] = (roomid, mask)
|
uw_unchecked[location_id] = (roomid, mask)
|
||||||
uw_begin = min(uw_begin, roomid)
|
uw_begin = min(uw_begin, roomid)
|
||||||
uw_end = max(uw_end, roomid + 1)
|
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:
|
if uw_begin < uw_end:
|
||||||
uw_data = await snes_read(ctx, SAVEDATA_START + (uw_begin * 2), (uw_end - uw_begin) * 2)
|
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)
|
roomdata = uw_data[offset] | (uw_data[offset + 1] << 8)
|
||||||
if roomdata & mask != 0:
|
if roomdata & mask != 0:
|
||||||
new_check(location_id)
|
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_begin = 0x82
|
||||||
ow_unchecked = {}
|
ow_unchecked = {}
|
||||||
|
ow_checked = {}
|
||||||
for location_id, screenid in location_table_ow_id.items():
|
for location_id, screenid in location_table_ow_id.items():
|
||||||
if location_id not in ctx.locations_checked:
|
if location_id not in ctx.locations_checked:
|
||||||
ow_unchecked[location_id] = screenid
|
ow_unchecked[location_id] = screenid
|
||||||
ow_begin = min(ow_begin, screenid)
|
ow_begin = min(ow_begin, screenid)
|
||||||
ow_end = max(ow_end, screenid + 1)
|
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:
|
if ow_begin < ow_end:
|
||||||
ow_data = await snes_read(ctx, SAVEDATA_START + 0x280 + ow_begin, ow_end - ow_begin)
|
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():
|
for location_id, screenid in ow_unchecked.items():
|
||||||
if ow_data[screenid - ow_begin] & 0x40 != 0:
|
if ow_data[screenid - ow_begin] & 0x40 != 0:
|
||||||
new_check(location_id)
|
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):
|
if not ctx.locations_checked.issuperset(location_table_npc_id):
|
||||||
npc_data = await snes_read(ctx, SAVEDATA_START + 0x410, 2)
|
npc_data = await snes_read(ctx, SAVEDATA_START + 0x410, 2)
|
||||||
if npc_data is not None:
|
if npc_data is not None:
|
||||||
|
npc_value_changed = False
|
||||||
npc_value = npc_data[0] | (npc_data[1] << 8)
|
npc_value = npc_data[0] | (npc_data[1] << 8)
|
||||||
for location_id, mask in location_table_npc_id.items():
|
for location_id, mask in location_table_npc_id.items():
|
||||||
if npc_value & mask != 0 and location_id not in ctx.locations_checked:
|
if npc_value & mask != 0 and location_id not in ctx.locations_checked:
|
||||||
new_check(location_id)
|
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):
|
if not ctx.locations_checked.issuperset(location_table_misc_id):
|
||||||
misc_data = await snes_read(ctx, SAVEDATA_START + 0x3c6, 4)
|
misc_data = await snes_read(ctx, SAVEDATA_START + 0x3c6, 4)
|
||||||
if misc_data is not None:
|
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():
|
for location_id, (offset, mask) in location_table_misc_id.items():
|
||||||
assert (0x3c6 <= offset <= 0x3c9)
|
assert (0x3c6 <= offset <= 0x3c9)
|
||||||
if misc_data[offset - 0x3c6] & mask != 0 and location_id not in ctx.locations_checked:
|
if misc_data[offset - 0x3c6] & mask != 0 and location_id not in ctx.locations_checked:
|
||||||
new_check(location_id)
|
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:
|
if new_locations:
|
||||||
await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": new_locations}])
|
await ctx.send_msgs([{"cmd": 'LocationChecks', "locations": new_locations}])
|
||||||
|
await snes_flush_writes(ctx)
|
||||||
|
|
||||||
|
|
||||||
async def game_watcher(ctx: Context):
|
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:
|
if not ctx.prev_rom or ctx.prev_rom != ctx.rom:
|
||||||
ctx.locations_checked = set()
|
ctx.locations_checked = set()
|
||||||
ctx.locations_scouted = set()
|
ctx.locations_scouted = set()
|
||||||
|
ctx.locations_info = {}
|
||||||
ctx.prev_rom = ctx.rom
|
ctx.prev_rom = ctx.rom
|
||||||
|
|
||||||
if ctx.awaiting_rom:
|
if ctx.awaiting_rom:
|
||||||
|
|
Loading…
Reference in New Issue