* Initial implementation of Yu-Gi-Oh! WC 2006 * Added Opponents and banlists * Initial implementation of Yu-Gi-Oh! WC 2006 * Added Opponents and banlists * Added Campaign Logic * Added Bonuses Logic * Added challenge logic * fixed yugioh client * ygo06 rom cleanup and include lua * ygo06 patch cleanup * ygo06 move client to world folder * lots of small changes * bug fixes * implemented filler item for yugioh06 * BizHawkClient: Add client and connector * BizHawkClient: Add launcher component and inno_setup lines * BizHawkClient: Misc stability updates and small improvements Bad commit organization a consequence of working with two different branches and not keeping the commits separated * BizHawkClient: Add docstrings * BizHawkClient: Pull in changes from other branch * BizHawkClient: Fix no handler message not displaying after changed ROMs * BizHawkClient: Remove extra print statement from lua * BizHawkClient: Change version command to use raw strings * BizHawkClient: Change script version to single integer * YGO06: added logic for "all expect type forbidden" limited duels * YGO06: Structure Deck choice now affects logic. Fixed a bug with tier 5 campaign opponents. Added logic for TD16 Union. * BizHawkClient: Add newline to version for lua script * BizHawkClient: Call send_connect from BizHawkClient's watcher loop * BizHawkClient: Add handling for failed request getting script version * BizHawkClient: Have base64.lua check lua version explicitly for bit operations On 2.9, it would detect LuaJIT and flood the console with deprecation warnings * BizHawkClient: Update connector script for slightly better errors and address Gambatte frame sync issue * BizHawkClient: Remove accidentally added print statements * BizHawkClient: Fix connector server not closing correctly * BizHawkClient: Move some connector code around, some linting * BizHawkClient: Small cleanup in lua * BizHawkClient: Lua linting * BizHawkClient: Remove outdated sentences in docstrings * YGO06: Logic additions and bug fixes * BizHawkClient: Correctly null check patch file arg * BizHawkClient: Initialize logging * BizHawkClient: Move code to worlds/_bizhawk Also splits out BizHawk communication functions to their own file for use outside this client * BizHawkClient: Add license to connector lua, add types to docs * BizHawkClient: Add module docstrings * YGO06: Logic additions * BizHawkClient: Allow clients to define multiple systems * BizHawkClient: Better logging and handling of interruptions to connection to script * YGO06: Logic additions * YGO06: Added text to options * YGO06: Ported to bizhawk client * YGO06: fix goal not being detected * YGO06: fix access item rule for tier 5 column 1 and 2 * YGO06: docu and bug fixes * YGO06: change name * YGO06: some fixes * YGO06: fix starting opponent and booster not applying * YGO06: added option to reduce the amount of challenges and remove the no ban list from pool. * YGO06: added rom being asked for on first use * YGO06: fix rules for challenges * YGO06: create proper rules for TD04 Ritual Summon * YGO06: mark most banlists as usefull instead of progression * YGO06: reduce the required core boosters across the board * YGO06: fix client not loading if another game already loaded the bizhawk client * YGO06: fix client not finding the bizhawk client. * YGO06: fix TD08 Draw not giving out an item * YGO06: small text changes * YGO06: update to version 0.4.4 * YGO06: logic mixin clean-up * YGO06: added option for campaign opponents as goal * Pokemon Emerald add encounter table randomization * Pokemon Emerald: Item ball randomization working * Pokemon Emerald: Clean up code a little * Pokemon Emerald: Partial rework of region/location creation * Pokemon Emerald: Dedupe items and add more readable names * Refactor region creation to manually defined regions * Split region json * Use new data.json with flattened constants and add HM locations * YGO06: bug fixes * YGO06: bug fix * YGO06: changes default options to be more beginner friendly * YGO06: attempt at universal tracker support. Settings are stored in slot data now. * YGO06: fix for older python versions * YGO06: fix slot data * YGO06: added diiferent opponents to the campaign * YGO06: fix small bug with opponent icons * YGO06: fix unwanted changes * YGO06: repair merge with main * YGO06: map out all of the opponents * YGO06: added opponent shuffle * YGO06: added logic to opponent shuffle * YGO06: added option to use ocg art * YGO06: bug_fixes * YGO06: removed todos, since they are not needed anymore * YGO06: added draft mode * YGO06: added logic to draft mode * YGO06: Added Money multiplier when you lose * YGO06: Fixed Unit Test errors * YGO06: Added Random deck option * YGO06: Bug fix with registering client * YGO06: client clean-up * YGO06: fixed card misspellings * YGO06: removed unused imports and other small changes * YGO06: small changes * YGO06: fix generation error when the combination of starting with "No Banlist" and not adding "No Banlist" to the pool is selected * YGO06: fix ocg art path overwriting Huge Revolution bugfix * YGO06: added comments and other minor changes * YGO06: fixed byte length in client for money * YGO06: fixes for webhost and options * YGO06: use the proper random function * YGO06: change settings to options * YGO06: move to procedure patch * YGO06: fix imports * YGO06: fix download link for patch not showing * YGO06: remove unnecessary Optional * YGO06: fix universal tracker stuff * YGO06: add typings * YGO06: small cleanup * yugioh06: small change to setup Co-authored-by: Scipio Wright <scipiowright@gmail.com> * YGO06: remove logic mixin * YGO06: fix create item and implement create filler and get filler item name * YGO06: remove double lambdas * YGO06: use pkgutil.get_data instaed pf zipFile * YGO06: fix starting items being duplicated * YGO06: lots of small changes * YGO06: moved functions to match execution order * YGO06: run ruff * YGO06: run ruff format * YGO06: fix ruff errors * YGO06: undo ruff format for rules * YGO06: move import to prevent circular dependency * YGO06: remove unused class * YGO06: optimizing rules * YGO06: some optimization and small bug fix --------- Co-authored-by: Zunawe <gyroscope15@gmail.com> Co-authored-by: Scipio Wright <scipiowright@gmail.com>
		
			
				
	
	
		
			140 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import math
 | 
						|
