Compare commits

..

32 Commits

Author SHA1 Message Date
David Chavez 5ecdc93f8e Enable JIT entitlement 2024-11-04 15:52:15 +01:00
David Chavez 7b9091428c Fixup builds 2024-11-04 14:26:06 +01:00
David Chavez ac7ee4f13e Improve post steps on macOS 2024-11-04 13:55:26 +01:00
dcvz 79d7503704 Add macOS Support 2024-11-04 13:31:04 +01:00
Mr-Wiseguy db4d9c668d Update runtime for heap allocator 2024-10-21 22:25:16 -04:00
LittleCube e862a38135
More vanilla bug fix exports (#497) 2024-10-20 19:35:41 -04:00
LittleCube 0f92410620
Add recomp_after_play_init event (#496)
* fix signature for recomp_set_allow_no_ocarina_tf, add new event recomp_after_play_init

* say initialize instead of construct
2024-10-14 16:53:30 -04:00
LittleCube 21ca074bf7 Add exports for fd anywhere and epona fix patches (#494)
* add exports for fd anywhere and epona fix patches

* use better logic for restoreHudVisibility

* cleanup

* fix a couple edge cases (being sent the bow while riding Epona)
2024-10-14 15:32:32 -04:00
LittleCube 8c8f5b889f Add events and exports for Play_Init (#495) 2024-10-14 15:32:32 -04:00
Mr-Wiseguy e5699e59a1 Update runtime to fix mod section alignment 2024-10-14 15:32:31 -04:00
Mr-Wiseguy fdbdf5edb0 Add custom symbols toml and made non-relocatable versions of original gamestate functions, added base patch for Play_Init 2024-10-14 15:32:31 -04:00
David Chavez aeefc1b6bb chore(ci): Bundle Windows PDBs (#492)
* update runners

* Save PDB

* Build RelWithDebInfo

* Update copy on runners

* Archive PDB separately

* Update copy

* Update PDB archive name
2024-10-14 15:32:31 -04:00
Mr-Wiseguy cd12bc0c20 Disable identical code folding to prevent mods from conflicting with themselves due to merged functions 2024-10-14 15:32:31 -04:00
LittleCube 24c436a572 add exports and events for moon crash save and owl save (#487)
* add exports and events for moon crash save and owl save

* fix recomp_on_owl_save event, add exports and callbacks for save loading

* add more flexible owl events

* add init event

* fix init event to not be terrible

* rename a couple events

* use deletes instead of resets

* use better names, add better annotations

* use full signature for event annotations
2024-10-14 15:32:18 -04:00
Mr-Wiseguy 5a8a1cb2ba Update runtime for custom mod content types and add RT64 texture pack support 2024-10-14 15:29:55 -04:00
Mr-Wiseguy 5dc260f35a Update runtime to add DLL search path, enable strict mode in patch recompilation 2024-10-14 15:29:55 -04:00
Mr-Wiseguy a568261064 Update runtime after merge 2024-10-14 15:29:55 -04:00
Mr-Wiseguy 33806821e2 Update runtime for populating missing runtime pointers in offline compiled mods 2024-10-14 15:29:55 -04:00
Mr-Wiseguy eda1979bf0 Update runtime to fix reference symbols 2024-10-14 15:29:55 -04:00
Mr-Wiseguy 765d1d32f0 Update runtime after merge 2024-10-14 15:29:55 -04:00
Mr-Wiseguy 2463fe4613 Update N64ModernRuntime for mod mips32 relocs and function lookups 2024-10-14 15:29:55 -04:00
Mr-Wiseguy 359f8a9279 Update runtime for mod loading on posix systems, enable all mods temporarily 2024-10-14 15:29:55 -04:00
Mr-Wiseguy 60b8d58e73 Update runtime and print mod authors and dependencies 2024-10-14 15:29:55 -04:00
Mr-Wiseguy ea0cc6e6be Update runtime to have mod list functionality 2024-10-14 15:29:55 -04:00
Mr-Wiseguy e6892248c7 Update runtime for new mod manifest schema 2024-10-14 15:29:54 -04:00
Mr-Wiseguy be70a2a8f1 Parse version number from a string and provide it to the runtime 2024-10-14 15:29:54 -04:00
Mr-Wiseguy 2c23d5f29b Update N64Recomp commit for CI 2024-10-14 15:29:45 -04:00
Mr-Wiseguy ba39a73dca Update modern runtime for mod support, add some exports and events in the patches 2024-10-14 15:28:30 -04:00
Mr-Wiseguy cf1943fe6a Removed shader cache 2024-10-14 15:28:30 -04:00
Mr-Wiseguy 670bd61067 Updated RT64 and enabled RT64 extended RDRAM mode 2024-10-14 15:28:30 -04:00
lkoger 0d0f64e32f
Fix ninja package name in Ubuntu build instructions (#482) 2024-10-06 13:07:26 -04:00
Mr-Wiseguy d99a84f04f Fix strict mode validation failure in latest N64Recomp version and update N64Recomp commit in github workflow 2024-09-06 16:56:58 -04:00
11 changed files with 535 additions and 73 deletions

12
.github/macos/entitlements.plist vendored Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>

View File

@ -17,11 +17,11 @@ on:
VULKAN_SDK_VERSION:
type: string
required: false
default: '1.3.290.0'
default: '1.3.296.0'
MOLTENVK_COMMIT:
type: string
required: false
default: '3b9e335fe8fc8a72cf6099acbd54128889445c0a'
default: ''
secrets:
ZRE_REPO_WITH_PAT:
required: true
@ -30,7 +30,7 @@ concurrency:
cancel-in-progress: true
jobs:
build-linux:
runs-on: ${{ matrix.os }}
runs-on: ${{ format('blaze/compute/{0}-amd64', matrix.os) }}
container:
image: dcvz/n64recomp:ubuntu-18.04
volumes:
@ -116,7 +116,7 @@ jobs:
name: Zelda64Recompiled-AppImage-X64-${{ matrix.type }}
path: Zelda64Recompiled-*.AppImage
build-linux-arm64:
runs-on: ${{ format('blaze/{0}', matrix.os) }}
runs-on: ${{ format('blaze/compute/{0}', matrix.os) }}
strategy:
matrix:
type: [ Debug, Release ]
@ -207,7 +207,7 @@ jobs:
runs-on: windows-latest
strategy:
matrix:
type: [ Debug, Release ]
type: [ Debug, RelWithDebInfo ]
name: windows (${{ matrix.type }})
steps:
- name: Checkout
@ -272,6 +272,7 @@ jobs:
Move-Item -Path "cmake-build/dxcompiler.dll" -Destination "dxcompiler.dll"
Move-Item -Path "cmake-build/dxil.dll" -Destination "dxil.dll"
Move-Item -Path "cmake-build/SDL2.dll" -Destination "SDL2.dll"
Move-Item -Path "cmake-build/Zelda64Recompiled.pdb" -Destination "Zelda64Recompiled.pdb"
Remove-Item -Path "assets/scss" -Recurse -Force
- name: Archive Zelda64Recomp
uses: actions/upload-artifact@v4
@ -284,6 +285,12 @@ jobs:
SDL2.dll
assets/
gamecontrollerdb.txt
- name: Archive Debug Files
uses: actions/upload-artifact@v4
with:
name: Zelda64Recompiled-PDB-${{ matrix.type }}
path: |
Zelda64Recompiled.pdb
build-macos:
runs-on: blaze/macos-14
strategy:
@ -346,16 +353,17 @@ jobs:
- name: Install Vulkan SDK
if: steps.cache-vulkan-sdk.outputs.cache-hit != 'true'
run: |
wget https://sdk.lunarg.com/sdk/download/${{ inputs.VULKAN_SDK_VERSION }}/mac/vulkansdk-macos-${{ inputs.VULKAN_SDK_VERSION }}.dmg
hdiutil attach ./vulkansdk-macos-${{ inputs.VULKAN_SDK_VERSION }}.dmg
sudo /Volumes/vulkansdk-macos-${{ inputs.VULKAN_SDK_VERSION }}/InstallVulkan.app/Contents/MacOS/InstallVulkan --root ~/VulkanSDK/${{ inputs.VULKAN_SDK_VERSION }} --accept-licenses --default-answer --confirm-command install
hdiutil detach /Volumes/vulkansdk-macos-${{ inputs.VULKAN_SDK_VERSION }}
wget https://sdk.lunarg.com/sdk/download/${{ inputs.VULKAN_SDK_VERSION }}/mac/vulkansdk-macos-${{ inputs.VULKAN_SDK_VERSION }}.zip
unzip vulkansdk-macos-${{ inputs.VULKAN_SDK_VERSION }}.zip
sudo InstallVulkan.app/Contents/MacOS/InstallVulkan --root ~/VulkanSDK/${{ inputs.VULKAN_SDK_VERSION }} --accept-licenses --default-answer --confirm-command install
- name: Checkout MoltenVK
if: inputs.MOLTENVK_COMMIT != ''
run: |
git clone https://github.com/KhronosGroup/MoltenVK.git
cd MoltenVK
git checkout ${{ inputs.MOLTENVK_COMMIT }}
- name: Cache MoltenVK Dependencies
if: inputs.MOLTENVK_COMMIT != ''
id: cache-mvk-dependencies
uses: actions/cache@v3
with:
@ -364,16 +372,17 @@ jobs:
!MoltenVK/External/build/Intermediates
key: ${{ runner.os }}-${{ matrix.type }}-${{ hashFiles('MoltenVK/fetchDependencies','MoltenVK/ExternalRevisions/**','MoltenVK/ExternalDependencies.xcodeproj/**','MoltenVK/Scripts/**') }}
- name: Fetch MVK Dependencies (Use Built Cache)
if: steps.cache-mvk-dependencies.outputs.cache-hit == 'true'
if: inputs.MOLTENVK_COMMIT != '' && steps.cache-mvk-dependencies.outputs.cache-hit == 'true'
run: |
cd MoltenVK
./fetchDependencies -v --none
- name: Fetch MVK Dependencies
if: steps.cache-mvk-dependencies.outputs.cache-hit != 'true'
if: inputs.MOLTENVK_COMMIT != '' && steps.cache-mvk-dependencies.outputs.cache-hit != 'true'
run: |
cd MoltenVK
./fetchDependencies -v --macos
- name: Build MoltenVK
if: inputs.MOLTENVK_COMMIT != ''
run: |
cd MoltenVK
make macos

View File

@ -20,7 +20,7 @@ For Linux the instructions for Ubuntu are provided, but you can find the equival
```bash
# For Ubuntu, simply run:
sudo apt-get install cmake ninja libsdl2-dev libgtk-3-dev lld llvm clang-15
sudo apt-get install cmake ninja-build libsdl2-dev libgtk-3-dev lld llvm clang
```
### Windows

View File

@ -275,6 +275,7 @@ if (WIN32)
)
target_sources(Zelda64Recompiled PRIVATE ${CMAKE_SOURCE_DIR}/icons/app.rc)
target_link_libraries(Zelda64Recompiled PRIVATE SDL2)
endif()
if (APPLE)
@ -285,7 +286,7 @@ if (APPLE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
target_link_libraries(Zelda64Recompiled PRIVATE ${CMAKE_DL_LIBS} Threads::Threads)
target_link_libraries(Zelda64Recompiled PRIVATE ${CMAKE_DL_LIBS} Threads::Threads SDL2::SDL2)
# Set bundle properties
set_target_properties(Zelda64Recompiled PROPERTIES
@ -342,46 +343,45 @@ if (APPLE)
# Copy required frameworks to bundle
target_link_libraries(Zelda64Recompiled PRIVATE ${MOLTENVK_PATH} ${VULKAN_LOADER_PATH})
# Define the path to the entitlements file
set(ENTITLEMENTS_FILE ${CMAKE_SOURCE_DIR}/.github/macos/entitlements.plist)
# Ensure the entitlements file exists
if(NOT EXISTS ${ENTITLEMENTS_FILE})
message(FATAL_ERROR "Entitlements file not found at ${ENTITLEMENTS_FILE}")
endif()
# Post-build steps for macOS bundle
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
# Copy and fix frameworks first
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/.github/macos/fixup_bundle.cmake
)
# Copy assets folder to the MacOS folder of the app bundle
set(TEMP_ASSETS_DIR "${CMAKE_BINARY_DIR}/temp_assets")
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets ${TEMP_ASSETS_DIR}
COMMAND ${CMAKE_COMMAND} -E remove_directory ${TEMP_ASSETS_DIR}/scss
COMMAND ${CMAKE_COMMAND} -E copy_directory ${TEMP_ASSETS_DIR} $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/assets
COMMAND ${CMAKE_COMMAND} -E remove_directory ${TEMP_ASSETS_DIR}
)
# Copy all resources
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets ${CMAKE_BINARY_DIR}/temp_assets
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/temp_assets/scss
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_BINARY_DIR}/temp_assets $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/assets
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/temp_assets
# Copy ICD files to macOS Resources folder
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
# Copy Vulkan ICD files
COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/vulkan/icd.d
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/.github/macOS/MoltenVK_icd.json $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/vulkan/icd.d/
)
# Copy controller db file to macOS Resources folder
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
# Copy controller database
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/gamecontrollerdb.txt $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/Resources/
)
# Use install_name_tool to set the RPATH after the build
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
# Set RPATH
COMMAND install_name_tool -add_rpath "@executable_path/../Frameworks/" $<TARGET_BUNDLE_DIR:Zelda64Recompiled>/Contents/MacOS/Zelda64Recompiled
)
# Apply JIT compilation workaround
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
# Apply JIT workaround
COMMAND ${CMAKE_COMMAND} -E echo "Applying JIT compilation workaround"
COMMAND /bin/bash -c "printf '\\x07' | dd of=$<TARGET_FILE:Zelda64Recompiled> bs=1 seek=160 count=1 conv=notrunc"
VERBATIM
)
# Code sign the app bundle with ad-hoc identity
add_custom_command(TARGET Zelda64Recompiled POST_BUILD
COMMAND codesign --deep --force --sign - $<TARGET_BUNDLE_DIR:Zelda64Recompiled>
COMMENT "Code signing the app bundle with ad-hoc identity"
# Finally sign the whole bundle with runtime option and entitlements
COMMAND codesign --deep --force --sign - --entitlements ${ENTITLEMENTS_FILE} $<TARGET_BUNDLE_DIR:Zelda64Recompiled>
COMMENT "Performing post-build steps for macOS bundle"
VERBATIM
)
endif()
@ -416,7 +416,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
message(STATUS "FREETYPE_LIBRARIES = ${FREETYPE_LIBRARIES}")
include_directories(${FREETYPE_LIBRARIES})
target_link_libraries(Zelda64Recompiled PRIVATE ${FREETYPE_LIBRARIES})
target_link_libraries(Zelda64Recompiled PRIVATE ${FREETYPE_LIBRARIES} SDL2::SDL2)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
@ -428,7 +428,6 @@ endif()
target_link_libraries(Zelda64Recompiled PRIVATE
PatchesLib
RecompiledFuncs
SDL2
librecomp
ultramodern
rt64

View File

@ -15,7 +15,7 @@ Zelda 64: Recompiled is a project that uses [N64: Recompiled](https://github.com
<br style="display: none;"/>
_Thank you [Blaze](https://runblaze.dev) for supporting this project by providing Linux ARM64 and Apple Silicon macOS Github Action Runners!_
_Special thanks to [Blaze](https://runblaze.dev) for their support of this project. They provide high-performance Linux (AMD64 & ARM64) and Apple Silicon macOS runners for GitHub Actions, greatly reducing our automated build times._
</div>

@ -1 +1 @@
Subproject commit a4f5ee10c8303474d9028468e84845b192e9297d
Subproject commit 3e39c2ec34340e245a5b7e353560b5a793b9990b

View File

@ -9,7 +9,7 @@ single_file_output = true
use_absolute_symbols = true
# Point the recompiler at the symbol files so that it can resolve relocations during recompilation.
func_reference_syms_file = "Zelda64RecompSyms/mm.us.rev1.syms.toml"
data_reference_syms_files = [ "Zelda64RecompSyms/mm.us.rev1.datasyms.toml", "Zelda64RecompSyms/mm.us.rev1.datasyms_static.toml" ]
data_reference_syms_files = [ "Zelda64RecompSyms/mm.us.rev1.datasyms.toml", "Zelda64RecompSyms/mm.us.rev1.datasyms_static.toml", "patches/custom_syms.toml" ]
# Tell the recompiler to write the output binary. Doing this instead of using objcopy allows the recompiler to patch MIPS32 relocs.
output_binary_path = "patches/patches.bin"
# Do not emit warnings for unpaired LO16 values, as clang produces many of them.

16
patches/custom_syms.toml Normal file
View File

@ -0,0 +1,16 @@
# Custom symbols used for patches.
[[section]]
name = "ABSOLUTE_SYMS"
vram = 0x00000000
size = 0x0
symbols = [
# Alternate references to symbols that would otherwise be relocated
{ name = "Setup_Init_NORELOCATE", vram = 0x80173338 }, # Not relocatable, but here for uniformity with the other gamestate funcs
{ name = "MapSelect_Init_NORELOCATE", vram = 0x80801B4C },
{ name = "ConsoleLogo_Init_NORELOCATE", vram = 0x8080074C },
{ name = "Play_Init_NORELOCATE", vram = 0x8016A2C8 },
{ name = "TitleSetup_Init_NORELOCATE", vram = 0x80803F30 },
{ name = "FileSelect_Init_NORELOCATE", vram = 0x80813C98 },
{ name = "DayTelop_Init_NORELOCATE", vram = 0x80815820 },
]

View File

@ -534,11 +534,31 @@ RECOMP_PATCH void Player_Action_86(Player *this, PlayState *play) {
func_808550D0(play, this, this->unk_B10[4], this->unk_B10[5], (this->transformation == PLAYER_FORM_HUMAN) ? 0 : 1);
}
bool no_bow_epona_fix = false;
// @recomp_export void recomp_set_no_bow_epona_fix(bool new_val): Set whether to enable the fix for getting on Epona without a bow.
RECOMP_EXPORT void recomp_set_no_bow_epona_fix(bool new_val) {
no_bow_epona_fix = new_val;
}
bool h_and_d_no_sword_fix = false;
// @recomp_export void recomp_set_h_and_d_no_sword_fix(bool new_val): Set whether to enable the fix for playing Honey and Darling without a sword.
RECOMP_EXPORT void recomp_set_h_and_d_no_sword_fix(bool new_val) {
h_and_d_no_sword_fix = new_val;
}
extern s16 sPictoState;
extern s16 sPictoPhotoBeingTaken;
extern void* gWorkBuffer;
u16 func_801A5100(void);
#define ON_EPONA (player->stateFlags1 & PLAYER_STATE1_800000)
#define EPONA_FIX_ACTIVE (no_bow_epona_fix && ON_EPONA)
#define AT_H_AND_D (play->sceneId == SCENE_BOWLING)
#define H_AND_D_FIX_ACTIVE (h_and_d_no_sword_fix && AT_H_AND_D)
// @recomp Patched to update status of extra buttons via set_extra_item_slot_status.
RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) {
InterfaceContext* interfaceCtx = &play->interfaceCtx;
@ -548,11 +568,11 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) {
if (gSaveContext.save.cutsceneIndex < 0xFFF0) {
gSaveContext.hudVisibilityForceButtonAlphasByStatus = false;
if ((player->stateFlags1 & PLAYER_STATE1_800000) || CHECK_WEEKEVENTREG(WEEKEVENTREG_08_01) ||
if (ON_EPONA || CHECK_WEEKEVENTREG(WEEKEVENTREG_08_01) ||
(!CHECK_EVENTINF(EVENTINF_41) && (play->unk_1887C >= 2))) {
// Riding Epona OR Honey & Darling minigame OR Horseback balloon minigame OR related to swamp boat
// (non-minigame?)
if ((player->stateFlags1 & PLAYER_STATE1_800000) && (player->currentMask == PLAYER_MASK_BLAST) &&
if (ON_EPONA && (player->currentMask == PLAYER_MASK_BLAST) &&
(gSaveContext.bButtonStatus == BTN_DISABLED)) {
// Riding Epona with blast mask?
restoreHudVisibility = true;
@ -603,16 +623,33 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) {
BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED;
set_extra_item_slot_status(BTN_DISABLED);
} else {
// @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix.
if (EPONA_FIX_ACTIVE) {
if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_BOW) {
BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW;
BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED;
}
} else {
BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW;
}
if (play->unk_1887C >= 2) {
Interface_LoadItemIconImpl(play, EQUIP_SLOT_B);
} else if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_NONE) {
// @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix.
if (EPONA_FIX_ACTIVE) {
gSaveContext.buttonStatus[EQUIP_SLOT_B] = BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B);
BUTTON_STATUS(EQUIP_SLOT_B) = BTN_DISABLED;
} else {
BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_NONE;
}
} else {
Interface_LoadItemIconImpl(play, EQUIP_SLOT_B);
}
// @recomp_use_export_var no_bow_epona_fix: If the B button does not contain a sword, don't disable the UI.
if (!EPONA_FIX_ACTIVE || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) < ITEM_SWORD_KOKIRI ||
BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) > ITEM_SWORD_GILDED) {
BUTTON_STATUS(EQUIP_SLOT_C_LEFT) = BTN_DISABLED;
BUTTON_STATUS(EQUIP_SLOT_C_DOWN) = BTN_DISABLED;
BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED;
@ -620,6 +657,11 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) {
Interface_SetHudVisibility(HUD_VISIBILITY_A_HEARTS_MAGIC_MINIMAP_WITH_OVERWRITE);
}
}
}
if (BUTTON_STATUS(EQUIP_SLOT_B) == BTN_DISABLED && BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) == ITEM_BOW) {
BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED;
}
if (play->transitionMode != TRANS_MODE_OFF) {
Interface_SetHudVisibility(HUD_VISIBILITY_NONE);
@ -640,12 +682,12 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) {
BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED;
set_extra_item_slot_status(BTN_DISABLED);
Interface_SetHudVisibility(HUD_VISIBILITY_A_B_MINIMAP);
} else if (player->stateFlags1 & PLAYER_STATE1_800000) {
} else if (ON_EPONA) {
Interface_SetHudVisibility(HUD_VISIBILITY_A_B_MINIMAP);
}
}
} else {
if (player->stateFlags1 & PLAYER_STATE1_800000) {
if (ON_EPONA) {
Interface_SetHudVisibility(HUD_VISIBILITY_A_B_MINIMAP);
}
@ -657,32 +699,59 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) {
} else {
BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW;
}
if (h_and_d_no_sword_fix) {
BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED;
}
BUTTON_STATUS(EQUIP_SLOT_C_LEFT) = BTN_DISABLED;
BUTTON_STATUS(EQUIP_SLOT_C_DOWN) = BTN_DISABLED;
BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED;
set_extra_item_slot_status(BTN_DISABLED);
} else {
// @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix.
if (EPONA_FIX_ACTIVE) {
if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_BOW) {
BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW;
BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED;
}
} else {
BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_BOW;
}
}
if (play->unk_1887C >= 2) {
Interface_LoadItemIconImpl(play, EQUIP_SLOT_B);
} else if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_NONE) {
} else if (gSaveContext.save.saveInfo.inventory.items[SLOT_BOW] == ITEM_NONE && !H_AND_D_FIX_ACTIVE) {
// @recomp_use_export_var no_bow_epona_fix: Part of the no bow Epona fix.
if (EPONA_FIX_ACTIVE) {
gSaveContext.buttonStatus[EQUIP_SLOT_B] = BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B);
BUTTON_STATUS(EQUIP_SLOT_B) = BTN_DISABLED;
} else {
BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) = ITEM_NONE;
}
} else {
Interface_LoadItemIconImpl(play, EQUIP_SLOT_B);
}
if (BUTTON_STATUS(EQUIP_SLOT_B) == BTN_DISABLED) {
// @recomp_use_export_var no_bow_epona_fix: Don't enable the B button unless it is being used for the bow.
if (!no_bow_epona_fix || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) == ITEM_BOW) {
BUTTON_STATUS(EQUIP_SLOT_B) = BTN_ENABLED;
restoreHudVisibility = true;
}
// @recomp_use_export_var no_bow_epona_fix: Don't restore hud visibility from Epona without a sword.
if (!no_bow_epona_fix || (player->stateFlags1 & PLAYER_STATE1_800000) == 0) {
restoreHudVisibility = true;
}
}
// @recomp_use_export_var no_bow_epona_fix: If the B button does not contain the bow, don't disable the UI.
if ((!no_bow_epona_fix || BUTTON_ITEM_EQUIP(CUR_FORM, EQUIP_SLOT_B) == ITEM_BOW) && !H_AND_D_FIX_ACTIVE) {
BUTTON_STATUS(EQUIP_SLOT_C_LEFT) = BTN_DISABLED;
BUTTON_STATUS(EQUIP_SLOT_C_DOWN) = BTN_DISABLED;
BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED;
set_extra_item_slot_status(BTN_DISABLED);
Interface_SetHudVisibility(HUD_VISIBILITY_A_HEARTS_MAGIC_MINIMAP_WITH_OVERWRITE);
}
if (play->transitionMode != TRANS_MODE_OFF) {
Interface_SetHudVisibility(HUD_VISIBILITY_NONE);
@ -700,8 +769,11 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) {
BUTTON_STATUS(EQUIP_SLOT_C_RIGHT) = BTN_DISABLED;
set_extra_item_slot_status(BTN_DISABLED);
Interface_SetHudVisibility(HUD_VISIBILITY_A_B_MINIMAP);
} else if (player->stateFlags1 & PLAYER_STATE1_800000) {
} else if (ON_EPONA) {
Interface_SetHudVisibility(HUD_VISIBILITY_A_B_MINIMAP);
} else if (H_AND_D_FIX_ACTIVE) {
Interface_LoadItemIconImpl(play, EQUIP_SLOT_B);
Interface_SetHudVisibility(HUD_VISIBILITY_B);
}
}
} else if (sPictoState != PICTO_BOX_STATE_OFF) {
@ -802,6 +874,13 @@ RECOMP_PATCH void Interface_UpdateButtonsPart1(PlayState* play) {
}
}
bool fd_anywhere = false;
// @recomp_export void recomp_set_fd_anywhere(bool new_val): Set whether the Fierce Deity's Mask has scene restrictions.
RECOMP_EXPORT void recomp_set_fd_anywhere(bool new_val) {
fd_anywhere = new_val;
}
/**
* A continuation of the if-else chain from Interface_UpdateButtonsPart1
* Also used directly when opening the pause menu i.e. skips part 1
@ -1181,7 +1260,8 @@ RECOMP_PATCH void Interface_UpdateButtonsPart2(PlayState* play) {
}
} else if (GET_CUR_FORM_BTN_ITEM(i) == ITEM_MASK_FIERCE_DEITY) {
// Fierce Deity's Mask is equipped
if ((play->sceneId != SCENE_MITURIN_BS) && (play->sceneId != SCENE_HAKUGIN_BS) &&
// @recomp_use_export_var fd_anywhere: Allow the player to use the Fierce Deity's Mask anywhere if mods enable it.
if (!fd_anywhere && (play->sceneId != SCENE_MITURIN_BS) && (play->sceneId != SCENE_HAKUGIN_BS) &&
(play->sceneId != SCENE_SEA_BS) && (play->sceneId != SCENE_INISIE_BS) &&
(play->sceneId != SCENE_LAST_BS)) {
if (BUTTON_STATUS(i) != BTN_DISABLED) {

View File

@ -1036,6 +1036,9 @@ RECOMP_PATCH void FileSelect_ConfirmFile(GameState *thisx) {
}
}
// Non-relocatable reference to the original address of Play_Init.
void Play_Init_NORELOCATE(GameState*);
/**
* Load the save for the appropriate file and start the game.
* Update function for `SM_LOAD_GAME`
@ -1060,7 +1063,7 @@ RECOMP_PATCH void FileSelect_LoadGame(GameState* thisx) {
gSaveContext.gameMode = GAMEMODE_NORMAL;
STOP_GAMESTATE(&this->state);
SET_NEXT_GAMESTATE(&this->state, Play_Init, sizeof(PlayState));
SET_NEXT_GAMESTATE(&this->state, Play_Init_NORELOCATE, sizeof(PlayState));
gSaveContext.respawnFlag = 0;
gSaveContext.respawn[RESPAWN_MODE_DOWN].entrance = ENTR_LOAD_OPENING;

View File

@ -1,6 +1,30 @@
#include "play_patches.h"
#include "z64debug_display.h"
#include "input.h"
#include "prevent_bss_reordering.h"
#include "z64.h"
#include "regs.h"
#include "functions.h"
#include "z64vismono.h"
#include "z64visfbuf.h"
#include "buffers.h"
#include "variables.h"
#include "macros.h"
#include "buffers.h"
#include "idle.h"
#include "sys_cfb.h"
#include "z64bombers_notebook.h"
#include "z64quake.h"
#include "z64rumble.h"
#include "z64shrink_window.h"
#include "z64view.h"
#include "overlays/gamestates/ovl_daytelop/z_daytelop.h"
#include "overlays/gamestates/ovl_opening/z_opening.h"
#include "overlays/gamestates/ovl_file_choose/z_file_select.h"
#include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h"
#include "debug.h"
extern Input D_801F6C18;
@ -98,3 +122,322 @@ RECOMP_PATCH s32 Room_HandleLoadCallbacks(PlayState* play, RoomContext* roomCtx)
return 1;
}
void ZeldaArena_Init(void* start, size_t size);
void Play_SpawnScene(PlayState* this, s32 sceneId, s32 spawn);
void Play_InitMotionBlur(void);
extern s16 sTransitionFillTimer;
extern Input D_801F6C18;
extern TransitionTile sTransitionTile;
extern s32 gTransitionTileState;
extern VisMono sPlayVisMono;
extern Color_RGBA8_u32 gVisMonoColor;
extern VisFbuf sPlayVisFbuf;
extern VisFbuf* sPlayVisFbufInstance;
extern BombersNotebook sBombersNotebook;
extern u8 sBombersNotebookOpen;
extern u8 sMotionBlurStatus;
extern s32 gDbgCamEnabled;
extern u8 D_801D0D54;
extern u8 gPictoPhotoI8[];
extern u8 D_80784600[];
// Non-relocatable references to the original addresses of these game state functions.
void DayTelop_Init_NORELOCATE(GameState*);
void TitleSetup_Init_NORELOCATE(GameState*);
RECOMP_DECLARE_EVENT(recomp_on_play_init(PlayState* this));
RECOMP_DECLARE_EVENT(recomp_after_play_init(PlayState* this));
bool allow_no_ocarina_tf = false;
// @recomp_export void recomp_set_allow_no_ocarina_tf(bool new_val): Set whether to force Termina Field to load normally even if Link has no ocarina.
RECOMP_EXPORT void recomp_set_allow_no_ocarina_tf(bool new_val) {
allow_no_ocarina_tf = new_val;
}
RECOMP_PATCH void Play_Init(GameState* thisx) {
PlayState* this = (PlayState*)thisx;
GraphicsContext* gfxCtx = this->state.gfxCtx;
s32 pad;
uintptr_t zAlloc;
s32 zAllocSize;
Player* player;
s32 i;
s32 spawn;
u8 sceneLayer;
s32 scene;
// @recomp_event recomp_on_play_init(PlayState* this): A new PlayState is being initialized.
recomp_on_play_init(this);
if ((gSaveContext.respawnFlag == -4) || (gSaveContext.respawnFlag == -0x63)) {
if (CHECK_EVENTINF(EVENTINF_TRIGGER_DAYTELOP)) {
CLEAR_EVENTINF(EVENTINF_TRIGGER_DAYTELOP);
STOP_GAMESTATE(&this->state);
// Use non-relocatable reference to DayTelop_Init instead.
SET_NEXT_GAMESTATE(&this->state, DayTelop_Init_NORELOCATE, sizeof(DayTelopState));
return;
}
gSaveContext.unk_3CA7 = 1;
if (gSaveContext.respawnFlag == -0x63) {
gSaveContext.respawnFlag = 2;
}
} else {
gSaveContext.unk_3CA7 = 0;
}
if (gSaveContext.save.entrance == -1) {
gSaveContext.save.entrance = 0;
STOP_GAMESTATE(&this->state);
// Use non-relocatable reference to TitleSetup_Init instead.
SET_NEXT_GAMESTATE(&this->state, TitleSetup_Init_NORELOCATE, sizeof(TitleSetupState));
return;
}
if ((gSaveContext.nextCutsceneIndex == 0xFFEF) || (gSaveContext.nextCutsceneIndex == 0xFFF0)) {
scene = ((void)0, gSaveContext.save.entrance) >> 9;
spawn = (((void)0, gSaveContext.save.entrance) >> 4) & 0x1F;
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_SNOWHEAD_TEMPLE)) {
if (scene == ENTR_SCENE_MOUNTAIN_VILLAGE_WINTER) {
scene = ENTR_SCENE_MOUNTAIN_VILLAGE_SPRING;
} else if (scene == ENTR_SCENE_GORON_VILLAGE_WINTER) {
scene = ENTR_SCENE_GORON_VILLAGE_SPRING;
} else if (scene == ENTR_SCENE_PATH_TO_GORON_VILLAGE_WINTER) {
scene = ENTR_SCENE_PATH_TO_GORON_VILLAGE_SPRING;
} else if ((scene == ENTR_SCENE_SNOWHEAD) || (scene == ENTR_SCENE_PATH_TO_SNOWHEAD) ||
(scene == ENTR_SCENE_PATH_TO_MOUNTAIN_VILLAGE) || (scene == ENTR_SCENE_GORON_SHRINE) ||
(scene == ENTR_SCENE_GORON_RACETRACK)) {
gSaveContext.nextCutsceneIndex = 0xFFF0;
}
}
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE)) {
if (scene == ENTR_SCENE_SOUTHERN_SWAMP_POISONED) {
scene = ENTR_SCENE_SOUTHERN_SWAMP_CLEARED;
} else if (scene == ENTR_SCENE_WOODFALL) {
gSaveContext.nextCutsceneIndex = 0xFFF1;
}
}
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE) && (scene == ENTR_SCENE_IKANA_CANYON)) {
gSaveContext.nextCutsceneIndex = 0xFFF2;
}
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_GREAT_BAY_TEMPLE) &&
((scene == ENTR_SCENE_GREAT_BAY_COAST) || (scene == ENTR_SCENE_ZORA_CAPE))) {
gSaveContext.nextCutsceneIndex = 0xFFF0;
}
// "First cycle" Termina Field
// @recomp_use_export_var allow_no_ocarina_tf: Skip loading into "First cycle" Termina Field if mods enable it.
if (!allow_no_ocarina_tf && INV_CONTENT(ITEM_OCARINA_OF_TIME) != ITEM_OCARINA_OF_TIME) {
if ((scene == ENTR_SCENE_TERMINA_FIELD) &&
(((void)0, gSaveContext.save.entrance) != ENTRANCE(TERMINA_FIELD, 10))) {
gSaveContext.nextCutsceneIndex = 0xFFF4;
}
}
//! FAKE:
gSaveContext.save.entrance =
Entrance_Create(((void)0, scene), spawn, ((void)0, gSaveContext.save.entrance) & 0xF);
}
GameState_Realloc(&this->state, 0);
KaleidoManager_Init(this);
ShrinkWindow_Init();
View_Init(&this->view, gfxCtx);
Audio_SetExtraFilter(0);
Quake_Init();
Distortion_Init(this);
for (i = 0; i < ARRAY_COUNT(this->cameraPtrs); i++) {
this->cameraPtrs[i] = NULL;
}
Camera_Init(&this->mainCamera, &this->view, &this->colCtx, this);
Camera_ChangeStatus(&this->mainCamera, CAM_STATUS_ACTIVE);
for (i = 0; i < ARRAY_COUNT(this->subCameras); i++) {
Camera_Init(&this->subCameras[i], &this->view, &this->colCtx, this);
Camera_ChangeStatus(&this->subCameras[i], CAM_STATUS_INACTIVE);
}
this->cameraPtrs[CAM_ID_MAIN] = &this->mainCamera;
this->cameraPtrs[CAM_ID_MAIN]->uid = CAM_ID_MAIN;
this->activeCamId = CAM_ID_MAIN;
Camera_OverwriteStateFlags(&this->mainCamera, CAM_STATE_0 | CAM_STATE_CHECK_WATER | CAM_STATE_2 | CAM_STATE_3 |
CAM_STATE_4 | CAM_STATE_DISABLE_MODE_CHANGE | CAM_STATE_6);
Sram_Alloc(&this->state, &this->sramCtx);
Regs_InitData(this);
Message_Init(this);
GameOver_Init(this);
SoundSource_InitAll(this);
EffFootmark_Init(this);
Effect_Init(this);
EffectSS_Init(this, 100);
CollisionCheck_InitContext(this, &this->colChkCtx);
AnimationContext_Reset(&this->animationCtx);
Cutscene_InitContext(this, &this->csCtx);
if (gSaveContext.nextCutsceneIndex != 0xFFEF) {
gSaveContext.save.cutsceneIndex = gSaveContext.nextCutsceneIndex;
gSaveContext.nextCutsceneIndex = 0xFFEF;
}
if (gSaveContext.save.cutsceneIndex == 0xFFFD) {
gSaveContext.save.cutsceneIndex = 0;
}
if (gSaveContext.nextDayTime != NEXT_TIME_NONE) {
gSaveContext.save.time = gSaveContext.nextDayTime;
gSaveContext.skyboxTime = gSaveContext.nextDayTime;
}
if ((CURRENT_TIME >= CLOCK_TIME(18, 0)) || (CURRENT_TIME < CLOCK_TIME(6, 30))) {
gSaveContext.save.isNight = true;
} else {
gSaveContext.save.isNight = false;
}
func_800EDDB0(this);
if (((gSaveContext.gameMode != GAMEMODE_NORMAL) && (gSaveContext.gameMode != GAMEMODE_TITLE_SCREEN)) ||
(gSaveContext.save.cutsceneIndex >= 0xFFF0)) {
gSaveContext.nayrusLoveTimer = 0;
Magic_Reset(this);
gSaveContext.sceneLayer = (gSaveContext.save.cutsceneIndex & 0xF) + 1;
// Set saved cutscene to 0 so it doesn't immediately play, but instead let the `CutsceneManager` handle it.
gSaveContext.save.cutsceneIndex = 0;
} else {
gSaveContext.sceneLayer = 0;
}
sceneLayer = gSaveContext.sceneLayer;
Play_SpawnScene(
this, Entrance_GetSceneIdAbsolute(((void)0, gSaveContext.save.entrance) + ((void)0, gSaveContext.sceneLayer)),
Entrance_GetSpawnNum(((void)0, gSaveContext.save.entrance) + ((void)0, gSaveContext.sceneLayer)));
KaleidoScopeCall_Init(this);
Interface_Init(this);
if (gSaveContext.nextDayTime != NEXT_TIME_NONE) {
if (gSaveContext.nextDayTime == NEXT_TIME_DAY) {
gSaveContext.save.day++;
gSaveContext.save.eventDayCount++;
gSaveContext.dogIsLost = true;
gSaveContext.nextDayTime = NEXT_TIME_DAY_SET;
} else {
gSaveContext.nextDayTime = NEXT_TIME_NIGHT_SET;
}
}
Play_InitMotionBlur();
R_PAUSE_BG_PRERENDER_STATE = PAUSE_BG_PRERENDER_OFF;
R_PICTO_PHOTO_STATE = PICTO_PHOTO_STATE_OFF;
PreRender_Init(&this->pauseBgPreRender);
PreRender_SetValuesSave(&this->pauseBgPreRender, gCfbWidth, gCfbHeight, NULL, NULL, NULL);
PreRender_SetValues(&this->pauseBgPreRender, gCfbWidth, gCfbHeight, NULL, NULL);
this->unk_18E64 = gWorkBuffer;
this->pictoPhotoI8 = gPictoPhotoI8;
this->unk_18E68 = D_80784600;
this->unk_18E58 = D_80784600;
this->unk_18E60 = D_80784600;
gTransitionTileState = TRANS_TILE_OFF;
this->transitionMode = TRANS_MODE_OFF;
D_801D0D54 = false;
FrameAdvance_Init(&this->frameAdvCtx);
Rand_Seed(osGetTime());
Matrix_Init(&this->state);
this->state.main = Play_Main;
this->state.destroy = Play_Destroy;
this->transitionTrigger = TRANS_TRIGGER_END;
this->worldCoverAlpha = 0;
this->bgCoverAlpha = 0;
this->haltAllActors = false;
this->unk_18844 = false;
if (gSaveContext.gameMode != GAMEMODE_TITLE_SCREEN) {
if (gSaveContext.nextTransitionType == TRANS_NEXT_TYPE_DEFAULT) {
this->transitionType =
(Entrance_GetTransitionFlags(((void)0, gSaveContext.save.entrance) + sceneLayer) >> 7) & 0x7F;
} else {
this->transitionType = gSaveContext.nextTransitionType;
gSaveContext.nextTransitionType = TRANS_NEXT_TYPE_DEFAULT;
}
} else {
this->transitionType = TRANS_TYPE_FADE_BLACK;
}
TransitionFade_Init(&this->unk_18E48);
TransitionFade_SetType(&this->unk_18E48, 3);
TransitionFade_SetColor(&this->unk_18E48, RGBA8(160, 160, 160, 255));
TransitionFade_Start(&this->unk_18E48);
VisMono_Init(&sPlayVisMono);
gVisMonoColor.a = 0;
sPlayVisFbufInstance = &sPlayVisFbuf;
VisFbuf_Init(sPlayVisFbufInstance);
sPlayVisFbufInstance->lodProportion = 0.0f;
sPlayVisFbufInstance->mode = VIS_FBUF_MODE_GENERAL;
sPlayVisFbufInstance->primColor.r = 0;
sPlayVisFbufInstance->primColor.g = 0;
sPlayVisFbufInstance->primColor.b = 0;
sPlayVisFbufInstance->primColor.a = 0;
sPlayVisFbufInstance->envColor.r = 0;
sPlayVisFbufInstance->envColor.g = 0;
sPlayVisFbufInstance->envColor.b = 0;
sPlayVisFbufInstance->envColor.a = 0;
CutsceneFlags_UnsetAll(this);
THA_GetRemaining(&this->state.tha);
zAllocSize = THA_GetRemaining(&this->state.tha);
zAlloc = (uintptr_t)THA_AllocTailAlign16(&this->state.tha, zAllocSize);
//! @bug: Incorrect ALIGN16s
ZeldaArena_Init((void*)((zAlloc + 8) & ~0xF), (zAllocSize - ((zAlloc + 8) & ~0xF)) + zAlloc);
Actor_InitContext(this, &this->actorCtx, this->linkActorEntry);
while (!Room_HandleLoadCallbacks(this, &this->roomCtx)) {}
if ((CURRENT_DAY != 0) && ((this->roomCtx.curRoom.behaviorType1 == ROOM_BEHAVIOR_TYPE1_1) ||
(this->roomCtx.curRoom.behaviorType1 == ROOM_BEHAVIOR_TYPE1_5))) {
Actor_Spawn(&this->actorCtx, this, ACTOR_EN_TEST4, 0.0f, 0.0f, 0.0f, 0, 0, 0, 0);
}
player = GET_PLAYER(this);
Camera_InitFocalActorSettings(&this->mainCamera, &player->actor);
gDbgCamEnabled = false;
if (PLAYER_GET_BG_CAM_INDEX(&player->actor) != 0xFF) {
Camera_ChangeActorCsCamIndex(&this->mainCamera, PLAYER_GET_BG_CAM_INDEX(&player->actor));
}
CutsceneManager_StoreCamera(&this->mainCamera);
Interface_SetSceneRestrictions(this);
Environment_PlaySceneSequence(this);
gSaveContext.seqId = this->sequenceCtx.seqId;
gSaveContext.ambienceId = this->sequenceCtx.ambienceId;
AnimationContext_Update(this, &this->animationCtx);
Cutscene_HandleEntranceTriggers(this);
gSaveContext.respawnFlag = 0;
sBombersNotebookOpen = false;
BombersNotebook_Init(&sBombersNotebook);
// @recomp_event recomp_after_play_init(PlayState* this): The new PlayState has finished initializing.
recomp_after_play_init(this);
}