Files
dockipelago/worlds/dk64/randomizer/Patching/MoveLocationRando.py
Jonathan Tinney 7971961166
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
add schedule I, sonic 1/frontiers/heroes, spirit island
2026-04-02 23:46:36 -07:00

576 lines
27 KiB
Python

"""Randomize Move Locations."""
from enum import IntEnum, auto
from randomizer.Enums.Items import Items
from randomizer.Enums.Kongs import Kongs
from randomizer.Enums.Settings import MicrohintsEnabled, MoveRando
from randomizer.Enums.Types import Types
from randomizer.Enums.MoveTypes import MoveTypes
from randomizer.Lists.Item import ItemList
from randomizer.Patching.Patcher import LocalROM
from randomizer.Patching.Library.Generic import setItemReferenceName
from randomizer.CompileHints import getHelmProgItems
# /* 0x0A8 */ unsigned char dk_crankymoves[7]; // First 4 bits indicates the moves type, 0 = Moves, 1 = Slam, 2 = Guns, 3 = Ammo Belt, 4 = Instrument, 0xF = No Upgrade. Last 4 bits indicate move level (eg. 1 = Baboon Blast, 2 = Strong Kong, 3 = Gorilla Grab). Each item in the array indicates the level it is given (eg. 1st slot is purchased in Japes, 2nd for Aztec etc.)
# /* 0x0AF */ unsigned char diddy_crankymoves[7]; // See "dk_crankymoves"
# /* 0x0B6 */ unsigned char lanky_crankymoves[7]; // See "dk_crankymoves"
# /* 0x0BD */ unsigned char tiny_crankymoves[7]; // See "dk_crankymoves"
# /* 0x0C4 */ unsigned char chunky_crankymoves[7]; // See "dk_crankymoves"
# /* 0x0CB */ unsigned char dk_funkymoves[7]; // See "dk_crankymoves"
# /* 0x0D2 */ unsigned char diddy_funkymoves[7]; // See "dk_crankymoves"
# /* 0x0D9 */ unsigned char lanky_funkymoves[7]; // See "dk_crankymoves"
# /* 0x0E0 */ unsigned char tiny_funkymoves[7]; // See "dk_crankymoves"
# /* 0x0E7 */ unsigned char chunky_funkymoves[7]; // See "dk_crankymoves"
# /* 0x0EE */ unsigned char dk_candymoves[7]; // See "dk_crankymoves". Note: Do not assign anything to item 0 or 4 as there's no Candy's in Japes or Fungi
# /* 0x0F5 */ unsigned char diddy_candymoves[7]; // See "dk_crankymoves". Note: Do not assign anything to item 0 or 4 as there's no Candy's in Japes or Fungi
# /* 0x0FC */ unsigned char lanky_candymoves[7]; // See "dk_crankymoves". Note: Do not assign anything to item 0 or 4 as there's no Candy's in Japes or Fungi
# /* 0x103 */ unsigned char tiny_candymoves[7]; // See "dk_crankymoves". Note: Do not assign anything to item 0 or 4 as there's no Candy's in Japes or Fungi
# /* 0x10A */ unsigned char chunky_candymoves[7]; // See "dk_crankymoves". Note: Do not assign anything to item 0 or 4 as there's no Candy's in Japes or Fungi
moveRandoOffset = 0x0A7
dk_crankymoves = []
diddy_crankymoves = []
lanky_crankymoves = []
tiny_crankymoves = []
chunky_crankymoves = []
dk_funkymoves = []
diddy_funkymoves = []
lanky_funkymoves = []
tiny_funkymoves = []
chunky_funkymoves = []
dk_candymoves = []
diddy_candymoves = []
lanky_candymoves = []
tiny_candymoves = []
chunky_candymoves = []
level_names = [
"Jungle Japes",
"Angry Aztec",
"Frantic Factory",
"Gloomy Galleon",
"Fungi Forest",
"Crystal Caves",
"Creepy Castle",
"DK Isles",
]
kong_names = {
Kongs.donkey: "Donkey Kong",
Kongs.diddy: "Diddy",
Kongs.lanky: "Lanky",
Kongs.tiny: "Tiny",
Kongs.chunky: "Chunky",
Kongs.any: "Any Kong",
}
class MoveMicrohintItemData:
"""Information about the microhint move."""
def __init__(self, subtype: str, index: int, kong: Kongs):
"""Initialize with given parameters."""
self.subtype = subtype
self.index = index
self.kong = kong
move_info_data = {
Items.BaboonBlast: MoveMicrohintItemData("special", 0, Kongs.donkey),
Items.StrongKong: MoveMicrohintItemData("special", 1, Kongs.donkey),
Items.GorillaGrab: MoveMicrohintItemData("special", 2, Kongs.donkey),
Items.ChimpyCharge: MoveMicrohintItemData("special", 0, Kongs.diddy),
Items.RocketbarrelBoost: MoveMicrohintItemData("special", 1, Kongs.diddy),
Items.SimianSpring: MoveMicrohintItemData("special", 2, Kongs.diddy),
Items.Orangstand: MoveMicrohintItemData("special", 0, Kongs.lanky),
Items.BaboonBalloon: MoveMicrohintItemData("special", 1, Kongs.lanky),
Items.OrangstandSprint: MoveMicrohintItemData("special", 2, Kongs.lanky),
Items.MiniMonkey: MoveMicrohintItemData("special", 0, Kongs.tiny),
Items.PonyTailTwirl: MoveMicrohintItemData("special", 1, Kongs.tiny),
Items.Monkeyport: MoveMicrohintItemData("special", 2, Kongs.tiny),
Items.HunkyChunky: MoveMicrohintItemData("special", 0, Kongs.chunky),
Items.PrimatePunch: MoveMicrohintItemData("special", 1, Kongs.chunky),
Items.GorillaGone: MoveMicrohintItemData("special", 2, Kongs.chunky),
Items.ProgressiveSlam: MoveMicrohintItemData("slam", 1, Kongs.any),
Items.Bongos: MoveMicrohintItemData("instrument", 0, Kongs.donkey),
Items.Guitar: MoveMicrohintItemData("instrument", 0, Kongs.diddy),
Items.Trombone: MoveMicrohintItemData("instrument", 0, Kongs.lanky),
Items.Saxophone: MoveMicrohintItemData("instrument", 0, Kongs.tiny),
Items.Triangle: MoveMicrohintItemData("instrument", 0, Kongs.chunky),
Items.Coconut: MoveMicrohintItemData("gun", 0, Kongs.donkey),
Items.Peanut: MoveMicrohintItemData("gun", 0, Kongs.diddy),
Items.Grape: MoveMicrohintItemData("gun", 0, Kongs.lanky),
Items.Feather: MoveMicrohintItemData("gun", 0, Kongs.tiny),
Items.Pineapple: MoveMicrohintItemData("gun", 0, Kongs.chunky),
}
class MoveMicrohints:
"""Information about microhints."""
def __init__(self, item: Items, file: int, enabled_hint_settings: list):
"""Initialize with given parameters."""
self.item = item
self.move = None
if item in list(move_info_data.keys()):
self.move = move_info_data[item]
self.file = file
self.enabled_hint_settings = enabled_hint_settings
def pushItemMicrohints(spoiler, move_dict: dict, level: int, kong: int, slot: int):
"""Push hint for the micro-hints system."""
if spoiler.settings.microhints_enabled != MicrohintsEnabled.off:
if kong != Kongs.any or slot == 0:
move = None # Using no item for the purpose of a default
helm_prog_items = getHelmProgItems(spoiler)
hinted_items = [
# Key = Item, Value = Textbox index in text file 19
MoveMicrohints(helm_prog_items[0], 26, [MicrohintsEnabled.base, MicrohintsEnabled.all]),
MoveMicrohints(helm_prog_items[1], 25, [MicrohintsEnabled.base, MicrohintsEnabled.all]),
MoveMicrohints(Items.Bongos, 27, [MicrohintsEnabled.all]),
MoveMicrohints(Items.Triangle, 28, [MicrohintsEnabled.all]),
MoveMicrohints(Items.Saxophone, 29, [MicrohintsEnabled.all]),
MoveMicrohints(Items.Trombone, 30, [MicrohintsEnabled.all]),
MoveMicrohints(Items.Guitar, 31, [MicrohintsEnabled.all]),
MoveMicrohints(Items.ProgressiveSlam, 33, [MicrohintsEnabled.base, MicrohintsEnabled.all]),
]
for item_data in hinted_items:
move_data = item_data.move
if (move_dict["move_type"] == move_data.subtype and move_dict["move_lvl"] == move_data.index and move_dict["move_kong"] == move_data.kong) or (
move_dict["move_type"] == move_data.subtype and move_data.subtype == "slam"
):
if spoiler.settings.microhints_enabled in list(item_data.enabled_hint_settings):
move = item_data
if move is not None:
data = {
"textbox_index": move.file,
"mode": "replace_whole",
"target": spoiler.microhints[ItemList[move.item].name],
}
if 19 in spoiler.text_changes:
spoiler.text_changes[19].append(data)
else:
spoiler.text_changes[19] = [data]
def writeMoveDataToROM(ROM_COPY: LocalROM, arr: list, enable_hints: bool, spoiler, kong_slot: int, kongs: list, level_override=None):
"""Write move data to ROM."""
for xi, x in enumerate(arr):
if x["move_type"] == "flag":
flag_dict = {
"dive": 0x182,
"orange": 0x184,
"barrel": 0x185,
"vine": 0x183,
"camera": 0x2FD,
"shockwave": 0x179,
"climbing": 0x297,
"camera_shockwave": 0xFFFE,
}
flag_index = 0xFFFF
if x["flag"] in flag_dict:
flag_index = flag_dict[x["flag"]]
ROM_COPY.writeMultipleBytes(MoveTypes.Flag, 2)
ROM_COPY.writeMultipleBytes(flag_index, 2)
ROM_COPY.writeMultipleBytes(0, 1)
ROM_COPY.writeMultipleBytes(x["price"], 1)
elif x["move_type"] is None:
ROM_COPY.writeMultipleBytes(MoveTypes.Nothing, 2)
ROM_COPY.writeMultipleBytes(0, 2)
ROM_COPY.writeMultipleBytes(0, 1)
ROM_COPY.writeMultipleBytes(0, 1)
else:
move_types = ["special", "slam", "gun", "ammo_belt", "instrument"]
price_var = 0
if isinstance(x["price"], list):
price_var = 0
else:
price_var = x["price"]
ROM_COPY.writeMultipleBytes(move_types.index(x["move_type"]), 2)
ROM_COPY.writeMultipleBytes(x["move_lvl"], 2)
ROM_COPY.writeMultipleBytes(x["move_kong"], 1)
ROM_COPY.writeMultipleBytes(price_var, 1)
if enable_hints:
if level_override is not None:
pushItemMicrohints(spoiler, x, level_override, kongs[xi], kong_slot)
else:
pushItemMicrohints(spoiler, x, xi, kongs[xi], kong_slot)
def dictEqual(dict1: dict, dict2: dict) -> bool:
"""Determine if two dictionaries are equal."""
if len(dict1) != len(dict2):
return False
else:
for i in dict1:
if dict1.get(i) != dict2.get(i):
return False
return True
def randomize_moves(spoiler, ROM_COPY: LocalROM):
"""Randomize Move locations based on move_data from spoiler."""
varspaceOffset = spoiler.settings.rom_data
movespaceOffset = spoiler.settings.move_location_data
hint_enabled = True
if spoiler.settings.shuffle_items and Types.Shop in spoiler.settings.valid_locations:
hint_enabled = False
if spoiler.settings.move_rando != MoveRando.off and spoiler.move_data is not None:
# Take a copy of move_data before modifying
move_arrays = spoiler.move_data.copy()
dk_crankymoves = move_arrays[0][0][0]
diddy_crankymoves = move_arrays[0][0][1]
lanky_crankymoves = move_arrays[0][0][2]
tiny_crankymoves = move_arrays[0][0][3]
chunky_crankymoves = move_arrays[0][0][4]
dk_funkymoves = move_arrays[0][1][0]
diddy_funkymoves = move_arrays[0][1][1]
lanky_funkymoves = move_arrays[0][1][2]
tiny_funkymoves = move_arrays[0][1][3]
chunky_funkymoves = move_arrays[0][1][4]
dk_candymoves = move_arrays[0][2][0]
diddy_candymoves = move_arrays[0][2][1]
lanky_candymoves = move_arrays[0][2][2]
tiny_candymoves = move_arrays[0][2][3]
chunky_candymoves = move_arrays[0][2][4]
training_moves = move_arrays[1]
bfi_move = move_arrays[2]
kong_lists = []
for shop in range(3):
shop_lst = []
for kong in range(5):
kong_lst = []
for level in range(8):
kong_lst.append([])
shop_lst.append(kong_lst)
kong_lists.append(shop_lst)
for shop in range(3):
for level in range(8):
is_shared = True
default = 0
for kong in range(5):
if kong == 0:
default = move_arrays[0][shop][kong][level]
if not dictEqual(default, move_arrays[0][shop][kong][level]):
is_shared = False
for kong in range(5):
applied_kong = kong
if is_shared:
applied_kong = Kongs.any
kong_lists[shop][kong][level] = applied_kong
ROM_COPY.seek(movespaceOffset)
writeMoveDataToROM(ROM_COPY, dk_crankymoves, hint_enabled, spoiler, 0, kong_lists[0][0])
writeMoveDataToROM(ROM_COPY, diddy_crankymoves, hint_enabled, spoiler, 1, kong_lists[0][1])
writeMoveDataToROM(ROM_COPY, lanky_crankymoves, hint_enabled, spoiler, 2, kong_lists[0][2])
writeMoveDataToROM(ROM_COPY, tiny_crankymoves, hint_enabled, spoiler, 3, kong_lists[0][3])
writeMoveDataToROM(ROM_COPY, chunky_crankymoves, hint_enabled, spoiler, 4, kong_lists[0][4])
writeMoveDataToROM(ROM_COPY, dk_funkymoves, hint_enabled, spoiler, 0, kong_lists[1][0])
writeMoveDataToROM(ROM_COPY, diddy_funkymoves, hint_enabled, spoiler, 1, kong_lists[1][1])
writeMoveDataToROM(ROM_COPY, lanky_funkymoves, hint_enabled, spoiler, 2, kong_lists[1][2])
writeMoveDataToROM(ROM_COPY, tiny_funkymoves, hint_enabled, spoiler, 3, kong_lists[1][3])
writeMoveDataToROM(ROM_COPY, chunky_funkymoves, hint_enabled, spoiler, 4, kong_lists[1][4])
writeMoveDataToROM(ROM_COPY, dk_candymoves, hint_enabled, spoiler, 0, kong_lists[2][0])
writeMoveDataToROM(ROM_COPY, diddy_candymoves, hint_enabled, spoiler, 1, kong_lists[2][1])
writeMoveDataToROM(ROM_COPY, lanky_candymoves, hint_enabled, spoiler, 2, kong_lists[2][2])
writeMoveDataToROM(ROM_COPY, tiny_candymoves, hint_enabled, spoiler, 3, kong_lists[2][3])
writeMoveDataToROM(ROM_COPY, chunky_candymoves, hint_enabled, spoiler, 4, kong_lists[2][4])
writeMoveDataToROM(ROM_COPY, training_moves, hint_enabled, spoiler, 0, [Kongs.any, Kongs.any, Kongs.any, Kongs.any], 7)
writeMoveDataToROM(ROM_COPY, bfi_move, hint_enabled, spoiler, 0, [Kongs.tiny], 7)
def getNextSlot(spoiler, ROM_COPY: LocalROM, item: Items) -> int:
"""Get slot for progressive item with pre-given moves."""
slots = []
if item == Items.ProgressiveAmmoBelt:
slots = [0x1C, 0x1D]
elif item == Items.ProgressiveInstrumentUpgrade:
slots = [0x20, 0x21, 0x22]
elif item == Items.ProgressiveSlam:
slots = [0xF, 0x10, 0x11]
if len(slots) == 0:
return None
for slot in slots:
offset = int(slot >> 3)
check = int(slot % 8)
ROM_COPY.seek(spoiler.settings.rom_data + 0xD5 + offset)
val = int.from_bytes(ROM_COPY.readBytes(1), "big")
if (val & (0x80 >> check)) == 0:
return slot
return None
def place_pregiven_moves(spoiler, ROM_COPY: LocalROM):
"""Place pre-given moves."""
item_order = [
Items.BaboonBlast,
Items.StrongKong,
Items.GorillaGrab,
Items.ChimpyCharge,
Items.RocketbarrelBoost,
Items.SimianSpring,
Items.Orangstand,
Items.BaboonBalloon,
Items.OrangstandSprint,
Items.MiniMonkey,
Items.PonyTailTwirl,
Items.Monkeyport,
Items.HunkyChunky,
Items.PrimatePunch,
Items.GorillaGone,
Items.ProgressiveSlam,
Items.ProgressiveSlam,
Items.ProgressiveSlam,
Items.Coconut,
Items.Peanut,
Items.Grape,
Items.Feather,
Items.Pineapple,
Items.Bongos,
Items.Guitar,
Items.Trombone,
Items.Saxophone,
Items.Triangle,
Items.ProgressiveAmmoBelt,
Items.ProgressiveAmmoBelt,
Items.HomingAmmo,
Items.SniperSight,
Items.ProgressiveInstrumentUpgrade,
Items.ProgressiveInstrumentUpgrade,
Items.ProgressiveInstrumentUpgrade,
Items.Swim,
Items.Oranges,
Items.Barrels,
Items.Vines,
Items.Camera,
Items.Shockwave,
Items.Climbing,
]
progressives = (Items.ProgressiveAmmoBelt, Items.ProgressiveInstrumentUpgrade, Items.ProgressiveSlam)
name_str = "Extra Training"
for item in spoiler.pregiven_items:
# print(item)
if item is not None and item != Items.NoItem:
new_slot = None
if item in progressives:
new_slot = getNextSlot(spoiler, ROM_COPY, item)
elif item in item_order:
new_slot = item_order.index(item)
elif item == Items.CameraAndShockwave:
new_slot = None # Setting is handled by the code below
for index in [item_order.index(Items.Camera), item_order.index(Items.Shockwave)]:
offset = int(index >> 3)
check = int(index % 8)
ROM_COPY.seek(spoiler.settings.rom_data + 0xD5 + offset)
val = int.from_bytes(ROM_COPY.readBytes(1), "big")
val |= 0x80 >> check
ROM_COPY.seek(spoiler.settings.rom_data + 0xD5 + offset)
ROM_COPY.writeMultipleBytes(val, 1)
if new_slot is not None:
offset = int(new_slot >> 3)
check = int(new_slot % 8)
ROM_COPY.seek(spoiler.settings.rom_data + 0xD5 + offset)
val = int.from_bytes(ROM_COPY.readBytes(1), "big")
val |= 0x80 >> check
ROM_COPY.seek(spoiler.settings.rom_data + 0xD5 + offset)
ROM_COPY.writeMultipleBytes(val, 1)
if item == Items.ProgressiveAmmoBelt:
setItemReferenceName(spoiler, item, new_slot - 0x1C, name_str)
elif item == Items.ProgressiveInstrumentUpgrade:
setItemReferenceName(spoiler, item, new_slot - 0x20, name_str)
elif item == Items.ProgressiveSlam:
setItemReferenceName(spoiler, item, new_slot - 0xF, name_str)
else:
setItemReferenceName(spoiler, item, 0, name_str)
class MoveDataSection(IntEnum):
"""Move Data Section enum."""
cranky = auto()
candy = auto()
funky = auto()
training = auto()
bfi = auto()
first_move = auto()
class MoveDataRequest(IntEnum):
"""Move Data Request Enum."""
price = auto()
flag = auto()
move_type = auto()
move_level = auto()
move_kong = auto()
move_no_kong = auto()
def getMoveSlot(vendor: MoveDataSection, kong: Kongs, level: int) -> int:
"""Get move slot in the global move array."""
global_index = None
shop_offsets = {
MoveDataSection.cranky: 0,
MoveDataSection.candy: 80,
MoveDataSection.funky: 40,
}
if vendor in (MoveDataSection.cranky, MoveDataSection.candy, MoveDataSection.funky):
global_index = shop_offsets[vendor] + (int(kong) * 8) + level
elif vendor == MoveDataSection.training:
global_index = 120 + level
elif vendor == MoveDataSection.bfi:
global_index = 124
elif vendor == MoveDataSection.first_move:
global_index = 125
if global_index is None:
raise Exception(f"Invalid global index for {vendor}")
return global_index
def readMoveData(ROM_COPY: LocalROM, move_data: int, vendor: MoveDataSection, kong: Kongs, level: int, data_request: MoveDataRequest) -> int:
"""Acquire data from move block."""
slot_address = move_data + (6 * getMoveSlot(vendor, kong, level))
if data_request == MoveDataRequest.price:
ROM_COPY.seek(slot_address + 5)
return int.from_bytes(ROM_COPY.readBytes(1), "big")
elif data_request in (MoveDataRequest.flag, MoveDataRequest.move_level):
ROM_COPY.seek(slot_address + 2)
return int.from_bytes(ROM_COPY.readBytes(2), "big")
elif data_request == MoveDataRequest.move_type:
ROM_COPY.seek(slot_address)
return int.from_bytes(ROM_COPY.readBytes(2), "big")
elif data_request == MoveDataRequest.move_no_kong:
ROM_COPY.seek(slot_address)
return int.from_bytes(ROM_COPY.readBytes(4), "big")
elif data_request == MoveDataRequest.move_kong:
ROM_COPY.seek(slot_address + 4)
return int.from_bytes(ROM_COPY.readBytes(1), "big")
raise Exception(f"Invalid data request: {data_request}")
def getSharedStatus(type_value: int) -> int:
"""Get shared status of vendor."""
if (type_value > 2) and (type_value < 5):
return type_value - 1
elif type_value != 1:
return 0
return 1
def filterMoveType(ROM_COPY: LocalROM, move_data: int, section: MoveDataSection, kong: Kongs, level: int) -> int:
"""Filter move type for the purpose of writing to ROM."""
move_type = readMoveData(ROM_COPY, move_data, section, kong, level, MoveDataRequest.move_type)
move_level = readMoveData(ROM_COPY, move_data, section, kong, level, MoveDataRequest.move_level)
if move_type == MoveTypes.Nothing:
return -1
if move_type == MoveTypes.Instruments: # Instrument
index = move_level + 1
if index > 1:
return MoveTypes.Flag # Flag
elif move_type in (MoveTypes.Slam, MoveTypes.AmmoBelt): # Slam, Belt
return MoveTypes.Flag # Flag
return move_type
def filterMoveIndex(
ROM_COPY: LocalROM,
move_data: int,
section: MoveDataSection,
kong: Kongs,
level: int,
slam_flag: int,
belt_flag: int,
ins_flag: int,
) -> tuple:
"""Filter move index for the purpose of writing to ROM."""
filtered_type = filterMoveType(ROM_COPY, move_data, section, kong, level)
index = readMoveData(ROM_COPY, move_data, section, kong, level, MoveDataRequest.move_level) + 1
original_item_type = readMoveData(ROM_COPY, move_data, section, kong, level, MoveDataRequest.move_type)
if original_item_type == MoveTypes.Slam: # Slam
return slam_flag + 1, belt_flag, ins_flag, slam_flag
if original_item_type == MoveTypes.AmmoBelt: # Ammo Belt
return slam_flag, belt_flag + 1, ins_flag, belt_flag
if original_item_type == MoveTypes.Instruments: # Instrument
if index > 1:
return slam_flag, belt_flag, ins_flag + 1, ins_flag
if filtered_type in (5, 6) or filtered_type > 7:
new_index = readMoveData(ROM_COPY, move_data, section, kong, level, MoveDataRequest.flag)
return slam_flag, belt_flag, ins_flag, new_index
return slam_flag, belt_flag, ins_flag, index
def parseMoveBlock(spoiler, ROM_COPY: LocalROM):
"""Parse move block and writes a section of ROM which will be copied to RAM."""
slam_flag = 0x3BF # FLAG_SHOPMOVE_SLAM_0
belt_flag = 0x299 # FLAG_SHOPMOVE_BELT_0
ins_flag = 0x29B # FLAG_SHOPMOVE_INS_0
move_data = spoiler.settings.move_location_data
write_data = []
for _ in range(126):
write_data.append({"move_type": 0, "move_level": 0, "move_kong": 0, "price": 0, "flag": -1})
for i in range(8): # LEVEL_COUNT
stored_slam = slam_flag
stored_belt = belt_flag
stored_ins = ins_flag
dk_cranky_type = readMoveData(ROM_COPY, move_data, MoveDataSection.cranky, Kongs.donkey, i, MoveDataRequest.move_type)
dk_funky_type = readMoveData(ROM_COPY, move_data, MoveDataSection.funky, Kongs.donkey, i, MoveDataRequest.move_type)
dk_candy_type = readMoveData(ROM_COPY, move_data, MoveDataSection.candy, Kongs.donkey, i, MoveDataRequest.move_type)
cranky_shared = getSharedStatus(dk_cranky_type)
funky_shared = getSharedStatus(dk_funky_type)
candy_shared = getSharedStatus(dk_candy_type)
cranky_targ_data = readMoveData(ROM_COPY, move_data, MoveDataSection.cranky, Kongs.donkey, i, MoveDataRequest.move_no_kong)
cranky_targ_flag = readMoveData(ROM_COPY, move_data, MoveDataSection.cranky, Kongs.donkey, i, MoveDataRequest.flag)
funky_targ_data = readMoveData(ROM_COPY, move_data, MoveDataSection.funky, Kongs.donkey, i, MoveDataRequest.move_no_kong)
funky_targ_flag = readMoveData(ROM_COPY, move_data, MoveDataSection.funky, Kongs.donkey, i, MoveDataRequest.flag)
candy_targ_data = readMoveData(ROM_COPY, move_data, MoveDataSection.candy, Kongs.donkey, i, MoveDataRequest.move_no_kong)
candy_targ_flag = readMoveData(ROM_COPY, move_data, MoveDataSection.candy, Kongs.donkey, i, MoveDataRequest.flag)
for kong in (Kongs.diddy, Kongs.lanky, Kongs.tiny, Kongs.chunky):
cranky_local_data = readMoveData(ROM_COPY, move_data, MoveDataSection.cranky, kong, i, MoveDataRequest.move_no_kong)
cranky_local_flag = readMoveData(ROM_COPY, move_data, MoveDataSection.cranky, kong, i, MoveDataRequest.flag)
funky_local_data = readMoveData(ROM_COPY, move_data, MoveDataSection.funky, kong, i, MoveDataRequest.move_no_kong)
funky_local_flag = readMoveData(ROM_COPY, move_data, MoveDataSection.funky, kong, i, MoveDataRequest.flag)
candy_local_data = readMoveData(ROM_COPY, move_data, MoveDataSection.candy, kong, i, MoveDataRequest.move_no_kong)
candy_local_flag = readMoveData(ROM_COPY, move_data, MoveDataSection.candy, kong, i, MoveDataRequest.flag)
if (cranky_local_data != cranky_targ_data) or (cranky_local_flag != cranky_targ_flag):
cranky_shared = 0
if (funky_local_data != funky_targ_data) or (funky_local_flag != funky_targ_flag):
funky_shared = 0
if (candy_local_data != candy_targ_data) or (candy_local_flag != candy_targ_flag):
candy_shared = 0
for j in range(5):
if (cranky_shared == 1) or (funky_shared == 1) or (candy_shared == 1):
slam_flag = stored_slam
if (cranky_shared == 2) or (funky_shared == 2) or (candy_shared == 2):
belt_flag = stored_belt
if (cranky_shared == 3) or (funky_shared == 3) or (candy_shared == 3):
ins_flag = stored_ins
for vendor in (MoveDataSection.cranky, MoveDataSection.candy, MoveDataSection.funky):
slot = getMoveSlot(vendor, j, i)
write_data[slot]["move_type"] = filterMoveType(ROM_COPY, move_data, vendor, j, i)
write_data[slot]["move_kong"] = readMoveData(ROM_COPY, move_data, vendor, j, i, MoveDataRequest.move_kong)
slam_flag, belt_flag, ins_flag, write_data[slot]["move_level"] = filterMoveIndex(ROM_COPY, move_data, vendor, j, i, slam_flag, belt_flag, ins_flag)
write_data[slot]["price"] = readMoveData(ROM_COPY, move_data, vendor, j, i, MoveDataRequest.price)
for i in range(4):
# Training Barrels
slot = getMoveSlot(MoveDataSection.training, 0, i)
write_data[slot]["move_type"] = filterMoveType(ROM_COPY, move_data, MoveDataSection.training, 0, i)
write_data[slot]["move_kong"] = readMoveData(ROM_COPY, move_data, MoveDataSection.training, 0, i, MoveDataRequest.move_kong)
slam_flag, belt_flag, ins_flag, write_data[slot]["move_level"] = filterMoveIndex(ROM_COPY, move_data, MoveDataSection.training, 0, i, slam_flag, belt_flag, ins_flag)
for extra_item in (MoveDataSection.bfi, MoveDataSection.first_move):
slot = getMoveSlot(extra_item, 0, 0)
write_data[slot]["move_type"] = filterMoveType(ROM_COPY, move_data, extra_item, 0, 0)
write_data[slot]["move_kong"] = readMoveData(ROM_COPY, move_data, extra_item, 0, 0, MoveDataRequest.move_kong)
slam_flag, belt_flag, ins_flag, write_data[slot]["move_level"] = filterMoveIndex(ROM_COPY, move_data, extra_item, 0, 0, slam_flag, belt_flag, ins_flag)
for index, item in enumerate(write_data):
item_head = 0x1FEF800 + (6 * index)
ROM_COPY.seek(item_head)
ROM_COPY.writeMultipleBytes(item.get("move_type", 7), 2)
ROM_COPY.writeMultipleBytes(item.get("move_level", 1), 2)
ROM_COPY.writeMultipleBytes(item.get("move_kong", 0), 1)
ROM_COPY.writeMultipleBytes(item.get("price", 0), 1)