Various code changes that handles unlimited rotten eggs option, checks no longer sending during demo/main menu, have certain items, if set to true in Items.py, to add/remove instead of setting, and logs to display when you are in BIOS and you need to wait a bit.

This commit is contained in:
MarioSpore
2025-08-14 00:23:40 -04:00
parent 922232264d
commit 044fdaa717
2 changed files with 56 additions and 12 deletions

View File

@@ -1,9 +1,11 @@
import asyncio
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from .Locations import grinch_locations from .Locations import grinch_locations
from .Items import ALL_ITEMS_TABLE from .Items import ALL_ITEMS_TABLE
import worlds._bizhawk as bizhawk import worlds._bizhawk as bizhawk
from worlds._bizhawk.client import BizHawkClient from worlds._bizhawk.client import BizHawkClient
from worlds.Files import APDeltaPatch from worlds.Files import APDeltaPatch
if TYPE_CHECKING: if TYPE_CHECKING:
from worlds._bizhawk.context import BizHawkClientContext from worlds._bizhawk.context import BizHawkClientContext
from CommonClient import logger from CommonClient import logger
@@ -14,35 +16,49 @@ class GrinchClient(BizHawkClient):
system = "PSX" system = "PSX"
patch_suffix = ".apgrinch" patch_suffix = ".apgrinch"
items_handling = 0b111 items_handling = 0b111
last_received_index = 0
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.last_received_index = 0
self.loading_bios_msg = False
self.loc_unlimited_eggs = False
async def validate_rom(self, ctx: "BizHawkClientContext") -> bool: async def validate_rom(self, ctx: "BizHawkClientContext") -> bool:
from CommonClient import logger from CommonClient import logger
# TODO Check the ROM data to see if it matches against bytes expected # TODO Check the ROM data to see if it matches against bytes expected
grinch_identifier_ram_address: int = 0x00928C grinch_identifier_ram_address: int = 0x00928C
bytes_expected: bytes = bytes.fromhex("e903c14f4becf89082f43ec936a68e62") bios_identifier_ram_address: int = 0x097F30
try: try:
bytes_actual: bytes = (await bizhawk.read(ctx.bizhawk_ctx, [( bytes_actual: bytes = (await bizhawk.read(ctx.bizhawk_ctx, [(
grinch_identifier_ram_address, 11, "MainRAM")]))[0] grinch_identifier_ram_address, 11, "MainRAM")]))[0]
psx_rom_name = bytes_actual.decode("ascii") psx_rom_name = bytes_actual.decode("ascii")
if psx_rom_name != "SLUS_011.97": if psx_rom_name != "SLUS_011.97":
bios_bytes_check: bytes = (await bizhawk.read(ctx.bizhawk_ctx, [(
bios_identifier_ram_address, 24, "MainRAM")]))[0]
if "System ROM Version" in bios_bytes_check.decode("ascii"):
if not self.loading_bios_msg:
self.loading_bios_msg = True
logger.error("BIOS is currently loading. Will wait up to 5 seconds before retrying.")
return False
logger.error("Invalid rom detected. You are not playing Grinch USA Version.") logger.error("Invalid rom detected. You are not playing Grinch USA Version.")
raise Exception("Invalid rom detected. You are not playing Grinch USA Version.") raise Exception("Invalid rom detected. You are not playing Grinch USA Version.")
except Exception(): except Exception:
return False return False
ctx.game = self.game ctx.game = self.game
ctx.items_handling = self.items_handling ctx.items_handling = self.items_handling
ctx.want_slot_data = True ctx.want_slot_data = True
ctx.watcher_timeout = 0.125 ctx.watcher_timeout = 0.125
self.loading_bios_msg = False
return True return True
async def on_package(self, ctx: "BizHawkClientContext", cmd: str, args: dict) -> None:
self.loc_unlimited_eggs = bool(ctx.slot_data["give_unlimited_eggs"])
async def set_auth(self, ctx: "BizHawkClientContext") -> None: async def set_auth(self, ctx: "BizHawkClientContext") -> None:
await ctx.get_username() await ctx.get_username()
@@ -52,6 +68,8 @@ class GrinchClient(BizHawkClient):
return return
try: try:
if not self.ingame_checker(ctx):
return
# # Read save data # # Read save data
# save_data = await bizhawk.read( # save_data = await bizhawk.read(
# ctx.bizhawk_ctx, # ctx.bizhawk_ctx,
@@ -79,8 +97,8 @@ class GrinchClient(BizHawkClient):
pass pass
async def location_checker(self, ctx: "BizHawkClientContext"): async def location_checker(self, ctx: "BizHawkClientContext"):
# TODO Write a function to check if I am ingame, determine how I am playing the game vs not in demo mode/game menu
# Update the AP Server to know what locations are not checked yet. # Update the AP Server to know what locations are not checked yet.
local_locations_checked: list[int] = []
for missing_location in ctx.missing_locations: for missing_location in ctx.missing_locations:
local_location = ctx.location_names.lookup_in_game(missing_location) local_location = ctx.location_names.lookup_in_game(missing_location)
# Missing location is the AP ID & we need to convert it back to a location name within our game. # Missing location is the AP ID & we need to convert it back to a location name within our game.
@@ -94,14 +112,15 @@ class GrinchClient(BizHawkClient):
addr_to_update.ram_address, addr_to_update.bit_size, "MainRAM")]))[0], "little") addr_to_update.ram_address, addr_to_update.bit_size, "MainRAM")]))[0], "little")
if is_binary: if is_binary:
if (current_ram_address_value & (1 << addr_to_update.binary_bit_pos)) > 0: if (current_ram_address_value & (1 << addr_to_update.binary_bit_pos)) > 0:
ctx.locations_checked.add(missing_location) local_locations_checked.append(missing_location)
else: else:
expected_int_value = addr_to_update.value expected_int_value = addr_to_update.value
if expected_int_value == current_ram_address_value: if expected_int_value == current_ram_address_value:
ctx.locations_checked.add(missing_location) local_locations_checked.append(missing_location)
# Update the AP server with the locally checked list of locations (In other words, locations I found in Grinch) # Update the AP server with the locally checked list of locations (In other words, locations I found in Grinch)
await ctx.check_locations(ctx.locations_checked) await ctx.check_locations(local_locations_checked)
ctx.locations_checked = set(local_locations_checked)
async def receiving_items_handler(self, ctx: "BizHawkClientContext"): async def receiving_items_handler(self, ctx: "BizHawkClientContext"):
# Len will give us the size of the items received list & we will track that against how many items we received already # Len will give us the size of the items received list & we will track that against how many items we received already
@@ -119,10 +138,12 @@ class GrinchClient(BizHawkClient):
for addr_to_update in grinch_item_ram_data.update_ram_addr: for addr_to_update in grinch_item_ram_data.update_ram_addr:
is_binary = True if not addr_to_update.binary_bit_pos is None else False is_binary = True if not addr_to_update.binary_bit_pos is None else False
current_ram_address_value = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [(
addr_to_update.ram_address, addr_to_update.bit_size, "MainRAM")]))[0], "little")
if is_binary: if is_binary:
current_ram_address_value = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [(
addr_to_update.ram_address, addr_to_update.bit_size, "MainRAM")]))[0], "little")
current_ram_address_value = (current_ram_address_value | (1 << addr_to_update.binary_bit_pos)) current_ram_address_value = (current_ram_address_value | (1 << addr_to_update.binary_bit_pos))
elif addr_to_update.update_existing_value:
current_ram_address_value += addr_to_update.value
else: else:
current_ram_address_value = addr_to_update.value current_ram_address_value = addr_to_update.value
@@ -131,3 +152,20 @@ class GrinchClient(BizHawkClient):
current_ram_address_value.to_bytes(addr_to_update.bit_size, "little"), "MainRAM")]) current_ram_address_value.to_bytes(addr_to_update.bit_size, "little"), "MainRAM")])
self.last_received_index += 1 self.last_received_index += 1
async def ingame_checker(self, ctx: "BizHawkClientContext"):
demo_mode = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [(
0x01008A, 1, "MainRAM")]))[0], "little")
if demo_mode == 1:
return False
is_not_ingame = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [(
0x010000, 1, "MainRAM")]))[0], "little")
if is_not_ingame <= 0x04 or is_not_ingame >= 0x35:
return False
return True
async def option_handler(self, ctx: "BizHawkClientContext"):
if self.loc_unlimited_eggs:
max_eggs: int = 200
await bizhawk.write(ctx.bizhawk_ctx, [(0x010058, max_eggs.to_bytes(1,"little"), "MainRAM")])

View File

@@ -5,7 +5,7 @@ from .Regions import connect_regions
from .Rules import set_rules from .Rules import set_rules
from .Client import * from .Client import *
from typing import ClassVar from typing import ClassVar, Mapping, Any
from worlds.AutoWorld import World from worlds.AutoWorld import World
@@ -68,3 +68,9 @@ class GrinchWorld(World):
def get_other_filler_item(self, other_filler: list[str]) -> str: def get_other_filler_item(self, other_filler: list[str]) -> str:
return self.random.choices(other_filler)[0] return self.random.choices(other_filler)[0]
def fill_slot_data(self):
return {
"give_unlimited_eggs": self.options.unlimited_eggs.value,
}