Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions worlds/tmc/Client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

from NetUtils import ClientStatus
import worlds._bizhawk as bizhawk
import Utils
from worlds._bizhawk.client import BizHawkClient
from Options import Toggle
from .Locations import all_locations, LocationData, events
from .Items import items_by_id

Expand Down Expand Up @@ -120,6 +122,20 @@ async def game_watcher(self, ctx: "BizHawkClientContext") -> None:
if ctx.server is None or ctx.server.socket.closed or ctx.slot_data is None:
return

if ctx.slot_data["remote_items"] == Toggle.option_true and not ctx.items_handling & 0b010:
ctx.items_handling = 0b011
Utils.async_start(ctx.send_msgs([{
"cmd": "ConnectUpdate",
"items_handling": ctx.items_handling
}]))

# Need to make sure items handling updates and we get the correct list of received items
# before continuing. Otherwise we might give some duplicate items and skip others.
# Should patch remote_items option value into the ROM in the future to guarantee we get the
# right item list before entering this part of the code
await asyncio.sleep(0.75)
return

try:
if ctx.seed_name is None:
return
Expand Down
9 changes: 9 additions & 0 deletions worlds/tmc/Options.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ class DeathLinkGameover(Toggle):
"""
display_name = "Deathlink is Gameover"

class RemoteItems(Toggle):
"""
Should all randomized items be handled through AP? This will require a connection to a server during all gameplay.
If you crash or lose your savefile, all items should be sent back to you.
When finding items placed in world, your items will use the remote item sprite instead of their usual sprite.
"""
display_name = "Remote Items"

@dataclass
class MinishCapOptions(PerGameCommonOptions):
start_inventory_from_pool: StartInventoryPool
Expand All @@ -182,6 +190,7 @@ class MinishCapOptions(PerGameCommonOptions):
dungeon_big_keys: BigKeys
dungeon_maps: DungeonMaps
dungeon_compasses: DungeonCompasses
remote_items: RemoteItems

def get_option_data(options: MinishCapOptions):
"""
Expand Down
10 changes: 9 additions & 1 deletion worlds/tmc/Rom.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ def write_tokens(world: "MinishCapWorld", patch: MinishCapProcedurePatch) -> Non
# Bake seed name into ROM
patch.write_token(APTokenTypes.WRITE, 0x000620, world.multiworld.seed_name.encode("UTF-8"))

if world.options.remote_items.value:
# Write remote items flag, causes the remote item pickup to be skipped.
# Otherwise it would cause the pickup animation will play twice, once for the remote item, then the actual item.
patch.write_token(APTokenTypes.WRITE, 0x000710, bytes([0x01]))
# Skip chest opening delay, required otherwise the player's input is awkwardly locked in front of chests with
# remote items in them... all of them
patch.write_token(APTokenTypes.WRITE, 0x0A74E2, bytes([0x00, 0x20, 0x00, 0x20]))

# Patch Items into Locations
for location_name, loc in location_table_by_name.items():
if loc.rom_addr is None:
Expand All @@ -58,7 +66,7 @@ def item_inject(world: "MinishCapWorld", patch: MinishCapProcedurePatch, locatio
item_byte_first = 0x00
item_byte_second = 0x00

if item.player == world.player:
if item.player == world.player and not world.options.remote_items.value:
# The item belongs to this player's world, it should use local item ids
item_byte_first = item_table[item.name].byte_ids[0]
item_byte_second = item_table[item.name].byte_ids[1]
Expand Down
2 changes: 1 addition & 1 deletion worlds/tmc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def fill_slot_data(self) -> Dict[str, any]:
"GoalVaati": self.options.goal_vaati.value,
}
data |= self.options.as_dict("death_link", "death_link_gameover", "rupeesanity", "obscure_spots", "goal_vaati",
"dungeon_small_keys", "dungeon_big_keys", "dungeon_compasses", "dungeon_maps",
"dungeon_small_keys", "dungeon_big_keys", "dungeon_compasses", "dungeon_maps", "remote_items",
casing="snake")
data |= get_option_data(self.options)
# If Element location should be known, add locations to slot data for tracker
Expand Down
Binary file modified worlds/tmc/data/basepatch.bsdiff
Binary file not shown.
Loading