Merge develop-rika -> develop

Merge develop-rika -> develop
This commit is contained in:
Archez 2024-07-11 22:36:55 -04:00 committed by GitHub
commit 57cb5d2b51
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 634 additions and 239 deletions

1
.gitignore vendored
View File

@ -66,3 +66,4 @@ _packages/
/mm/src/boot/build.c
/mm/windows/properties.h
/clang-format.exe

View File

@ -5,11 +5,11 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
project(2s2h VERSION 1.0.1 LANGUAGES C CXX)
project(2s2h VERSION 1.0.2 LANGUAGES C CXX)
include(CMake/2ship-cvars.cmake)
include(CMake/lus-cvars.cmake)
set(PROJECT_BUILD_NAME "Rika Bravo" CACHE STRING "")
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "")
set(PROJECT_BUILD_NAME "Rika Charlie" CACHE STRING "" FORCE)
set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "" FORCE)
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT 2ship)

View File

@ -1,8 +1,82 @@
[comment]: <> (Todo: Make Light Mode Image)
[comment]: <> (Todo: Make Dark Mode Image)
# 2 Ship 2 Harkinian
## Discord
Official Discord: https://discord.com/invite/shipofharkinian
If you're having any trouble after reading through this `README`, feel free ask for help in the 2 Ship 2 Harkinian Support text channels. Please keep in mind that we do not condone piracy.
# Quick Start
2Ship does not include any copyrighted assets. You are required to provide a supported copy of the game.
### 1. Verify your ROM dump
You can verify you have dumped a supported copy of the game by using the compatibility checker at https://2ship.equipment/. If you'd prefer to manually validate your ROM dump, you can cross-reference its `sha1` hash with the hashes [here](docs/supportedHashes.json).
### 2. Download 2 Ship 2 Harkinian from [Releases](https://github.com/HarbourMasters/2Ship2Harkinian/releases)
### 3. Launch the Game!
#### Windows
* Extract the zip
* Launch `2ship.exe`
#### Linux
* Place your supported copy of the game in the same folder as the appimage.
* Execute `2ship.appimage`. You may have to `chmod +x` the appimage via terminal.
#### macOS
* Run `2ship.app`.
* When prompted, select your supported copy of the game.
### 4. Play!
Congratulations, you are now sailing with 2 Ship 2 Harkinian! Have fun!
# Configuration
### Default keyboard configuration
| N64 | A | B | Z | Start | Analog stick | C buttons | D-Pad |
| - | - | - | - | - | - | - | - |
| Keyboard | X | C | Z | Space | WASD | Arrow keys | TFGH |
### Other shortcuts
| Keys | Action |
| - | - |
| F1 | Toggle menubar |
| F11 | Fullscreen |
| Tab | Toggle Alternate assets |
| Ctrl+R | Reset |
### Graphics Backends
Currently, there are three rendering APIs supported: DirectX11 (Windows), OpenGL (all platforms), and Metal (macOS). You can change which API to use in the `Settings` menu of the menubar, which requires a restart. If you're having an issue with crashing, you can change the API in the `2ship2harkinian.json` file by finding the line `"Backend":{`... and changing the `id` value to `3` and set the `Name` to `OpenGL`. `DirectX 11` with id `2` is the default on Windows. `Metal` with id `4` is the default on macOS.
# Custom Assets
Custom assets are packed in `.o2r` or `.otr` files. To use custom assets, place them in the `mods` folder.
If you're interested in creating and/or packing your own custom asset `.o2r`/`.otr` files, check out the following tools:
* [**retro - OTR and O2R generator**](https://github.com/HarbourMasters64/retro)
* [**fast64 - Blender plugin (Note that MM is not fully supported at this time)**](https://github.com/HarbourMasters/fast64)
# Development
### Building
If you want to manually compile 2S2H, please consult the [building instructions](docs/BUILDING.md).
### Playtesting
If you want to playtest a continuous integration build, you can find them at the links below. Keep in mind that these are for playtesting only, and you will likely encounter bugs and possibly crashes.
* [Windows](https://nightly.link/HarbourMasters/2ship2harkinian/workflows/main/develop/2ship-windows.zip)
* [Linux](https://nightly.link/HarbourMasters/2ship2harkinian/workflows/main/develop/2ship-linux.zip)
* [Mac](https://nightly.link/HarbourMasters/2ship2harkinian/workflows/main/develop/2ship-mac.zip)
<a href="https://github.com/Kenix3/libultraship/">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./docs/poweredbylus.darkmode.png">
<img alt="Powered by libultraship" src="./docs/poweredbylus.lightmode.png">
</picture>
</a>

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

View File

@ -1,10 +1,10 @@
[
{
"name": "N64 US",
"name": "NTSC-U 1.0",
"sha1": "d6133ace5afaa0882cf214cf88daba39e266c078"
},
{
"name": "GC US",
"name": "NTSC-U GC",
"sha1": "9743aa026e9269b339eb0e3044cd5830a440c1fd"
}
]
]

View File

@ -57,6 +57,24 @@ static const std::unordered_map<int32_t, const char*> alwaysWinDoggyraceOptions
};
namespace BenGui {
std::shared_ptr<std::vector<Ship::WindowBackend>> availableWindowBackends;
std::unordered_map<Ship::WindowBackend, const char*> availableWindowBackendsMap;
Ship::WindowBackend configWindowBackend;
void UpdateWindowBackendObjects() {
Ship::WindowBackend runningWindowBackend = Ship::Context::GetInstance()->GetWindow()->GetWindowBackend();
int32_t configWindowBackendId = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1);
if (Ship::Context::GetInstance()->GetWindow()->IsAvailableWindowBackend(configWindowBackendId)) {
configWindowBackend = static_cast<Ship::WindowBackend>(configWindowBackendId);
} else {
configWindowBackend = runningWindowBackend;
}
availableWindowBackends = Ship::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends();
for (auto& backend : *availableWindowBackends) {
availableWindowBackendsMap[backend] = windowBackendsMap[backend];
}
}
void DrawMenuBarIcon() {
static bool gameIconLoaded = false;
@ -249,31 +267,17 @@ void DrawSettingsMenu() {
// UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f);
// #endregion */
Ship::WindowBackend runningWindowBackend = Ship::Context::GetInstance()->GetWindow()->GetWindowBackend();
Ship::WindowBackend configWindowBackend;
int32_t configWindowBackendId = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1);
if (Ship::Context::GetInstance()->GetWindow()->IsAvailableWindowBackend(configWindowBackendId)) {
configWindowBackend = static_cast<Ship::WindowBackend>(configWindowBackendId);
} else {
configWindowBackend = runningWindowBackend;
}
auto availableWindowBackends = Ship::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends();
std::unordered_map<Ship::WindowBackend, const char*> availableWindowBackendsMap;
for (auto& backend : *availableWindowBackends) {
availableWindowBackendsMap[backend] = windowBackendsMap[backend];
}
if (UIWidgets::Combobox(
"Renderer API (Needs reload)", &configWindowBackend, availableWindowBackendsMap,
{ .tooltip = "Sets the renderer API used by the game. Requires a relaunch to take effect.",
.disabled = Ship::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1,
.disabled = availableWindowBackends->size() <= 1,
.disabledTooltip = "Only one renderer API is available on this platform." })) {
Ship::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id",
static_cast<int32_t>(configWindowBackend));
Ship::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name",
windowBackendsMap.at(configWindowBackend));
Ship::Context::GetInstance()->GetConfig()->Save();
UpdateWindowBackendObjects();
}
if (Ship::Context::GetInstance()->GetWindow()->CanDisableVerticalSync()) {
@ -811,6 +815,10 @@ void DrawDeveloperToolsMenu() {
}
}
void BenMenuBar::InitElement() {
UpdateWindowBackendObjects();
}
void BenMenuBar::DrawElement() {
if (ImGui::BeginMenuBar()) {
DrawMenuBarIcon();

View File

@ -15,7 +15,7 @@ class BenMenuBar : public Ship::GuiMenuBar {
protected:
void DrawElement() override;
void InitElement() override{};
void InitElement() override;
void UpdateElement() override{};
};
} // namespace BenGui

View File

@ -11,6 +11,8 @@ extern "C" {
#include <macros.h>
#include <variables.h>
#include <functions.h>
#include "overlays/actors/ovl_En_Test4/z_en_test4.h"
extern PlayState* gPlayState;
extern SaveContext gSaveContext;
extern TexturePtr gItemIcons[131];
@ -25,6 +27,9 @@ void PlayerCall_Init(Actor* thisx, PlayState* play);
void PlayerCall_Update(Actor* thisx, PlayState* play);
void PlayerCall_Draw(Actor* thisx, PlayState* play);
void TransitionFade_SetColor(void* thisx, u32 color);
void func_80A42198(EnTest4* thisx);
void func_80A425E4(EnTest4* thisx, PlayState* play);
}
bool safeMode = true;
@ -140,6 +145,174 @@ int setPlayerName(ImGuiInputTextCallbackData* data) {
return 0;
};
EnTest4* FindEnTest4Actor() {
if (gPlayState == NULL) {
return NULL;
}
Actor* enTest4Search = gPlayState->actorCtx.actorLists[ACTORCAT_SWITCH].first;
while (enTest4Search != NULL) {
if (enTest4Search->id == ACTOR_EN_TEST4) {
return (EnTest4*)enTest4Search;
}
enTest4Search = enTest4Search->next;
}
return NULL;
}
void UpdateGameTime(u16 gameTime) {
bool newTimeIsNight = (gameTime > CLOCK_TIME(18, 0)) || (gameTime < CLOCK_TIME(6, 0));
bool prevTimeIsNight = (gSaveContext.save.time > CLOCK_TIME(18, 0)) || (gSaveContext.save.time < CLOCK_TIME(6, 0));
gSaveContext.save.time = gameTime;
if (gPlayState == NULL) {
return;
}
// Clear weather from day 2
gWeatherMode = WEATHER_MODE_CLEAR;
gPlayState->envCtx.lightningState = LIGHTNING_LAST;
// When transitioning over night boundaries, stop the sequences and ask to replay, then respawn actors
if (newTimeIsNight != prevTimeIsNight) {
// AMBIENCE_ID_13 is used to persist a scenes sequence through night, so we shouldn't
// change anything if thats active
if (gPlayState->sequenceCtx.ambienceId != AMBIENCE_ID_13) {
SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_AMBIENCE, 0);
SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM_MAIN, 240);
gSaveContext.seqId = (u8)NA_BGM_DISABLED;
gSaveContext.ambienceId = AMBIENCE_ID_DISABLED;
Environment_PlaySceneSequence(gPlayState);
}
// Kills/Spawns half-day actors
gPlayState->numSetupActors = -gPlayState->numSetupActors;
}
EnTest4* enTest4 = FindEnTest4Actor();
// Update EnTest4 actor to be in sync with the new time
// This ensures that day transitions are not triggered with the change
if (enTest4 != NULL) {
enTest4->unk_146 = gameTime;
enTest4->lastBellTime = gameTime;
enTest4->csIdIndex = newTimeIsNight ? 0 : 1;
// Sets the nextBellTime based on the new current time
if (CURRENT_DAY == 3) {
func_80A42198(enTest4);
} else {
func_80A425E4(enTest4, gPlayState);
}
// Unset any screen scaling from the above funcs
gSaveContext.screenScale = 1000.0f;
gSaveContext.screenScaleFlag = false;
}
}
void DrawTempleClears() {
bool cleared;
bool open;
// Woodfall
cleared = CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE);
if (UIWidgets::Checkbox("Woodfall cleared", &cleared)) {
if (cleared) {
SET_WEEKEVENTREG(WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE);
} else {
CLEAR_WEEKEVENTREG(WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE);
}
}
ImGui::SameLine();
if (cleared) {
open = true;
SET_WEEKEVENTREG(WEEKEVENTREG_20_01);
} else {
open = CHECK_WEEKEVENTREG(WEEKEVENTREG_20_01);
}
if (UIWidgets::Checkbox("Woodfall Open", &open, { .disabled = cleared })) {
if (open) {
SET_WEEKEVENTREG(WEEKEVENTREG_20_01);
} else {
CLEAR_WEEKEVENTREG(WEEKEVENTREG_20_01);
}
}
// Snowhead
cleared = CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_SNOWHEAD_TEMPLE);
if (UIWidgets::Checkbox("Snowhead cleared", &cleared)) {
if (cleared) {
SET_WEEKEVENTREG(WEEKEVENTREG_CLEARED_SNOWHEAD_TEMPLE);
} else {
CLEAR_WEEKEVENTREG(WEEKEVENTREG_CLEARED_SNOWHEAD_TEMPLE);
}
}
ImGui::SameLine();
if (cleared) {
open = true;
SET_WEEKEVENTREG(WEEKEVENTREG_30_01);
} else {
open = CHECK_WEEKEVENTREG(WEEKEVENTREG_30_01);
}
if (UIWidgets::Checkbox("Snowhead Open", &open, { .disabled = cleared })) {
if (open) {
SET_WEEKEVENTREG(WEEKEVENTREG_30_01);
} else {
CLEAR_WEEKEVENTREG(WEEKEVENTREG_30_01);
}
}
// Great Bay
cleared = CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_GREAT_BAY_TEMPLE);
if (UIWidgets::Checkbox("Great Bay cleared", &cleared)) {
if (cleared) {
SET_WEEKEVENTREG(WEEKEVENTREG_CLEARED_GREAT_BAY_TEMPLE);
} else {
CLEAR_WEEKEVENTREG(WEEKEVENTREG_CLEARED_GREAT_BAY_TEMPLE);
}
}
ImGui::SameLine();
if (cleared) {
open = true;
// 53_20 is if the turtle is raised
// 93_08 determines if a long or short cutscene should play
SET_WEEKEVENTREG(WEEKEVENTREG_53_20);
SET_WEEKEVENTREG(WEEKEVENTREG_93_08);
} else {
open = CHECK_WEEKEVENTREG(WEEKEVENTREG_53_20);
}
if (UIWidgets::Checkbox("Great Bay Open", &open, { .disabled = cleared })) {
if (open) {
SET_WEEKEVENTREG(WEEKEVENTREG_53_20);
SET_WEEKEVENTREG(WEEKEVENTREG_93_08);
} else {
CLEAR_WEEKEVENTREG(WEEKEVENTREG_53_20);
CLEAR_WEEKEVENTREG(WEEKEVENTREG_93_08);
}
}
// Stone Tower
// Stone Tower Temple is always open so there is no need to have an option to open it.
cleared = CHECK_WEEKEVENTREG(WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE);
if (UIWidgets::Checkbox("Stone Tower cleared", &cleared)) {
if (cleared) {
SET_WEEKEVENTREG(WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE);
} else {
CLEAR_WEEKEVENTREG(WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE);
}
}
}
void DrawGeneralTab() {
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 3.0f);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8.0f, 8.0f));
@ -182,8 +355,11 @@ void DrawGeneralTab() {
}
hours += std::to_string(curHours);
std::string timeString = hours + ":" + minutes + ampm + " (0x%x)";
ImGui::SliderScalar("##timeInput", ImGuiDataType_U16, &gSaveContext.save.time, &minTime, &maxTime,
timeString.c_str());
u16 gameTime = gSaveContext.save.time;
if (ImGui::SliderScalar("##timeInput", ImGuiDataType_U16, &gameTime, &minTime, &maxTime, timeString.c_str())) {
UpdateGameTime(gameTime);
}
UIWidgets::PopStyleSlider();
ImGui::EndGroup();
@ -233,7 +409,7 @@ void DrawGeneralTab() {
for (size_t i = 0; i < timeSkipAmounts.size(); i++) {
const auto& skip = timeSkipAmounts.at(i);
if (UIWidgets::Button(skip.second, { .color = UIWidgets::Colors::Indigo, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.time += CLOCK_TIME(0, skip.first);
UpdateGameTime(gSaveContext.save.time + CLOCK_TIME(0, skip.first));
}
if (i < timeSkipAmounts.size() - 1) {
ImGui::SameLine();
@ -241,27 +417,33 @@ void DrawGeneralTab() {
}
// Day slider
UIWidgets::PushStyleSlider();
static s32 minDay = 1;
static s32 maxDay = 3;
static s32 minDay = 0;
static s32 maxDay = 4;
if (ImGui::SliderScalar("##dayInput", ImGuiDataType_S32, &gSaveContext.save.day, &minDay, &maxDay, "Day: %d")) {
gSaveContext.save.eventDayCount = CURRENT_DAY;
// Reset the time to the start of day/night
if (gSaveContext.save.time < CLOCK_TIME(6, 0) || gSaveContext.save.time > CLOCK_TIME(18, 0)) {
gSaveContext.save.time = CLOCK_TIME(18, 1);
} else {
gSaveContext.save.time = CLOCK_TIME(6, 1);
}
if (gPlayState != nullptr) {
Interface_NewDay(gPlayState, CURRENT_DAY);
// Inverting setup actors forces actors to kill/respawn for new day
// Inverting setup actors forces half-day actors to kill/respawn for new day
gPlayState->numSetupActors = -gPlayState->numSetupActors;
// Load environment values for new day
func_800FEAF4(&gPlayState->envCtx);
// Clear weather from day 2
gWeatherMode = WEATHER_MODE_CLEAR;
gPlayState->envCtx.lightningState = LIGHTNING_LAST;
}
}
// Time speed slider
// Values are added to R_TIME_SPEED which is generally 3 in normal play state
static s32 minSpeed = -3; // Time frozen
static s32 maxSpeed = 7;
std::string timeSpeedString = "Time Speed: " + std::to_string(gSaveContext.save.timeSpeedOffset + 3);
std::string extraText = "";
if (gSaveContext.save.timeSpeedOffset == 0) {
extraText = " (default)";
} else if (gSaveContext.save.timeSpeedOffset == -2) {
extraText = " (inverted)";
}
std::string timeSpeedString = "Time Speed: " + std::to_string(gSaveContext.save.timeSpeedOffset + 3) + extraText;
ImGui::SliderScalar("##timeSpeedInput", ImGuiDataType_S32, &gSaveContext.save.timeSpeedOffset, &minSpeed, &maxSpeed,
timeSpeedString.c_str());
UIWidgets::PopStyleSlider();
@ -362,24 +544,7 @@ void DrawGeneralTab() {
UIWidgets::Tooltip("To recieve the rewards, set the bank to 199, 999, or 4,999 then deposit a single rupee");
UIWidgets::PopStyleSlider();
// Temple clears
static const std::array<std::pair<int32_t, const char*>, 4> templeClears = { {
{ WEEKEVENTREG_CLEARED_WOODFALL_TEMPLE, "Woodfall Cleared" },
{ WEEKEVENTREG_CLEARED_SNOWHEAD_TEMPLE, "Snowhead Cleared" },
{ WEEKEVENTREG_CLEARED_GREAT_BAY_TEMPLE, "Great Bay Cleared" },
{ WEEKEVENTREG_CLEARED_STONE_TOWER_TEMPLE, "Stone Tower Cleared" },
} };
for (const auto& temple : templeClears) {
bool cleared = CHECK_WEEKEVENTREG(temple.first);
if (UIWidgets::Checkbox(temple.second, &cleared, { .color = UIWidgets::Colors::Gray })) {
if (cleared) {
SET_WEEKEVENTREG(temple.first);
} else {
CLEAR_WEEKEVENTREG(temple.first);
}
}
}
DrawTempleClears();
UIWidgets::Checkbox("Has Tatl", (bool*)&gSaveContext.save.hasTatl, { .color = UIWidgets::Colors::Gray });
UIWidgets::Checkbox("Is Owl Save", (bool*)&gSaveContext.save.isOwlSave, { .color = UIWidgets::Colors::Gray });
@ -420,38 +585,38 @@ void DrawEquipItemMenu(InventorySlot slot) {
if (ImGui::BeginMenu("Equip")) {
if (ImGui::MenuItem("C-Left")) {
gSaveContext.save.saveInfo.equips.buttonItems[CUR_FORM][EQUIP_SLOT_C_LEFT] = currentItemId;
gSaveContext.save.saveInfo.equips.cButtonSlots[CUR_FORM][EQUIP_SLOT_C_LEFT] = slot;
SET_CUR_FORM_BTN_ITEM(EQUIP_SLOT_C_LEFT, currentItemId);
SET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_C_LEFT, slot);
Interface_LoadItemIconImpl(gPlayState, EQUIP_SLOT_C_LEFT);
}
if (ImGui::MenuItem("C-Down")) {
gSaveContext.save.saveInfo.equips.buttonItems[CUR_FORM][EQUIP_SLOT_C_DOWN] = currentItemId;
gSaveContext.save.saveInfo.equips.cButtonSlots[CUR_FORM][EQUIP_SLOT_C_DOWN] = slot;
SET_CUR_FORM_BTN_ITEM(EQUIP_SLOT_C_DOWN, currentItemId);
SET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_C_DOWN, slot);
Interface_LoadItemIconImpl(gPlayState, EQUIP_SLOT_C_DOWN);
}
if (ImGui::MenuItem("C-Right")) {
gSaveContext.save.saveInfo.equips.buttonItems[CUR_FORM][EQUIP_SLOT_C_RIGHT] = currentItemId;
gSaveContext.save.saveInfo.equips.cButtonSlots[CUR_FORM][EQUIP_SLOT_C_RIGHT] = slot;
SET_CUR_FORM_BTN_ITEM(EQUIP_SLOT_C_RIGHT, currentItemId);
SET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_C_RIGHT, slot);
Interface_LoadItemIconImpl(gPlayState, EQUIP_SLOT_C_RIGHT);
}
if (ImGui::MenuItem("D-Right")) {
gSaveContext.save.shipSaveInfo.dpadEquips.dpadItems[CUR_FORM][EQUIP_SLOT_D_RIGHT] = currentItemId;
gSaveContext.save.shipSaveInfo.dpadEquips.dpadSlots[CUR_FORM][EQUIP_SLOT_D_RIGHT] = slot;
DPAD_SET_CUR_FORM_BTN_ITEM(EQUIP_SLOT_D_RIGHT, currentItemId);
DPAD_SET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_D_RIGHT, slot);
Interface_Dpad_LoadItemIconImpl(gPlayState, EQUIP_SLOT_D_RIGHT);
}
if (ImGui::MenuItem("D-Left")) {
gSaveContext.save.shipSaveInfo.dpadEquips.dpadItems[CUR_FORM][EQUIP_SLOT_D_LEFT] = currentItemId;
gSaveContext.save.shipSaveInfo.dpadEquips.dpadSlots[CUR_FORM][EQUIP_SLOT_D_LEFT] = slot;
DPAD_SET_CUR_FORM_BTN_ITEM(EQUIP_SLOT_D_LEFT, currentItemId);
DPAD_SET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_D_LEFT, slot);
Interface_Dpad_LoadItemIconImpl(gPlayState, EQUIP_SLOT_D_LEFT);
}
if (ImGui::MenuItem("D-Down")) {
gSaveContext.save.shipSaveInfo.dpadEquips.dpadItems[CUR_FORM][EQUIP_SLOT_D_DOWN] = currentItemId;
gSaveContext.save.shipSaveInfo.dpadEquips.dpadSlots[CUR_FORM][EQUIP_SLOT_D_DOWN] = slot;
DPAD_SET_CUR_FORM_BTN_ITEM(EQUIP_SLOT_D_DOWN, currentItemId);
DPAD_SET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_D_DOWN, slot);
Interface_Dpad_LoadItemIconImpl(gPlayState, EQUIP_SLOT_D_DOWN);
}
if (ImGui::MenuItem("D-Up")) {
gSaveContext.save.shipSaveInfo.dpadEquips.dpadItems[CUR_FORM][EQUIP_SLOT_D_UP] = currentItemId;
gSaveContext.save.shipSaveInfo.dpadEquips.dpadSlots[CUR_FORM][EQUIP_SLOT_D_UP] = slot;
DPAD_SET_CUR_FORM_BTN_ITEM(EQUIP_SLOT_D_UP, currentItemId);
DPAD_SET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_D_UP, slot);
Interface_Dpad_LoadItemIconImpl(gPlayState, EQUIP_SLOT_D_UP);
}
ImGui::EndMenu();
@ -524,9 +689,13 @@ void DrawSlot(InventorySlot slot) {
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 1.0f, 1.0f, 0.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 1.0f, 1.0f, 0.2f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1.0f, 1.0f, 1.0f, 0.1f));
if (gSaveContext.save.saveInfo.equips.cButtonSlots[CUR_FORM][EQUIP_SLOT_C_LEFT] == slot ||
gSaveContext.save.saveInfo.equips.cButtonSlots[CUR_FORM][EQUIP_SLOT_C_DOWN] == slot ||
gSaveContext.save.saveInfo.equips.cButtonSlots[CUR_FORM][EQUIP_SLOT_C_RIGHT] == slot) {
if (GET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_C_LEFT) == slot || GET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_C_DOWN) == slot ||
GET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_C_RIGHT) == slot ||
(CVarGetInteger("gEnhancements.Dpad.DpadEquips", 0) &&
(DPAD_GET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_D_RIGHT) == slot ||
DPAD_GET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_D_LEFT) == slot ||
DPAD_GET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_D_DOWN) == slot ||
DPAD_GET_CUR_FORM_BTN_SLOT(EQUIP_SLOT_D_UP) == slot))) {
ImGui::PushStyleColor(ImGuiCol_Border, UIWidgets::Colors::White);
} else {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.0f, 1.0f, 1.0f, 0.0f));
@ -1351,7 +1520,7 @@ void DrawFlagsTab() {
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(1.0f, 1.0f));
switch (selectedFlagSection) {
case 0:
case 0: // currentSceneFlags
if (gPlayState == NULL) {
ImGui::Text("Play state is NULL, cannot display scene flags");
break;
@ -1528,7 +1697,7 @@ void DrawFlagsTab() {
UIWidgets::DrawFlagArray32("##collectible3", gPlayState->actorCtx.sceneFlags.collectible[3]);
ImGui::EndGroup();
break;
case 1:
case 1: // weekEventReg
for (int i = 0; i < 100; i++) {
ImGui::PushID(i);
ImGui::Text("%02d", i);
@ -1537,7 +1706,7 @@ void DrawFlagsTab() {
ImGui::PopID();
}
break;
case 2:
case 2: // eventInf
for (int i = 0; i < 8; i++) {
ImGui::PushID(i);
ImGui::Text("%02d", i);
@ -1546,7 +1715,7 @@ void DrawFlagsTab() {
ImGui::PopID();
}
break;
case 3:
case 3: // scenesVisible
if (UIWidgets::Button("All##scenesVisible",
{ .color = UIWidgets::Colors::Gray, .size = UIWidgets::Sizes::Inline })) {
for (int i = 0; i < 7; i++) {
@ -1566,19 +1735,20 @@ void DrawFlagsTab() {
ImGui::PopID();
}
break;
case 4:
if (UIWidgets::Button("All##scenesVisible",
case 4: // owlActivation
if (UIWidgets::Button("All##owlActivationFlags",
{ .color = UIWidgets::Colors::Gray, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.playerData.owlActivationFlags = UINT16_MAX;
}
ImGui::SameLine();
if (UIWidgets::Button("Clear##scenesVisible",
if (UIWidgets::Button("Clear##owlActivationFlags",
{ .color = UIWidgets::Colors::Red, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.playerData.owlActivationFlags = 0;
}
UIWidgets::DrawFlagArray16("##scenesVisible", gSaveContext.save.saveInfo.playerData.owlActivationFlags);
UIWidgets::DrawFlagArray16("##owlActivationFlags",
gSaveContext.save.saveInfo.playerData.owlActivationFlags);
break;
case 5:
case 5: // permanentSceneFlags
ImGui::BeginGroup();
ImGui::AlignTextToFramePadding();
ImGui::Text("chest");
@ -1693,19 +1863,19 @@ void DrawFlagsTab() {
UIWidgets::DrawFlagArray32("##rooms", gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].rooms);
ImGui::EndGroup();
break;
case 6:
case 6: // cycleSceneFlags
ImGui::BeginGroup();
ImGui::AlignTextToFramePadding();
ImGui::Text("chest");
ImGui::SameLine(110);
if (UIWidgets::Button("All##chest",
{ .color = UIWidgets::Colors::Gray, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].chest = UINT32_MAX;
gSaveContext.cycleSceneFlags[selectedScene].chest = UINT32_MAX;
}
ImGui::SameLine();
if (UIWidgets::Button("Clear##chest",
{ .color = UIWidgets::Colors::Red, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].chest = 0;
gSaveContext.cycleSceneFlags[selectedScene].chest = 0;
}
UIWidgets::DrawFlagArray32("##chest", gSaveContext.cycleSceneFlags[selectedScene].chest);
ImGui::EndGroup();
@ -1716,12 +1886,12 @@ void DrawFlagsTab() {
ImGui::SameLine(110);
if (UIWidgets::Button("All##switch0",
{ .color = UIWidgets::Colors::Gray, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].switch0 = UINT32_MAX;
gSaveContext.cycleSceneFlags[selectedScene].switch0 = UINT32_MAX;
}
ImGui::SameLine();
if (UIWidgets::Button("Clear##switch0",
{ .color = UIWidgets::Colors::Red, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].switch0 = 0;
gSaveContext.cycleSceneFlags[selectedScene].switch0 = 0;
}
UIWidgets::DrawFlagArray32("##switch0", gSaveContext.cycleSceneFlags[selectedScene].switch0);
ImGui::EndGroup();
@ -1731,12 +1901,12 @@ void DrawFlagsTab() {
ImGui::SameLine(110);
if (UIWidgets::Button("All##collectible",
{ .color = UIWidgets::Colors::Gray, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].collectible = UINT32_MAX;
gSaveContext.cycleSceneFlags[selectedScene].collectible = UINT32_MAX;
}
ImGui::SameLine();
if (UIWidgets::Button("Clear##collectible",
{ .color = UIWidgets::Colors::Red, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].collectible = 0;
gSaveContext.cycleSceneFlags[selectedScene].collectible = 0;
}
UIWidgets::DrawFlagArray32("##collectible", gSaveContext.cycleSceneFlags[selectedScene].collectible);
ImGui::EndGroup();
@ -1747,12 +1917,12 @@ void DrawFlagsTab() {
ImGui::SameLine(110);
if (UIWidgets::Button("All##switch1",
{ .color = UIWidgets::Colors::Gray, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].switch1 = UINT32_MAX;
gSaveContext.cycleSceneFlags[selectedScene].switch1 = UINT32_MAX;
}
ImGui::SameLine();
if (UIWidgets::Button("Clear##switch1",
{ .color = UIWidgets::Colors::Red, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].switch1 = 0;
gSaveContext.cycleSceneFlags[selectedScene].switch1 = 0;
}
UIWidgets::DrawFlagArray32("##switch1", gSaveContext.cycleSceneFlags[selectedScene].switch1);
ImGui::EndGroup();
@ -1762,12 +1932,12 @@ void DrawFlagsTab() {
ImGui::SameLine(110);
if (UIWidgets::Button("All##clearedRoom",
{ .color = UIWidgets::Colors::Gray, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].clearedRoom = UINT32_MAX;
gSaveContext.cycleSceneFlags[selectedScene].clearedRoom = UINT32_MAX;
}
ImGui::SameLine();
if (UIWidgets::Button("Clear##clearedRoom",
{ .color = UIWidgets::Colors::Red, .size = UIWidgets::Sizes::Inline })) {
gSaveContext.save.saveInfo.permanentSceneFlags[selectedScene].clearedRoom = 0;
gSaveContext.cycleSceneFlags[selectedScene].clearedRoom = 0;
}
UIWidgets::DrawFlagArray32("##clearedRoom", gSaveContext.cycleSceneFlags[selectedScene].clearedRoom);
ImGui::EndGroup();

View File

@ -21,24 +21,26 @@ extern s32 sCameraInterfaceFlags;
static bool sCanFreeLook = false;
void UpdateFreeLookState(Camera* camera) {
if (CAM_MODE_TARGET <= camera->mode && camera->mode <= CAM_MODE_BATTLE) {
sCanFreeLook = false;
}
if (CAM_MODE_FIRSTPERSON <= camera->mode && camera->mode <= CAM_MODE_CLIMBZ) {
sCanFreeLook = false;
}
if (camera->mode == CAM_MODE_HANGZ) {
sCanFreeLook = false;
}
if (CAM_MODE_BOOMERANG <= camera->mode && camera->mode <= CAM_MODE_ZORAFINZ) {
sCanFreeLook = false;
}
if (gPlayState != nullptr && Player_InCsMode(gPlayState)) {
sCanFreeLook = false;
switch (camera->mode) {
case CAM_MODE_BOWARROWZ:
case CAM_MODE_FIRSTPERSON:
case CAM_MODE_FOLLOWBOOMERANG:
case CAM_MODE_ZORAFIN:
case CAM_MODE_FOLLOWTARGET:
case CAM_MODE_TARGET:
case CAM_MODE_TALK:
case CAM_MODE_SLINGSHOT:
case CAM_MODE_BOWARROW:
case CAM_MODE_BATTLE:
case CAM_MODE_DEKUHIDE:
case CAM_MODE_CLIMBZ:
case CAM_MODE_HOOKSHOT:
case CAM_MODE_HANGZ:
case CAM_MODE_DEKUFLYZ:
case CAM_MODE_BOOMERANG:
case CAM_MODE_CHARGEZ:
case CAM_MODE_ZORAFINZ:
sCanFreeLook = false;
}
}
@ -141,6 +143,15 @@ bool Camera_CanFreeLook(Camera* camera) {
if (!sCanFreeLook && (fabsf(camX) >= 15.0f || fabsf(camY) >= 15.0f)) {
sCanFreeLook = true;
}
// Pressing Z will "Reset" Camera
if (CHECK_BTN_ALL(sCamPlayState->state.input[0].press.button, BTN_Z)) {
sCanFreeLook = false;
}
// Reset camera during cutscenes
if (gPlayState != nullptr && Player_InCsMode(gPlayState)) {
sCanFreeLook = false;
}
return sCanFreeLook;
}

View File

@ -19,7 +19,7 @@ void RegisterMoonJumpOnL() {
Player* player = GET_PLAYER(gPlayState);
if (CHECK_BTN_ANY(gPlayState->state.input[0].cur.button, BTN_L)) {
if (player != nullptr && CHECK_BTN_ANY(gPlayState->state.input[0].cur.button, BTN_L)) {
player->actor.velocity.y = 6.34375f;
}
});

View File

@ -7,11 +7,13 @@ extern "C" {
}
SaveInfo saveInfoCopy;
ShipSaveInfo shipSaveInfoCopy;
s32 timeSpeedOffsetCopy = 0;
void RegisterEndOfCycleSaveHooks() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::BeforeEndOfCycleSave>([]() {
memcpy(&saveInfoCopy, &gSaveContext.save.saveInfo, sizeof(SaveInfo));
memcpy(&shipSaveInfoCopy, &gSaveContext.save.shipSaveInfo, sizeof(ShipSaveInfo));
timeSpeedOffsetCopy = gSaveContext.save.timeSpeedOffset;
});
@ -71,14 +73,27 @@ void RegisterEndOfCycleSaveHooks() {
SET_CUR_FORM_BTN_ITEM(j, saveInfoCopy.equips.buttonItems[0][j]);
}
}
for (int j = EQUIP_SLOT_D_RIGHT; j <= EQUIP_SLOT_D_UP; j++) {
if (DPAD_GET_CUR_FORM_BTN_ITEM(j) == ITEM_BOTTLE) {
DPAD_SET_CUR_FORM_BTN_ITEM(j, shipSaveInfoCopy.dpadEquips.dpadItems[0][j]);
}
}
}
if (CVarGetInteger("gEnhancements.Cycle.DoNotResetRazorSword", 0) &&
((saveInfoCopy.equips.equipment & gEquipMasks[EQUIP_TYPE_SWORD]) >> gEquipShifts[EQUIP_TYPE_SWORD]) ==
EQUIP_VALUE_SWORD_RAZOR) {
if (CVarGetInteger("gEnhancements.Cycle.DoNotResetRazorSword", 0)) {
u8 curSword =
(saveInfoCopy.equips.equipment & gEquipMasks[EQUIP_TYPE_SWORD]) >> gEquipShifts[EQUIP_TYPE_SWORD];
SET_EQUIP_VALUE(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_RAZOR);
CUR_FORM_EQUIP(EQUIP_SLOT_B) = ITEM_SWORD_RAZOR;
// Check for razor sword equipped, stolen, or turned into the smithy
if (curSword == EQUIP_VALUE_SWORD_RAZOR ||
(curSword == EQUIP_VALUE_SWORD_NONE &&
((saveInfoCopy.permanentSceneFlags[SCENE_KAJIYA].unk_14 & 4) ||
(((saveInfoCopy.stolenItems & 0xFF000000) >> 0x18) == ITEM_SWORD_RAZOR) ||
(((saveInfoCopy.stolenItems & 0x00FF0000) >> 0x10) == ITEM_SWORD_RAZOR)))) {
SET_EQUIP_VALUE(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_RAZOR);
BUTTON_ITEM_EQUIP(0, EQUIP_SLOT_B) = ITEM_SWORD_RAZOR;
}
}
if (CVarGetInteger("gEnhancements.Cycle.DoNotResetTimeSpeed", 0)) {

View File

@ -40,6 +40,11 @@ void RegisterFastTransformation() {
TransitionFade_SetColor(&gPlayState->unk_18E48, 0x000000);
R_TRANS_FADE_FLASH_ALPHA_STEP = -1;
Player_PlaySfx(GET_PLAYER(gPlayState), NA_SE_SY_TRANSFORM_MASK_FLASH);
// Clear previous mask to prevent crashing with masks being drawn while we switch transformations
if (player->transformation == PLAYER_FORM_HUMAN) {
player->prevMask = PLAYER_MASK_NONE;
}
}
});
}

View File

@ -74,6 +74,13 @@ extern "C" bool SavingEnhancements_CanSave() {
return false;
}
// Not in minigames that set temporary flags
if (CHECK_WEEKEVENTREG(WEEKEVENTREG_08_01) || CHECK_WEEKEVENTREG(WEEKEVENTREG_82_08) ||
CHECK_WEEKEVENTREG(WEEKEVENTREG_90_20) || CHECK_WEEKEVENTREG(WEEKEVENTREG_KICKOUT_WAIT) ||
CHECK_EVENTINF(EVENTINF_34) || CHECK_EVENTINF(EVENTINF_41)) {
return false;
}
return true;
}

View File

@ -23,7 +23,7 @@ typedef enum SkyboxId {
typedef struct SkyboxContext {
/* 0x000 */ View view;
/* 0x168 */ void* staticSegments[2][5];
/* 0x168 */ void* staticSegments[2][6]; // 2S2H [Port] Changed to hold enough pointers to OTR resources
/* 0x178 */ void* paletteStaticSegment;
/* 0x17C */ Gfx (*dListBuf)[150];
/* 0x180 */ Gfx* roomDL;
@ -41,33 +41,6 @@ typedef struct SkyboxContext {
/* 0x225 */ Color_RGB8 env;
} SkyboxContext; // size = 0x228
typedef struct {
char** file;
char* palette;
} SkyboxFiles;
#if 0
typedef struct SkyboxContext {
/* 0x000 */ View view;
/* 0x168 */ void* staticSegments[4];
/* 0x178 */ void* paletteStaticSegment;
/* 0x17C */ Gfx (*dListBuf)[150];
/* 0x180 */ Gfx* roomDL;
/* 0x184 */ Vtx* roomVtx;
/* 0x188 */ DmaRequest unk188;
/* 0x1A8 */ DmaRequest unk1A8;
/* 0x1C8 */ DmaRequest unk1C8;
/* 0x1E8 */ OSMesgQueue loadQueue;
/* 0x200 */ OSMesg loadMsg;
/* 0x204 */ s16 skyboxShouldDraw;
/* 0x208 */ Vec3f rot;
/* 0x214 */ Vec3f eye;
/* 0x220 */ s16 angle;
/* 0x222 */ Color_RGB8 prim;
/* 0x225 */ Color_RGB8 env;
} SkyboxContext; // size = 0x228
#endif
typedef struct struct_801C5F44 {
/* 0x00 */ s32 unk0;
/* 0x04 */ s32 unk4;
@ -88,4 +61,13 @@ void Skybox_Draw(SkyboxContext* skyboxCtx, struct GraphicsContext* gfxCtx, s16 s
f32 z);
void Skybox_Update(SkyboxContext* skyboxCtx);
// #region 2S2H [Port]
typedef enum SkyboxTexturesIndex {
/* 0 */ SKYBOX_TEXTURES_FINE,
/* 1 */ SKYBOX_TEXTURES_CLOUD,
} SkyboxTexturesIndex;
extern TexturePtr sSkyboxTextures[2][6];
// #endregion
#endif

View File

@ -1049,28 +1049,44 @@ void Environment_UpdateSkybox(u8 skyboxId, EnvironmentContext* envCtx, SkyboxCon
if ((envCtx->skybox1Index != skybox1Index) && (envCtx->skyboxDmaState == SKYBOX_DMA_INACTIVE)) {
envCtx->skyboxDmaState = SKYBOX_DMA_TEXTURE1_START;
size = sNormalSkyFiles[skybox1Index].file.vromEnd - sNormalSkyFiles[skybox1Index].file.vromStart;
osCreateMesgQueue(&envCtx->loadQueue, envCtx->loadMsg, ARRAY_COUNT(envCtx->loadMsg));
DmaMgr_SendRequestImpl(&envCtx->dmaRequest, skyboxCtx->staticSegments[0],
sNormalSkyFiles[skybox1Index].file.vromStart, size, 0, &envCtx->loadQueue,
OS_MESG_PTR(NULL));
// size = sNormalSkyFiles[skybox1Index].file.vromEnd - sNormalSkyFiles[skybox1Index].file.vromStart;
// osCreateMesgQueue(&envCtx->loadQueue, envCtx->loadMsg, ARRAY_COUNT(envCtx->loadMsg));
// DmaMgr_SendRequestImpl(&envCtx->dmaRequest, skyboxCtx->staticSegments[0],
// sNormalSkyFiles[skybox1Index].file.vromStart, size, 0, &envCtx->loadQueue,
// OS_MESG_PTR(NULL));
// 2S2h [Port] Bypass DMA request and assign each skybox texture directly to the static segment
for (size_t i = 0; i < ARRAY_COUNTU(skyboxCtx->staticSegments[0]); i++) {
skyboxCtx->staticSegments[0][i] = sSkyboxTextures[skybox1Index][i];
}
envCtx->skybox1Index = skybox1Index;
}
if ((envCtx->skybox2Index != skybox2Index) && (envCtx->skyboxDmaState == SKYBOX_DMA_INACTIVE)) {
envCtx->skyboxDmaState = SKYBOX_DMA_TEXTURE2_START;
size = sNormalSkyFiles[skybox2Index].file.vromEnd - sNormalSkyFiles[skybox2Index].file.vromStart;
osCreateMesgQueue(&envCtx->loadQueue, envCtx->loadMsg, ARRAY_COUNT(envCtx->loadMsg));
DmaMgr_SendRequestImpl(&envCtx->dmaRequest, skyboxCtx->staticSegments[1],
sNormalSkyFiles[skybox2Index].file.vromStart, size, 0, &envCtx->loadQueue,
OS_MESG_PTR(NULL));
// size = sNormalSkyFiles[skybox2Index].file.vromEnd - sNormalSkyFiles[skybox2Index].file.vromStart;
// osCreateMesgQueue(&envCtx->loadQueue, envCtx->loadMsg, ARRAY_COUNT(envCtx->loadMsg));
// DmaMgr_SendRequestImpl(&envCtx->dmaRequest, skyboxCtx->staticSegments[1],
// sNormalSkyFiles[skybox2Index].file.vromStart, size, 0, &envCtx->loadQueue,
// OS_MESG_PTR(NULL));
for (size_t i = 0; i < ARRAY_COUNTU(skyboxCtx->staticSegments[1]); i++) {
skyboxCtx->staticSegments[1][i] = sSkyboxTextures[skybox2Index][i];
}
envCtx->skybox2Index = skybox2Index;
}
if ((envCtx->skyboxDmaState == SKYBOX_DMA_TEXTURE1_START) ||
(envCtx->skyboxDmaState == SKYBOX_DMA_TEXTURE2_START)) {
if (osRecvMesg(&envCtx->loadQueue, NULL, 0) == 0) {
// if (osRecvMesg(&envCtx->loadQueue, NULL, 0) == 0) {
if (true) {
envCtx->skyboxDmaState = SKYBOX_DMA_INACTIVE;
// 2S2H [Port] Since the skybox static segments point to OTR strings, we need to re-create the skybox
// display lists to have the new textures loaded
func_80143148(skyboxCtx, 5);
// #endregion
}
}

View File

@ -5638,12 +5638,7 @@ void Message_Update(PlayState* play) {
case MSGMODE_TEXT_DISPLAYING:
if (msgCtx->textBoxType != TEXTBOX_TYPE_4) {
if ((CHECK_BTN_ALL(input->press.button, BTN_B) ||
// 2S2H [Enhancement] When fast text is on, we want to check if B is held instead of only if it was
// just pressed
(CVarGetInteger("gEnhancements.Dialogue.FastText", 0) &&
CHECK_BTN_ALL(input->cur.button, BTN_B))) &&
!msgCtx->textUnskippable) {
if (CHECK_BTN_ALL(input->press.button, BTN_B) && !msgCtx->textUnskippable) {
msgCtx->textboxSkipped = true;
msgCtx->textDrawPos = msgCtx->decodedTextLen;
} else if (CHECK_BTN_ALL(input->press.button, BTN_A) && !msgCtx->textUnskippable) {
@ -5657,6 +5652,14 @@ void Message_Update(PlayState* play) {
}
msgCtx->textDrawPos++;
}
// 2S2H [Enhancement] When fast text is on, we want to check if B is held instead of only if it was
// just pressed. Has an additional check that the textbox hasnt been skipped already to prevent the
// message from failing to continue.
} else if ((CVarGetInteger("gEnhancements.Dialogue.FastText", 0) &&
CHECK_BTN_ALL(input->cur.button, BTN_B)) &&
!msgCtx->textUnskippable && !msgCtx->textboxSkipped) {
msgCtx->textboxSkipped = true;
msgCtx->textDrawPos = msgCtx->decodedTextLen;
}
} else if (CHECK_BTN_ALL(input->press.button, BTN_A) && (msgCtx->textUnskippable == 0)) {
while (true) {

View File

@ -4325,7 +4325,7 @@ s32 Inventory_ConsumeFairy(PlayState* play) {
}
// #region 2S2H [Dpad]
if (CVarGetInteger("gEnhancements.Dpad.DpadEquips", 0)) {
for (u8 dpadBtn = EQUIP_SLOT_C_LEFT; dpadBtn <= EQUIP_SLOT_C_RIGHT; dpadBtn++) {
for (u8 dpadBtn = EQUIP_SLOT_D_RIGHT; dpadBtn <= EQUIP_SLOT_D_UP; dpadBtn++) {
if (DPAD_GET_CUR_FORM_BTN_ITEM(dpadBtn) == ITEM_FAIRY) {
DPAD_SET_CUR_FORM_BTN_ITEM(dpadBtn, ITEM_BOTTLE);
Interface_Dpad_LoadItemIconImpl(play, dpadBtn);

View File

@ -2194,9 +2194,6 @@ void Play_FillScreen(GameState* thisx, s16 fillScreenOn, u8 red, u8 green, u8 bl
void Play_Init(GameState* thisx) {
PlayState* this = (PlayState*)thisx;
// #region 2S2H [General] Making gPlayState available
gPlayState = this;
// #endregion
GraphicsContext* gfxCtx = this->state.gfxCtx;
s32 pad;
uintptr_t zAlloc;
@ -2230,6 +2227,11 @@ void Play_Init(GameState* thisx) {
return;
}
// #region 2S2H [General] Making gPlayState available
// Setting after the early returns, so that Play_Destroy is registered to unset the ptr later
gPlayState = this;
// #endregion
if ((gSaveContext.nextCutsceneIndex == 0xFFEF) || (gSaveContext.nextCutsceneIndex == 0xFFF0)) {
scene = ((void)0, gSaveContext.save.entrance) >> 9;
spawn = (((void)0, gSaveContext.save.entrance) >> 4) & 0x1F;

View File

@ -2415,7 +2415,7 @@ s32 Player_OverrideLimbDrawGameplayDefault(PlayState* play, s32 limbIndex, Gfx**
if (handIndex != 0) {
handIndex = (handIndex >> 8) - 1;
if (CVarGetInteger("gEnhancements.Fixes.HessCrash", 1)) {
if (handIndex > 2) {
if (handIndex >= 2) {
handIndex = 0;
}
}

View File

@ -12,9 +12,18 @@
RumbleManager gRumbleMgr;
#define RUMBLE_FRAMES_PER_UPDATE (R_UPDATE_RATE > 0 ? R_UPDATE_RATE : 1)
void Rumble_Update(void* arg0) {
RumbleManager_Update(&gRumbleMgr);
PadMgr_RumbleSet(gRumbleMgr.rumbleEnabled);
// BENTODO: Workaround for rumble being too long.
// On hardware, PadMgr_ThreadEntry would run once per VI (60hertz),
// however we do not have OS Threads implemented, and instead opted to execute the PadMgr alongside
// the Graph thread. This means it will run less often when the game is in 20fps or 30fps mode.
// Here we call the rumble manager extra times to simulate updates happening at 60hertz.
for (int i = 0; i < RUMBLE_FRAMES_PER_UPDATE; i++) {
RumbleManager_Update(&gRumbleMgr);
PadMgr_RumbleSet(gRumbleMgr.rumbleEnabled);
}
}
// Used by some bosses (and fishing)

View File

@ -1030,7 +1030,11 @@ void AnimationContext_SetLoadFrame(PlayState* play, PlayerAnimationHeader* anima
// printf("Streaming %s, seg = %08X\n", animPath, linkAnimHeader->segment);
s16* animData = /* ResourceMgr_LoadPlayerAnimByName*/ (animation->segmentVoid);
// 2S2H [Port] sometimes a HESS can set a negative frame value from a negative playback speed. When converted to
// a signed value this will cause a crash due to copying way much data.
if (frame < 0) {
frame = 0;
}
memcpy(ram, (uintptr_t)animData + (((sizeof(Vec3s) * limbCount + 2) * frame)), sizeof(Vec3s) * limbCount + 2);
}
}

View File

@ -3,6 +3,7 @@
#include "assets/misc/skyboxes/d2_cloud_static.h"
#include "assets/misc/skyboxes/d2_fine_static.h"
#include "assets/misc/skyboxes/d2_fine_pal_static.h"
#include "assets/2s2h_assets.h"
u32 D_801C5E30[] = { 0, 0x2000, 0x4000, 0x6000, 0x8000, 0xC000 };
@ -21,18 +22,14 @@ s16 D_801C5EC4[] = {
24, 7, 29, 28, 25, 26, 30, 10, 26, 27, 11, 30, 27, 28, 31, 11, 28, 29, 15, 31,
};
const char* sD2FineStaticTex[] = {
gClearSkybox1Tex, gClearSkybox2Tex, gClearSkybox3Tex, gClearSkybox4Tex, gClearSkybox5Tex,
};
const char* sD2CloudStaticTex[] = {
gCloudySkybox1Tex, gCloudySkybox2Tex, gCloudySkybox3Tex, gCloudySkybox4Tex, gCloudySkybox5Tex,
};
SkyboxFiles skyboxFiles[] = {
// 2S2H [Port] Renamed from files because of conflcit
{ sD2FineStaticTex, gClearSkyboxTlue },
{ sD2CloudStaticTex, gClearSkyboxTlue },
// 2S2H [Port] Skybox textures for our resource manager.
// The last texture is repeated for the top and bottom skybox faces.
TexturePtr sSkyboxTextures[2][6] = {
// d2_fine_static
{ gClearSkybox1Tex, gClearSkybox2Tex, gClearSkybox3Tex, gClearSkybox4Tex, gClearSkybox5Tex, gClearSkybox5Tex },
// d2_cloud_static
{ gCloudySkybox1Tex, gCloudySkybox2Tex, gCloudySkybox3Tex, gCloudySkybox4Tex, gCloudySkybox5Tex,
gCloudySkybox5Tex },
};
s32 func_80142440(SkyboxContext* skyboxCtx, Vtx* roomVtx, s32 arg2, s32 arg3, s32 arg4, s32 arg5, s32 arg6, s32 arg7,
@ -221,25 +218,29 @@ void Skybox_Setup(GameState* gameState, SkyboxContext* skyboxCtx, s16 skyboxId)
// size = SEGMENT_ROM_SIZE(d2_cloud_static);
// segment = (void*)ALIGN8((uintptr_t)skyboxCtx->staticSegments[0] + size);
// DmaMgr_SendRequest0(skyboxCtx->staticSegments[0], SEGMENT_ROM_START(d2_cloud_static), size);
for (size_t i = 0; i < ARRAY_COUNTU(sD2FineStaticTex); i++) {
skyboxCtx->staticSegments[0][i] = sD2FineStaticTex[i];
// 2S2h [Port] Bypass DMA request and assign each skybox texture directly to the static segment
for (size_t i = 0; i < ARRAY_COUNTU(skyboxCtx->staticSegments[0]); i++) {
skyboxCtx->staticSegments[0][i] = sSkyboxTextures[SKYBOX_TEXTURES_CLOUD][i];
}
for (size_t i = 0; i < ARRAY_COUNTU(sD2FineStaticTex); i++) {
skyboxCtx->staticSegments[1][i] = sD2CloudStaticTex[i];
}
skyboxCtx->paletteStaticSegment = gClearSkyboxTlue;
// Send a DMA request for the clear sky texture
// skyboxCtx->staticSegments[1] = segment;
// size = SEGMENT_ROM_SIZE(d2_fine_static);
// segment = (void*)ALIGN8((uintptr_t)segment + size);
// DmaMgr_SendRequest0(skyboxCtx->staticSegments[1], SEGMENT_ROM_START(d2_fine_static), size);
for (size_t i = 0; i < ARRAY_COUNTU(skyboxCtx->staticSegments[1]); i++) {
skyboxCtx->staticSegments[1][i] = sSkyboxTextures[SKYBOX_TEXTURES_FINE][i];
}
// Send a DMA request for the skybox palette
// skyboxCtx->paletteStaticSegment = segment;
// size = SEGMENT_ROM_SIZE(d2_fine_pal_static);
// segment = (void*)ALIGN8((uintptr_t)segment + size);
// ResourceMgr_LoadTexOrDListByName(gClearSkyboxTlue);
////DmaMgr_SendRequest0(skyboxCtx->paletteStaticSegment, SEGMENT_ROM_START(d2_fine_pal_static), size);
// DmaMgr_SendRequest0(skyboxCtx->paletteStaticSegment, SEGMENT_ROM_START(d2_fine_pal_static), size);
skyboxCtx->paletteStaticSegment = gClearSkyboxTlue;
// #endregion
skyboxCtx->prim.r = 145;
skyboxCtx->prim.g = 120;
@ -256,17 +257,18 @@ void Skybox_Setup(GameState* gameState, SkyboxContext* skyboxCtx, s16 skyboxId)
break;
case SKYBOX_2:
// BENTODO: in the original code, this case does nothing
// however this causes skyboxCtx->staticSegments to be 0 which in turn causes
// the draw calls in func_80142440 to crash because of the texture address ends up being 0
// I'm not sure if this is a mm bug or a 2s2h bug
for (size_t i = 0; i < ARRAY_COUNTU(sD2FineStaticTex); i++) {
skyboxCtx->staticSegments[0][i] = sD2FineStaticTex[i];
// #region 2S2H [Port] In the original code, this case does nothing
// however because we changed skyboxCtx->staticSegments to be pointers to OTR strings
// the draw calls in func_80142440 will crash because NULL being passed to the renderer.
// Here we set the segments to point to the empty texture to prevent the crash
for (size_t i = 0; i < ARRAY_COUNTU(skyboxCtx->staticSegments[0]); i++) {
skyboxCtx->staticSegments[0][i] = gEmptyTexture;
}
for (size_t i = 0; i < ARRAY_COUNTU(sD2FineStaticTex); i++) {
skyboxCtx->staticSegments[1][i] = sD2CloudStaticTex[i];
for (size_t i = 0; i < ARRAY_COUNTU(skyboxCtx->staticSegments[1]); i++) {
skyboxCtx->staticSegments[1][i] = gEmptyTexture;
}
skyboxCtx->paletteStaticSegment = gClearSkyboxTlue;
skyboxCtx->paletteStaticSegment = gEmptyTexture;
// #endregion
break;
default:
@ -282,59 +284,70 @@ void func_80143324(PlayState* play, SkyboxContext* skyboxCtx, s16 skyboxId) {
osCreateMesgQueue(&skyboxCtx->loadQueue, &skyboxCtx->loadMsg, 1);
if (play->envCtx.skybox1Index == 0) {
for (size_t i = 0; i < ARRAY_COUNTU(sD2FineStaticTex); i++) {
skyboxCtx->staticSegments[0][i] = sD2FineStaticTex[i];
}
//// Send a DMA request for the clear sky texture
// Send a DMA request for the clear sky texture
// size = SEGMENT_ROM_SIZE(d2_fine_static);
//
// DmaMgr_SendRequestImpl(&skyboxCtx->unk188, skyboxCtx->staticSegments[0],
// SEGMENT_ROM_START(d2_fine_static), size, 0, &skyboxCtx->loadQueue, NULL);
} else {
for (size_t i = 0; i < ARRAY_COUNTU(sD2FineStaticTex); i++) {
skyboxCtx->staticSegments[0][i] = sD2CloudStaticTex[i];
// 2S2h [Port] Bypass DMA request and assign each skybox texture directly to the static segment
for (size_t i = 0; i < ARRAY_COUNTU(skyboxCtx->staticSegments[0]); i++) {
skyboxCtx->staticSegments[0][i] = sSkyboxTextures[SKYBOX_TEXTURES_FINE][i];
}
//// Send a DMA request for the cloudy sky texture
} else {
// Send a DMA request for the cloudy sky texture
// size = SEGMENT_ROM_SIZE(d2_cloud_static);
//
// DmaMgr_SendRequestImpl(&skyboxCtx->unk188, skyboxCtx->staticSegments[0],
// SEGMENT_ROM_START(d2_cloud_static), size, 0, &skyboxCtx->loadQueue, NULL);
for (size_t i = 0; i < ARRAY_COUNTU(skyboxCtx->staticSegments[0]); i++) {
skyboxCtx->staticSegments[0][i] = sSkyboxTextures[SKYBOX_TEXTURES_CLOUD][i];
}
}
osRecvMesg(&skyboxCtx->loadQueue, NULL, OS_MESG_BLOCK);
osCreateMesgQueue(&skyboxCtx->loadQueue, &skyboxCtx->loadMsg, 1);
if (play->envCtx.skybox2Index == 0) {
for (size_t i = 0; i < ARRAY_COUNTU(sD2FineStaticTex); i++) {
skyboxCtx->staticSegments[1][i] = sD2FineStaticTex[i];
}
// Send a DMA request for the clear sky texture
// size = SEGMENT_ROM_SIZE(d2_fine_static);
//
// DmaMgr_SendRequestImpl(&skyboxCtx->unk1A8, skyboxCtx->staticSegments[1],
// SEGMENT_ROM_START(d2_fine_static), size, 0, &skyboxCtx->loadQueue, NULL);
} else {
for (size_t i = 0; i < ARRAY_COUNTU(sD2FineStaticTex); i++) {
skyboxCtx->staticSegments[1][i] = sD2CloudStaticTex[i];
for (size_t i = 0; i < ARRAY_COUNTU(skyboxCtx->staticSegments[1]); i++) {
skyboxCtx->staticSegments[1][i] = sSkyboxTextures[SKYBOX_TEXTURES_FINE][i];
}
} else {
// Send a DMA request for the cloudy sky texture
// size = SEGMENT_ROM_SIZE(d2_cloud_static);
//
// DmaMgr_SendRequestImpl(&skyboxCtx->unk1A8, skyboxCtx->staticSegments[1],
// SEGMENT_ROM_START(d2_cloud_static), size, 0, &skyboxCtx->loadQueue, NULL);
for (size_t i = 0; i < ARRAY_COUNTU(skyboxCtx->staticSegments[1]); i++) {
skyboxCtx->staticSegments[1][i] = sSkyboxTextures[SKYBOX_TEXTURES_CLOUD][i];
}
}
osRecvMesg(&skyboxCtx->loadQueue, NULL, OS_MESG_BLOCK);
osCreateMesgQueue(&skyboxCtx->loadQueue, &skyboxCtx->loadMsg, 1);
skyboxCtx->paletteStaticSegment = gClearSkyboxTlue;
// size = SEGMENT_ROM_SIZE(d2_fine_pal_static);
//
//// Send a DMA request for the skybox palette
// Send a DMA request for the skybox palette
// DmaMgr_SendRequestImpl(&skyboxCtx->unk1C8, skyboxCtx->paletteStaticSegment,
// SEGMENT_ROM_START(d2_fine_pal_static), size, 0, &skyboxCtx->loadQueue, NULL);
//
// osRecvMesg(&skyboxCtx->loadQueue, NULL, OS_MESG_BLOCK);
osRecvMesg(&skyboxCtx->loadQueue, NULL, OS_MESG_BLOCK);
skyboxCtx->paletteStaticSegment = gClearSkyboxTlue;
// 2S2H [Port] Since the skybox static segments point to OTR strings, we need to re-create the skybox
// display lists to have the new textures loaded
func_80143148(skyboxCtx, 5);
// #endregion
break;

View File

@ -18,6 +18,7 @@ void EnBat_Init(Actor* thisx, PlayState* play);
void EnBat_Destroy(Actor* thisx, PlayState* play);
void EnBat_Update(Actor* thisx, PlayState* play);
void EnBat_Draw(Actor* thisx, PlayState* play);
void EnBat_Reset(void);
s32 EnBat_IsGraveyardOnSecondDay(PlayState* play);
void EnBat_SetupPerch(EnBat* this);
@ -39,6 +40,7 @@ ActorInit En_Bat_InitVars = {
/**/ EnBat_Destroy,
/**/ EnBat_Update,
/**/ EnBat_Draw,
/**/ EnBat_Reset,
};
static ColliderSphereInit sSphereInit = {
@ -560,3 +562,8 @@ void EnBat_Draw(Actor* thisx, PlayState* play) {
this->drawDmgEffFrozenSteamScale, this->drawDmgEffAlpha, this->drawDmgEffType);
}
}
void EnBat_Reset(void) {
sNumberAttacking = 0;
sAlreadySpawned = false;
}

View File

@ -32,6 +32,7 @@
void EnFall_Init(Actor* thisx, PlayState* play);
void EnFall_Destroy(Actor* thisx, PlayState* play);
void EnFall_Update(Actor* thisx, PlayState* play);
void EnFall_Reset(void);
void EnFall_Setup(EnFall* this, PlayState* play);
void EnFall_CrashingMoon_PerformCutsceneActions(EnFall* this, PlayState* play);
@ -73,6 +74,7 @@ ActorInit En_Fall_InitVars = {
/**/ EnFall_Destroy,
/**/ EnFall_Update,
/**/ NULL,
/**/ EnFall_Reset,
};
/**
@ -316,8 +318,10 @@ void EnFall_Setup(EnFall* this, PlayState* play) {
}
}
// 2S2H [Port] Moved static vars out of function scope so they can be cleared in actor reset
static s32 sGiantsCutsceneState = 0;
void EnFall_CrashingMoon_HandleGiantsCutscene(EnFall* this, PlayState* play) {
static s32 sGiantsCutsceneState = 0;
if ((play->sceneId == SCENE_00KEIKOKU) && (gSaveContext.sceneLayer == 1) && (play->csCtx.scriptIndex == 0)) {
switch (sGiantsCutsceneState) {
@ -949,3 +953,7 @@ void EnFall_MoonsTear_Draw(Actor* thisx, PlayState* play) {
CLOSE_DISPS(play->state.gfxCtx);
}
void EnFall_Reset(void) {
sGiantsCutsceneState = 0;
}

View File

@ -15,6 +15,8 @@ void EnNiw_Init(Actor* thisx, PlayState* play);
void EnNiw_Destroy(Actor* thisx, PlayState* play);
void EnNiw_Update(Actor* thisx, PlayState* play);
void EnNiw_Draw(Actor* thisx, PlayState* play);
void EnNiw_Reset(void);
void EnNiw_SetupIdle(EnNiw* this);
void EnNiw_Idle(EnNiw* this, PlayState* play);
void EnNiw_Thrown(EnNiw* this, PlayState* play);
@ -58,6 +60,7 @@ ActorInit En_Niw_InitVars = {
/**/ EnNiw_Destroy,
/**/ EnNiw_Update,
/**/ EnNiw_Draw,
/**/ EnNiw_Reset,
};
static f32 sHeadRotations[] = { 5000.0f, -5000.0f };
@ -1031,3 +1034,7 @@ void EnNiw_DrawFeathers(EnNiw* this, PlayState* play) {
CLOSE_DISPS(gfxCtx);
}
void EnNiw_Reset(void) {
sCuccoStormActive = false;
}

View File

@ -12,6 +12,7 @@
#include "interface/icon_item_gameover_static/icon_item_gameover_static.h"
#include "BenPort.h"
#include "assets/2s2h_assets.h"
// unused
UNK_TYPE D_808158E0[] = {
@ -126,11 +127,20 @@ TexturePtr sHoursLeftTextures[] = {
gDaytelop72HoursNESTex,
gDaytelop48HoursNESTex,
gDaytelop24HoursNESTex,
// 2S2H [Port] Added empty texture to support "Dawn of" with the 4th day glitch and prevent crashing
gEmptyTexture,
};
void DayTelop_Draw(DayTelopState* this) {
GraphicsContext* gfxCtx = this->state.gfxCtx;
// 2S2H [Port] Exit early for day 0 or less to avoid an OOB read on the texture arrays.
// This is only possible when using the save editor while the "Dawn of" screen is up.
if (CURRENT_DAY <= 0) {
return;
}
OPEN_DISPS(gfxCtx);
Gfx_SetupDL39_Opa(this->state.gfxCtx);

View File

@ -20,13 +20,40 @@ void MapSelect_LoadConsoleLogo(MapSelectState* this) {
void MapSelect_LoadGame(MapSelectState* this, u32 entrance, s32 spawn) {
if (gSaveContext.fileNum == 0xFF) {
Sram_InitDebugSave();
// #region 2S2H [Debug] Clear all flags when using debug file slot.
// This is mostly copied from Sram_OpenSave.
for (size_t i = 0; i < ARRAY_COUNT(gSaveContext.eventInf); i++) {
gSaveContext.eventInf[i] = 0;
}
for (size_t i = 0; i < ARRAY_COUNT(gSaveContext.cycleSceneFlags); i++) {
gSaveContext.cycleSceneFlags[i].chest = gSaveContext.save.saveInfo.permanentSceneFlags[i].chest;
gSaveContext.cycleSceneFlags[i].switch0 = gSaveContext.save.saveInfo.permanentSceneFlags[i].switch0;
gSaveContext.cycleSceneFlags[i].switch1 = gSaveContext.save.saveInfo.permanentSceneFlags[i].switch1;
gSaveContext.cycleSceneFlags[i].clearedRoom = gSaveContext.save.saveInfo.permanentSceneFlags[i].clearedRoom;
gSaveContext.cycleSceneFlags[i].collectible = gSaveContext.save.saveInfo.permanentSceneFlags[i].collectible;
}
// #endregion
}
// #region 2S2H [Debug] Clear some potential lingering flags and values
CLEAR_WEEKEVENTREG(WEEKEVENTREG_08_01);
CLEAR_WEEKEVENTREG(WEEKEVENTREG_KICKOUT_WAIT);
CLEAR_WEEKEVENTREG(WEEKEVENTREG_82_08);
CLEAR_WEEKEVENTREG(WEEKEVENTREG_90_20);
CLEAR_EVENTINF(EVENTINF_17);
CLEAR_EVENTINF(EVENTINF_34);
CLEAR_EVENTINF(EVENTINF_41);
CLEAR_EVENTINF(EVENTINF_TRIGGER_DAYTELOP);
gSaveContext.save.equippedMask = PLAYER_MASK_NONE;
// #endregion
gSaveContext.buttonStatus[EQUIP_SLOT_B] = BTN_ENABLED;
gSaveContext.buttonStatus[EQUIP_SLOT_C_LEFT] = BTN_ENABLED;
gSaveContext.buttonStatus[EQUIP_SLOT_C_DOWN] = BTN_ENABLED;
gSaveContext.buttonStatus[EQUIP_SLOT_C_RIGHT] = BTN_ENABLED;
// #region 2S2H
// #region 2S2H [Dpad]
gSaveContext.shipSaveContext.dpad.status[EQUIP_SLOT_D_RIGHT] = BTN_ENABLED;
gSaveContext.shipSaveContext.dpad.status[EQUIP_SLOT_D_LEFT] = BTN_ENABLED;
gSaveContext.shipSaveContext.dpad.status[EQUIP_SLOT_D_DOWN] = BTN_ENABLED;

View File

@ -255,7 +255,7 @@ u8 gAreaGsFlags[] = {
// TODO: Also applies to owl warps
s16 sGameOverRectPosY = 66;
void Kaleido_LoadMapNameStatic(void* segment, u32 texIndex) {
void Kaleido_LoadMapNameStatic(void** segment, u32 texIndex) {
static const char* gMapNameStatics[] = {
gMapPointGreatBayENGTex, gMapPointZoraHallENGTex, gMapPointRomaniRanchENGTex,
gMapPointDekuPalaceENGTex, gMapPointWoodfallENGTex, gMapPointClockTownENGTex,
@ -264,17 +264,26 @@ void Kaleido_LoadMapNameStatic(void* segment, u32 texIndex) {
gMapPointSouthernSwampENGTex, gMapPointMountainVillageENGTex, gMapPointMilkRoadENGTex,
gMapPointZoraCapeENGTex,
};
void* tex = ResourceMgr_LoadTexOrDListByName(gMapNameStatics[texIndex]);
memcpy(segment, tex, 0x400);
// 2S2H [Port] Bounds check texture to load to prevent crashes
if (texIndex < ARRAY_COUNTU(gMapNameStatics)) {
*segment = gMapNameStatics[texIndex];
} else {
*segment = gEmptyTexture;
}
// CmpDma_LoadFile(SEGMENT_ROM_START(map_name_static), texIndex, segment, 0x400);
}
//! note: nothing from `map_name_static` is of size `0xA00` in US 1.0
void Kaleido_LoadMapNameStaticLarge(void* segment, u32 texIndex) {
CmpDma_LoadFile(SEGMENT_ROM_START(map_name_static), texIndex, segment, 0xA00);
void Kaleido_LoadMapNameStaticLarge(void** segment, u32 texIndex) {
// 2S2H [Port] Just call the normal map name func since the textures are the same
Kaleido_LoadMapNameStatic(segment, texIndex);
// CmpDma_LoadFile(SEGMENT_ROM_START(map_name_static), texIndex, segment, 0xA00);
}
void Kaleido_LoadItemNameStatic(void* segment, u32 texIndex) {
void Kaleido_LoadItemNameStatic(void** segment, u32 texIndex) {
static const char* gItemNameStatics[] = {
gItemNameOcarinaOfTimeENGTex,
gItemNameHerosBowENGTex,
@ -397,8 +406,14 @@ void Kaleido_LoadItemNameStatic(void* segment, u32 texIndex) {
gItemNameDungeonMapENGTex,
gItemNameStrayFairiesENGTex,
};
void* tex = ResourceMgr_LoadTexOrDListByName(gItemNameStatics[texIndex]);
memcpy(segment, tex, 0x400);
// 2S2H [Port] Bounds check texture to load to prevent crashes
if (texIndex < ARRAY_COUNTU(gItemNameStatics)) {
*segment = gItemNameStatics[texIndex];
} else {
*segment = gEmptyTexture;
}
// CmpDma_LoadFile(SEGMENT_ROM_START(item_name_static), texIndex, segment, 0x400);
}
@ -1264,8 +1279,7 @@ void KaleidoScope_DrawInfoPanel(PlayState* play) {
} else {
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
}
// BENTODO is this the right way to do this?
gSPInvalidateTexCache(POLY_OPA_DISP++, pauseCtx->nameSegment);
POLY_OPA_DISP = Gfx_DrawTexQuad4b(POLY_OPA_DISP, pauseCtx->nameSegment, G_IM_FMT_IA, 128, 16, 0);
}
} else if ((pauseCtx->mainState <= PAUSE_MAIN_STATE_SONG_PLAYBACK) ||
@ -1429,9 +1443,9 @@ void KaleidoScope_UpdateNamePanel(PlayState* play) {
if (pauseCtx->namedItem != PAUSE_ITEM_NONE) {
if ((pauseCtx->pageIndex == PAUSE_MAP) && !sInDungeonScene) {
Kaleido_LoadMapNameStatic(pauseCtx->nameSegment, namedItem);
Kaleido_LoadMapNameStatic(&pauseCtx->nameSegment, namedItem);
} else {
Kaleido_LoadItemNameStatic(pauseCtx->nameSegment, namedItem);
Kaleido_LoadItemNameStatic(&pauseCtx->nameSegment, namedItem);
}
pauseCtx->nameDisplayTimer = 0;
}
@ -1694,7 +1708,7 @@ void KaleidoScope_DrawOwlWarpInfoPanel(PlayState* play) {
} else {
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
}
gSPInvalidateTexCache(POLY_OPA_DISP++, pauseCtx->nameSegment);
POLY_OPA_DISP = Gfx_DrawTexQuad4b(POLY_OPA_DISP, pauseCtx->nameSegment, G_IM_FMT_IA, 128, 16, 0);
}
@ -1715,9 +1729,9 @@ void KaleidoScope_UpdateOwlWarpNamePanel(PlayState* play) {
if (pauseCtx->namedItem != PAUSE_ITEM_NONE) {
if ((pauseCtx->pageIndex == PAUSE_MAP) && !sInDungeonScene) {
Kaleido_LoadMapNameStatic(pauseCtx->nameSegment, texIndex);
Kaleido_LoadMapNameStatic(&pauseCtx->nameSegment, texIndex);
} else {
Kaleido_LoadItemNameStatic(pauseCtx->nameSegment, texIndex);
Kaleido_LoadItemNameStatic(&pauseCtx->nameSegment, texIndex);
}
pauseCtx->nameDisplayTimer = 0;
}
@ -3335,7 +3349,8 @@ void KaleidoScope_Update(PlayState* play) {
pauseCtx->nameSegment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItemLangSegment + size2);
Interface_SetAButtonDoAction(play, DO_ACTION_INFO);
if (((void)0, gSaveContext.worldMapArea) < 0x16) {
Kaleido_LoadMapNameStaticLarge(pauseCtx->nameSegment + 0x400, ((void)0, gSaveContext.worldMapArea));
Kaleido_LoadMapNameStaticLarge(&pauseCtx->nameSegment /* + 0x400 */,
((void)0, gSaveContext.worldMapArea));
}
pauseCtx->iconItemVtxSegment = (void*)ALIGN16((uintptr_t)pauseCtx->nameSegment + 0xA00);
@ -3941,7 +3956,7 @@ void KaleidoScope_Update(PlayState* play) {
pauseCtx->nameSegment = (void*)ALIGN16((uintptr_t)pauseCtx->iconItemLangSegment + size2);
Interface_SetAButtonDoAction(play, DO_ACTION_WARP);
worldMapCursorPoint = pauseCtx->cursorPoint[PAUSE_WORLD_MAP];
Kaleido_LoadMapNameStatic(pauseCtx->nameSegment, worldMapCursorPoint);
Kaleido_LoadMapNameStatic(&pauseCtx->nameSegment, worldMapCursorPoint);
pauseCtx->iconItemVtxSegment = (void*)ALIGN16((uintptr_t)pauseCtx->nameSegment + 0xA00);
DmaMgr_SendRequest0(pauseCtx->iconItemVtxSegment, SEGMENT_ROM_START(icon_item_vtx_static),

View File

@ -1,3 +1,4 @@
Using Namespace System
$url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.6/LLVM-14.0.6-win64.exe"
$llvmInstallerPath = ".\LLVM-14.0.6-win64.exe"
$clangFormatFilePath = ".\clang-format.exe"