diff --git a/open_samus_returns_rando/files/doors.lua b/open_samus_returns_rando/files/doors.lua new file mode 100644 index 0000000..4d2c673 --- /dev/null +++ b/open_samus_returns_rando/files/doors.lua @@ -0,0 +1,17 @@ +Doors = {} + +function Doors.Dummy() +end +function Doors.RemoveDoors(_ARG_0_) + local actor_name = _ARG_0_.sName + -- TOOD: Remove the debug message + GUI.LaunchMessage(actor_name, "Doors.Dummy", "") + local ending = string.sub(actor_name, -2) + if ending == "_o" then + actor_name = string.sub(actor_name, 0, -3) + end + Game.DeleteEntity(actor_name) + Game.DeleteEntity(actor_name .. "_o") + Scenario.WriteToBlackboard("entity_" .. actor_name .. "_dead", "b", true) + Scenario.WriteToBlackboard("entity_" .. actor_name .. "_o_dead", "b", true) +end \ No newline at end of file diff --git a/open_samus_returns_rando/files/randomizer_powerup.lua b/open_samus_returns_rando/files/randomizer_powerup.lua index 22f59f2..0a0b984 100644 --- a/open_samus_returns_rando/files/randomizer_powerup.lua +++ b/open_samus_returns_rando/files/randomizer_powerup.lua @@ -9,14 +9,6 @@ RandomizerPowerup.Self = nil function RandomizerPowerup.Dummy() end -function RandomizerPowerup.GenerateADN() - -- TODO: - -- Add the __ARG__0 param - -- read its name and follow a name scheme for left and right side to delete other side - -- find out how to save -> reload -> permanently delete the door (guess blackboard property) - Game.DeleteEntity("LE_SpazerShield_Door008") - Game.DeleteEntity("LE_SpazerShield_Door008_a") -end function RandomizerPowerup.SetItemAmount(item_id, quantity) if type(quantity) == "string" then diff --git a/open_samus_returns_rando/samus_returns_patcher.py b/open_samus_returns_rando/samus_returns_patcher.py index 6fbab81..11b1e01 100644 --- a/open_samus_returns_rando/samus_returns_patcher.py +++ b/open_samus_returns_rando/samus_returns_patcher.py @@ -4,9 +4,7 @@ import typing from pathlib import Path -from construct import Container from mercury_engine_data_structures.file_tree_editor import OutputFormat -from mercury_engine_data_structures.formats import Bmsad from open_samus_returns_rando.bmsld_add import add_actor_to_entity_groups from open_samus_returns_rando.lua_editor import LuaEditor @@ -15,6 +13,7 @@ from open_samus_returns_rando.patcher_editor import PatcherEditor from open_samus_returns_rando.pickup import patch_pickups from open_samus_returns_rando.specific_patches import game_patches +from open_samus_returns_rando.specific_patches.door_patches import patch_shields from open_samus_returns_rando.specific_patches.heat_room_patches import patch_heat_rooms from open_samus_returns_rando.specific_patches.static_fixes import apply_static_fixes from open_samus_returns_rando.validator_with_default import DefaultValidatingDraft7Validator @@ -99,42 +98,6 @@ def patch_custom_pickups(editor: PatcherEditor, pickup_config: list[dict]): editor.copy_actor(scenario_name, new_pos, base_actor, new_actor_name, 9) add_actor_to_entity_groups(scenario, collision_camera_name, new_actor_name) -def patch_shields(editor: PatcherEditor): - # TODO: Move this function clean up this mess - # TODO: Write down all door / shields...lol - # TODO: Make unk06 a float in MEDS branch (cause I'm assign float values here) - # create custom pickup - _EXAMPLE_LEFT_SIDE = {"scenario": "s000_surface", "layer": "9", "actor": "LE_MissileShield_Door_002"} - _EXAMPLE_RIGHT_SIDE = {"scenario": "s010_area1", "layer": "9", "actor": "LE_DoorShieldMissile"} - _EXAMPLE_SPAZER = {"scenario": "s050_area5", "layer": "9", "actor": "LE_SpazerShield_Door008"} - - scenario = editor.get_scenario("s050_area5") - scenario.remove_actor_from_all_groups("LE_SpazerShield_Door008") - - - left_actor = editor.resolve_actor_reference(_EXAMPLE_LEFT_SIDE) - left_actor["unk06"] = 90 - right_actor = editor.resolve_actor_reference(_EXAMPLE_RIGHT_SIDE) - right_actor["unk06"] = 90 - - # messy spazer stuff (basically adds a call to RandomizerPowerup.GenerateADN when the door creature dies) - spazer_bmsad = editor.get_parsed_asset("actors/props/doorspazerbeam/charclasses/doorspazerbeam.bmsad", type_hint=Bmsad) # noqa - alpha_bmsad = editor.get_parsed_asset("actors/characters/alphanewborn/charclasses/alphanewborn.bmsad", type_hint=Bmsad) # noqa - spazer_bmsad.raw["components"]["SCRIPT"] = alpha_bmsad.raw["components"]["SCRIPT"] - spazer_bmsad.raw["components"]["SCRIPT"]["functions"][0]["params"]["Param1"]["value"] = "actors/items/randomizer_powerup/scripts/randomizer_powerup.lua" # noqa - spazer_bmsad.raw["components"]["SCRIPT"]["functions"][0]["params"]["Param2"]["value"] = "RandomizerPowerup" - unknown_mess = Container({"unk1": 22, "unk2": 1, "unk3": 0, "args": Container({601445949: Container({"type": "s", "value": "GenerateADN"})})}) # noqa - spazer_bmsad.action_sets[0].raw["animations"][0].event_counts[0] = spazer_bmsad.action_sets[0].raw["animations"][0].event_counts[0] + 1 # noqa - spazer_bmsad.action_sets[0].raw["animations"][0]["events0"].append(unknown_mess) - editor.replace_asset("actors/props/doorspazerbeam/charclasses/doorspazerbeam.bmsad", spazer_bmsad) - - spazer_actor = editor.resolve_actor_reference(_EXAMPLE_SPAZER) - new_spazer_actor = editor.copy_actor(_EXAMPLE_SPAZER["scenario"], (spazer_actor["x"], spazer_actor["y"], spazer_actor["z"]), spazer_actor, "LE_SpazerShield_Door008_a", 9) # noqa - new_spazer_actor["unk05"] = 0 - new_spazer_actor["unk06"] = 0 - new_spazer_actor["unk07"] = 0 - - def patch_extracted(input_path: Path, output_path: Path, configuration: dict): LOG.info("Will patch files from %s", input_path) @@ -170,6 +133,7 @@ def patch_extracted(input_path: Path, output_path: Path, configuration: dict): # Fix unheated heat rooms patch_heat_rooms(editor) + # Make shields on both sides patch_shields(editor) # Specific game patches diff --git a/open_samus_returns_rando/specific_patches/door_patches.py b/open_samus_returns_rando/specific_patches/door_patches.py new file mode 100644 index 0000000..35f28be --- /dev/null +++ b/open_samus_returns_rando/specific_patches/door_patches.py @@ -0,0 +1,112 @@ + +import copy + +from construct import Container, ListContainer +from mercury_engine_data_structures.formats import Bmsad + +from open_samus_returns_rando.constants import ALL_AREAS +from open_samus_returns_rando.files import files_path +from open_samus_returns_rando.patcher_editor import PatcherEditor + +SCRIPT_COMPONENT = Container({ + "type": "CScriptComponent", + "unk_1": 3000, + "unk_2": -1.0, + "functions": ListContainer([ + Container({ + "name": "SetParams", + "unk1": True, + "unk2": False, + "params": Container({ + "Param1": Container({ + "type": "s", + "value": "actors/props/doors/scripts/doors.lua", + }), + "Param2": Container({ + "type" :"s", + "value":"Doors", + }), + }), + }), + ]), + "fields": Container(), + "dependencies": None, +}) + +ON_DEAD_CB = Container({ + "unk1": 22, + "unk2": 1, + "unk3": 0, + "args": Container({ + 601445949: Container({ + "type": "s", + "value": "RemoveDoors", + }), + }), +}) + +def _patch_missile_covers(editor: PatcherEditor): + missile_types = {"doorshieldmissile", "doorshieldpowerbomb", "doorshieldsupermissile"} + for area in ALL_AREAS: + scenario = editor.get_scenario(area) + for layer, actor_name, actor in scenario.all_actors(): + if actor.type in missile_types: + actor["unk06"] = 90 + +def _patch_beam_covers(editor: PatcherEditor): + creature_bmsad_files = [ + "actors/props/doorspazerbeam/charclasses/doorspazerbeam.bmsad", + "actors/props/doorcreature/charclasses/doorcreature.bmsad", + "actors/props/doorwave/charclasses/doorwave.bmsad", + ] + for creature_bmsad_file in creature_bmsad_files: + cr_bmsad = editor.get_parsed_asset(creature_bmsad_file, type_hint=Bmsad) + cr_bmsad.raw["components"]["SCRIPT"] = SCRIPT_COMPONENT + action_set_anim = cr_bmsad.action_sets[0].raw["animations"][0] + action_set_anim.event_counts[0] = action_set_anim.event_counts[0] + 1 + action_set_anim["events0"].append(ON_DEAD_CB) + action_set_anim["animation_id"] = 30 + editor.replace_asset(creature_bmsad_file, cr_bmsad) + + beam_types = {"doorwave", "doorspazerbeam", "doorcreature"} + for area in ALL_AREAS: + editor.ensure_present_in_scenario(area, "actors/props/doors/scripts/doors.lc") + editor.ensure_present_in_scenario(area, "actors/props/doorspazerbeam/collisions/doorspazerbeam.bmscd") + editor.ensure_present_in_scenario(area, "actors/props/doorspazerbeam/models/doorspazerbeam.bcmdl") + scenario = editor.get_scenario(area) + actor_list_copy = {actor_name: actor for layer, actor_name, actor in scenario.all_actors()} + for actor_name, actor in actor_list_copy.items(): + if actor.type in beam_types: + new_actor_name = f"{actor_name}_o" + new_actor = editor.copy_actor( + area, (actor["x"], actor["y"], actor["z"]), actor, new_actor_name, 9 + ) + if new_actor["unk06"] == 0.0: + new_actor["unk05"] = 0 + new_actor["unk06"] = 180 + new_actor["unk07"] = 0 + elif new_actor["unk06"] == 180.0: + new_actor["unk05"] = 0 + new_actor["unk06"] = 0 + new_actor["unk07"] = 0 + else: + # that one is weird (because of fake surface west ?) + if area == "s000_surface" and actor_name == "LE_SpazerShield_Door_012": + continue + raise Exception + + # no idea if this really gets the right door + door_name = actor_name[actor_name.find("Door"):] + door_name = door_name.replace("ShieldPlasma", "").replace("ShieldWave", "") + door_actor = actor_list_copy.get(door_name, None) + if door_actor is None: + door_actor = actor_list_copy[door_name.replace("_", "")] + door_actor.components.append(copy.deepcopy(door_actor.components[0])) + door_actor.components[1]["arguments"][3]["value"] = new_actor_name + +def patch_shields(editor: PatcherEditor): + # TODO: Commit MEDS changes + editor.add_new_asset("actors/props/doors/scripts/doors.lc", files_path().joinpath("doors.lua").read_bytes(), []) + + _patch_missile_covers(editor) + _patch_beam_covers(editor) diff --git a/tests/test_files/thanatos_dev_heat_5_1.json b/tests/test_files/thanatos_dev_heat_5_1.json index ff233ff..6845a62 100644 --- a/tests/test_files/thanatos_dev_heat_5_1.json +++ b/tests/test_files/thanatos_dev_heat_5_1.json @@ -6,6 +6,7 @@ }, "starting_items": { "ITEM_MAX_LIFE": 599, + "ITEM_MAX_SPECIAL_ENERGY": 1000, "ITEM_WEAPON_MISSILE_MAX": 50, "ITEM_WEAPON_SUPER_MISSILE_MAX": 10, "ITEM_WEAPON_POWER_BOMB_MAX": 0,