diff --git a/README.md b/README.md index 7322441b74..c2fe53576d 100644 --- a/README.md +++ b/README.md @@ -10,28 +10,19 @@ First make sure your dump of the game is clean and supported by Dusk. You can do this by checking the sha1 hash of your dump against this list of supported versions. | Version | sha1 hash | -| ------------ | ---------------------------------------- | +|--------------| ---------------------------------------- | | GameCube USA | 75edd3ddff41f125d1b4ce1a40378f1b565519e7 | +| GameCube PAL | 2601822a488eeb86fb89db16ca8f29c2c953e1ca | ### 2. Download [Dusk](https://github.com/TwilitRealm/dusk/releases) ### 3. Setup the game -#### Windows - Extract the zip folder -- Place your dump of the game into the same folder where you extracted to -- Launch `dusk.exe` +- Launch Dusk +- Select Options, then set the ISO Path to your supported game dump +- Press Start Game to play! -#### macOS -- TODO - -#### Linux -- TODO - -#### iOS -- TODO - -#### android -- TODO +![DuskOptions](assets/dusk_options.png) # Building If you'd like to build Dusk from source, please read the [build instructions](docs/building.md). diff --git a/assets/dusk_options.png b/assets/dusk_options.png new file mode 100644 index 0000000000..4ed4ad7563 Binary files /dev/null and b/assets/dusk_options.png differ diff --git a/files.cmake b/files.cmake index 958e0c69f7..645af00c45 100644 --- a/files.cmake +++ b/files.cmake @@ -1348,6 +1348,7 @@ set(DUSK_FILES src/dusk/game_clock.cpp src/dusk/globals.cpp src/dusk/gyro.cpp + src/dusk/gamepad_color.cpp src/dusk/io.cpp src/dusk/layout.cpp src/dusk/logging.cpp diff --git a/include/d/d_menu_ring.h b/include/d/d_menu_ring.h index acb7747b88..74624eac80 100644 --- a/include/d/d_menu_ring.h +++ b/include/d/d_menu_ring.h @@ -210,6 +210,10 @@ private: f32 mCursorInterpPrevY; f32 mCursorInterpCurrX; f32 mCursorInterpCurrY; + s16 mCursorInterpPrevAngle; + s16 mCursorInterpCurrAngle; + bool mCursorInterpPrevAngular; + bool mCursorInterpCurrAngular; bool mCursorInterpInit; #endif }; diff --git a/include/dusk/gamepad_color.h b/include/dusk/gamepad_color.h new file mode 100644 index 0000000000..c7cfc1e716 --- /dev/null +++ b/include/dusk/gamepad_color.h @@ -0,0 +1,8 @@ +#pragma once + +#ifndef GAMEPAD_COLOR_H +#define GAMEPAD_COLOR_H + +void handleGamepadColor(); + +#endif \ No newline at end of file diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index 0f442aff94..d53476aa91 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -41,7 +41,7 @@ void daAlink_c::handleWolfHowl() { return; } - bool canTransform = false; + bool canHowl = false; if (mLinkAcch.ChkGroundHit() && !checkModeFlg(MODE_PLAYER_FLY) && !checkMagneBootsOn()) { if (!checkForestOldCentury()) { @@ -52,12 +52,17 @@ void daAlink_c::handleWolfHowl() { (checkEventRun() || getMidnaActor()->checkMetamorphoseEnable()) && (checkModeFlg(4) || dComIfGp_checkPlayerStatus0(0, 0x10)))) { - canTransform = true; + canHowl = true; } } } } + if (!canHowl) { + Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0); + return; + } + getWolfHowlMgrP()->setCorrectCurve(9); procWolfHowlDemoInit(); } diff --git a/src/d/d_map_path.cpp b/src/d/d_map_path.cpp index 916bd2c223..8288a2ef9f 100644 --- a/src/d/d_map_path.cpp +++ b/src/d/d_map_path.cpp @@ -237,6 +237,13 @@ void dDrawPath_c::rendering(dDrawPath_c::line_class const* p_line) { if (isDrawType(p_line->field_0x0)) { int width = getLineWidth(p_line->field_0x1); + #if TARGET_PC + f32 height = JUTVideo::getManager()->getRenderHeight() / 448.0f; + if (height > 1.0f) { + width /= 2; + } + #endif + if (width > 0 && p_line->mDataNum >= 2) { GXSetLineWidth(width, GX_TO_ZERO); GXSetTevColor(GX_TEVREG0, *getLineColor(p_line->field_0x0 & 0x3F, p_line->field_0x1)); diff --git a/src/d/d_menu_ring.cpp b/src/d/d_menu_ring.cpp index 4c00781ec1..05dc71bd5f 100644 --- a/src/d/d_menu_ring.cpp +++ b/src/d/d_menu_ring.cpp @@ -190,6 +190,10 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i mCursorInterpPrevY = 0.0f; mCursorInterpCurrX = 0.0f; mCursorInterpCurrY = 0.0f; + mCursorInterpPrevAngle = 0; + mCursorInterpCurrAngle = 0; + mCursorInterpPrevAngular = false; + mCursorInterpCurrAngular = false; mCursorInterpInit = false; #endif for (int i = 0; i < 4; i++) { @@ -639,34 +643,70 @@ void dMenu_Ring_c::_draw() { drawSelectItem(); drawItem2(); #if TARGET_PC + f32 simX = 0.0f; + f32 simY = 0.0f; + bool restoreSimPos = false; if (dusk::frame_interp::is_enabled() && mAlphaRate >= 1.0f) { - f32 cursorX = mpDrawCursor->getPositionX(); - f32 cursorY = mpDrawCursor->getPositionY(); + simX = mpDrawCursor->getPositionX(); + simY = mpDrawCursor->getPositionY(); + + const bool isAngular = (mStatus == STATUS_MOVE) && !mDirectSelectActive; if (dusk::frame_interp::get_ui_tick_pending()) { mCursorInterpPrevX = mCursorInterpCurrX; mCursorInterpPrevY = mCursorInterpCurrY; - mCursorInterpCurrX = cursorX; - mCursorInterpCurrY = cursorY; + mCursorInterpPrevAngle = mCursorInterpCurrAngle; + mCursorInterpPrevAngular = mCursorInterpCurrAngular; - if (!mCursorInterpInit) { + mCursorInterpCurrX = simX; + mCursorInterpCurrY = simY; + mCursorInterpCurrAngle = field_0x66e; + mCursorInterpCurrAngular = isAngular; + + // reset prev = curr for first render pass or + // when angle modes prev/curr differ + // to prevent arrival jitter + if (!mCursorInterpInit || + mCursorInterpPrevAngular != mCursorInterpCurrAngular) { mCursorInterpPrevX = mCursorInterpCurrX; mCursorInterpPrevY = mCursorInterpCurrY; + mCursorInterpPrevAngle = mCursorInterpCurrAngle; + mCursorInterpPrevAngular = mCursorInterpCurrAngular; mCursorInterpInit = true; } } if (mCursorInterpInit) { const f32 step = dusk::frame_interp::get_interpolation_step(); - mpDrawCursor->setPos( - mCursorInterpPrevX + (mCursorInterpCurrX - mCursorInterpPrevX) * step, - mCursorInterpPrevY + (mCursorInterpCurrY - mCursorInterpPrevY) * step - ); + if (mCursorInterpPrevAngular && mCursorInterpCurrAngular) { + const s16 delta = mCursorInterpCurrAngle - mCursorInterpPrevAngle; + const s16 lerpedAngle = mCursorInterpPrevAngle + (s16)(delta * step); + + // yoinked from stick_move_proc() + const f32 x = g_ringHIO.mItemRingPosX + FB_WIDTH_BASE / 2 + + mRingRadiusH * cM_ssin(lerpedAngle); + const f32 y = g_ringHIO.mItemRingPosY + FB_HEIGHT_BASE / 2 + + mRingRadiusV * cM_scos(lerpedAngle); + mpDrawCursor->setPos(x, y); + } else { + mpDrawCursor->setPos( + mCursorInterpPrevX + (mCursorInterpCurrX - mCursorInterpPrevX) * step, + mCursorInterpPrevY + (mCursorInterpCurrY - mCursorInterpPrevY) * step + ); + } + restoreSimPos = true; } } else { mCursorInterpInit = false; } #endif mpDrawCursor->draw(); +#if TARGET_PC + // prevents offsetting at destination on the next frame + // since stick_wait_proc doesn't call setPos and we clobbered mPositionX/Y + if (restoreSimPos) { + mpDrawCursor->setPos(simX, simY); + } +#endif mpItemExplain->trans(mCenterPosX, mCenterPosY); mpItemExplain->draw((J2DOrthoGraph*)grafPort); drawFlag0(); diff --git a/src/d/d_msg_class.cpp b/src/d/d_msg_class.cpp index 37085a6bb9..7af18f0732 100644 --- a/src/d/d_msg_class.cpp +++ b/src/d/d_msg_class.cpp @@ -1987,6 +1987,13 @@ bool jmessage_tSequenceProcessor::do_isReady() { } #endif +#if TARGET_PC + if (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) { + field_0xb2 = 1; + pReference->setSendTimer(0); + } +#endif + if (dComIfGp_checkMesgBgm()) { bool isItemMusicPlaying = true; if (mDoAud_checkPlayingSubBgmFlag() != Z2BGM_ITEM_GET && diff --git a/src/dusk/gamepad_color.cpp b/src/dusk/gamepad_color.cpp new file mode 100644 index 0000000000..cba32da632 --- /dev/null +++ b/src/dusk/gamepad_color.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include + +cXyz currentGamepadColor = {0, 0, 0}; +cXyz finalGamepadColor = {0, 0, 0}; +cXyz additionalGamepadColor = {0, 0, 0}; + +float lerpSpeed = 0.0f; + +const cXyz duskColor = {50, 50, -50}; +const cXyz noColor = {0, 0, 0}; + +cXyz LerpColor(cXyz a, cXyz b, float t) { + return {std::lerp(a.x, b.x, t), std::lerp(a.y, b.y, t), std::lerp(a.z, b.z, t)}; +} + +void FadeLED(cXyz newColor, float speed) { + finalGamepadColor = newColor; + lerpSpeed = speed / 30.0f; +} + +void SetLED(cXyz newColor) { + currentGamepadColor = newColor; + finalGamepadColor = newColor; +} + +void SetGamepadAdditionalColor(cXyz addColor) { + additionalGamepadColor.x = addColor.x; + additionalGamepadColor.y = addColor.y; + additionalGamepadColor.z = addColor.z; +} + +void handleGamepadColor() { + bool setColor = false; + + fopAc_ac_c* zhint = dComIfGp_att_getZHint(); + if (zhint != NULL) { + FadeLED({50, 50, 175}, 2.0f); + setColor = true; + } + + daPy_py_c* player = daPy_getPlayerActorClass(); + daAlink_c* link = daAlink_getAlinkActorClass(); + + if (link != nullptr && !setColor) { + if (link->checkWolf()) { + FadeLED({115, 115, 75}, 5.0f); + setColor = true; + } else { + switch (dComIfGs_getSelectEquipClothes()) { + case dItemNo_WEAR_KOKIRI_e: + FadeLED({0, 100, 0}, 5.0f); + setColor = true; + break; + case dItemNo_WEAR_ZORA_e: + FadeLED({0, 0, 100}, 5.0f); + setColor = true; + break; + case dItemNo_ARMOR_e: + if (link->checkMagicArmorHeavy()) { + FadeLED({5, 100, 100}, 5.0f); + } else { + FadeLED({100, 0, 5}, 5.0f); + } + setColor = true; + break; + case dItemNo_WEAR_CASUAL_e: + FadeLED({235, 230, 115}, 5.0f); + setColor = true; + break; + } + } + } + + if (dKy_darkworld_check()) { + SetGamepadAdditionalColor(duskColor); + } else { + SetGamepadAdditionalColor(noColor); + } + + f32 finalRed = finalGamepadColor.x + additionalGamepadColor.x; + f32 finalGreen = finalGamepadColor.y + additionalGamepadColor.y; + f32 finalBlue = finalGamepadColor.z + additionalGamepadColor.z; + + if (finalRed > 255) + finalRed = 255; + if (finalRed < 0) + finalRed = 0; + + if (finalGreen > 255) + finalGreen = 255; + if (finalGreen < 0) + finalGreen = 0; + + if (finalBlue > 255) + finalBlue = 255; + if (finalBlue < 0) + finalBlue = 0; + + currentGamepadColor = LerpColor(currentGamepadColor, cXyz{finalRed, finalGreen, finalBlue}, lerpSpeed); + PADSetColor(PAD_CHAN0, (u8)currentGamepadColor.x, (u8)currentGamepadColor.y, (u8)currentGamepadColor.z); +} \ No newline at end of file diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 46b277f421..78fc240db4 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -23,6 +23,7 @@ #include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_main.h" #include "tracy/Tracy.hpp" +#include fapGm_HIO_c::fapGm_HIO_c() { mUsingHostIO = true; @@ -734,6 +735,8 @@ static void fapGm_AfterRecord() { } static void duskExecute() { + handleGamepadColor(); + if (mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getTrigX(PAD_1)) { if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { dynamic_cast(link)->handleWolfHowl();