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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 34 additions & 25 deletions Container.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,30 +248,38 @@ def generate_patch(world: "Rac2World", patch: Rac2ProcedurePatch, instruction=No
current platinum bolt count. This changes it to read a single byte that we control to get that count instead. This
is done to decouple the platinum bolt count from platinum bolt locations checked. This same concept is also applied
to nanotech boosts below. """
upper_half, lower_half = MIPS.get_address_halves(ram.platinum_bolt_count)
for address in addresses.PLAT_BOLT_COUNT_FUNCS:
patch.write_token(APTokenTypes.WRITE, address + 0x4, bytes([0x13, 0x00, 0x00, 0x10]))
patch.write_token(APTokenTypes.WRITE, address + 0x8, bytes([0xE4, 0xB2, 0x46, 0x90]))
patch.write_token(APTokenTypes.WRITE, address, bytes([
*upper_half, 0x02, 0x3C, # lui v0,<HI>
0x13, 0x00, 0x00, 0x10, # b (+0x13)
*lower_half, 0x46, 0x90 # _lbu a2,<LO>(v0)
]))

# For some reason, the "Weapons" menu sets the secondary inventory flag for any weapon you hover with your cursor.
# This is a problem for us since secondary inventory is tied to locations, so we just disable that behavior.
for address in addresses.WEAPONS_MENU_FUNCS:
patch.write_token(APTokenTypes.WRITE, address + 0x408, MIPS.nop())

# Same for nanotech boosts
upper_half, lower_half = MIPS.get_address_halves(ram.nanotech_boost_count)
for address, spaceish_wars_address in zip(addresses.NANOTECH_COUNT_FUNCS, addresses.SPACEISH_WARS_FUNCS):
# Inject a custom procedure run on each tick of the main loop of each planet.
# It will be called through the NANOTECH_COUNT_FUNC since we are removing a few instructions there,
# leaving space for a call.
planet = ram.planet[IsoAddresses.get_planet_id_from_iso_address(address)]
patch.write_token(APTokenTypes.WRITE, spaceish_wars_address, custom_main_loop(ram, planet))

patch.write_token(APTokenTypes.WRITE, address + 0x70, bytes([0xE5, 0xB2, 0xA5, 0x90])) # lbu a1,-0x4D1B(a1)
patch.write_token(APTokenTypes.WRITE, address + 0x74, bytes([0x00, 0x00, 0xA4, 0x8F])) # lw a0,0x0(sp)
patch.write_token(APTokenTypes.WRITE, address + 0x78, bytes([0x21, 0x10, 0x85, 0x00])) # addu v0,a0,a1
patch.write_token(APTokenTypes.WRITE, address + 0x7C, MIPS.jal(planet.spaceish_wars_func))
patch.write_token(APTokenTypes.WRITE, address + 0x80, bytes([0x00, 0x00, 0xA2, 0xAF])) # sw v0,0x0(sp)
patch.write_token(APTokenTypes.WRITE, address + 0x84, bytes([0x07, 0x00, 0x00, 0x10])) # beq zero,zero,0x7
patch.write_token(APTokenTypes.WRITE, address + 0x88, MIPS.nop())
patch.write_token(APTokenTypes.WRITE, address + 0x6C, bytes([
*upper_half, 0x05, 0x3C, # lui a1,<HI>
*lower_half, 0xA5, 0x90, # lbu a1,<LO>(a1)
0x00, 0x00, 0xA4, 0x8F, # lw a0,0x0(sp)
0x21, 0x10, 0x85, 0x00, # addu v0,a0,a1
*MIPS.jal(planet.spaceish_wars_func),
0x00, 0x00, 0xA2, 0xAF, # _sw v0,0x0(sp)
0x07, 0x00, 0x00, 0x10, # beq zero,zero,0x7
*MIPS.nop()
]))

# Prevent Platinum Bolt received message popup at the end of ship races.
for address in addresses.RACE_CONTROLLER_FUNCS:
Expand Down Expand Up @@ -636,22 +644,23 @@ def generate_patch(world: "Rac2World", patch: Rac2ProcedurePatch, instruction=No
patch.write_token(APTokenTypes.WRITE, address + 0x440, bytes([0x67, 0x7B, 0x63, 0x90]))
# Make Hypnotist check AP controlled Hypnomatic Part Count
# instead of normal address to determine total parts collected.
patch.write_token(APTokenTypes.WRITE, address + 0x19C, bytes([0x1A, 0x00, 0x03, 0x3C]))
patch.write_token(APTokenTypes.WRITE, address + 0x1A0, bytes([0xE6, 0xB2, 0x62, 0x90]))
patch.write_token(APTokenTypes.WRITE, address + 0x1A4, bytes([0x03, 0x00, 0x42, 0x28]))
patch.write_token(APTokenTypes.WRITE, address + 0x1A8, bytes([0x14, 0x00, 0x40, 0x14]))
patch.write_token(APTokenTypes.WRITE, address + 0x1AC, NOP)
patch.write_token(APTokenTypes.WRITE, address + 0x1B0, NOP)
patch.write_token(APTokenTypes.WRITE, address + 0x1B4, NOP)
patch.write_token(APTokenTypes.WRITE, address + 0x1B8, NOP)
patch.write_token(APTokenTypes.WRITE, address + 0x1BC, NOP)
patch.write_token(APTokenTypes.WRITE, address + 0x218, bytes([0x1A, 0x00, 0x03, 0x3C]))
patch.write_token(APTokenTypes.WRITE, address + 0x21C, bytes([0xE6, 0xB2, 0x62, 0x90]))
patch.write_token(APTokenTypes.WRITE, address + 0x220, bytes([0xD9, 0x27, 0x04, 0x24]))
patch.write_token(APTokenTypes.WRITE, address + 0x224, bytes([0xFF, 0xFF, 0x06, 0x24]))
patch.write_token(APTokenTypes.WRITE, address + 0x228, bytes([0x03, 0x00, 0x03, 0x24]))
patch.write_token(APTokenTypes.WRITE, address + 0x22C, bytes([0x22, 0x28, 0x62, 0x00]))
patch.write_token(APTokenTypes.WRITE, address + 0x230, bytes([0x24, 0x00, 0x00, 0x10]))
upper_half, lower_half = MIPS.get_address_halves(ram.hypnomatic_part_count)
patch.write_token(APTokenTypes.WRITE, address + 0x19C, bytes([
*upper_half, 0x03, 0x3C,
*lower_half, 0x62, 0x90,
0x03, 0x00, 0x42, 0x28,
0x14, 0x00, 0x40, 0x14,
*(MIPS.nop() * 5)
]))
patch.write_token(APTokenTypes.WRITE, address + 0x218, bytes([
*upper_half, 0x03, 0x3C,
*lower_half, 0x62, 0x90,
0xD9, 0x27, 0x04, 0x24,
0xFF, 0xFF, 0x06, 0x24,
0x03, 0x00, 0x03, 0x24,
0x22, 0x28, 0x62, 0x00,
0x24, 0x00, 0x00, 0x10
]))
# Replace code that gives Hypnomatic with code that just sets Secondary Inventory flag.
patch.write_token(APTokenTypes.WRITE, address + 0x4A0, bytes([0x01, 0x00, 0x04, 0x24]))
patch.write_token(APTokenTypes.WRITE, address + 0x4A4, bytes([0x77, 0x8B, 0x84, 0xA3]))
Expand Down
64 changes: 36 additions & 28 deletions data/IsoAddresses.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from worlds.rac2.data.Planets import *
from worlds.rac2.data import Planets


def get_planet_id_from_iso_address(address):
Expand Down Expand Up @@ -201,7 +201,15 @@ class AddressesSCUS97268:
0xB6BF1144, 0xB9803FBC, 0xBAFC7AF0, 0xBF9C6DF8, 0xC3315BFC, 0xC62D316C, 0xC8F428B0, 0xCA5AE1C0, 0xCD97DC9C,
0xD00C1DA8, 0xD240DDF0, 0xD6790700, 0xDAEE2B1C, 0xDCCAB6B8, 0xDE86B62C, 0xDFA214B8, 0xE0682840, 0xE151F054
]

MEMCARD_GAME_NAMES: list[int] = [0x3010BD, 0x3010D5, 0x3010ED, 0x30110D, 0x30112D, 0x301141, 0x30115D]
# MEMCARD_SAVED_DATA_TABLES: list[int] = [
# 0x003AF8B8, 0x949B5C84,
# 0x9D292724, 0x9EB1F958, 0xA193E324, 0xA5DDA684, 0xA8EF558C, 0xACA9CBC8, 0xAE398904, 0xB070F218, 0xB2F6AE6C,
# 0xB6B82B1C, 0xB978CFF8, 0xBAF57CD4, 0xBF94F7F4, 0xC32A12EC, 0xC625C84C, 0xC8EC991C, 0xCA5416AC, 0xCD908DAC,
# 0xD003BF84, 0xD239E950, 0xD6712A84, 0xDAE6DCAC, 0xDCC32E6C, 0xDE7F0B4C, 0xDF9AD70C, 0xE060BE78, 0xE14A9C2C
# ]
# DEFAULT_MEMCARD_SAVE_FILE: int = 0x948F31F4

ROLL_RANDOM_NUMBER_FUNCS: list[int] = [
0x00400F60, 0x94A06324,
Expand All @@ -211,33 +219,33 @@ class AddressesSCUS97268:
]

PLANET_WADS = {
ARANOS_TUTORIAL.number: [0x9D04C000, 0x9DF0C27F], # LEVEL0.WAD
OOZLA.number: [0x9E909800, 0x9FDE9D53], # LEVEL1.WAD
MAKTAR_NEBULA.number: [0xA1753800, 0xA2B143F7], # LEVEL2.WAD
ENDAKO.number: [0xA5B5E000, 0xA6C3185F], # LEVEL3.WAD
BARLOW.number: [0xA8CD7000, 0xAA4689DB], # LEVEL4.WAD
FELTZIN_SYSTEM.number: [0xAC85B800, 0xAD8452CF], # LEVEL5.WAD
NOTAK.number: [0xAE11F800, 0xAF3A2BDF], # LEVEL6.WAD
SIBERIUS.number: [0xB04BB800, 0xB19FB52F], # LEVEL7.WAD
TABORA.number: [0xB2D04000, 0xB40AA02F], # LEVEL8.WAD
DOBBO.number: [0xB690A000, 0xB7AFD2DF], # LEVEL9.WAD
HRUGIS_CLOUD.number: [0xB955E000, 0xBA3188BF], # LEVEL10.WAD
JOBA.number: [0xBAD77000, 0xBC2CEA9F], # LEVEL11.WAD
TODANO.number: [0xBF6F8000, 0xC07B628F], # LEVEL12.WAD
BOLDAN.number: [0xC3067800, 0xC418DAAF], # LEVEL13.WAD
ARANOS_PRISON.number: [0xC5FE2800, 0xC706FF9F], # LEVEL14.WAD
GORN.number: [0xC8C75000, 0xC99E65BF], # LEVEL15.WAD
SNIVELAK.number: [0xCA2D4800, 0xCB4563DF], # LEVEL16.WAD
SMOLG.number: [0xCD6E7800, 0xCE6E081F], # LEVEL17.WAD
DAMOSEL.number: [0xCFDEE800, 0xD0ECDABF], # LEVEL18.WAD
GRELBIN.number: [0xD2144800, 0xD39392D7], # LEVEL19.WAD
YEEDIL.number: [0xD64EA000, 0xD794D25B], # LEVEL20.WAD
INSOMNIAC_MUSEUM.number: [0xDAC72800, 0xDB9300DF], # LEVEL21.WAD
DOBBO_ORBIT.number: [0xDCA0C800, 0xDD708D2F], # LEVEL22.WAD
DAMOSEL_ORBIT.number: [0xDE57C000, 0xDF1811CF], # LEVEL23.WAD
SHIP_SHACK.number: [0xDF7F1800, 0xDFFE82D6], # LEVEL24.WAD
WUPASH_NEBULA.number: [0xE03D5000, 0xE0C12E8C], # LEVEL25.WAD
JAMMING_ARRAY.number: [0xE12CC800, 0xE1D47A8F], # LEVEL26.WAD
Planets.ARANOS_TUTORIAL.number: [0x9D04C000, 0x9DF0C27F], # LEVEL0.WAD
Planets.OOZLA.number: [0x9E909800, 0x9FDE9D53], # LEVEL1.WAD
Planets.MAKTAR_NEBULA.number: [0xA1753800, 0xA2B143F7], # LEVEL2.WAD
Planets.ENDAKO.number: [0xA5B5E000, 0xA6C3185F], # LEVEL3.WAD
Planets.BARLOW.number: [0xA8CD7000, 0xAA4689DB], # LEVEL4.WAD
Planets.FELTZIN_SYSTEM.number: [0xAC85B800, 0xAD8452CF], # LEVEL5.WAD
Planets.NOTAK.number: [0xAE11F800, 0xAF3A2BDF], # LEVEL6.WAD
Planets.SIBERIUS.number: [0xB04BB800, 0xB19FB52F], # LEVEL7.WAD
Planets.TABORA.number: [0xB2D04000, 0xB40AA02F], # LEVEL8.WAD
Planets.DOBBO.number: [0xB690A000, 0xB7AFD2DF], # LEVEL9.WAD
Planets.HRUGIS_CLOUD.number: [0xB955E000, 0xBA3188BF], # LEVEL10.WAD
Planets.JOBA.number: [0xBAD77000, 0xBC2CEA9F], # LEVEL11.WAD
Planets.TODANO.number: [0xBF6F8000, 0xC07B628F], # LEVEL12.WAD
Planets.BOLDAN.number: [0xC3067800, 0xC418DAAF], # LEVEL13.WAD
Planets.ARANOS_PRISON.number: [0xC5FE2800, 0xC706FF9F], # LEVEL14.WAD
Planets.GORN.number: [0xC8C75000, 0xC99E65BF], # LEVEL15.WAD
Planets.SNIVELAK.number: [0xCA2D4800, 0xCB4563DF], # LEVEL16.WAD
Planets.SMOLG.number: [0xCD6E7800, 0xCE6E081F], # LEVEL17.WAD
Planets.DAMOSEL.number: [0xCFDEE800, 0xD0ECDABF], # LEVEL18.WAD
Planets.GRELBIN.number: [0xD2144800, 0xD39392D7], # LEVEL19.WAD
Planets.YEEDIL.number: [0xD64EA000, 0xD794D25B], # LEVEL20.WAD
Planets.INSOMNIAC_MUSEUM.number: [0xDAC72800, 0xDB9300DF], # LEVEL21.WAD
Planets.DOBBO_ORBIT.number: [0xDCA0C800, 0xDD708D2F], # LEVEL22.WAD
Planets.DAMOSEL_ORBIT.number: [0xDE57C000, 0xDF1811CF], # LEVEL23.WAD
Planets.SHIP_SHACK.number: [0xDF7F1800, 0xDFFE82D6], # LEVEL24.WAD
Planets.WUPASH_NEBULA.number: [0xE03D5000, 0xE0C12E8C], # LEVEL25.WAD
Planets.JAMMING_ARRAY.number: [0xE12CC800, 0xE1D47A8F], # LEVEL26.WAD
}

# Oozla
Expand Down
52 changes: 34 additions & 18 deletions data/Items.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,42 @@ class EquipmentData(ItemData):
oclass_id: Optional[int] = 0x0047 # Wrench model
icon_id: Optional[int] = 0xEA75 # Question Mark icon `?`

# Unreferenced equipment offsets:
# - 00: ???
# - 01: ???
# - 04: "Hydro-Pack"
# - 06: "Armor"
# - 0A: "Wrench"
# - 0B: ???
# - 0F: Unused Weapon 1
# - 21: ???
# - 22: Unused Weapon 2
# - 23: Unused Weapon 3
# - 28: Unused Weapon 4
# - 2F: "Megacorp Helmet
# - 30: "Biker Helmet"
# - 34: ???


# Gadgets/Items
HELI_PACK = EquipmentData(1, "Heli-Pack", 2, oclass_id=0x025F, icon_id=0xEA8D)
THRUSTER_PACK = EquipmentData(2, "Thruster-Pack", 3, oclass_id=0x0260, icon_id=0xEA7E)
MAPPER = EquipmentData(3, "Mapper", 5, oclass_id=0x1235, icon_id=0xEA9F)
ARMOR_MAGNETIZER = EquipmentData(4, "Armor Magnetizer", 7, oclass_id=0x112F, icon_id=0xEA9A)
LEVITATOR = EquipmentData(5, "Levitator", 8, oclass_id=0x096C, icon_id=0xEA90)
SWINGSHOT = EquipmentData(6, "Swingshot", 13, oclass_id=0x00D0, icon_id=0xEA8B)
GRAVITY_BOOTS = EquipmentData(7, "Gravity Boots", 19, oclass_id=0x00AD, icon_id=0xEA88)
GRIND_BOOTS = EquipmentData(8, "Grindboots", 20, oclass_id=0x00C3, icon_id=0xEA8C)
GLIDER = EquipmentData(9, "Glider", 21, icon_id=0xEA91)
DYNAMO = EquipmentData(10, "Dynamo", 36, oclass_id=0x0825, icon_id=0xEA7F)
ELECTROLYZER = EquipmentData(11, "Electrolyzer", 38, oclass_id=0x0870, icon_id=0xEA81)
THERMANATOR = EquipmentData(12, "Thermanator", 39, oclass_id=0x0FB0, icon_id=0xEA82)
TRACTOR_BEAM = EquipmentData(13, "Tractor Beam", 46, oclass_id=0x00BC, icon_id=0xEA80)
QWARK_STATUETTE = EquipmentData(14, "Qwark Statuette", 49, icon_id=0xEA9C)
BOX_BREAKER = EquipmentData(15, "Box Breaker", 50, oclass_id=0x1238, icon_id=0xEAA1)
INFILTRATOR = EquipmentData(16, "Infiltrator", 51, oclass_id=0x0BD3, icon_id=0xEA83)
CHARGE_BOOTS = EquipmentData(17, "Charge Boots", 54, oclass_id=0x0E70, icon_id=0xEA89)
HYPNOMATIC = EquipmentData(18, "Hypnomatic", 55, oclass_id=0x0950, icon_id=0xEA84)
HELI_PACK = EquipmentData(1, "Heli-Pack", 0x2, oclass_id=0x025F, icon_id=0xEA8D)
THRUSTER_PACK = EquipmentData(2, "Thruster-Pack", 0x3, oclass_id=0x0260, icon_id=0xEA7E)
MAPPER = EquipmentData(3, "Mapper", 0x5, oclass_id=0x1235, icon_id=0xEA9F)
ARMOR_MAGNETIZER = EquipmentData(4, "Armor Magnetizer", 0x7, oclass_id=0x112F, icon_id=0xEA9A)
LEVITATOR = EquipmentData(5, "Levitator", 0x8, oclass_id=0x096C, icon_id=0xEA90)
SWINGSHOT = EquipmentData(6, "Swingshot", 0xD, oclass_id=0x00D0, icon_id=0xEA8B)
GRAVITY_BOOTS = EquipmentData(7, "Gravity Boots", 0x13, oclass_id=0x00AD, icon_id=0xEA88)
GRIND_BOOTS = EquipmentData(8, "Grindboots", 0x14, oclass_id=0x00C3, icon_id=0xEA8C)
GLIDER = EquipmentData(9, "Glider", 0x15, icon_id=0xEA91)
DYNAMO = EquipmentData(10, "Dynamo", 0x24, oclass_id=0x0825, icon_id=0xEA7F)
ELECTROLYZER = EquipmentData(11, "Electrolyzer", 0x26, oclass_id=0x0870, icon_id=0xEA81)
THERMANATOR = EquipmentData(12, "Thermanator", 0x27, oclass_id=0x0FB0, icon_id=0xEA82)
TRACTOR_BEAM = EquipmentData(13, "Tractor Beam", 0x2E, oclass_id=0x00BC, icon_id=0xEA80)
QWARK_STATUETTE = EquipmentData(14, "Qwark Statuette", 0x31, icon_id=0xEA9C)
BOX_BREAKER = EquipmentData(15, "Box Breaker", 0x32, oclass_id=0x1238, icon_id=0xEAA1)
INFILTRATOR = EquipmentData(16, "Infiltrator", 0x33, oclass_id=0x0BD3, icon_id=0xEA83)
CHARGE_BOOTS = EquipmentData(17, "Charge Boots", 0x36, oclass_id=0x0E70, icon_id=0xEA89)
HYPNOMATIC = EquipmentData(18, "Hypnomatic", 0x37, oclass_id=0x0950, icon_id=0xEA84)


@dataclass
Expand Down
33 changes: 19 additions & 14 deletions data/RamAddresses.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def __init__(self, game_version: str):
self.inventory: int = 0x1A7AF8
self.secondary_inventory: int = 0x1A7B30
self.vendor_list: int = 0x1A7B68
# self.savefile_play_time: int = 0x1A7BC0
self.unlocked_planets: int = 0x1A7BC8
self.loaded_flag: int = 0x1A7BE5
self.highlighted_planets: int = 0x1A7BE8
Expand Down Expand Up @@ -344,21 +345,25 @@ def __init__(self, game_version: str):
# Custom addresses
################################################

# I use some unused addresses at the end of the platinum bolt table to store some extra data for AP.
self.platinum_bolt_count: int = self.platinum_bolt_table + 0x6C
self.nanotech_boost_count: int = self.platinum_bolt_table + 0x6D
self.hypnomatic_part_count: int = self.platinum_bolt_table + 0x6E
# We use secondary inventory for unused weapons to store "global" data that needs to be saved to memcard
self.platinum_bolt_count: int = self.secondary_inventory + 0x0F # Unused weapon 1
self.nanotech_boost_count: int = self.secondary_inventory + 0x22 # Unused weapon 2
self.hypnomatic_part_count: int = self.secondary_inventory + 0x23 # Unused weapon 3
self.bolt_pack_count: int = self.secondary_inventory + 0x28 # Unused weapon 4

# The "enemy kill count table" is actually one table per planet of 0x400 bytes each, holding the number
# of times two enemies were killed (one in the upper half, the other in the lower half of the byte).
# As one might expect, this is way too much and most of this data is empty, but still saved on the memcard.
# We use the table for Feltzin since spaceship systems don't use that mechanic at all, but still have that
# table.
self.feltzin_kill_count_table: int = self.enemy_kill_count_table + (FELTZIN_SYSTEM.number * 0x400)
self.tabora_wrench_cutscene_flag: int = self.feltzin_kill_count_table + 0x1
self.aranos_wrench_cutscene_flag: int = self.feltzin_kill_count_table + 0x2
self.custom_text_notification_trigger: int = self.feltzin_kill_count_table + 0x3
self.bolt_pack_count: int = self.feltzin_kill_count_table + 0x4
# Put the new Tabora wrench cutscene flag inside the platinum bolt table for Tabora so it gets saved along
# other planet specific data
self.tabora_wrench_cutscene_flag: int = self.platinum_bolt_table + (TABORA.number * 4) + 3
# Put the new Aranos Prison wrench cutscene flag inside the platinum bolt table for Aranos so it gets
# saved along other planet specific data
self.aranos_wrench_cutscene_flag: int = self.platinum_bolt_table + (ARANOS_PRISON.number * 4) + 1

# The "enemy kill count table" is a 0x400 table for each, holding the number of times two enemies were
# killed (one in the upper half, the other in the lower half of the byte).
# We use Feltzin's table as a spot to put temporary data, since spaceship systems don't use that mechanic
# at all but still have that table.
self.temporary_data_table: int = self.enemy_kill_count_table + (FELTZIN_SYSTEM.number * 0x400)
self.custom_text_notification_trigger: int = self.temporary_data_table


class PlanetAddresses(NamedTuple):
Expand Down