diff --git a/__init__.py b/__init__.py index d822f902b..1a67b172b 100644 --- a/__init__.py +++ b/__init__.py @@ -22,6 +22,7 @@ from .fast64_internal.oot import OOT_Properties, oot_register, oot_unregister from .fast64_internal.oot.oot_constants import oot_world_defaults from .fast64_internal.oot.props_panel_main import OOT_ObjectProperties +from .fast64_internal.oot.actor.properties import initOOTActorProperties from .fast64_internal.utility_anim import utility_anim_register, utility_anim_unregister, ArmatureApplyWithMeshOperator from .fast64_internal.mk64 import MK64_Properties, mk64_register, mk64_unregister @@ -430,6 +431,7 @@ def register(): register_class(ExampleAddonPreferences) addon_updater_ops.register(bl_info) + initOOTActorProperties() utility_anim_register() mat_register() render_engine_register() diff --git a/fast64_internal/oot/actor/operators.py b/fast64_internal/oot/actor/operators.py index e1702a8af..44cc60939 100644 --- a/fast64_internal/oot/actor/operators.py +++ b/fast64_internal/oot/actor/operators.py @@ -6,29 +6,70 @@ from ..oot_constants import ootData +class OOT_SearchChestContentEnumOperator(Operator): + bl_idname = "object.oot_search_chest_content_enum_operator" + bl_label = "Select Chest Content" + bl_property = "chest_content" + bl_options = {"REGISTER", "UNDO"} + + chest_content: EnumProperty(items=ootData.actorData.ootEnumChestContent, default="item_heart") + obj_name: StringProperty() + prop_name: StringProperty() + + def execute(self, context): + setattr(bpy.data.objects[self.obj_name].ootActorProperty, self.prop_name, self.chest_content) + context.region.tag_redraw() + self.report({"INFO"}, f"Selected: {self.chest_content}") + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.invoke_search_popup(self) + return {"RUNNING_MODAL"} + + +class OOT_SearchNaviMsgIDEnumOperator(Operator): + bl_idname = "object.oot_search_navi_msg_id_enum_operator" + bl_label = "Select Message ID" + bl_property = "navi_msg_id" + bl_options = {"REGISTER", "UNDO"} + + navi_msg_id: EnumProperty(items=ootData.actorData.ootEnumNaviMessageData, default="msg_00") + obj_name: StringProperty() + prop_name: StringProperty() + + def execute(self, context): + setattr(bpy.data.objects[self.obj_name].ootActorProperty, self.prop_name, self.navi_msg_id) + context.region.tag_redraw() + self.report({"INFO"}, f"Selected: {self.navi_msg_id}") + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.invoke_search_popup(self) + return {"RUNNING_MODAL"} + + class OOT_SearchActorIDEnumOperator(Operator): bl_idname = "object.oot_search_actor_id_enum_operator" bl_label = "Select Actor ID" - bl_property = "actorID" + bl_property = "actor_id" bl_options = {"REGISTER", "UNDO"} - actorID: EnumProperty(items=ootData.actorData.ootEnumActorID, default="ACTOR_PLAYER") - actorUser: StringProperty(default="Actor") - objName: StringProperty() + actor_id: EnumProperty(items=lambda self, context: ootData.actorData.getItems(self.actor_user)) + actor_user: StringProperty(default="Actor") + obj_name: StringProperty() def execute(self, context): - obj = bpy.data.objects[self.objName] - if self.actorUser == "Transition Actor": - obj.ootTransitionActorProperty.actor.actorID = self.actorID - elif self.actorUser == "Actor": - obj.ootActorProperty.actorID = self.actorID - elif self.actorUser == "Entrance": - obj.ootEntranceProperty.actor.actorID = self.actorID + obj = bpy.data.objects[self.obj_name] + + if self.actor_user == "Transition Actor": + obj.ootTransitionActorProperty.actor.actor_id = self.actor_id + elif self.actor_user == "Actor": + obj.ootActorProperty.actor_id = self.actor_id else: - raise PluginError("Invalid actor user for search: " + str(self.actorUser)) + raise PluginError("Invalid actor user for search: " + str(self.actor_user)) context.region.tag_redraw() - self.report({"INFO"}, "Selected: " + self.actorID) + self.report({"INFO"}, f"Selected: {self.actor_id}") return {"FINISHED"} def invoke(self, context, event): @@ -36,7 +77,11 @@ def invoke(self, context, event): return {"RUNNING_MODAL"} -classes = (OOT_SearchActorIDEnumOperator,) +classes = ( + OOT_SearchActorIDEnumOperator, + OOT_SearchChestContentEnumOperator, + OOT_SearchNaviMsgIDEnumOperator, +) def actor_ops_register(): diff --git a/fast64_internal/oot/actor/properties.py b/fast64_internal/oot/actor/properties.py index 50f0a7054..8236b078e 100644 --- a/fast64_internal/oot/actor/properties.py +++ b/fast64_internal/oot/actor/properties.py @@ -1,12 +1,16 @@ from bpy.types import Object, PropertyGroup, UILayout from bpy.utils import register_class, unregister_class from bpy.props import EnumProperty, StringProperty, IntProperty, BoolProperty, CollectionProperty, PointerProperty -from ...utility import prop_split, label_split +from ...utility import PluginError, prop_split, label_split from ..oot_constants import ootData, ootEnumCamTransition from ..oot_upgrade import upgradeActors from ..scene.properties import OOTAlternateSceneHeaderProperty from ..room.properties import OOTAlternateRoomHeaderProperty -from .operators import OOT_SearchActorIDEnumOperator +from .operators import ( + OOT_SearchActorIDEnumOperator, + OOT_SearchChestContentEnumOperator, + OOT_SearchNaviMsgIDEnumOperator, +) from ..oot_utility import ( getRoomObj, @@ -14,6 +18,10 @@ drawAddButton, drawCollectionOps, drawEnumWithCustom, + getEvalParams, + getEvalParamsInt, + getShiftFromMask, + getFormattedParams, ) ootEnumSceneSetupPreset = [ @@ -23,6 +31,57 @@ ] +def get_prop_name(actor_key: str, param_type: str, param_subtype: str, param_index: int): + flag_to_prop_suffix = {"Chest": "chestFlag", "Collectible": "collectibleFlag", "Switch": "switchFlag"} + param_to_prop_suffix = { + "Type": "type", + "Property": "props", + "Bool": "bool", + "Enum": "enum", + "ChestContent": "chestContent", + "Collectible": "collectibleDrop", + "Message": "naviMsg", + } + suffix = param_to_prop_suffix[param_type] if param_type != "Flag" else flag_to_prop_suffix[param_subtype] + return f"{actor_key}.{suffix}{param_index}" # e.g.: ``en_test.props1`` + + +def initOOTActorProperties(): + """This function is used to edit the OOTActorProperty class""" + + prop_annotations = getattr(OOTActorProperty, "__annotations__", None) + + if prop_annotations is None: + OOTActorProperty.__annotations__ = prop_annotations = {} + + param_type_to_enum_items = { + "ChestContent": ootData.actorData.ootEnumChestContent, + "Collectible": ootData.actorData.ootEnumCollectibleItems, + "Message": ootData.actorData.ootEnumNaviMessageData, + } + + for actor in ootData.actorData.actorList: + for param in actor.params: + prop_name = get_prop_name(actor.key, param.type, param.subType, param.index) + enum_items = None + + if len(param.items) > 0: + enum_items = [(f"0x{val:04X}", name, f"0x{val:04X}") for val, name in param.items] + enum_items.insert(0, ("Custom", "Custom Value", "Custom")) + elif param.type in {"ChestContent", "Collectible", "Message"}: + enum_items = param_type_to_enum_items[param.type] + + if param.type in {"Property", "Flag"}: + prop_annotations[prop_name] = StringProperty(name="", default="0x0") + elif param.type == "Bool": + prop_annotations[prop_name] = BoolProperty(name="", default=False) + elif param.type in {"Type", "Enum", "ChestContent", "Collectible", "Message"} and enum_items is not None: + prop_annotations[prop_name] = EnumProperty(name="", items=enum_items, default=enum_items[1][0]) + + if param.type in {"Type", "Enum", "ChestContent", "Collectible", "Message"}: + prop_annotations[f"{prop_name}_custom"] = StringProperty(name="", default="0x0") + + class OOTActorHeaderItemProperty(PropertyGroup): headerIndex: IntProperty(name="Scene Setup", min=4, default=4) expandTab: BoolProperty(name="Expand Tab") @@ -108,52 +167,315 @@ def draw_props( class OOTActorProperty(PropertyGroup): - actorID: EnumProperty(name="Actor", items=ootData.actorData.ootEnumActorID, default="ACTOR_PLAYER") - actorIDCustom: StringProperty(name="Actor ID", default="ACTOR_PLAYER") - actorParam: StringProperty(name="Actor Parameter", default="0x0000") - rotOverride: BoolProperty(name="Override Rotation", default=False) - rotOverrideX: StringProperty(name="Rot X", default="0") - rotOverrideY: StringProperty(name="Rot Y", default="0") - rotOverrideZ: StringProperty(name="Rot Z", default="0") + actor_id: EnumProperty(name="Actor", items=ootData.actorData.ootEnumActorID, default="ACTOR_PLAYER") + actor_id_custom: StringProperty(name="Actor ID", default="ACTOR_PLAYER") + + # only used for actors with the id "Custom" + # because of the get/set functions we need a way to input any value + params_custom: StringProperty(name="Actor Parameter", default="0x0000") + rot_override: BoolProperty(name="Override Rotation", default=False) + rot_x_custom: StringProperty(name="Rot X", default="0x0000") + rot_y_custom: StringProperty(name="Rot Y", default="0x0000") + rot_z_custom: StringProperty(name="Rot Z", default="0x0000") + + # non-custom actors + params: StringProperty( + name="Actor Parameter", + default="0x0000", + get=lambda self: self.get_param_value("Params"), + set=lambda self, value: self.set_param_value(value, "Params"), + ) + + rot_x: StringProperty( + name="Rot X", + default="0", + get=lambda self: self.get_param_value("XRot"), + set=lambda self, value: self.set_param_value(value, "XRot"), + ) + rot_y: StringProperty( + name="Rot Y", + default="0", + get=lambda self: self.get_param_value("YRot"), + set=lambda self, value: self.set_param_value(value, "YRot"), + ) + rot_z: StringProperty( + name="Rot Z", + default="0", + get=lambda self: self.get_param_value("ZRot"), + set=lambda self, value: self.set_param_value(value, "ZRot"), + ) + headerSettings: PointerProperty(type=OOTActorHeaderProperty) + eval_params: BoolProperty(name="Eval Params", default=False) @staticmethod def upgrade_object(obj: Object): print(f"Processing '{obj.name}'...") upgradeActors(obj) - def draw_props(self, layout: UILayout, altRoomProp: OOTAlternateRoomHeaderProperty, objName: str): - # prop_split(layout, actorProp, 'actorID', 'Actor') + def is_rotation_used(self, target: str): + actor = ootData.actorData.actorsByID[self.actor_id] + selected_type = None + + for param in actor.params: + if param.type == "Type": + prop_name = get_prop_name(actor.key, param.type, param.subType, param.index) + base_val = getattr(self, prop_name) + + if base_val == "Custom": + base_val = getattr(self, f"{prop_name}_custom") + + selected_type = getEvalParamsInt(base_val) + + # the first parameter type is always the "Actor Type" + # because of that we need to make sure the current "Actor Type" value + # is included in type list of the property as not all properties are used sometimes + if selected_type is not None and selected_type in param.tiedTypes or len(param.tiedTypes) == 0: + if param.target != "Params" and target == param.target: + return True + + return False + + def is_value_in_range(self, value: int, min: int, max: int): + if min is not None and max is not None: + return value >= min and value <= max + return True + + def set_param_value(self, base_value: str | bool, target: str): + actor = ootData.actorData.actorsByID[self.actor_id] + base_value = getEvalParamsInt(base_value) + found_type = None + + for param in actor.params: + if target == param.target: + shift = getShiftFromMask(param.mask) + if param.type != "Type": + value = (base_value & param.mask) >> shift + else: + value = base_value & param.mask + + if "Rot" in target: + found_type = getEvalParamsInt(getattr(self, get_prop_name(actor.key, "Type", None, 1))) + else: + found_type = value + + is_in_range = self.is_value_in_range(value, param.valueRange[0], param.valueRange[1]) + found_type_in_tied_types = found_type is not None and found_type in param.tiedTypes + + if is_in_range and (found_type_in_tied_types or len(param.tiedTypes) == 0): + prop_name = get_prop_name(actor.key, param.type, param.subType, param.index) + + if param.type == "ChestContent": + prop_value = ootData.actorData.chestItemByValue[value].key + elif param.type == "Collectible": + prop_value = ootData.actorData.collectibleItemsByValue[value].key + elif param.type == "Message": + prop_value = ootData.actorData.messageItemsByValue[value].key + elif param.type == "Bool": + prop_value = bool(value) + else: + prop_value = f"0x{value:04X}" + + try: + setattr(self, prop_name, prop_value) + except: + if param.type in {"Type", "Enum", "ChestContent", "Collectible", "Message"}: + setattr(self, prop_name, "Custom") + setattr(self, f"{prop_name}_custom", prop_value) + print( + f"WARNING: invalid value '{prop_value}' ('{base_value}') for '{prop_name}'. " + + "Maybe `ActorList.xml` is missing informations?" + ) + + def get_param_value(self, target: str): + actor = ootData.actorData.actorsByID[self.actor_id] + param_list = [] + type_value = None + have_custom_value = False + + for param in actor.params: + if target == param.target: + param_val = None + prop_name = get_prop_name(actor.key, param.type, param.subType, param.index) + cur_prop_value = getattr(self, prop_name) + + if param.type not in {"Type", "Enum", "ChestContent", "Collectible", "Message"}: + if param.type == "Bool": + value_to_eval = "1" if cur_prop_value else "0" + else: + value_to_eval = cur_prop_value + + param_val = getEvalParamsInt(value_to_eval) + + # treat any invalid value as a custom value + if param_val is None: + param_list.append(value_to_eval) + have_custom_value = True + continue + else: + if cur_prop_value == "Custom": + cur_prop_value = getattr(self, f"{prop_name}_custom") + param_list.append(cur_prop_value) + have_custom_value = True + continue + + if param.type in {"Type", "Enum"}: + type_value = getEvalParamsInt(cur_prop_value) + else: + param_val = 0 + + if param.type == "ChestContent": + param_val = ootData.actorData.chestItemByKey[cur_prop_value].value + elif param.type == "Collectible": + param_val = ootData.actorData.collectibleItemsByKey[cur_prop_value].value + elif param.type == "Message": + param_val = ootData.actorData.messageItemsByKey[cur_prop_value].value + + if "Rot" in target: + type_value = getEvalParamsInt(getattr(self, get_prop_name(actor.key, "Type", None, 1))) + + if type_value is not None and type_value in param.tiedTypes or len(param.tiedTypes) == 0: + val = ((param_val if param_val is not None else -1) & param.mask) >> getShiftFromMask(param.mask) + is_in_range = self.is_value_in_range(val, param.valueRange[0], param.valueRange[1]) + + if is_in_range and param.type != "Type" and param_val is not None: + value = getFormattedParams(param.mask, param_val, param.type == "Bool") + + if value is not None: + param_list.append(value) + + if len(param_list) > 0: + param_str = " | ".join(val for val in param_list) + else: + param_str = "0x0" + + if "Rot" in target: + type_value = None + + eval_type_value = type_value if type_value is not None else 0 + + # don't evaluate the params if there's a custom value + if not have_custom_value: + eval_param_value = getEvalParamsInt(param_str) + else: + eval_param_value = 0 + + if eval_type_value and (eval_param_value != 0 or have_custom_value) and type_value is not None: + param_str = f"(0x{type_value:04X} | ({param_str}))" + elif eval_type_value and not (eval_param_value != 0 or have_custom_value) and type_value is not None: + param_str = f"0x{type_value:04X}" + elif not eval_type_value and (eval_param_value != 0 or have_custom_value): + param_str = f"({param_str})" + else: + param_str = "0x0" + + if self.eval_params: + # return `param_str` if the eval failed + # should only happen if the user inputs invalid numbers (hex or dec) + # returns the non-evaluated value if the function returned None + try: + value = getEvalParams(param_str) + return value if value is not None else param_str + except: + pass + + return param_str + + def draw_params(self, layout: UILayout, obj: Object): + actor = ootData.actorData.actorsByID[self.actor_id] + selected_type = None + + for param in actor.params: + prop_name = get_prop_name(actor.key, param.type, param.subType, param.index) + + if param.type == "Type": + base_val = getattr(self, prop_name) + + if base_val == "Custom": + base_val = getattr(self, f"{prop_name}_custom") + + selected_type = getEvalParamsInt(base_val) + + # the first parameter type is always the "Actor Type" + # because of that we need to make sure the current "Actor Type" value + # is included in type list of the property as not all properties are used sometimes + is_type_in_tied_types = selected_type is not None and selected_type in param.tiedTypes + if is_type_in_tied_types or param.type == "Type" or len(param.tiedTypes) == 0: + if param.type in {"ChestContent", "Message"}: + key: str = getattr(self, prop_name) + + if param.type == "ChestContent": + search_op = layout.operator(OOT_SearchChestContentEnumOperator.bl_idname) + label_name = "Chest Content" + item_map = ootData.actorData.chestItemByKey + else: + search_op = layout.operator(OOT_SearchNaviMsgIDEnumOperator.bl_idname) + label_name = "Navi Message ID" + item_map = ootData.actorData.messageItemsByKey + + search_op.obj_name = obj.name + search_op.prop_name = prop_name + + if key != "Custom": + label_split(layout, label_name, item_map[key].name) + else: + prop_split(layout, self, f"{prop_name}_custom", f"{label_name} Custom") + else: + prop_split(layout, self, prop_name, param.name) + + if param.type in {"Type", "Enum", "Collectible"}: + if getattr(self, prop_name) == "Custom": + prop_split(layout, self, f"{prop_name}_custom", f"{param.name} Custom") + + def draw_props(self, layout: UILayout, altRoomProp: OOTAlternateRoomHeaderProperty, obj: Object): actorIDBox = layout.column() - # actorIDBox.box().label(text = "Settings") searchOp = actorIDBox.operator(OOT_SearchActorIDEnumOperator.bl_idname, icon="VIEWZOOM") - searchOp.actorUser = "Actor" - searchOp.objName = objName + searchOp.actor_user = "Actor" + searchOp.obj_name = obj.name split = actorIDBox.split(factor=0.5) - if self.actorID == "None": + if self.actor_id == "None": actorIDBox.box().label(text="This Actor was deleted from the XML file.") return split.label(text="Actor ID") - split.label(text=getEnumName(ootData.actorData.ootEnumActorID, self.actorID)) + split.label(text=getEnumName(ootData.actorData.ootEnumActorID, self.actor_id)) - if self.actorID == "Custom": - # actorIDBox.prop(actorProp, 'actorIDCustom', text = 'Actor ID') - prop_split(actorIDBox, self, "actorIDCustom", "") + if self.actor_id != "Custom": + self.draw_params(actorIDBox, obj) + else: + prop_split(actorIDBox, self, "actor_id_custom", "") - # layout.box().label(text = 'Actor IDs defined in include/z64actors.h.') - prop_split(actorIDBox, self, "actorParam", "Actor Parameter") + paramBox = actorIDBox.box() + paramBox.label(text="Actor Parameter") - actorIDBox.prop(self, "rotOverride", text="Override Rotation (ignore Blender rot)") - if self.rotOverride: - prop_split(actorIDBox, self, "rotOverrideX", "Rot X") - prop_split(actorIDBox, self, "rotOverrideY", "Rot Y") - prop_split(actorIDBox, self, "rotOverrideZ", "Rot Z") + if self.actor_id != "Custom": + paramBox.prop(self, "eval_params") + paramBox.prop(self, "params", text="") + else: + paramBox.prop(self, "params_custom", text="") + + rotations_used = [] + if self.rot_override: + rotations_used = ["X", "Y", "Z"] + elif self.actor_id != "Custom": + if self.is_rotation_used("XRot"): + rotations_used.append("X") + if self.is_rotation_used("YRot"): + rotations_used.append("Y") + if self.is_rotation_used("ZRot"): + rotations_used.append("Z") + + if self.actor_id == "Custom": + paramBox.prop(self, "rot_override", text="Override Rotation (ignore Blender rot)") + + for rot in rotations_used: + custom = "_custom" if self.actor_id == "Custom" else "" + prop_split(paramBox, self, f"rot_{rot.lower()}{custom}", f"Rot {rot}") headerProp: OOTActorHeaderProperty = self.headerSettings - headerProp.draw_props(actorIDBox, "Actor", altRoomProp, objName) + headerProp.draw_props(actorIDBox, "Actor", altRoomProp, obj.name) class OOTTransitionActorProperty(PropertyGroup): @@ -175,18 +497,25 @@ def draw_props( ): actorIDBox = layout.column() searchOp = actorIDBox.operator(OOT_SearchActorIDEnumOperator.bl_idname, icon="VIEWZOOM") - searchOp.actorUser = "Transition Actor" - searchOp.objName = objName + searchOp.actor_user = "Transition Actor" + searchOp.obj_name = objName split = actorIDBox.split(factor=0.5) split.label(text="Actor ID") - split.label(text=getEnumName(ootData.actorData.ootEnumActorID, self.actor.actorID)) + split.label(text=getEnumName(ootData.actorData.ootEnumActorID, self.actor.actor_id)) - if self.actor.actorID == "Custom": - prop_split(actorIDBox, self.actor, "actorIDCustom", "") + if self.actor.actor_id == "Custom": + prop_split(actorIDBox, self.actor, "actor_id_custom", "") + else: + self.actor.draw_params(actorIDBox, roomObj) - # layout.box().label(text = 'Actor IDs defined in include/z64actors.h.') - prop_split(actorIDBox, self.actor, "actorParam", "Actor Parameter") + paramBox = actorIDBox.box() + paramBox.label(text="Actor Parameter") + if self.actor.actor_id != "Custom": + paramBox.prop(self.actor, "eval_params") + paramBox.prop(self.actor, "params", text="") + else: + paramBox.prop(self.actor, "params_custom", text="") if roomObj is None: actorIDBox.label(text="This must be part of a Room empty's hierarchy.", icon="OUTLINER") @@ -222,7 +551,6 @@ def isRoomEmptyObject(self, obj: Object): def draw_props(self, layout: UILayout, obj: Object, altSceneProp: OOTAlternateSceneHeaderProperty, objName: str): box = layout.column() - # box.box().label(text = "Properties") roomObj = getRoomObj(obj) if roomObj is None: box.label(text="This must be part of a Room empty's hierarchy.", icon="OUTLINER") @@ -230,10 +558,21 @@ def draw_props(self, layout: UILayout, obj: Object, altSceneProp: OOTAlternateSc entranceProp = obj.ootEntranceProperty prop_split(box, entranceProp, "tiedRoom", "Room") prop_split(box, entranceProp, "spawnIndex", "Spawn Index") - prop_split(box, entranceProp.actor, "actorParam", "Actor Param") + box.prop(entranceProp, "customActor") if entranceProp.customActor: - prop_split(box, entranceProp.actor, "actorIDCustom", "Actor ID Custom") + prop_split(box, entranceProp.actor, "actor_id_custom", "Actor ID Custom") + + if not self.customActor: + self.actor.draw_params(box, obj) + + paramBox = box.box() + paramBox.label(text="Actor Parameter") + if not self.customActor: + paramBox.prop(self.actor, "eval_params") + paramBox.prop(self.actor, "params", text="") + else: + paramBox.prop(self.actor, "params_custom", text="") headerProps: OOTActorHeaderProperty = entranceProp.actor.headerSettings headerProps.draw_props(box, "Entrance", altSceneProp, objName) diff --git a/fast64_internal/oot/data/oot_actor_data.py b/fast64_internal/oot/data/oot_actor_data.py index 7f7642b2a..f6a732f90 100644 --- a/fast64_internal/oot/data/oot_actor_data.py +++ b/fast64_internal/oot/data/oot_actor_data.py @@ -4,10 +4,31 @@ from .oot_data import OoT_BaseElement +@dataclass +class OoT_ParameterElement: + type: str # bool, enum, type, property, etc... + index: int + mask: int + name: str + subType: str # used for and + target: str + tiedTypes: list[int] + items: list[tuple[int, str]] # for and , int is "Value"/"Params" and str is the name + valueRange: list[int] + + +@dataclass +class OoT_ListElement: + key: str + name: str + value: int + + @dataclass class OoT_ActorElement(OoT_BaseElement): category: str tiedObjects: list[str] + params: list[OoT_ParameterElement] class OoT_ActorData: @@ -21,12 +42,68 @@ def __init__(self): # general actor list self.actorList: list[OoT_ActorElement] = [] + # list elements + self.chestItems: list[OoT_ListElement] = [] + self.collectibleItems: list[OoT_ListElement] = [] + self.messageItems: list[OoT_ListElement] = [] + + listNameToList = { + "Chest Content": self.chestItems, + "Collectibles": self.collectibleItems, + "Elf_Msg Message ID": self.messageItems, + } + + for elem in actorRoot.iterfind("List"): + listName = elem.get("Name") + if listName is not None: + for item in elem: + listNameToList[listName].append( + OoT_ListElement(item.get("Key"), item.get("Name"), int(item.get("Value"), base=16)) + ) + for actor in actorRoot.iterfind("Actor"): tiedObjects = [] objKey = actor.get("ObjectKey") actorName = f"{actor.attrib['Name']} - {actor.attrib['ID'].removeprefix('ACTOR_')}" + if objKey is not None: # actors don't always use an object tiedObjects = objKey.split(",") + + # parameters + params: list[OoT_ParameterElement] = [] + for elem in actor: + elemType = elem.tag + if elemType != "Notes": + items: list[tuple[int, str]] = [] + if elemType == "Type" or elemType == "Enum": + for item in elem: + key = "Params" if elemType == "Type" else "Value" + name = item.text.strip() if elemType == "Type" else item.get("Name") + if key is not None and name is not None: + items.append((int(item.get(key), base=16), name)) + + # not every actor have parameters tied to a specific actor type + tiedTypes = elem.get("TiedActorTypes") + tiedTypeList = [] + if tiedTypes is not None: + tiedTypeList = [int(val, base=16) for val in tiedTypes.split(",")] + + defaultName = f"{elem.get('Type')} {elemType}" + valueRange = elem.get("ValueRange") + params.append( + OoT_ParameterElement( + elemType, + int(elem.get("Index", "1")), + int(elem.get("Mask", "0xFFFF"), base=16), + elem.get("Name", defaultName if not "None" in defaultName else elemType), + elem.get("Type"), + elem.get("Target", "Params"), + tiedTypeList, + items, + [int(val) for val in valueRange.split("-")] if valueRange is not None else [None, None], + ) + ) + self.actorList.append( OoT_ActorElement( actor.attrib["ID"], @@ -35,14 +112,55 @@ def __init__(self): int(actor.attrib["Index"]), actor.attrib["Category"], tiedObjects, + params, ) ) + self.actorsByKey = {actor.key: actor for actor in self.actorList} self.actorsByID = {actor.id: actor for actor in self.actorList} + self.chestItemByKey = {elem.key: elem for elem in self.chestItems} + self.collectibleItemsByKey = {elem.key: elem for elem in self.collectibleItems} + self.messageItemsByKey = {elem.key: elem for elem in self.messageItems} + + self.chestItemByValue = {elem.value: elem for elem in self.chestItems} + self.collectibleItemsByValue = {elem.value: elem for elem in self.collectibleItems} + self.messageItemsByValue = {elem.value: elem for elem in self.messageItems} + # list of tuples used by Blender's enum properties + lastIndex = max(1, *(actor.index for actor in self.actorList)) self.ootEnumActorID = [("None", f"{i} (Deleted from the XML)", "None") for i in range(lastIndex)] self.ootEnumActorID.insert(0, ("Custom", "Custom Actor", "Custom")) + + doorTotal = 0 + for actor in self.actorList: + if actor.category == "ACTORCAT_DOOR": + doorTotal += 1 + self.ootEnumTransitionActorID = [("None", f"{i} (Deleted from the XML)", "None") for i in range(doorTotal)] + self.ootEnumTransitionActorID.insert(0, ("Custom", "Custom Actor", "Custom")) + + i = 1 for actor in self.actorList: self.ootEnumActorID[actor.index] = (actor.id, actor.name, actor.id) + if actor.category == "ACTORCAT_DOOR": + self.ootEnumTransitionActorID[i] = (actor.id, actor.name, actor.id) + i += 1 + + self.ootEnumChestContent = [(elem.key, elem.name, elem.key) for elem in self.chestItems] + self.ootEnumCollectibleItems = [(elem.key, elem.name, elem.key) for elem in self.collectibleItems] + self.ootEnumNaviMessageData = [(elem.key, elem.name, elem.key) for elem in self.messageItems] + + self.ootEnumChestContent.insert(0, ("Custom", "Custom Value", "Custom")) + self.ootEnumCollectibleItems.insert(0, ("Custom", "Custom Value", "Custom")) + self.ootEnumNaviMessageData.insert(0, ("Custom", "Custom Value", "Custom")) + + def getItems(self, actorUser: str): + if actorUser == "Actor": + return self.ootEnumActorID + elif actorUser == "Transition Actor": + return self.ootEnumTransitionActorID + elif actorUser == "Entrance": + return [(self.actorsByKey["player"].id, self.actorsByKey["player"].name, self.actorsByKey["player"].id)] + else: + raise ValueError("ERROR: The Actor User is unknown!") diff --git a/fast64_internal/oot/data/xml/ActorList.xml b/fast64_internal/oot/data/xml/ActorList.xml index a53b1ebfc..f3303de70 100644 --- a/fast64_internal/oot/data/xml/ActorList.xml +++ b/fast64_internal/oot/data/xml/ActorList.xml @@ -30,6 +30,7 @@ for each sub element (of ) mentioned below: * Name -> display name (in the UI) * TiedActorTypes -> optional, used to use this property for the current actor type (see en_rd for an example) * Target -> optional, defines which variable should be used to store this parameter (actor.home.rot.X-Y-Z, actor.params), if none then Params is used by default +* ValueRange -> optionnal, used for actors that have parameters that shared the same location but does different things depending on the value (see en_wood02) - -> adds a bool property (checkbox) - -> adds an enum property, different from (use this if you want multiple enums for now) @@ -46,17 +47,17 @@ for each sub element (of ) mentioned below: - Invisible, Can't Control //Used for cutscenes without Link - Master Sword Pull and Drop Animation //Overwrites coordinates - Spawn: Blue Warp //used when returning from a blue warp - Spawn: Immobile - Spawn: Exit via Grotto //Y velocity = 12 - Spawn: Warp Song - Spawn: Farore's Wind - Spawn: Thrown Out - Stand - Slow Walk Forward - Retain Previous Velocity //Walk speed set by last exit + Invisible, Can't Control //Used for cutscenes without Link + Master Sword Pull and Drop Animation //Overwrites coordinates + Spawn: Blue Warp //used when returning from a blue warp + Spawn: Immobile + Spawn: Exit via Grotto //Y velocity = 12 + Spawn: Warp Song + Spawn: Farore's Wind + Spawn: Thrown Out + Stand + Slow Walk Forward + Retain Previous Velocity //Walk speed set by last exit Last 2 digits = Camera Initial Focus //Data defined by scene Link spawns in @@ -64,11 +65,12 @@ for each sub element (of ) mentioned below: - Invisible (Lens of Truth), Mini-Boss Theme - Rises from Ground, Mini-Boss Theme - Rises from Ground //Pair with 0001 - Drops From Sky on Approach - Rises from Ground, Mini-Boss Theme + Invisible (Lens of Truth), Mini-Boss Theme + Rises from Ground, Mini-Boss Theme + Rises from Ground //Pair with 0001 + Drops From Sky on Approach + Rises from Ground, Mini-Boss Theme + Unknown @@ -77,48 +79,50 @@ for each sub element (of ) mentioned below: - Green Flame - Purple Flame - Red Bubbles - Invisible Hovering Object w/Shadow, bursts into purple flames - Green Flame - Green Flame - Purple Flame - Green Flame + Green Flame + Purple Flame + Red Bubbles + Invisible Hovering Object w/Shadow, bursts into purple flames + Green Flame + Green Flame + Purple Flame + Green Flame - - Large Orange Flame - Large Orange Flame - Large Blue Flame - Large Green Flame - Small Orange Flame - Large Orange Flame - Large Green Flame - Large Blue Flame - Large Magenta Flame - Large Pale Orange Flame - Large Pale Yellow Flame - Large Pale Green Flame - Large Pale Pink Flame - Large Pale Purple Flame - Large Pale Indigo Flame - Large Pale Blue Flame - Candle Flame - Faint Blue Aura - + + Large Orange Flame + Large Orange Flame + Large Blue Flame + Large Green Flame + Small Orange Flame + Large Orange Flame + Large Green Flame + Large Blue Flame + Large Magenta Flame + Large Pale Orange Flame + Large Pale Yellow Flame + Large Pale Green Flame + Large Pale Pink Flame + Large Pale Purple Flame + Large Pale Indigo Flame + Large Pale Blue Flame + + + + + - Loads Room - Small Key Locked Door - Loads Room - Scene Transition - Ajar (slams on approach) - Displays Textbox - Time Locked (Unlocked between 18:00 and 21:00) - Loads Room + Loads Room + Small Key Locked Door + Loads Room + Scene Transition + Ajar (slams on approach) + Displays Textbox + Time Locked (Unlocked between 18:00 and 21:00) + Loads Room @@ -127,18 +131,18 @@ for each sub element (of ) mentioned below: - Large - Large, Appears, Clear Flag - Boss Key's Chest - Large, Falling, Switch Flag - Large, Invisible - Small - Small, Invisible - Small, Appears, Clear Flag - Small, Falls, Switch Flag - Large, Appears, Zelda's Lullaby - Large, Appears, Sun's Song Triggered - Large, Appears, Switch Flag + Large + Large, Appears, Clear Flag + Boss Key's Chest + Large, Falling, Switch Flag + Large, Invisible + Small + Small, Invisible + Small, Appears, Clear Flag + Small, Falls, Switch Flag + Large, Appears, Zelda's Lullaby + Large, Appears, Sun's Song Triggered + Large, Appears, Switch Flag @@ -155,11 +159,11 @@ for each sub element (of ) mentioned below: - Graveyard Poe - Graveyard Poe //Leaves a Blue Rupee at its spawn point - (006E) Sharp (Composer Brothers) //Sets Permanent Switch Flag 0B when spoken to, use object 006E - (006E) Flat (Composer Brothers) //Sets Permanent Switch Flag 0A when talked to, use object 006E - Graveyard Poe + Graveyard Poe + Graveyard Poe //Leaves a Blue Rupee at its spawn point + (006E) Sharp (Composer Brothers) //Sets Permanent Switch Flag 0B when spoken to, use object 006E + (006E) Flat (Composer Brothers) //Sets Permanent Switch Flag 0A when talked to, use object 006E + Graveyard Poe May need another object @@ -170,9 +174,9 @@ for each sub element (of ) mentioned below: - Web-Covered Hole - Vertical Web Wall - Web-Covered Hole //When burned, web becomes inverse-conical and extends upwards + Web-Covered Hole + Vertical Web Wall + Web-Covered Hole //When burned, web becomes inverse-conical and extends upwards @@ -181,105 +185,105 @@ for each sub element (of ) mentioned below: - Bomb - Bomb Shadow + Bomb + Bomb Shadow - Timer Spawn (every 6 seconds) - Proximity Spawn - Spawn on Switch Flag + Timer Spawn (every 6 seconds) + Proximity Spawn + Spawn on Switch Flag + 0x3F00 = Switch Flag (Flag to spawn on. Used by type 02 only) - Default - Two-Foot Dodongo //Emits fire and smoke from mouth upon death - Two-Foot Dodongo //Doesn't emit fire and smoke from mouth upon death + Default + Two-Foot Dodongo //Emits fire and smoke from mouth upon death + Two-Foot Dodongo //Doesn't emit fire and smoke from mouth upon death - Fire Keese - Aggressive Keese - Roosting Keese - Ice Keese + Fire Keese + Aggressive Keese + Roosting Keese + Ice Keese +8000 = Invisible - Epona - No Epona - Default + Epona + No Epona + Default - Green Rupee - Blue Rupee - Red Rupee - Recovery Heart - Bomb - Arrow (1) //Used for collecting arrows stuck in walls - Heart Piece - Deku Seeds (5) or Arrows (5) - Deku Seeds (5) or Arrows (10) - Deku Seeds (5) or Arrows (30) - Bombs (5) - Deku Nut - Deku Stick - Large Magic Jar - Small Magic Jar - Deku Seeds (5) or Arrows (5) - Small Key - Flexible Drop //Used for randomized drops, see comments. Will spawn as an invisible Recovery Heart in some situations - Giant Orange Rupee - Large Purple Rupee - Deku Shield //May require Child Link's object - Hylian Shield - Zora Tunic - Goron Tunic - Bombs (5) - Invisible Item + Green Rupee + Blue Rupee + Red Rupee + Recovery Heart + Bomb + Arrow (1) //Used for collecting arrows stuck in walls + Heart Piece + Deku Seeds (5) or Arrows (5) + Deku Seeds (5) or Arrows (10) + Deku Seeds (5) or Arrows (30) + Bombs (5) + Deku Nut + Deku Stick + Large Magic Jar + Small Magic Jar + Deku Seeds (5) or Arrows (5) + Small Key + Flexible Drop //Used for randomized drops, see comments. Will spawn as an invisible Recovery Heart in some situations + Giant Orange Rupee + Large Purple Rupee + Deku Shield //May require Child Link's object + Hylian Shield + Zora Tunic + Goron Tunic + Bombs (5) + Invisible Item +0x3F00 = Collectible Flag - Fire Arrow - Wooden Arrow + Fire Arrow + Wooden Arrow - Navi - Bottled Healing Fairy - Roaming Healing Fairy - Group of Healing Fairies - Fairy Healing You - Roaming Large Healing Fairy + Navi + Bottled Healing Fairy + Roaming Healing Fairy + Group of Healing Fairies + Fairy Healing You + Roaming Large Healing Fairy - Flees when approached //Cucco hidden in the box in Kakariko - Doesn't Flee - Non-Targetable //The non-super cuccos in the Ranch house - Default + Flees when approached //Cucco hidden in the box in Kakariko + Doesn't Flee + Non-Targetable //The non-super cuccos in the Ranch house + Default - Red Tektite - Blue Tektite - Normal Tektite - Dies Instantly + Red Tektite + Blue Tektite + Normal Tektite + Dies Instantly @@ -288,9 +292,9 @@ for each sub element (of ) mentioned below: - Flying Peahat //Spawns Larva - Peahat Larva - Burrowed Peahat + Flying Peahat //Spawns Larva + Peahat Larva + Burrowed Peahat @@ -298,17 +302,17 @@ for each sub element (of ) mentioned below: - Large Bug - Three Small Bugs - Small Bug + Large Bug + Three Small Bugs + Small Bug - Flopping - Swimming, Doesn't Flee //Used for very small pools of water - Swimming, Reacts to Link - Swimming, Flees + Flopping + Swimming, Doesn't Flee //Used for very small pools of water + Swimming, Reacts to Link + Swimming, Flees @@ -326,11 +330,11 @@ for each sub element (of ) mentioned below: - Lizalfos mini-boss, drops from ceiling //Partner to 01, in order to be killed - Lizalfos mini-boss, no mini-boss music //Partner to 00, in order to be killed - Lizalfos, no mini-boss music - Dinolfos, no mini-boss music - Lizalfos, no mini-boss music, drops from ceiling + Lizalfos mini-boss, drops from ceiling //Partner to 01, in order to be killed + Lizalfos mini-boss, no mini-boss music //Partner to 00, in order to be killed + Lizalfos, no mini-boss music + Dinolfos, no mini-boss music + Lizalfos, no mini-boss music, drops from ceiling +0xFF00 = Nullable Switch Flag Lizalfos miniboss spawns when entering room from door bound to this switch flag @@ -360,27 +364,28 @@ To differentiate the two encounters (as both are in room 3), the switch flag is - Impa's Horse - Impa on Horse - Zelda - Ganondorf on Horse (Stationary) - Ganondorf's Horse (Stationary) - Ganondorf on Horse (Riding) + Flames - Ganondorf's Horse (Galloping) - Ganondorf hands crossed //use object 009B - Ganondorf Bowing to King - Ganondorf floating (Curse You) //use object 00E1 + Impa's Horse + Impa on Horse + Zelda + Ganondorf on Horse (Stationary) + Ganondorf's Horse (Stationary) + Ganondorf on Horse (Riding) + Flames + Ganondorf's Horse (Galloping) + Ganondorf hands crossed //use object 009B + Ganondorf Bowing to King + Ganondorf floating (Curse You) //use object 00E1 They need their respective objects to load - + - Falls, lands on ground, hatches in moments - Crashes - Normal egg on ground - Invisible until it hatches (or with Lens of Truth) - Destroyed - Puffs of Blue Smoke (dies away when Link approaches) + Spawned by Gohma Boss, falls on ground, hatches quickly + Spawned by Gohma Boss (unknown 1) + Spawned by Gohma Boss (unknown 2) + Ground Gohma Egg (increase spawn count) + Ground Gohma Egg + Ceiling Gohma Egg (increase spawn count, invisible?) + Ceiling Gohma Egg (invisible?) @@ -443,9 +448,9 @@ Depending on the scene ID, they need certain objects loaded as the first one in - Normal - Big - Invisible + Normal + Big + Invisible + Normal @@ -456,80 +461,80 @@ Depending on the scene ID, they need certain objects loaded as the first one in - Small grey stone block - Large grey stone block - Huge grey stone block - Small grey stone block, rotates when you stand on it - Large grey stone block, rotates when you stand on it - Small grey stone cube - Crashes - Grass clump - Small tree stump - Oblong Signpost (unbreakable) - Arrow Signpost - Black knobby thing + Small grey stone block + Large grey stone block + Huge grey stone block + Small grey stone block, rotates when you stand on it + Large grey stone block, rotates when you stand on it + Small grey stone cube + Crashes + Grass clump + Small tree stump + Oblong Signpost (unbreakable) + Arrow Signpost + Black knobby thing +0xFF00 = Message ID (+0300) - Four spinning a circle, but once you kill one, the rest are gone as well - Three in formation, sink under floor and do not activate - Two in formation, sink under floor and do not activate - One in formation, sink under floor and do not activate - Single + Four spinning a circle, but once you kill one, the rest are gone as well + Three in formation, sink under floor and do not activate + Two in formation, sink under floor and do not activate + One in formation, sink under floor and do not activate + Single - River (Multi-Point) - Stream - Magma - Waterfall - Small Stream - Stream - Fire Temple's Lower Ambient Noise - Fire Temple's Higher Ambient Noise - Water Dripping (Well) - River - Market gibberish - Decrease current BGM volume - Proximity Saria's Song - Howling wind - Gurgling - Temple of Light's dripping sounds - Low booming-likish sound - Quake/Collapse - Fairy Fountain - Torches - Cows - Outside of the ambient noise domain + River (Multi-Point) + Stream + Magma + Waterfall + Small Stream + Stream + Fire Temple's Lower Ambient Noise + Fire Temple's Higher Ambient Noise + Water Dripping (Well) + River + Market gibberish + Decrease current BGM volume + Proximity Saria's Song + Howling wind + Gurgling + Temple of Light's dripping sounds + Low booming-likish sound + Quake/Collapse + Fairy Fountain + Torches + Cows + Outside of the ambient noise domain +0xFF00 = Path ID (Used for sound sources, Type 00, 04 and 05 only) - Tan, Runs Around - Tan, Runs Around - Tan, Runs Away - Tan, Runs Around + Tan, Runs Around + Tan, Runs Around + Tan, Runs Away + Tan, Runs Around - Kokiri Shopkeeper, Objects 0x0FC, 0x101, 0x102 - Kakariko Potion Shopkeeper, Object 0x159 - Bombchu Shopkeeper, spawn when King Dodongo is beaten, Object 0x165 - Market Potion Shopkeeper, Object 0x159 - Bazaar Shopkeeper, Object 0x05B - Unused? Shopkeeper, Object 0x05B - Unused? Shopkeeper, Object 0x05B - Zora Shopkeeper, Object 0x0FE - Goron Shopkeeper, Object 0x05B - Unused? Shopkeeper, Object 0x05B - Happy Mask Shopkeeper, Object 0x13E + Kokiri Shopkeeper, Objects 0x0FC, 0x101, 0x102 + Kakariko Potion Shopkeeper, Object 0x159 + Bombchu Shopkeeper, spawn when King Dodongo is beaten, Object 0x165 + Market Potion Shopkeeper, Object 0x159 + Bazaar Shopkeeper, Object 0x05B + Unused? Shopkeeper, Object 0x05B + Unused? Shopkeeper, Object 0x05B + Zora Shopkeeper, Object 0x0FE + Goron Shopkeeper, Object 0x05B + Unused? Shopkeeper, Object 0x05B + Happy Mask Shopkeeper, Object 0x13E @@ -545,8 +550,8 @@ Out-of-bounds Plane (typ.) - Lower Part (Flame decal) - Top Part (Face decal) + Lower Part (Flame decal) + Top Part (Face decal) +0xFF00 = Switch Flag @@ -565,52 +570,53 @@ Out-of-bounds Plane (typ.) - - Large Face Cube //Pushable - Squat Cube //Shakes and flies into the air when you land on it + + Large Face Cube //Pushable + Squat Cube //Shakes and flies into the air when you land on it + - 2-way diagonal - 4-way plus + 2-way diagonal + 4-way plus - Sinking - Sliding + Sinking + Sliding - Idle - Unknown - Unknown - Unknown - Transformation into Zelda - Nocturne CS - Minuet CS - Bolero CS - Serenade CS - First Meeting at ToT + Idle + Unknown + Unknown + Unknown + Transformation into Zelda + Nocturne CS + Minuet CS + Bolero CS + Serenade CS + First Meeting at ToT +0x0FC0 = Chest Flag - Large, turns off with room clear. - Large, plays cutscene, switches off for long time with ticking sound. Turns off permanently with chest flag. - Small, switches off for long time silently. - Large, plays cutscene, switches off for short time with ticking sound. - Disabled, small, switches on for short time. - Disabled, large, can be switched on and off. - Large, switches off permanently, won't spawn if room is cleared. - Nothing + Large, turns off with room clear. + Large, plays cutscene, switches off for long time with ticking sound. Turns off permanently with chest flag. + Small, switches off for long time silently. + Large, plays cutscene, switches off for short time with ticking sound. + Disabled, small, switches on for short time. + Disabled, large, can be switched on and off. + Large, switches off permanently, won't spawn if room is cleared. + Nothing @@ -618,30 +624,30 @@ Out-of-bounds Plane (typ.) - Chains - Drawbridge + Chains + Drawbridge - Club Moblin //Pounds the ground - Spear Moblin + Club Moblin //Pounds the ground + Spear Moblin +0xFF00 = path Id (Spear Moblins only) - Bomb - Invisible Bomb - Default + Bomb + Invisible Bomb + Default - Light Arrows CS - Pre-Credits - Post Castle Collapse + Light Arrows CS + Pre-Credits + Post Castle Collapse @@ -650,30 +656,31 @@ Out-of-bounds Plane (typ.) - Floating Platform - Water Plane - 3 Raising platforms + Floating Platform + Water Plane + 3 Raising platforms - - Rotating Spike Cylinder - Deku tree ladder falling when hit by slingshot (switchflag?) + + Rotating Spike Cylinder + Deku tree ladder falling when hit by slingshot (switchflag?) + - Statue - Enemy + Statue + Enemy - Small - Big + Small + Big @@ -686,10 +693,10 @@ Out-of-bounds Plane (typ.) - Bombable Wall, triggers intro cutscene - Bombable Wall - Bombable Floor - Lava Cover + Bombable Wall, triggers intro cutscene + Bombable Wall + Bombable Floor + Lava Cover @@ -697,7 +704,7 @@ Out-of-bounds Plane (typ.) - Lord Jabu-Jabu + Lord Jabu-Jabu The actor spawns the collision data @@ -708,27 +715,27 @@ Out-of-bounds Plane (typ.) - Normal (adult Link) - Spawning in from crystal //Combine with Link's gentle fall spawn in - Normal - Nothing - Blue warp, disappears - Giant purple crystal/magic enclosure - Yellow warp, disappears - Blue warp, doesn't warp you - Spawn in from child blue warp //Combine with Link's gentle fall - Blue warp, warping animation - Tan warp, disappears - Green warp, disappears - Red warp, disappears - Area fails to load + Normal (adult Link) + Spawning in from crystal //Combine with Link's gentle fall spawn in + Normal + Nothing + Blue warp, disappears + Giant purple crystal/magic enclosure + Yellow warp, disappears + Blue warp, doesn't warp you + Spawn in from child blue warp //Combine with Link's gentle fall + Blue warp, warping animation + Tan warp, disappears + Green warp, disappears + Red warp, disappears + Area fails to load - Golden Torch - Puzzle Torch - Wooden Torch + Golden Torch + Puzzle Torch + Wooden Torch @@ -753,14 +760,14 @@ Out-of-bounds Plane (typ.) - Floating Square platform, sloped bottom //Used in first room, on center column - Floating Square platform - Floating Square platform, tapered on bottom //Center Room floating block - Dragon Head Statue //Main Room - Dragon Head Statue //Skulltula Room - Dragon Head Statue //before Dark Link - Dragon Head Statue - Moving Square Platform with Hookshot Target + Floating Square platform, sloped bottom //Used in first room, on center column + Floating Square platform + Floating Square platform, tapered on bottom //Center Room floating block + Dragon Head Statue //Main Room + Dragon Head Statue //Skulltula Room + Dragon Head Statue //before Dark Link + Dragon Head Statue + Moving Square Platform with Hookshot Target @@ -774,12 +781,12 @@ Out-of-bounds Plane (typ.) - Switches to lowest (Triforce seems to activate itself for some reason in the ToT) - Stays at ground level (Triforce isn't affected in ToT) - Water Temple Map 3, Standard Quest - Water Temple Map 6, Standard Quest - Water Temple Map 14, Standard Quest - Water Temple (most rooms), Standard Quest + Switches to lowest (Triforce seems to activate itself for some reason in the ToT) + Stays at ground level (Triforce isn't affected in ToT) + Water Temple Map 3, Standard Quest + Water Temple Map 6, Standard Quest + Water Temple Map 14, Standard Quest + Water Temple (most rooms), Standard Quest @@ -794,19 +801,19 @@ Out-of-bounds Plane (typ.) - Large Green Bubble //requires movement path - Green Bubble //requires movement path - White Bubble //requires movement path - Fire Bubble //Proximity activated, bounces on solid surfaces, hides in lava - Blue Bubble + Large Green Bubble //requires movement path + Green Bubble //requires movement path + White Bubble //requires movement path + Fire Bubble //Proximity activated, bounces on solid surfaces, hides in lava + Blue Bubble +0xFF00 = Path Id - Normal - Invisible + Normal + Invisible @@ -828,23 +835,23 @@ Use with actors 008C and 008B for the cutscene to work - (0068) Ocarina //Unused - (0062) Light Medallion - (0063) Shadow Medallion - (0064) Fire Medallion - (0065) Water Medallion - (0066) Spirit Medallion - (0067) Forest Medallion + (0068) Ocarina //Unused + (0062) Light Medallion + (0063) Shadow Medallion + (0064) Fire Medallion + (0065) Water Medallion + (0066) Spirit Medallion + (0067) Forest Medallion Add the object in brackets for it to work - Yellow with corner removed - Green and rectangular - Yellow/green and rectangular, looks rusty - Crashes, but not without drawing a huge black thing that I can only assume is a gate... - Crashes before it can even light the area... + Yellow with corner removed + Green and rectangular + Yellow/green and rectangular, looks rusty + Crashes, but not without drawing a huge black thing that I can only assume is a gate... + Crashes before it can even light the area... + Crashes, no sign of a gate @@ -855,8 +862,8 @@ Use with actors 008C and 008B for the cutscene to work - Hammer-triggered Stone Steps - Platform, one sided + Hammer-triggered Stone Steps + Platform, one sided +0x3F00 = Switch Flag @@ -866,34 +873,36 @@ Use with actors 008C and 008B for the cutscene to work - Large tree - Medium tree - Small tree - Group of trees - Medium tree - Medium tree, dark brown trunk, greener leaves - Group of trees, dark brown trunk, yellow leaves - Medium tree, dark brown trunk, yellow leaves - Group of trees, dark brown trunk, greener leaves - Medium tree, dark brown trunk, greener leaves - Ugly tree from Kakariko Village - Bush - Large bush - Group of bushes - Bush - Group of large bushes - Large bush - Dark bush - Large dark bush - Group of dark bushes - Dark bush - Group of large dark bushes - Large dark bush - Dancing dark bush //Disappears after several repetitions - - + Large Conical Tree + Medium Conical Tree + Small Conical Tree + Conical Tree Spawner + Conical Tree Spawned + Oval Green Tree + Oval Yellow Tree Spawner + Oval Yellow Tree Spawned + Oval Green Tree Spawner + Oval Green Tree Spawned + Adult Kakariko Tree + Small Bush + Large Bush + Small Bush Spawner + Small Bush Spawned + Large Bush Spawner + Large Bush Spawned + Small Black Bush + Large Black Bush + Small Black Bush Spawner + Small Black Bush Spawned + Large Black Bush Spawner + Large Black Bush Spawned + Green leaf + Yellow leaf + + - + + +0xFF00 = Controls item(s) dropped (trees only) -0000 Random -0800 Deku seeds @@ -910,26 +919,26 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Normal, flashes blue when struck with sword - Frickin' huge, doesn't flash when struck - Even bigger? - Ridiculously huge? - Small size, flashes blue when struck + Normal, flashes blue when struck with sword + Frickin' huge, doesn't flash when struck + Even bigger? + Ridiculously huge? + Small size, flashes blue when struck Unused - Stone cube, side struck with sword flashes blue - Slightly larger + Stone cube, side struck with sword flashes blue + Slightly larger - 4-Way Attack - Line Loop - Circle Loop + 4-Way Attack + Line Loop + Circle Loop @@ -960,40 +969,40 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Attacking Beamos (2 health) - Attacking Beamos (1 health) + Attacking Beamos (2 health) + Attacking Beamos (1 health) XX00: 05 in dodongo's cavern, 08 in ganon's castle entrance - Crystal Light, used by Triforce in Hyrule Creation CS - Flame, used by Din in Hyrule Creation CS - Blue Orb, used by Din in Hyrule Creation CS - Large Green Cone, used by Farore in Hyrule Creation CS - Din - Nayru - Farore - Blue Light Ring, used by Din and Farore in Hyrule Creation CS - Triforce - Fire Medallion - Water Medallion - Forest Medallion - Spirit Medallion - Shadow Medallion - Light Medallion - Time Warp Effect from Temple of Time - Blue Light Ring that shrinks, used by Din in Hyrule Creation CS - Vertical Light Effect used by Triforce - Light Ball from the 6 Sages when sealing Ganondorf - Kokiri Emerald - Goron Ruby - Zora Sapphire - Dust, used in Light Arrow CS - Light Ball, used by Zelda - Large Block of Time Time Warp Effect - Small Block of Time Time Warp Effect + Crystal Light, used by Triforce in Hyrule Creation CS + Flame, used by Din in Hyrule Creation CS + Blue Orb, used by Din in Hyrule Creation CS + Large Green Cone, used by Farore in Hyrule Creation CS + Din + Nayru + Farore + Blue Light Ring, used by Din and Farore in Hyrule Creation CS + Triforce + Fire Medallion + Water Medallion + Forest Medallion + Spirit Medallion + Shadow Medallion + Light Medallion + Time Warp Effect from Temple of Time + Blue Light Ring that shrinks, used by Din in Hyrule Creation CS + Vertical Light Effect used by Triforce + Light Ball from the 6 Sages when sealing Ganondorf + Kokiri Emerald + Goron Ruby + Zora Sapphire + Dust, used in Light Arrow CS + Light Ball, used by Zelda + Large Block of Time Time Warp Effect + Small Block of Time Time Warp Effect @@ -1008,30 +1017,30 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Blue Rain Effect, used by Goddesses/Triforce CS - Blue Rain Effect, used in the Master Sword CS - Giant Rock 1 - Giant Rock 2 - Giant Rock 3 - Giant Rock 4 - Giant Rock 5 - Fluffy Clouds - Bolero 3D Note (not implemented) - Serenade 3D Note (not implemented) - Requiem 3D Note (not implemented) - ? 3D Note (not implemented) - ? 3D Note (not implemented) - Door of Time - Yellow Light, used in Master Sword's chamber - Warp Song leaving effect - Warp Song arriving effect - Orange Sparkly Effect, used by appearing chests + Blue Rain Effect, used by Goddesses/Triforce CS + Blue Rain Effect, used in the Master Sword CS + Giant Rock 1 + Giant Rock 2 + Giant Rock 3 + Giant Rock 4 + Giant Rock 5 + Fluffy Clouds + Bolero 3D Note (not implemented) + Serenade 3D Note (not implemented) + Requiem 3D Note (not implemented) + ? 3D Note (not implemented) + ? 3D Note (not implemented) + Door of Time + Yellow Light, used in Master Sword's chamber + Warp Song leaving effect + Warp Song arriving effect + Orange Sparkly Effect, used by appearing chests - - Stationary with switch and hardcoded camera cutscene - Follows you + + Stationary with switch and hardcoded camera cutscene + Follows Player @@ -1040,34 +1049,34 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Slow Patrolling Guard - Fast Patrolling Guard - Slow Patrolling Guard, can skip some waypoints - Fast Patrolling Guard, can skip some waypoints - Nighttime Standing Guard + Slow Patrolling Guard + Fast Patrolling Guard + Slow Patrolling Guard, can skip some waypoints + Fast Patrolling Guard, can skip some waypoints + Nighttime Standing Guard Rupees circle spawned if Path ID == 3 - Rising Gibdo - Gibdo - Redead, doesn't mourn - Redead, doesn't mourn if walking - Redead - Crying Redead - Invisible Redead + Rising Gibdo + Gibdo + Redead, doesn't mourn + Redead, doesn't mourn if walking + Redead + Crying Redead + Invisible Redead - Meg, Purple Poe - Joelle, Red Poe - Beth, Blue Poe - Amy, Green Poe + Meg, Purple Poe + Joelle, Red Poe + Beth, Blue Poe + Amy, Green Poe @@ -1075,8 +1084,8 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Sinks into the ground - Breaks on impact + Sinks into the ground + Breaks on impact @@ -1085,20 +1094,20 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - ??? Amy - ??? Amy - Joelle Painting Puzzle - Beth Painting Puzzle - ??? Amy + ??? Amy + ??? Amy + Joelle Painting Puzzle + Beth Painting Puzzle + ??? Amy +0x3F = Switch Flag - Fish - Bug - Butterfly + Fish + Bug + Butterfly @@ -1112,12 +1121,12 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - - Skullwalltula - Gold Skulltula + + Skullwalltula + Gold Skulltula - + @@ -1147,11 +1156,11 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Flying Fairies, Dustmotes - Lightning - Snow - Electric Spark Effect, object 0x0A1 - Ganon's Castle Barrier Colored Light Beams, object 0x179 + Flying Fairies, Dustmotes + Lightning + Snow + Electric Spark Effect, object 0x0A1 + Ganon's Castle Barrier Colored Light Beams, object 0x179 @@ -1162,14 +1171,13 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Visible - Appears on Song of Storms - Appears on explosion or Megaton Hammer + Visible + Appears on Song of Storms + Appears on explosion or Megaton Hammer - - + @@ -1185,47 +1193,57 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) + + + + + + + + + + - Shadow Temple's Eye of Truth Door - Small Square Patch of Ground, child only, blocks entrance to Dampe's Grave - Royal Tomb Grave, despawn if the Royal Tomb CS is watched and the scene is the graveyard - Thunderbolt used with the electric spark effect - Light Aura, appears when Royal Tomb Grave explodes + Shadow Temple's Eye of Truth Door + Small Square Patch of Ground, child only, blocks entrance to Dampe's Grave + Royal Tomb Grave, despawn if the Royal Tomb CS is watched and the scene is the graveyard + Thunderbolt used with the electric spark effect + Light Aura, appears when Royal Tomb Grave explodes +0xFF00 = Switch Flag - Default - Plays discovery sfx when pulled back - Typical + Default + Plays discovery sfx when pulled back + Typical - Normal (no sphere) - Dissipating (no sphere) + Normal (no sphere) + Dissipating (no sphere) - Blue Warp and Ruto - Leaning Ruto //no collision data, targetable - Ruto, First Encounter //Plays cutscene from Jabu-Jabu's Belly when you first meet her - Ruto, after falling down the hole in Jabu-Jabu + Blue Warp and Ruto + Leaning Ruto //no collision data, targetable + Ruto, First Encounter //Plays cutscene from Jabu-Jabu's Belly when you first meet her + Ruto, after falling down the hole in Jabu-Jabu - Flies, lands, dies in a bit //try not to run into it, Link'll catch on fire - Flies, lands, creeps towards Link, dies in a bit //it's blue, but it's still fire + Flies, lands, dies in a bit //try not to run into it, Link'll catch on fire + Flies, lands, creeps towards Link, dies in a bit //it's blue, but it's still fire @@ -1235,16 +1253,16 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Light Medallion and post-Spirit/Shadow Medallions - Ganon's Castle and post-Ganon + Light Medallion and post-Spirit/Shadow Medallions + Ganon's Castle and post-Ganon - Leever //Use object 0017, spawn on sand (max defined by code) - Red Tektite //Use object 0016 (max defined by code) - Stalchildren //Use object 0184, spawn on dirt - Wolfos //Use object 0183 + Leever //Use object 0017, spawn on sand (max defined by code) + Red Tektite //Use object 0016 (max defined by code) + Stalchildren //Use object 0184, spawn on dirt + Wolfos //Use object 0183 @@ -1258,28 +1276,28 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Fire Medallion (Default) - Goron Ruby - Chamber After Ganon - Credits + Fire Medallion (Default) + Goron Ruby + Chamber After Ganon + Credits - Shadow Medallion - Chamber After Ganon/Ganon's Castle - Escort - Hyrule Field after ZL - First Time Escort - Credits + Shadow Medallion + Chamber After Ganon/Ganon's Castle + Escort + Hyrule Field after ZL + First Time Escort + Credits - No damage - One-Hit Kill + No damage + One-Hit Kill @@ -1290,26 +1308,26 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Rock Wall with Skull //style that sometimes has glowy eyes - Black square with large skull face - Shadow Temple Boss Room platforms - Wall of Skulls - Shadow Temple Floor //bluish? texture - Massive Platform - Wall with bluish?, fat bricks texture (one sided) - Shadow Temple Diamond Room (before big key) Fake Walls - Wall with purplish?, fat brick texture (both side) - Room 11's invisible spikes, invisible hookshot point. + Rock Wall with Skull //style that sometimes has glowy eyes + Black square with large skull face + Shadow Temple Boss Room platforms + Wall of Skulls + Shadow Temple Floor //bluish? texture + Massive Platform + Wall with bluish?, fat bricks texture (one sided) + Shadow Temple Diamond Room (before big key) Fake Walls + Wall with purplish?, fat brick texture (both side) + Room 11's invisible spikes, invisible hookshot point. Need Object 0x69 - Moving stone platforms - Rising and falling stone platforms - Spinning black platform - Metal grate - Same as 0001, but graphics are glitched + Moving stone platforms + Rising and falling stone platforms + Spinning black platform + Metal grate + Same as 0001, but graphics are glitched +0xFF00 = Switch Flag //Type 03 Only @@ -1321,27 +1339,27 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Shadow Temple Scythes (Visible) //Use object 0069 - Shadow Temple Scythes (Invisible) //Use object 0069 - Ice Cavern Spinning Blade //Use object 0069 + Shadow Temple Scythes (Visible) //Use object 0069 + Shadow Temple Scythes (Invisible) //Use object 0069 + Ice Cavern Spinning Blade //Use object 0069 May require additional object - Hyrule Castle guard - Death Mountain gate guard - Ceremonial guard + Hyrule Castle guard + Death Mountain gate guard + Ceremonial guard - Large - Medium - Small - Large + Large + Medium + Small + Large @@ -1350,31 +1368,31 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Spirit Temple's Sun-Block Room - Spirit Temple's Single Cobra-Mirror Room - Spirit Temple's Four Armos Room - Spirit Temple's Topmost Room + Spirit Temple's Sun-Block Room + Spirit Temple's Single Cobra-Mirror Room + Spirit Temple's Four Armos Room + Spirit Temple's Topmost Room - Bridge Sides - Broken Bridge - Bridge as Child - Tent - Repaired Bridge + Bridge Sides + Broken Bridge + Bridge as Child + Tent + Repaired Bridge - Statue, no spear, movable with Adult Link - Spear only, climbable + Statue, no spear, movable with Adult Link + Spear only, climbable - Barinade + Barinade @@ -1383,28 +1401,28 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Guillotine Blade (Slow) - Spiked Box on Chain - Spiked Wooden Wall, moving //FIXME: moves in wrong direction? - Opposite Spiked Wooden Wall, moving //FIXME: moves in wrong direction? - Propeller, blows wind - Guillotine Blade (Fast) + Guillotine Blade (Slow) + Spiked Box on Chain + Spiked Wooden Wall, moving //FIXME: moves in wrong direction? + Opposite Spiked Wooden Wall, moving //FIXME: moves in wrong direction? + Propeller, blows wind + Guillotine Blade (Fast) + Graphical glitches, same as 2 or 3 (unsure) - Spawns gibdo //(needs object 0098) - Spawns 2 keese //(needs object 000D) + Spawns gibdo //(needs object 0098) + Spawns 2 keese //(needs object 000D) +0x3F = Switch Flag - Giant Bird Statue, bombing it will make it fall - Bombable Wall of Skulls - Bombable Rubble (Object 0x8D) + Giant Bird Statue, bombing it will make it fall + Bombable Wall of Skulls + Bombable Rubble (Object 0x8D) +0x3F00 = Switch Flag @@ -1417,19 +1435,19 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Wooden (Default) - Stone (Zora) - Granite (Goron) + Wooden (Default) + Stone (Zora) + Granite (Goron) - Spirit Medallion - Chamber After Ganon/Ganon's Castle - Kidnapping CS - Iron Knuckle - Credits - Crawlspace + Spirit Medallion + Chamber After Ganon/Ganon's Castle + Kidnapping CS + Iron Knuckle + Credits + Crawlspace @@ -1438,72 +1456,72 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Sits there, mini-boss music starts, slice it to make it move (no teleport), green target - Already running around, yellow target this time, no music + Sits there, mini-boss music starts, slice it to make it move (no teleport), green target + Already running around, yellow target this time, no music Slicing it in the back will make it jump to the y location of its room, which is typically below most floors - Normal Deku Baba - Straight Deku Baba + Normal Deku Baba + Straight Deku Baba - Giant Octo's Platform - Elevator Platform - Water Square //Rises when Switch Flag is set - Lowering Platform //Lowers into place when stepped on, sets Switch Flag + Giant Octo's Platform + Elevator Platform + Water Square //Rises when Switch Flag is set + Lowering Platform //Lowers into place when stepped on, sets Switch Flag +0xFF00 = Nullable Switch Flag - Chamber of Sages, gives Forest Medallion - Chamber After Ganon/Ganon's Castle //Use with actor 01A7 - Credits, Death Mountain Trail - Fairy Ocarina Cutscene + Chamber of Sages, gives Forest Medallion + Chamber After Ganon/Ganon's Castle //Use with actor 01A7 + Credits, Death Mountain Trail + Fairy Ocarina Cutscene - Unknown - Unknown - Unknown + Unknown + Unknown + Unknown - Unknown - Unknown - Unknown - Default + Unknown + Unknown + Unknown + Default - Koume - Kotake + Koume + Kotake - Default - Debris - Debris - Debris - Debris - Debris + Default + Debris + Debris + Debris + Debris + Debris - Cracked stone floor - Bombable stone wall - Large bombable stone wall + Cracked stone floor + Bombable stone wall + Large bombable stone wall +0x3F00 = Switch Flag @@ -1532,10 +1550,10 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Water Medallion - Chamber After Ganon/Ganon's Castle - Credits - Water Temple Meeting + Water Medallion + Chamber After Ganon/Ganon's Castle + Credits + Water Temple Meeting @@ -1545,10 +1563,10 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Temple Gate - Gate lock - Water plane - Ice Block blocking Zora's Domain Entrance (Adult only) + Temple Gate + Gate lock + Water plane + Ice Block blocking Zora's Domain Entrance (Adult only) +0xFF = Nullable Switch Flag @@ -1565,10 +1583,10 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Ingo Race - Gerudo Archery - Unused? - Malon Race + Ingo Race + Gerudo Archery + Unused? + Malon Race @@ -1577,20 +1595,20 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Reddish brown - Green - Grayish blue with some red - Already dead + Reddish brown + Green + Grayish blue with some red + Already dead - Reddish brown - Green - Grayish blue with some red - Corrupt textures, still visible and works - Dark brownish - Blackish gray + Reddish brown + Green + Grayish blue with some red + Corrupt textures, still visible and works + Dark brownish + Blackish gray @@ -1599,13 +1617,13 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Default + Default - Rotating platforms - Metal Gate + Rotating platforms + Metal Gate @@ -1614,19 +1632,19 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Gray - Expanding, gray //Unused? - Expanding, gray //Unused? - Default + Gray + Expanding, gray //Unused? + Expanding, gray //Unused? + Default - Floor Blue Switch, release when not stood on - Floor Heavy Switch (Need Ruto to press it) - Standard Floor Yellow Switch - Standard Tall Yellow Switch - On/Off Toggle Tall Yellow Switch + Floor Blue Switch, release when not stood on + Floor Heavy Switch (Need Ruto to press it) + Standard Floor Yellow Switch + Standard Tall Yellow Switch + On/Off Toggle Tall Yellow Switch +0x3F00 = Switch Flag @@ -1635,92 +1653,92 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Default - Begins battle - Ganondorf death sequence + Default + Begins battle + Ganondorf death sequence - Default + Default - Normal - Does not open //possibly waiting for some trap to spring? + Normal + Does not open //possibly waiting for some trap to spring? - Frog Game Ocarina Spot - Yellow Frog - Blue Frog - Red Frog - Purple Frog - White Frog + Frog Game Ocarina Spot + Yellow Frog + Blue Frog + Red Frog + Purple Frog + White Frog - Collectible Deku Shield - Burning Deku shield + Collectible Deku Shield + Burning Deku shield - Large crystal - Smaller crystal - Crystal platform - Meltable ice sheet - Giant crystal + Large crystal + Smaller crystal + Crystal platform + Meltable ice sheet + Giant crystal 0xFF = Nullable Switch Flag - Group of small blue flames, disappear - Blue flame, disappears - Blue flame, targetable + Group of small blue flames, disappear + Blue flame, disappears + Blue flame, targetable - Ocarina of Time being tossed higher in air - Ocarina of Time being tossed in air - Ocarina of Time - Collectible Ocarina of Time + Ocarina of Time being tossed higher in air + Ocarina of Time being tossed in air + Ocarina of Time + Collectible Ocarina of Time - Normal - No bright sphere, first one dies off quickly + Normal + No bright sphere, first one dies off quickly - Rain of multi-colored light balls, used in Rainbow Bridge CS - Lots of small particles, used with the White 'Black Hole' - White 'Black Hole' Effect, used in the Ganondorf's Sealing CS - Red Light Ball, used in Ganon's Castle - Green Light Ball, used in Ganon's Castle - Yellow Light Ball, used in Ganon's Castle - Purple Light Ball, used in Ganon's Castle - Orange Light Ball, used in Ganon's Castle - Blue Light Ball, used in Ganon's Castle - Koume/Kotake Red Light Ball Attack - Koume/Kotake Blue Light Ball Attack - 'Nabooru Disappearing' Orange Particles - Ganondorf's Light Ball Attack Purple Loading Effect - Ganondorf's Light Ball Attack, used in Zelda Fleeing CS - Red Light Ball with particles, used in the LLR/DMT part of the credits - Green Light Ball with particles, used in the LLR/DMT part of the credits - Yellow Light Ball with particles, used in ToT Cutscenes - Purple Light Ball with particles, used in the LLR/DMT part of the credits - Orange Light Ball with particles, used in the LLR/DMT part of the credits - Blue Light Ball with particles, used in the LLR/DMT part of the credits + Rain of multi-colored light balls, used in Rainbow Bridge CS + Lots of small particles, used with the White 'Black Hole' + White 'Black Hole' Effect, used in the Ganondorf's Sealing CS + Red Light Ball, used in Ganon's Castle + Green Light Ball, used in Ganon's Castle + Yellow Light Ball, used in Ganon's Castle + Purple Light Ball, used in Ganon's Castle + Orange Light Ball, used in Ganon's Castle + Blue Light Ball, used in Ganon's Castle + Koume/Kotake Red Light Ball Attack + Koume/Kotake Blue Light Ball Attack + 'Nabooru Disappearing' Orange Particles + Ganondorf's Light Ball Attack Purple Loading Effect + Ganondorf's Light Ball Attack, used in Zelda Fleeing CS + Red Light Ball with particles, used in the LLR/DMT part of the credits + Green Light Ball with particles, used in the LLR/DMT part of the credits + Yellow Light Ball with particles, used in ToT Cutscenes + Purple Light Ball with particles, used in the LLR/DMT part of the credits + Orange Light Ball with particles, used in the LLR/DMT part of the credits + Blue Light Ball with particles, used in the LLR/DMT part of the credits @@ -1728,18 +1746,18 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Rotatable Bird Statue - Circular Trap Door Platform //Opens when wrong skull is chosen - Gate //Only blocks one-way - Skull Top - Glitchy graphics, can't see object, behaves like the gate + Rotatable Bird Statue + Circular Trap Door Platform //Opens when wrong skull is chosen + Gate //Only blocks one-way + Skull Top + Glitchy graphics, can't see object, behaves like the gate +0x3F00 = Switch Flag - Default + Default Not market town gate @@ -1753,9 +1771,9 @@ ZROT 0x00FF = Gold Skulltula spawn var high byte (See Gold Skulltula Actor 0095) - Large shadow //looks like it's reproduced, well-done though - Small Shadow //CRASH? - No shadow //CRASH? + Large shadow //looks like it's reproduced, well-done though + Small Shadow //CRASH? + No shadow //CRASH? @@ -1768,19 +1786,19 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Wearing red vest over blue shirt, no hat - Normal fish - Hylian Loach - Huge Hylian Loach - Pond stuff, still no hat + Wearing red vest over blue shirt, no hat + Normal fish + Hylian Loach + Huge Hylian Loach + Pond stuff, still no hat - Small Push Block - Medium Push Block - Large Push Block - Huge Push Block + Small Push Block + Medium Push Block + Large Push Block + Huge Push Block @@ -1798,13 +1816,13 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Default + Default - Rushing white particles //Jabu-Jabu, when he opens his mouth - Rushing white particles to one point (???) + Rushing white particles //Jabu-Jabu, when he opens his mouth + Rushing white particles to one point (???) @@ -1813,15 +1831,15 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Default + Default - Purple (Meg) - Red (Joelle) - Blue (Beth) - Green (Amy) + Purple (Meg) + Red (Joelle) + Blue (Beth) + Green (Amy) +0x3F = Switch Flag @@ -1833,9 +1851,9 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Fence - Nothing //Possibly waypoint for the Ingo Race? - Fence + Fence + Nothing //Possibly waypoint for the Ingo Race? + Fence @@ -1846,14 +1864,14 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Bottle //Use group 00C6 - Bottle with Ruto's Letter //Use group 010B - Hylian shield //Use group 00DC - Quiver //Use group 00BE - Silver Scale //Use group 00DB - Golden Scale //Use group 00DB - Small Key //Use group 00AA - Fire Arrow //Use group 0158 + Bottle //Use group 00C6 + Bottle with Ruto's Letter //Use group 010B + Hylian shield //Use group 00DC + Quiver //Use group 00BE + Silver Scale //Use group 00DB + Golden Scale //Use group 00DB + Small Key //Use group 00AA + Fire Arrow //Use group 0158 @@ -1868,15 +1886,15 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Collectible gave if each tag points are reached (no order) - Tag Point (no order) - Gives collectible if in range - Invisible Collectible - Collectible gave if each tag points are reached in order - Tag Point (sets order) - Sets Switch Flag if in range (no collectible) - Bomberman Soldier - Collectible gave if player rolls + Collectible gave if each tag points are reached (no order) + Tag Point (no order) + Gives collectible if in range + Invisible Collectible + Collectible gave if each tag points are reached in order + Tag Point (sets order) + Sets Switch Flag if in range (no collectible) + Bomberman Soldier + Collectible gave if player rolls @@ -1909,42 +1927,42 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Nabooru Knuckle //May Crash - White, sitting //Stone Chair - Black, standing - White, standing - White, no armor falls off when at low health + Nabooru Knuckle //May Crash + White, sitting //Stone Chair + Black, standing + White, standing + White, no armor falls off when at low health +0xFF00 = Nullable Switch Flag - Unknown - Unknown - Unknown - Unknown - Unknown - Unknown + Unknown + Unknown + Unknown + Unknown + Unknown + Unknown - Saria's Song HP Skull Kid - Ocarina Game Left Skull Kid - Ocarina Game Right Skull Kid - Saria's Song HP Ocarina Spot - Memory Game Ocarina Spot - Enemy Skull Kid + Saria's Song HP Skull Kid + Ocarina Game Left Skull Kid + Ocarina Game Right Skull Kid + Saria's Song HP Ocarina Spot + Memory Game Ocarina Spot + Enemy Skull Kid - Silver Rupee Tracker (handles puzzle resolution) - Silver Rupee (the puzzle itself) - Horseback Archery Pot + Silver Rupee Tracker (handles puzzle resolution) + Silver Rupee (the puzzle itself) + Horseback Archery Pot @@ -1957,47 +1975,47 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Deku Nuts - Deku Sticks - Piece of Heart (10 rupees) - Deku Seeds - Deku Shield - Bombs - Deku Seeds - Red Potion - Green Potion - Deku Stick Upgrade - Deku Nut Upgrade - Never speaks, and Link is sadly very patient... - Pocket Egg? + Deku Nuts + Deku Sticks + Piece of Heart (10 rupees) + Deku Seeds + Deku Shield + Bombs + Deku Seeds + Red Potion + Green Potion + Deku Stick Upgrade + Deku Nut Upgrade + Never speaks, and Link is sadly very patient... + Pocket Egg? - Talk when in range - C-Up Prompt + Talk when in range + C-Up Prompt - Stone Eye - Heat-Seeking flame - Immobile flame, dies - Flame sound effect + Stone Eye + Heat-Seeking flame + Immobile flame, dies + Flame sound effect - Heart or Green Rupee - Bombs - Deku Seeds - Deku Nuts - Deku Seeds - Giant Purple Rupee - Goron Tunic - Nothing + Heart or Green Rupee + Bombs + Deku Seeds + Deku Nuts + Deku Seeds + Giant Purple Rupee + Goron Tunic + Nothing +0x3F = Collectible Flag @@ -2010,14 +2028,14 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Waterfall and Pool //Room 1 - King's Chamber Water //Room 0 + Waterfall and Pool //Room 1 + King's Chamber Water //Room 0 - Immobile - Mobile //Hidden When Spawned + Immobile + Mobile //Hidden When Spawned @@ -2025,8 +2043,8 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Rotating platform - Dampé Race Stone Door + Rotating platform + Dampé Race Stone Door +0xFF = Nullable Switch Flag @@ -2036,9 +2054,9 @@ The sun switch has to be between 252 and 308 units from the cobra mirror to be a - Normal shrub. Random drops. //Use object 0002 - Cut-able, regenerating grass //Use object 012B, Drops: Heart, Arrows or Deku Seeds - Cut-able grass //Use object 012B, Set drop table via Random Drop Table param + Normal shrub. Random drops. //Use object 0002 + Cut-able, regenerating grass //Use object 012B, Drops: Heart, Arrows or Deku Seeds + Cut-able grass //Use object 012B, Set drop table via Random Drop Table param @@ -2068,11 +2086,11 @@ ZROT +0x0003 = Speed, Acceleration - Floor - Rusted Floor - Eye - Crystal - Targetable Crystal + Floor + Rusted Floor + Eye + Crystal + Targetable Crystal @@ -2083,8 +2101,8 @@ ZROT +0x0003 = Speed, Acceleration - Large - Small + Large + Small @@ -2098,21 +2116,21 @@ ZROT +0x0003 = Speed, Acceleration - Hookshot Target Tower - Hookshot Target Tower, lifts up on Switch Flag - Square Hookshot Target + Hookshot Target Tower + Hookshot Target Tower, lifts up on Switch Flag + Square Hookshot Target - Zora River, Zelda's Lullaby Spot (no cutscene) - Windmill, Song of Storms spot (cutscene) - Temple of Time, Song of Time spot (cutscene) - Learn Sun's Song spot - Royal Family Tomb, Zelda's Lullaby spot - Puzzle Spot + Zora River, Zelda's Lullaby Spot (no cutscene) + Windmill, Song of Storms spot (cutscene) + Temple of Time, Song of Time spot (cutscene) + Learn Sun's Song spot + Royal Family Tomb, Zelda's Lullaby spot + Puzzle Spot @@ -2127,17 +2145,17 @@ ZROT +0x0003 = Speed, Acceleration - End Targets - Mounted Target (Small) - Mounted Target (Big) //Center one + End Targets + Mounted Target (Small) + Mounted Target (Big) //Center one - Follows path, disappears, reappears at first waypoint //simulates falling into a hole - Follows path, breaks into pieces, reappears at first waypoint //As in adult Death Mountain Trail - Follows path, treating it as a closed loop - Follows path, halts, reverses, repeat //As in Fire Temple boulder maze + Follows path, disappears, reappears at first waypoint //simulates falling into a hole + Follows path, breaks into pieces, reappears at first waypoint //As in adult Death Mountain Trail + Follows path, treating it as a closed loop + Follows path, halts, reverses, repeat //As in Fire Temple boulder maze @@ -2150,21 +2168,21 @@ ROTZ 0x0001 = Behavior after colliding with Link - Sparkling blue rupee - Huge Magenta Rupee, explodes when touched //Unused - Blue, red, and orange rupees, explode when touched //Unused - Random-colored rupees, collectible - Green rupees underground, not collectible //Unused + Sparkling blue rupee + Huge Magenta Rupee, explodes when touched //Unused + Blue, red, and orange rupees, explode when touched //Unused + Random-colored rupees, collectible + Green rupees underground, not collectible //Unused - Ichiro //Red/Purple Pants, "normal" hair - Sabooro //Light-Blue Pants - Jiro //Green Pants - Shiro //Pink/Purple Pants, two-spiked hair + Ichiro //Red/Purple Pants, "normal" hair + Sabooro //Light-Blue Pants + Jiro //Green Pants + Shiro //Pink/Purple Pants, two-spiked hair @@ -2181,12 +2199,12 @@ ROTZ 0x0001 = Behavior after colliding with Link - Shoos you away //Calls you a kid regardless of your actual age - Gate Manager (Gerudo Fortress) - Generic Guard (Gerudo Fortress) - Stands By Cow (Gerudo Valley) - Horseback Archery - Gerudo Training Grounds Guard + Shoos you away //Calls you a kid regardless of your actual age + Gate Manager (Gerudo Fortress) + Generic Guard (Gerudo Fortress) + Stands By Cow (Gerudo Valley) + Horseback Archery + Gerudo Training Grounds Guard +0x3F00 = Switch Flag @@ -2200,8 +2218,8 @@ ROTZ 0x0001 = Behavior after colliding with Link - Cutscene start - No cutscene //required if you spawn more than four or five of these + Cutscene start + No cutscene //required if you spawn more than four or five of these @@ -2213,130 +2231,130 @@ ROTZ 0x0001 = Behavior after colliding with Link - Default + Default - Default + Default Text ID 10B1 when sleeping - Standard - Cutscene Gate, Left Part - Cutscene Gate, Right Part + Standard + Cutscene Gate, Left Part + Cutscene Gate, Right Part - X - Hyrule Field - Hyrule Castle Town - The Temple of Time - Dead End - Kakariko Village / Death Mountain Trail / Starting Point - Kakariko Village Graveyard - Dark! Narrow! Scary! / Well of Three Features - Death Mountain / No passage without a / Royal Decree! - Death Mountain Trail - Dodongo's Cavern / Don't enter without permission! - Land of the Gorons / Goron City - Zora's River / Watch out for swift current / and strong undertow. - The Shadow will yield only to one / with the eye of truth, handed / down in Kakariko Village. - Zora's Domain - Zora's Fountain / Don't disturb Lord Jabu-Jabu! / –King Zora XVI - Forest Training Center / Don't recklessly cut signs– / read them carefully! - All those reckless enough to / venture into the desert–please drop by our shop. / Carpet Merchant - Just ahead: / Great Deku Tree's Meadow - Forest Temple - The Lost Woods - Talon and Malon's / Lon Lon Ranch - The Great Ingo's / Ingo Ranch - Lake Hylia - Lakeside Laboratory / Daily trying to get to the bottom / of the mysteries of Lake Hylia! / –Lake Scientist - Gerudo Valley - Horseback Archery Range / Skilled players are welcome! / Current record: # Points - Gerudo Training Ground / Only registered members are / allowed! - Haunted Wasteland / If you chase a mirage, the / desert will swallow you. / Only one path is true! - Spirit Temple - Kokiri Shop / We have original forest goods! - LINK's House - Forest folk shall not leave these woods. - Follow the trail along the edge of / the cliff and you will reach / Goron City, home of the Gorons. - Natural Wonder / Bomb Flower / Danger! Do not uproot! - Death Mountain Summit / Entrance to the crater ahead / Beware of intense heat! - King Zora's Throne Room / To hear the King's royal / proclamations, stand on the / platform and speak to him. - If you can stop my wild rolling, you might get something great. / –Hot Rodder Goron - Only one with the eye of truth / will find the stone umbrella / that protects against the / rain of blades. - Only one who has sacred feet / can cross the valley of the dead. - The record time of those / who raced against me was: / ##"##" / –Dampé the Gravekeeper - Shooting Gallery / etc. - Treasure Chest Shop / We don't necessarily sell them... - High Dive Practice Spot / Are you confident / in your diving skill? - 032c - Mountain Summit / Danger Ahead - Keep Out - Happy Mask Shop! / Now hiring happiness / delivery men! - Bombchu Bowling Alley / You can experience the / latest in Bomb technology! - Bazaar / We have a little bit of everything! - Potion Shop / We have the best quality / potions! - Goron Shop / Mountaineering supplies! - Zora Shop / We have fresh fish! - Heart-Pounding Gravedigging Tour! / From 18:00 to 21:00 Hyrule Time / –Dampé the Gravekeeper - Heart-Pounding Gravedigging Tour! / Tours are cancelled until a new / gravekeeper is found. We / apologize for any inconvenience. - Thrust Attack Signs! / To thrust with your sword, press / CS toward your target while / Z Targeting, then press B. - Hole of “Z” / Let's go through this small / hole! / Stand in front of the hole and / push CS towards it. When the / Action Icon shows “Enter,” press / A to crawl into the hole. / Pay attention to what the Action / Icon says! - Cut Grass With Your Sword / If you just swing with B, you'll / cut horizontally. If you hold Z as / you swing, you'll cut vertically. - Hyrule Castle / Lon Lon Ranch - You are here: Hyrule Castle / This way to Lon Lon Ranch - Just Ahead / King Zora's Chamber / Show the proper respect! - House of the Great Mido / Boss of the Kokiri - House of the Know-It-All Brothers - House of Twins - Saria's House - View Point with Z Targeting / When you have no object to look / at, you can just look forward / with Z. / Stop moving and then change the / direction you are facing, or hold / down Z for a little while. / This can help you get oriented in / the direction you want to face. / It's quite convenient! / If you hold down Z, you can / walk sideways while facing / straight ahead. / Walking sideways can be a very / important technique in dungeon / corridors. Turn around and try doing this right now. - Stepping Stones in the Pond / If you boldly go in the direction / you want to jump, you will leap / automatically. / If you hop around on the stones, / you'll become happier! - No Diving Allowed / –It won't do you any good! - Switch Targeting / If you see a \/ icon above an / object, you can target it with Z. / ... / You can target the stones next to this sign for practice! - Forest Stage / We are waiting to see your / beautiful face! / Win fabulous prizes! - Visit the / House of the Know-It-All Brothers / to get answers to all your / item-related questions! - Pocket Egg + X + Hyrule Field + Hyrule Castle Town + The Temple of Time + Dead End + Kakariko Village / Death Mountain Trail / Starting Point + Kakariko Village Graveyard + Dark! Narrow! Scary! / Well of Three Features + Death Mountain / No passage without a / Royal Decree! + Death Mountain Trail + Dodongo's Cavern / Don't enter without permission! + Land of the Gorons / Goron City + Zora's River / Watch out for swift current / and strong undertow. + The Shadow will yield only to one / with the eye of truth, handed / down in Kakariko Village. + Zora's Domain + Zora's Fountain / Don't disturb Lord Jabu-Jabu! / –King Zora XVI + Forest Training Center / Don't recklessly cut signs– / read them carefully! + All those reckless enough to / venture into the desert–please drop by our shop. / Carpet Merchant + Just ahead: / Great Deku Tree's Meadow + Forest Temple + The Lost Woods + Talon and Malon's / Lon Lon Ranch + The Great Ingo's / Ingo Ranch + Lake Hylia + Lakeside Laboratory / Daily trying to get to the bottom / of the mysteries of Lake Hylia! / –Lake Scientist + Gerudo Valley + Horseback Archery Range / Skilled players are welcome! / Current record: # Points + Gerudo Training Ground / Only registered members are / allowed! + Haunted Wasteland / If you chase a mirage, the / desert will swallow you. / Only one path is true! + Spirit Temple + Kokiri Shop / We have original forest goods! + LINK's House + Forest folk shall not leave these woods. + Follow the trail along the edge of / the cliff and you will reach / Goron City, home of the Gorons. + Natural Wonder / Bomb Flower / Danger! Do not uproot! + Death Mountain Summit / Entrance to the crater ahead / Beware of intense heat! + King Zora's Throne Room / To hear the King's royal / proclamations, stand on the / platform and speak to him. + If you can stop my wild rolling, you might get something great. / –Hot Rodder Goron + Only one with the eye of truth / will find the stone umbrella / that protects against the / rain of blades. + Only one who has sacred feet / can cross the valley of the dead. + The record time of those / who raced against me was: / ##"##" / –Dampé the Gravekeeper + Shooting Gallery / etc. + Treasure Chest Shop / We don't necessarily sell them... + High Dive Practice Spot / Are you confident / in your diving skill? + 032c + Mountain Summit / Danger Ahead - Keep Out + Happy Mask Shop! / Now hiring happiness / delivery men! + Bombchu Bowling Alley / You can experience the / latest in Bomb technology! + Bazaar / We have a little bit of everything! + Potion Shop / We have the best quality / potions! + Goron Shop / Mountaineering supplies! + Zora Shop / We have fresh fish! + Heart-Pounding Gravedigging Tour! / From 18:00 to 21:00 Hyrule Time / –Dampé the Gravekeeper + Heart-Pounding Gravedigging Tour! / Tours are cancelled until a new / gravekeeper is found. We / apologize for any inconvenience. + Thrust Attack Signs! / To thrust with your sword, press / CS toward your target while / Z Targeting, then press B. + Hole of “Z” / Let's go through this small / hole! / Stand in front of the hole and / push CS towards it. When the / Action Icon shows “Enter,” press / A to crawl into the hole. / Pay attention to what the Action / Icon says! + Cut Grass With Your Sword / If you just swing with B, you'll / cut horizontally. If you hold Z as / you swing, you'll cut vertically. + Hyrule Castle / Lon Lon Ranch + You are here: Hyrule Castle / This way to Lon Lon Ranch + Just Ahead / King Zora's Chamber / Show the proper respect! + House of the Great Mido / Boss of the Kokiri + House of the Know-It-All Brothers + House of Twins + Saria's House + View Point with Z Targeting / When you have no object to look / at, you can just look forward / with Z. / Stop moving and then change the / direction you are facing, or hold / down Z for a little while. / This can help you get oriented in / the direction you want to face. / It's quite convenient! / If you hold down Z, you can / walk sideways while facing / straight ahead. / Walking sideways can be a very / important technique in dungeon / corridors. Turn around and try doing this right now. + Stepping Stones in the Pond / If you boldly go in the direction / you want to jump, you will leap / automatically. / If you hop around on the stones, / you'll become happier! + No Diving Allowed / –It won't do you any good! + Switch Targeting / If you see a \/ icon above an / object, you can target it with Z. / ... / You can target the stones next to this sign for practice! + Forest Stage / We are waiting to see your / beautiful face! / Win fabulous prizes! + Visit the / House of the Know-It-All Brothers / to get answers to all your / item-related questions! + Pocket Egg Message ID //Value + 0x0300 - Whistleblower - Stands there, does nothing + Whistleblower + Stands there, does nothing - Non-solid cucco, hops oddly every once in awhile and only goes in one direction - Invisible, solid cucco, doesn't move, can be attacked but will only smoke and molt - Invisible cucco, cannot be attacked it seems, no idea what it does, but you can hear it + Non-solid cucco, hops oddly every once in awhile and only goes in one direction + Invisible, solid cucco, doesn't move, can be attacked but will only smoke and molt + Invisible cucco, cannot be attacked it seems, no idea what it does, but you can hear it - Default + Default - Default + Default - Temple of Time stone altar dialog - Gravekeeper's diary dialog //Navi hovers higher than normal - Royal Composer Sharp's grave dialog //Use Object 006E, Sets Temporary Switch Flag 09, spawns Sharp - "Royal Family Tomb" dialog - Royal Composer Flat's grave dialog //Use Object 006E, Sets Temporary Switch Flag 08, spawns Flat + Temple of Time stone altar dialog + Gravekeeper's diary dialog //Navi hovers higher than normal + Royal Composer Sharp's grave dialog //Use Object 006E, Sets Temporary Switch Flag 09, spawns Sharp + "Royal Family Tomb" dialog + Royal Composer Flat's grave dialog //Use Object 006E, Sets Temporary Switch Flag 08, spawns Flat +0x3F = Switch Flag //Spot deactivates when flag is set @@ -2353,28 +2371,28 @@ ROTZ 0x0001 = Behavior after colliding with Link - Does nothing - Outside of Kokiri Forest exit, auto talks - Near Hyrule Castle, auto talks - In front of Kakariko Village, auto talks - Between Lake Hylia and Gerudo Valley, auto talks - In front of Lake Hylia, auto talks - Nothing - Lake Hylia, manual talk, talon grab shortcut - Death Mountain summit, manual talk, talon grab shortcut - Death Mountain summit, manual talk, talon grab shortcut - Desert Colossus, auto talks - Lost Woods, before meeting Saria, auto talks - Lost Woods, after meeting Saria, auto talks - Outside of Kokiri Forest exit, auto talks, Head position alternates? + Does nothing + Outside of Kokiri Forest exit, auto talks + Near Hyrule Castle, auto talks + In front of Kakariko Village, auto talks + Between Lake Hylia and Gerudo Valley, auto talks + In front of Lake Hylia, auto talks + Nothing + Lake Hylia, manual talk, talon grab shortcut + Death Mountain summit, manual talk, talon grab shortcut + Death Mountain summit, manual talk, talon grab shortcut + Desert Colossus, auto talks + Lost Woods, before meeting Saria, auto talks + Lost Woods, after meeting Saria, auto talks + Outside of Kokiri Forest exit, auto talks, Head position alternates? +0x3F = Switch Flag - Small rock, random drops - Large light-gray rock, can't pick up as Young Link, no drop + Small rock, random drops + Large light-gray rock, can't pick up as Young Link, no drop @@ -2389,18 +2407,18 @@ ROTZ 0x0001 = Behavior after colliding with Link - Flower for grave - Non-liftable small rock - Uncuttable small shrub - Erratic collision data + Flower for grave + Non-liftable small rock + Uncuttable small shrub + Erratic collision data - Stays On - On/Off Toggle - Activated while enlightened - Burns + Stays On + On/Off Toggle + Activated while enlightened + Burns @@ -2408,25 +2426,25 @@ ROTZ 0x0001 = Behavior after colliding with Link - Circle of shrubs with one in the middle - Scattered shrubs - Circle of rocks + Circle of shrubs with one in the middle + Scattered shrubs + Circle of rocks +0xFF00 = Random Drop Table - Link the Goron - Fire Temple Generic - DMT DC Entrance - DMT Rolling - DMT Near Bomb Flower - Goron City Entrance - Goron City Island - Goron City Lost Woods - Unused - Biggoron + Link the Goron + Fire Temple Generic + DMT DC Entrance + DMT Rolling + DMT Near Bomb Flower + Goron City Entrance + Goron City Island + Goron City Lost Woods + Unused + Biggoron @@ -2482,8 +2500,8 @@ ROTZ 0x0001 = Behavior after colliding with Link - Tall and narrow - Short and wide + Tall and narrow + Short and wide @@ -2491,19 +2509,19 @@ ROTZ 0x0001 = Behavior after colliding with Link - Standing boy lifting a rock - Standing girl near Fado - Boxing boy - Blocking boy - Backflipping boy - Sitting girl on Shop - Standing girl near Mido's House - Know-It-All Bro teaching about HUD icons - Know-It-All Bro teaching about map and items - Sitting girl in house - Standing girl in Shop - Know-It-All Bro teaching about C-Up - Fado + Standing boy lifting a rock + Standing girl near Fado + Boxing boy + Blocking boy + Backflipping boy + Sitting girl on Shop + Standing girl near Mido's House + Know-It-All Bro teaching about HUD icons + Know-It-All Bro teaching about map and items + Sitting girl in house + Standing girl in Shop + Know-It-All Bro teaching about C-Up + Fado @@ -2512,14 +2530,14 @@ ROTZ 0x0001 = Behavior after colliding with Link - Cloudy Market - Cloudy Ranch - Snowy Zora's Domain - Rainy Lake Hylia - Cloudy Death Mountain - Thunderstrorm Kakariko - Sandstorm Intensity - Thunderstrorm Graveyard + Cloudy Market + Cloudy Ranch + Snowy Zora's Domain + Rainy Lake Hylia + Cloudy Death Mountain + Thunderstrorm Kakariko + Sandstorm Intensity + Thunderstrorm Graveyard @@ -2530,32 +2548,32 @@ ROTZ 0x0001 = Behavior after colliding with Link - Bomb Bag (Bombchu Bowling given prize) - Heart Piece (Bombchu Bowling given prize) - Bombchus (Bombchu Bowling given prize) - Bombs (Bombchu Bowling given prize) - Purple Rupee (Bombchu Bowling given prize) - Bomb Bag (Bombchu Bowing prize preview) - Heart Piece (Bombchu Bowing prize preview) - Bombchus (Bombchu Bowing prize preview) - Bombs (Bombchu Bowing prize preview) - Purple Rupee (Bombchu Bowing prize preview) - Green Rupee (Chest Game) - Blue Rupee (Chest Game) - Red Rupee (Chest Game) - Purple Rupee (Unused Chest Game Rupee) - Small Key (Chest Game) - Din's Fire - Farore's Wind - Nayru's Love - Bullet Bag + Bomb Bag (Bombchu Bowling given prize) + Heart Piece (Bombchu Bowling given prize) + Bombchus (Bombchu Bowling given prize) + Bombs (Bombchu Bowling given prize) + Purple Rupee (Bombchu Bowling given prize) + Bomb Bag (Bombchu Bowing prize preview) + Heart Piece (Bombchu Bowing prize preview) + Bombchus (Bombchu Bowing prize preview) + Bombs (Bombchu Bowing prize preview) + Purple Rupee (Bombchu Bowing prize preview) + Green Rupee (Chest Game) + Blue Rupee (Chest Game) + Red Rupee (Chest Game) + Purple Rupee (Unused Chest Game Rupee) + Small Key (Chest Game) + Din's Fire + Farore's Wind + Nayru's Love + Bullet Bag Each type needs its own object to load - Brick pillar - Brick throne + Brick pillar + Brick throne @@ -2568,31 +2586,31 @@ ROTZ 0x0001 = Behavior after colliding with Link - Blocking Deku Tree + Blocking Deku Tree - Richard's Owner // Use object 0105, text ID 079D - Woman in white, blues and yellow near Apothicary // Use object 018C, text ID 7016 first, then 7017 - Bearded man in white and green near Bazaar // Use object 0107, text ID 701A - Sakon (Jogging Man) // Use object 0111, needs pathway, text ID 7002 - Staunch man in black and green // Use object 0107, text ID 7023 first, then 7024 - Begging man // Use object 0111 // Use object 0111, buy things in bottles, text ID 70ED and followings - Old woman in white // Use object 010D, text ID 7021 first, then 7022 - Old man in blue near Bombchu Bowling // Use object 010C, text ID 7027 first, then 7028 - Woman in lilac near Bombchu Bowling // Use object 0108, text ID 701D first, then 701E - Laughing man in red and white // Use object 0111, text ID 701F first, then 7020 - Explaining man in blue and white // Use object 0111, text ID 7018 first, then 7019 - 'Dancing' woman in blue and yellow near Archery Game // Use object 0108, text ID 7014 - Watchtower man in crimson // Use object 0111, text ID 7015 - Red haired man in green and lilac // Use object 0107, text ID 7055 - Bearded, red haired man in green and white // Use object 0111, text ID 7089 - Old bald man in brown // Use object 010C, text ID 708A - Man in white // Use object 0111, text ID 700E - Man from Impa's House // Use object 0107, text ID 505B first, then 505C - Old bald man in purple // Use object 010C - Man in two shades of green // Use object 0107 + Richard's Owner // Use object 0105, text ID 079D + Woman in white, blues and yellow near Apothicary // Use object 018C, text ID 7016 first, then 7017 + Bearded man in white and green near Bazaar // Use object 0107, text ID 701A + Sakon (Jogging Man) // Use object 0111, needs pathway, text ID 7002 + Staunch man in black and green // Use object 0107, text ID 7023 first, then 7024 + Begging man // Use object 0111 // Use object 0111, buy things in bottles, text ID 70ED and followings + Old woman in white // Use object 010D, text ID 7021 first, then 7022 + Old man in blue near Bombchu Bowling // Use object 010C, text ID 7027 first, then 7028 + Woman in lilac near Bombchu Bowling // Use object 0108, text ID 701D first, then 701E + Laughing man in red and white // Use object 0111, text ID 701F first, then 7020 + Explaining man in blue and white // Use object 0111, text ID 7018 first, then 7019 + 'Dancing' woman in blue and yellow near Archery Game // Use object 0108, text ID 7014 + Watchtower man in crimson // Use object 0111, text ID 7015 + Red haired man in green and lilac // Use object 0107, text ID 7055 + Bearded, red haired man in green and white // Use object 0111, text ID 7089 + Old bald man in brown // Use object 010C, text ID 708A + Man in white // Use object 0111, text ID 700E + Man from Impa's House // Use object 0107, text ID 505B first, then 505C + Old bald man in purple // Use object 010C + Man in two shades of green // Use object 0107 +0x780 = Path Id //NPCs 03 and 07 only @@ -2617,24 +2635,20 @@ ROTZ 0x0001 = Behavior after colliding with Link - Unknown - Unknown - Unknown - Unknown - Unknown - Unknown - Unknown - Unknown - Unknown - Unknown + Unknown + Unknown + Unknown + Unknown + Unknown + Unknown + Unknown + Unknown + Unknown + Unknown - - Big Poe - Normal poe, circles around you - - + @@ -2644,18 +2658,18 @@ ROTZ 0x0001 = Behavior after colliding with Link - Time teller - Stands by Impa's House, tells time - Dying guard in Market Town - Stands in Market Town at night + Time teller + Stands by Impa's House, tells time + Dying guard in Market Town + Stands in Market Town at night Text ID 5063, then 5064 - Zelda in Ganondorf Fight (used by game engine) - Zelda in Ganon Fight (used by game engine) - Zelda in Castle Collapse + Zelda in Ganondorf Fight (used by game engine) + Zelda in Ganon Fight (used by game engine) + Zelda in Castle Collapse @@ -2684,70 +2698,70 @@ ROTZ 0x0001 = Behavior after colliding with Link - Drunken Ingo // Use Object 00C0 - Drunken Talon // Use Object 0088 - Windmill man breakdancing // Use Object 0133 - Encouraging Kokiri Boy // Use Object 00FC - Encouraging Kokiri Girl // Use Object 00FD - White-haired man in blue // Use Object 010C - Black-bearded man in white and green // Use Object 0107 - Bushy-haired woman in red and black // Use Object 0115 - Little old lady // Use Object 010D - Carpenter Boss, Singing // Use Object 0121 - Carpenter, Singing // Use Object 0122 - Carpenter, Singing // Use Object 0122 - Carpenter, Singing // Use Object 0122 - Carpenter, Singing // Use Object 0122 - Kokiri Boy, Dancing // Use Object 00FC - Kokiri Girl, Dancing // Use Object 00FD - Gerudo, Line-dancing 1 // Use Object 0116 - Gerudo, Line-dancing 2 // Use Object 0116 - Gerudo, spikey-haired, Line-dancing // Use Object 0116 - Dancing Zora // Use Object 00FE - King Zora // Use Object 00FF - Mido, sitting // Use Object 00FB - Floating cucco // Use Object 0013 - Floating cucco 2 // Use Object 0013 - Walking cucco // Use Object 0013 - Cucco Lady // Use Object 0110 - Potion Shopkeeper // Use Object 0159 - Happy Mask Salesman // Use Object 013E - Fisherman // Use Object 015B - Bombchu Shopkeeper // Use Object 0165 - Dancing Goron // Use Object 00C9 - Belly slapping Goron // Use Object 00C9 - Biggoron, dancing // Use Object 00C9 - Medigoron, lying down // Use Object 00C9 - Singing Malon // Use Object 00D0 + Drunken Ingo // Use Object 00C0 + Drunken Talon // Use Object 0088 + Windmill man breakdancing // Use Object 0133 + Encouraging Kokiri Boy // Use Object 00FC + Encouraging Kokiri Girl // Use Object 00FD + White-haired man in blue // Use Object 010C + Black-bearded man in white and green // Use Object 0107 + Bushy-haired woman in red and black // Use Object 0115 + Little old lady // Use Object 010D + Carpenter Boss, Singing // Use Object 0121 + Carpenter, Singing // Use Object 0122 + Carpenter, Singing // Use Object 0122 + Carpenter, Singing // Use Object 0122 + Carpenter, Singing // Use Object 0122 + Kokiri Boy, Dancing // Use Object 00FC + Kokiri Girl, Dancing // Use Object 00FD + Gerudo, Line-dancing 1 // Use Object 0116 + Gerudo, Line-dancing 2 // Use Object 0116 + Gerudo, spikey-haired, Line-dancing // Use Object 0116 + Dancing Zora // Use Object 00FE + King Zora // Use Object 00FF + Mido, sitting // Use Object 00FB + Floating cucco // Use Object 0013 + Floating cucco 2 // Use Object 0013 + Walking cucco // Use Object 0013 + Cucco Lady // Use Object 0110 + Potion Shopkeeper // Use Object 0159 + Happy Mask Salesman // Use Object 013E + Fisherman // Use Object 015B + Bombchu Shopkeeper // Use Object 0165 + Dancing Goron // Use Object 00C9 + Belly slapping Goron // Use Object 00C9 + Biggoron, dancing // Use Object 00C9 + Medigoron, lying down // Use Object 00C9 + Singing Malon // Use Object 00D0 Each variable requires it's own object - Lake Hylia's Sun Hitbox - Big Fairy, spawns with Sun's Song - Big Fairy, spawns with Song of Storms + Lake Hylia's Sun Hitbox + Big Fairy, spawns with Sun's Song + Big Fairy, spawns with Song of Storms - Pink spiral beam - Green spiral beam - Purple spiral beam - Blue spiral beam + Pink spiral beam + Green spiral beam + Purple spiral beam + Blue spiral beam + Black spiral beam - Black and green spiral beam - Gray and green spiral beam - Light blue spiral beam - Light purple spiral beam + Black and green spiral beam + Gray and green spiral beam + Light blue spiral beam + Light purple spiral beam - Checkable, Sets Switch - Instant Text - Checkable, Disappears on Switch - Z-Target, No Text + Checkable, Sets Switch + Instant Text + Checkable, Disappears on Switch + Z-Target, No Text @@ -2818,9 +2832,9 @@ ROTZ 0x0001 = Behavior after colliding with Link - Turns around, can't move, whistle-blower - Won't turn around, can't move, whistle-blower - Purple Gerudo, acts like the one that gives you the membership card + Turns around, can't move, whistle-blower + Won't turn around, can't move, whistle-blower + Purple Gerudo, acts like the one that gives you the membership card @@ -2833,57 +2847,57 @@ ROTZ 0x0001 = Behavior after colliding with Link - Main Hyliantula //(gold skulltulas lower than 100) - Hyliantula without an arm //(gold skulltulas lower than 10) - Hyliantula without an arm //(gold skulltulas lower than 20) - Hyliantula without an arm //(gold skulltulas lower than 30) - Hyliantula without an arm //(gold skulltulas lower than 40) - Hyliantula without an arm //(gold skulltulas lower than 50) - Hyliantula without an arm //(gold skulltulas lower than 60) - Hyliantula without an arm //(gold skulltulas lower than 70) - Hyliantula without an arm //(gold skulltulas lower than 80) - Hyliantula without an arm //(gold skulltulas lower than 90) - Hyliantula without an arm //(gold skulltulas lower than 100) - Hyliantula without an arm //(gold skulltulas lower than 110) + Main Hyliantula //(gold skulltulas lower than 100) + Hyliantula without an arm //(gold skulltulas lower than 10) + Hyliantula without an arm //(gold skulltulas lower than 20) + Hyliantula without an arm //(gold skulltulas lower than 30) + Hyliantula without an arm //(gold skulltulas lower than 40) + Hyliantula without an arm //(gold skulltulas lower than 50) + Hyliantula without an arm //(gold skulltulas lower than 60) + Hyliantula without an arm //(gold skulltulas lower than 70) + Hyliantula without an arm //(gold skulltulas lower than 80) + Hyliantula without an arm //(gold skulltulas lower than 90) + Hyliantula without an arm //(gold skulltulas lower than 100) + Hyliantula without an arm //(gold skulltulas lower than 110) - Main Hyliantula //(gold skulltulas lower than 100) - Hyliantula without an arm //(gold skulltulas lower than 10) - Hyliantula without an arm //(gold skulltulas lower than 20) - Hyliantula without an arm //(gold skulltulas lower than 30) - Hyliantula without an arm //(gold skulltulas lower than 40) - Hyliantula without an arm //(gold skulltulas lower than 50) - Hyliantula without an arm //(gold skulltulas lower than 60) - Hyliantula without an arm //(gold skulltulas lower than 70) - Hyliantula without an arm //(gold skulltulas lower than 80) - Hyliantula without an arm //(gold skulltulas lower than 90) - Hyliantula without an arm //(gold skulltulas lower than 100) - Hyliantula without an arm //(gold skulltulas lower than 110) + Main Hyliantula //(gold skulltulas lower than 100) + Hyliantula without an arm //(gold skulltulas lower than 10) + Hyliantula without an arm //(gold skulltulas lower than 20) + Hyliantula without an arm //(gold skulltulas lower than 30) + Hyliantula without an arm //(gold skulltulas lower than 40) + Hyliantula without an arm //(gold skulltulas lower than 50) + Hyliantula without an arm //(gold skulltulas lower than 60) + Hyliantula without an arm //(gold skulltulas lower than 70) + Hyliantula without an arm //(gold skulltulas lower than 80) + Hyliantula without an arm //(gold skulltulas lower than 90) + Hyliantula without an arm //(gold skulltulas lower than 100) + Hyliantula without an arm //(gold skulltulas lower than 110) - Purple wormhole - Blue wormhole + Purple wormhole + Blue wormhole - Regular effects, storm begins - Texture-spanning effect only, no storm, music isn't affected, effect does not dissipate + Regular effects, storm begins + Texture-spanning effect only, no storm, music isn't affected, effect does not dissipate - Default + Default - Large flat square floor tile, makes water noises when walking on it - Large vertical gate + Large flat square floor tile, makes water noises when walking on it + Large vertical gate +0x3F00 = Switch Flag //Type 01 only @@ -2894,9 +2908,9 @@ ROTZ 0x0001 = Behavior after colliding with Link - Chair Crumble - Pillar Crumble - Round stone thing, explodes as soon as area loads + Chair Crumble + Pillar Crumble + Round stone thing, explodes as soon as area loads @@ -2911,9 +2925,10 @@ ROTZ 0x0001 = Behavior after colliding with Link - Scrub on path to Deku Slingshot - 231/312 Hint scrub - Final Deku Scrub + (Invalid) + Scrub on path to Deku Slingshot + 231/312 Hint scrub + Final Deku Scrub @@ -2925,32 +2940,32 @@ ROTZ 0x0001 = Behavior after colliding with Link - Mad Scrubs - Hint Scrubs - Business Scrubs - Forest Stage Judge - Forest Stage Patron + Mad Scrubs + Hint Scrubs + Business Scrubs + Forest Stage Judge + Forest Stage Patron - Broken Drawbridge - Fences (Hyrule Field) + Broken Drawbridge + Fences (Hyrule Field) - Deku Nuts - Deku Sticks - Piece of Heart - Deku Seeds - Deku Shield - Bombs - Deku Seeds - Red Potion - Green Potion - Deku Stick Upgrade - Deku Nut Upgrade + Deku Nuts + Deku Sticks + Piece of Heart + Deku Seeds + Deku Shield + Bombs + Deku Seeds + Red Potion + Green Potion + Deku Stick Upgrade + Deku Nut Upgrade @@ -2973,22 +2988,22 @@ ROTZ 0x0001 = Behavior after colliding with Link - Dirty blond dog - Chocolate brown dog - Red dog - Multicolored, flashing dog - Red dog - Multicolored, flashing dog - Dark dog (black fur) - Green dog - Red dog - Purple dog - Red dog - Green dog - Green dog - Black dog - Black dog - Purple dog + Dirty blond dog + Chocolate brown dog + Red dog + Multicolored, flashing dog + Red dog + Multicolored, flashing dog + Dark dog (black fur) + Green dog + Red dog + Purple dog + Red dog + Green dog + Green dog + Black dog + Black dog + Purple dog @@ -3018,11 +3033,11 @@ ROTZ 0x0001 = Behavior after colliding with Link - Potion Shop Poster - Shooting Gallery Poster - Bazaar Poster - Shooting Gallery (Partially Complete) //Spawns Carpenter Sabooro (Kakariko) during the day - Shooting Gallery (Complete) + Potion Shop Poster + Shooting Gallery Poster + Bazaar Poster + Shooting Gallery (Partially Complete) //Spawns Carpenter Sabooro (Kakariko) during the day + Shooting Gallery (Complete) @@ -3045,7 +3060,7 @@ Z ROTATION +0x3F = Collectible Flag - Default + Default @@ -3053,7 +3068,7 @@ Z ROTATION +0x3F = Collectible Flag - Default + Default Yields deku seed upgrade @@ -3066,13 +3081,13 @@ Z ROTATION +0x3F = Collectible Flag - Magic Barrier - Blue Magic Core //Use with actor 00D2 (Adult Ruto), var 0002 - Yellow Magic Core //Use with actor 00A6 (Rauru), var 0002 - Red Magic Core //Use with actor 00A8 (Cutscene Darunia), var 0002 - Purple Magic Core //Use with actor 00A9 (Impa), var 0002 - Orange Magic Core //Use with actor 00C3 (Nabooru), var 0002 - Green Magic Core //Use with actor 00C9 (Cutscene Saria), var 0002 + Magic Barrier + Blue Magic Core //Use with actor 00D2 (Adult Ruto), var 0002 + Yellow Magic Core //Use with actor 00A6 (Rauru), var 0002 + Red Magic Core //Use with actor 00A8 (Cutscene Darunia), var 0002 + Purple Magic Core //Use with actor 00A9 (Impa), var 0002 + Orange Magic Core //Use with actor 00C3 (Nabooru), var 0002 + Green Magic Core //Use with actor 00C9 (Cutscene Saria), var 0002 @@ -3086,9 +3101,9 @@ Z ROTATION +0x3F = Collectible Flag - Five Blue Rupees stacked vertically - Five Green Rupees in a row - Six Green Rupees in a circle with a Red Rupee in the center + Five Blue Rupees stacked vertically + Five Green Rupees in a row + Six Green Rupees in a circle with a Red Rupee in the center @@ -3097,33 +3112,33 @@ Z ROTATION +0x3F = Collectible Flag - Blue/green textures - Green/brown textures - Green/red textures - Purple/red textures - Orange/red textures - Purple/black textures - Flashing purple/blue textures - Flashing purple/cyan/green textures, depends on movement of camera - Purple/red textures + Blue/green textures + Green/brown textures + Green/red textures + Purple/red textures + Orange/red textures + Purple/black textures + Flashing purple/blue textures + Flashing purple/cyan/green textures, depends on movement of camera + Purple/red textures - Big Rollin' Goron - Link the Goron - Biggoron - Generic Fire Temple Goron - Goron from DMT near a bomb flower - Rolling Goron from DMT - Goron near Dodongo's Cavern Entrance - Goron at the entrance of Goron City - Goron on the island from Goron City - Goron near Darunia's room - Goron in the stairwell in Goron City - Goron near Lost Woods - Goron talking about the Great Fairy in DMT - Goron in Market's Bazaar + Big Rollin' Goron + Link the Goron + Biggoron + Generic Fire Temple Goron + Goron from DMT near a bomb flower + Rolling Goron from DMT + Goron near Dodongo's Cavern Entrance + Goron at the entrance of Goron City + Goron on the island from Goron City + Goron near Darunia's room + Goron in the stairwell in Goron City + Goron near Lost Woods + Goron talking about the Great Fairy in DMT + Goron in Market's Bazaar @@ -3131,8 +3146,8 @@ Z ROTATION +0x3F = Collectible Flag - Normal - White Wolfos, mini-boss music starts + Normal + White Wolfos, mini-boss music starts +0xFF00 = Nullable Switch Flag @@ -3145,33 +3160,33 @@ Z ROTATION +0x3F = Collectible Flag - Around Arena, indestructible rubble - Rubble Pile 1 (where Ganondorf rises) - Rubble Pile 2 (where Ganondorf rises) - Rubble Pile 3 (where Ganondorf rises) - Rubble Pile 4 (where Ganondorf rises) - Rubble Pile 5 (where Ganondorf rises) - Rubble Pile 6 (where Ganondorf rises) - Rubble Pile 7 (where Ganondorf rises) - 'Sun' destructible rubble, drops collectible (draw depends on Ganon) - 'Wall' destructible rubble, drops collectible (draw depends on Ganon) - Tall destructible rubble, drops collectible (draw depends on Ganon) + Around Arena, indestructible rubble + Rubble Pile 1 (where Ganondorf rises) + Rubble Pile 2 (where Ganondorf rises) + Rubble Pile 3 (where Ganondorf rises) + Rubble Pile 4 (where Ganondorf rises) + Rubble Pile 5 (where Ganondorf rises) + Rubble Pile 6 (where Ganondorf rises) + Rubble Pile 7 (where Ganondorf rises) + 'Sun' destructible rubble, drops collectible (draw depends on Ganon) + 'Wall' destructible rubble, drops collectible (draw depends on Ganon) + Tall destructible rubble, drops collectible (draw depends on Ganon) - Large chunk - Medium chunk - Small chunk - Large chunk - Medium chunk - Small chunk - Large chunk - Medium chunk - Small chunk - Small chunk + Large chunk + Medium chunk + Small chunk + Large chunk + Medium chunk + Small chunk + Large chunk + Medium chunk + Small chunk + Small chunk non-solid, possibly Ganon's Tower rubble @@ -3180,9 +3195,9 @@ Z ROTATION +0x3F = Collectible Flag - Invisible Path - Glass Block, appears on Switch Flag - Invisible Timer + Invisible Path + Glass Block, appears on Switch Flag + Invisible Timer +0xFF00 = Nullable Switch Flag //If null, Enabled and ignoring switch flag input @@ -3198,17 +3213,17 @@ Z ROTATION +0x3F = Collectible Flag - Ceiling Web - Light Source (draws when web burned) - Light Floor (draws when web burned) + Ceiling Web + Light Source (draws when web burned) + Light Floor (draws when web burned) - Square Stone - Stone Brick - Similar to 1, but looks like a different texture + Square Stone + Stone Brick + Similar to 1, but looks like a different texture + Graphics glitchy @@ -3220,57 +3235,57 @@ Z ROTATION +0x3F = Collectible Flag - This is a Gossip Stone! - They say you can swim faster by continuously pressing B. - They say there is a secret near the lone tree which is not far from the river in the northwest part of Hyrule Field. - They say that there is a secret on the road that leads to Lake Hylia. - They say that Biggoron's Sword is super sharp and will never break. - They say that Medigoron didn't really think about his own size, so his store is really cramped. - They say that Malon set the original record in the obstacle course of Lon Lon Ranch. - They say that Malon of Lon Lon Ranch hopes a knight in shining armor will come and sweep her off her feet someday. - They say that Ruto, the Zora princess who is known for her selfish nature, likes a certain boy... - They say that players who select the “HOLD” option for “Z TARGETING” are the real “Zelda players!” - They say that there is a secret near a tree in Kakariko Village. - They say that, contrary to her elegant image, Princess Zelda of Hyrule Castle is, in fact, a tomboy! - They say that Princess Zelda's nanny is actually one of the Sheikah, who many thought had died out. - They say there is a man who can always be found running around in Hyrule Field. - They say that it is against the rules to use glasses at the Treasure Chest Shop in Hyrule Castle Town Market. - They say that the chicken lady goes to the Lakeside Laboratory to study how to breed pocket-sized Cuccos. - They say that Gerudos sometimes come to Hyrule Castle Town to look for boyfriends. - They say that the thief named Nabooru, who haunts this area, is a Gerudo. - They say that if you get close to a butterfly while holding a Deku Stick in your hands, something good will happen. - They say that you may find something new in dungeons that you have already finished. - They say that Gerudos worship Ganondorf almost like a god. - They say that there is a secret around the entrance to Gerudo Valley. - They say that the owl named Kaepora Gaebora is the reincarnation of an ancient Sage. - They say that strange owl, Kaepora Gaebora, may look big and heavy, but its character is rather lighthearted. - They say that the horse Ganondorf rides is a solid black Gerudo stallion. - They say that Ganondorf is not satisfied with ruling only the Gerudo and aims to conquer all of Hyrule! - They say that the treasure you can earn in the Gerudo's Training Ground is not as great as you would expect, given its difficulty! - They say that there is a switch that you can activate only by using the Spin Attack. - They say that it's possible to find a total of 100 Gold Skulltulas throughout Hyrule. - They say that when non-fairy folk enter the Lost Woods, they become monsters! - They say that the small holes in the ground that you can find all over Hyrule make perfect breeding ground for bugs. - They say that the Kokiri are always followed by small fairies. - They say that one Kokiri has left the forest, but he is still alive! + This is a Gossip Stone! + They say you can swim faster by continuously pressing B. + They say there is a secret near the lone tree which is not far from the river in the northwest part of Hyrule Field. + They say that there is a secret on the road that leads to Lake Hylia. + They say that Biggoron's Sword is super sharp and will never break. + They say that Medigoron didn't really think about his own size, so his store is really cramped. + They say that Malon set the original record in the obstacle course of Lon Lon Ranch. + They say that Malon of Lon Lon Ranch hopes a knight in shining armor will come and sweep her off her feet someday. + They say that Ruto, the Zora princess who is known for her selfish nature, likes a certain boy... + They say that players who select the “HOLD” option for “Z TARGETING” are the real “Zelda players!” + They say that there is a secret near a tree in Kakariko Village. + They say that, contrary to her elegant image, Princess Zelda of Hyrule Castle is, in fact, a tomboy! + They say that Princess Zelda's nanny is actually one of the Sheikah, who many thought had died out. + They say there is a man who can always be found running around in Hyrule Field. + They say that it is against the rules to use glasses at the Treasure Chest Shop in Hyrule Castle Town Market. + They say that the chicken lady goes to the Lakeside Laboratory to study how to breed pocket-sized Cuccos. + They say that Gerudos sometimes come to Hyrule Castle Town to look for boyfriends. + They say that the thief named Nabooru, who haunts this area, is a Gerudo. + They say that if you get close to a butterfly while holding a Deku Stick in your hands, something good will happen. + They say that you may find something new in dungeons that you have already finished. + They say that Gerudos worship Ganondorf almost like a god. + They say that there is a secret around the entrance to Gerudo Valley. + They say that the owl named Kaepora Gaebora is the reincarnation of an ancient Sage. + They say that strange owl, Kaepora Gaebora, may look big and heavy, but its character is rather lighthearted. + They say that the horse Ganondorf rides is a solid black Gerudo stallion. + They say that Ganondorf is not satisfied with ruling only the Gerudo and aims to conquer all of Hyrule! + They say that the treasure you can earn in the Gerudo's Training Ground is not as great as you would expect, given its difficulty! + They say that there is a switch that you can activate only by using the Spin Attack. + They say that it's possible to find a total of 100 Gold Skulltulas throughout Hyrule. + They say that when non-fairy folk enter the Lost Woods, they become monsters! + They say that the small holes in the ground that you can find all over Hyrule make perfect breeding ground for bugs. + They say that the Kokiri are always followed by small fairies. + They say that one Kokiri has left the forest, but he is still alive! +0xFF00 Collectible Flag (fairy) - Floor - Cracked Wall - Unused - Stinger Room 1 - Stinger Room 2 + Floor + Cracked Wall + Unused + Stinger Room 1 + Stinger Room 2 - Vertical - Horizontal + Vertical + Horizontal + Invalid @@ -3280,10 +3295,10 @@ Z ROTATION +0x3F = Collectible Flag - Ichiro //Red/Purple Pants, "normal" hair - Sabooro //Light-blue Pants - Jiro //Green Pants - Shiro //Pink/Purple Pants, Two-Spiked Hair + Ichiro //Red/Purple Pants, "normal" hair + Sabooro //Light-blue Pants + Jiro //Green Pants + Shiro //Pink/Purple Pants, Two-Spiked Hair +0xFF00 = Path @@ -3291,14 +3306,14 @@ Z ROTATION +0x3F = Collectible Flag - First Wall - Second Wall + First Wall + Second Wall - First Wall - Second Wall + First Wall + Second Wall @@ -3311,11 +3326,11 @@ Z ROTATION +0x3F = Collectible Flag - Fake door - Debris - Debris - Debris - Debris + Fake door + Debris + Debris + Debris + Debris @@ -3331,24 +3346,24 @@ Z ROTATION +0x3F = Collectible Flag - Cow - Tail only + Cow + Tail only - Stalagmite (floor) - Stalactite (ceiling) //falls when Link is underneath - Regrowing Stalactite (ceiling) //falls when Link is underneath + Stalagmite (floor) + Stalactite (ceiling) //falls when Link is underneath + Regrowing Stalactite (ceiling) //falls when Link is underneath - - vertical, clear flag - vertical, switch softlock - horizontal, clear flag + + vertical, clear flag + vertical, switch softlock + horizontal, clear flag - + +0x3F00 switchflag @@ -3363,29 +3378,29 @@ Z ROTATION +0x3F = Collectible Flag - Scarecrow song effect? - purple + Scarecrow song effect? + purple - Circular piece of false stone wall //Visible, invisible with Lens of Truth - Square piece of false stone wall //Oriented horizontally + Circular piece of false stone wall //Visible, invisible with Lens of Truth + Square piece of false stone wall //Oriented horizontally - Zora near the ladder/grotto - Zora near the shop - Zora near the fishes - Zora near the Lake Hylia exit - Zora near the grotto platform - Zora between ladder and grotto platform - Zora near the Lakeside Laboratory - Zora near the Domain exit - Zora from Zora Shop + Zora near the ladder/grotto + Zora near the shop + Zora near the fishes + Zora near the Lake Hylia exit + Zora near the grotto platform + Zora between ladder and grotto platform + Zora near the Lakeside Laboratory + Zora near the Domain exit + Zora from Zora Shop @@ -3399,8 +3414,8 @@ Z ROTATION +0x3F = Collectible Flag - Child Visible - Adult Visible + Child Visible + Adult Visible @@ -3416,8 +3431,8 @@ Z ROTATION +0x3F = Collectible Flag - Tent, starts the race - Waiting in Lost Woods, ends the race + Tent, starts the race + Waiting in Lost Woods, ends the race @@ -3425,8 +3440,8 @@ Z ROTATION +0x3F = Collectible Flag - Invisible - Visible + Invisible + Visible diff --git a/fast64_internal/oot/exporter/room/header.py b/fast64_internal/oot/exporter/room/header.py index bcc275f73..7a8c122b5 100644 --- a/fast64_internal/oot/exporter/room/header.py +++ b/fast64_internal/oot/exporter/room/header.py @@ -6,6 +6,7 @@ from ...oot_utility import getObjectList from ...oot_constants import ootData from ...room.properties import OOTRoomHeaderProperty +from ...actor.properties import OOTActorProperty from ..utility import Utility from ..actor import Actor @@ -136,6 +137,23 @@ class RoomActors: name: str actorList: list[Actor] + @staticmethod + def get_rotation_values(actorProp: OOTActorProperty, blender_rot_values: list[int]): + # Figure out which rotation to export, Blender's or the override + custom = "_custom" if actorProp.actor_id == "Custom" else "" + rot_values = [getattr(actorProp, f"rot_{rot}{custom}") for rot in ["x", "y", "z"]] + export_rot_values = [f"DEG_TO_BINANG({(rot * (180 / 0x8000)):.3f})" for rot in blender_rot_values] + + if actorProp.actor_id == "Custom": + export_rot_values = rot_values if actorProp.rot_override else export_rot_values + else: + for i, rot in enumerate(["X", "Y", "Z"]): + if actorProp.is_rotation_used(f"{rot}Rot"): + export_rot_values[i] = rot_values[i] + + assert len(export_rot_values) == 3 + return export_rot_values + @staticmethod def new( name: str, @@ -148,7 +166,7 @@ def new( actorList: list[Actor] = [] actorObjList = getObjectList(sceneObj.children, "EMPTY", "Actor", parentObj=roomObj, room_index=room_index) for obj in actorObjList: - actorProp = obj.ootActorProperty + actorProp: OOTActorProperty = obj.ootActorProperty if not Utility.isCurrentHeaderValid(actorProp.headerSettings, headerIndex): continue @@ -157,30 +175,27 @@ def new( # any data loss as Blender saves the index of the element in the Actor list used for the EnumProperty # and not the identifier as defined by the first element of the tuple. Therefore, we need to check if # the current Actor has the ID `None` to avoid export issues. - if actorProp.actorID != "None": + if actorProp.actor_id != "None": pos, rot, _, _ = Utility.getConvertedTransform(transform, sceneObj, obj, True) actor = Actor() - if actorProp.actorID == "Custom": - actor.id = actorProp.actorIDCustom + if actorProp.actor_id == "Custom": + actor.id = actorProp.actor_id_custom else: - actor.id = actorProp.actorID + actor.id = actorProp.actor_id - if actorProp.rotOverride: - actor.rot = ", ".join([actorProp.rotOverrideX, actorProp.rotOverrideY, actorProp.rotOverrideZ]) - else: - actor.rot = ", ".join(f"DEG_TO_BINANG({(r * (180 / 0x8000)):.3f})" for r in rot) + actor.rot = ", ".join(RoomActors.get_rotation_values(actorProp, rot)) actor.name = ( - ootData.actorData.actorsByID[actorProp.actorID].name.replace( - f" - {actorProp.actorID.removeprefix('ACTOR_')}", "" + ootData.actorData.actorsByID[actorProp.actor_id].name.replace( + f" - {actorProp.actor_id.removeprefix('ACTOR_')}", "" ) - if actorProp.actorID != "Custom" + if actorProp.actor_id != "Custom" else "Custom Actor" ) actor.pos = pos - actor.params = actorProp.actorParam + actor.params = actorProp.params if actorProp.actor_id != "Custom" else actorProp.params_custom actorList.append(actor) return RoomActors(name, actorList) diff --git a/fast64_internal/oot/exporter/scene/actors.py b/fast64_internal/oot/exporter/scene/actors.py index 8f7735b6e..70b16f083 100644 --- a/fast64_internal/oot/exporter/scene/actors.py +++ b/fast64_internal/oot/exporter/scene/actors.py @@ -5,6 +5,7 @@ from ....utility import PluginError, CData, indent from ...oot_utility import getObjectList from ...oot_constants import ootData +from ...actor.properties import OOTActorProperty from ..utility import Utility from ..actor import Actor @@ -59,10 +60,8 @@ def new(name: str, sceneObj: Object, transform: Matrix, headerIndex: int): entries: list[TransitionActor] = [] for obj in actorObjList: transActorProp = obj.ootTransitionActorProperty - if ( - Utility.isCurrentHeaderValid(transActorProp.actor.headerSettings, headerIndex) - and transActorProp.actor.actorID != "None" - ): + actorProp: OOTActorProperty = transActorProp.actor + if Utility.isCurrentHeaderValid(actorProp.headerSettings, headerIndex) and actorProp.actor_id != "None": pos, rot, _, _ = Utility.getConvertedTransform(transform, sceneObj, obj, True) transActor = TransitionActor() @@ -76,22 +75,22 @@ def new(name: str, sceneObj: Object, transform: Matrix, headerIndex: int): front = (fromIndex, Utility.getPropValue(transActorProp, "cameraTransitionFront")) back = (toIndex, Utility.getPropValue(transActorProp, "cameraTransitionBack")) - if transActorProp.actor.actorID == "Custom": - transActor.id = transActorProp.actor.actorIDCustom + if actorProp.actor_id == "Custom": + transActor.id = actorProp.actor_id_custom else: - transActor.id = transActorProp.actor.actorID + transActor.id = actorProp.actor_id transActor.name = ( - ootData.actorData.actorsByID[transActorProp.actor.actorID].name.replace( - f" - {transActorProp.actor.actorID.removeprefix('ACTOR_')}", "" + ootData.actorData.actorsByID[actorProp.actor_id].name.replace( + f" - {actorProp.actor_id.removeprefix('ACTOR_')}", "" ) - if transActorProp.actor.actorID != "Custom" + if actorProp.actor_id != "Custom" else "Custom Actor" ) transActor.pos = pos transActor.rot = f"DEG_TO_BINANG({(rot[1] * (180 / 0x8000)):.3f})" # TODO: Correct axis? - transActor.params = transActorProp.actor.actorParam + transActor.params = actorProp.params if actorProp.actor_id != "Custom" else actorProp.params_custom transActor.roomFrom, transActor.cameraFront = front transActor.roomTo, transActor.cameraBack = back entries.append(transActor) @@ -145,25 +144,23 @@ def new(name: str, sceneObj: Object, transform: Matrix, headerIndex: int): actorObjList = getObjectList(sceneObj.children_recursive, "EMPTY", "Entrance") for obj in actorObjList: entranceProp = obj.ootEntranceProperty - if ( - Utility.isCurrentHeaderValid(entranceProp.actor.headerSettings, headerIndex) - and entranceProp.actor.actorID != "None" - ): + actorProp: OOTActorProperty = entranceProp.actor + if Utility.isCurrentHeaderValid(actorProp.headerSettings, headerIndex) and actorProp.actor_id != "None": pos, rot, _, _ = Utility.getConvertedTransform(transform, sceneObj, obj, True) entranceActor = EntranceActor() entranceActor.name = ( - ootData.actorData.actorsByID[entranceProp.actor.actorID].name.replace( - f" - {entranceProp.actor.actorID.removeprefix('ACTOR_')}", "" + ootData.actorData.actorsByID[actorProp.actor_id].name.replace( + f" - {actorProp.actor_id.removeprefix('ACTOR_')}", "" ) - if entranceProp.actor.actorID != "Custom" + if actorProp.actor_id != "Custom" else "Custom Actor" ) - entranceActor.id = "ACTOR_PLAYER" if not entranceProp.customActor else entranceProp.actor.actorIDCustom + entranceActor.id = "ACTOR_PLAYER" if not entranceProp.customActor else actorProp.actor_id_custom entranceActor.pos = pos entranceActor.rot = ", ".join(f"DEG_TO_BINANG({(r * (180 / 0x8000)):.3f})" for r in rot) - entranceActor.params = entranceProp.actor.actorParam + entranceActor.params = actorProp.params if not entranceProp.customActor else actorProp.params_custom if entranceProp.tiedRoom is not None: entranceActor.roomIndex = entranceProp.tiedRoom.ootRoomHeader.roomIndex else: diff --git a/fast64_internal/oot/importer/actor.py b/fast64_internal/oot/importer/actor.py index 557c2d646..266122215 100644 --- a/fast64_internal/oot/importer/actor.py +++ b/fast64_internal/oot/importer/actor.py @@ -34,8 +34,8 @@ def parseTransActorList( position = tuple([hexOrDecInt(value) for value in params[5:8]]) - rotY = getEvalParams(params[8]) if "DEG_TO_BINANG" in params[8] else params[8] - rotation = tuple([0, hexOrDecInt(rotY), 0]) + rot_y = getEvalParams(params[8]) if "DEG_TO_BINANG" in params[8] else params[8] + rotation = tuple([0, hexOrDecInt(rot_y), 0]) roomIndexFront = hexOrDecInt(params[0]) camFront = params[1] @@ -77,8 +77,11 @@ def parseTransActorList( setCustomProperty(transActorProp, "cameraTransitionBack", camBack, ootEnumCamTransition) actorProp = transActorProp.actor - setCustomProperty(actorProp, "actorID", actorID, ootData.actorData.ootEnumActorID) - actorProp.actorParam = actorParam + setCustomProperty(actorProp, "actor_id", actorID, ootData.actorData.ootEnumActorID) + if actorProp.actor_id != "Custom": + actorProp.params = actorParam + else: + actorProp.params_custom = actorParam handleActorWithRotAsParam(actorProp, actorID, rotation) unsetAllHeadersExceptSpecified(actorProp.headerSettings, headerIndex) @@ -154,8 +157,11 @@ def parseSpawnList( spawnProp.spawnIndex = spawnIndex spawnProp.customActor = actorID != "ACTOR_PLAYER" actorProp = spawnProp.actor - setCustomProperty(actorProp, "actorID", actorID, ootData.actorData.ootEnumActorID) - actorProp.actorParam = actorParam + setCustomProperty(actorProp, "actor_id", actorID, ootData.actorData.ootEnumActorID) + if actorProp.actor_id != "Custom": + actorProp.params = actorParam + else: + actorProp.params_custom = actorParam handleActorWithRotAsParam(actorProp, actorID, rotation) unsetAllHeadersExceptSpecified(actorProp.headerSettings, headerIndex) @@ -192,8 +198,11 @@ def parseActorList( actorObj.name = getDisplayNameFromActorID(actorID) actorProp = actorObj.ootActorProperty - setCustomProperty(actorProp, "actorID", actorID, ootData.actorData.ootEnumActorID) - actorProp.actorParam = actorParam + setCustomProperty(actorProp, "actor_id", actorID, ootData.actorData.ootEnumActorID) + if actorProp.actor_id != "Custom": + actorProp.params = actorParam + else: + actorProp.params_custom = actorParam handleActorWithRotAsParam(actorProp, actorID, rotation) unsetAllHeadersExceptSpecified(actorProp.headerSettings, headerIndex) diff --git a/fast64_internal/oot/importer/utility.py b/fast64_internal/oot/importer/utility.py index 8eb975813..ec435ac94 100644 --- a/fast64_internal/oot/importer/utility.py +++ b/fast64_internal/oot/importer/utility.py @@ -47,10 +47,15 @@ def getDisplayNameFromActorID(actorID: str): def handleActorWithRotAsParam(actorProp: OOTActorProperty, actorID: str, rotation: list[int]): if actorID in actorsWithRotAsParam: - actorProp.rotOverride = True - actorProp.rotOverrideX = hex(rotation[0]) - actorProp.rotOverrideY = hex(rotation[1]) - actorProp.rotOverrideZ = hex(rotation[2]) + if actorProp.actor_id != "Custom": + actorProp.rot_x = hex(rotation[0]) + actorProp.rot_y = hex(rotation[1]) + actorProp.rot_z = hex(rotation[2]) + else: + actorProp.rot_override = True + actorProp.rot_x_custom = hex(rotation[0]) + actorProp.rot_y_custom = hex(rotation[1]) + actorProp.rot_z_custom = hex(rotation[2]) def getDataMatch( diff --git a/fast64_internal/oot/oot_upgrade.py b/fast64_internal/oot/oot_upgrade.py index 75e3c4fb1..d575615c0 100644 --- a/fast64_internal/oot/oot_upgrade.py +++ b/fast64_internal/oot/oot_upgrade.py @@ -6,7 +6,7 @@ from bpy.types import Object, CollectionProperty from ..utility import PluginError from .data import OoT_ObjectData -from .oot_utility import getEvalParams +from .oot_utility import getEvalParams, get_actor_prop_from_obj from .oot_constants import ootData from .cutscene.constants import ootEnumCSMotionCamMode @@ -307,6 +307,61 @@ def upgradeCutsceneMotion(csMotionObj: Object): # Actors ##################################### def upgradeActors(actorObj: Object): + # parameters + actorProp = get_actor_prop_from_obj(actorObj) + isCustom = False + + if actorObj.ootEmptyType == "Entrance": + isCustom = actorObj.ootEntranceProperty.customActor + else: + if "actorID" in actorProp: + actorProp.actor_id = ootData.actorData.ootEnumActorID[actorProp["actorID"]][0] + del actorProp["actorID"] + + if "actorIDCustom" in actorProp: + actorProp.actor_id_custom = actorProp["actorIDCustom"] + del actorProp["actorIDCustom"] + + isCustom = actorProp.actor_id == "Custom" + + if "actorParam" in actorProp: + if not isCustom: + prop_name = "params" + + if getEvalParams(actorProp["actorParam"]) is None: + actorProp.actor_id_custom = actorProp.actor_id + actorProp.actor_id = "Custom" + prop_name = "params_custom" + else: + prop_name = "params_custom" + + setattr(actorProp, prop_name, actorProp["actorParam"]) + del actorProp["actorParam"] + + if actorObj.ootEmptyType == "Actor": + custom = "_custom" if actorProp.actor_id == "Custom" else "" + + if isCustom: + if "rotOverride" in actorProp: + actorProp.rot_override = actorProp["rotOverride"] + del actorProp["rotOverride"] + + for rot in {"X", "Y", "Z"}: + if actorProp.actor_id == "Custom" or actorProp.is_rotation_used(f"{rot}Rot"): + if f"rotOverride{rot}" in actorProp: + if getEvalParams(actorProp[f"rotOverride{rot}"]) is None: + custom = "_custom" + + if actorProp.actor_id != "Custom": + actorProp.actor_id_custom = actorProp.actor_id + actorProp.params_custom = actorProp.params + actorProp.actor_id = "Custom" + actorProp.rot_override = True + + setattr(actorProp, f"rot_{rot.lower()}{custom}", actorProp[f"rotOverride{rot}"]) + del actorProp[f"rotOverride{rot}"] + + # room stuff if actorObj.ootEmptyType == "Entrance": entranceProp = actorObj.ootEntranceProperty diff --git a/fast64_internal/oot/oot_utility.py b/fast64_internal/oot/oot_utility.py index 3173cc299..51793fcc3 100644 --- a/fast64_internal/oot/oot_utility.py +++ b/fast64_internal/oot/oot_utility.py @@ -3,7 +3,7 @@ import os import re -from ast import parse, Expression, Num, UnaryOp, USub, Invert, BinOp +from ast import parse, Expression, Constant, UnaryOp, USub, Invert, BinOp from mathutils import Vector from bpy.types import Object from bpy.utils import register_class, unregister_class @@ -28,6 +28,7 @@ if TYPE_CHECKING: from .scene.properties import OOTBootupSceneOptions + from .actor.properties import OOTActorProperty def isPathObject(obj: bpy.types.Object) -> bool: @@ -951,16 +952,16 @@ def onHeaderPropertyChange(self, context: bpy.types.Context, callback: Callable[ bpy.context.scene.ootActiveHeaderLock = False -def getEvalParams(input: str): +def getEvalParamsInt(input: str): """Evaluates a string to an hexadecimal number""" # degrees to binary angle conversion if "DEG_TO_BINANG(" in input: input = input.strip().removeprefix("DEG_TO_BINANG(").removesuffix(")").strip() - return f"0x{round(float(input) * (0x8000 / 180)):X}" + return round(float(input) * (0x8000 / 180)) if input is None or "None" in input: - return "0x0" + return 0 # remove spaces input = input.strip() @@ -970,10 +971,10 @@ def getEvalParams(input: str): except Exception as e: raise ValueError(f"Could not parse {input} as an AST.") from e - def _eval(node): + def _eval(node) -> int: if isinstance(node, Expression): return _eval(node.body) - elif isinstance(node, Num): + elif isinstance(node, Constant): return node.n elif isinstance(node, UnaryOp): if isinstance(node.op, USub): @@ -987,7 +988,40 @@ def _eval(node): else: raise ValueError(f"Unsupported AST node {node}") - return f"0x{_eval(node.body):X}" + try: + return _eval(node.body) + except: + return None + + +def getEvalParams(input: str): + num = getEvalParamsInt(input) + return f"0x{num:X}" if num is not None else None + + +def getShiftFromMask(mask: int): + """Returns the shift value from the mask""" + + # make sure the mask is a mask + binaryMask = f"{mask:016b}" + assert set(f"{mask:b}".rstrip("0")) == {"1"}, binaryMask + + # get the shift by subtracting the length of the mask + # converted in binary on 16 bits (since the mask can be on 16 bits) with + # that length but with the rightmost zeros stripped + return len(binaryMask) - len(binaryMask.rstrip("0")) + + +def getFormattedParams(mask: int, value: int, isBool: bool): + """Returns the parameter with the correct format""" + shift = getShiftFromMask(mask) + + if value == 0: + return None + elif not isBool: + return f"((0x{value:02X} << {shift}) & 0x{mask:04X})" if shift > 0 else f"(0x{value:02X} & 0x{mask:04X})" + else: + return f"(0x{value:02X} << {shift})" if shift > 0 else f"0x{value:02X}" def getNewPath(type: str, isClosedShape: bool): @@ -1100,3 +1134,25 @@ def getObjectList( ret.append(obj) ret.sort(key=lambda o: o.name) return ret + + +def get_actor_prop_from_obj(actor_obj: Object) -> "OOTActorProperty": + """ + Returns the reference to `OOTActorProperty` + + Parameters: + - `actor_obj`: the Blender object to use to find the actor properties + """ + + actor_prop = None + + if actor_obj.ootEmptyType == "Actor": + actor_prop = actor_obj.ootActorProperty + elif actor_obj.ootEmptyType == "Transition Actor": + actor_prop = actor_obj.ootTransitionActorProperty.actor + elif actor_obj.ootEmptyType == "Entrance": + actor_prop = actor_obj.ootEntranceProperty.actor + else: + raise PluginError(f"ERROR: Empty type not supported: {actor_obj.ootEmptyType}") + + return actor_prop diff --git a/fast64_internal/oot/props_panel_main.py b/fast64_internal/oot/props_panel_main.py index 3323825b3..331a54d04 100644 --- a/fast64_internal/oot/props_panel_main.py +++ b/fast64_internal/oot/props_panel_main.py @@ -135,7 +135,7 @@ def draw(self, context): if obj.ootEmptyType == "Actor": actorProp: OOTActorProperty = obj.ootActorProperty - actorProp.draw_props(box, altRoomProp, objName) + actorProp.draw_props(box, altRoomProp, obj) elif obj.ootEmptyType == "Transition Actor": transActorProp: OOTTransitionActorProperty = obj.ootTransitionActorProperty @@ -198,7 +198,7 @@ def upgrade_changed_props(): if obj.type == "EMPTY": if obj.ootEmptyType == "Room": OOTObjectProperty.upgrade_object(obj) - if obj.ootEmptyType in {"Entrance", "Transition Actor"}: + if obj.ootEmptyType in {"Actor", "Entrance", "Transition Actor"}: OOTActorProperty.upgrade_object(obj) if obj.ootEmptyType == "Cutscene": OOTCutsceneProperty.upgrade_object(obj) diff --git a/fast64_internal/oot/tools/operators.py b/fast64_internal/oot/tools/operators.py index 5b40e36c3..1e834fce3 100644 --- a/fast64_internal/oot/tools/operators.py +++ b/fast64_internal/oot/tools/operators.py @@ -54,8 +54,8 @@ def execute(self, context): emptyObj = context.view_layer.objects.active emptyObj.ootEmptyType = "Transition Actor" emptyObj.name = "Door Actor" - emptyObj.ootTransitionActorProperty.actor.actorID = "ACTOR_DOOR_SHUTTER" - emptyObj.ootTransitionActorProperty.actor.actorParam = "0x0000" + emptyObj.ootTransitionActorProperty.actor.actor_id = "ACTOR_DOOR_SHUTTER" + emptyObj.ootTransitionActorProperty.actor.params = "0x0000" parentObject(cubeObj, emptyObj) @@ -89,7 +89,7 @@ def execute(self, context): entranceObj = context.view_layer.objects.active entranceObj.ootEmptyType = "Entrance" entranceObj.name = "Entrance" - entranceObj.ootEntranceProperty.actor.actorParam = "0x0FFF" + entranceObj.ootEntranceProperty.actor.params = "0x0FFF" parentObject(planeObj, entranceObj) location += Vector([0, 0, 10])