From 226bb0ba391cf4f65a27a94bf16efc11558316fb Mon Sep 17 00:00:00 2001 From: 1theory Date: Sun, 2 Aug 2026 02:50:00 +0200 Subject: [PATCH 01/18] Beginning Progressive Wrench item implementation. --- worlds/rac3/client/rac3_interface.py | 21 +++++++++++++++- worlds/rac3/constants/data/item.py | 16 ++++++++++++ worlds/rac3/constants/instruction.py | 23 ++++++++++++++++- worlds/rac3/constants/item_tags.py | 1 + worlds/rac3/constants/items.py | 1 + worlds/rac3/constants/options.py | 1 + worlds/rac3/constants/region.py | 29 ++++++++++++++++++++++ worlds/rac3/constants/status.py | 5 ++++ worlds/rac3/constants/wrench.py | 21 ++++++++++++++++ worlds/rac3/items.py | 2 ++ worlds/rac3/options/prog_wrench_options.py | 23 +++++++++++++++++ worlds/rac3/rac3options.py | 4 +++ worlds/rac3/universal_tracker.py | 1 + worlds/rac3/world.py | 1 + 14 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 worlds/rac3/constants/wrench.py create mode 100644 worlds/rac3/options/prog_wrench_options.py diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index b08d180958b6..914cf9a00e70 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -56,7 +56,7 @@ from worlds.rac3.constants.player_action import PLAYER_ACTION_NAMES, RAC3PLAYERACTION from worlds.rac3.constants.player_type import PLAYER_TYPE_TO_NAME, RAC3PLAYERTYPE from worlds.rac3.constants.progress_flag import HALO_JUMP_TO_REGION, RAC3PROGRESSFLAG -from worlds.rac3.constants.region import (PLANET_LOAD_OFFSET, PLANET_NAME_FROM_ID, PLANET_VENDOR_OFFSET, +from worlds.rac3.constants.region import (PLANET_LOAD_OFFSET, PLANET_NAME_FROM_ID, PLANET_VENDOR_OFFSET, WRENCH_FUNCTION_OFFSET, PLANETS_WITH_HACKER_PUZZLES, PLANETS_WITH_REFRACTOR_PUZZLES, PLANETS_WITH_TYHRRANOID_PUZZLES, RAC3REGION, REGION_TO_HACKER_DOOR_COUNT, RESPAWN_COORDS_OFFSET) @@ -70,6 +70,7 @@ from worlds.rac3.constants.version import (GAME_ID_TO_OFFSET, GAME_ID_TO_VERSION, PAL_SHIFTED_PLANETS, RAC3VERSION, VERSION_TO_BLACK_SCREEN_ORIGINAL_VALUE, jp_convert_address, jp_get_pause_physical_address, ) +from worlds.rac3.constants.wrench import RAC3WRENCH class Rac3Interface(GameInterface): @@ -97,6 +98,7 @@ class Options: starting_weapons: dict[str, int] bolt_and_xp_multiplier: int progressive_weapons: int + progressive_wrench: int armor_upgrade: int skill_points: int trophies: int @@ -324,6 +326,7 @@ def proc_option(self, slot_data: dict[str, Any]): self.options.starting_weapons = slot_data[RAC3OPTION.STARTING_WEAPONS] self.options.bolt_and_xp_multiplier = slot_data[RAC3OPTION.BOLT_AND_XP_MULTIPLIER] self.options.progressive_weapons = slot_data[RAC3OPTION.PROGRESSIVE_WEAPONS] + self.options.progressive_wrench = slot_data[RAC3OPTION.PROGRESSIVE_WRENCH] self.options.armor_upgrade = slot_data[RAC3OPTION.ARMOR_UPGRADE] self.options.skill_points = slot_data[RAC3OPTION.SKILL_POINTS] self.options.trophies = slot_data[RAC3OPTION.TROPHIES] @@ -925,6 +928,8 @@ def item_received(self, case RAC3ITEM.CLANK: self.UnlockItem[RAC3ITEM.HELI_PACK].status = 1 self.UnlockItem[RAC3ITEM.THRUSTER_PACK].status = 1 + #case RAC3ITEM.PROGRESSIVE_WRENCH: + # pass case RAC3ITEM.TITANIUM_BOLT: pass case RAC3ITEM.BOLTS: @@ -1780,6 +1785,7 @@ def late_update(self): self.gadget_cycler() self.planet_cycler() self.weapon_cycler() + self.wrench_cycler() self.vidcomic_cycler() self.armor_cycler() self.timer_cycler() @@ -1967,6 +1973,19 @@ def weapon_cycler(self): else: self.update_weapon_equip(self.last_used_3, self.last_used_3, self.last_used_4, self.last_used_5) + def wrench_cycler(self): + """Cycle through the wrench properties and update its state""" + prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] + current_wrench_level = self._read8(RAC3STATUS.WRENCH_LEVEL) + wrench_func = RAC3WRENCH.get_wrench_property_address(self.planet) + wrench_level = wrench_func + RAC3WRENCH.UPGRADE_ID_OFFSET + target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] + logger.info (f"Wrench current level:{hex(current_wrench_level)}") + if current_wrench_level != 0x09: + self._write8(RAC3STATUS.WRENCH_LEVEL, target_id) + else: + self._write8(wrench_level, target_id) + def update_weapon_equip(self, equip: int | None, last_0: int | None, last_1: int | None, last_2: int | None): """Writes new values to the player's last used item history""" diff --git a/worlds/rac3/constants/data/item.py b/worlds/rac3/constants/data/item.py index 693eacf10e9c..c1f4472f3c0a 100644 --- a/worlds/rac3/constants/data/item.py +++ b/worlds/rac3/constants/data/item.py @@ -166,6 +166,16 @@ def construct_vidcomic(idx: int, else: tags: list[str] = [RAC3ITEMTAG.VIDCOMIC] return RAC3ITEMDATA(idx, address, ap_classification=ItemClassification.progression, tags=tags) + + @staticmethod + def construct_wrench(idx: int, + tag: list[str] | None = None): + """Construct a progressive OmniWrench item""" + if tag: + tags: list[str] = [*tag, RAC3ITEMTAG.PROG_WRENCH] + else: + tags: list[str] = [RAC3ITEMTAG.PROG_WRENCH] + return RAC3ITEMDATA(idx, ap_classification=ItemClassification.progression, tags=tags) @staticmethod def construct_trap(idx: int, @@ -438,6 +448,8 @@ def construct_cheat(idx: int, RAC3ITEMDATA.construct_weapon_prog(0xDD, ItemClassification.progression_skip_balancing), RAC3ITEM.PROGRESSIVE_RY3N0: RAC3ITEMDATA.construct_weapon_prog(0xDE, ItemClassification.progression_skip_balancing, [RAC3ITEMTAG.NGPLUS]), + RAC3ITEM.PROGRESSIVE_WRENCH: + RAC3ITEMDATA.construct_wrench(0xDF, [RAC3ITEMTAG.PROG_WRENCH]), # Infobots RAC3ITEM.VELDIN: RAC3ITEMDATA.construct_infobot(0xE1, ItemClassification.progression), RAC3ITEM.FLORANA: RAC3ITEMDATA.construct_infobot(0xE2, ItemClassification.progression), @@ -526,6 +538,7 @@ def from_tag(tag: str) -> dict[str, RAC3ITEMDATA]: ngplus_data: dict[str, RAC3ITEMDATA] = from_tag(RAC3ITEMTAG.NGPLUS) non_prog_weapon_data: dict[str, RAC3ITEMDATA] = from_tag(RAC3ITEMTAG.NON_PROG_WEAPON) prog_weapon_data: dict[str, RAC3ITEMDATA] = from_tag(RAC3ITEMTAG.PROG_WEAPON) +prog_wrench_data: dict[str, RAC3ITEMDATA] = from_tag(RAC3ITEMTAG.PROG_WRENCH) progressive_data: dict[str, RAC3ITEMDATA] = from_tag(RAC3ITEMTAG.PROGRESSIVE) trap_data: dict[str, RAC3ITEMDATA] = from_tag(RAC3ITEMTAG.TRAP) unused_data: dict[str, RAC3ITEMDATA] = from_tag(RAC3ITEMTAG.UNUSED) @@ -542,6 +555,7 @@ def from_tag(tag: str) -> dict[str, RAC3ITEMDATA]: item_counts: dict[str, int] = { **dict.fromkeys(non_prog_weapon_data.keys(), 1), **dict.fromkeys(prog_weapon_data.keys(), 5), + **dict.fromkeys(prog_wrench_data.keys(), 5), **dict.fromkeys(gadget_data.keys(), 1), **dict.fromkeys(cheat_data.keys(), 1), RAC3ITEM.CLANK: 1, @@ -555,6 +569,7 @@ def from_tag(tag: str) -> dict[str, RAC3ITEMDATA]: ngplus_item_counts: dict[str, int] = { **dict.fromkeys(non_prog_weapon_data.keys(), 1), **dict.fromkeys(prog_weapon_data.keys(), 8), + **dict.fromkeys(prog_wrench_data.keys(), 8), **dict.fromkeys(gadget_data.keys(), 1), **dict.fromkeys(cheat_data.keys(), 1), RAC3ITEM.CLANK: 1, @@ -599,6 +614,7 @@ def from_tag(tag: str) -> dict[str, RAC3ITEMDATA]: RAC3ITEMTAG.NGPLUS: set(ngplus_data.keys()), RAC3ITEMTAG.NON_PROG_WEAPON: set(non_prog_weapon_data.keys()), RAC3ITEMTAG.PROG_WEAPON: set(prog_weapon_data.keys()), + RAC3ITEMTAG.PROG_WEAPON: set(prog_wrench_data.keys()), RAC3ITEMTAG.PROGRESSIVE: set(progressive_data.keys()), RAC3ITEMTAG.TRAP: set(trap_data.keys()), RAC3ITEMTAG.UNUSED: set(unused_data.keys()), diff --git a/worlds/rac3/constants/instruction.py b/worlds/rac3/constants/instruction.py index 42e738240786..7c7ae0f0f3e6 100644 --- a/worlds/rac3/constants/instruction.py +++ b/worlds/rac3/constants/instruction.py @@ -13,11 +13,27 @@ class RAC3INSTRUCTION: PHOENIX_CAN_BUY_ARMOR_JP = 0x004B13E0 # 1062001A beq v1,v0,0x004B144C PHOENIX_HYPERSHOT_QUICK_SELECT_REMOVAL_NTSC = 0x0040D0A8 # AC600000 sw zero,0x0(v1) PHOENIX_HYPERSHOT_QUICK_SELECT_REMOVAL_PAL = 0x0040FA08 # AC600000 sw zero,0x0(v1) + PHOENIX_HOLDING_WRENCH_V2_NTSC = 0x004FD27C NATION_SLEEP_GAS_HEALTH_UPDATE = 0x0032F884 # 0x2442FFFF addiu v0,v0,-0x1 NATION_HEALTH_REFILL = 0x00330068 # AC652850 sw a1,0x2850(v1) NATION_LEVELUP_HEALING = 0x00319C78 # 00621821 addu v1,v1,v0 NATION_LEVELUP_MILESTONE_HEALING = 0x00319CA4 # ACA22850 sw a0,0x2850(v1) - + NATION_HOLDING_WRENCH_V2_NTSC = 0x0050E99C # 240200A4 addiu v0,zero,0xA4 + NATION_HOLDING_WRENCH_V3_NTSC = 0x0050E9B4 # 240200A5 addiu v0,zero,0xA5 + NATION_HOLDING_WRENCH_V4_NTSC = 0x0050E9CC # 240200C6 addiu v0,zero,0xC6 + NATION_HOLDING_WRENCH_V5_NTSC = 0x0050E9E4 # 240200C7 addiu v0,zero,0xC7 + NATION_HOLDING_WRENCH_V6_NTSC = 0x0050E9FC # 240200C8 addiu v0,zero,0xC8 + NATION_HOLDING_WRENCH_V7_NTSC = 0x0050EA14 # 240200C9 addiu v0,zero,0xC9 + NATION_HOLDING_WRENCH_V8_NTSC = 0x0050EA2C # 240200CA addiu v0,zero,0xCA + NATION_WRENCH_UPGRADE_NTSC = 0x0050EA30 # A0620009 sb v0,0x9(v1) + VELDIN_WRITE_TO_WRENCH_V2_NTSC = 0x0050FBDC # 240200A4 addiu v0,zero,0xA4 + VELDIN_WRITE_TO_WRENCH_V3_NTSC = 0x0050FBF4 # 240200A5 addiu v0,zero,0xA5 + VELDIN_WRITE_TO_WRENCH_V4_NTSC = 0x0050FC0C # 240200C6 addiu v0,zero,0xC6 + VELDIN_WRITE_TO_WRENCH_V5_NTSC = 0x0050FC25 # 240200C7 addiu v0,zero,0xC7 + VELDIN_WRITE_TO_WRENCH_V6_NTSC = 0x0050FC3C # 240200C8 addiu v0,zero,0xC8 + VELDIN_WRITE_TO_WRENCH_V7_NTSC = 0x0050FC54 # 240200C9 addiu v0,zero,0xC9 + VELDIN_WRITE_TO_WRENCH_V8_NTSC = 0x0050FC6C # 240200CA addiu v0,zero,0xCA + VELDIN_WRENCH_UPGRADE_NTSC = 0x0050FC70 # A0620009 sb v0,0x9(v1) ORIGINAL_INSTRUCTIONS: dict[int, int] = { RAC3INSTRUCTION.PHOENIX_CAN_BUY_ARMOR_NTSC: 0x1062001A, @@ -29,6 +45,7 @@ class RAC3INSTRUCTION: RAC3INSTRUCTION.NATION_HEALTH_REFILL: 0xAC652850, RAC3INSTRUCTION.NATION_LEVELUP_HEALING: 0x00621821, RAC3INSTRUCTION.NATION_LEVELUP_MILESTONE_HEALING: 0xACA22850, + RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: 0xA0620009 } PATCHED_INSTRUCTIONS: dict[int, int] = { @@ -41,6 +58,7 @@ class RAC3INSTRUCTION: RAC3INSTRUCTION.NATION_HEALTH_REFILL: 0x00000000, RAC3INSTRUCTION.NATION_LEVELUP_HEALING: 0x00000000, RAC3INSTRUCTION.NATION_LEVELUP_MILESTONE_HEALING: 0x00000000, + RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: 0xA0620000, } PATCH_INSTRUCTION_TO_NAME: dict[int, str] = { @@ -53,6 +71,7 @@ class RAC3INSTRUCTION: RAC3INSTRUCTION.NATION_HEALTH_REFILL: "Annihilation Nation: 1-HP: Health refill removal", RAC3INSTRUCTION.NATION_LEVELUP_HEALING: "Annihilation Nation: 1-HP: Level up healing removal", RAC3INSTRUCTION.NATION_LEVELUP_MILESTONE_HEALING: "Annihilation Nation: 1-HP: Level up milestone healing removal", + RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: "Veldin: Wrench upgrades decoupled from Nanotech (NTSC)", } PATCH_INSTRUCTION_TO_PLANET: dict[int, str] = { @@ -65,6 +84,7 @@ class RAC3INSTRUCTION: RAC3INSTRUCTION.NATION_HEALTH_REFILL: RAC3REGION.ANNIHILATION_NATION, RAC3INSTRUCTION.NATION_LEVELUP_HEALING: RAC3REGION.ANNIHILATION_NATION, RAC3INSTRUCTION.NATION_LEVELUP_MILESTONE_HEALING: RAC3REGION.ANNIHILATION_NATION, + RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: RAC3REGION.VELDIN, } # None in PATCH_INSTRUCTION_TO_GAME_IDS means the patch applies to all versions. @@ -78,4 +98,5 @@ class RAC3INSTRUCTION: RAC3INSTRUCTION.NATION_HEALTH_REFILL: [RAC3VERSION.US_ID, RAC3VERSION.US_GH_ID], RAC3INSTRUCTION.NATION_LEVELUP_HEALING: [RAC3VERSION.US_ID, RAC3VERSION.US_GH_ID], RAC3INSTRUCTION.NATION_LEVELUP_MILESTONE_HEALING: [RAC3VERSION.US_ID, RAC3VERSION.US_GH_ID], + RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: [RAC3VERSION.US_ID, RAC3VERSION.US_GH_ID], } diff --git a/worlds/rac3/constants/item_tags.py b/worlds/rac3/constants/item_tags.py index b455fcee0591..5f8b62e092a5 100644 --- a/worlds/rac3/constants/item_tags.py +++ b/worlds/rac3/constants/item_tags.py @@ -12,6 +12,7 @@ class RAC3ITEMTAG: NGPLUS = "NG+" NON_PROG_WEAPON = "Non-Progressive Weapon" PROG_WEAPON = "Progressive Weapon" + PROG_WRENCH = "Progressive Wrench" PROGRESSIVE = "Progressive" TRAP = "Trap" UNUSED = "Unused" diff --git a/worlds/rac3/constants/items.py b/worlds/rac3/constants/items.py index 7081407c4465..a5667941a97b 100644 --- a/worlds/rac3/constants/items.py +++ b/worlds/rac3/constants/items.py @@ -231,6 +231,7 @@ class RAC3ITEM: PROGRESSIVE_VIDCOMIC = "Progressive VidComic" PROGRESSIVE_ARMOR = "Progressive Armor" PROGRESSIVE_PACK = "Progressive Pack" + PROGRESSIVE_WRENCH = "Progressive Omniwrench" VELDIN = "Infobot: Veldin" FLORANA = "Infobot: Florana" diff --git a/worlds/rac3/constants/options.py b/worlds/rac3/constants/options.py index ab344f26387d..dc83453cace5 100644 --- a/worlds/rac3/constants/options.py +++ b/worlds/rac3/constants/options.py @@ -12,6 +12,7 @@ class RAC3OPTION: STARTING_WEAPONS = "Starting Weapons" BOLT_AND_XP_MULTIPLIER = "Bolt and XP Multiplier" PROGRESSIVE_WEAPONS = "Progressive Weapons" + PROGRESSIVE_WRENCH = "Progressive Wrench" ARMOR_UPGRADE = "Armor Upgrade" SKILL_POINTS = "Skill Points" TROPHIES = "Trophies" diff --git a/worlds/rac3/constants/region.py b/worlds/rac3/constants/region.py index 07a781aa5af7..9db746c0de91 100644 --- a/worlds/rac3/constants/region.py +++ b/worlds/rac3/constants/region.py @@ -262,6 +262,35 @@ class RAC3REGION: RAC3REGION.OBANI_DRACO: 0x400, RAC3REGION.COMMAND_CENTER: 0x1D80, } +WRENCH_FUNCTION_OFFSET: dict[str, int] = { + RAC3REGION.VELDIN: 0x2FDE8, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x1D488, + RAC3REGION.MARCADIA: 0x3A348, + RAC3REGION.DAXX: 0x28BB0, + RAC3REGION.PHOENIX_ASSAULT: 0x13758, + RAC3REGION.ANNIHILATION_NATION: 0x2EBA8, + RAC3REGION.AQUATOS: 0x9CE0, + RAC3REGION.TYHRRANOSIS: 0x42CE0, + RAC3REGION.ZELDRIN_STARPORT: 0x12910, + RAC3REGION.OBANI_GEMINI: 0x5E10, + RAC3REGION.BLACKWATER_CITY: 0x313B0, + RAC3REGION.HOLOSTAR_STUDIOS: 0xFA10, + RAC3REGION.KOROS: 0x1A668, + RAC3REGION.METROPOLIS: 0x412F8, + RAC3REGION.CRASH_SITE: 0x9008, + RAC3REGION.ARIDIA: 0x42688, + RAC3REGION.QWARKS_HIDEOUT: 0x21250, + RAC3REGION.COMMAND_CENTER_2: 0x4F830, + RAC3REGION.OBANI_DRACO: 0x6C88, + RAC3REGION.COMMAND_CENTER: 0x36978, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0x13C00, + RAC3REGION.MUSEUM: 0x14BD8, + RAC3REGION.METROPOLIS_RANGERS: 0x38900, + RAC3REGION.AQUATOS_BASE: -0x16E8, + RAC3REGION.AQUATOS_SEWERS: -0x89F8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x3B238 +} PLANETS_WITH_HACKER_PUZZLES: list[str] = [ RAC3REGION.STARSHIP_PHOENIX, RAC3REGION.AQUATOS, diff --git a/worlds/rac3/constants/status.py b/worlds/rac3/constants/status.py index 9bb23af6999e..d2e489751d6a 100644 --- a/worlds/rac3/constants/status.py +++ b/worlds/rac3/constants/status.py @@ -10,6 +10,7 @@ class RAC3STATUS: SECOND_PREV_ACTION = 0x001A71BC ACTION_TYPE = 0x001A71AC LEVEL_TABLE = 0x001425C0 + WRENCH_LEVEL= 0x001425C9 BOLTS = 0x00142660 MAX_HEALTH = 0x00142668 LAST_USED_0 = 0x00142670 @@ -117,3 +118,7 @@ class RAC3STATUS: PAUSE_BASE = 0x001DF068 RESPAWN_BASE = 0x002348D0 VENDOR_BASE = 0x002418C0 + WRENCH_FUNCTION_BASE = 0x004DFB38 + MAGNETISM_FUNCTION_BASE = 0x004B98CC + GRAV_BOOTS_EVERYWHERE_BASE = 0x004B9808 + CHECK_FLOOR_BASE = 0x004B97FC diff --git a/worlds/rac3/constants/wrench.py b/worlds/rac3/constants/wrench.py new file mode 100644 index 000000000000..66dec4e4201b --- /dev/null +++ b/worlds/rac3/constants/wrench.py @@ -0,0 +1,21 @@ +"""This module provides constant address offsets, for use when reading data regarding the OmniWrench""" + +from worlds.rac3.constants.region import WRENCH_FUNCTION_OFFSET +from worlds.rac3.constants.status import RAC3STATUS + + +class RAC3WRENCH: + """Base struct for the Wrench function data, containing common address offsets""" + NANOTECH_THRESHOLD_OFFSET: int = 0x2B0 # Contains the instruction that holds the Nanotech required to reach a certain upgrade. + NANOTECH_DIFFERENCE_CHECK_OFFSET: int = 0x2B4 # Example: For V2, this address contains the decimal number 25. 25 + 15 = 40, OmniWrench V3. + UPGRADE_ID_OFFSET: int = 0x2BC # Contains the ID that will be written to the BASE_ITEM_ID. + BASE_ITEM_ID_OFFSET: int = 0x350 # Contains the item ID that the function will write to. If 00 or 01, the OmniWrench is decoupled from Nanotech + # and the function will write there instead. + PER_LEVEL_OFFSET: int = 0x18 # Starting at WRENCH_FUNCTION_BASE + NANOTECH_THRESHOLD_OFFSET, + # every +0x18 will contain an upgrade. +0x90 directly jumps from V2 to V8. + + @staticmethod + def get_wrench_property_address(planet: str) -> int: + """Provides the wrench property address for reading data""" + addr = RAC3STATUS.WRENCH_FUNCTION_BASE + WRENCH_FUNCTION_OFFSET[planet] + return addr \ No newline at end of file diff --git a/worlds/rac3/items.py b/worlds/rac3/items.py index d15b1fbf4f4f..dc5beca30d1e 100644 --- a/worlds/rac3/items.py +++ b/worlds/rac3/items.py @@ -61,6 +61,8 @@ def create_itempool(world: "RaC3World") -> list[Item]: continue if RAC3ITEMTAG.NON_PROG_WEAPON in item_tags and options.progressive_weapons.value: continue + if RAC3ITEMTAG.PROG_WRENCH in item_tags and options.progressive_wrench.value: + continue # NG+ Item option if RAC3ITEMTAG.NGPLUS in item_tags: diff --git a/worlds/rac3/options/prog_wrench_options.py b/worlds/rac3/options/prog_wrench_options.py new file mode 100644 index 000000000000..349f9ccfabeb --- /dev/null +++ b/worlds/rac3/options/prog_wrench_options.py @@ -0,0 +1,23 @@ +"""This module contains options for the Progressive OmniWrench in the item pool""" + +from Options import Choice +from worlds.rac3.constants.options import RAC3OPTION + + +class ProgressiveWrench(Choice): + """ + Determines whether the OmniWrench is a Progressive item or not. + ------------------------------------------------------------------------------------ + Disable: OmniWrench functions like in the vanilla game. + Manual Upgrade: OmniWrench is allowed to upgrade if the Nanotech level required is reached and its progressive item is collected. + Automatic Upgrade: The OmniWrench will upgrade when its progressive item is collected, ignoring your Nanotech level. + Lost Wrench: Ratchet will start without its OmniWrench and will need to be collected first. DO NOT USE YET. + ------------------------------------------------------------------------------------ + Note: If Weapon Level Locations are enabled, Automatic Upgrade will be forced to Manual Upgrade instead. + """ + display_name = RAC3OPTION.PROGRESSIVE_WRENCH + option_disable = 0 + option_manual_upgrade = 1 + option_automatic_upgrade = 2 + option_lost_wrench = 3 + default = 0 diff --git a/worlds/rac3/rac3options.py b/worlds/rac3/rac3options.py index a84ad8c78bb7..c5e34fbec157 100644 --- a/worlds/rac3/rac3options.py +++ b/worlds/rac3/rac3options.py @@ -19,6 +19,7 @@ from worlds.rac3.options.ngplus_vendor_options import NGPlusVendor from worlds.rac3.options.one_hp_options import OneHpChallenge from worlds.rac3.options.prog_weapons_options import ProgressiveWeapons +from worlds.rac3.options.prog_wrench_options import ProgressiveWrench from worlds.rac3.options.rangers_options import Rangers from worlds.rac3.options.ratchet_skins_options import RatchetSkin from worlds.rac3.options.scout_vendors_options import ScoutVendors @@ -60,6 +61,7 @@ class RaC3Options(PerGameCommonOptions): starting_weapons: StartingWeapons bolt_and_xp_multiplier: BoltAndXPMultiplier progressive_weapons: ProgressiveWeapons + progressive_wrench: ProgressiveWrench armor_upgrade: ArmorUpgrade filler_weight: FillerWeight traps_enabled: EnableTraps @@ -113,6 +115,7 @@ class RaC3Options(PerGameCommonOptions): StartingWeapons, NGPlusItems, ProgressiveWeapons, + ProgressiveWrench, ArmorUpgrade, ClankOptions, EnableTraps, @@ -159,6 +162,7 @@ class RaC3Options(PerGameCommonOptions): RAC3OPTION.STARTING_WEAPONS, RAC3OPTION.BOLT_AND_XP_MULTIPLIER, RAC3OPTION.PROGRESSIVE_WEAPONS, + RAC3OPTION.PROGRESSIVE_WRENCH, RAC3OPTION.NGPLUS_ITEMS, RAC3OPTION.NGPLUS_START, RAC3OPTION.ARMOR_UPGRADE, diff --git a/worlds/rac3/universal_tracker.py b/worlds/rac3/universal_tracker.py index 03d197fb2adb..db605fe3f644 100644 --- a/worlds/rac3/universal_tracker.py +++ b/worlds/rac3/universal_tracker.py @@ -21,6 +21,7 @@ def setup_options_from_slot_data(world: "RaC3World") -> None: world.options.starting_weapons.value = world.passthrough[RAC3OPTION.STARTING_WEAPONS] world.options.bolt_and_xp_multiplier.value = world.passthrough[RAC3OPTION.BOLT_AND_XP_MULTIPLIER] world.options.progressive_weapons.value = world.passthrough[RAC3OPTION.PROGRESSIVE_WEAPONS] + world.options.progressive_wrench.value = world.passthrough[RAC3OPTION.PROGRESSIVE_WRENCH] world.options.armor_upgrade.value = world.passthrough[RAC3OPTION.ARMOR_UPGRADE] world.options.skill_points.value = world.passthrough[RAC3OPTION.SKILL_POINTS] world.options.trophies.value = world.passthrough[RAC3OPTION.TROPHIES] diff --git a/worlds/rac3/world.py b/worlds/rac3/world.py index 0722d73599b2..e6cf963e60f9 100644 --- a/worlds/rac3/world.py +++ b/worlds/rac3/world.py @@ -249,6 +249,7 @@ def fill_slot_data(self) -> dict[str, Any]: RAC3OPTION.STARTING_WEAPONS: self.options.starting_weapons.value, RAC3OPTION.BOLT_AND_XP_MULTIPLIER: self.options.bolt_and_xp_multiplier.value, RAC3OPTION.PROGRESSIVE_WEAPONS: self.options.progressive_weapons.value, + RAC3OPTION.PROGRESSIVE_WRENCH: self.options.progressive_wrench.value, RAC3OPTION.ARMOR_UPGRADE: self.options.armor_upgrade.value, RAC3OPTION.SKILL_POINTS: self.options.skill_points.value, RAC3OPTION.TROPHIES: self.options.trophies.value, From 618842ca8d69280e7a7cca228feabd1177263000 Mon Sep 17 00:00:00 2001 From: 1theory Date: Sun, 2 Aug 2026 02:53:03 +0200 Subject: [PATCH 02/18] Temporary fix removed. --- worlds/rac3/client/rac3_interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index 914cf9a00e70..11951b650543 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -1981,7 +1981,7 @@ def wrench_cycler(self): wrench_level = wrench_func + RAC3WRENCH.UPGRADE_ID_OFFSET target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] logger.info (f"Wrench current level:{hex(current_wrench_level)}") - if current_wrench_level != 0x09: + if current_wrench_level == 0x09: self._write8(RAC3STATUS.WRENCH_LEVEL, target_id) else: self._write8(wrench_level, target_id) From 09ed13d018716de45d5189bc435686085a9e0a47 Mon Sep 17 00:00:00 2001 From: 1theory Date: Sun, 2 Aug 2026 04:49:57 +0200 Subject: [PATCH 03/18] Optimizing cycler. Missing patch safety and PAL version. --- worlds/rac3/client/rac3_interface.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index 11951b650543..335e31effebc 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -1976,15 +1976,11 @@ def weapon_cycler(self): def wrench_cycler(self): """Cycle through the wrench properties and update its state""" prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] - current_wrench_level = self._read8(RAC3STATUS.WRENCH_LEVEL) - wrench_func = RAC3WRENCH.get_wrench_property_address(self.planet) - wrench_level = wrench_func + RAC3WRENCH.UPGRADE_ID_OFFSET - target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] - logger.info (f"Wrench current level:{hex(current_wrench_level)}") - if current_wrench_level == 0x09: - self._write8(RAC3STATUS.WRENCH_LEVEL, target_id) - else: - self._write8(wrench_level, target_id) + wrench_level_instruction = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.BASE_ITEM_ID_OFFSET + target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] + self._write8(wrench_level_instruction, 0) + self._write8(RAC3STATUS.WRENCH_LEVEL, target_id) + def update_weapon_equip(self, equip: int | None, last_0: int | None, last_1: int | None, last_2: int | None): From 6c023de2d656b42b2e76f2640c896fa6f1678df2 Mon Sep 17 00:00:00 2001 From: 1theory Date: Mon, 3 Aug 2026 18:14:57 +0200 Subject: [PATCH 04/18] Updated wrench cycler and fixed option. --- worlds/rac3/client/rac3_interface.py | 13 +++++++++++++ worlds/rac3/items.py | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index 335e31effebc..ceeccd0ea014 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -1976,11 +1976,24 @@ def weapon_cycler(self): def wrench_cycler(self): """Cycle through the wrench properties and update its state""" prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] +<<<<<<< Updated upstream wrench_level_instruction = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.BASE_ITEM_ID_OFFSET target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] self._write8(wrench_level_instruction, 0) self._write8(RAC3STATUS.WRENCH_LEVEL, target_id) +======= + if self.planet != RAC3REGION.MENU: + wrench_instruction = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.BASE_ITEM_ID_OFFSET + wrench_upgrade = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.UPGRADE_ID_OFFSET + target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] + if self.between_planets is False: + wrench_upgrade + if self._read32(wrench_instruction) == 0xA0620009: + for _ in range(7): + self._write8(wrench_upgrade, target_id) + wrench_upgrade += RAC3WRENCH.PER_LEVEL_OFFSET +>>>>>>> Stashed changes def update_weapon_equip(self, equip: int | None, last_0: int | None, last_1: int | None, last_2: int | None): diff --git a/worlds/rac3/items.py b/worlds/rac3/items.py index dc5beca30d1e..94c2414d2061 100644 --- a/worlds/rac3/items.py +++ b/worlds/rac3/items.py @@ -61,7 +61,7 @@ def create_itempool(world: "RaC3World") -> list[Item]: continue if RAC3ITEMTAG.NON_PROG_WEAPON in item_tags and options.progressive_weapons.value: continue - if RAC3ITEMTAG.PROG_WRENCH in item_tags and options.progressive_wrench.value: + if RAC3ITEMTAG.PROG_WRENCH in item_tags and not options.progressive_wrench.value: continue # NG+ Item option From aba3b063ffd6432c537a0b98d37b69de6af47565 Mon Sep 17 00:00:00 2001 From: 1theory Date: Mon, 3 Aug 2026 18:18:44 +0200 Subject: [PATCH 05/18] Removing leftover. --- worlds/rac3/client/rac3_interface.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index ceeccd0ea014..3c3e17a549ac 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -1976,24 +1976,15 @@ def weapon_cycler(self): def wrench_cycler(self): """Cycle through the wrench properties and update its state""" prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] -<<<<<<< Updated upstream - wrench_level_instruction = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.BASE_ITEM_ID_OFFSET - target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] - self._write8(wrench_level_instruction, 0) - self._write8(RAC3STATUS.WRENCH_LEVEL, target_id) - -======= if self.planet != RAC3REGION.MENU: wrench_instruction = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.BASE_ITEM_ID_OFFSET wrench_upgrade = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.UPGRADE_ID_OFFSET target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] if self.between_planets is False: - wrench_upgrade if self._read32(wrench_instruction) == 0xA0620009: for _ in range(7): self._write8(wrench_upgrade, target_id) wrench_upgrade += RAC3WRENCH.PER_LEVEL_OFFSET ->>>>>>> Stashed changes def update_weapon_equip(self, equip: int | None, last_0: int | None, last_1: int | None, last_2: int | None): From 0ecd844cbca592677bead8f22edf810ac7b0bd4e Mon Sep 17 00:00:00 2001 From: 1theory Date: Mon, 3 Aug 2026 19:56:33 +0200 Subject: [PATCH 06/18] Commenting unused wrench instructions. Weapon saved data bugged. --- worlds/rac3/client/rac3_interface.py | 21 ++++++++++--------- worlds/rac3/constants/instruction.py | 30 +++++++++------------------- 2 files changed, 19 insertions(+), 32 deletions(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index 3c3e17a549ac..c0837c150025 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -1974,17 +1974,16 @@ def weapon_cycler(self): self.update_weapon_equip(self.last_used_3, self.last_used_3, self.last_used_4, self.last_used_5) def wrench_cycler(self): - """Cycle through the wrench properties and update its state""" - prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] - if self.planet != RAC3REGION.MENU: - wrench_instruction = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.BASE_ITEM_ID_OFFSET - wrench_upgrade = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.UPGRADE_ID_OFFSET - target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] - if self.between_planets is False: - if self._read32(wrench_instruction) == 0xA0620009: - for _ in range(7): - self._write8(wrench_upgrade, target_id) - wrench_upgrade += RAC3WRENCH.PER_LEVEL_OFFSET + """Cycle through the wrench properties and update its state""" + prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] + if self.planet != RAC3REGION.MENU and self.between_planets is False: + wrench_instruction = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.BASE_ITEM_ID_OFFSET + wrench_upgrade = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.UPGRADE_ID_OFFSET + target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] + if self._read32(wrench_instruction) == 0xA0620009: + for _ in range(6): + self._write8(wrench_upgrade, target_id) + wrench_upgrade += RAC3WRENCH.PER_LEVEL_OFFSET def update_weapon_equip(self, equip: int | None, last_0: int | None, last_1: int | None, last_2: int | None): diff --git a/worlds/rac3/constants/instruction.py b/worlds/rac3/constants/instruction.py index 7c7ae0f0f3e6..327366f83774 100644 --- a/worlds/rac3/constants/instruction.py +++ b/worlds/rac3/constants/instruction.py @@ -18,22 +18,10 @@ class RAC3INSTRUCTION: NATION_HEALTH_REFILL = 0x00330068 # AC652850 sw a1,0x2850(v1) NATION_LEVELUP_HEALING = 0x00319C78 # 00621821 addu v1,v1,v0 NATION_LEVELUP_MILESTONE_HEALING = 0x00319CA4 # ACA22850 sw a0,0x2850(v1) - NATION_HOLDING_WRENCH_V2_NTSC = 0x0050E99C # 240200A4 addiu v0,zero,0xA4 - NATION_HOLDING_WRENCH_V3_NTSC = 0x0050E9B4 # 240200A5 addiu v0,zero,0xA5 - NATION_HOLDING_WRENCH_V4_NTSC = 0x0050E9CC # 240200C6 addiu v0,zero,0xC6 - NATION_HOLDING_WRENCH_V5_NTSC = 0x0050E9E4 # 240200C7 addiu v0,zero,0xC7 - NATION_HOLDING_WRENCH_V6_NTSC = 0x0050E9FC # 240200C8 addiu v0,zero,0xC8 - NATION_HOLDING_WRENCH_V7_NTSC = 0x0050EA14 # 240200C9 addiu v0,zero,0xC9 - NATION_HOLDING_WRENCH_V8_NTSC = 0x0050EA2C # 240200CA addiu v0,zero,0xCA - NATION_WRENCH_UPGRADE_NTSC = 0x0050EA30 # A0620009 sb v0,0x9(v1) - VELDIN_WRITE_TO_WRENCH_V2_NTSC = 0x0050FBDC # 240200A4 addiu v0,zero,0xA4 - VELDIN_WRITE_TO_WRENCH_V3_NTSC = 0x0050FBF4 # 240200A5 addiu v0,zero,0xA5 - VELDIN_WRITE_TO_WRENCH_V4_NTSC = 0x0050FC0C # 240200C6 addiu v0,zero,0xC6 - VELDIN_WRITE_TO_WRENCH_V5_NTSC = 0x0050FC25 # 240200C7 addiu v0,zero,0xC7 - VELDIN_WRITE_TO_WRENCH_V6_NTSC = 0x0050FC3C # 240200C8 addiu v0,zero,0xC8 - VELDIN_WRITE_TO_WRENCH_V7_NTSC = 0x0050FC54 # 240200C9 addiu v0,zero,0xC9 - VELDIN_WRITE_TO_WRENCH_V8_NTSC = 0x0050FC6C # 240200CA addiu v0,zero,0xCA - VELDIN_WRENCH_UPGRADE_NTSC = 0x0050FC70 # A0620009 sb v0,0x9(v1) + #NATION_HOLDING_WRENCH_V2_NTSC = 0x0050E99C # 240200A4 addiu v0,zero,0xA4 + #NATION_WRENCH_UPGRADE_NTSC = 0x0050EA30 # A0620009 sb v0,0x9(v1) + #VELDIN_WRITE_TO_WRENCH_V2_NTSC = 0x0050FBDC # 240200A4 addiu v0,zero,0xA4 + #VELDIN_WRENCH_UPGRADE_NTSC = 0x0050FC70 # A0620009 sb v0,0x9(v1) ORIGINAL_INSTRUCTIONS: dict[int, int] = { RAC3INSTRUCTION.PHOENIX_CAN_BUY_ARMOR_NTSC: 0x1062001A, @@ -45,7 +33,7 @@ class RAC3INSTRUCTION: RAC3INSTRUCTION.NATION_HEALTH_REFILL: 0xAC652850, RAC3INSTRUCTION.NATION_LEVELUP_HEALING: 0x00621821, RAC3INSTRUCTION.NATION_LEVELUP_MILESTONE_HEALING: 0xACA22850, - RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: 0xA0620009 + #RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: 0xA0620009 } PATCHED_INSTRUCTIONS: dict[int, int] = { @@ -58,7 +46,7 @@ class RAC3INSTRUCTION: RAC3INSTRUCTION.NATION_HEALTH_REFILL: 0x00000000, RAC3INSTRUCTION.NATION_LEVELUP_HEALING: 0x00000000, RAC3INSTRUCTION.NATION_LEVELUP_MILESTONE_HEALING: 0x00000000, - RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: 0xA0620000, + #RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: 0xA0620000, } PATCH_INSTRUCTION_TO_NAME: dict[int, str] = { @@ -71,7 +59,7 @@ class RAC3INSTRUCTION: RAC3INSTRUCTION.NATION_HEALTH_REFILL: "Annihilation Nation: 1-HP: Health refill removal", RAC3INSTRUCTION.NATION_LEVELUP_HEALING: "Annihilation Nation: 1-HP: Level up healing removal", RAC3INSTRUCTION.NATION_LEVELUP_MILESTONE_HEALING: "Annihilation Nation: 1-HP: Level up milestone healing removal", - RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: "Veldin: Wrench upgrades decoupled from Nanotech (NTSC)", + #RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: "Veldin: Wrench upgrades decoupled from Nanotech (NTSC)", } PATCH_INSTRUCTION_TO_PLANET: dict[int, str] = { @@ -84,7 +72,7 @@ class RAC3INSTRUCTION: RAC3INSTRUCTION.NATION_HEALTH_REFILL: RAC3REGION.ANNIHILATION_NATION, RAC3INSTRUCTION.NATION_LEVELUP_HEALING: RAC3REGION.ANNIHILATION_NATION, RAC3INSTRUCTION.NATION_LEVELUP_MILESTONE_HEALING: RAC3REGION.ANNIHILATION_NATION, - RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: RAC3REGION.VELDIN, + #RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: RAC3REGION.VELDIN, } # None in PATCH_INSTRUCTION_TO_GAME_IDS means the patch applies to all versions. @@ -98,5 +86,5 @@ class RAC3INSTRUCTION: RAC3INSTRUCTION.NATION_HEALTH_REFILL: [RAC3VERSION.US_ID, RAC3VERSION.US_GH_ID], RAC3INSTRUCTION.NATION_LEVELUP_HEALING: [RAC3VERSION.US_ID, RAC3VERSION.US_GH_ID], RAC3INSTRUCTION.NATION_LEVELUP_MILESTONE_HEALING: [RAC3VERSION.US_ID, RAC3VERSION.US_GH_ID], - RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: [RAC3VERSION.US_ID, RAC3VERSION.US_GH_ID], + #RAC3INSTRUCTION.VELDIN_WRENCH_UPGRADE_NTSC: [RAC3VERSION.US_ID, RAC3VERSION.US_GH_ID], } From cfa2234ed746f1fbe2001d7ba2f9af6bdd07f587 Mon Sep 17 00:00:00 2001 From: 1theory Date: Fri, 7 Aug 2026 19:31:54 +0200 Subject: [PATCH 07/18] RAC3: Typo in Wrench options. --- worlds/rac3/client/rac3_interface.py | 7 +++---- worlds/rac3/constants/data/item.py | 2 +- worlds/rac3/items.py | 6 ++++-- worlds/rac3/options/prog_wrench_options.py | 24 ++++++++++------------ 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index c0837c150025..9331bb8d7394 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -1932,8 +1932,6 @@ def weapon_cycler(self): for name in non_prog_weapon_data.keys(): unlock_addr = non_prog_weapon_data[name].UNLOCK_ADDRESS ammo_addr = non_prog_weapon_data[name].AMMO_ADDRESS - xp_addr = non_prog_weapon_data[name].XP_ADDRESS - level_addr = non_prog_weapon_data[name].LEVEL_ADDRESS if self.UnlockItem[name].status: if self.UnlockItem[name].unlock_delay: self._write8(unlock_addr, 1) @@ -1951,8 +1949,6 @@ def weapon_cycler(self): # Prevent the player from using locked weapons and leveling them to accidentally break vendors self._write8(unlock_addr, 0) self._write32(ammo_addr, 0) - self._write32(xp_addr, 0) - self._write8(level_addr, UPGRADE_DICT[name][0]) if self.equipped_item > 1 and self.UnlockItem[ITEM_NAME_FROM_ID[self.equipped_item]].status == 0: if self.last_used_1 == 0: @@ -1976,6 +1972,9 @@ def weapon_cycler(self): def wrench_cycler(self): """Cycle through the wrench properties and update its state""" prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] + if not prog_wrench: + return + if self.planet != RAC3REGION.MENU and self.between_planets is False: wrench_instruction = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.BASE_ITEM_ID_OFFSET wrench_upgrade = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.UPGRADE_ID_OFFSET diff --git a/worlds/rac3/constants/data/item.py b/worlds/rac3/constants/data/item.py index c1f4472f3c0a..a90a168f48ba 100644 --- a/worlds/rac3/constants/data/item.py +++ b/worlds/rac3/constants/data/item.py @@ -614,7 +614,7 @@ def from_tag(tag: str) -> dict[str, RAC3ITEMDATA]: RAC3ITEMTAG.NGPLUS: set(ngplus_data.keys()), RAC3ITEMTAG.NON_PROG_WEAPON: set(non_prog_weapon_data.keys()), RAC3ITEMTAG.PROG_WEAPON: set(prog_weapon_data.keys()), - RAC3ITEMTAG.PROG_WEAPON: set(prog_wrench_data.keys()), + RAC3ITEMTAG.PROG_WRENCH: set(prog_wrench_data.keys()), RAC3ITEMTAG.PROGRESSIVE: set(progressive_data.keys()), RAC3ITEMTAG.TRAP: set(trap_data.keys()), RAC3ITEMTAG.UNUSED: set(unused_data.keys()), diff --git a/worlds/rac3/items.py b/worlds/rac3/items.py index 94c2414d2061..12601d8cef78 100644 --- a/worlds/rac3/items.py +++ b/worlds/rac3/items.py @@ -61,8 +61,10 @@ def create_itempool(world: "RaC3World") -> list[Item]: continue if RAC3ITEMTAG.NON_PROG_WEAPON in item_tags and options.progressive_weapons.value: continue - if RAC3ITEMTAG.PROG_WRENCH in item_tags and not options.progressive_wrench.value: - continue + if RAC3ITEMTAG.PROG_WRENCH in item_tags: + if name != RAC3ITEM.PROGRESSIVE_WRENCH: + continue + item_amount = options.progressive_wrench.value # NG+ Item option if RAC3ITEMTAG.NGPLUS in item_tags: diff --git a/worlds/rac3/options/prog_wrench_options.py b/worlds/rac3/options/prog_wrench_options.py index 349f9ccfabeb..2cbff539c879 100644 --- a/worlds/rac3/options/prog_wrench_options.py +++ b/worlds/rac3/options/prog_wrench_options.py @@ -1,23 +1,21 @@ """This module contains options for the Progressive OmniWrench in the item pool""" -from Options import Choice +from Options import Range from worlds.rac3.constants.options import RAC3OPTION -class ProgressiveWrench(Choice): +class ProgressiveWrench(Range): """ - Determines whether the OmniWrench is a Progressive item or not. + Determines how many Progressive Armor items are included in the item pool. ------------------------------------------------------------------------------------ - Disable: OmniWrench functions like in the vanilla game. - Manual Upgrade: OmniWrench is allowed to upgrade if the Nanotech level required is reached and its progressive item is collected. - Automatic Upgrade: The OmniWrench will upgrade when its progressive item is collected, ignoring your Nanotech level. - Lost Wrench: Ratchet will start without its OmniWrench and will need to be collected first. DO NOT USE YET. + Set to 0 for No Wrench Upgrades. + Set to 7 for all OmniWrench upgrades to be available. + Set above 7 to add extra OmniWrench Upgrades copies into the item pool. + Collecting more than 7 Progressive OmniWrench items will do nothing. ------------------------------------------------------------------------------------ - Note: If Weapon Level Locations are enabled, Automatic Upgrade will be forced to Manual Upgrade instead. + Note: Experimental feature. """ display_name = RAC3OPTION.PROGRESSIVE_WRENCH - option_disable = 0 - option_manual_upgrade = 1 - option_automatic_upgrade = 2 - option_lost_wrench = 3 - default = 0 + range_start = 0 + range_end = 9 + default = 7 From f9198edc979e8b045c57190420938a62a6351f53 Mon Sep 17 00:00:00 2001 From: 1theory Date: Fri, 7 Aug 2026 21:10:05 +0200 Subject: [PATCH 08/18] RAC3: Options fixed. --- worlds/rac3/constants/data/address.py | 1 + worlds/rac3/constants/data/item.py | 16 ++++++++-------- worlds/rac3/items.py | 12 ++++++++---- worlds/rac3/options/prog_wrench_options.py | 19 +++++++++---------- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/worlds/rac3/constants/data/address.py b/worlds/rac3/constants/data/address.py index 314150423825..ba6603080fb5 100644 --- a/worlds/rac3/constants/data/address.py +++ b/worlds/rac3/constants/data/address.py @@ -27,6 +27,7 @@ def __init__(self, data: tuple[int, CHECKTYPE, int]): RAC3ADDRESSDATA((RAC3STATUS.CRYSTALS_CURRENT, CHECKTYPE.BYTE, 0)), *[RAC3ADDRESSDATA((weapon.AMMO_ADDRESS, CHECKTYPE.INT, weapon.AMMO)) for weapon in non_prog_weapon_data.values()], *[RAC3ADDRESSDATA((weapon.XP_ADDRESS, CHECKTYPE.INT, 0)) for weapon in non_prog_weapon_data.values()], + *[RAC3ADDRESSDATA((weapon.LEVEL_ADDRESS, CHECKTYPE.BYTE, weapon.ID)) for weapon in non_prog_weapon_data.values()], # Stored Fillers RAC3ADDRESSDATA((RAC3STATUS.BOLT_PACKS, CHECKTYPE.INT, 0)), RAC3ADDRESSDATA((RAC3STATUS.NANOTECH_EXP_PACKS, CHECKTYPE.INT, 0)), diff --git a/worlds/rac3/constants/data/item.py b/worlds/rac3/constants/data/item.py index a90a168f48ba..bdffab97ecf9 100644 --- a/worlds/rac3/constants/data/item.py +++ b/worlds/rac3/constants/data/item.py @@ -377,8 +377,6 @@ def construct_cheat(idx: int, RAC3ITEM.PLASMA_COIL_V2: RAC3ITEMDATA.construct_weapon_level(0xA0, 3000, 15, 8000), RAC3ITEM.LAVA_GUN_V2: RAC3ITEMDATA.construct_weapon_level(0xA1, 240, 150, 600), RAC3ITEM.MINI_TURRET_V2: RAC3ITEMDATA.construct_weapon_level(0xA2, 800, 10, 400), - RAC3ITEM.WRENCH_V2: RAC3ITEMDATA.construct_unused(0xA4), - RAC3ITEM.WRENCH_V3: RAC3ITEMDATA.construct_unused(0xA5), RAC3ITEM.BOUNCER_V2: RAC3ITEMDATA.construct_weapon_level(0xA6, 1400, 10, 2500), RAC3ITEM.SHIELD_CHARGER_V2: RAC3ITEMDATA.construct_weapon_level(0xA7, 100, 3, 2200), RAC3ITEM.MINI_TURRET_V3: RAC3ITEMDATA.construct_weapon_level(0xA8, 1000, 12, 1000), @@ -411,11 +409,6 @@ def construct_cheat(idx: int, RAC3ITEM.TESLA_BARRIER_V6: RAC3ITEMDATA.construct_weapon_level(0xC3, 300, 4, tags=[RAC3ITEMTAG.NGPLUS]), RAC3ITEM.TESLA_BARRIER_V7: RAC3ITEMDATA.construct_weapon_level(0xC4, 400, 5, 12000, [RAC3ITEMTAG.NGPLUS]), RAC3ITEM.TESLA_BARRIER_V8: RAC3ITEMDATA.construct_weapon_level(0xC5, 500, 5, 30000, [RAC3ITEMTAG.NGPLUS]), - RAC3ITEM.WRENCH_V4: RAC3ITEMDATA.construct_unused(0xC6), - RAC3ITEM.WRENCH_V5: RAC3ITEMDATA.construct_unused(0xC7), - RAC3ITEM.WRENCH_V6: RAC3ITEMDATA.construct_unused(0xC8), - RAC3ITEM.WRENCH_V7: RAC3ITEMDATA.construct_unused(0xC9), - RAC3ITEM.WRENCH_V8: RAC3ITEMDATA.construct_unused(0xCA), # Progressive RAC3ITEM.PROGRESSIVE_PLASMA_COIL: RAC3ITEMDATA.construct_rac2_prog(0xCB, ItemClassification.progression_skip_balancing), RAC3ITEM.PROGRESSIVE_LAVA_GUN: RAC3ITEMDATA.construct_rac2_prog(0xCC, ItemClassification.progression_skip_balancing), @@ -449,7 +442,14 @@ def construct_cheat(idx: int, RAC3ITEM.PROGRESSIVE_RY3N0: RAC3ITEMDATA.construct_weapon_prog(0xDE, ItemClassification.progression_skip_balancing, [RAC3ITEMTAG.NGPLUS]), RAC3ITEM.PROGRESSIVE_WRENCH: - RAC3ITEMDATA.construct_wrench(0xDF, [RAC3ITEMTAG.PROG_WRENCH]), + RAC3ITEMDATA.construct_wrench(0xDF, [RAC3ITEMTAG.PROGRESSIVE]), + RAC3ITEM.WRENCH_V2: RAC3ITEMDATA.construct_wrench(0xA4), + RAC3ITEM.WRENCH_V3: RAC3ITEMDATA.construct_wrench(0xA5), + RAC3ITEM.WRENCH_V4: RAC3ITEMDATA.construct_wrench(0xC6), + RAC3ITEM.WRENCH_V5: RAC3ITEMDATA.construct_wrench(0xC7), + RAC3ITEM.WRENCH_V6: RAC3ITEMDATA.construct_wrench(0xC8), + RAC3ITEM.WRENCH_V7: RAC3ITEMDATA.construct_wrench(0xC9), + RAC3ITEM.WRENCH_V8: RAC3ITEMDATA.construct_wrench(0xCA), # Infobots RAC3ITEM.VELDIN: RAC3ITEMDATA.construct_infobot(0xE1, ItemClassification.progression), RAC3ITEM.FLORANA: RAC3ITEMDATA.construct_infobot(0xE2, ItemClassification.progression), diff --git a/worlds/rac3/items.py b/worlds/rac3/items.py index 12601d8cef78..c39ae745d7d5 100644 --- a/worlds/rac3/items.py +++ b/worlds/rac3/items.py @@ -43,12 +43,16 @@ def create_itempool(world: "RaC3World") -> list[Item]: if options.ngplus_items.value: if name == RAC3ITEM.PROGRESSIVE_RY3N0: item_amount: int = 5 + if name == RAC3ITEM.PROGRESSIVE_WRENCH: + item_amount: int = 7 else: item_amount: int = ngplus_item_counts.get(name, 1) elif name != RAC3ITEM.PROGRESSIVE_RY3N0: item_amount: int = item_counts.get(name, 1) else: continue + if not options.ngplus_items.value and name == RAC3ITEM.PROGRESSIVE_WRENCH: + item_amount: int = 4 # Already placed items (Starting items and vanilla) if name in world.preplaced_items: count = world.preplaced_items.count(name) @@ -61,10 +65,10 @@ def create_itempool(world: "RaC3World") -> list[Item]: continue if RAC3ITEMTAG.NON_PROG_WEAPON in item_tags and options.progressive_weapons.value: continue - if RAC3ITEMTAG.PROG_WRENCH in item_tags: - if name != RAC3ITEM.PROGRESSIVE_WRENCH: - continue - item_amount = options.progressive_wrench.value + + # Progressive Wrench option + if RAC3ITEMTAG.PROG_WRENCH in item_tags and not options.progressive_wrench.value: + continue # NG+ Item option if RAC3ITEMTAG.NGPLUS in item_tags: diff --git a/worlds/rac3/options/prog_wrench_options.py b/worlds/rac3/options/prog_wrench_options.py index 2cbff539c879..fc242946b8b1 100644 --- a/worlds/rac3/options/prog_wrench_options.py +++ b/worlds/rac3/options/prog_wrench_options.py @@ -1,21 +1,20 @@ """This module contains options for the Progressive OmniWrench in the item pool""" -from Options import Range +from Options import Choice from worlds.rac3.constants.options import RAC3OPTION -class ProgressiveWrench(Range): +class ProgressiveWrench(Choice): """ - Determines how many Progressive Armor items are included in the item pool. + Determines if Progresive OmniWrench items are included in the item pool. ------------------------------------------------------------------------------------ - Set to 0 for No Wrench Upgrades. - Set to 7 for all OmniWrench upgrades to be available. - Set above 7 to add extra OmniWrench Upgrades copies into the item pool. - Collecting more than 7 Progressive OmniWrench items will do nothing. + Disable for the vanilla OmniWrench behaviour. + Enable for OmniWrench upgrades to be included in the item pool. ------------------------------------------------------------------------------------ Note: Experimental feature. """ display_name = RAC3OPTION.PROGRESSIVE_WRENCH - range_start = 0 - range_end = 9 - default = 7 + option_disabled = 0 + option_enabled = 1 + default = 0 + From f09d031ae13f00c3690bb9399cf494a4121fac39 Mon Sep 17 00:00:00 2001 From: 1theory Date: Sat, 8 Aug 2026 16:57:54 +0200 Subject: [PATCH 09/18] RAC3: Added PAL support for the Progressive Wrench --- worlds/rac3/client/rac3_interface.py | 29 ++++++++++---------- worlds/rac3/constants/region.py | 31 +++++++++++++++++++++- worlds/rac3/constants/status.py | 9 ++++--- worlds/rac3/constants/wrench.py | 21 ++++++++++----- worlds/rac3/options/prog_wrench_options.py | 2 +- 5 files changed, 66 insertions(+), 26 deletions(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index 9331bb8d7394..562ed7e7d5ba 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -56,8 +56,8 @@ from worlds.rac3.constants.player_action import PLAYER_ACTION_NAMES, RAC3PLAYERACTION from worlds.rac3.constants.player_type import PLAYER_TYPE_TO_NAME, RAC3PLAYERTYPE from worlds.rac3.constants.progress_flag import HALO_JUMP_TO_REGION, RAC3PROGRESSFLAG -from worlds.rac3.constants.region import (PLANET_LOAD_OFFSET, PLANET_NAME_FROM_ID, PLANET_VENDOR_OFFSET, WRENCH_FUNCTION_OFFSET, - PLANETS_WITH_HACKER_PUZZLES, PLANETS_WITH_REFRACTOR_PUZZLES, +from worlds.rac3.constants.region import (PLANET_LOAD_OFFSET, PLANET_NAME_FROM_ID, PLANET_VENDOR_OFFSET, WRENCH_FUNCTION_OFFSET_NTSC, + WRENCH_FUNCTION_OFFSET_PAL, PLANETS_WITH_HACKER_PUZZLES, PLANETS_WITH_REFRACTOR_PUZZLES, PLANETS_WITH_TYHRRANOID_PUZZLES, RAC3REGION, REGION_TO_HACKER_DOOR_COUNT, RESPAWN_COORDS_OFFSET) from worlds.rac3.constants.ship_slot import RAC3SHIPSLOT, SHIP_SLOTS @@ -1971,18 +1971,19 @@ def weapon_cycler(self): def wrench_cycler(self): """Cycle through the wrench properties and update its state""" - prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] - if not prog_wrench: - return - - if self.planet != RAC3REGION.MENU and self.between_planets is False: - wrench_instruction = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.BASE_ITEM_ID_OFFSET - wrench_upgrade = RAC3WRENCH.get_wrench_property_address(self.planet) + RAC3WRENCH.UPGRADE_ID_OFFSET - target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] - if self._read32(wrench_instruction) == 0xA0620009: - for _ in range(6): - self._write8(wrench_upgrade, target_id) - wrench_upgrade += RAC3WRENCH.PER_LEVEL_OFFSET + if self.options.progressive_wrench: + prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] + if not prog_wrench: + return + + if self.planet != RAC3REGION.MENU and self.between_planets is False: + wrench_instruction = RAC3WRENCH.get_wrench_property_address(self.planet, self.current_game) + RAC3WRENCH.BASE_ITEM_ID_OFFSET + wrench_upgrade = RAC3WRENCH.get_wrench_property_address(self.planet, self.current_game) + RAC3WRENCH.UPGRADE_ID_OFFSET + target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] + if self._read32(wrench_instruction) == 0xA0620009: + for _ in range(6): + self._write8(wrench_upgrade, target_id) + wrench_upgrade += RAC3WRENCH.PER_LEVEL_OFFSET def update_weapon_equip(self, equip: int | None, last_0: int | None, last_1: int | None, last_2: int | None): diff --git a/worlds/rac3/constants/region.py b/worlds/rac3/constants/region.py index 9db746c0de91..9a7fef21dc26 100644 --- a/worlds/rac3/constants/region.py +++ b/worlds/rac3/constants/region.py @@ -262,7 +262,7 @@ class RAC3REGION: RAC3REGION.OBANI_DRACO: 0x400, RAC3REGION.COMMAND_CENTER: 0x1D80, } -WRENCH_FUNCTION_OFFSET: dict[str, int] = { +WRENCH_FUNCTION_OFFSET_NTSC: dict[str, int] = { RAC3REGION.VELDIN: 0x2FDE8, RAC3REGION.FLORANA: 0x0, RAC3REGION.STARSHIP_PHOENIX: 0x1D488, @@ -291,6 +291,35 @@ class RAC3REGION: RAC3REGION.AQUATOS_SEWERS: -0x89F8, RAC3REGION.TYHRRANOSIS_RANGERS: 0x3B238 } +WRENCH_FUNCTION_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x2F990, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x1D418, + RAC3REGION.MARCADIA: 0x3A208, + RAC3REGION.DAXX: 0x28E18, + RAC3REGION.PHOENIX_ASSAULT: 0x130E0, + RAC3REGION.ANNIHILATION_NATION: 0x2E6D0, + RAC3REGION.AQUATOS: 0x9D10, + RAC3REGION.TYHRRANOSIS: 0x42A80, + RAC3REGION.ZELDRIN_STARPORT: 0x12B80, + RAC3REGION.OBANI_GEMINI: 0x5AF8, + RAC3REGION.BLACKWATER_CITY: 0x310D8, + RAC3REGION.HOLOSTAR_STUDIOS: 0xF918, + RAC3REGION.KOROS: 0x1A350, + RAC3REGION.METROPOLIS: 0x41120, + RAC3REGION.CRASH_SITE: 0x8A30, + RAC3REGION.ARIDIA: 0x42770, + RAC3REGION.QWARKS_HIDEOUT: 0x214E0, + RAC3REGION.COMMAND_CENTER_2: 0x4F9D8, + RAC3REGION.OBANI_DRACO: 0x67B0, + RAC3REGION.COMMAND_CENTER: 0x366A8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0x13778, + RAC3REGION.MUSEUM: 0x14800, + RAC3REGION.METROPOLIS_RANGERS: 0x38928, + RAC3REGION.AQUATOS_BASE: -0x1DF0, + RAC3REGION.AQUATOS_SEWERS: -0x8950, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x3B0E0 +} PLANETS_WITH_HACKER_PUZZLES: list[str] = [ RAC3REGION.STARSHIP_PHOENIX, RAC3REGION.AQUATOS, diff --git a/worlds/rac3/constants/status.py b/worlds/rac3/constants/status.py index d2e489751d6a..93cce81b9f8a 100644 --- a/worlds/rac3/constants/status.py +++ b/worlds/rac3/constants/status.py @@ -118,7 +118,8 @@ class RAC3STATUS: PAUSE_BASE = 0x001DF068 RESPAWN_BASE = 0x002348D0 VENDOR_BASE = 0x002418C0 - WRENCH_FUNCTION_BASE = 0x004DFB38 - MAGNETISM_FUNCTION_BASE = 0x004B98CC - GRAV_BOOTS_EVERYWHERE_BASE = 0x004B9808 - CHECK_FLOOR_BASE = 0x004B97FC + WRENCH_FUNCTION_BASE_NTSC = 0x004DFB38 + WRENCH_FUNCTION_BASE_PAL = 0x004E3F68 + MAGNETISM_FUNCTION_BASE_NTSC = 0x004B98CC + GRAV_BOOTS_EVERYWHERE_BASE_NTSC = 0x004B9808 + CHECK_FLOOR_BASE_NTSC = 0x004B97FC diff --git a/worlds/rac3/constants/wrench.py b/worlds/rac3/constants/wrench.py index 66dec4e4201b..61d6f4fb3bf7 100644 --- a/worlds/rac3/constants/wrench.py +++ b/worlds/rac3/constants/wrench.py @@ -1,7 +1,8 @@ """This module provides constant address offsets, for use when reading data regarding the OmniWrench""" -from worlds.rac3.constants.region import WRENCH_FUNCTION_OFFSET +from worlds.rac3.constants.region import WRENCH_FUNCTION_OFFSET_NTSC, WRENCH_FUNCTION_OFFSET_PAL from worlds.rac3.constants.status import RAC3STATUS +from worlds.rac3.constants.version import RAC3VERSION class RAC3WRENCH: @@ -12,10 +13,18 @@ class RAC3WRENCH: BASE_ITEM_ID_OFFSET: int = 0x350 # Contains the item ID that the function will write to. If 00 or 01, the OmniWrench is decoupled from Nanotech # and the function will write there instead. PER_LEVEL_OFFSET: int = 0x18 # Starting at WRENCH_FUNCTION_BASE + NANOTECH_THRESHOLD_OFFSET, - # every +0x18 will contain an upgrade. +0x90 directly jumps from V2 to V8. + # every +0x18 will contain an upgrade. +0x90 directly jumps from V2 to V8. @staticmethod - def get_wrench_property_address(planet: str) -> int: - """Provides the wrench property address for reading data""" - addr = RAC3STATUS.WRENCH_FUNCTION_BASE + WRENCH_FUNCTION_OFFSET[planet] - return addr \ No newline at end of file + def get_wrench_property_address(planet: str, game_id: str = '') -> int: + """Provides the wrench property address for reading data""" + match game_id: + case RAC3VERSION.US_ID: + addr = RAC3STATUS.WRENCH_FUNCTION_BASE_NTSC + WRENCH_FUNCTION_OFFSET_NTSC[planet] + return addr + case RAC3VERSION.EU_ID: + addr = RAC3STATUS.WRENCH_FUNCTION_BASE_PAL + WRENCH_FUNCTION_OFFSET_PAL[planet] + return addr + case _: + addr = RAC3STATUS.WRENCH_FUNCTION_BASE_NTSC + WRENCH_FUNCTION_OFFSET_NTSC[planet] + return addr \ No newline at end of file diff --git a/worlds/rac3/options/prog_wrench_options.py b/worlds/rac3/options/prog_wrench_options.py index fc242946b8b1..891ec2325b5e 100644 --- a/worlds/rac3/options/prog_wrench_options.py +++ b/worlds/rac3/options/prog_wrench_options.py @@ -11,7 +11,7 @@ class ProgressiveWrench(Choice): Disable for the vanilla OmniWrench behaviour. Enable for OmniWrench upgrades to be included in the item pool. ------------------------------------------------------------------------------------ - Note: Experimental feature. + Note: Experimental feature. Even if enabled, you will start with the OmniWrench V1. """ display_name = RAC3OPTION.PROGRESSIVE_WRENCH option_disabled = 0 From a2c2b352b257358b697fccc69d526edc73b494bb Mon Sep 17 00:00:00 2001 From: 1theory Date: Sat, 8 Aug 2026 17:10:15 +0200 Subject: [PATCH 10/18] RAC3: Slight constant change. --- worlds/rac3/client/rac3_interface.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index 562ed7e7d5ba..9be54091b5e4 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -1972,14 +1972,14 @@ def weapon_cycler(self): def wrench_cycler(self): """Cycle through the wrench properties and update its state""" if self.options.progressive_wrench: - prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] + prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH.status] if not prog_wrench: return if self.planet != RAC3REGION.MENU and self.between_planets is False: wrench_instruction = RAC3WRENCH.get_wrench_property_address(self.planet, self.current_game) + RAC3WRENCH.BASE_ITEM_ID_OFFSET wrench_upgrade = RAC3WRENCH.get_wrench_property_address(self.planet, self.current_game) + RAC3WRENCH.UPGRADE_ID_OFFSET - target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] + target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench] if self._read32(wrench_instruction) == 0xA0620009: for _ in range(6): self._write8(wrench_upgrade, target_id) From f5211de67a2d3b1d18953080584c4aa9e976ac42 Mon Sep 17 00:00:00 2001 From: 1theory Date: Sat, 8 Aug 2026 18:14:03 +0200 Subject: [PATCH 11/18] RAC3: Cycler quick fix --- worlds/rac3/client/rac3_interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index 9be54091b5e4..b6dadaf7ce53 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -1972,7 +1972,7 @@ def weapon_cycler(self): def wrench_cycler(self): """Cycle through the wrench properties and update its state""" if self.options.progressive_wrench: - prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH.status] + prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH].status if not prog_wrench: return From 0dc2ff159c62420f5e3e758eca6383d49df6f05b Mon Sep 17 00:00:00 2001 From: 1theory Date: Sun, 9 Aug 2026 19:08:50 +0200 Subject: [PATCH 12/18] RAC3: Adding rules for the Progressive Wrench and further improving the cycler --- worlds/rac3/client/rac3_interface.py | 14 +++++++------- worlds/rac3/rules.py | 12 ++++++++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index b6dadaf7ce53..0854596ef113 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -1971,20 +1971,20 @@ def weapon_cycler(self): def wrench_cycler(self): """Cycle through the wrench properties and update its state""" - if self.options.progressive_wrench: - prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH].status - if not prog_wrench: - return - + if self.options.progressive_wrench: + prog_wrench = self.UnlockItem[RAC3ITEM.PROGRESSIVE_WRENCH] if self.planet != RAC3REGION.MENU and self.between_planets is False: wrench_instruction = RAC3WRENCH.get_wrench_property_address(self.planet, self.current_game) + RAC3WRENCH.BASE_ITEM_ID_OFFSET - wrench_upgrade = RAC3WRENCH.get_wrench_property_address(self.planet, self.current_game) + RAC3WRENCH.UPGRADE_ID_OFFSET - target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench] + wrench_upgrade = RAC3WRENCH.get_wrench_property_address(self.planet, self.current_game) + RAC3WRENCH.UPGRADE_ID_OFFSET + target_id = UPGRADE_DICT[RAC3ITEM.WRENCH][prog_wrench.status] if self._read32(wrench_instruction) == 0xA0620009: for _ in range(6): self._write8(wrench_upgrade, target_id) wrench_upgrade += RAC3WRENCH.PER_LEVEL_OFFSET + else: + return + def update_weapon_equip(self, equip: int | None, last_0: int | None, last_1: int | None, last_2: int | None): """Writes new values to the player's last used item history""" diff --git a/worlds/rac3/rules.py b/worlds/rac3/rules.py index db6e9127264c..0dc7a41d8199 100644 --- a/worlds/rac3/rules.py +++ b/worlds/rac3/rules.py @@ -88,6 +88,12 @@ def set_rules(world: "RaC3World"): if ngplus_enabled: progressive_requirement += 5 if world.options.ngplus_items.value else 4 + progressive_wrench_requirement = 1 + if world.options.progressive_wrench.value != 0: + progressive_wrench_requirement += 4 if world.options.ngplus_items.value else 3 + else: progressive_wrench_requirement = 0 + + region_rules_dict: dict[str, Callable] = { # Intro Florana @@ -357,7 +363,8 @@ def set_rules(world: "RaC3World"): and state.can_reach_location(RAC3LOCATION.NATION_WHIP_IT_GOOD, world.player), RAC3SKILLPOINT.NATION_BASH: - lambda state: state.can_reach_location(RAC3LOCATION.NATION_BBQ_BOULEVARD, world.player), + lambda state: state.can_reach_location(RAC3LOCATION.NATION_BBQ_BOULEVARD, world.player) + and state.has(RAC3ITEM.PROGRESSIVE_WRENCH, world.player, progressive_wrench_requirement), RAC3LOCATION.NATION_MEET_COURTNEY: lambda state: state.can_reach_location(RAC3LOCATION.NATION_BBQ_BOULEVARD, world.player), RAC3LOCATION.NATION_INFOBOT_HOLOSTAR: @@ -577,7 +584,8 @@ def set_rules(world: "RaC3World"): RAC3TBOLT.OBANI_GEMINI_2: lambda state: state.has(RAC3ITEM.REFRACTOR, world.player), RAC3LOCATION.OBANI_GEMINI_SKIDD: lambda state: state.has(RAC3ITEM.REFRACTOR, world.player), - # RAC3SKILLPOINT.BLACKWATER_BASH + RAC3SKILLPOINT.BLACKWATER_BASH: + lambda state: state.has(RAC3ITEM.PROGRESSIVE_WRENCH, world.player, progressive_wrench_requirement), # RAC3LOCATION.BLACKWATER_CITY_RANGERS_1 RAC3LOCATION.BLACKWATER_CITY_RANGERS_2: lambda state: state.can_reach_location(RAC3LOCATION.BLACKWATER_CITY_RANGERS_1, world.player), From 184022c3fa593e706eae70e0a72f6017cc80df6c Mon Sep 17 00:00:00 2001 From: 1theory Date: Tue, 11 Aug 2026 00:06:33 +0200 Subject: [PATCH 13/18] RAC3: Added specific file for functions and organizing --- worlds/rac3/constants/function.py | 137 ++++++++++++++++++++++++++++++ worlds/rac3/constants/region.py | 58 ------------- worlds/rac3/constants/status.py | 6 +- worlds/rac3/constants/wrench.py | 51 +++++++++-- 4 files changed, 182 insertions(+), 70 deletions(-) create mode 100644 worlds/rac3/constants/function.py diff --git a/worlds/rac3/constants/function.py b/worlds/rac3/constants/function.py new file mode 100644 index 000000000000..75ddbea520ae --- /dev/null +++ b/worlds/rac3/constants/function.py @@ -0,0 +1,137 @@ +"""This module contains the constant base addresses used when reading in game functions""" + +from worlds.rac3.constants.region import RAC3REGION + +class RAC3FUNCTION: + """Constant addresses for functions""" + + ENEMY_SPEED_BASE_NTSC = 0x00410494 + RATCHET_SKELETON_BASE_NTSC = 0x004112F0 + SWING_WRENCH_BASE_NTSC = 0x004D38F0 + EQUIP_WRENCH_BASE_NTSC = 0x004BDB58 + EQUIP_WRENCH_BASE_PAL = 0x004C1DA8 + INVERSE_JUMP_BASE_NTSC = 0x004C2B88 + JUMP_FUNCTION_BASE_NTSC = 0x004C2908 + WRENCH_FUNCTION_BASE_NTSC = 0x004DFB38 + WRENCH_FUNCTION_BASE_PAL = 0x004E3F68 + PLAYER_STATE_LOCK_BASE_NTSC = 0x004CF420 + MAGNETISM_FUNCTION_BASE_NTSC = 0x004B98CC + GRAV_BOOTS_EVERYWHERE_BASE_NTSC = 0x004B9808 + CHECK_FLOOR_BASE_NTSC = 0x004C0B40 # + 0x30C + +WRENCH_FUNCTION_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x2FDE8, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x1D488, + RAC3REGION.MARCADIA: 0x3A348, + RAC3REGION.DAXX: 0x28BB0, + RAC3REGION.PHOENIX_ASSAULT: 0x13758, + RAC3REGION.ANNIHILATION_NATION: 0x2EBA8, + RAC3REGION.AQUATOS: 0x9CE0, + RAC3REGION.TYHRRANOSIS: 0x42CE0, + RAC3REGION.ZELDRIN_STARPORT: 0x12910, + RAC3REGION.OBANI_GEMINI: 0x5E10, + RAC3REGION.BLACKWATER_CITY: 0x313B0, + RAC3REGION.HOLOSTAR_STUDIOS: 0xFA10, + RAC3REGION.KOROS: 0x1A668, + RAC3REGION.METROPOLIS: 0x412F8, + RAC3REGION.CRASH_SITE: 0x9008, + RAC3REGION.ARIDIA: 0x42688, + RAC3REGION.QWARKS_HIDEOUT: 0x21250, + RAC3REGION.COMMAND_CENTER_2: 0x4F830, + RAC3REGION.OBANI_DRACO: 0x6C88, + RAC3REGION.COMMAND_CENTER: 0x36978, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0x13C00, + RAC3REGION.MUSEUM: 0x14BD8, + RAC3REGION.METROPOLIS_RANGERS: 0x38900, + RAC3REGION.AQUATOS_BASE: -0x16E8, + RAC3REGION.AQUATOS_SEWERS: -0x89F8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x3B238 +} +WRENCH_FUNCTION_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x2F990, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x1D418, + RAC3REGION.MARCADIA: 0x3A208, + RAC3REGION.DAXX: 0x28E18, + RAC3REGION.PHOENIX_ASSAULT: 0x130E0, + RAC3REGION.ANNIHILATION_NATION: 0x2E6D0, + RAC3REGION.AQUATOS: 0x9D10, + RAC3REGION.TYHRRANOSIS: 0x42A80, + RAC3REGION.ZELDRIN_STARPORT: 0x12B80, + RAC3REGION.OBANI_GEMINI: 0x5AF8, + RAC3REGION.BLACKWATER_CITY: 0x310D8, + RAC3REGION.HOLOSTAR_STUDIOS: 0xF918, + RAC3REGION.KOROS: 0x1A350, + RAC3REGION.METROPOLIS: 0x41120, + RAC3REGION.CRASH_SITE: 0x8A30, + RAC3REGION.ARIDIA: 0x42770, + RAC3REGION.QWARKS_HIDEOUT: 0x214E0, + RAC3REGION.COMMAND_CENTER_2: 0x4F9D8, + RAC3REGION.OBANI_DRACO: 0x67B0, + RAC3REGION.COMMAND_CENTER: 0x366A8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0x13778, + RAC3REGION.MUSEUM: 0x14800, + RAC3REGION.METROPOLIS_RANGERS: 0x38928, + RAC3REGION.AQUATOS_BASE: -0x1DF0, + RAC3REGION.AQUATOS_SEWERS: -0x8950, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x3B0E0 +} +EQUIP_WRENCH_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x2ACD8, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x182D8, + RAC3REGION.MARCADIA: 0x39BD8, + RAC3REGION.DAXX: 0x23AB8, + RAC3REGION.PHOENIX_ASSAULT: 0xE6B0, + RAC3REGION.ANNIHILATION_NATION: 0x29B00, + RAC3REGION.AQUATOS: 0xBB60, + RAC3REGION.TYHRRANOSIS: 0x43688, + RAC3REGION.ZELDRIN_STARPORT: 0xD818, + RAC3REGION.OBANI_GEMINI: 0xD18, + RAC3REGION.BLACKWATER_CITY: 0x2C2A0, + RAC3REGION.HOLOSTAR_STUDIOS: 0xA918, + RAC3REGION.KOROS: 0x15570, + RAC3REGION.METROPOLIS: 0x3C1E8, + RAC3REGION.CRASH_SITE: 0x3F60, + RAC3REGION.ARIDIA: 0x3D578, + RAC3REGION.QWARKS_HIDEOUT: 0x1EA58, + RAC3REGION.COMMAND_CENTER_2: 0x4A720, + RAC3REGION.OBANI_DRACO: 0x1B90, + RAC3REGION.COMMAND_CENTER: 0x31868, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xCEA8, + RAC3REGION.MUSEUM: 0xFAC8, + RAC3REGION.METROPOLIS_RANGERS: 0x337F0, + RAC3REGION.AQUATOS_BASE: 0x6C0, + RAC3REGION.AQUATOS_SEWERS: -0xDAF0, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x36128 +} +EQUIP_WRENCH_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x2A858, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x18240, + RAC3REGION.MARCADIA: 0x39AA0, + RAC3REGION.DAXX: 0x23CF8, + RAC3REGION.PHOENIX_ASSAULT: 0xE010, + RAC3REGION.ANNIHILATION_NATION: 0x29600, + RAC3REGION.AQUATOS: 0xBBB0, + RAC3REGION.TYHRRANOSIS: 0x43448, + RAC3REGION.ZELDRIN_STARPORT: 0xDA60, + RAC3REGION.OBANI_GEMINI: 0x9D8, + RAC3REGION.BLACKWATER_CITY: 0x2BFA0, + RAC3REGION.HOLOSTAR_STUDIOS: 0xA7F8, + RAC3REGION.KOROS: 0x15230, + RAC3REGION.METROPOLIS: 0x3BFE8, + RAC3REGION.CRASH_SITE: 0x3960, + RAC3REGION.ARIDIA: 0x3D638, + RAC3REGION.QWARKS_HIDEOUT: 0x1ED10, + RAC3REGION.COMMAND_CENTER_2: 0x4A8A0, + RAC3REGION.OBANI_DRACO: 0x1690, + RAC3REGION.COMMAND_CENTER: 0x31570, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xC9F0, + RAC3REGION.MUSEUM: 0xF6C8, + RAC3REGION.METROPOLIS_RANGERS: 0x337F0, + RAC3REGION.AQUATOS_BASE: -0x30, + RAC3REGION.AQUATOS_SEWERS: -0xDA70, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x35FA8 +} \ No newline at end of file diff --git a/worlds/rac3/constants/region.py b/worlds/rac3/constants/region.py index 9a7fef21dc26..07a781aa5af7 100644 --- a/worlds/rac3/constants/region.py +++ b/worlds/rac3/constants/region.py @@ -262,64 +262,6 @@ class RAC3REGION: RAC3REGION.OBANI_DRACO: 0x400, RAC3REGION.COMMAND_CENTER: 0x1D80, } -WRENCH_FUNCTION_OFFSET_NTSC: dict[str, int] = { - RAC3REGION.VELDIN: 0x2FDE8, - RAC3REGION.FLORANA: 0x0, - RAC3REGION.STARSHIP_PHOENIX: 0x1D488, - RAC3REGION.MARCADIA: 0x3A348, - RAC3REGION.DAXX: 0x28BB0, - RAC3REGION.PHOENIX_ASSAULT: 0x13758, - RAC3REGION.ANNIHILATION_NATION: 0x2EBA8, - RAC3REGION.AQUATOS: 0x9CE0, - RAC3REGION.TYHRRANOSIS: 0x42CE0, - RAC3REGION.ZELDRIN_STARPORT: 0x12910, - RAC3REGION.OBANI_GEMINI: 0x5E10, - RAC3REGION.BLACKWATER_CITY: 0x313B0, - RAC3REGION.HOLOSTAR_STUDIOS: 0xFA10, - RAC3REGION.KOROS: 0x1A668, - RAC3REGION.METROPOLIS: 0x412F8, - RAC3REGION.CRASH_SITE: 0x9008, - RAC3REGION.ARIDIA: 0x42688, - RAC3REGION.QWARKS_HIDEOUT: 0x21250, - RAC3REGION.COMMAND_CENTER_2: 0x4F830, - RAC3REGION.OBANI_DRACO: 0x6C88, - RAC3REGION.COMMAND_CENTER: 0x36978, - RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0x13C00, - RAC3REGION.MUSEUM: 0x14BD8, - RAC3REGION.METROPOLIS_RANGERS: 0x38900, - RAC3REGION.AQUATOS_BASE: -0x16E8, - RAC3REGION.AQUATOS_SEWERS: -0x89F8, - RAC3REGION.TYHRRANOSIS_RANGERS: 0x3B238 -} -WRENCH_FUNCTION_OFFSET_PAL: dict[str, int] = { - RAC3REGION.VELDIN: 0x2F990, - RAC3REGION.FLORANA: 0x0, - RAC3REGION.STARSHIP_PHOENIX: 0x1D418, - RAC3REGION.MARCADIA: 0x3A208, - RAC3REGION.DAXX: 0x28E18, - RAC3REGION.PHOENIX_ASSAULT: 0x130E0, - RAC3REGION.ANNIHILATION_NATION: 0x2E6D0, - RAC3REGION.AQUATOS: 0x9D10, - RAC3REGION.TYHRRANOSIS: 0x42A80, - RAC3REGION.ZELDRIN_STARPORT: 0x12B80, - RAC3REGION.OBANI_GEMINI: 0x5AF8, - RAC3REGION.BLACKWATER_CITY: 0x310D8, - RAC3REGION.HOLOSTAR_STUDIOS: 0xF918, - RAC3REGION.KOROS: 0x1A350, - RAC3REGION.METROPOLIS: 0x41120, - RAC3REGION.CRASH_SITE: 0x8A30, - RAC3REGION.ARIDIA: 0x42770, - RAC3REGION.QWARKS_HIDEOUT: 0x214E0, - RAC3REGION.COMMAND_CENTER_2: 0x4F9D8, - RAC3REGION.OBANI_DRACO: 0x67B0, - RAC3REGION.COMMAND_CENTER: 0x366A8, - RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0x13778, - RAC3REGION.MUSEUM: 0x14800, - RAC3REGION.METROPOLIS_RANGERS: 0x38928, - RAC3REGION.AQUATOS_BASE: -0x1DF0, - RAC3REGION.AQUATOS_SEWERS: -0x8950, - RAC3REGION.TYHRRANOSIS_RANGERS: 0x3B0E0 -} PLANETS_WITH_HACKER_PUZZLES: list[str] = [ RAC3REGION.STARSHIP_PHOENIX, RAC3REGION.AQUATOS, diff --git a/worlds/rac3/constants/status.py b/worlds/rac3/constants/status.py index 93cce81b9f8a..b8188876c069 100644 --- a/worlds/rac3/constants/status.py +++ b/worlds/rac3/constants/status.py @@ -109,6 +109,7 @@ class RAC3STATUS: NANOTECH_EXP_PACKS = 0x00142DE8 WEAPON_LEVEL_PACKS = 0x00142DEC JACKPOT_PACKS = 0x00142DF0 + CURRENT_FLOOR = 0x001A6050 # these values are high enough to vary based on planet VIDCOMIC_PAUSE = 0x001D7C48 PLANET_LOAD_BASE = 0x001DE544 @@ -118,8 +119,3 @@ class RAC3STATUS: PAUSE_BASE = 0x001DF068 RESPAWN_BASE = 0x002348D0 VENDOR_BASE = 0x002418C0 - WRENCH_FUNCTION_BASE_NTSC = 0x004DFB38 - WRENCH_FUNCTION_BASE_PAL = 0x004E3F68 - MAGNETISM_FUNCTION_BASE_NTSC = 0x004B98CC - GRAV_BOOTS_EVERYWHERE_BASE_NTSC = 0x004B9808 - CHECK_FLOOR_BASE_NTSC = 0x004B97FC diff --git a/worlds/rac3/constants/wrench.py b/worlds/rac3/constants/wrench.py index 61d6f4fb3bf7..fbbda6dbb97a 100644 --- a/worlds/rac3/constants/wrench.py +++ b/worlds/rac3/constants/wrench.py @@ -1,10 +1,9 @@ """This module provides constant address offsets, for use when reading data regarding the OmniWrench""" -from worlds.rac3.constants.region import WRENCH_FUNCTION_OFFSET_NTSC, WRENCH_FUNCTION_OFFSET_PAL -from worlds.rac3.constants.status import RAC3STATUS +from worlds.rac3.constants.function import (RAC3FUNCTION, WRENCH_FUNCTION_OFFSET_PAL, WRENCH_FUNCTION_OFFSET_NTSC, EQUIP_WRENCH_OFFSET_NTSC, + EQUIP_WRENCH_OFFSET_PAL) from worlds.rac3.constants.version import RAC3VERSION - class RAC3WRENCH: """Base struct for the Wrench function data, containing common address offsets""" NANOTECH_THRESHOLD_OFFSET: int = 0x2B0 # Contains the instruction that holds the Nanotech required to reach a certain upgrade. @@ -15,16 +14,54 @@ class RAC3WRENCH: PER_LEVEL_OFFSET: int = 0x18 # Starting at WRENCH_FUNCTION_BASE + NANOTECH_THRESHOLD_OFFSET, # every +0x18 will contain an upgrade. +0x90 directly jumps from V2 to V8. + #SWING_WRENCH_BASE_NTSC = 0x004D38F0 + SWING_WRENCH_ADDRESS_OFFSET: int = 0xD8 # 24020009, if 24020000 or NOP'd, you cannot swing the wrench. + + #EQUIP_WRENCH_BASE_NTSC = 0x004BDB58 + EQUIP_WRENCH_ADDRESS_OFFSET: int = 0x174 # 908228CA, if 90820000 or NOP'd, you cannot equip the wrench. + HELD_WRENCH_ADDRESS_OFFSET: int = 0x1B0 # 24040009, if 24040000 or NOP'd, the player will hold nothing when pressing square. + + #todo: Research and write the offsets in their determined file + @staticmethod def get_wrench_property_address(planet: str, game_id: str = '') -> int: """Provides the wrench property address for reading data""" match game_id: case RAC3VERSION.US_ID: - addr = RAC3STATUS.WRENCH_FUNCTION_BASE_NTSC + WRENCH_FUNCTION_OFFSET_NTSC[planet] + addr = RAC3FUNCTION.WRENCH_FUNCTION_BASE_NTSC + WRENCH_FUNCTION_OFFSET_NTSC[planet] return addr case RAC3VERSION.EU_ID: - addr = RAC3STATUS.WRENCH_FUNCTION_BASE_PAL + WRENCH_FUNCTION_OFFSET_PAL[planet] + addr = RAC3FUNCTION.WRENCH_FUNCTION_BASE_PAL + WRENCH_FUNCTION_OFFSET_PAL[planet] return addr case _: - addr = RAC3STATUS.WRENCH_FUNCTION_BASE_NTSC + WRENCH_FUNCTION_OFFSET_NTSC[planet] - return addr \ No newline at end of file + addr = RAC3FUNCTION.WRENCH_FUNCTION_BASE_NTSC + WRENCH_FUNCTION_OFFSET_NTSC[planet] + return addr + + @staticmethod + def get_swing_wrench_address(planet: str, game_id: str = '') -> int: + """Provides one of the many address that effectively allows or disallows the player to swing the wrench""" + match game_id: + case RAC3VERSION.US_ID: + addr = RAC3FUNCTION.SWING_WRENCH_BASE_NTSC + SWING_WRENCH_OFFSET_NTSC[planet] + return addr + case RAC3VERSION.EU_ID: + addr = RAC3FUNCTION.SWING_WRENCH_BASE_PAL + SWING_WRENCH_OFFSET_PAL[planet] + return addr + case _: + addr = RAC3FUNCTION.SWING_WRENCH_BASE_NTSC + SWING_WRENCH_OFFSET_NTSC[planet] + return addr + #RESEARCH AQUATOS AND AQUATOS BASE + + @staticmethod + def get_equip_wrench_address(planet: str, game_id: str = '') -> int: + """Provides one of the many address that effectively allows or disallows the player to equip the wrench""" + match game_id: + case RAC3VERSION.US_ID: + addr = RAC3FUNCTION.EQUIP_WRENCH_BASE_NTSC + EQUIP_WRENCH_OFFSET_NTSC[planet] + return addr + case RAC3VERSION.EU_ID: + addr = RAC3FUNCTION.EQUIP_WRENCH_BASE_PAL + EQUIP_WRENCH_OFFSET_PAL[planet] + return addr + case _: + addr = RAC3FUNCTION.EQUIP_WRENCH_BASE_NTSC + EQUIP_WRENCH_OFFSET_NTSC[planet] + return addr From 2ddb11d398c1c94e20d7632a6808e691b53417df Mon Sep 17 00:00:00 2001 From: 1theory Date: Tue, 11 Aug 2026 00:08:18 +0200 Subject: [PATCH 14/18] RAC3: Removed unaccessed wrench constant --- worlds/rac3/client/rac3_interface.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/rac3/client/rac3_interface.py b/worlds/rac3/client/rac3_interface.py index 0854596ef113..f9bb5aebcf58 100644 --- a/worlds/rac3/client/rac3_interface.py +++ b/worlds/rac3/client/rac3_interface.py @@ -56,8 +56,7 @@ from worlds.rac3.constants.player_action import PLAYER_ACTION_NAMES, RAC3PLAYERACTION from worlds.rac3.constants.player_type import PLAYER_TYPE_TO_NAME, RAC3PLAYERTYPE from worlds.rac3.constants.progress_flag import HALO_JUMP_TO_REGION, RAC3PROGRESSFLAG -from worlds.rac3.constants.region import (PLANET_LOAD_OFFSET, PLANET_NAME_FROM_ID, PLANET_VENDOR_OFFSET, WRENCH_FUNCTION_OFFSET_NTSC, - WRENCH_FUNCTION_OFFSET_PAL, PLANETS_WITH_HACKER_PUZZLES, PLANETS_WITH_REFRACTOR_PUZZLES, +from worlds.rac3.constants.region import (PLANET_LOAD_OFFSET, PLANET_NAME_FROM_ID, PLANET_VENDOR_OFFSET, PLANETS_WITH_HACKER_PUZZLES, PLANETS_WITH_REFRACTOR_PUZZLES, PLANETS_WITH_TYHRRANOID_PUZZLES, RAC3REGION, REGION_TO_HACKER_DOOR_COUNT, RESPAWN_COORDS_OFFSET) from worlds.rac3.constants.ship_slot import RAC3SHIPSLOT, SHIP_SLOTS From 313b0867ce2ee4662adef5464a734cdfd8f7fdbc Mon Sep 17 00:00:00 2001 From: 1theory Date: Tue, 11 Aug 2026 00:32:22 +0200 Subject: [PATCH 15/18] RAC3: Introducing swing and equip wrench functions and offsets --- worlds/rac3/constants/function.py | 58 +++++++++++++++++++++++++++++++ worlds/rac3/constants/wrench.py | 2 +- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/worlds/rac3/constants/function.py b/worlds/rac3/constants/function.py index 75ddbea520ae..acd04d263751 100644 --- a/worlds/rac3/constants/function.py +++ b/worlds/rac3/constants/function.py @@ -134,4 +134,62 @@ class RAC3FUNCTION: RAC3REGION.AQUATOS_BASE: -0x30, RAC3REGION.AQUATOS_SEWERS: -0xDA70, RAC3REGION.TYHRRANOSIS_RANGERS: 0x35FA8 +} +SWING_WRENCH_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x2DD88, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x1B388, + RAC3REGION.MARCADIA: 0x39820, + RAC3REGION.DAXX: 0x26B68, + RAC3REGION.PHOENIX_ASSAULT: 0x11760, + RAC3REGION.ANNIHILATION_NATION: 0x2CBB0, + RAC3REGION.AQUATOS: 0x96D8, + RAC3REGION.TYHRRANOSIS: 0x42DD8, + RAC3REGION.ZELDRIN_STARPORT: 0x108C8, + RAC3REGION.OBANI_GEMINI: 0x3DC8, + RAC3REGION.BLACKWATER_CITY: 0x2F350, + RAC3REGION.HOLOSTAR_STUDIOS: 0xD9C8, + RAC3REGION.KOROS: 0x18620, + RAC3REGION.METROPOLIS: 0x3F298, + RAC3REGION.CRASH_SITE: 0x7010, + RAC3REGION.ARIDIA: 0x40628, + RAC3REGION.QWARKS_HIDEOUT: 0x1F928, + RAC3REGION.COMMAND_CENTER_2: 0x4D7D0, + RAC3REGION.OBANI_DRACO: 0x4C40, + RAC3REGION.COMMAND_CENTER: 0x34918, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0x11120, + RAC3REGION.MUSEUM: 0x12B78, + RAC3REGION.METROPOLIS_RANGERS: 0x368A0, + RAC3REGION.AQUATOS_BASE: -0x1BD8, + RAC3REGION.AQUATOS_SEWERS: -0xAA40, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x391D8 +} +SWING_WRENCH_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x2D928, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x1B310, + RAC3REGION.MARCADIA: 0x396E8, + RAC3REGION.DAXX: 0x26DC8, + RAC3REGION.PHOENIX_ASSAULT: 0x110E0, + RAC3REGION.ANNIHILATION_NATION: 0x2C6D0, + RAC3REGION.AQUATOS: 0x9710, + RAC3REGION.TYHRRANOSIS: 0x42B80, + RAC3REGION.ZELDRIN_STARPORT: 0x10B30, + RAC3REGION.OBANI_GEMINI: 0x3AA8, + RAC3REGION.BLACKWATER_CITY: 0x2F070, + RAC3REGION.HOLOSTAR_STUDIOS: 0xD8C8, + RAC3REGION.KOROS: 0x18300, + RAC3REGION.METROPOLIS: 0x3F0B8, + RAC3REGION.CRASH_SITE: 0x6A30, + RAC3REGION.ARIDIA: 0x40708, + RAC3REGION.QWARKS_HIDEOUT: 0x1FBB0, + RAC3REGION.COMMAND_CENTER_2: 0x4D970, + RAC3REGION.OBANI_DRACO: 0x4760, + RAC3REGION.COMMAND_CENTER: 0x34640, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0x10C90, + RAC3REGION.MUSEUM: 0x12798, + RAC3REGION.METROPOLIS_RANGERS: 0x368C0, + RAC3REGION.AQUATOS_BASE: -0x22D8, + RAC3REGION.AQUATOS_SEWERS: -0xA9A0, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x39078 } \ No newline at end of file diff --git a/worlds/rac3/constants/wrench.py b/worlds/rac3/constants/wrench.py index fbbda6dbb97a..c04dea5937b7 100644 --- a/worlds/rac3/constants/wrench.py +++ b/worlds/rac3/constants/wrench.py @@ -1,7 +1,7 @@ """This module provides constant address offsets, for use when reading data regarding the OmniWrench""" from worlds.rac3.constants.function import (RAC3FUNCTION, WRENCH_FUNCTION_OFFSET_PAL, WRENCH_FUNCTION_OFFSET_NTSC, EQUIP_WRENCH_OFFSET_NTSC, - EQUIP_WRENCH_OFFSET_PAL) + EQUIP_WRENCH_OFFSET_PAL, SWING_WRENCH_OFFSET_NTSC, SWING_WRENCH_OFFSET_PAL) from worlds.rac3.constants.version import RAC3VERSION class RAC3WRENCH: From d5eafd2fe9fda511b5a7c85f47b1e73693bd604a Mon Sep 17 00:00:00 2001 From: 1theory Date: Tue, 11 Aug 2026 04:24:09 +0200 Subject: [PATCH 16/18] RAC3: Added a slice of JP support --- worlds/rac3/constants/function.py | 274 +++++++++++++++++++++++++++++- worlds/rac3/constants/wrench.py | 6 +- 2 files changed, 275 insertions(+), 5 deletions(-) diff --git a/worlds/rac3/constants/function.py b/worlds/rac3/constants/function.py index acd04d263751..af392a148e73 100644 --- a/worlds/rac3/constants/function.py +++ b/worlds/rac3/constants/function.py @@ -6,18 +6,25 @@ class RAC3FUNCTION: """Constant addresses for functions""" ENEMY_SPEED_BASE_NTSC = 0x00410494 + ENEMY_SPEED_BASE_PAL = 0x00413A04 + ENEMY_SPEED_BASE_JP = 0x0041AA54 RATCHET_SKELETON_BASE_NTSC = 0x004112F0 + RATCHET_SKELETON_BASE_PAL = 0x00414870 + RATCHET_SKELETON_BASE_JP = 0x0041B8B0 SWING_WRENCH_BASE_NTSC = 0x004D38F0 + SWING_WRENCH_BASE_PAL = 0x004D7C78 EQUIP_WRENCH_BASE_NTSC = 0x004BDB58 EQUIP_WRENCH_BASE_PAL = 0x004C1DA8 - INVERSE_JUMP_BASE_NTSC = 0x004C2B88 - JUMP_FUNCTION_BASE_NTSC = 0x004C2908 + EQUIP_WRENCH_BASE_JP = 0x004C89E0 WRENCH_FUNCTION_BASE_NTSC = 0x004DFB38 WRENCH_FUNCTION_BASE_PAL = 0x004E3F68 + CHECK_FLOOR_BASE_NTSC = 0x004C0B40 # + 0x30C + CHECK_FLOOR_BASE_PAL = 0x004C4D98 PLAYER_STATE_LOCK_BASE_NTSC = 0x004CF420 MAGNETISM_FUNCTION_BASE_NTSC = 0x004B98CC GRAV_BOOTS_EVERYWHERE_BASE_NTSC = 0x004B9808 - CHECK_FLOOR_BASE_NTSC = 0x004C0B40 # + 0x30C + INVERSE_JUMP_BASE_NTSC = 0x004C2B88 + JUMP_FUNCTION_BASE_NTSC = 0x004C2908 WRENCH_FUNCTION_OFFSET_NTSC: dict[str, int] = { RAC3REGION.VELDIN: 0x2FDE8, @@ -135,6 +142,35 @@ class RAC3FUNCTION: RAC3REGION.AQUATOS_SEWERS: -0xDA70, RAC3REGION.TYHRRANOSIS_RANGERS: 0x35FA8 } +EQUIP_WRENCH_OFFSET_JP: dict[str, int] = { + RAC3REGION.VELDIN: 0x2AC40, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x18240, + RAC3REGION.MARCADIA: 0x39B40, + RAC3REGION.DAXX: 0x23AB8, + RAC3REGION.PHOENIX_ASSAULT: 0xE670, + RAC3REGION.ANNIHILATION_NATION: 0x29A28, + RAC3REGION.AQUATOS: 0xBC20, + RAC3REGION.TYHRRANOSIS: 0x43270, + RAC3REGION.ZELDRIN_STARPORT: 0xD918, + RAC3REGION.OBANI_GEMINI: 0xD58, + RAC3REGION.BLACKWATER_CITY: 0x2C248, + RAC3REGION.HOLOSTAR_STUDIOS: 0xAA58, + RAC3REGION.KOROS: 0x155F0, + RAC3REGION.METROPOLIS: 0x3C150, + RAC3REGION.CRASH_SITE: 0x3FA0, + RAC3REGION.ARIDIA: 0x3D5A0, + RAC3REGION.QWARKS_HIDEOUT: 0x1EB58, + RAC3REGION.COMMAND_CENTER_2: 0x4A6C8, + RAC3REGION.OBANI_DRACO: 0x1BD0, + RAC3REGION.COMMAND_CENTER: 0x31890, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xCE68, + RAC3REGION.MUSEUM: 0xFB48, + RAC3REGION.METROPOLIS_RANGERS: 0x33758, + RAC3REGION.AQUATOS_BASE: 0x780, + RAC3REGION.AQUATOS_SEWERS: -0xDA70, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x36150 +} SWING_WRENCH_OFFSET_NTSC: dict[str, int] = { RAC3REGION.VELDIN: 0x2DD88, RAC3REGION.FLORANA: 0x0, @@ -192,4 +228,236 @@ class RAC3FUNCTION: RAC3REGION.AQUATOS_BASE: -0x22D8, RAC3REGION.AQUATOS_SEWERS: -0xA9A0, RAC3REGION.TYHRRANOSIS_RANGERS: 0x39078 +} +CHECK_FLOOR_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x2AF28, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x18528, + RAC3REGION.MARCADIA: 0x39D80, + RAC3REGION.DAXX: 0x23D08, + RAC3REGION.PHOENIX_ASSAULT: 0xE900, + RAC3REGION.ANNIHILATION_NATION: 0x29D50, + RAC3REGION.AQUATOS: 0xBD58, + RAC3REGION.TYHRRANOSIS: 0x43688, + RAC3REGION.ZELDRIN_STARPORT: 0xDA68, + RAC3REGION.OBANI_GEMINI: 0xF68, + RAC3REGION.BLACKWATER_CITY: 0x2C4F0, + RAC3REGION.HOLOSTAR_STUDIOS: 0xAB68, + RAC3REGION.KOROS: 0x157C0, + RAC3REGION.METROPOLIS: 0x3C438, + RAC3REGION.CRASH_SITE: 0x41B0, + RAC3REGION.ARIDIA: 0x3D7C8, + RAC3REGION.QWARKS_HIDEOUT: 0x1EC68, + RAC3REGION.COMMAND_CENTER_2: 0x4A970, + RAC3REGION.OBANI_DRACO: 0x1DE0, + RAC3REGION.COMMAND_CENTER: 0x31AB8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xD250, + RAC3REGION.MUSEUM: 0xFD18, + RAC3REGION.METROPOLIS_RANGERS: 0x33A40, + RAC3REGION.AQUATOS_BASE: 0x868, + RAC3REGION.AQUATOS_SEWERS: -0xD8A0, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x36378 +} +CHECK_FLOOR_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x2AAA8, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x18490, + RAC3REGION.MARCADIA: 0x39C48, + RAC3REGION.DAXX: 0x23F48, + RAC3REGION.PHOENIX_ASSAULT: 0xE260, + RAC3REGION.ANNIHILATION_NATION: 0x29850, + RAC3REGION.AQUATOS: 0xBDA8, + RAC3REGION.TYHRRANOSIS: 0x43448, + RAC3REGION.ZELDRIN_STARPORT: 0xDCB0, + RAC3REGION.OBANI_GEMINI: 0xC28, + RAC3REGION.BLACKWATER_CITY: 0x2C1F0, + RAC3REGION.HOLOSTAR_STUDIOS: 0xAA48, + RAC3REGION.KOROS: 0x15480, + RAC3REGION.METROPOLIS: 0x3C238, + RAC3REGION.CRASH_SITE: 0x3BB0, + RAC3REGION.ARIDIA: 0x3D888, + RAC3REGION.QWARKS_HIDEOUT: 0x1EF20, + RAC3REGION.COMMAND_CENTER_2: 0x4AAF0, + RAC3REGION.OBANI_DRACO: 0x18E0, + RAC3REGION.COMMAND_CENTER: 0x317C0, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xCD98, + RAC3REGION.MUSEUM: 0xF918, + RAC3REGION.METROPOLIS_RANGERS: 0x33A40, + RAC3REGION.AQUATOS_BASE: 0x178, + RAC3REGION.AQUATOS_SEWERS: -0xD820, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x361F8 +} +ENEMY_SPEED_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x28598, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x158C8, + RAC3REGION.MARCADIA: 0x379B8, + RAC3REGION.DAXX: 0x21188, + RAC3REGION.PHOENIX_ASSAULT: 0xB908, + RAC3REGION.ANNIHILATION_NATION: 0x28B08, + RAC3REGION.AQUATOS: 0xAA88, + RAC3REGION.TYHRRANOSIS: 0x41AF0, + RAC3REGION.ZELDRIN_STARPORT: 0xB388, + RAC3REGION.OBANI_GEMINI: 0x688, + RAC3REGION.BLACKWATER_CITY: 0x296B8, + RAC3REGION.HOLOSTAR_STUDIOS: 0x8A08, + RAC3REGION.KOROS: 0x12DC8, + RAC3REGION.METROPOLIS: 0x38D78, + RAC3REGION.CRASH_SITE: 0x31C8, + RAC3REGION.ARIDIA: 0x3A688, + RAC3REGION.QWARKS_HIDEOUT: 0x1C408, + RAC3REGION.COMMAND_CENTER_2: 0x47A48, + RAC3REGION.OBANI_DRACO: 0x15C8, + RAC3REGION.COMMAND_CENTER: 0x2D6F8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xB288, + RAC3REGION.MUSEUM: 0xEF98, + RAC3REGION.METROPOLIS_RANGERS: 0x30C08, + RAC3REGION.AQUATOS_BASE: 0xA48, + RAC3REGION.AQUATOS_SEWERS: -0xD478, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x33688 +} +ENEMY_SPEED_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x28118, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x157C8, + RAC3REGION.MARCADIA: 0x37878, + RAC3REGION.DAXX: 0x213C8, + RAC3REGION.PHOENIX_ASSAULT: 0xB248, + RAC3REGION.ANNIHILATION_NATION: 0x28608, + RAC3REGION.AQUATOS: 0xAA88, + RAC3REGION.TYHRRANOSIS: 0x418B0, + RAC3REGION.ZELDRIN_STARPORT: 0xB588, + RAC3REGION.OBANI_GEMINI: 0x348, + RAC3REGION.BLACKWATER_CITY: 0x293B8, + RAC3REGION.HOLOSTAR_STUDIOS: 0x88C8, + RAC3REGION.KOROS: 0x12A88, + RAC3REGION.METROPOLIS: 0x38B78, + RAC3REGION.CRASH_SITE: 0x2BC8, + RAC3REGION.ARIDIA: 0x3A748, + RAC3REGION.QWARKS_HIDEOUT: 0x1C648, + RAC3REGION.COMMAND_CENTER_2: 0x47BC8, + RAC3REGION.OBANI_DRACO: 0x10C8, + RAC3REGION.COMMAND_CENTER: 0x2D3B8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xADC8, + RAC3REGION.MUSEUM: 0xEB98, + RAC3REGION.METROPOLIS_RANGERS: 0x30C08, + RAC3REGION.AQUATOS_BASE: 0x308, + RAC3REGION.AQUATOS_SEWERS: -0xD3F8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x33508 +} +ENEMY_SPEED_OFFSET_JP: dict[str, int] = { + RAC3REGION.VELDIN: 0x284D8, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x15808, + RAC3REGION.MARCADIA: 0x378F8, + RAC3REGION.DAXX: 0x21188, + RAC3REGION.PHOENIX_ASSAULT: 0xB8C8, + RAC3REGION.ANNIHILATION_NATION: 0x28A08, + RAC3REGION.AQUATOS: 0xAB48, + RAC3REGION.TYHRRANOSIS: 0x416B0, + RAC3REGION.ZELDRIN_STARPORT: 0xB488, + RAC3REGION.OBANI_GEMINI: 0x6C8, + RAC3REGION.BLACKWATER_CITY: 0x29638, + RAC3REGION.HOLOSTAR_STUDIOS: 0x8B48, + RAC3REGION.KOROS: 0x12E48, + RAC3REGION.METROPOLIS: 0x38CB8, + RAC3REGION.CRASH_SITE: 0x3208, + RAC3REGION.ARIDIA: 0x3A688, + RAC3REGION.QWARKS_HIDEOUT: 0x1C508, + RAC3REGION.COMMAND_CENTER_2: 0x479C8, + RAC3REGION.OBANI_DRACO: 0x1608, + RAC3REGION.COMMAND_CENTER: 0x2D6F8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xB248, + RAC3REGION.MUSEUM: 0xF018, + RAC3REGION.METROPOLIS_RANGERS: 0x30B48, + RAC3REGION.AQUATOS_BASE: 0xB08, + RAC3REGION.AQUATOS_SEWERS: -0xD3F8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x33688 +} +RATCHET_SKELETON_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x28598, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x158C8, + RAC3REGION.MARCADIA: 0x379B8, + RAC3REGION.DAXX: 0x21188, + RAC3REGION.PHOENIX_ASSAULT: 0xB908, + RAC3REGION.ANNIHILATION_NATION: 0x28B08, + RAC3REGION.AQUATOS: 0xAA48, + RAC3REGION.TYHRRANOSIS: 0x41AF0, + RAC3REGION.ZELDRIN_STARPORT: 0xB388, + RAC3REGION.OBANI_GEMINI: 0x688, + RAC3REGION.BLACKWATER_CITY: 0x296B8, + RAC3REGION.HOLOSTAR_STUDIOS: 0x8A08, + RAC3REGION.KOROS: 0x12DC8, + RAC3REGION.METROPOLIS: 0x38D78, + RAC3REGION.CRASH_SITE: 0x31C8, + RAC3REGION.ARIDIA: 0x3A688, + RAC3REGION.QWARKS_HIDEOUT: 0x1C408, + RAC3REGION.COMMAND_CENTER_2: 0x47A48, + RAC3REGION.OBANI_DRACO: 0x15C8, + RAC3REGION.COMMAND_CENTER: 0x2D6F8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xB288, + RAC3REGION.MUSEUM: 0xEF98, + RAC3REGION.METROPOLIS_RANGERS: 0x30C08, + RAC3REGION.AQUATOS_BASE: 0xA48, + RAC3REGION.AQUATOS_SEWERS: -0xD478, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x33688 +} +RATCHET_SKELETON_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x28118, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x157C8, + RAC3REGION.MARCADIA: 0x37878, + RAC3REGION.DAXX: 0x213C8, + RAC3REGION.PHOENIX_ASSAULT: 0xB248, + RAC3REGION.ANNIHILATION_NATION: 0x28608, + RAC3REGION.AQUATOS: 0xAA88, + RAC3REGION.TYHRRANOSIS: 0x418B0, + RAC3REGION.ZELDRIN_STARPORT: 0xB588, + RAC3REGION.OBANI_GEMINI: 0x348, + RAC3REGION.BLACKWATER_CITY: 0x293B8, + RAC3REGION.HOLOSTAR_STUDIOS: 0x88C8, + RAC3REGION.KOROS: 0x12A88, + RAC3REGION.METROPOLIS: 0x38B78, + RAC3REGION.CRASH_SITE: 0x2BC8, + RAC3REGION.ARIDIA: 0x3A748, + RAC3REGION.QWARKS_HIDEOUT: 0x1C648, + RAC3REGION.COMMAND_CENTER_2: 0x47BC8, + RAC3REGION.OBANI_DRACO: 0x10C8, + RAC3REGION.COMMAND_CENTER: 0x2D3B8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xADC8, + RAC3REGION.MUSEUM: 0xEB98, + RAC3REGION.METROPOLIS_RANGERS: 0x30C08, + RAC3REGION.AQUATOS_BASE: 0x308, + RAC3REGION.AQUATOS_SEWERS: -0xD3F8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x33508 +} +RATCHET_SKELETON_OFFSET_JP: dict[str, int] = { + RAC3REGION.VELDIN: 0x284D8, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x15808, + RAC3REGION.MARCADIA: 0x378F8, + RAC3REGION.DAXX: 0x21188, + RAC3REGION.PHOENIX_ASSAULT: 0xB8C8, + RAC3REGION.ANNIHILATION_NATION: 0x28A08, + RAC3REGION.AQUATOS: 0xAB48, + RAC3REGION.TYHRRANOSIS: 0x416B0, + RAC3REGION.ZELDRIN_STARPORT: 0xB488, + RAC3REGION.OBANI_GEMINI: 0x6C8, + RAC3REGION.BLACKWATER_CITY: 0x29638, + RAC3REGION.HOLOSTAR_STUDIOS: 0x8B48, + RAC3REGION.KOROS: 0x12E48, + RAC3REGION.METROPOLIS: 0x38CB8, + RAC3REGION.CRASH_SITE: 0x3208, + RAC3REGION.ARIDIA: 0x3A688, + RAC3REGION.QWARKS_HIDEOUT: 0x1C508, + RAC3REGION.COMMAND_CENTER_2: 0x479C8, + RAC3REGION.OBANI_DRACO: 0x1608, + RAC3REGION.COMMAND_CENTER: 0x2D6F8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xB248, + RAC3REGION.MUSEUM: 0xF018, + RAC3REGION.METROPOLIS_RANGERS: 0x30B48, + RAC3REGION.AQUATOS_BASE: 0xB08, + RAC3REGION.AQUATOS_SEWERS: -0xD3F8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x33688 } \ No newline at end of file diff --git a/worlds/rac3/constants/wrench.py b/worlds/rac3/constants/wrench.py index c04dea5937b7..f3492f6a2699 100644 --- a/worlds/rac3/constants/wrench.py +++ b/worlds/rac3/constants/wrench.py @@ -1,7 +1,7 @@ """This module provides constant address offsets, for use when reading data regarding the OmniWrench""" from worlds.rac3.constants.function import (RAC3FUNCTION, WRENCH_FUNCTION_OFFSET_PAL, WRENCH_FUNCTION_OFFSET_NTSC, EQUIP_WRENCH_OFFSET_NTSC, - EQUIP_WRENCH_OFFSET_PAL, SWING_WRENCH_OFFSET_NTSC, SWING_WRENCH_OFFSET_PAL) + EQUIP_WRENCH_OFFSET_PAL, EQUIP_WRENCH_OFFSET_JP, SWING_WRENCH_OFFSET_NTSC, SWING_WRENCH_OFFSET_PAL) from worlds.rac3.constants.version import RAC3VERSION class RAC3WRENCH: @@ -50,7 +50,6 @@ def get_swing_wrench_address(planet: str, game_id: str = '') -> int: case _: addr = RAC3FUNCTION.SWING_WRENCH_BASE_NTSC + SWING_WRENCH_OFFSET_NTSC[planet] return addr - #RESEARCH AQUATOS AND AQUATOS BASE @staticmethod def get_equip_wrench_address(planet: str, game_id: str = '') -> int: @@ -62,6 +61,9 @@ def get_equip_wrench_address(planet: str, game_id: str = '') -> int: case RAC3VERSION.EU_ID: addr = RAC3FUNCTION.EQUIP_WRENCH_BASE_PAL + EQUIP_WRENCH_OFFSET_PAL[planet] return addr + case RAC3VERSION.JP_ID: + addr = RAC3FUNCTION.EQUIP_WRENCH_BASE_JP + EQUIP_WRENCH_OFFSET_JP[planet] + return addr case _: addr = RAC3FUNCTION.EQUIP_WRENCH_BASE_NTSC + EQUIP_WRENCH_OFFSET_NTSC[planet] return addr From 1398e4d97529b7e4e8118b650b5c0fcbe82a02e3 Mon Sep 17 00:00:00 2001 From: 1theory Date: Tue, 11 Aug 2026 20:04:57 +0200 Subject: [PATCH 17/18] RAC3: Added a huge bunch of functions and its offsets --- worlds/rac3/constants/function.py | 454 ++++++++++++++++++++++++++++-- 1 file changed, 438 insertions(+), 16 deletions(-) diff --git a/worlds/rac3/constants/function.py b/worlds/rac3/constants/function.py index af392a148e73..9abbda77c164 100644 --- a/worlds/rac3/constants/function.py +++ b/worlds/rac3/constants/function.py @@ -1,30 +1,46 @@ """This module contains the constant base addresses used when reading in game functions""" from worlds.rac3.constants.region import RAC3REGION +from worlds.rac3.constants.version import RAC3VERSION class RAC3FUNCTION: """Constant addresses for functions""" - ENEMY_SPEED_BASE_NTSC = 0x00410494 - ENEMY_SPEED_BASE_PAL = 0x00413A04 - ENEMY_SPEED_BASE_JP = 0x0041AA54 - RATCHET_SKELETON_BASE_NTSC = 0x004112F0 - RATCHET_SKELETON_BASE_PAL = 0x00414870 - RATCHET_SKELETON_BASE_JP = 0x0041B8B0 - SWING_WRENCH_BASE_NTSC = 0x004D38F0 - SWING_WRENCH_BASE_PAL = 0x004D7C78 + WRENCH_FUNCTION_BASE_NTSC = 0x004DFB38 + WRENCH_FUNCTION_BASE_PAL = 0x004E3F68 EQUIP_WRENCH_BASE_NTSC = 0x004BDB58 EQUIP_WRENCH_BASE_PAL = 0x004C1DA8 EQUIP_WRENCH_BASE_JP = 0x004C89E0 - WRENCH_FUNCTION_BASE_NTSC = 0x004DFB38 - WRENCH_FUNCTION_BASE_PAL = 0x004E3F68 - CHECK_FLOOR_BASE_NTSC = 0x004C0B40 # + 0x30C + SWING_WRENCH_BASE_NTSC = 0x004D38F0 + SWING_WRENCH_BASE_PAL = 0x004D7C78 + CHECK_FLOOR_BASE_NTSC = 0x004C0B40 # +0x30C to CHECK_FLOOR_ADDRESS. Value: A6221470, if A6220000 or NOP'd, nothing is written in the CURRENT_FLOOR address CHECK_FLOOR_BASE_PAL = 0x004C4D98 - PLAYER_STATE_LOCK_BASE_NTSC = 0x004CF420 - MAGNETISM_FUNCTION_BASE_NTSC = 0x004B98CC - GRAV_BOOTS_EVERYWHERE_BASE_NTSC = 0x004B9808 - INVERSE_JUMP_BASE_NTSC = 0x004C2B88 - JUMP_FUNCTION_BASE_NTSC = 0x004C2908 + ENEMY_SPEED_BASE_NTSC = 0x00410494 # -0x54 to its function start. Value: 3C043F7F, tampering with 3F7F directly affects the enemies speed + ENEMY_SPEED_BASE_PAL = 0x00413A04 + ENEMY_SPEED_BASE_JP = 0x0041AA54 + RATCHET_SKELETON_BASE_NTSC = 0x004112F0 # -0x90 to its function start. Value: 23010004, tampering with the last byte directly affects Ratchet's moby + RATCHET_SKELETON_BASE_PAL = 0x00414870 + RATCHET_SKELETON_BASE_JP = 0x0041B8B0 + SHIP_KEYS_BASE_NTSC = 0x0047ECB4 # -0x304 to its function start. Value: 3C02001D, +0x4, value: 90425533. + SHIP_KEYS_BASE_PAL = 0x00482B24 # Forms 0x001D5533, which is the Phoenix infobot flag, which is required to enter the ship + PLAYER_STATE_LOCK_BASE_NTSC = 0x004CF420 # -0x68 to its function start. Value: AE1125C4, if AE110000 or NOP'd, player state freezes and can be written over + PLAYER_STATE_LOCK_BASE_PAL = 0x004D3728 + PLAYER_STATE_LOCK_BASE_JP = 0x004DA2E8 + JUMP_FUNCTION_BASE_NTSC = 0x004C2908 # -0x98 to its function start. Value: 1040000E, if NOP'd, Ratchet cannot gain height when jumping + JUMP_FUNCTION_BASE_PAL = 0x004C6B60 + JUMP_FUNCTION_BASE_JP = 0x004CD790 + INVERSE_JUMP_BASE_NTSC = 0x004C2B88 # -0x318 to its function start. Value: 247000F0, if NOP'd, double jumps will pull Ratchet down instead + INVERSE_JUMP_BASE_PAL = 0x004C6DE0 # Same offsets as JUMP_FUNCTION + INVERSE_JUMP_BASE_JP = 0x004CDA10 + TELEPORT_BASE_NTSC = 0x00419970 # +0x14 to TELEPORT_ADDRESS. Value: A0E50020, if NOP'd, player cannot use teleport plataforms + TELEPORT_BASE_PAL = 0x0041CF28 + TELEPORT_BASE_JP = 0x00423F30 + MAGNETISM_BASE_NTSC = 0x004B98CC # -0x114 to its function start. Value: A4820368, if A4820360, magnetism is disabled + MAGNETISM_BASE_PAL = 0x004BDB14 + MAGNETISM_BASE_JP = 0x004C4754 + GRAV_BOOTS_EVERYWHERE_BASE_NTSC = 0x004B9808 # -0x50 to its function start. Value: A6200368, if tampered with, every surface is magnetic + GRAV_BOOTS_EVERYWHERE_BASE_PAL = 0x004BDA50 + GRAV_BOOTS_EVERYWHERE_BASE_JP = 0x004C4690 WRENCH_FUNCTION_OFFSET_NTSC: dict[str, int] = { RAC3REGION.VELDIN: 0x2FDE8, @@ -460,4 +476,410 @@ class RAC3FUNCTION: RAC3REGION.AQUATOS_BASE: 0xB08, RAC3REGION.AQUATOS_SEWERS: -0xD3F8, RAC3REGION.TYHRRANOSIS_RANGERS: 0x33688 +} +SHIP_KEYS_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x29E20, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x17498, + RAC3REGION.MARCADIA: 0x39920, + RAC3REGION.DAXX: 0x22BA0, + RAC3REGION.PHOENIX_ASSAULT: 0xD640, + RAC3REGION.ANNIHILATION_NATION: 0x28C58, + RAC3REGION.AQUATOS: 0xBD18, + RAC3REGION.TYHRRANOSIS: 0x43A10, + RAC3REGION.ZELDRIN_STARPORT: 0xC8F0, + RAC3REGION.OBANI_GEMINI: -0x190, + RAC3REGION.BLACKWATER_CITY: 0x2B188, + RAC3REGION.HOLOSTAR_STUDIOS: 0x9B78, + RAC3REGION.KOROS: 0x145F8, + RAC3REGION.METROPOLIS: 0x3B250, + RAC3REGION.CRASH_SITE: 0x3290, + RAC3REGION.ARIDIA: 0x3C558, + RAC3REGION.QWARKS_HIDEOUT: 0x1E408, + RAC3REGION.COMMAND_CENTER_2: 0x49868, + RAC3REGION.OBANI_DRACO: 0xCE8, + RAC3REGION.COMMAND_CENTER: 0x307E8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xB788, + RAC3REGION.MUSEUM: 0xEEF0, + RAC3REGION.METROPOLIS_RANGERS: 0x327D0, + RAC3REGION.AQUATOS_BASE: 0x5C0, + RAC3REGION.AQUATOS_SEWERS: -0xE8A0, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x351A0 +} +SHIP_KEYS_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x299A0, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x17400, + RAC3REGION.MARCADIA: 0x397E0, + RAC3REGION.DAXX: 0x22DE0, + RAC3REGION.PHOENIX_ASSAULT: 0xCFA0, + RAC3REGION.ANNIHILATION_NATION: 0x28758, + RAC3REGION.AQUATOS: 0xBD60, + RAC3REGION.TYHRRANOSIS: 0x437D0, + RAC3REGION.ZELDRIN_STARPORT: 0xCB38, + RAC3REGION.OBANI_GEMINI: -0x4D0, + RAC3REGION.BLACKWATER_CITY: 0x2AE88, + RAC3REGION.HOLOSTAR_STUDIOS: 0x9A58, + RAC3REGION.KOROS: 0x142B8, + RAC3REGION.METROPOLIS: 0x3B050, + RAC3REGION.CRASH_SITE: 0x2C90, + RAC3REGION.ARIDIA: 0x3C618, + RAC3REGION.QWARKS_HIDEOUT: 0x1E6C0, + RAC3REGION.COMMAND_CENTER_2: 0x499E8, + RAC3REGION.OBANI_DRACO: 0x7E8, + RAC3REGION.COMMAND_CENTER: 0x304F0, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xB2D8, + RAC3REGION.MUSEUM: 0xEAF0, + RAC3REGION.METROPOLIS_RANGERS: 0x327D0, + RAC3REGION.AQUATOS_BASE: -0x138, + RAC3REGION.AQUATOS_SEWERS: -0xE820, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x35020 +} +PLAYER_STATE_LOCK_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x2D160, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x1A760, + RAC3REGION.MARCADIA: 0x39598, + RAC3REGION.DAXX: 0x25F40, + RAC3REGION.PHOENIX_ASSAULT: 0x10B38, + RAC3REGION.ANNIHILATION_NATION: 0x2BF88, + RAC3REGION.AQUATOS: 0x99C0, + RAC3REGION.TYHRRANOSIS: 0x43050, + RAC3REGION.ZELDRIN_STARPORT: 0xFCA0, + RAC3REGION.OBANI_GEMINI: 0x31A0, + RAC3REGION.BLACKWATER_CITY: 0x2E728, + RAC3REGION.HOLOSTAR_STUDIOS: 0xCDA0, + RAC3REGION.KOROS: 0x179F8, + RAC3REGION.METROPOLIS: 0x3E670, + RAC3REGION.CRASH_SITE: 0x63E8, + RAC3REGION.ARIDIA: 0x3FA00, + RAC3REGION.QWARKS_HIDEOUT: 0x1F928, + RAC3REGION.COMMAND_CENTER_2: 0x4CBA8, + RAC3REGION.OBANI_DRACO: 0x4018, + RAC3REGION.COMMAND_CENTER: 0x33CF0, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0x101F0, + RAC3REGION.MUSEUM: 0x11F50, + RAC3REGION.METROPOLIS_RANGERS: 0x35C78, + RAC3REGION.AQUATOS_BASE: -0x1A60, + RAC3REGION.AQUATOS_SEWERS: -0xB668, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x385B0 +} +PLAYER_STATE_LOCK_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x2CD10, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x1A6F8, + RAC3REGION.MARCADIA: 0x39468, + RAC3REGION.DAXX: 0x261B0, + RAC3REGION.PHOENIX_ASSAULT: 0x104C8, + RAC3REGION.ANNIHILATION_NATION: 0x2BAB8, + RAC3REGION.AQUATOS: 0x9A00, + RAC3REGION.TYHRRANOSIS: 0x42E00, + RAC3REGION.ZELDRIN_STARPORT: 0xFF18, + RAC3REGION.OBANI_GEMINI: 0x2E90, + RAC3REGION.BLACKWATER_CITY: 0x2E458, + RAC3REGION.HOLOSTAR_STUDIOS: 0xCCB0, + RAC3REGION.KOROS: 0x176E8, + RAC3REGION.METROPOLIS: 0x3E4A0, + RAC3REGION.CRASH_SITE: 0x5E18, + RAC3REGION.ARIDIA: 0x3FAF0, + RAC3REGION.QWARKS_HIDEOUT: 0x1FBE0, + RAC3REGION.COMMAND_CENTER_2: 0x4CD58, + RAC3REGION.OBANI_DRACO: 0x3B48, + RAC3REGION.COMMAND_CENTER: 0x33A28, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xFD68, + RAC3REGION.MUSEUM: 0x11B80, + RAC3REGION.METROPOLIS_RANGERS: 0x35CA8, + RAC3REGION.AQUATOS_BASE: -0x2158, + RAC3REGION.AQUATOS_SEWERS: -0xB5B8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x38460 +} +PLAYER_STATE_LOCK_OFFSET_JP: dict[str, int] = { + RAC3REGION.VELDIN: 0x2D0C8, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x1A6C8, + RAC3REGION.MARCADIA: 0x39500, + RAC3REGION.DAXX: 0x25F40, + RAC3REGION.PHOENIX_ASSAULT: 0x10AF8, + RAC3REGION.ANNIHILATION_NATION: 0x2BEB0, + RAC3REGION.AQUATOS: 0x9A80, + RAC3REGION.TYHRRANOSIS: 0x42C38, + RAC3REGION.ZELDRIN_STARPORT: 0xFDA0, + RAC3REGION.OBANI_GEMINI: 0x31E0, + RAC3REGION.BLACKWATER_CITY: 0x2E6D0, + RAC3REGION.HOLOSTAR_STUDIOS: 0xCEE0, + RAC3REGION.KOROS: 0x17A78, + RAC3REGION.METROPOLIS: 0x3E5D8, + RAC3REGION.CRASH_SITE: 0x6428, + RAC3REGION.ARIDIA: 0x3FA28, + RAC3REGION.QWARKS_HIDEOUT: 0x1FA28, + RAC3REGION.COMMAND_CENTER_2: 0x4CB50, + RAC3REGION.OBANI_DRACO: 0x4058, + RAC3REGION.COMMAND_CENTER: 0x33D18, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0x101B0, + RAC3REGION.MUSEUM: 0x11FD0, + RAC3REGION.METROPOLIS_RANGERS: 0x35BE0, + RAC3REGION.AQUATOS_BASE: -0x19A0, + RAC3REGION.AQUATOS_SEWERS: -0xB5E8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x385D8 +} +JUMP_FUNCTION_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x2AFF0, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x185F0, + RAC3REGION.MARCADIA: 0x39D18, + RAC3REGION.DAXX: 0x23DD0, + RAC3REGION.PHOENIX_ASSAULT: 0xE9C8, + RAC3REGION.ANNIHILATION_NATION: 0x29E18, + RAC3REGION.AQUATOS: 0xBC60, + RAC3REGION.TYHRRANOSIS: 0x43670, + RAC3REGION.ZELDRIN_STARPORT: 0xDB30, + RAC3REGION.OBANI_GEMINI: 0x1030, + RAC3REGION.BLACKWATER_CITY: 0x2C5B8, + RAC3REGION.HOLOSTAR_STUDIOS: 0xAC30, + RAC3REGION.KOROS: 0x15888, + RAC3REGION.METROPOLIS: 0x3C500, + RAC3REGION.CRASH_SITE: 0x4278, + RAC3REGION.ARIDIA: 0x3D890, + RAC3REGION.QWARKS_HIDEOUT: 0x1ECA0, + RAC3REGION.COMMAND_CENTER_2: 0x4AA38, + RAC3REGION.OBANI_DRACO: 0x1EA8, + RAC3REGION.COMMAND_CENTER: 0x31B80, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xD318, + RAC3REGION.MUSEUM: 0xFDE0, + RAC3REGION.METROPOLIS_RANGERS: 0x33B08, + RAC3REGION.AQUATOS_BASE: 0x7E8, + RAC3REGION.AQUATOS_SEWERS: -0xD7D8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x36440 +} +JUMP_FUNCTION_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x2AB70, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x18558, + RAC3REGION.MARCADIA: 0x39BE0, + RAC3REGION.DAXX: 0x24010, + RAC3REGION.PHOENIX_ASSAULT: 0xE328, + RAC3REGION.ANNIHILATION_NATION: 0x29918, + RAC3REGION.AQUATOS: 0xBCB0, + RAC3REGION.TYHRRANOSIS: 0x43430, + RAC3REGION.ZELDRIN_STARPORT: 0xDD78, + RAC3REGION.OBANI_GEMINI: 0xCF0, + RAC3REGION.BLACKWATER_CITY: 0x2C2B8, + RAC3REGION.HOLOSTAR_STUDIOS: 0xAB10, + RAC3REGION.KOROS: 0x15548, + RAC3REGION.METROPOLIS: 0x3C300, + RAC3REGION.CRASH_SITE: 0x3C78, + RAC3REGION.ARIDIA: 0x3D950, + RAC3REGION.QWARKS_HIDEOUT: 0x1EF58, + RAC3REGION.COMMAND_CENTER_2: 0x4ABB8, + RAC3REGION.OBANI_DRACO: 0x19A8, + RAC3REGION.COMMAND_CENTER: 0x31888, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xCE60, + RAC3REGION.MUSEUM: 0xF9E0, + RAC3REGION.METROPOLIS_RANGERS: 0x33B08, + RAC3REGION.AQUATOS_BASE: 0xF8, + RAC3REGION.AQUATOS_SEWERS: -0xD758, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x362C0 +} +JUMP_FUNCTION_OFFSET_JP: dict[str, int] = { + RAC3REGION.VELDIN: 0x2AF58, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x18558, + RAC3REGION.MARCADIA: 0x39C80, + RAC3REGION.DAXX: 0x23DD0, + RAC3REGION.PHOENIX_ASSAULT: 0xE988, + RAC3REGION.ANNIHILATION_NATION: 0x29D40, + RAC3REGION.AQUATOS: 0xBD20, + RAC3REGION.TYHRRANOSIS: 0x43258, + RAC3REGION.ZELDRIN_STARPORT: 0xDC30, + RAC3REGION.OBANI_GEMINI: 0x1070, + RAC3REGION.BLACKWATER_CITY: 0x2C560, + RAC3REGION.HOLOSTAR_STUDIOS: 0xAD70, + RAC3REGION.KOROS: 0x15908, + RAC3REGION.METROPOLIS: 0x3C468, + RAC3REGION.CRASH_SITE: 0x42B8, + RAC3REGION.ARIDIA: 0x3D8B8, + RAC3REGION.QWARKS_HIDEOUT: 0x1EDA0, + RAC3REGION.COMMAND_CENTER_2: 0x4A9E0, + RAC3REGION.OBANI_DRACO: 0x1EE8, + RAC3REGION.COMMAND_CENTER: 0x31BA8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xD2D8, + RAC3REGION.MUSEUM: 0xFE60, + RAC3REGION.METROPOLIS_RANGERS: 0x33A70, + RAC3REGION.AQUATOS_BASE: 0x8A8, + RAC3REGION.AQUATOS_SEWERS: -0xD758, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x36468 +} +TELEPORT_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x28648, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x158C8, + RAC3REGION.MARCADIA: 0x37A68, + RAC3REGION.DAXX: 0x21188, + RAC3REGION.PHOENIX_ASSAULT: 0xB908, + RAC3REGION.ANNIHILATION_NATION: 0x28BB8, + RAC3REGION.AQUATOS: 0xAA88, + RAC3REGION.TYHRRANOSIS: 0x41BA0, + RAC3REGION.ZELDRIN_STARPORT: 0xB388, + RAC3REGION.OBANI_GEMINI: 0x688, + RAC3REGION.BLACKWATER_CITY: 0x29768, + RAC3REGION.HOLOSTAR_STUDIOS: 0x8AB8, + RAC3REGION.KOROS: 0x12DC8, + RAC3REGION.METROPOLIS: 0x38E28, + RAC3REGION.CRASH_SITE: 0x31C8, + RAC3REGION.ARIDIA: 0x3A738, + RAC3REGION.QWARKS_HIDEOUT: 0x1C408, + RAC3REGION.COMMAND_CENTER_2: 0x47A48, + RAC3REGION.OBANI_DRACO: 0x15C8, + RAC3REGION.COMMAND_CENTER: 0x2D7A8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xB288, + RAC3REGION.MUSEUM: 0xEF98, + RAC3REGION.METROPOLIS_RANGERS: 0x30CB8, + RAC3REGION.AQUATOS_BASE: 0xAF8, + RAC3REGION.AQUATOS_SEWERS: -0xD478, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x33738 +} +TELEPORT_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x281C8, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x157C8, + RAC3REGION.MARCADIA: 0x37928, + RAC3REGION.DAXX: 0x213C8, + RAC3REGION.PHOENIX_ASSAULT: 0xB248, + RAC3REGION.ANNIHILATION_NATION: 0x286B8, + RAC3REGION.AQUATOS: 0xAA88, + RAC3REGION.TYHRRANOSIS: 0x41960, + RAC3REGION.ZELDRIN_STARPORT: 0xB588, + RAC3REGION.OBANI_GEMINI: 0x348, + RAC3REGION.BLACKWATER_CITY: 0x29468, + RAC3REGION.HOLOSTAR_STUDIOS: 0x8978, + RAC3REGION.KOROS: 0x12A88, + RAC3REGION.METROPOLIS: 0x38C28, + RAC3REGION.CRASH_SITE: 0x2BC8, + RAC3REGION.ARIDIA: 0x3A7F8, + RAC3REGION.QWARKS_HIDEOUT: 0x1C648, + RAC3REGION.COMMAND_CENTER_2: 0x47BC8, + RAC3REGION.OBANI_DRACO: 0x10C8, + RAC3REGION.COMMAND_CENTER: 0x2D468, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xADC8, + RAC3REGION.MUSEUM: 0xEB98, + RAC3REGION.METROPOLIS_RANGERS: 0x30CB8, + RAC3REGION.AQUATOS_BASE: 0x3B8, + RAC3REGION.AQUATOS_SEWERS: -0xD3F8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x335B8 +} +TELEPORT_OFFSET_JP: dict[str, int] = { + RAC3REGION.VELDIN: 0x28588, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x15808, + RAC3REGION.MARCADIA: 0x379A8, + RAC3REGION.DAXX: 0x21188, + RAC3REGION.PHOENIX_ASSAULT: 0xB8C8, + RAC3REGION.ANNIHILATION_NATION: 0x28AB8, + RAC3REGION.AQUATOS: 0xAB48, + RAC3REGION.TYHRRANOSIS: 0x41760, + RAC3REGION.ZELDRIN_STARPORT: 0xB488, + RAC3REGION.OBANI_GEMINI: 0x6C8, + RAC3REGION.BLACKWATER_CITY: 0x296E8, + RAC3REGION.HOLOSTAR_STUDIOS: 0x8BF8, + RAC3REGION.KOROS: 0x12E48, + RAC3REGION.METROPOLIS: 0x38D68, + RAC3REGION.CRASH_SITE: 0x3208, + RAC3REGION.ARIDIA: 0x3A738, + RAC3REGION.QWARKS_HIDEOUT: 0x1C508, + RAC3REGION.COMMAND_CENTER_2: 0x479C8, + RAC3REGION.OBANI_DRACO: 0x1608, + RAC3REGION.COMMAND_CENTER: 0x2D7A8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xB248, + RAC3REGION.MUSEUM: 0xF018, + RAC3REGION.METROPOLIS_RANGERS: 0x30BF8, + RAC3REGION.AQUATOS_BASE: 0xBB8, + RAC3REGION.AQUATOS_SEWERS: -0xD3F8, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x33738 +} +MAGNETISM_OFFSET_NTSC: dict[str, int] = { + RAC3REGION.VELDIN: 0x2A738, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x17D38, + RAC3REGION.MARCADIA: 0x39F74, + RAC3REGION.DAXX: 0x23518, + RAC3REGION.PHOENIX_ASSAULT: 0xE110, + RAC3REGION.ANNIHILATION_NATION: 0x29560, + RAC3REGION.AQUATOS: 0xC09C, + RAC3REGION.TYHRRANOSIS: 0x43AD4, + RAC3REGION.ZELDRIN_STARPORT: 0xD278, + RAC3REGION.OBANI_GEMINI: 0x778, + RAC3REGION.BLACKWATER_CITY: 0x2BD00, + RAC3REGION.HOLOSTAR_STUDIOS: 0xA378, + RAC3REGION.KOROS: 0x14FD0, + RAC3REGION.METROPOLIS: 0x3BC48, + RAC3REGION.CRASH_SITE: 0x39C0, + RAC3REGION.ARIDIA: 0x3CFD8, + RAC3REGION.QWARKS_HIDEOUT: 0x1E630, + RAC3REGION.COMMAND_CENTER_2: 0x4A180, + RAC3REGION.OBANI_DRACO: 0x15F0, + RAC3REGION.COMMAND_CENTER: 0x312C8, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xC908, + RAC3REGION.MUSEUM: 0xF528, + RAC3REGION.METROPOLIS_RANGERS: 0x33250, + RAC3REGION.AQUATOS_BASE: 0xA5C, + RAC3REGION.AQUATOS_SEWERS: -0xE090, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x35B88 +} +MAGNETISM_OFFSET_PAL: dict[str, int] = { + RAC3REGION.VELDIN: 0x2A2B8, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x17CA0, + RAC3REGION.MARCADIA: 0x39E34, + RAC3REGION.DAXX: 0x23758, + RAC3REGION.PHOENIX_ASSAULT: 0xDA70, + RAC3REGION.ANNIHILATION_NATION: 0x29060, + RAC3REGION.AQUATOS: 0xC0E4, + RAC3REGION.TYHRRANOSIS: 0x43894, + RAC3REGION.ZELDRIN_STARPORT: 0xD4C0, + RAC3REGION.OBANI_GEMINI: 0x438, + RAC3REGION.BLACKWATER_CITY: 0x2BA00, + RAC3REGION.HOLOSTAR_STUDIOS: 0xA258, + RAC3REGION.KOROS: 0x14C90, + RAC3REGION.METROPOLIS: 0x3BA48, + RAC3REGION.CRASH_SITE: 0x33C0, + RAC3REGION.ARIDIA: 0x3D098, + RAC3REGION.QWARKS_HIDEOUT: 0x1E8E8, + RAC3REGION.COMMAND_CENTER_2: 0x4A300, + RAC3REGION.OBANI_DRACO: 0x10F0, + RAC3REGION.COMMAND_CENTER: 0x30FD0, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xC450, + RAC3REGION.MUSEUM: 0xF128, + RAC3REGION.METROPOLIS_RANGERS: 0x33250, + RAC3REGION.AQUATOS_BASE: 0x364, + RAC3REGION.AQUATOS_SEWERS: -0xE010, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x35A08 +} +MAGNETISM_OFFSET_JP: dict[str, int] = { + RAC3REGION.VELDIN: 0x2A6A0, + RAC3REGION.FLORANA: 0x0, + RAC3REGION.STARSHIP_PHOENIX: 0x17CA0, + RAC3REGION.MARCADIA: 0x39EDC, + RAC3REGION.DAXX: 0x23518, + RAC3REGION.PHOENIX_ASSAULT: 0xE0D0, + RAC3REGION.ANNIHILATION_NATION: 0x29488, + RAC3REGION.AQUATOS: 0xC15C, + RAC3REGION.TYHRRANOSIS: 0x436BC, + RAC3REGION.ZELDRIN_STARPORT: 0xD378, + RAC3REGION.OBANI_GEMINI: 0x7B8, + RAC3REGION.BLACKWATER_CITY: 0x2BCA8, + RAC3REGION.HOLOSTAR_STUDIOS: 0xA4B8, + RAC3REGION.KOROS: 0x15050, + RAC3REGION.METROPOLIS: 0x3BBB0, + RAC3REGION.CRASH_SITE: 0x3A00, + RAC3REGION.ARIDIA: 0x3D000, + RAC3REGION.QWARKS_HIDEOUT: 0x1E730, + RAC3REGION.COMMAND_CENTER_2: 0x4A128, + RAC3REGION.OBANI_DRACO: 0x1630, + RAC3REGION.COMMAND_CENTER: 0x312F0, + RAC3REGION.HOLOSTAR_STUDIOS_CLANK: 0xC8C8, + RAC3REGION.MUSEUM: 0xF5A8, + RAC3REGION.METROPOLIS_RANGERS: 0x331B8, + RAC3REGION.AQUATOS_BASE: 0xB1C, + RAC3REGION.AQUATOS_SEWERS: -0xE010, + RAC3REGION.TYHRRANOSIS_RANGERS: 0x35BB0 } \ No newline at end of file From 41988cbc9baa8db760a10882e38370c67e7a8c4d Mon Sep 17 00:00:00 2001 From: 1theory Date: Wed, 12 Aug 2026 03:09:09 +0200 Subject: [PATCH 18/18] RAC3: Added original function values --- worlds/rac3/constants/function.py | 104 +++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/worlds/rac3/constants/function.py b/worlds/rac3/constants/function.py index 9abbda77c164..ce67dfb84bbc 100644 --- a/worlds/rac3/constants/function.py +++ b/worlds/rac3/constants/function.py @@ -13,7 +13,7 @@ class RAC3FUNCTION: EQUIP_WRENCH_BASE_JP = 0x004C89E0 SWING_WRENCH_BASE_NTSC = 0x004D38F0 SWING_WRENCH_BASE_PAL = 0x004D7C78 - CHECK_FLOOR_BASE_NTSC = 0x004C0B40 # +0x30C to CHECK_FLOOR_ADDRESS. Value: A6221470, if A6220000 or NOP'd, nothing is written in the CURRENT_FLOOR address + CHECK_FLOOR_BASE_NTSC = 0x004C0B40 # Value: A6221470, if A6220000 or NOP'd, nothing is written in the CURRENT_FLOOR address CHECK_FLOOR_BASE_PAL = 0x004C4D98 ENEMY_SPEED_BASE_NTSC = 0x00410494 # -0x54 to its function start. Value: 3C043F7F, tampering with 3F7F directly affects the enemies speed ENEMY_SPEED_BASE_PAL = 0x00413A04 @@ -39,8 +39,106 @@ class RAC3FUNCTION: MAGNETISM_BASE_PAL = 0x004BDB14 MAGNETISM_BASE_JP = 0x004C4754 GRAV_BOOTS_EVERYWHERE_BASE_NTSC = 0x004B9808 # -0x50 to its function start. Value: A6200368, if tampered with, every surface is magnetic - GRAV_BOOTS_EVERYWHERE_BASE_PAL = 0x004BDA50 - GRAV_BOOTS_EVERYWHERE_BASE_JP = 0x004C4690 + GRAV_BOOTS_EVERYWHERE_BASE_PAL = 0x004BDA50 # theoretically, this could be accomplished with just the CHECK_FLOOR function, but this one is saved + GRAV_BOOTS_EVERYWHERE_BASE_JP = 0x004C4690 # just for reference and future use + + ORIGINAL_CHECK_FLOOR_VALUE = 0xA6221470 + ORIGINAL_ENEMY_SPEED_VALUE = 0x3C043F7F + ORIGINAL_RATCHET_SKELETON_VALUE = 0x23010004 + ORIGINAL_SHIP_KEYS_1_VALUE = 0x3C02001D + ORIGINAL_SHIP_KEYS_2_VALUE = 0x90425533 + ORIGINAL_PLAYER_STATE_LOCK_VALUE = 0xAE1125C4 + ORIGINAL_JUMP_FUNCTION_VALUE = 0x1040000E + ORIGINAL_INVERSE_JUMP_VALUE = 0x247000F0 + ORIGINAL_TELEPORT_VALUE = 0xA0E50020 + ORIGINAL_MAGNETISM_VALUE = 0xA4820368 + ORIGINAL_GRAV_BOOTS_EVERYWHERE_VALUE = 0xA6200368 + + @staticmethod + def get_check_floor_address(planet: str, game_id: str = '') -> int: + """Provides the address that effectively allows or disallows the CURRENT_FLOOR to be overwritten""" + ADDRESS_OFFSET = 0x30C + match game_id: + case RAC3VERSION.US_ID: + addr = RAC3FUNCTION.CHECK_FLOOR_BASE_NTSC + CHECK_FLOOR_OFFSET_NTSC[planet] + ADDRESS_OFFSET + return addr + case RAC3VERSION.EU_ID: + addr = RAC3FUNCTION.CHECK_FLOOR_BASE_PAL + CHECK_FLOOR_OFFSET_PAL[planet] + ADDRESS_OFFSET + return addr + #case RAC3VERSION.JP_ID: + #addr = RAC3FUNCTION.CHECK_FLOOR_BASE_JP + CHECK_FLOOR_OFFSET_JP[planet] + #return addr + case _: + addr = RAC3FUNCTION.CHECK_FLOOR_BASE_NTSC + CHECK_FLOOR_OFFSET_NTSC[planet] + ADDRESS_OFFSET + return addr + + @staticmethod + def get_enemy_speed_address(planet: str, game_id: str = '') -> int: + """Provides the address that effectively affects the enemies speed""" # Most likely causes enemy-related bugs if too fast. Use with caution + match game_id: + case RAC3VERSION.US_ID: + addr = RAC3FUNCTION.ENEMY_SPEED_BASE_NTSC + ENEMY_SPEED_OFFSET_NTSC[planet] + return addr + case RAC3VERSION.EU_ID: + addr = RAC3FUNCTION.ENEMY_SPEED_BASE_PAL + ENEMY_SPEED_OFFSET_PAL[planet] + return addr + case RAC3VERSION.JP_ID: + addr = RAC3FUNCTION.ENEMY_SPEED_BASE_JP + ENEMY_SPEED_OFFSET_JP[planet] + return addr + case _: + addr = RAC3FUNCTION.ENEMY_SPEED_BASE_NTSC + ENEMY_SPEED_OFFSET_NTSC[planet] + return addr + + @staticmethod + def get_ratchet_skeleton_address(planet: str, game_id: str = '') -> int: + """Provides the address that affects Ratchet's moby bones""" + match game_id: + case RAC3VERSION.US_ID: + addr = RAC3FUNCTION.RATCHET_SKELETON_BASE_NTSC + RATCHET_SKELETON_OFFSET_NTSC[planet] + return addr + case RAC3VERSION.EU_ID: + addr = RAC3FUNCTION.RATCHET_SKELETON_BASE_PAL + RATCHET_SKELETON_OFFSET_PAL[planet] + return addr + case RAC3VERSION.JP_ID: + addr = RAC3FUNCTION.RATCHET_SKELETON_BASE_JP + RATCHET_SKELETON_OFFSET_JP[planet] + return addr + case _: + addr = RAC3FUNCTION.RATCHET_SKELETON_BASE_NTSC + RATCHET_SKELETON_OFFSET_NTSC[planet] + return addr + + @staticmethod + def get_ship_keys_address(planet: str, game_id: str = '') -> int: + """Provides the address that can effectively change what allows the player to enter the ship""" + match game_id: + case RAC3VERSION.US_ID: + addr = RAC3FUNCTION.SHIP_KEYS_BASE_NTSC + SHIP_KEYS_OFFSET_NTSC[planet] + return addr + case RAC3VERSION.EU_ID: + addr = RAC3FUNCTION.SHIP_KEYS_BASE_PAL + SHIP_KEYS_OFFSET_PAL[planet] + return addr + #case RAC3VERSION.JP_ID: + #addr = RAC3FUNCTION.SHIP_KEYS_BASE_JP + SHIP_KEYS_OFFSET_JP[planet] + #return addr + case _: + addr = RAC3FUNCTION.SHIP_KEYS_BASE_NTSC + SHIP_KEYS_OFFSET_NTSC[planet] + return addr + + @staticmethod + def get_player_state_lock_address(planet: str, game_id: str = '') -> int: + """Provides the address that effectively unlocks player state to write whatever to it""" # Can cause crashes with untested action states + match game_id: + case RAC3VERSION.US_ID: + addr = RAC3FUNCTION.PLAYER_STATE_LOCK_BASE_NTSC + PLAYER_STATE_LOCK_OFFSET_NTSC[planet] + return addr + case RAC3VERSION.EU_ID: + addr = RAC3FUNCTION.PLAYER_STATE_LOCK_BASE_PAL + PLAYER_STATE_LOCK_OFFSET_PAL[planet] + return addr + case RAC3VERSION.JP_ID: + addr = RAC3FUNCTION.PLAYER_STATE_LOCK_BASE_JP + PLAYER_STATE_LOCK_OFFSET_JP[planet] + return addr + case _: + addr = RAC3FUNCTION.PLAYER_STATE_LOCK_BASE_NTSC + PLAYER_STATE_LOCK_OFFSET_NTSC[planet] + return addr WRENCH_FUNCTION_OFFSET_NTSC: dict[str, int] = { RAC3REGION.VELDIN: 0x2FDE8,