mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Ocarina of Time 7.0 (#1277)
## What is this fixing or adding? - Adds the majority of OoTR 7.0 features: - Pot shuffle, Freestanding item shuffle, Crate shuffle, Beehive shuffle - Key rings mode - Dungeon shortcuts to speed up dungeons - "Regional" shuffle for dungeon items - New options for shop pricing in shopsanity - Expanded Ganon's Boss Key shuffle options - Pre-planted beans - Improved Chest Appearance Matches Contents mode - Blue Fire Arrows - Bonk self-damage - Finer control over MQ dungeons and spawn position randomization - Several bugfixes as a result of the update: - Items recognized by the server and valid starting items are now in a 1-to-1 correspondence. In particular, starting with keys is now supported. - Entrance randomization success rate improved. Hopefully it is now at 100%. Co-authored-by: Zach Parks <zach@alliware.com>
This commit is contained in:
120
worlds/oot/SceneFlags.py
Normal file
120
worlds/oot/SceneFlags.py
Normal file
@@ -0,0 +1,120 @@
|
||||
from math import ceil
|
||||
|
||||
from .LocationList import location_table
|
||||
|
||||
# Create a dict of dicts of the format:
|
||||
# {
|
||||
# scene_number_n : {
|
||||
# room_setup_number: max_flags
|
||||
# }
|
||||
# }
|
||||
# where room_setup_number defines the room + scene setup as ((setup << 6) + room) for scene n
|
||||
# and max_flags is the highest used enemy flag for that setup/room
|
||||
def get_collectible_flag_table(world):
|
||||
scene_flags = {}
|
||||
alt_list = []
|
||||
for i in range(0, 101):
|
||||
max_room_num = 0
|
||||
max_enemy_flag = 0
|
||||
scene_flags[i] = {}
|
||||
for location in world.get_locations():
|
||||
if(location.scene == i and location.type in ["Freestanding", "Pot", "FlyingPot", "Crate", "SmallCrate", "Beehive", "RupeeTower"]):
|
||||
default = location.default
|
||||
if(isinstance(default, list)): #List of alternative room/setup/flag to use
|
||||
primary_tuple = default[0]
|
||||
for c in range(1,len(default)):
|
||||
alt_list.append((location, default[c], primary_tuple))
|
||||
default = location.default[0] #Use the first tuple as the primary tuple
|
||||
if(isinstance(default, tuple)):
|
||||
room, setup, flag = default
|
||||
room_setup = room + (setup << 6)
|
||||
if(room_setup in scene_flags[i].keys()):
|
||||
curr_room_max_flag = scene_flags[i][room_setup]
|
||||
if flag > curr_room_max_flag:
|
||||
scene_flags[i][room_setup] = flag
|
||||
else:
|
||||
scene_flags[i][room_setup] = flag
|
||||
if len(scene_flags[i].keys()) == 0:
|
||||
del scene_flags[i]
|
||||
#scene_flags.append((i, max_enemy_flag))
|
||||
return (scene_flags, alt_list)
|
||||
|
||||
# Create a byte array from the scene flag table created by get_collectible_flag_table
|
||||
def get_collectible_flag_table_bytes(scene_flag_table):
|
||||
num_flag_bytes = 0
|
||||
bytes = bytearray()
|
||||
bytes.append(len(scene_flag_table.keys()))
|
||||
for scene_id in scene_flag_table.keys():
|
||||
rooms = scene_flag_table[scene_id]
|
||||
room_count = len(rooms.keys())
|
||||
bytes.append(scene_id)
|
||||
bytes.append(room_count)
|
||||
for room in rooms:
|
||||
bytes.append(room)
|
||||
bytes.append((num_flag_bytes & 0xFF00) >> 8)
|
||||
bytes.append(num_flag_bytes & 0x00FF )
|
||||
num_flag_bytes += ceil((rooms[room] + 1) / 8)
|
||||
|
||||
return bytes, num_flag_bytes
|
||||
|
||||
def get_alt_list_bytes(alt_list):
|
||||
bytes = bytearray()
|
||||
for entry in alt_list:
|
||||
location, alt, primary = entry
|
||||
room, scene_setup, flag = alt
|
||||
alt_override = (room << 8) + (scene_setup << 14) + flag
|
||||
room, scene_setup, flag = primary
|
||||
primary_override = (room << 8) + (scene_setup << 14) + flag
|
||||
bytes.append(location.scene)
|
||||
bytes.append(0x06)
|
||||
bytes.append((alt_override & 0xFF00) >> 8)
|
||||
bytes.append(alt_override & 0xFF)
|
||||
bytes.append(location.scene)
|
||||
bytes.append(0x06)
|
||||
bytes.append((primary_override & 0xFF00) >> 8)
|
||||
bytes.append(primary_override & 0xFF)
|
||||
return bytes
|
||||
|
||||
# AP method to retrieve address + bit for each item
|
||||
# Based on get_collectible_flag_offset in the C code
|
||||
def get_collectible_flag_addresses(world, collectible_scene_flags_table):
|
||||
|
||||
# Ported directly from get_items.c
|
||||
def get_collectible_flag_offset(scene: int, room: int, setup_id: int) -> int:
|
||||
num_scenes = collectible_scene_flags_table[0]
|
||||
index = 1
|
||||
scene_id = 0
|
||||
room_id = 0
|
||||
room_setup_count = 0
|
||||
room_byte_offset = 0
|
||||
# Loop through collectible_scene_flags_table until we find the right scene
|
||||
while num_scenes > 0:
|
||||
scene_id = collectible_scene_flags_table[index]
|
||||
room_setup_count = collectible_scene_flags_table[index+1]
|
||||
index += 2
|
||||
if scene_id == scene: # found the scene
|
||||
# Loop through each room/setup combination until we find the right one.
|
||||
for i in range(room_setup_count):
|
||||
room_id = collectible_scene_flags_table[index] & 0x3F
|
||||
setup_id_temp = (collectible_scene_flags_table[index] & 0xC0) >> 6
|
||||
room_byte_offset = (collectible_scene_flags_table[index+1] << 8) + collectible_scene_flags_table[index+2]
|
||||
index += 3
|
||||
if room_id == room and setup_id_temp == setup_id:
|
||||
return room_byte_offset
|
||||
else: # Not the right scene, skip to the next one
|
||||
index += 3 * room_setup_count
|
||||
num_scenes -= 1
|
||||
return -1
|
||||
|
||||
collectible_flag_addresses = {}
|
||||
for location in world.get_locations():
|
||||
if location.type in ["Freestanding", "Pot", "FlyingPot", "Crate", "SmallCrate", "Beehive", "RupeeTower"]:
|
||||
default = location.default
|
||||
if isinstance(default, list):
|
||||
default = default[0]
|
||||
room, setup, flag = default
|
||||
offset = get_collectible_flag_offset(location.scene, room, setup)
|
||||
item_id = location.address
|
||||
collectible_flag_addresses[item_id] = [offset, flag]
|
||||
return collectible_flag_addresses
|
||||
|
||||
Reference in New Issue
Block a user