From 4cfb4086d90c538cd29a50f1054c62d87406438d Mon Sep 17 00:00:00 2001 From: dyceron <38679103+dyceron@users.noreply.github.com> Date: Tue, 15 Aug 2023 17:32:46 -0400 Subject: [PATCH] Overwrite main (#43) * Input json for testing (will remove later) * - Add minimum required starting items to schema - Add minimum required starting items to test file * Add missing items in schema definition * Cleanup samus_returns_patcher.py * Minor cleanup * Prep for custom powerups * Move PatcherEditor to its own file * Remove version.py from being tracked * - Delete content of input_path - Add very primitive functions to add IPS patches * Reference new path of schema * Update pyproject.toml * Patch Pickups Attempt 1 * fix item id * BMSAD part passed (still wip) * Pickup shuffle semi-works (with broken visuals) * Update schema to match patch_data_factory.py in RDV * Update model_data.py * Cleanup * Fixes 2 * Revert "Merge branch 'main' into WorkingVersion" This reverts commit 0563a671658e8a1656c4013bec9d5095463decb5, reversing changes made to 9659a51053ca6c15ec1577b4479ea190f2a18fe4. --------- Co-authored-by: Thanatos Co-authored-by: duncathan salt --- .github/workflows/python.yml | 4 +- input.json | 1733 +++++++++++++++++ open_samus_returns_rando/__init__.py | 15 +- open_samus_returns_rando/cli.py | 7 +- open_samus_returns_rando/constants.py | 24 - .../files/custom_player.lua | 3 +- .../files/pickups/powerup_energyshield.lua | 18 - .../files/pickups/powerup_energywave.lua | 18 - .../pickups/powerup_phasedisplacement.lua | 18 - .../files/pickups/powerup_scanningpulse.lua | 3 +- .../files/randomizer_powerup.lua | 238 +-- open_samus_returns_rando/files/schema.json | 91 +- open_samus_returns_rando/logger.py | 3 - open_samus_returns_rando/lua_editor.py | 128 -- open_samus_returns_rando/lua_util.py | 64 +- .../misc_patches/exefs.py | 8 + open_samus_returns_rando/model_data.py | 27 +- open_samus_returns_rando/patch_util.py | 54 - open_samus_returns_rando/patcher_editor.py | 8 +- open_samus_returns_rando/pickup.py | 257 --- .../samus_returns_patcher.py | 181 +- .../templates/progressive_model_template.lua | 1 - .../randomizer_progressive_template.lua | 11 - open_samus_returns_rando/text_patches.py | 40 - .../validator_with_default.py | 21 - open_samus_returns_rando/version.py | 5 - pyproject.toml | 29 +- tests/test_files/starter_preset_patcher.json | 8 +- 28 files changed, 2015 insertions(+), 1002 deletions(-) create mode 100644 input.json delete mode 100644 open_samus_returns_rando/constants.py delete mode 100644 open_samus_returns_rando/files/pickups/powerup_energyshield.lua delete mode 100644 open_samus_returns_rando/files/pickups/powerup_energywave.lua delete mode 100644 open_samus_returns_rando/files/pickups/powerup_phasedisplacement.lua delete mode 100644 open_samus_returns_rando/logger.py delete mode 100644 open_samus_returns_rando/lua_editor.py create mode 100644 open_samus_returns_rando/misc_patches/exefs.py delete mode 100644 open_samus_returns_rando/patch_util.py delete mode 100644 open_samus_returns_rando/pickup.py delete mode 100644 open_samus_returns_rando/templates/progressive_model_template.lua delete mode 100644 open_samus_returns_rando/templates/randomizer_progressive_template.lua delete mode 100644 open_samus_returns_rando/text_patches.py delete mode 100644 open_samus_returns_rando/validator_with_default.py delete mode 100644 open_samus_returns_rando/version.py diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index cfbe525..73dbad0 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -98,7 +98,7 @@ jobs: repository_url: https://test.pypi.org/legacy/ - name: Create GitHub release - uses: svenstaro/upload-release-action@2.7.0 + uses: svenstaro/upload-release-action@2.3.0 if: ${{ startsWith(github.ref, 'refs/tags/') }} with: repo_token: ${{ secrets.GITHUB_TOKEN }} @@ -110,6 +110,6 @@ jobs: - name: Publish 📦 to PyPI if: ${{ startsWith(github.ref, 'refs/tags/') }} - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.pypi_password }} diff --git a/input.json b/input.json new file mode 100644 index 0000000..29530de --- /dev/null +++ b/input.json @@ -0,0 +1,1733 @@ +{ + "starting_location": { + "scenario": "s000_surface", + "actor": "StartPoint0" + }, + "starting_items": { + "ITEM_WEAPON_MISSILE_MAX": 24, + "ITEM_MAX_LIFE": 99, + "ITEM_SPECIAL_ENERGY_SCANNING_PULSE": 1, + "ITEM_MAX_SPECIAL_ENERGY": 1450, + "ITEM_BABY_HATCHLING": 1 + }, + "pickups": [ + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_001" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_002" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_003" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_004" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_005" + }, + "model": "item_missiletank" + }, + { + "caption": "Charge Beam acquired.", + "item_id": "ITEM_WEAPON_CHARGE_BEAM", + "quantity": 1, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_006" + }, + "model": "powerup_chargebeam" + }, + { + "caption": "Gravity Suit acquired.", + "item_id": "ITEM_GRAVITY_SUIT", + "quantity": 1, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_007" + }, + "model": "powerup_gravitysuit" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_008" + }, + "model": "item_missiletank" + }, + { + "caption": "Space Jump acquired.", + "item_id": "ITEM_SPACE_JUMP", + "quantity": 1, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_010" + }, + "model": "powerup_spacejump" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_011" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_Item_012" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Energy Tank acquired.\nEnergy capacity increased by 100.", + "item_id": "ITEM_ENERGY_TANKS", + "quantity": 1, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_PowerUP_ChargeBeam" + }, + "model": "item_energytank" + }, + { + "caption": "Morph Ball acquired.", + "item_id": "ITEM_MORPH_BALL", + "quantity": 1, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_PowerUP_Morphball" + }, + "model": "powerup_morphball" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "LE_SpecialAbility_ScanningPulse" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s000_surface", + "actor": "HiddenPowerup001" + }, + "model": "item_missiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_001" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_003" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_004" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Grapple Beam acquired.", + "item_id": "ITEM_WEAPON_GRAPPLE_BEAM", + "quantity": 1, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_005" + }, + "model": "powerup_grapplebeam" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_006" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_008" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_011" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_013" + }, + "model": "item_missiletank" + }, + { + "caption": "Plasma Beam acquired.", + "item_id": "ITEM_WEAPON_PLASMA_BEAM", + "quantity": 1, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_014" + }, + "model": "powerup_plasmabeam" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_016" + }, + "model": "item_missiletank" + }, + { + "caption": "High Jump Boots acquired.", + "item_id": "ITEM_HIGH_JUMP_BOOTS", + "quantity": 1, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_Item_017" + }, + "model": "powerup_highjumpboots" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_PowerUp_Bomb" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_PowerUp_IceBeam" + }, + "model": "item_missiletank" + }, + { + "caption": "Nothing acquired.", + "item_id": "ITEM_NONE", + "quantity": 1, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "LE_PowerUp_SpiderBall" + }, + "model": "itemsphere" + }, + { + "caption": "Spring Ball acquired.", + "item_id": "ITEM_SPRING_BALL", + "quantity": 1, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "HiddenPowerup001" + }, + "model": "powerup_springball" + }, + { + "caption": "Bomb acquired.", + "item_id": "ITEM_WEAPON_BOMB", + "quantity": 1, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "HiddenPowerup002" + }, + "model": "powerup_bomb" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s010_area1", + "actor": "HiddenPowerup003" + }, + "model": "item_missiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s020_area2", + "actor": "LE_Item_001" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s020_area2", + "actor": "LE_Item_003" + }, + "model": "item_senergytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s020_area2", + "actor": "LE_Item_004" + }, + "model": "item_missiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s020_area2", + "actor": "LE_Item_005" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s020_area2", + "actor": "LE_Item_006" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s020_area2", + "actor": "LE_PowerUp_Springball" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s020_area2", + "actor": "HiddenPowerup001" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s020_area2", + "actor": "HiddenPowerup002" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s025_area2b", + "actor": "LE_Item_001" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s025_area2b", + "actor": "LE_Item_002" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s025_area2b", + "actor": "LE_Item_005" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s025_area2b", + "actor": "LE_Item_006" + }, + "model": "item_missiletank" + }, + { + "caption": "Energy Tank acquired.\nEnergy capacity increased by 100.", + "item_id": "ITEM_ENERGY_TANKS", + "quantity": 1, + "pickup_actor": { + "scenario": "s025_area2b", + "actor": "LE_PowerUp_HighJumpBoots" + }, + "model": "item_energytank" + }, + { + "caption": "Energy Tank acquired.\nEnergy capacity increased by 100.", + "item_id": "ITEM_ENERGY_TANKS", + "quantity": 1, + "pickup_actor": { + "scenario": "s025_area2b", + "actor": "LE_PowerUp_VariaSuite" + }, + "model": "item_energytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s025_area2b", + "actor": "LE_PowerUp_WaveBeam" + }, + "model": "item_missiletank" + }, + { + "caption": "Nothing acquired.", + "item_id": "ITEM_NONE", + "quantity": 1, + "pickup_actor": { + "scenario": "s025_area2b", + "actor": "HP_Item_001" + }, + "model": "itemsphere" + }, + { + "caption": "Super Missile Launcher acquired.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE", + "quantity": 1, + "pickup_actor": { + "scenario": "s025_area2b", + "actor": "HP_Item_002" + }, + "model": "powerup_supermissile" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s028_area2c", + "actor": "LE_Item_001" + }, + "model": "item_senergytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s028_area2c", + "actor": "LE_Item_002" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s028_area2c", + "actor": "LE_Item_003" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s028_area2c", + "actor": "LE_Item_005" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s028_area2c", + "actor": "LE_SpecialAbility_EnergyShield" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s028_area2c", + "actor": "HiddenPowerup001" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Nothing acquired.", + "item_id": "ITEM_NONE", + "quantity": 1, + "pickup_actor": { + "scenario": "s030_area3", + "actor": "LE_Item_001" + }, + "model": "itemsphere" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s030_area3", + "actor": "LE_Item_002" + }, + "model": "item_missiletank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s030_area3", + "actor": "LE_Item_003" + }, + "model": "item_senergytank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s030_area3", + "actor": "LE_Item_004" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s030_area3", + "actor": "LE_Item_005" + }, + "model": "item_missiletank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s030_area3", + "actor": "LE_PowerUp_GrappleBeam" + }, + "model": "item_senergytank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s030_area3", + "actor": "LE_SpecialAbility_EnergyWave" + }, + "model": "item_senergytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s030_area3", + "actor": "HP_ChozoHologram_002" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s030_area3", + "actor": "HiddenPowerup001" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s030_area3", + "actor": "HiddenPowerup002" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s033_area3b", + "actor": "LE_Item_001" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s033_area3b", + "actor": "LE_Item_002" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s033_area3b", + "actor": "LE_Item_003" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s033_area3b", + "actor": "LE_Item_004" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s033_area3b", + "actor": "LE_Item_007" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s033_area3b", + "actor": "HiddenPowerup001" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s033_area3b", + "actor": "HiddenPowerup002" + }, + "model": "item_missiletank" + }, + { + "caption": "Screw Attack acquired.", + "item_id": "ITEM_SCREW_ATTACK", + "quantity": 1, + "pickup_actor": { + "scenario": "s033_area3b", + "actor": "HiddenPowerup003" + }, + "model": "powerup_screwattack" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s036_area3c", + "actor": "LE_Item_001" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s036_area3c", + "actor": "LE_Item_002" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s036_area3c", + "actor": "LE_Item_004" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s036_area3c", + "actor": "LE_Item_006" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s036_area3c", + "actor": "HiddenPowerup001" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "LE_Item_002" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "LE_Item_003" + }, + "model": "item_missiletank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "LE_Item_005" + }, + "model": "item_senergytank" + }, + { + "caption": "Wave Beam acquired.", + "item_id": "ITEM_WEAPON_WAVE_BEAM", + "quantity": 1, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "LE_Item_006" + }, + "model": "powerup_wavebeam" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "LE_Item_007" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "LE_Item_008" + }, + "model": "item_missiletank" + }, + { + "caption": "Nothing acquired.", + "item_id": "ITEM_NONE", + "quantity": 1, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "LE_PowerUp_SpazerBeam" + }, + "model": "itemsphere" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "HP_ChozoHologram_002" + }, + "model": "item_senergytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "HiddenPowerup001" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "HiddenPowerup003" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s040_area4", + "actor": "HiddenPowerup004" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_Item_002" + }, + "model": "item_senergytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_Item_003" + }, + "model": "item_missiletank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_Item_004" + }, + "model": "item_senergytank" + }, + { + "caption": "Ice Beam acquired.", + "item_id": "ITEM_WEAPON_ICE_BEAM", + "quantity": 1, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_Item_005" + }, + "model": "powerup_icebeam" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_Item_006" + }, + "model": "item_missiletank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_Item_009" + }, + "model": "item_senergytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_Item_010" + }, + "model": "item_missiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_Item_012" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Energy Tank acquired.\nEnergy capacity increased by 100.", + "item_id": "ITEM_ENERGY_TANKS", + "quantity": 1, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_Item_013" + }, + "model": "item_energytank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_PoweUp_SuperMissile" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "LE_PowerUp_SpaceJump" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "HiddenPowerup001" + }, + "model": "item_missiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s050_area5", + "actor": "HiddenPowerup002" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Main Power Bomb acquired.", + "item_id": "ITEM_WEAPON_POWER_BOMB", + "quantity": 1, + "pickup_actor": { + "scenario": "s060_area6", + "actor": "LE_Item_002" + }, + "model": "powerup_powerbomb" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s060_area6", + "actor": "LE_Item_003" + }, + "model": "item_senergytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s060_area6", + "actor": "LE_Item_004" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s060_area6", + "actor": "LE_Item_006" + }, + "model": "item_missiletank" + }, + { + "caption": "Energy Tank acquired.\nEnergy capacity increased by 100.", + "item_id": "ITEM_ENERGY_TANKS", + "quantity": 1, + "pickup_actor": { + "scenario": "s060_area6", + "actor": "LE_Item_007" + }, + "model": "item_energytank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s060_area6", + "actor": "LE_SpecialAbility_PhaseDisplacement" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s060_area6", + "actor": "HiddenPowerup001" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s060_area6", + "actor": "HiddenPowerup002" + }, + "model": "item_missiletank" + }, + { + "caption": "Varia Suit acquired.", + "item_id": "ITEM_VARIA_SUIT", + "quantity": 1, + "pickup_actor": { + "scenario": "s065_area6b", + "actor": "LE_Item_001" + }, + "model": "powerup_variasuit" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s065_area6b", + "actor": "LE_Item_002" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s065_area6b", + "actor": "LE_Item_003" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s065_area6b", + "actor": "LE_Item_004" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s065_area6b", + "actor": "LE_Item_005" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s065_area6b", + "actor": "LE_Item_006" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s065_area6b", + "actor": "LE_Item_007" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s065_area6b", + "actor": "LE_PowerUp_ScrewAttack" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s065_area6b", + "actor": "HiddenPowerup001" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s067_area6c", + "actor": "LE_Item_001" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s067_area6c", + "actor": "LE_Item_002" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s067_area6c", + "actor": "LE_Item_003" + }, + "model": "item_missiletank" + }, + { + "caption": "Energy Tank acquired.\nEnergy capacity increased by 100.", + "item_id": "ITEM_ENERGY_TANKS", + "quantity": 1, + "pickup_actor": { + "scenario": "s067_area6c", + "actor": "LE_Item_004" + }, + "model": "item_energytank" + }, + { + "caption": "Energy Tank acquired.\nEnergy capacity increased by 100.", + "item_id": "ITEM_ENERGY_TANKS", + "quantity": 1, + "pickup_actor": { + "scenario": "s067_area6c", + "actor": "LE_Item_005" + }, + "model": "item_energytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s067_area6c", + "actor": "LE_PowerUp_GravitySuite" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s067_area6c", + "actor": "LE_PowerUp_PlasmaBeam" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s067_area6c", + "actor": "HP_ChozoHologram_001" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Nothing acquired.", + "item_id": "ITEM_NONE", + "quantity": 1, + "pickup_actor": { + "scenario": "s067_area6c", + "actor": "HiddenPowerup002" + }, + "model": "itemsphere" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s067_area6c", + "actor": "HiddenPowerup003" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_001" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_002" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_004" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_007" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_008" + }, + "model": "item_missiletank" + }, + { + "caption": "Spider Ball acquired.", + "item_id": "ITEM_SPIDER_BALL", + "quantity": 1, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_009" + }, + "model": "powerup_spiderball" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_010" + }, + "model": "item_missiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_012" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_013" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_014" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_PowerUp_Powerbomb" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_011" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s070_area7", + "actor": "LE_Item_015" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "LE_Item_001" + }, + "model": "item_senergytank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "LE_Item_002" + }, + "model": "item_senergytank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "LE_Item_003" + }, + "model": "item_senergytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "LE_Item_004" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "LE_Item_008" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "LE_Item_009" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "LE_Item_010" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Energy Tank acquired.\nEnergy capacity increased by 100.", + "item_id": "ITEM_ENERGY_TANKS", + "quantity": 1, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "LE_Item_011" + }, + "model": "item_energytank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "LE_Item_012" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "LE_Item_013" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "HiddenPowerup001" + }, + "model": "item_missiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "HiddenPowerup002" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s090_area9", + "actor": "HiddenPowerup003" + }, + "model": "item_missiletank" + }, + { + "caption": "Spazer Beam acquired.", + "item_id": "ITEM_WEAPON_SPAZER_BEAM", + "quantity": 1, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_001" + }, + "model": "powerup_spazerbeam" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_003" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_004" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_005" + }, + "model": "item_missiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_007" + }, + "model": "item_powerbombtank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_008" + }, + "model": "item_missiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_009" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_010" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_011" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_012" + }, + "model": "item_missiletank" + }, + { + "caption": "Missile Tank acquired.\nMissile capacity increased by 3.", + "item_id": "ITEM_WEAPON_MISSILE_MAX", + "quantity": 3, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_013" + }, + "model": "item_missiletank" + }, + { + "caption": "Energy Tank acquired.\nEnergy capacity increased by 100.", + "item_id": "ITEM_ENERGY_TANKS", + "quantity": 1, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "LE_Item_014" + }, + "model": "item_energytank" + }, + { + "caption": "Aeion Tank acquired.\nAieon capacity increased by 50", + "item_id": "ITEM_MAX_SPECIAL_ENERGY", + "quantity": 50, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "HiddenPowerup001" + }, + "model": "item_senergytank" + }, + { + "caption": "Energy Tank acquired.\nEnergy capacity increased by 100.", + "item_id": "ITEM_ENERGY_TANKS", + "quantity": 1, + "pickup_actor": { + "scenario": "s100_area10", + "actor": "HiddenPowerup002" + }, + "model": "item_energytank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s110_surfaceb", + "actor": "LE_Item_013" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Super Missile Tank acquired.\nSuper Missile capacity increased by 1.", + "item_id": "ITEM_WEAPON_SUPER_MISSILE_MAX", + "quantity": 1, + "pickup_actor": { + "scenario": "s110_surfaceb", + "actor": "HiddenPowerup002" + }, + "model": "item_supermissiletank" + }, + { + "caption": "Power Bomb Tank acquired.\nPower Bomb capacity increased by 1.", + "item_id": "ITEM_WEAPON_POWER_BOMB_MAX", + "quantity": 1, + "pickup_actor": {}, + "model": "item_powerbombtank" + } + ], + "energy_per_tank": 100 + } \ No newline at end of file diff --git a/open_samus_returns_rando/__init__.py b/open_samus_returns_rando/__init__.py index 7adf7af..7a6e722 100644 --- a/open_samus_returns_rando/__init__.py +++ b/open_samus_returns_rando/__init__.py @@ -1,14 +1 @@ -from pathlib import Path - -from .patch_util import patch_with_status_update - - -def patch(input_path: Path, output_path: Path, configuration: dict): - from .samus_returns_patcher import patch_extracted - return patch_extracted(input_path, output_path, configuration) - - -__all__ = [ - patch, - patch_with_status_update, -] \ No newline at end of file +from .samus_returns_patcher import patch \ No newline at end of file diff --git a/open_samus_returns_rando/cli.py b/open_samus_returns_rando/cli.py index 2dd79ab..527ff09 100644 --- a/open_samus_returns_rando/cli.py +++ b/open_samus_returns_rando/cli.py @@ -2,7 +2,6 @@ import json import logging import logging.config -import time from pathlib import Path from open_samus_returns_rando import samus_returns_patcher @@ -54,15 +53,13 @@ def main(): setup_logging() parser = create_parser() args = parser.parse_args() + print(args) with args.input_json.open() as f: configuration = json.load(f) - start = time.time() - samus_returns_patcher.patch_extracted( + samus_returns_patcher.patch( args.input_path, args.output_path, configuration, ) - end = time.time() - print(f"Patcher took {end - start:.03f} seconds") \ No newline at end of file diff --git a/open_samus_returns_rando/constants.py b/open_samus_returns_rando/constants.py deleted file mode 100644 index 57affeb..0000000 --- a/open_samus_returns_rando/constants.py +++ /dev/null @@ -1,24 +0,0 @@ -from enum import Enum - -# constant data, including "magic numbers" and common data that many modules use - -# list of all scenarios -ALL_SCENARIOS = [ - "s000_surface", - "s010_area1", - "s020_area2", - "s025_area2b", - "s028_area2c", - "s030_area3", - "s033_area3b", - "s036_area3c", - "s040_area4", - "s050_area5", - "s060_area6", - "s065_area6b", - "s067_area6c", - "s070_area7", - "s090_area9", - "s100_area10", - "s110_surfaceb" -] \ No newline at end of file diff --git a/open_samus_returns_rando/files/custom_player.lua b/open_samus_returns_rando/files/custom_player.lua index b597ede..cdca18b 100644 --- a/open_samus_returns_rando/files/custom_player.lua +++ b/open_samus_returns_rando/files/custom_player.lua @@ -1,6 +1,5 @@ Game.ImportLibrary("actors/characters/player/scripts/player_original.lua") function Player.UnlockScanningPulse() - Game.LockAeionReserveTank() Player.SetAbilityUnlocked("ScanningPulse", true) -end \ No newline at end of file +end diff --git a/open_samus_returns_rando/files/pickups/powerup_energyshield.lua b/open_samus_returns_rando/files/pickups/powerup_energyshield.lua deleted file mode 100644 index 6d163ba..0000000 --- a/open_samus_returns_rando/files/pickups/powerup_energyshield.lua +++ /dev/null @@ -1,18 +0,0 @@ -function PowerUpEnergyShield.main() -end -function PowerUpEnergyShield.BeginPlay(_ARG_0_) - Game.PlayEntityLoop("generic/hability_projector.wav", _ARG_0_.sName, 0.15, 600, 3600, 1.2, false) -end -function PowerUpEnergyShield.OnPickedUp(_ARG_0_) - if Game.GetPlayer() ~= nil and Game.GetPlayer().SPECIALENERGY ~= nil then - Game.GetPlayer().SPECIALENERGY.fMaxEnergy = Game.GetPlayer().SPECIALENERGY.fMaxEnergy + 150 - Game.GetPlayer().SPECIALENERGY.fEnergy = Game.GetPlayer().SPECIALENERGY.fMaxEnergy - end - Game.PlayEntitySoundContinueOnDead("generic/obtencion.wav", _ARG_0_.sName, 1, 500, 4000, 1) --- CurrentScenario.LaunchSpecialEnergyCutscene() - guicallbacks.OnPickableItemPickedUp("#GUI_ITEM_ACQUIRED_LIGHTNING_ARMOR", true) - SpecialEnergyCloud.ActivateSpecialEnergy("TG_SpecialEnergyCloud") - Game.GetPlayerInfo():FillSpecialEnergyReserveTank() --- Game.HUDAvailabilityGoOff(true, false, false, false) --- Game.SetIgnoreHUDAvailabilityActivationByAbilityComponent(true) -end \ No newline at end of file diff --git a/open_samus_returns_rando/files/pickups/powerup_energywave.lua b/open_samus_returns_rando/files/pickups/powerup_energywave.lua deleted file mode 100644 index 76d2165..0000000 --- a/open_samus_returns_rando/files/pickups/powerup_energywave.lua +++ /dev/null @@ -1,18 +0,0 @@ -function PowerUpEnergyWave.main() -end -function PowerUpEnergyWave.BeginPlay(_ARG_0_) - Game.PlayEntityLoop("generic/hability_projector.wav", _ARG_0_.sName, 0.15, 600, 1800, 1.2, false) -end -function PowerUpEnergyWave.OnPickedUp(_ARG_0_) - if Game.GetPlayer() ~= nil and Game.GetPlayer().SPECIALENERGY ~= nil then - Game.GetPlayer().SPECIALENERGY.fMaxEnergy = Game.GetPlayer().SPECIALENERGY.fMaxEnergy + 150 - Game.GetPlayer().SPECIALENERGY.fEnergy = Game.GetPlayer().SPECIALENERGY.fMaxEnergy - end - Game.PlayEntitySoundContinueOnDead("generic/obtencion.wav", _ARG_0_.sName, 1, 500, 4000, 1) - -- CurrentScenario.LaunchSpecialEnergyCutscene() - guicallbacks.OnPickableItemPickedUp("#GUI_ITEM_ACQUIRED_WEAPON_BOOST", true) - SpecialEnergyCloud.ActivateSpecialEnergy("TG_SpecialEnergyCloud") - Game.GetPlayerInfo():FillSpecialEnergyReserveTank() - -- Game.HUDAvailabilityGoOff(true, false, false, false) - -- Game.SetIgnoreHUDAvailabilityActivationByAbilityComponent(true) -end \ No newline at end of file diff --git a/open_samus_returns_rando/files/pickups/powerup_phasedisplacement.lua b/open_samus_returns_rando/files/pickups/powerup_phasedisplacement.lua deleted file mode 100644 index dd36565..0000000 --- a/open_samus_returns_rando/files/pickups/powerup_phasedisplacement.lua +++ /dev/null @@ -1,18 +0,0 @@ -function PowerUpPhaseDisplacement.main() -end -function PowerUpPhaseDisplacement.BeginPlay(_ARG_0_) - Game.PlayEntityLoop("generic/hability_projector.wav", _ARG_0_.sName, 0.15, 600, 1200, 1.2, false) -end -function PowerUpPhaseDisplacement.OnPickedUp(_ARG_0_) - if Game.GetPlayer() ~= nil and Game.GetPlayer().SPECIALENERGY ~= nil then - Game.GetPlayer().SPECIALENERGY.fMaxEnergy = Game.GetPlayer().SPECIALENERGY.fMaxEnergy + 150 - Game.GetPlayer().SPECIALENERGY.fEnergy = Game.GetPlayer().SPECIALENERGY.fMaxEnergy - end - Game.PlayEntitySoundContinueOnDead("generic/obtencion.wav", _ARG_0_.sName, 1, 500, 4000, 1) --- CurrentScenario.LaunchSpecialEnergyCutscene() - guicallbacks.OnPickableItemPickedUp("#GUI_ITEM_ACQUIRED_PHASE_DISPLACEMENT", true) - SpecialEnergyCloud.ActivateSpecialEnergy("TG_SpecialEnergyCloud") - Game.GetPlayerInfo():FillSpecialEnergyReserveTank() --- Game.HUDAvailabilityGoOff(true, false, false, false) --- Game.SetIgnoreHUDAvailabilityActivationByAbilityComponent(true) -end \ No newline at end of file diff --git a/open_samus_returns_rando/files/pickups/powerup_scanningpulse.lua b/open_samus_returns_rando/files/pickups/powerup_scanningpulse.lua index 6061f68..f97697c 100644 --- a/open_samus_returns_rando/files/pickups/powerup_scanningpulse.lua +++ b/open_samus_returns_rando/files/pickups/powerup_scanningpulse.lua @@ -7,9 +7,8 @@ function PowerUpScanningPulse.OnPickedUp(_ARG_0_) -- Game.ScanningPulseTutorialSE_XY() Game.PlayEntitySoundContinueOnDead("generic/obtencion.wav", _ARG_0_.sName, 1, 500, 4000, 1) -- CurrentScenario.LaunchSpecialEnergyCutscene() - GUI.LaunchMessageSequence(4) + guicallbacks.OnPickableItemPickedUp("#GUI_ITEM_ACQUIRED_SCANNING_PULSE", false) SpecialEnergyCloud.ActivateSpecialEnergy("TG_SpecialEnergyCloud") - Game.GetPlayerInfo():FillSpecialEnergyReserveTank() -- Game.HUDAvailabilityGoOff(true, false, false, false) -- Game.SetIgnoreHUDAvailabilityActivationByAbilityComponent(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 713d55e..6f13bcd 100644 --- a/open_samus_returns_rando/files/randomizer_powerup.lua +++ b/open_samus_returns_rando/files/randomizer_powerup.lua @@ -4,241 +4,5 @@ RandomizerPowerup = {} function RandomizerPowerup.main() end -RandomizerPowerup.tProgressiveModels = {} - -RandomizerPowerup.Self = nil - -function RandomizerPowerup.SetItemAmount(item_id, quantity) - if type(quantity) == "string" then - quantity = RandomizerPowerup.GetItemAmount(quantity) - end - Game.SetItemAmount(Game.GetPlayerName(), item_id, quantity) -end -function RandomizerPowerup.GetItemAmount(item_id) - return Game.GetItemAmount(Game.GetPlayerName(), item_id) -end -function RandomizerPowerup.HasItem(item_id) - return RandomizerPowerup.GetItemAmount(item_id) > 0 -end -function RandomizerPowerup.IncreaseItemAmount(item_id, quantity, capacity) - local target = RandomizerPowerup.GetItemAmount(item_id) + quantity - if capacity ~= nil then - if type(capacity) == "string" then - capacity = RandomizerPowerup.GetItemAmount(capacity) - end - target = math.min(target, capacity) - end - target = math.max(target, 0) - RandomizerPowerup.SetItemAmount(item_id, target) -end - -function RandomizerPowerup.PropertyForLocation(locationIdentifier) - return "Location_Collected_" .. locationIdentifier -end - -function RandomizerPowerup.MarkLocationCollected(locationIdentifier) - local playerSection = Game.GetPlayerBlackboardSectionName() - local propName = RandomizerPowerup.PropertyForLocation(locationIdentifier) - Game.LogWarn(0, propName) - Blackboard.SetProp(playerSection, propName, "b", true) -end - -function RandomizerPowerup.IncrementInventoryIndex() - local playerSection = Game.GetPlayerBlackboardSectionName() - local propName = "InventoryIndex" - local currentIndex = Blackboard.GetProp(playerSection, propName) or 0 - currentIndex = currentIndex + 1 - Blackboard.SetProp(playerSection, propName, "f", currentIndex) -end - -function RandomizerPowerup.OnPickedUp(actor, resources) - RandomizerPowerup.Self = actor - local name = "Boss" - if actor ~= nil then - name = actor.sName - RandomizerPowerup.MarkLocationCollected(string.format("%s_%s", Scenario.CurrentScenarioID, name)) - end - - Game.LogWarn(0, "Collected pickup: " .. name) - local granted = RandomizerPowerup.HandlePickupResources(resources) - - for _, resource in ipairs(granted) do - RandomizerPowerup.IncreaseEnergy(resource) - RandomizerPowerup.IncreaseAmmo(resource) - - RandomizerPowerup.CheckArtifacts(resource) - end - - RandomizerPowerup.ApplyTunableChanges() - Scenario.UpdateProgressiveItemModels() - RandomizerPowerup.IncrementInventoryIndex() - RL.UpdateRDVClient(false) - return granted -end - -function RandomizerPowerup.HandlePickupResources(progression) - progression = progression or {} - - local alwaysGrant = false - - if #progression == 0 then - return {} - elseif #progression == 1 then - alwaysGrant = true - end - - Game.LogWarn(0, "Resources:") - for _, resource_list in ipairs(progression) do - local data = " - " - for _, resource in ipairs(resource_list) do - data = data .. resource.item_id .. " (" .. resource.quantity .. ") / " - end - Game.LogWarn(0, data) - end - - -- For each progression stage, if the player does not have the FIRST item in that stage, the whole stage is granted - for _, resource_list in ipairs(progression) do - -- Check if we need to grant anything from this progression stage - - if #resource_list > 0 then - local current = RandomizerPowerup.GetItemAmount(resource_list[1].item_id) - local shouldGrant = alwaysGrant or current < resource_list[1].quantity - - if shouldGrant then - for _, resource in ipairs(resource_list) do - Game.LogWarn(0, "Granting " .. resource.quantity .. " " .. resource.item_id) - RandomizerPowerup.IncreaseItemAmount(resource.item_id, resource.quantity) - end - - return resource_list - end - end - - -- Otherwise, loop to next progression stage (or fall out of loop) - end - - return {} -- nothing granted after final stage of progression is reached -end - -function RandomizerPowerup.ChangeSuit() - -- ordered by priority - local suits = { - {item = "ITEM_GRAVITY_SUIT", model = "Gravity"}, - {item = "ITEM_VARIA_SUIT", model = "Varia"}, - } - local model_updater = Game.GetPlayer().MODELUPDATER - for _, suit in ipairs(suits) do - if suit.model == model_updater.sModelAlias then break end - if RandomizerPowerup.HasItem(suit.item) then - Game.AddPSF(0.1, RandomizerPowerup.Delayed_ChangeSuit, "s", suit.model) - break - end - end -end - -MAX_ENERGY = 1499 -function RandomizerPowerup.IncreaseEnergy(resource) - -- No resource, quit - if not resource then return end - - local item_id = resource.item_id - - -- Not etank, quit - if item_id ~= "ITEM_ENERGY_TANKS" then return end - - local energy = Init.fEnergyPerTank - - Game.LogWarn(0, "Increasing player energy.") - - local new_max = RandomizerPowerup.GetItemAmount("ITEM_MAX_LIFE") + energy - new_max = math.min(new_max, MAX_ENERGY) - - local new_current = new_max - - RandomizerPowerup.SetItemAmount("ITEM_MAX_LIFE", new_max) - RandomizerPowerup.SetItemAmount("ITEM_CURRENT_LIFE", new_current) - - local life = Game.GetPlayer().LIFE - life.fMaxLife = new_max - life.fCurrentLife = new_current -end - -MAX_AEION = 2000 -function RandomizerPowerup.IncreaseAeion(resource) - if not resource then return end - - local item_id = resource.item_id - - -- Not aeion tank, quit - if item_id ~= "ITEM_SENERGY_TANKS" then return end - - local aeion = Init.fAeionPerTank - - Game.LogWarn(0, "Increasing player aeion.") - - local new_max = RandomizerPowerup.GetItemAmount("ITEM_MAX_SPECIAL_ENERGY") + aeion - new_max = math.min(new_max, MAX_AEION) - - local new_current = new_max - - RandomizerPowerup.SetItemAmount("ITEM_MAX_SPECIAL_ENERGY", new_max) - RandomizerPowerup.SetItemAmount("ITEM_CURRENT_SPECIAL_ENERGY", new_current) - - local energy = Game.GetPlayer().SPECIALENERGY - energy.fMaxEnergy = new_max - energy.fEnergy = new_current -end - -function RandomizerPowerup.IncreaseAmmo(resource) - if not resource then return end - - local current_id = nil - - if resource.item_id == "ITEM_WEAPON_POWER_BOMB_MAX" then - current_id = "ITEM_WEAPON_POWER_BOMB_CURRENT" - elseif resource.item_id == "ITEM_WEAPON_SUPER_MISSILE_MAX" then - current_id = "ITEM_WEAPON_SUPER_MISSILE_CURRENT" - elseif resource.item_id == "ITEM_WEAPON_MISSILE_MAX" then - current_id = "ITEM_WEAPON_MISSILE_CURRENT" - end - - if current_id == nil then return end - - RandomizerPowerup.IncreaseItemAmount(current_id, resource.quantity, resource.item_id) -end - -local tItemTunableHandlers = { - ["ITEM_SPECIAL_ENERGY_SCANNING_PULSE"] = function(quantity) - -- Amount of Aeion used by Scan Pulse - Scenario.SetTunableValue("CTunableAbilityScanningPulse", "fConsumptionOnActivation", quantity = 0 ) -} - -function RandomizerPowerup.ApplyTunableChanges() - Game.AddSF(0, "RandomizerPowerup._ApplyTunableChanges", "") -end - -function RandomizerPowerup._ApplyTunableChanges() - for item, handler in pairs(tItemTunableHandlers) do - local totalQuantity = RandomizerPowerup.GetItemAmount(item) - - Game.LogWarn(0, "Calling tunable handler for " .. item .. " = " .. totalQuantity) - - handler(totalQuantity) - end -end - --- Main Supers -RandomizerSuperMissile = {} -setmetatable(RandomizerSuperMissile, {__index = RandomizerPowerup}) -function RandomizerSuperMissile.OnPickedUp(actor, progression) - progression = progression or {{{ item_id = "ITEM_WEAPON_SUPER_MISSILE_MAX", quantity = 0 }}} - RandomizerPowerup.OnPickedUp(actor, progression) -end - --- Main PBs -RandomizerPowerBomb = {} -setmetatable(RandomizerPowerBomb, {__index = RandomizerPowerup}) -function RandomizerPowerBomb.OnPickedUp(actor, progression) - progression = progression or {{{ item_id = "ITEM_WEAPON_POWER_BOMB_MAX", quantity = 0 }}} - RandomizerPowerup.OnPickedUp(actor, progression) +function RandomizerPowerup.OnPickedUp() end \ No newline at end of file diff --git a/open_samus_returns_rando/files/schema.json b/open_samus_returns_rando/files/schema.json index 85a668d..1d3f7e2 100644 --- a/open_samus_returns_rando/files/schema.json +++ b/open_samus_returns_rando/files/schema.json @@ -5,24 +5,37 @@ "starting_location": { "$ref": "#/$defs/actor_reference" }, + "starting_items": { + "type": "object", + "propertyNames": { + "$ref": "#/$defs/item_id" + }, + "required": [ + "ITEM_MAX_LIFE", + "ITEM_WEAPON_MISSILE_MAX", + "ITEM_WEAPON_SUPER_MISSILE_MAX", + "ITEM_WEAPON_POWER_BOMB_MAX" + ] + }, "pickups": { "type": "array", "items": { + "type": "object", "properties": { - "pickup_actor": { - "$ref": "#/$defs/actor_reference_with_layer" - }, "caption": { "type": "string" }, - "model": { - "type": "string" - }, "item_id": { "type": "string" }, "quantity": { "type": "number" + }, + "pickup_actor": { + "$ref": "#/$defs/actor_reference_with_layer" + }, + "model": { + "type": "string" } }, "required": [ @@ -50,22 +63,6 @@ "destination" ] } - }, - "starting_items": { - "type": "object", - "propertyNames": { - "$ref": "#/$defs/item_id" - } - }, - "energy_per_tank": { - "description": "How much energy collecting an Energy Tank gives.", - "type": "number", - "default": 100.0 - }, - "aeion_per_tank": { - "description": "How much aeion collecting an aeion Tank gives.", - "type": "number", - "default": 50.0 } }, "required": [ @@ -73,12 +70,6 @@ "starting_location", "pickups" ], - "text_patches": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, "$defs": { "actor_reference_with_layer": { "type": "object", @@ -86,13 +77,15 @@ "scenario": { "$ref": "#/$defs/scenario_name" }, + "layer": { + "type": "string", + "default": "default" + }, "actor": { "type": "string" } }, "required": [ - "scenario", - "actor" ] }, "actor_reference": { @@ -106,8 +99,6 @@ } }, "required": [ - "scenario", - "actor" ] }, "scenario_name": { @@ -136,11 +127,12 @@ "type": "string", "enum": [ "ITEM_NONE", - "ITEM_WEAPON_CHARGE_BEAM", + "ITEM_MAX_LIFE", "ITEM_WEAPON_ICE_BEAM", "ITEM_WEAPON_WAVE_BEAM", "ITEM_WEAPON_SPAZER_BEAM", "ITEM_WEAPON_PLASMA_BEAM", + "ITEM_WEAPON_CHARGE_BEAM", "ITEM_WEAPON_GRAPPLE_BEAM", "ITEM_WEAPON_SUPER_MISSILE", "ITEM_SPECIAL_ENERGY_SCANNING_PULSE", @@ -151,45 +143,22 @@ "ITEM_GRAVITY_SUIT", "ITEM_MORPH_BALL", "ITEM_WEAPON_BOMB", - "ITEM_WEAPON_POWER_BOMB", "ITEM_SPIDER_BALL", "ITEM_SPRING_BALL", - "ITEM_HIGH_JUMP", + "ITEM_WEAPON_POWER_BOMB", + "ITEM_HIGH_JUMP_BOOTS", "ITEM_SPACE_JUMP", "ITEM_SCREW_ATTACK", + "ITEM_BABY_HATCHLING", "ITEM_ENERGY_TANKS", - "ITEM_SENERGY_TANKS", - "ITEM_MAX_LIFE", - "ITEM_CURRENT_LIFE", - "ITEM_MAX_SPECIAL_ENERGY", - "ITEM_CURRENT_SPECIAL_ENERGY", - "ITEM_WEAPON_MISSILE_CURRENT", "ITEM_WEAPON_MISSILE_MAX", - "ITEM_WEAPON_SUPER_MISSILE_CURRENT", "ITEM_WEAPON_SUPER_MISSILE_MAX", - "ITEM_WEAPON_POWER_BOMB_CURRENT", "ITEM_WEAPON_POWER_BOMB_MAX", + "ITEM_MAX_SPECIAL_ENERGY", "ITEM_METROID_COUNT", "ITEM_METROID_TOTAL_COUNT", - "ITEM_ADN", - "ITEM_BABY_HATCHLING" + "ITEM_ADN" ] - }, - "item": { - "type": "object", - "properties": { - "item_id": { - "$ref": "#/$defs/item_id" - }, - "quantity": { - "type": "number" - } - }, - "required": [ - "item_id", - "quantity" - ], - "additionalProperties": false } } } diff --git a/open_samus_returns_rando/logger.py b/open_samus_returns_rando/logger.py deleted file mode 100644 index ec8ea0b..0000000 --- a/open_samus_returns_rando/logger.py +++ /dev/null @@ -1,3 +0,0 @@ -import logging - -LOG = logging.getLogger("samus_returns_patcher") \ No newline at end of file diff --git a/open_samus_returns_rando/lua_editor.py b/open_samus_returns_rando/lua_editor.py deleted file mode 100644 index 89a82f2..0000000 --- a/open_samus_returns_rando/lua_editor.py +++ /dev/null @@ -1,128 +0,0 @@ -import itertools -from pathlib import Path - -from open_samus_returns_rando import lua_util -from open_samus_returns_rando.constants import ALL_SCENARIOS -from open_samus_returns_rando.patcher_editor import PatcherEditor, path_for_level - - -def _read_powerup_lua() -> bytes: - return Path(__file__).parent.joinpath("files", "randomizer_powerup.lua").read_bytes() - - -def _read_level_lua(level_id: str) -> str: - return Path(__file__).parent.joinpath("files", "levels", f"{level_id}.lua").read_text() - - -SPECIFIC_CLASSES = { - "ITEM_WEAPON_SUPER_MISSILE": "RandomizerSuperMissile", - "ITEM_WEAPON_POWER_BOMB": "RandomizerPowerBomb", -} - - -class LuaEditor: - def __init__(self): - self._progressive_classes = {} - self._powerup_script = _read_powerup_lua() - self._custom_level_scripts: dict[str, dict] = self._read_levels() - - def _read_levels(self) -> dict[str, dict]: - return { - scenario: {"script": _read_level_lua(scenario), "edited": False} - for scenario in ALL_SCENARIOS - } - - def get_parent_for(self, item_id) -> str: - return SPECIFIC_CLASSES.get(item_id, "RandomizerPowerup") - - def get_script_class(self, pickup: dict, boss: bool = False, actordef_name: str = "") -> str: - pickup_resources = pickup["resources"] - parent = self.get_parent_for(pickup_resources[0][0]["item_id"]) - - if not boss and len(pickup_resources) == 1 and len(pickup_resources[0]) == 1: - # Single-item pickup; don't include progressive template - return parent - - if actordef_name and len(pickup["model"]) > 1: - self.add_progressive_models(pickup, actordef_name) - - hashable_progression = "_".join([ - f'{res[0]["item_id"]}_{res[0]["quantity"]}' - for res in pickup_resources - ]).replace("-", "MINUS") - - if hashable_progression in self._progressive_classes.keys(): - return self._progressive_classes[hashable_progression] - - class_name = f"RandomizerProgressive{hashable_progression}" - - resources = [ - [ - { - "item_id": lua_util.wrap_string(res["item_id"]), - "quantity": res["quantity"] - } - for res in resource_list - ] - for resource_list in pickup_resources - ] - replacement = { - "name": class_name, - "resources": resources, - "parent": parent, - } - self.add_progressive_class(replacement) - - self._progressive_classes[hashable_progression] = class_name - return class_name - - def add_progressive_class(self, replacement): - new_class = lua_util.replace_lua_template("randomizer_progressive_template.lua", replacement) - self._powerup_script += new_class.encode("utf-8") - - def add_progressive_models(self, pickup: dict, actordef_name: str): - progressive_models = [ - { - "item": lua_util.wrap_string(resource["item_id"]), - "alias": lua_util.wrap_string(model_name), - } - for resource, model_name in itertools.chain( - zip([r[0] for r in pickup["resources"]], pickup["model"][1:]), - [(pickup["resources"][-1][0], pickup["model"][-1])], - ) - ] - progressive_models.reverse() - - replacement = { - "actordef_name": actordef_name, - "progressive_models": progressive_models, - } - - models = lua_util.replace_lua_template("progressive_model_template.lua", replacement) - self._powerup_script += models.encode("utf-8") - - def patch_actordef_pickup_script(self, editor: PatcherEditor, pickup: dict, pickup_lua_callback: dict, - extra_code: str = ""): - scenario = pickup_lua_callback["scenario"] - scenario_path = path_for_level(scenario) - lua_util.create_script_copy(editor, scenario_path) - - script = self._custom_level_scripts[scenario] - - if not script["edited"]: - script["script"] += "\nGame.DoFile('actors/items/randomizer_powerup/scripts/randomizer_powerup.lua')\n\n" - script["edited"] = True - - replacement = { - "scenario": scenario, - "funcname": pickup_lua_callback["function"], - "pickup_class": self.get_script_class(pickup, True), - "extra_code": extra_code, - "args": ", ".join([f"_ARG_{i}_" for i in range(pickup_lua_callback["args"])]) - } - script["script"] += lua_util.replace_lua_template("boss_powerup_template.lua", replacement) - - def save_modifications(self, editor: PatcherEditor): - editor.replace_asset("actors/items/randomizer_powerup/scripts/randomizer_powerup.lc", self._powerup_script) - for scenario, script in self._custom_level_scripts.items(): - editor.replace_asset(path_for_level(scenario) + ".lc", script["script"].encode("utf-8")) diff --git a/open_samus_returns_rando/lua_util.py b/open_samus_returns_rando/lua_util.py index 11a8dcd..2c2b7b9 100644 --- a/open_samus_returns_rando/lua_util.py +++ b/open_samus_returns_rando/lua_util.py @@ -1,6 +1,5 @@ import re from pathlib import Path -from typing import Any from mercury_engine_data_structures.file_tree_editor import FileTreeEditor @@ -13,16 +12,12 @@ def _files() -> Path: return Path(__file__).parent.joinpath("files") -def replace_lua_template(file: str, replacement: dict[str, Any], wrap_strings: bool = False) -> str: +def replace_lua_template(file: str, replacement: dict[str, str]) -> str: code = _templates().joinpath(file).read_text() for key, content in replacement.items(): - # Replace `TEMPLATE("key")`-style replacements - code = code.replace(f'TEMPLATE("{key}")', lua_convert(content, wrap_strings)) - # Replace `T__key__T`-style replacements - code = code.replace(f'T__{key}__T', lua_convert(content, wrap_strings)) + code = code.replace(f'TEMPLATE("{key}")', lua_convert(content)) unknown_templates = re.findall(r'TEMPLATE\("([^"]+)"\)', code) - unknown_templates.extend(re.findall(r'T__(\w+)__T', code)) if unknown_templates: raise ValueError("The following templates were left unfulfilled: " + str(unknown_templates)) @@ -30,23 +25,19 @@ def replace_lua_template(file: str, replacement: dict[str, Any], wrap_strings: b return code -def lua_convert(data, wrap_strings: bool = False) -> str: +def lua_convert(data) -> str: if isinstance(data, list): return "{\n" + "\n".join( - f"{lua_convert(item, wrap_strings)}," + "{},".format(lua_convert(item)) for item in data ) + "\n}" if isinstance(data, dict): return "{\n" + "\n".join( - f"{key} = {lua_convert(value, wrap_strings)}," + "{} = {},".format(key, lua_convert(value)) for key, value in data.items() ) + "\n}" if isinstance(data, bool): return "true" if data else "false" - if data is None: - return "nil" - if wrap_strings and isinstance(data, str): - return wrap_string(data) return str(data) @@ -67,4 +58,47 @@ def create_script_copy(editor: FileTreeEditor, path: str): def replace_script(editor: FileTreeEditor, path: str, replacement_path: str): create_script_copy(editor, path) - editor.replace_asset(path + ".lc", _files().joinpath(replacement_path).read_bytes()) \ No newline at end of file + editor.replace_asset(path + ".lc", _files().joinpath(replacement_path).read_bytes()) + + +def replace_area_lua(editor: FileTreeEditor): + + ALL_AREAS = [ + "s000_surface", + "s010_area1", + "s020_area2", + "s025_area2b", + "s028_area2c", + "s030_area3", + "s033_area3b", + "s036_area3c", + "s040_area4", + "s050_area5", + "s060_area6", + "s065_area6b", + "s067_area6c", + "s070_area7", + "s090_area9", + "s100_area10", + "s110_surfaceb", + ] + + # ALL_PICKUPS = [ + # "powerup_gravitysuit", + # "powerup_variasuit", + # "powerup_scanningpulse", + # ] + + for x in ALL_AREAS: + replace_script( + editor, + f"maps/levels/c10_samus/{x}/{x}", + f"levels/{x}.lua" + ) + + # for x in ALL_PICKUPS: + # replace_script( + # editor, + # f"actors/items/{x}/scripts/{x}", + # f"pickups/{x}.lua" + # ) \ No newline at end of file diff --git a/open_samus_returns_rando/misc_patches/exefs.py b/open_samus_returns_rando/misc_patches/exefs.py new file mode 100644 index 0000000..e247995 --- /dev/null +++ b/open_samus_returns_rando/misc_patches/exefs.py @@ -0,0 +1,8 @@ +import ips + +class DSPatch(ips.Patch): + def __init__(self): + super().__init__(False) + + def add_record(self, offset, content, rle_size=-1): + return super().add_record(offset, content, rle_size) \ No newline at end of file diff --git a/open_samus_returns_rando/model_data.py b/open_samus_returns_rando/model_data.py index eb40eba..885cbbd 100644 --- a/open_samus_returns_rando/model_data.py +++ b/open_samus_returns_rando/model_data.py @@ -1,12 +1,12 @@ import dataclasses -from typing import Optional +from typing import Optional, Tuple @dataclasses.dataclass(frozen=True) class Transform: - position: tuple[float, float, float] = (0.0, 0.0, 0.0) - angle: tuple[float, float, float] = (0.0, 0.0, 0.0) - scale: tuple[float, float, float] = (1.0, 1.0, 1.0) + position: Tuple[float, float, float] = (0.0, 0.0, 0.0) + angle: Tuple[float, float, float] = (0.0, 0.0, 0.0) + scale: Tuple[float, float, float] = (1.0, 1.0, 1.0) @dataclasses.dataclass(frozen=True) @@ -117,6 +117,9 @@ class ModelData: "actors/items/powerup_scanningpulse/models/powerup_scanningpulse.bcmdl", "actors/items/powerup_scanningpulse/scripts/powerup_scanningpulse.lc", ), + transform=Transform( + position=(0.0, 30.0, 0.0), + ) ), "powerup_energyshield": ModelData( @@ -128,6 +131,9 @@ class ModelData: "actors/items/powerup_energyshield/models/powerup_energyshield.bcmdl", "actors/items/powerup_energyshield/scripts/powerup_energyshield.lc", ), + transform=Transform( + position=(0.0, 30.0, 0.0), + ) ), "powerup_energywave": ModelData( @@ -139,6 +145,9 @@ class ModelData: "actors/items/powerup_energywave/models/powerup_energywave.bcmdl", "actors/items/powerup_energywave/scripts/powerup_energywave.lc", ), + transform=Transform( + position=(0.0, 30.0, 0.0), + ) ), "powerup_phasedisplacement": ModelData( @@ -150,6 +159,9 @@ class ModelData: "actors/items/powerup_phasedisplacement/models/powerup_phasedisplacement.bcmdl", "actors/items/powerup_phasedisplacement/scripts/powerup_phasedisplacement.lc", ), + transform=Transform( + position=(0.0, 30.0, 0.0), + ) ), "powerup_variasuit": ModelData( @@ -160,6 +172,7 @@ class ModelData: "actors/items/powerup_variasuit/models/textures/itemspherecoat.bctex", "actors/items/powerup_variasuit/models/textures/itemvariasuit_d.bctex", "actors/items/powerup_variasuit/scripts/powerup_variasuit.lc", + "actors/items/itemsphere/animations/relax.bcskla", ), ), @@ -171,6 +184,7 @@ class ModelData: "actors/items/powerup_gravitysuit/models/textures/cubemetroids.bctex", "actors/items/powerup_gravitysuit/models/textures/itemgravitysuit_d.bctex", "actors/items/powerup_gravitysuit/scripts/powerup_gravitysuit.lc", + "actors/items/itemsphere/animations/relax.bcskla", ), ), @@ -212,6 +226,9 @@ class ModelData: "actors/items/powerup_spiderball/models/textures/powerup_morphball_d.bctex", "actors/items/powerup_spiderball/scripts/powerup_spiderball.lc", ), + transform=Transform( + position=(0.0, 30.0, 0.0), + ) ), "powerup_highjumpboots": ModelData( @@ -306,4 +323,4 @@ class ModelData: def get_data(name: str) -> ModelData: - return ALL_MODEL_DATA.get(name, ALL_MODEL_DATA["itemsphere"]) \ No newline at end of file + return ALL_MODEL_DATA.get(name, ALL_MODEL_DATA["itemsphere"]) diff --git a/open_samus_returns_rando/patch_util.py b/open_samus_returns_rando/patch_util.py deleted file mode 100644 index 3cf972f..0000000 --- a/open_samus_returns_rando/patch_util.py +++ /dev/null @@ -1,54 +0,0 @@ -import logging -import typing -from pathlib import Path - -from open_samus_returns_rando.logger import LOG - - -def patch_with_status_update(input_path: Path, output_path: Path, configuration: dict, - status_update: typing.Callable[[float, str], None]): - from open_samus_returns_rando.samus_returns_patcher import patch_extracted - total_logs = 108 - - class StatusUpdateHandler(logging.Handler): - count = 0 - - def emit(self, record: logging.LogRecord) -> None: - message = self.format(record) - - # Ignore "Writing <...>.pkg" messages, since there's also Updating... - if message.startswith("Writing ") and message.endswith(".pkg"): - return - - # Encoding a bmsad is quick, skip these - if message.endswith(".bmsad"): - return - - # These can come up frequently and are benign - if message.startswith("Skipping extracted file"): - return - - self.count += 1 - status_update(self.count / total_logs, message) - - new_handler = StatusUpdateHandler() - # new_handler.setFormatter(logging.Formatter('[%(asctime)s] [%(levelname)s] %(message)s')) - tree_editor_log = logging.getLogger("mercury_engine_data_structures.file_tree_editor") - - try: - tree_editor_log.setLevel(logging.DEBUG) - tree_editor_log.handlers.insert(0, new_handler) - tree_editor_log.propagate = False - LOG.setLevel(logging.INFO) - LOG.handlers.insert(0, new_handler) - LOG.propagate = False - - patch_extracted(input_path, output_path, configuration) - if new_handler.count < total_logs: - status_update(1, f"Done was {new_handler.count}") - - finally: - tree_editor_log.removeHandler(new_handler) - tree_editor_log.propagate = True - LOG.removeHandler(new_handler) - LOG.propagate = True \ No newline at end of file diff --git a/open_samus_returns_rando/patcher_editor.py b/open_samus_returns_rando/patcher_editor.py index 109d91a..6b334d8 100644 --- a/open_samus_returns_rando/patcher_editor.py +++ b/open_samus_returns_rando/patcher_editor.py @@ -14,7 +14,7 @@ class PatcherEditor(FileTreeEditor): memory_files: dict[str, BaseResource] def __init__(self, root: Path): - super().__init__(root, target_game=Game.SAMUS_RETURNS) + super().__init__(root, Game.SAMUS_RETURNS) self.memory_files = {} def get_file(self, path: str, type_hint: typing.Type[T] = BaseResource) -> T: @@ -22,9 +22,6 @@ def get_file(self, path: str, type_hint: typing.Type[T] = BaseResource) -> T: self.memory_files[path] = self.get_parsed_asset(path, type_hint=type_hint) return self.memory_files[path] - def get_scenario(self, name: str) -> Bmsld: - return self.get_file(path_for_level(name) + ".bmsld", Bmsld) - def get_level_pkgs(self, name: str) -> set[str]: return set(self.find_pkgs(path_for_level(name) + ".bmsld")) @@ -32,6 +29,9 @@ def ensure_present_in_scenario(self, scenario: str, asset): for pkg in self.get_level_pkgs(scenario): self.ensure_present(pkg, asset) + def get_scenario(self, name: str) -> Bmsld: + return self.get_file(path_for_level(name) + ".bmsld", Bmsld) + def flush_modified_assets(self): for name, resource in self.memory_files.items(): self.replace_asset(name, resource) diff --git a/open_samus_returns_rando/pickup.py b/open_samus_returns_rando/pickup.py deleted file mode 100644 index a55c2ca..0000000 --- a/open_samus_returns_rando/pickup.py +++ /dev/null @@ -1,257 +0,0 @@ -import copy -import functools -import json -from pathlib import Path - -from mercury_engine_data_structures.formats import Bmsad, Txt - -from open_samus_returns_rando import lua_util -from open_samus_returns_rando.model_data import ALL_MODEL_DATA -from open_samus_returns_rando.patcher_editor import PatcherEditor, path_for_level - - -@functools.cache -def _read_template_powerup(): - with Path(__file__).parent.joinpath("templates", "template_powerup_bmsad.json").open() as f: - return json.load(f) - - -def _read_powerup_lua() -> bytes: - return Path(__file__).parent.joinpath("files", "randomizer_powerup.lua").read_bytes() - - -def patch_actor_pickup(editor: PatcherEditor, pickup: dict, pickup_id: int): - template_bmsad = _read_template_powerup() - - pkgs_for_level = set(editor.find_pkgs(path_for_level(pickup["pickup_actor"]["scenario"]) + ".bmsld")) - - for pickup in pickup_id: - actor_reference = pickup["pickup_actor"] - scenario = editor.get_scenario(actor_reference["scenario"]) - actor_name = actor_reference["actor"] - - model_name: str = pickup["model"] - model_data = ALL_MODEL_DATA.get(model_name, ALL_MODEL_DATA["itemsphere"]) - - found_actor = False - for actors in scenario.raw.actors: - if actor_name in actors: - actor = actors[actor_name] - actor["type"] = pickup["type"] - found_actor = True - break - - if not found_actor: - raise KeyError("Actor named '{}' found in ".format(actor_name, actor_reference["scenario"])) - - new_template = copy.deepcopy(template_bmsad) - new_template["name"] = f"randomizer_powerup_{pickup_id}" - - # Update used model - new_template["property"]["model_name"] = model_data.bcmdl_path - MODELUPDATER = new_template["property"]["components"]["MODELUPDATER"] - MODELUPDATER["functions"][0]["params"]["Param1"]["value"] = model_data.bcmdl_path - - # Update given item - if len(pickup["resources"]) == 1: - new_template = patch_single_item_pickup(new_template, pickup, pickup_id) - else: - new_template = patch_progressive_pickup(new_template, pickup, pickup_id) - - new_path = f"actors/items/randomizer_powerup/charclasses/randomizer_powerup_{pickup_id}.bmsad" - editor.add_new_asset(new_path, Bmsad(new_template, editor.target_game), in_pkgs=pkgs_for_level) - actor.oActorDefLink = f"actordef:{new_path}" - - # Powerup is in plain sight (except for the part we're using the sphere model) - actor.pComponents.pop("LIFE", None) - - # Dependencies - for level_pkg in pkgs_for_level: - editor.ensure_present(level_pkg, "system/animtrees/base.bmsat") - for dep in model_data.dependencies: - editor.ensure_present(level_pkg, dep) - - # For debugging, write the bmsad we just created - _outpath.joinpath(f"randomizer_powerup_{pickup_id}.bmsad.json").write_text( - json.dumps(new_template, indent=4) - ) - for pkg in pkgs_for_level: - editor.ensure_present(pkg, "actors/items/randomizer_powerup/scripts/randomizer_powerup.lc") - - -def patch_single_item_pickup(bmsad: dict, pickup: dict, pickup_id: int) -> dict: - PICKABLE: dict = bmsad["property"]["components"]["PICKABLE"] - SCRIPT: dict = bmsad["property"]["components"]["SCRIPT"] - - set_custom_params: dict = PICKABLE["functions"][0]["params"] - item_id: str = pickup["resources"][0]["item_id"] - quantity: float = pickup["resources"][0]["quantity"] - - if item_id == "ITEM_ENERGY_TANKS": - item_id = "fMaxLife" - quantity *= 100.0 - set_custom_params["Param4"]["value"] = "Full" - set_custom_params["Param5"]["value"] = "fCurrentLife" - set_custom_params["Param6"]["value"] = "LIFE" - - elif item_id == "ITEM_SENERGY_TANK": - item_id = "fMaxEnergy" - quantity *= 50.0 - set_custom_params["Param4"]["value"] = "Full" - set_custom_params["Param5"]["value"] = "fEnergy" - set_custom_params["Param6"]["value"] = "SPECIALENERGY" - - elif item_id in {"ITEM_WEAPON_MISSILE_MAX", "ITEM_WEAPON_SUPER_MISSILE_MAX" "ITEM_WEAPON_POWER_BOMB_MAX"}: - set_custom_params["Param4"]["value"] = "Custom" - set_custom_params["Param5"]["value"] = item_id.replace("_MAX", "_CURRENT") - set_custom_params["Param8"]["value"] = "guicallbacks.OnSecondaryGunsFire" - set_custom_params["Param13"] = { - "type": "f", - "value": quantity, - } - - SCRIPT["functions"][0]["params"]["Param2"]["value"] = get_script_class(pickup) - - if item_id == "ITEM_WEAPON_POWER_BOMB": - item_id = "ITEM_WEAPON_POWER_BOMB_MAX" - elif item_id == "ITEM_WEAPON_SUPER_MISSILE": - item_id = "ITEM_WEAPON_SUPER_MISSILE_MAX" - - set_custom_params["Param1"]["value"] = item_id - set_custom_params["Param2"]["value"] = quantity - - return bmsad - - -expansions = {"ITEM_ENERGY_TANKS", "ITEM_SENERGY_TANKS", "ITEM_WEAPON_MISSILE_MAX", "ITEM_WEAPON_SUPER_MISSILE_MAX", "ITEM_WEAPON_SUPER_MISSILE", - "ITEM_WEAPON_POWER_BOMB_MAX", "ITEM_WEAPON_POWER_BOMB"} - - -def patch_progressive_pickup(bmsad: dict, pickup: dict, pickup_id: int) -> dict: - item_ids = {resource["item_id"] for resource in pickup["resources"]} - if not expansions.isdisjoint(item_ids): - raise NotImplementedError("Progressive pickups cannot include expansions.") - - PICKABLE: dict = bmsad["property"]["components"]["PICKABLE"] - SCRIPT: dict = bmsad["property"]["components"]["SCRIPT"] - - set_custom_params: dict = PICKABLE["functions"][0]["params"] - set_custom_params["Param1"]["value"] = "ITEM_NONE" - - SCRIPT["functions"][0]["params"]["Param2"]["value"] = get_script_class(pickup) - - return bmsad - - -_progressive_classes = {} - - -def get_script_class(pickup: dict, boss: bool = False) -> str: - main_pb = pickup["resources"][0]["item_id"] == "ITEM_WEAPON_POWER_BOMB" - if len(pickup["resources"]) == 1: - return "RandomizerPowerBomb" if main_pb else "RandomizerPowerup" - - super_launcher = pickup["resources"][0]["item_id"] == "ITEM_WEAPON_SUPER_MISSILE" - if len(pickup["resources"]) == 1: - return "RandomizerSuperMissile" if main_pb else "RandomizerPowerup" - - hashable_progression = "_".join([f'{res["item_id"]}_{res["quantity"]}' for res in pickup["resources"]]) - - if hashable_progression in _progressive_classes.keys(): - return _progressive_classes[hashable_progression] - - class_name = f"RandomizerProgressive{hashable_progression}" - - resources = [ - { - "item_id": lua_util.wrap_string(res["item_id"]), - "quantity": res["quantity"] - } - for res in pickup["resources"] - ] - replacementPB = { - "name": class_name, - "progression": resources, - "parent": "RandomizerPowerBomb" if main_pb else "RandomizerPowerup", - } - replacementSuper = { - "name": class_name, - "progression": resources, - "parent": "RandomizerSuperMissile" if super_launcher else "RandomizerPowerup", - } - add_progressive_class(replacementPB) - add_progressive_class(replacementSuper) - - _progressive_classes[hashable_progression] = class_name - return class_name - - -_powerup_script: str = None - - -def add_progressive_class(replacement): - global _powerup_script - if _powerup_script is None: - _powerup_script = _read_powerup_lua() - - new_class = lua_util.replace_lua_template("randomizer_progressive_template.lua", replacement) - _powerup_script += new_class.encode("utf-8") - - -def _patch_actordef_pickup(editor: PatcherEditor, pickup: dict, - pickup_id: int, item_id_field: str) -> tuple[str, Bmsad]: - item_id: str = pickup["resources"][0]["item_id"] - - if len(pickup["resources"]) > 1 or pickup["resources"][0]["quantity"] > 1 or item_id in expansions: - item_id = "ITEM_NONE" - _patch_actordef_pickup_script(editor, pickup) - - bmsad_path: str = pickup["pickup_actordef"] - actordef = editor.get_file(bmsad_path, Bmsad) - - AI = actordef.raw["property"]["components"]["AI"] - AI["fields"]["fields"][item_id_field] = item_id - - # may want to edit all the localization files? - text_files = { - # "eu_dutch.txt", - # "eu_french.txt", - # "eu_german.txt", - # "eu_italian.txt", - # "eu_spanish.txt", - # "japanese.txt", - # "korean.txt", - # "russian.txt", - # "simplified_chinese.txt", - # "traditional_chinese.txt", - "us_english.txt", - # "us_french.txt", - # "us_spanish.txt" - } - for text_file in text_files: - text_file = "system/localization/" + text_file - text = editor.get_file(text_file, Txt) - text.strings[pickup["pickup_string_key"]] = pickup["caption"] - editor.replace_asset(text_file, text) - - return bmsad_path, actordef - - -_custom_level_scripts: dict[str, str] = {} - - -def _patch_actordef_pickup_script(editor: PatcherEditor, pickup: dict): - scenario: str = pickup["pickup_lua_callback"]["scenario"] - - scenario_path = path_for_level(scenario) - lua_util.create_script_copy(editor, scenario_path) - - if scenario not in _custom_level_scripts.keys(): - _custom_level_scripts[scenario] = "\n".join([ - f"Game.LogWarn(0, 'Loading original {scenario}...')", - f"Game.ImportLibrary('{scenario_path}_original.lua')", - f"Game.LogWarn(0, 'Loaded original {scenario}.')", - f"Game.DoFile('actors/items/randomizer_powerup/scripts/randomizer_powerup.lua')\n\n", - ]) - -_outpath = Path() \ No newline at end of file diff --git a/open_samus_returns_rando/samus_returns_patcher.py b/open_samus_returns_rando/samus_returns_patcher.py index cddf4af..5390606 100644 --- a/open_samus_returns_rando/samus_returns_patcher.py +++ b/open_samus_returns_rando/samus_returns_patcher.py @@ -1,22 +1,23 @@ +import copy import json +import logging import shutil import typing from pathlib import Path +import jsonschema + from mercury_engine_data_structures.file_tree_editor import OutputFormat +from mercury_engine_data_structures.formats import Bmsad -import open_samus_returns_rando.pickup +from open_samus_returns_rando.misc_patches.exefs import DSPatch +from open_samus_returns_rando.patcher_editor import PatcherEditor, path_for_level from open_samus_returns_rando import lua_util -from open_samus_returns_rando.logger import LOG -from open_samus_returns_rando.lua_editor import LuaEditor -from open_samus_returns_rando.patcher_editor import PatcherEditor -from open_samus_returns_rando.patcher_editor import path_for_level, PatcherEditor -from open_samus_returns_rando.pickup import _read_powerup_lua, _powerup_script, _custom_level_scripts -from open_samus_returns_rando.text_patches import apply_text_patches -from open_samus_returns_rando.validator_with_default import DefaultValidatingDraft7Validator +from open_samus_returns_rando.model_data import get_data T = typing.TypeVar("T") +LOG = logging.getLogger("samus_returns_patcher") def _read_schema(): @@ -24,90 +25,164 @@ def _read_schema(): return json.load(f) -def create_custom_init(editor: PatcherEditor, configuration: dict) -> str: - inventory: dict[str, int] = configuration["starting_items"] - starting_location: dict = configuration["starting_location"] +def _read_template_powerup(): + with Path(__file__).parent.joinpath("templates", "template_powerup_bmsad.json").open() as f: + return json.load(f) + + +def _read_powerup_lua() -> bytes: + return Path(__file__).parent.joinpath("files", "randomizer_powerup.lua").read_bytes() + + +def create_custom_init(inventory: dict[str, int], starting_location: dict): + def _wrap(v: str): + return f'"{v}"' # Game doesn't like to start if some fields are missing, like ITEM_WEAPON_POWER_BOMB_MAX final_inventory = { "ITEM_MAX_LIFE": 99, - "ITEM_CURRENT_SPECIAL_ENERGY": 1000, - "ITEM_WEAPON_ICE_BEAM": 0, "ITEM_MAX_SPECIAL_ENERGY": 1000, + "ITEM_METROID_COUNT": 0, + "ITEM_METROID_TOTAL_COUNT": 40, "ITEM_WEAPON_MISSILE_MAX": 0, "ITEM_WEAPON_SUPER_MISSILE_MAX": 0, "ITEM_WEAPON_POWER_BOMB_MAX": 0, - "ITEM_METROID_COUNT": 0, - "ITEM_METROID_TOTAL_COUNT": 40, } final_inventory.update(inventory) replacement = { - "new_game_inventory": final_inventory, - "starting_scenario": lua_util.wrap_string(starting_location["scenario"]), - "starting_actor": lua_util.wrap_string(starting_location["actor"]), + "new_game_inventory": "\n".join( + "{} = {},".format(key, value) + for key, value in final_inventory.items() + ), + "starting_scenario": _wrap(starting_location["scenario"]), + "starting_actor": _wrap(starting_location["actor"]), } - return lua_util.replace_lua_template("custom_init.lua", replacement) - - -def powerup_lua(): - return _powerup_script or _read_powerup_lua() + return lua_util.replace_lua_template("custom_init.lua", replacement) def patch_pickups(editor: PatcherEditor, pickups_config: list[dict]): - # add to the TOC - editor.add_new_asset("actors/items/randomizer_powerup/scripts/randomizer_powerup.lc", b'', []) + template_bmsad = editor.get_parsed_asset("actors/items/powerup_chargebeam/charclasses/powerup_chargebeam.bmsad").raw + + pkgs_for_lua = set() for i, pickup in enumerate(pickups_config): LOG.info("Writing pickup %d: %s", i, pickup["item_id"]) - - # replace with the generated script - editor.replace_asset("actors/items/randomizer_powerup/scripts/randomizer_powerup.lc", powerup_lua()) - for scenario, script in _custom_level_scripts.items(): - editor.replace_asset(path_for_level(scenario) + ".lc", script.encode("utf-8")) - -def validate(configuration: dict): - DefaultValidatingDraft7Validator(_read_schema()).validate(configuration) - -def patch_extracted(input_path: Path, output_path: Path, configuration: dict): - open_samus_returns_rando.pickup._outpath = output_path + pkgs_for_level = set(editor.find_pkgs(path_for_level(pickup["pickup_actor"]["scenario"]) + ".bmsld")) + pkgs_for_lua.update(pkgs_for_level) + + actor_reference = pickup["pickup_actor"] + scenario = editor.get_scenario(actor_reference["scenario"]) + actor_name = actor_reference["actor"] + + actor = next((layer[actor_name] for layer in scenario.raw.actors if actor_name in layer), None) + if actor is None: + raise KeyError(f"No actor named '{actor_name}' found in {actor_reference['scenario']}") + + model_name: str = pickup["model"] + model_data = get_data(model_name) + + new_template = copy.deepcopy(template_bmsad) + + # Update used model + new_template["model_name"] = model_data.bcmdl_path + MODELUPDATER = new_template["components"]["MODELUPDATER"] + MODELUPDATER["functions"][0]["params"]["Param1"]["value"] = model_data.bcmdl_path + + # Update caption + PICKABLE = new_template["components"]["PICKABLE"] + + # Update given item + set_custom_params: dict = PICKABLE["functions"][0]["params"] + item_id: str = pickup["item_id"] + quantity: float = pickup["quantity"] + + if item_id == "ITEM_ENERGY_TANKS": + item_id = "fMaxLife" + quantity *= 100.0 + set_custom_params["Param4"]["value"] = "Full" + set_custom_params["Param5"]["value"] = "fCurrentLife" + set_custom_params["Param6"]["value"] = "LIFE" + + elif item_id == "ITEM_SENERGY_TANKS": + item_id = "fMaxEnergy" + quantity *= 50.0 + set_custom_params["Param4"]["value"] = "Full" + set_custom_params["Param5"]["value"] = "fEnergy" + set_custom_params["Param6"]["value"] = "SPECIALENERGY" + + set_custom_params["Param1"]["value"] = item_id + set_custom_params["Param2"]["value"] = quantity + + actordef_id = f"randomizer_powerup_{i}" + new_template["name"] = actordef_id + new_path = f"actors/items/{actordef_id}/charclasses/{actordef_id}.bmsad" + + editor.add_new_asset(new_path, Bmsad(new_template, editor.target_game), in_pkgs=pkgs_for_level) + actor.type = actordef_id + + # Powerup is in plain sight (except for the part we're using the sphere model) + # actor.components.pop("LIFE", None) + + # Dependencies + for level_pkg in pkgs_for_level: + editor.ensure_present(level_pkg, "system/animtrees/base.bmsat") + for dep in model_data.dependencies: + editor.ensure_present(level_pkg, dep) + + # For debugging, write the bmsad we just created + # Path("custom_bmsad", f"randomizer_powerup_{i}.bmsad.json").write_text( + # json.dumps(new_template, indent=4) + # ) + + editor.add_new_asset("actors/items/randomizer_powerup/scripts/randomizer_powerup.lc", + _read_powerup_lua(), + in_pkgs=pkgs_for_lua) + +def patch_exefs(exefs_patches: Path, configuration: dict): + exefs_patches.mkdir(parents=True, exist_ok=True) + patch = DSPatch() + # file needs to be named code.ips for Citra + exefs_patches.joinpath("code.ips").write_bytes(bytes(patch)) + +def patch(input_path: Path, output_path: Path, configuration: dict): LOG.info("Will patch files from %s", input_path) - validate(configuration) + jsonschema.validate(instance=configuration, schema=_read_schema()) out_romfs = output_path.joinpath("romfs") + out_exefs= output_path.joinpath("exefs") + shutil.rmtree(out_romfs, ignore_errors=True) + shutil.rmtree(out_exefs, ignore_errors=True) editor = PatcherEditor(input_path) - lua_scripts = LuaEditor() # Update init.lc lua_util.create_script_copy(editor, "system/scripts/init") editor.replace_asset( "system/scripts/init.lc", - create_custom_init(editor, configuration).encode("ascii"), + create_custom_init( + configuration["starting_items"], + configuration["starting_location"] + ).encode("ascii"), ) - # Update scenario.lc lua_util.replace_script(editor, "system/scripts/scenario", "custom_scenario.lua") - - # Update player.lc lua_util.replace_script(editor, "actors/characters/player/scripts/player", "custom_player.lua") + # Replaces the original area lua files with modified ones + lua_util.replace_area_lua(editor) + # Pickups patch_pickups(editor, configuration["pickups"]) - # Text patches - if "text_patches" in configuration: - apply_text_patches(editor, configuration["text_patches"]) + # Exefs + LOG.info("Creating exefs patches") + patch_exefs(out_exefs, configuration) - LOG.info("Saving modified lua scripts") - lua_scripts.save_modifications(editor) - - LOG.info("Flush modified assets") editor.flush_modified_assets() - LOG.info("Saving modified pkgs to %s", out_romfs) - shutil.rmtree(out_romfs, ignore_errors=True) + # shutil.rmtree(out_romfs) editor.save_modifications(out_romfs, OutputFormat.PKG) - - LOG.info("Done") \ No newline at end of file + + logging.info("Done") \ No newline at end of file diff --git a/open_samus_returns_rando/templates/progressive_model_template.lua b/open_samus_returns_rando/templates/progressive_model_template.lua deleted file mode 100644 index e3bb4ce..0000000 --- a/open_samus_returns_rando/templates/progressive_model_template.lua +++ /dev/null @@ -1 +0,0 @@ -RandomizerPowerup.tProgressiveModels['TEMPLATE("actordef_name")'] = TEMPLATE("progressive_models") \ No newline at end of file diff --git a/open_samus_returns_rando/templates/randomizer_progressive_template.lua b/open_samus_returns_rando/templates/randomizer_progressive_template.lua deleted file mode 100644 index df05a67..0000000 --- a/open_samus_returns_rando/templates/randomizer_progressive_template.lua +++ /dev/null @@ -1,11 +0,0 @@ -Game.LogWarn(0, 'loading TEMPLATE("name")') - -T__name__T = {} -setmetatable(T__name__T, {__index = TEMPLATE("parent")}) -function T__name__T.main() -end -function T__name__T.OnPickedUp(actor) - Game.LogWarn(0, 'picked up TEMPLATE("name")') - local resources = TEMPLATE("resources") - TEMPLATE("parent").OnPickedUp(actor, resources) -end \ No newline at end of file diff --git a/open_samus_returns_rando/text_patches.py b/open_samus_returns_rando/text_patches.py deleted file mode 100644 index be831b6..0000000 --- a/open_samus_returns_rando/text_patches.py +++ /dev/null @@ -1,40 +0,0 @@ -from __future__ import annotations - -import typing - -from mercury_engine_data_structures.formats import Txt - -if typing.TYPE_CHECKING: - from open_samus_returns_rando.patcher_editor import PatcherEditor - -# may want to edit all the localization files? -ALL_TEXT_FILES = { - # "eu_dutch.txt", - # "eu_french.txt", - # "eu_german.txt", - # "eu_italian.txt", - # "eu_spanish.txt", - # "japanese.txt", - # "korean.txt", - # "russian.txt", - # "simplified_chinese.txt", - # "traditional_chinese.txt", - "us_english.txt", - # "us_french.txt", - # "us_spanish.txt" -} - -def patch_text(editor: PatcherEditor, key: str, value: str): - for text_file in ALL_TEXT_FILES: - text = editor.get_file(f"system/localization/{text_file}", Txt) - text.strings[key] = value - - -def get_text(editor: PatcherEditor, key: str, text_file: str = "us_english.txt") -> str: - text = editor.get_file(f"system/localization/{text_file}", Txt) - return text.strings[key] - - -def apply_text_patches(editor: PatcherEditor, patches: dict[str, str]): - for k, v in patches.items(): - patch_text(editor, k, v) \ No newline at end of file diff --git a/open_samus_returns_rando/validator_with_default.py b/open_samus_returns_rando/validator_with_default.py deleted file mode 100644 index f08ea66..0000000 --- a/open_samus_returns_rando/validator_with_default.py +++ /dev/null @@ -1,21 +0,0 @@ -from jsonschema import Draft7Validator, validators - - -def extend_with_default(validator_class): - validate_properties = validator_class.VALIDATORS["properties"] - - def set_defaults(validator, properties, instance, schema): - for property, subschema in properties.items(): - if "default" in subschema: - instance.setdefault(property, subschema["default"]) - - yield from validate_properties( - validator, properties, instance, schema, - ) - - return validators.extend( - validator_class, {"properties": set_defaults}, - ) - - -DefaultValidatingDraft7Validator = extend_with_default(Draft7Validator) \ No newline at end of file diff --git a/open_samus_returns_rando/version.py b/open_samus_returns_rando/version.py deleted file mode 100644 index ac6a627..0000000 --- a/open_samus_returns_rando/version.py +++ /dev/null @@ -1,5 +0,0 @@ -# coding: utf-8 -# file generated by setuptools_scm -# don't change, don't track in version control -__version__ = version = '0.1.dev18' -__version_tuple__ = version_tuple = (0, 1, 'dev18') diff --git a/pyproject.toml b/pyproject.toml index 5d7d2ce..483d8b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,34 @@ [build-system] -requires = ["setuptools>=44.0.0", "setuptools_scm[toml]>=3.4.3"] +requires = [ + "setuptools>=61.2", + "setuptools_scm[toml]>=3.4.3" +] build-backend = "setuptools.build_meta" +[project] +name = "open_samus_returns_rando" +description = "An open source randomizer patcher for Metroid: Samus Returns." +classifiers = [ + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.9", +] +requires-python = ">=3.9" +dependencies = [ + "mercury-engine-data-structures>=0.23.2", + "jsonschema>=4.0.0", + "ips.py>=0.1.2", +] +dynamic = ["version"] + +[project.readme] +file = "README.md" +content-type = "text/markdown" + +[project.urls] +Homepage = "https://github.com/randovania/open-samus-returns-rando" + [tool.setuptools_scm] local_scheme = "no-local-version" write_to = "open_samus_returns_rando/version.py" \ No newline at end of file diff --git a/tests/test_files/starter_preset_patcher.json b/tests/test_files/starter_preset_patcher.json index c56fb88..3a5a920 100644 --- a/tests/test_files/starter_preset_patcher.json +++ b/tests/test_files/starter_preset_patcher.json @@ -1,12 +1,14 @@ { + "$schema": "../../open_samus_returns_rando/files/schema.json", "starting_location": { "scenario": "s000_surface", "actor": "StartPoint0" }, "starting_items": { - "ITEM_SPECIAL_ENERGY_SCANNING_PULSE": 1, - "ITEM_MAX_SPECIAL_ENERGY": 1000, - "ITEM_WEAPON_MISSILE_MAX": 24 + "ITEM_MAX_LIFE": 99, + "ITEM_WEAPON_MISSILE_MAX": 24, + "ITEM_WEAPON_SUPER_MISSILE_MAX": 0, + "ITEM_WEAPON_POWER_BOMB_MAX": 0 }, "pickups": [ {