Files
Grinch-AP/worlds/yugioh06/client_bh.py
Rensen3 539ee1c5da Yu-Gi-oh! 2006: implement new game (#2795)
* 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>
2024-05-17 19:23:05 +02:00

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