From 3deae4995b069f606d4b1d2ee7e34c357474bf80 Mon Sep 17 00:00:00 2001 From: jesusyoshi54 Date: Fri, 23 Dec 2022 09:46:09 -0500 Subject: [PATCH] [SM64] Allow editing of group level segments on level export (#183) * added ability to export a segment for actor groups from level object * added ability for sm64 segment selector to have custom segment exports Co-authored-by: scut --- fast64_internal/sm64/sm64_constants.py | 31 ++++++++++++ fast64_internal/sm64/sm64_level_writer.py | 45 ++++++++++++++-- fast64_internal/sm64/sm64_objects.py | 62 +++++++++++++++++++++++ 3 files changed, 135 insertions(+), 3 deletions(-) diff --git a/fast64_internal/sm64/sm64_constants.py b/fast64_internal/sm64/sm64_constants.py index d49d08c71..c16864f10 100644 --- a/fast64_internal/sm64/sm64_constants.py +++ b/fast64_internal/sm64/sm64_constants.py @@ -1769,6 +1769,37 @@ def __init__(self, geoAddr, level, switchDict): ("macro_yellow_coin_2", "Yellow Coin 2", "Yellow Coin 2"), ] + +# groups you can select for levels +groupsSeg5 = [ + ("group1", "group1", "Ground objects (Thwomp, Heave-Ho, Hoot etc.)"), + ("group2", "group2", "Bully/Blargg"), + ("group3", "group3", "King Bob-Omb"), + ("group4", "group4", "Water Objects (Unagi, Manta, Clam)"), + ("group5", "group5", "Sand Objects (Pokey, Eyerock, klepto)"), + ("group6", "group6", "TTM Objects (Monty Mole, uUkiki, Fwoosh)"), + ("group7", "group7", "Snow Objects (Mr Blizzard, Spindrift etc.)"), + ("group8", "group8", "Cap Switch"), + ("group9", "group9", "Haunted Objects (Boo, Mad Piano etc.)"), + ("group10", "group10", "Peach/Yoshi"), + ("group11", "group11", "THI Ojbects (Lakitu, Wiggler, Bubba)"), + ("Do Not Write", "Do Not Write", "Do Not Write"), + ("Custom", "Custom", "Custom"), +] + + +groupsSeg6 = [ + ("group12", "group12", "Bowser/Bowser Bomb"), + ("group13", "group13", "Water Objects (Skeeter, Treasure Chest etc.)"), + ("group14", "group14", "Ground Objects (Piranha Plant, Chain Chomp etc.)"), + ("group15", "group15", "Castle Objects (MIPS, Toad etc.)"), + ("group16", "group16", "Ice Objects (Chill Bully, Moneybags)"), + ("group17", "group17", "Cave Objects (Swoop, Scuttlebug, Dorrie etc.)"), + ("Do Not Write", "Do Not Write", "Do Not Write"), + ("Custom", "Custom", "Custom"), +] + + marioAnimations = [ # ( Adress, "Animation name" ), ( 5162640, "0 - Climb up ledge (right leg going up)"), diff --git a/fast64_internal/sm64/sm64_level_writer.py b/fast64_internal/sm64/sm64_level_writer.py index 5c45210d2..3aa4bd83d 100644 --- a/fast64_internal/sm64/sm64_level_writer.py +++ b/fast64_internal/sm64/sm64_level_writer.py @@ -445,6 +445,29 @@ def replaceSegmentLoad(levelscript, segmentName, command, changedSegment): changedLoad[1][2] = segmentName + "SegmentRomEnd" +def replaceScriptLoads(levelscript, obj): + newFuncs = [] + for jumpLink in levelscript.levelFunctions: + target = jumpLink[1][0] # format is [macro, list[args], comment] + if "script_func_global_" not in target: + newFuncs.append(jumpLink) + continue + scriptNum = int(re.findall(r"\d+", target)[-1]) + # this is common0 + if scriptNum == 1: + newFuncs.append(jumpLink) + continue + if scriptNum < 13: + newNum = obj.fast64.sm64.segment_loads.group5 + else: + newNum = obj.fast64.sm64.segment_loads.group6 + if newNum == "Do Not Write": + newFuncs.append(jumpLink) + continue + newFuncs.append(["JUMP_LINK", [newNum], jumpLink[2]]) + levelscript.levelFunctions = newFuncs + + def stringToMacros(data): macroData = [] for matchResult in re.finditer("(\w*)\((((?!\)).)*)\),?(((?!\n)\s)*\/\/((?!\n).)*)?", data): @@ -813,9 +836,9 @@ def exportLevelC( # Generate levelscript string compressionFmt = bpy.context.scene.compressionFormat - replaceSegmentLoad(prevLevelScript, "_" + levelName + "_segment_7", "LOAD_" + compressionFmt.upper(), 0x07) + replaceSegmentLoad(prevLevelScript, f"_{levelName}_segment_7", f"LOAD_{compressionFmt.upper()}", 0x07) if usesEnvFX: - replaceSegmentLoad(prevLevelScript, "_effect_" + compressionFmt, "LOAD_" + compressionFmt.upper(), 0x0B) + replaceSegmentLoad(prevLevelScript, f"_effect_{compressionFmt}", f"LOAD_{compressionFmt.upper()}", 0x0B) if not obj.useBackgroundColor: segment = "" if obj.background == "CUSTOM": @@ -823,9 +846,25 @@ def exportLevelC( else: segment = backgroundSegments[obj.background] + "_skybox" + replaceSegmentLoad(prevLevelScript, f"_{segment}_{compressionFmt}", f"LOAD_{compressionFmt.upper()}", 0x0A) + # actor groups + if obj.fast64.sm64.segment_loads.seg5_enum != "Do Not Write": + replaceSegmentLoad( + prevLevelScript, + f"_{obj.fast64.sm64.segment_loads.seg5}_{compressionFmt}", + f"LOAD_{compressionFmt.upper()}", + 0x05, + ) + replaceSegmentLoad(prevLevelScript, f"_{obj.fast64.sm64.segment_loads.seg5}_geo", "LOAD_RAW", 0x0C) + if obj.fast64.sm64.segment_loads.seg6_enum != "Do Not Write": replaceSegmentLoad( - prevLevelScript, "_" + segment + "_" + compressionFmt, "LOAD_" + compressionFmt.upper(), 0x0A + prevLevelScript, + f"_{obj.fast64.sm64.segment_loads.seg6}_{compressionFmt}", + f"LOAD_{compressionFmt.upper()}", + 0x06, ) + replaceSegmentLoad(prevLevelScript, f"_{obj.fast64.sm64.segment_loads.seg6}_geo", "LOAD_RAW", 0x0D) + replaceScriptLoads(prevLevelScript, obj) levelscriptString = prevLevelScript.to_c(areaString) if bpy.context.scene.exportHiddenGeometry: diff --git a/fast64_internal/sm64/sm64_objects.py b/fast64_internal/sm64/sm64_objects.py index ab918060f..3329fc408 100644 --- a/fast64_internal/sm64/sm64_objects.py +++ b/fast64_internal/sm64/sm64_objects.py @@ -1,5 +1,6 @@ import math, bpy, mathutils from bpy.utils import register_class, unregister_class +from re import findall from .sm64_function_map import func_map from ..utility import ( @@ -22,6 +23,8 @@ enumMacrosNames, enumSpecialsNames, enumBehaviourPresets, + groupsSeg5, + groupsSeg6, ) from .sm64_spline import ( @@ -1256,6 +1259,8 @@ def draw(self, context): # box.box().label(text = 'Background IDs defined in include/geo_commands.h.') box.prop(obj, "actSelectorIgnore") box.prop(obj, "setAsStartLevel") + grid = box.grid_flow(columns=2) + obj.fast64.sm64.segment_loads.draw(grid) prop_split(box, obj, "acousticReach", "Acoustic Reach") obj.starGetCutscenes.draw(box) @@ -1826,6 +1831,61 @@ def get_behavior_params(self): return self.bparams +class SM64_SegmentProperties(bpy.types.PropertyGroup): + seg5_load_custom: bpy.props.StringProperty(name="Segment 5 Seg") + seg5_group_custom: bpy.props.StringProperty(name="Segment 5 Group") + seg6_load_custom: bpy.props.StringProperty(name="Segment 6 Seg") + seg6_group_custom: bpy.props.StringProperty(name="Segment 6 Group") + seg5_enum: bpy.props.EnumProperty(name="Segment 5 Group", default="Do Not Write", items=groupsSeg5) + seg6_enum: bpy.props.EnumProperty(name="Segment 6 Group", default="Do Not Write", items=groupsSeg6) + + def draw(self, layout): + col = layout.column() + prop_split(col, self, "seg5_enum", "Segment 5 Select") + if self.seg5_enum == "Custom": + prop_split(col, self, "seg5_load_custom", "Segment 5 Seg") + prop_split(col, self, "seg5_group_custom", "Segment 5 Group") + col = layout.column() + prop_split(col, self, "seg6_enum", "Segment 6 Select") + if self.seg6_enum == "Custom": + prop_split(col, self, "seg6_load_custom", "Segment 6 Seg") + prop_split(col, self, "seg6_group_custom", "Segment 6 Group") + + def jump_link_from_enum(self, grp): + if grp == "Do Not Write": + return grp + num = int(grp.removeprefix("group")) + 1 + return f"script_func_global_{num}" + + @property + def seg5(self): + if self.seg5_enum == "Custom": + return self.seg5_load_custom + else: + return self.seg5_enum + + @property + def seg6(self): + if self.seg6_enum == "Custom": + return self.seg6_load_custom + else: + return self.seg6_enum + + @property + def group5(self): + if self.seg5_enum == "Custom": + return self.seg5_group_custom + else: + return self.jump_link_from_enum(self.seg5_enum) + + @property + def group6(self): + if self.seg6_enum == "Custom": + return self.seg6_group_custom + else: + return self.jump_link_from_enum(self.seg6_enum) + + class SM64_ObjectProperties(bpy.types.PropertyGroup): version: bpy.props.IntProperty(name="SM64_ObjectProperties Version", default=0) cur_version = 3 # version after property migration @@ -1834,6 +1894,7 @@ class SM64_ObjectProperties(bpy.types.PropertyGroup): level: bpy.props.PointerProperty(type=SM64_LevelProperties) area: bpy.props.PointerProperty(type=SM64_AreaProperties) game_object: bpy.props.PointerProperty(type=SM64_GameObjectProperties) + segment_loads: bpy.props.PointerProperty(type=SM64_SegmentProperties) @staticmethod def upgrade_changed_props(): @@ -1860,6 +1921,7 @@ def upgrade_changed_props(): SM64_LevelProperties, SM64_AreaProperties, SM64_GameObjectProperties, + SM64_SegmentProperties, SM64_ObjectProperties, )