from typing import TYPE_CHECKING, List, Optional, Set
 | 
						|
 | 
						|
from NetUtils import ClientStatus, NetworkItem
 | 
						|
 | 
						|
import worlds._bizhawk as bizhawk
 | 
						|
from worlds._bizhawk.client import BizHawkClient
 | 
						|
from worlds.yugioh06 import item_to_index
 | 
						|
 | 
						|
if TYPE_CHECKING:
 | 
						|
    from worlds._bizhawk.context import BizHawkClientContext
 | 
						|
 | 
						|
 | 
						|
class YuGiOh2006Client(BizHawkClient):
 | 
						|
    game = "Yu-Gi-Oh! 2006"
 | 
						|
    system = "GBA"
 | 
						|
    patch_suffix = ".apygo06"
 | 
						|
    local_checked_locations: Set[int]
 | 
						|
    goal_flag: int
 | 
						|
    rom_slot_name: Optional[str]
 | 
						|
 | 
						|
    def __init__(self) -> None:
 | 
						|
        super().__init__()
 | 
						|
        self.local_checked_locations = set()
 | 
						|
        self.rom_slot_name = None
 | 
						|
 | 
						|
    async def validate_rom(self, ctx: "BizHawkClientContext") -> bool:
 | 
						|
        from CommonClient import logger
 | 
						|
 | 
						|
        try:
 | 
						|
            # Check if ROM is some version of Yu-Gi-Oh! 2006
 | 
						|
            game_name = ((await bizhawk.read(ctx.bizhawk_ctx, [(0xA0, 11, "ROM")]))[0]).decode("ascii")
 | 
						|
            if game_name != "YUGIOHWCT06":
 | 
						|
                return False
 | 
						|
 | 
						|
            # Check if we can read the slot name. Doing this here instead of set_auth as a protection against
 | 
						|
            # validating a ROM where there's no slot name to read.
 | 
						|
            try:
 | 
						|
                slot_name_bytes = (await bizhawk.read(ctx.bizhawk_ctx, [(0x30, 32, "ROM")]))[0]
 | 
						|
                self.rom_slot_name = bytes([byte for byte in slot_name_bytes if byte != 0]).decode("utf-8")
 | 
						|
            except UnicodeDecodeError:
 | 
						|
                logger.info("Could not read slot name from ROM. Are you sure this ROM matches this client version?")
 | 
						|
                return False
 | 
						|
        except UnicodeDecodeError:
 | 
						|
            return False
 | 
						|
        except bizhawk.RequestFailedError:
 | 
						|
            return False  # Should verify on the next pass
 | 
						|
 | 
						|
        ctx.game = self.game
 | 
						|
        ctx.items_handling = 0b001
 | 
						|
        ctx.want_slot_data = False
 | 
						|
        return True
 | 
						|
 | 
						|
    async def set_auth(self, ctx: "BizHawkClientContext") -> None:
 | 
						|
        ctx.auth = self.rom_slot_name
 | 
						|
 | 
						|
    async def game_watcher(self, ctx: "BizHawkClientContext") -> None:
 | 
						|
        try:
 | 
						|
            read_state = await bizhawk.read(
 | 
						|
                ctx.bizhawk_ctx,
 | 
						|
                [
 | 
						|
                    (0x0, 8, "EWRAM"),
 | 
						|
                    (0x52E8, 32, "EWRAM"),
 | 
						|
                    (0x5308, 32, "EWRAM"),
 | 
						|
                    (0x5325, 1, "EWRAM"),
 | 
						|
                    (0x6C38, 4, "EWRAM"),
 | 
						|
                ],
 | 
						|
            )
 | 
						|
            game_state = read_state[0].decode("utf-8")
 | 
						|
            locations = read_state[1]
 | 
						|
            items = read_state[2]
 | 
						|
            amount_items = int.from_bytes(read_state[3], "little")
 | 
						|
            money = int.from_bytes(read_state[4], "little")
 | 
						|
 | 
						|
            # make sure save was created
 | 
						|
            if game_state != "YWCT2006":
 | 
						|
                return
 | 
						|
            local_items = bytearray(items)
 | 
						|
            await bizhawk.guarded_write(
 | 
						|
                ctx.bizhawk_ctx,
 | 
						|
                [(0x5308, parse_items(bytearray(items), ctx.items_received), "EWRAM")],
 | 
						|
                [(0x5308, local_items, "EWRAM")],
 | 
						|
            )
 | 
						|
            money_received = 0
 | 
						|
            for item in ctx.items_received:
 | 
						|
                if item.item == item_to_index["5000DP"] + 5730000:
 | 
						|
                    money_received += 1
 | 
						|
            if money_received > amount_items:
 | 
						|
                await bizhawk.guarded_write(
 | 
						|
                    ctx.bizhawk_ctx,
 | 
						|
                    [
 | 
						|
                        (0x6C38, (money + (money_received - amount_items) * 5000).to_bytes(4, "little"), "EWRAM"),
 | 
						|
                        (0x5325, money_received.to_bytes(2, "little"), "EWRAM"),
 | 
						|
                    ],
 | 
						|
                    [
 | 
						|
                        (0x6C38, money.to_bytes(4, "little"), "EWRAM"),
 | 
						|
                        (0x5325, amount_items.to_bytes(2, "little"), "EWRAM"),
 | 
						|
                    ],
 | 
						|
                )
 | 
						|
 | 
						|
            locs_to_send = set()
 | 
						|
 | 
						|
            # Check for set location flags.
 | 
						|
            for byte_i, byte in enumerate(bytearray(locations)):
 | 
						|
                for i in range(8):
 | 
						|
                    and_value = 1 << i
 | 
						|
                    if byte & and_value != 0:
 | 
						|
                        flag_id = byte_i * 8 + i
 | 
						|
 | 
						|
                        location_id = flag_id + 5730001
 | 
						|
                        if location_id in ctx.server_locations:
 | 
						|
                            locs_to_send.add(location_id)
 | 
						|
 | 
						|
            # Send locations if there are any to send.
 | 
						|
            if locs_to_send != self.local_checked_locations:
 | 
						|
                self.local_checked_locations = locs_to_send
 | 
						|
 | 
						|
                if locs_to_send is not None:
 | 
						|
                    await ctx.send_msgs([{"cmd": "LocationChecks", "locations": list(locs_to_send)}])
 | 
						|
 | 
						|
            # Send game clear if we're in either any ending cutscene or the credits state.
 | 
						|
            if not ctx.finished_game and locations[18] & (1 << 5) != 0:
 | 
						|
                await ctx.send_msgs([{"cmd": "StatusUpdate", "status": ClientStatus.CLIENT_GOAL}])
 | 
						|
 | 
						|
        except bizhawk.RequestFailedError:
 | 
						|
            # Exit handler and return to main loop to reconnect.
 | 
						|
            pass
 | 
						|
 | 
						|
 | 
						|
# Parses bit-map for local items and adds the received items to that bit-map
 | 
						|
def parse_items(local_items: bytearray, items: List[NetworkItem]) -> bytearray:
 | 
						|
    array = local_items
 | 
						|
    for item in items:
 | 
						|
        index = item.item - 5730001
 | 
						|
        if index != 254:
 | 
						|
            byte = math.floor(index / 8)
 | 
						|
            bit = index % 8
 | 
						|
            array[byte] = array[byte] | (1 << bit)
 | 
						|
    return array
 |