Merge remote-tracking branch 'origin/main' into feature/autosave

# Conflicts:
#	src/dusk/imgui/ImGuiConsole.cpp
This commit is contained in:
MelonSpeedruns
2026-04-30 14:51:17 -04:00
99 changed files with 3280 additions and 373 deletions
+11
View File
@@ -468,9 +468,20 @@ s16 cLib_targetAngleX(cXyz const* lhs, cXyz const* rhs) {
void cLib_offsetPos(cXyz* pdest, cXyz const* psrc, s16 angle, cXyz const* vec) {
f32 cos = cM_scos(angle);
f32 sin = cM_ssin(angle);
// MWCC loads vec members into registers before writing to pdest; other compilers may not,
// which corrupts results when pdest and vec alias the same memory.
#if !__MWERKS__
f32 vx = vec->x;
f32 vy = vec->y;
f32 vz = vec->z;
pdest->x = psrc->x + (vx * cos + vz * sin);
pdest->y = psrc->y + vy;
pdest->z = psrc->z + (vz * cos - vx * sin);
#else
pdest->x = psrc->x + (vec->x * cos + vec->z * sin);
pdest->y = psrc->y + vec->y;
pdest->z = psrc->z + (vec->z * cos - vec->x * sin);
#endif
}
/**
+16
View File
@@ -5877,6 +5877,11 @@ void daAlink_c::setItemMatrix(int param_0) {
modelCalc(mSheathModel);
int var_r26;
#if AVOID_UB
var_r26 = 0;
#endif
if (!checkNoResetFlg3(FLG3_UNK_4000000)) {
if (mEquipItem == 0x103 || param_0 != 0) {
mSwordModel->setBaseTRMtx(mpLinkModel->getAnmMtx(mLeftItemJntNo));
@@ -18936,11 +18941,20 @@ void daAlink_c::setDrawHand() {
mpLinkHandModel->setBaseTRMtx(mpLinkModel->getBaseTRMtx());
mpLinkHandModel->calc();
#if TARGET_PC
// FRAME INTERP NOTE: Always set these, otherwise the hands occasionally zip to origin.
// Doing it regardless of interpolation being active seems harmless.
mpLinkHandModel->setAnmMtx(1, mpLinkModel->getAnmMtx(9));
mpLinkHandModel->setAnmMtx(2, mpLinkModel->getAnmMtx(0xE));
#endif
if (var_r30 == 0xFE || var_r30 == 0xFB) {
field_0x06d0 = field_0x06d8;
} else {
field_0x06d0 = mpLinkHandModel->getModelData()->getMaterialNodePointer(var_r30)->getShape();
#if !TARGET_PC
mpLinkHandModel->setAnmMtx(1, mpLinkModel->getAnmMtx(9));
#endif
}
if (var_r30 == 0xFB) {
@@ -18959,7 +18973,9 @@ void daAlink_c::setDrawHand() {
field_0x06d4 = field_0x06dc;
} else {
field_0x06d4 = mpLinkHandModel->getModelData()->getMaterialNodePointer(var_r29)->getShape();
#if !TARGET_PC
mpLinkHandModel->setAnmMtx(2, mpLinkModel->getAnmMtx(0xE));
#endif
}
if (var_r29 == 0xFB) {
+13
View File
@@ -8,6 +8,10 @@
#include "d/actor/d_a_horse.h"
#include "d/actor/d_a_crod.h"
#include "d/d_msg_object.h"
#ifdef TARGET_PC
#include "d/actor/d_a_obj_carry.h"
#include "dusk/achievements.h"
#endif
#if DEBUG
#include "d/d_s_menu.h"
@@ -677,6 +681,15 @@ BOOL daAlink_c::checkDamageAction() {
}
setDamagePoint(dmg, at_mtrl == dCcD_MTRL_FIRE || at_mtrl == dCcD_MTRL_ICE, TRUE, 0);
#ifdef TARGET_PC
if (tghit_ac_name == fpcNm_Obj_Carry_e) {
auto* carry = static_cast<daObjCarry_c*>(tghit_ac);
if (carry->prm_chk_type_ironball() && carry->checkCannon()) {
dusk::AchievementSystem::get().signal("iron_ball_hit_player");
}
}
#endif
if (armor_no_dmg && at_mtrl != dCcD_MTRL_ELECTRIC && at_mtrl != dCcD_MTRL_ICE) {
setGuardSe(var_r29);
+10
View File
@@ -23,6 +23,7 @@
#include "d/actor/d_a_npc_tkc.h"
#include <cstring>
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/settings.h"
BOOL daAlink_c::checkEventRun() const {
@@ -4005,6 +4006,15 @@ int daAlink_c::procGanonFinishInit() {
field_0x37c8 = current.pos;
onEndResetFlg1(ERFLG1_SHIELD_BACKBONE);
#if TARGET_PC
if (dusk::getSettings().game.speedrunMode) {
if (dusk::m_speedrunInfo.m_isRunStarted) {
dusk::m_speedrunInfo.stopRun();
}
}
#endif
return 1;
}
+4
View File
@@ -18,6 +18,10 @@ enum {
};
void daAlink_c::hsChainShape_c::draw() {
if (dusk::getSettings().game.superClawshot) {
return;
}
static const int dummy = 0;
daAlink_c* alink = (daAlink_c*)getUserArea();
+60
View File
@@ -17,6 +17,9 @@
#include "Z2AudioLib/Z2Instances.h"
#include "dusk/frame_interpolation.h"
#include "dusk/settings.h"
class daB_GND_HIO_c : public JORReflexible {
public:
daB_GND_HIO_c();
@@ -279,6 +282,30 @@ static int h_nodeCallBack(J3DJoint* i_joint, int param_2) {
return 1;
}
#if TARGET_PC
static void b_gnd_rein_interp_callback(bool isSimFrame, void* pUserWork) {
b_gnd_class* i_this = (b_gnd_class*)pUserWork;
if (!i_this->mReinsInterpPrevValid || !i_this->mReinsInterpCurrValid) {
return;
}
const f32 alpha = dusk::frame_interp::get_interpolation_step();
for (int r = 0; r < 2; r++) {
cXyz* dst = i_this->mHorseReins[r].getPos(0);
for (int i = 0; i < 16; i++) {
const cXyz& p0 = i_this->mReinsInterpPrev[r][i];
const cXyz& p1 = i_this->mReinsInterpCurr[r][i];
dst[i] = p0 + (p1 - p0) * alpha;
}
}
cXyz* dst = i_this->field_0x21e8.getPos(0);
for (int i = 0; i < 2; i++) {
const cXyz& p0 = i_this->mReinsTexInterpPrev[i];
const cXyz& p1 = i_this->mReinsTexInterpCurr[i];
dst[i] = p0 + (p1 - p0) * alpha;
}
}
#endif
static int daB_GND_Draw(b_gnd_class* i_this) {
fopAc_ac_c* a_this = (fopAc_ac_c*)i_this;
@@ -366,6 +393,21 @@ static int daB_GND_Draw(b_gnd_class* i_this) {
i_this->field_0x21e8.update(2, l_color, &a_this->tevStr);
dComIfGd_set3DlineMat(&i_this->field_0x21e8);
#if TARGET_PC
if (dusk::getSettings().game.enableFrameInterpolation) {
if (i_this->mReinsInterpCurrValid) {
memcpy(i_this->mReinsInterpPrev, i_this->mReinsInterpCurr, sizeof(i_this->mReinsInterpCurr));
memcpy(i_this->mReinsTexInterpPrev, i_this->mReinsTexInterpCurr, sizeof(i_this->mReinsTexInterpCurr));
i_this->mReinsInterpPrevValid = true;
}
for (int r = 0; r < 2; r++) {
memcpy(i_this->mReinsInterpCurr[r], i_this->mHorseReins[r].getPos(0), 16 * sizeof(cXyz));
}
memcpy(i_this->mReinsTexInterpCurr, i_this->field_0x21e8.getPos(0), 2 * sizeof(cXyz));
i_this->mReinsInterpCurrValid = true;
dusk::frame_interp::add_interpolation_callback(&b_gnd_rein_interp_callback, i_this);
}
#endif
}
return 1;
@@ -1189,10 +1231,16 @@ static void b_gnd_h_end(b_gnd_class* i_this) {
if (i_this->mDemoCamMode < 32) {
i_this->mDemoCamMode = 32;
#if TARGET_PC
i_this->mDemoCamSyncTicks = 2;
#endif
} else {
i_this->mDemoCamMode = 34;
i_this->mDemoCamTimer = 0;
i_this->mMoveMode = 2;
#if TARGET_PC
i_this->mDemoCamSyncTicks = 2;
#endif
}
}
break;
@@ -2887,6 +2935,9 @@ static void demo_camera(b_gnd_class* i_this) {
cXyz spF0;
s8 sp8 = false;
#if TARGET_PC
const s16 entry_demo_cam_mode = i_this->mDemoCamMode;
#endif
switch (i_this->mDemoCamMode) {
case 0:
break;
@@ -3725,6 +3776,15 @@ static void demo_camera(b_gnd_class* i_this) {
i_this->mDemoCamTimer = 10000;
}
}
#if TARGET_PC
if (entry_demo_cam_mode != i_this->mDemoCamMode) {
i_this->mDemoCamSyncTicks = 2;
}
if (i_this->mDemoCamSyncTicks > 0) {
dusk::frame_interp::request_presentation_sync();
i_this->mDemoCamSyncTicks--;
}
#endif
}
static void anm_se_set(b_gnd_class* i_this) {
+14 -3
View File
@@ -6,6 +6,7 @@
#include "d/dolzel_rel.h" // IWYU pragma: keep
#include "d/actor/d_a_balloon_2D.h"
#include "dusk/frame_interpolation.h"
#include "JSystem/J2DGraph/J2DGrafContext.h"
#include "JSystem/J2DGraph/J2DScreen.h"
#include "JSystem/J2DGraph/J2DTextBox.h"
@@ -438,7 +439,12 @@ void daBalloon2D_c::setComboAlpha() {
void daBalloon2D_c::drawAddScore() {
for (s32 i = 19; i >= 0; i--) {
if (field_0x5f8[i].field_0xe != 0) {
field_0x5f8[i].field_0xe--;
#ifdef TARGET_PC
if (dusk::frame_interp::get_ui_tick_pending())
#endif
{
field_0x5f8[i].field_0xe--;
}
s32 score3;
s32 score2;
s32 score = field_0x5f8[i].field_0xc;
@@ -446,8 +452,13 @@ void daBalloon2D_c::drawAddScore() {
u8 local_88 = 0xff;
f32 dVar11 = 30.0f;
f32 dVar9 = 30.0f;
field_0x5f8[i].field_0x0.x += cM_ssin(temp0) * 0.3f;
field_0x5f8[i].field_0x0.y -= 1.0f;
#ifdef TARGET_PC
if (dusk::frame_interp::get_ui_tick_pending())
#endif
{
field_0x5f8[i].field_0x0.x += cM_ssin(temp0) * 0.3f;
field_0x5f8[i].field_0x0.y -= 1.0f;
}
if (field_0x5f8[i].field_0xe < 10) {
f32 fVar5 = field_0x5f8[i].field_0xe / 10.0f;
local_88 = fVar5 * 255.0f;
+29
View File
@@ -12,6 +12,8 @@
#include "d/d_bomb.h"
#include "c/c_damagereaction.h"
#include "Z2AudioLib/Z2Instances.h"
#include "dusk/frame_interpolation.h"
#include "dusk/settings.h"
#define ACTION_STANDBY 0
#define ACTION_WALK1 1
@@ -63,6 +65,22 @@ static void anm_init(e_mb_class* i_this, int i_anmID, f32 i_morf, u8 i_attr, f32
i_this->mAnm = i_anmID;
}
#if TARGET_PC
static void e_mb_rope_interp_callback(bool isSimFrame, void* pUserWork) {
e_mb_class* i_this = (e_mb_class*)pUserWork;
if (!i_this->mRopeInterpPrevValid || !i_this->mRopeInterpCurrValid) {
return;
}
const f32 alpha = dusk::frame_interp::get_interpolation_step();
cXyz* dst = i_this->mRopeMat.getPos(0);
for (int i = 0; i < 16; i++) {
const cXyz& p0 = i_this->mRopeInterpPrev[i];
const cXyz& p1 = i_this->mRopeInterpCurr[i];
dst[i] = p0 + (p1 - p0) * alpha;
}
}
#endif
static int daE_MB_Draw(e_mb_class* i_this) {
fopAc_ac_c* a_this = (fopAc_ac_c*)i_this;
@@ -86,6 +104,17 @@ static int daE_MB_Draw(e_mb_class* i_this) {
static GXColor l_color = {0x14, 0x0F, 0x00, 0xFF};
i_this->mRopeMat.update(16, l_color, &a_this->tevStr);
dComIfGd_set3DlineMat(&i_this->mRopeMat);
#if TARGET_PC
if (dusk::getSettings().game.enableFrameInterpolation) {
if (i_this->mRopeInterpCurrValid) {
memcpy(i_this->mRopeInterpPrev, i_this->mRopeInterpCurr, sizeof(i_this->mRopeInterpCurr));
i_this->mRopeInterpPrevValid = true;
}
memcpy(i_this->mRopeInterpCurr, i_this->mRopeMat.getPos(0), 16 * sizeof(cXyz));
i_this->mRopeInterpCurrValid = true;
dusk::frame_interp::add_interpolation_callback(&e_mb_rope_interp_callback, i_this);
}
#endif
return 1;
}
+58
View File
@@ -14,6 +14,10 @@
#include "f_op/f_op_camera_mng.h"
#include <cstring>
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
class daE_SM2_HIO_c : public fOpAcm_HIO_entry_c {
public:
daE_SM2_HIO_c();
@@ -76,8 +80,62 @@ static int nodeCallBack(J3DJoint* i_joint, int param_1) {
return 1;
}
#if TARGET_PC
static void daE_SM2_interp_callback(bool isSimFrame, void* pUserWork) {
e_sm2_class* i_this = static_cast<e_sm2_class*>(pUserWork);
if (i_this == NULL) {
return;
}
fopAc_ac_c* actor = (fopAc_ac_c*)&i_this->enemy;
g_env_light.settingTevStruct(0, &actor->current.pos, &actor->tevStr);
if (!i_this->isPiece) {
if (i_this->modelMorf == NULL) {
return;
}
J3DModel* model = i_this->modelMorf->getModel();
if (model == NULL) {
return;
}
g_env_light.setLightTevColorType_MAJI(model, &actor->tevStr);
J3DMaterial* material = model->getModelData()->getMaterialNodePointer(0);
material->getTevKColor(1)->r = i_this->color_R;
material->getTevKColor(1)->g = i_this->color_G;
material->getTevKColor(1)->b = i_this->color_B;
material->getTevKColor(1)->a = 217.0f * i_this->color_alpha;
if (i_this->pbtk != NULL) {
i_this->pbtk->entry(model->getModelData());
}
} else {
if (i_this->pieceModelMorf == NULL) {
return;
}
J3DModel* model = i_this->pieceModelMorf->getModel();
if (model == NULL) {
return;
}
J3DMaterial* material = model->getModelData()->getMaterialNodePointer(0);
material->getTevKColor(1)->r = i_this->color_R;
material->getTevKColor(1)->g = i_this->color_G;
material->getTevKColor(1)->b = i_this->color_B;
material->getTevKColor(1)->a = 217.0f * i_this->color_alpha;
g_env_light.setLightTevColorType_MAJI(model, &actor->tevStr);
}
}
#endif
static int daE_SM2_Draw(e_sm2_class* i_this) {
fopAc_ac_c* actor = (fopAc_ac_c*)&i_this->enemy;
#if TARGET_PC
dusk::frame_interp::add_interpolation_callback(&daE_SM2_interp_callback, i_this);
#endif
g_env_light.settingTevStruct(0, &actor->current.pos, &actor->tevStr);
J3DModel* model;
+5
View File
@@ -282,6 +282,11 @@ static void e_th_spin_B(e_th_class* i_this) {
i_this->current.pos += spC;
f32 speed_target;
#if AVOID_UB
speed_target = 0;
#endif
f32 anm_frame = i_this->mpModelMorf->getFrame();
switch (i_this->mMode) {
+3 -3
View File
@@ -1069,7 +1069,7 @@ void daE_YM_c::executeDown() {
if (mAcch.ChkGroundHit()) {
if (mFlyType != 1) {
#if TARGET_PC
bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f);
bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears ? 2.0f : 1.0f);
#else
bckSet(6, 0, 0.0f, 1.0f);
#endif
@@ -1093,7 +1093,7 @@ void daE_YM_c::executeDown() {
mSound.startCreatureSound(Z2SE_CM_BODYFALL_WATER_M, 0, -1);
mSound.startCreatureSound(Z2SE_EN_YM_MOGAKU, 0, -1);
#if TARGET_PC
bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f);
bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears ? 2.0f : 1.0f);
#else
bckSet(6, 0, 0.0f, 1.0f);
#endif
@@ -1115,7 +1115,7 @@ void daE_YM_c::executeDown() {
|| dComIfG_Bgsp().GetGroundCode(gnd_chk) == 5)
{
#if TARGET_PC
bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f);
bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears ? 2.0f : 1.0f);
#else
bckSet(6, 0, 0.0f, 1.0f);
#endif
+9 -4
View File
@@ -13,9 +13,12 @@
#if TARGET_PC
#include "dusk/dvd_asset.hpp"
#include "dusk/frame_interpolation.h"
static u8* l_Egnd_mantTEX_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x1C00, 0x4000), true); return buf; }
static u8* l_Egnd_mantTEX_U_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x5C00, 0x4000), true); return buf; }
static u8* l_Egnd_mantPAL_get() { alignas(32) static u8 buf[0x60]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x9C00, 0x60), true); return buf; }
using GameVersion = dusk::version::GameVersion;
static u8* l_Egnd_mantTEX_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0x1C00}, {GameVersion::GcnPal, 0x1C00}}, 0x4000), true); return buf; }
static u8* l_Egnd_mantTEX_U_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0x5C00}, {GameVersion::GcnPal, 0x5C00}}, 0x4000), true); return buf; }
static u8* l_Egnd_mantPAL_get() { alignas(32) static u8 buf[0x60]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0x9C00}, {GameVersion::GcnPal, 0x9C00}}, 0x60), true); return buf; }
#define l_Egnd_mantTEX (l_Egnd_mantTEX_get())
#define l_Egnd_mantTEX_U (l_Egnd_mantTEX_U_get())
#define l_Egnd_mantPAL (l_Egnd_mantPAL_get())
@@ -251,7 +254,9 @@ static u32 l_texCoord[338] = {
};
#if TARGET_PC
static u8* l_Egnd_mantDL_get() { alignas(32) static u8 buf[0x3EC]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0xA9A0, 0x3EC), true); return buf; }
using GameVersion = dusk::version::GameVersion;
static u8* l_Egnd_mantDL_get() { alignas(32) static u8 buf[0x3EC]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", {{GameVersion::GcnUsa, 0xA9A0}, {GameVersion::GcnPal, 0xA9A0}}, 0x3EC), true); return buf; }
#define l_Egnd_mantDL (l_Egnd_mantDL_get())
#else
#include "assets/l_Egnd_mantDL.h"
+25 -2
View File
@@ -22,6 +22,7 @@
#include "d/d_s_play.h"
#include "d/d_vibration.h"
#include "f_op/f_op_kankyo_mng.h"
#include "dusk/version.hpp"
#include <cstring>
#define ANM_MG_FISH_MOUTH_CLOSE 4
@@ -3230,7 +3231,17 @@ static int daMg_Fish_Execute(mg_fish_class* i_this) {
daPy_py_c* player = daPy_getPlayerActorClass();
#if VERSION == VERSION_GCN_JPN
#if TARGET_PC
if (dusk::version::isRegionJpn()) {
lit_1008 = 0;
} else if (dusk::version::isRegionPal()) {
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) {
lit_1008 = 2;
} else {
lit_1008 = 0;
}
}
#elif VERSION == VERSION_GCN_JPN
lit_1008 = 0;
#elif VERSION == VERSION_GCN_PAL
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) {
@@ -3843,7 +3854,19 @@ static int daMg_Fish_Create(fopAc_ac_c* i_this) {
a_this->mResName = "O_gD_bott";
}
#if VERSION == VERSION_GCN_JPN
#if TARGET_PC
if (dusk::version::isRegionJpn()) {
lit_1008 = 0;
} else if (dusk::version::isRegionPal()) {
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) {
lit_1008 = 2;
} else {
lit_1008 = 0;
}
} else {
lit_1008 = 1;
}
#elif VERSION == VERSION_GCN_JPN
lit_1008 = 0;
#elif VERSION == VERSION_GCN_PAL
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) {
+17 -5
View File
@@ -5,14 +5,15 @@
#include "d/dolzel_rel.h" // IWYU pragma: keep
#include "Z2AudioLib/Z2Instances.h"
#include "d/actor/d_a_mg_fish.h"
#include "d/actor/d_a_mg_fshop.h"
#include "d/actor/d_a_npc_henna.h"
#include "d/actor/d_a_mg_fish.h"
#include "d/actor/d_a_player.h"
#include "f_op/f_op_camera_mng.h"
#include "d/d_timer.h"
#include "d/d_s_play.h"
#include "Z2AudioLib/Z2Instances.h"
#include "d/d_timer.h"
#include "dusk/version.hpp"
#include "f_op/f_op_camera_mng.h"
#if TARGET_PC
#include "dusk/gyro.h"
@@ -1742,7 +1743,18 @@ static int daFshop_Create(fopAc_ac_c* actor) {
fopAcM_createChild(fpcNm_FSHOP_e, fopAcM_GetID(actor), 0xFFFFFF23, &actor->current.pos, fopAcM_GetRoomNo(actor), NULL, NULL, -1, NULL);
u8 sp10;
#if VERSION == VERSION_GCN_PAL || VERSION == VERSION_WII_PAL
#if TARGET_PC
if (dusk::version::isRegionPal()) {
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) {
sp10 = 2;
} else {
sp10 = 0;
}
} else {
sp10 = 1;
}
#elif VERSION == VERSION_GCN_PAL || VERSION == VERSION_WII_PAL
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) {
sp10 = 2;
} else {
+28 -2
View File
@@ -25,6 +25,8 @@
#include <cmath>
#include <cstring>
#include "dusk/version.hpp"
class dmg_rod_HIO_c : public JORReflexible {
public:
dmg_rod_HIO_c();
@@ -5734,10 +5736,22 @@ static void play_camera_u(dmg_rod_class* i_this) {
static int dmg_rod_Execute(dmg_rod_class* i_this) {
fopAc_ac_c* actor = &i_this->actor;
#if TARGET_PC
if (dusk::version::isPalOrAtLeastWiiR2()) {
if (dComIfGs_getPalLanguage() == 0) {
data_804BBBD4 = 2;
} else {
data_804BBBD4 = 0;
}
} else if (dusk::version::isRegionJpn()) {
data_804BBBD4 = 0;
} else {
data_804BBBD4 = 1;
}
//TODO: It seems possible that dComIfGs_getPalLanguage returns a constant value for non-PAL
// versions (causing the first block to be elided), and it's also possible that the value
// being compared against is an enum value with per-version definitions.
#if VERSION == VERSION_SHIELD_DEBUG
#elif VERSION == VERSION_SHIELD_DEBUG
if (dComIfGs_getPalLanguage() == 1) {
data_804BBBD4 = 2;
} else {
@@ -6303,7 +6317,19 @@ static int dmg_rod_Create(fopAc_ac_c* i_this) {
heap_size = 0xC9A0;
}
#if VERSION == VERSION_SHIELD_DEBUG
#if TARGET_PC
if (dusk::version::isPalOrAtLeastWiiR2()) {
if (dComIfGs_getPalLanguage() == 0) {
data_804BBBD4 = 2;
} else {
data_804BBBD4 = 0;
}
} else if (dusk::version::isRegionJpn()) {
data_804BBBD4 = 0;
} else {
data_804BBBD4 = 1;
}
#elif VERSION == VERSION_SHIELD_DEBUG
if (dComIfGs_getPalLanguage() == 1) {
data_804BBBD4 = 2;
} else {
+10
View File
@@ -40,6 +40,7 @@ dMirror_packet_c::dMirror_packet_c() {
void dMirror_packet_c::reset() {
#if TARGET_PC
mbReset = true;
mbHadEntry = false;
#else
mModelCount = 0;
#endif
@@ -96,6 +97,9 @@ int dMirror_packet_c::entryModel(J3DModel* i_model) {
}
mModels[mModelCount++] = i_model;
#if TARGET_PC
mbHadEntry = true;
#endif
return 1;
}
@@ -624,6 +628,12 @@ int daMirror_c::draw() {
mDoExt_modelUpdateDL(mpModel);
}
#if TARGET_PC
if (mPacket.mbReset && !mPacket.mbHadEntry) {
mPacket.mModelCount = 0;
}
mPacket.mbHadEntry = true;
#endif
dComIfGd_getOpaListBG()->entryImm(&mPacket, 0);
return 1;
}
+2 -3
View File
@@ -956,7 +956,7 @@ static void npc_ne_tame(npc_ne_class* i_this) {
i_this->mpMorf->setPlaySpeed(i_this->mAnmSpeed);
/* dSv_event_flag_c::F_0470 - Fishing Pond - Reserved for fishing */
if (dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])) {
if (IF_DUSK(dusk::getSettings().game.no2ndFishForCat) || dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])) {
if (fpcEx_Search(s_fish_sub, _this) != NULL) {
i_this->mAction = npc_ne_class::ACT_HOME;
i_this->mMode = 10;
@@ -2948,8 +2948,7 @@ static int daNpc_Ne_Execute(npc_ne_class* i_this) {
if (i_this->mWantsFish && (i_this->mCounter & 0xf) == 0) {
/* dSv_event_flag_c::F_0470 - Fishing Pond - Reserved for fishing */
if (dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])
&& i_this->mDistToTarget < 1500.0f) {
if ((IF_DUSK(dusk::getSettings().game.no2ndFishForCat) || dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])) && i_this->mDistToTarget < 1500.0f) {
if (fopAcM_SearchByName(fpcNm_MG_ROD_e) != NULL) {
i_this->mNoFollow = false;
} else {
+7
View File
@@ -205,6 +205,13 @@ int daObj_Balloon_c::_delete() {
Z2GetAudioMgr()->seStop(Z2SE_OBJ_WATERMILL_ROUND, 0);
if (mHIOInit) {
hio_set = false;
#ifdef TARGET_PC
// !@bug d_a_obj_balloon.rel unload used to zero these file-statics; with static linking they dangle across scenes.
m_combo_type = 0xFFFFFFFF;
m_combo_count = 0;
m_combo_next_score = 0;
m_balloon_score = 0;
#endif
}
return 1;
}
+4 -4
View File
@@ -265,8 +265,8 @@ int daObjDrop_c::modeParentWait() {
mModeAction = 1;
#if TARGET_PC
mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 20 : 40;
if (dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0) {
mModeTimer = dusk::getSettings().game.fastTears ? 0 : 40;
if (dusk::getSettings().game.fastTears) {
current.pos.y += 100.0f;
} else {
current.pos.y += 300.0f;
@@ -285,7 +285,7 @@ int daObjDrop_c::modeParentWait() {
case 2:
createBodyEffect();
#if TARGET_PC
mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 5 : 45;
mModeTimer = dusk::getSettings().game.fastTears ? 0 : 45;
#else
mModeTimer = 45;
#endif
@@ -331,7 +331,7 @@ int daObjDrop_c::modeWait() {
case 2:
case 50:
#if TARGET_PC
if (dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0) {
if (dusk::getSettings().game.fastTears) {
f32 player_dist = current.pos.abs(daPy_getPlayerActorClass()->current.pos);
f32 home_dist = current.pos.abs(home.pos);
+41
View File
@@ -10,6 +10,10 @@
#include "d/d_path.h"
#include "d/d_bg_w.h"
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
daL8Lift_HIO_c::daL8Lift_HIO_c() {
mStopDisappearTime = 30;
mStartMoveTime = 60;
@@ -380,7 +384,44 @@ void daL8Lift_c::setNextPoint() {
mCurrentPoint = next_point;
}
#if TARGET_PC
void daL8Lift_interp_callback(bool isSimFrame, void* pUserWork) {
daL8Lift_c* lift = static_cast<daL8Lift_c*>(pUserWork);
if (lift == NULL || lift->mpModel == NULL) {
return;
}
g_env_light.settingTevStruct(0x10, &lift->current.pos, &lift->tevStr);
g_env_light.setLightTevColorType_MAJI(lift->mpModel, &lift->tevStr);
J3DModelData* modelData = lift->mpModel->getModelData();
J3DMaterial* materialp = modelData->getMaterialNodePointer(0);
if (materialp->getTexGenBlock()->getTexMtx(1) != NULL) {
J3DTexMtxInfo* mtx_info = &materialp->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo();
if (mtx_info != NULL) {
Mtx m;
C_MTXLightOrtho(m, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f);
mDoMtx_stack_c::XrotS(0x4000);
mDoMtx_stack_c::transM(-lift->current.pos.x, -lift->current.pos.y, -lift->current.pos.z);
cMtx_concat(m, mDoMtx_stack_c::get(), mtx_info->mEffectMtx);
}
}
lift->mBtk.entry(modelData);
J3DGXColor* color = materialp->getTevKColor(1);
color->r = l_HIO.mColorR;
color->g = l_HIO.mColorG;
color->b = l_HIO.mColorB;
}
#endif
int daL8Lift_c::Draw() {
#if TARGET_PC
dusk::frame_interp::add_interpolation_callback(&daL8Lift_interp_callback, this);
#endif
g_env_light.settingTevStruct(16, &current.pos, &tevStr);
g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr);
J3DModelData* modelData = mpModel->getModelData();
+41
View File
@@ -11,6 +11,10 @@
#include "d/d_com_inf_game.h"
#include "d/d_path.h"
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
daOptiLift_HIO_c::daOptiLift_HIO_c() {
mStopDisappearTime = 30;
mStartMoveTime = 30;
@@ -412,7 +416,44 @@ void daOptiLift_c::setNextPoint() {
mCurrentPoint = next_point;
}
#if TARGET_PC
static void daOptiLift_interp_callback(bool isSimFrame, void* pUserWork) {
daOptiLift_c* lift = static_cast<daOptiLift_c*>(pUserWork);
if (lift == NULL || lift->mpModel == NULL) {
return;
}
g_env_light.settingTevStruct(0x10, &lift->current.pos, &lift->tevStr);
g_env_light.setLightTevColorType_MAJI(lift->mpModel, &lift->tevStr);
J3DModelData* modelData = lift->mpModel->getModelData();
J3DMaterial* materialp = modelData->getMaterialNodePointer(0);
if (materialp->getTexGenBlock()->getTexMtx(1) != NULL) {
J3DTexMtxInfo* mtx_info = &materialp->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo();
if (mtx_info != NULL) {
Mtx m;
C_MTXLightOrtho(m, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f);
mDoMtx_stack_c::XrotS(0x4000);
mDoMtx_stack_c::transM(-lift->current.pos.x, -lift->current.pos.y, -lift->current.pos.z);
cMtx_concat(m, mDoMtx_stack_c::get(), mtx_info->mEffectMtx);
}
}
lift->mBtk.entry(modelData);
J3DGXColor* color = materialp->getTevKColor(1);
color->r = l_HIO.mColorR;
color->g = l_HIO.mColorG;
color->b = l_HIO.mColorB;
}
#endif
int daOptiLift_c::Draw() {
#if TARGET_PC
dusk::frame_interp::add_interpolation_callback(&daOptiLift_interp_callback, this);
#endif
g_env_light.settingTevStruct(0x10, &current.pos, &tevStr);
g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr);
+6 -7
View File
@@ -369,18 +369,17 @@ JKRHeap* daPy_anmHeap_c::setAnimeHeap() {
#if !PLATFORM_WII
#if TARGET_PC
#include "dusk/dvd_asset.hpp"
using GameVersion = dusk::version::GameVersion;
static const u8* l_sightDL_get() {
static u8 buf[0x89];
static bool _ = (
dusk::LoadDolAsset(
buf,
#if VERSION == VERSION_GCN_PAL
0x803BBDA0,
#elif VERSION == VERSION_GCN_JPN
0x803B4220,
#elif VERSION == VERSION_GCN_USA
0x803BA0C0,
#endif
{
{GameVersion::GcnUsa, 0x803BA0C0},
{GameVersion::GcnPal, 0x803BBDA0},
{GameVersion::GcnJpn, 0x803B4220}
},
0x89
),
true
+17 -13
View File
@@ -1,21 +1,22 @@
#include "d/dolzel_rel.h" // IWYU pragma: keep
#include "JSystem/J2DGraph/J2DScreen.h"
#include "JSystem/J2DGraph/J2DTextBox.h"
#include "JSystem/JKernel/JKRExpHeap.h"
#include "JSystem/JKernel/JKRMemArchive.h"
#include "d/actor/d_a_title.h"
#include "d/d_com_inf_game.h"
#include "d/d_demo.h"
#include "d/d_menu_collect.h"
#include "d/d_pane_class_alpha.h"
#include "d/d_s_logo.h"
#include "d/d_s_play.h"
#include "d/d_demo.h"
#include "d/d_pane_class_alpha.h"
#include "d/d_menu_collect.h"
#include "dusk/version.hpp"
#include "f_op/f_op_msg_mng.h"
#include "f_op/f_op_overlap_mng.h"
#include "f_op/f_op_scene_mng.h"
#include "m_Do/m_Do_Reset.h"
#include "m_Do/m_Do_controller_pad.h"
#include "d/d_com_inf_game.h"
#include "JSystem/JKernel/JKRExpHeap.h"
#include "f_op/f_op_overlap_mng.h"
#include "f_op/f_op_msg_mng.h"
#include "f_op/f_op_scene_mng.h"
#include "JSystem/J2DGraph/J2DScreen.h"
#include "JSystem/JKernel/JKRMemArchive.h"
#include "JSystem/J2DGraph/J2DTextBox.h"
#include "m_Do/m_Do_graphic.h"
#ifdef TARGET_PC
@@ -49,7 +50,10 @@ static u8 const lit_3772[12] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC
using namespace dusk::version;
#define l_arcName versionSelect<const char*>({{GameVersion::GcnPal, "TitlePal"}}, "Title")
#elif VERSION == VERSION_GCN_PAL
static char const l_arcName[] = "TitlePal";
#else
static char const l_arcName[] = "Title";
@@ -59,7 +63,7 @@ daTit_HIO_c::daTit_HIO_c() {
mPSScaleX = 1.0f;
mPSScaleY = 1.0f;
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
switch (OSGetLanguage()) {
case OS_LANGUAGE_ENGLISH:
case OS_LANGUAGE_GERMAN:
+23 -23
View File
@@ -7,17 +7,13 @@
#include "dusk/frame_interpolation.h"
#if TARGET_PC
const u16 l_J_Ohana00_64TEX__width = 64;
const u16 l_J_Ohana00_64TEX__height = 64;
#else
const u16 l_J_Ohana00_64TEX__width = 63;
const u16 l_J_Ohana00_64TEX__height = 63;
#endif
#if TARGET_PC
#include "dusk/dvd_asset.hpp"
static u8* l_J_Ohana00_64TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9060, 0x800), true); return buf; }
using GameVersion = dusk::version::GameVersion;
static u8* l_J_Ohana00_64TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9060}, {GameVersion::GcnPal, 0x9060}}, 0x800), true); return buf; }
#define l_J_Ohana00_64TEX (l_J_Ohana00_64TEX_get())
#else
#include "assets/l_J_Ohana00_64TEX.h"
@@ -113,10 +109,12 @@ static u8 l_flowerTexCoord[] = {
0x3E, 0xA7, 0x72, 0xD6, 0xBD, 0x2F, 0x46, 0xAA};
#if TARGET_PC
static u8* l_J_hana00DL_get() { static u8 buf[0x150]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9D20, 0x150), true); return buf; }
static u8* l_J_hana00_cDL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9E80, 0xDE), true); return buf; }
static u8* l_matDL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9F60, 0x99), true); return buf; }
static u8* l_matLight4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xA000, 0x99), true); return buf; }
using GameVersion = dusk::version::GameVersion;
static u8* l_J_hana00DL_get() { static u8 buf[0x150]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9D20}, {GameVersion::GcnPal, 0x9D20}}, 0x150), true); return buf; }
static u8* l_J_hana00_cDL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9E80}, {GameVersion::GcnPal, 0x9E80}}, 0xDE), true); return buf; }
static u8* l_matDL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x9F60}, {GameVersion::GcnPal, 0x9F60}}, 0x99), true); return buf; }
static u8* l_matLight4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xA000}, {GameVersion::GcnPal, 0xA000}}, 0x99), true); return buf; }
#define l_J_hana00DL (l_J_hana00DL_get())
#define l_J_hana00_cDL (l_J_hana00_cDL_get())
#define l_matDL (l_matDL_get())
@@ -133,16 +131,12 @@ l_matDL__d_a_grass(l_J_Ohana00_64TEX)
l_matLight4DL(l_J_Ohana00_64TEX)
#endif
#if TARGET_PC
const u16 l_J_Ohana01_64128_0419TEX__width = 64;
const u16 l_J_Ohana01_64128_0419TEX__height = 128;
#else
const u16 l_J_Ohana01_64128_0419TEX__width = 63;
const u16 l_J_Ohana01_64128_0419TEX__height = 127;
#endif
#if TARGET_PC
static u8* l_J_Ohana01_64128_0419TEX_get() { static u8 buf[0x1000]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xA0A0, 0x1000), true); return buf; }
using GameVersion = dusk::version::GameVersion;
static u8* l_J_Ohana01_64128_0419TEX_get() { static u8 buf[0x1000]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xA0A0}, {GameVersion::GcnPal, 0xA0A0}}, 0x1000), true); return buf; }
#define l_J_Ohana01_64128_0419TEX (l_J_Ohana01_64128_0419TEX_get())
#else
#include "assets/l_J_Ohana01_64128_0419TEX.h"
@@ -274,11 +268,13 @@ static u8 l_flowerTexCoord2[] = {
0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x80, 0x3F, 0x79, 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x51, 0x10, 0x6F};
#if TARGET_PC
static u8* l_J_hana01DL_get() { static u8 buf[0x138]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB7C0, 0x138), true); return buf; }
static u8* l_J_hana01_c_00DL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB900, 0xDE), true); return buf; }
static u8* l_J_hana01_c_01DL_get() { static u8 buf[0x128]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB9E0, 0x128), true); return buf; }
static u8* l_mat2DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xBB20, 0x99), true); return buf; }
static u8* l_mat2Light4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xBBC0, 0x99), true); return buf; }
using GameVersion = dusk::version::GameVersion;
static u8* l_J_hana01DL_get() { static u8 buf[0x138]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xB7C0}, {GameVersion::GcnPal, 0xB7C0}}, 0x138), true); return buf; }
static u8* l_J_hana01_c_00DL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xB900}, {GameVersion::GcnPal, 0xB900}}, 0xDE), true); return buf; }
static u8* l_J_hana01_c_01DL_get() { static u8 buf[0x128]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xB9E0}, {GameVersion::GcnPal, 0xB9E0}}, 0x128), true); return buf; }
static u8* l_mat2DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xBB20}, {GameVersion::GcnPal, 0xBB20}}, 0x99), true); return buf; }
static u8* l_mat2Light4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0xBBC0}, {GameVersion::GcnPal, 0xBBC0}}, 0x99), true); return buf; }
#define l_J_hana01DL (l_J_hana01DL_get())
#define l_J_hana01_c_00DL (l_J_hana01_c_00DL_get())
#define l_J_hana01_c_01DL (l_J_hana01_c_01DL_get())
@@ -586,11 +582,11 @@ dFlower_packet_c::dFlower_packet_c() {
#if TARGET_PC
GXInitTexObj(&mTexObj_l_J_Ohana00_64TEX, l_J_Ohana00_64TEX,
l_J_Ohana00_64TEX__width, l_J_Ohana00_64TEX__height, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
l_J_Ohana00_64TEX__width + 1, l_J_Ohana00_64TEX__height + 1, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
);
GXInitTexObj(&mTexObj_l_J_Ohana01_64128_0419TEX, l_J_Ohana01_64128_0419TEX,
l_J_Ohana01_64128_0419TEX__width, l_J_Ohana01_64128_0419TEX__height, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
l_J_Ohana01_64128_0419TEX__width + 1, l_J_Ohana01_64128_0419TEX__height + 1, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
);
#endif
@@ -789,6 +785,10 @@ void dFlower_packet_c::draw() {
GXColor sp28;
#if AVOID_UB
sp28 = {1, 1, 1, 1};
#endif
//u8 sp26, sp25, sp24;
GXColor sp24;
sp24.r = -0.4f * temp_r29->AmbCol.r * var_f29;
+17 -16
View File
@@ -20,8 +20,9 @@ const u16 l_M_kusa05_RGBATEX__height = 31;
#if TARGET_PC
#include "dusk/dvd_asset.hpp"
static u8* l_M_kusa05_RGBATEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x7680, 0x800), true); return buf; }
static u8* l_M_Hijiki00TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x7E80, 0x800), true); return buf; }
using GameVersion = dusk::version::GameVersion;
static u8* l_M_kusa05_RGBATEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x7680}, {GameVersion::GcnPal, 0x7680}}, 0x800), true); return buf; }
static u8* l_M_Hijiki00TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x7E80}, {GameVersion::GcnPal, 0x7E80}}, 0x800), true); return buf; }
#define l_M_kusa05_RGBATEX (l_M_kusa05_RGBATEX_get())
#define l_M_Hijiki00TEX (l_M_Hijiki00TEX_get())
#else
@@ -113,12 +114,14 @@ static u8 l_texCoord[160] = {
};
#if TARGET_PC
static u8* l_M_Kusa_9qDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8B00, 0xCB), true); return buf; }
static u8* l_M_Kusa_9q_cDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8BE0, 0xCB), true); return buf; }
static u8* l_M_TenGusaDL_get() { static u8 buf[0xD4]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8CC0, 0xD4), true); return buf; }
static u8* l_Tengusa_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8DA0, 0xA8), true); return buf; }
static u8* l_kusa9q_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8E60, 0xA8), true); return buf; }
static u8* l_kusa9q_l4_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8F20, 0xA8), true); return buf; }
using GameVersion = dusk::version::GameVersion;
static u8* l_M_Kusa_9qDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8B00}, {GameVersion::GcnPal, 0x8B00}}, 0xCB), true); return buf; }
static u8* l_M_Kusa_9q_cDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8BE0}, {GameVersion::GcnPal, 0x8BE0}}, 0xCB), true); return buf; }
static u8* l_M_TenGusaDL_get() { static u8 buf[0xD4]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8CC0}, {GameVersion::GcnPal, 0x8CC0}}, 0xD4), true); return buf; }
static u8* l_Tengusa_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8DA0}, {GameVersion::GcnPal, 0x8DA0}}, 0xA8), true); return buf; }
static u8* l_kusa9q_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8E60}, {GameVersion::GcnPal, 0x8E60}}, 0xA8), true); return buf; }
static u8* l_kusa9q_l4_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", {{GameVersion::GcnUsa, 0x8F20}, {GameVersion::GcnPal, 0x8F20}}, 0xA8), true); return buf; }
#define l_M_Kusa_9qDL (l_M_Kusa_9qDL_get())
#define l_M_Kusa_9q_cDL (l_M_Kusa_9q_cDL_get())
#define l_M_TenGusaDL (l_M_TenGusaDL_get())
@@ -491,11 +494,11 @@ dGrass_packet_c::dGrass_packet_c() {
#if TARGET_PC
GXInitTexObj(&mTexObj_l_M_kusa05_RGBATEX, l_M_kusa05_RGBATEX,
l_M_kusa05_RGBATEX__width, l_M_kusa05_RGBATEX__height, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE
l_M_kusa05_RGBATEX__width + 1, l_M_kusa05_RGBATEX__height + 1, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE
);
GXInitTexObj(&mTexObj_l_M_Hijiki00TEX, l_M_Hijiki00TEX,
l_M_Hijiki00TEX__width, l_M_Hijiki00TEX__height, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE
l_M_Hijiki00TEX__width + 1, l_M_Hijiki00TEX__height + 1, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE
);
#endif
@@ -643,18 +646,14 @@ void dGrass_packet_c::draw() {
}
if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) {
#if TARGET_PC
GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0);
#endif
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0));
if (sp48 <= 3) {
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
} else {
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
}
} else {
#if TARGET_PC
GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0);
#endif
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0));
GXCallDisplayList(l_Tengusa_matDL, 0xA0);
}
@@ -680,12 +679,14 @@ void dGrass_packet_c::draw() {
while (var_r29 != NULL) {
if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) {
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0));
if (sp48 <= 2) {
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
} else {
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
}
} else {
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0));
GXCallDisplayList(l_Tengusa_matDL, 0xA0);
}
+13
View File
@@ -9,6 +9,8 @@
#include "JSystem/J2DGraph/J2DScreen.h"
#include "JSystem/J2DGraph/J2DTextBox.h"
#include "d/d_msg_string.h"
#include "dusk/livesplit.h"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "m_Do/m_Do_controller_pad.h"
dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) {
@@ -138,6 +140,17 @@ void dBrightCheck_c::modeWait() {}
void dBrightCheck_c::modeMove() {
if (mDoCPd_c::getTrigA(PAD_1) || mDoCPd_c::getTrigStart(PAD_1)) {
mDoAud_seStart(Z2SE_ENTER_GAME, NULL, 0, 0);
#ifdef TARGET_PC
dusk::speedrun::start();
if (dusk::getSettings().game.speedrunMode && !dusk::getSettings().game.hideTvSettingsScreen) {
// start a new run if a run isn't already in progress
if (!dusk::m_speedrunInfo.m_isRunStarted) {
dusk::ImGuiMenuGame::resetForSpeedrunMode();
dusk::m_speedrunInfo.startRun();
}
}
#endif
mCompleteCheck = true;
mMode = MODE_WAIT_e;
}
+78
View File
@@ -794,6 +794,9 @@ void dCamera_c::updatePad() {
if (mTriggerLeftLast > mCamSetup.ManualEndVal()) {
if (mLockLActive == 0) {
#if TARGET_PC
mCamParam.mManualMode = 0;
#endif
mLockLJustActivated = 1;
} else {
mLockLJustActivated = 0;
@@ -833,6 +836,12 @@ void dCamera_c::updatePad() {
mHoldB = mDoCPd_c::getHoldB(mPadID) ? true : false;
mTrigB = mDoCPd_c::getTrigB(mPadID) ? true : false;
#if TARGET_PC
if (mCamParam.mManualMode) {
return;
}
#endif
bool sp6B = true;
bool sp6C = true;
int temp1;
@@ -1167,6 +1176,7 @@ bool dCamera_c::Run() {
}
} else {
sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle);
field_0x170++;
field_0x160++;
mCurCamStyleTimer++;
@@ -3078,6 +3088,11 @@ bool dCamera_c::bumpCheck(u32 i_flags) {
} else {
field_0x968 *= mMonitor.field_0xc / 5.0f;
}
#if TARGET_PC
if (!dusk::getSettings().game.freeCamera || !mCamParam.mManualMode) {
#endif
f32 tmp = field_0x96c * (mIsWolf == 1 ? 30.0f : 30.0f);
center += vec3.norm() * (tmp * globe.V().Sin());
cSGlobe globe2(vec2 - center);
@@ -3091,6 +3106,10 @@ bool dCamera_c::bumpCheck(u32 i_flags) {
vec = lin_chk1.GetCross();
}
#if TARGET_PC
}
#endif
#if DEBUG
if (mCamSetup.CheckFlag(0x8000)) {
dDbVw_Report(20, 235, " U");
@@ -3501,6 +3520,12 @@ void dCamera_c::checkGroundInfo() {
}
bool dCamera_c::chaseCamera(s32 param_0) {
#if TARGET_PC
if (freeCamera()) {
return 1;
}
#endif
static f32 JumpCushion = 0.9f;
f32 charge_latitude = mCamSetup.ChargeLatitude();
int charge_timer = mCamSetup.ChargeTimer();
@@ -4604,6 +4629,7 @@ bool dCamera_c::chaseCamera(s32 param_0) {
sp110 = mViewCache.mDirection.R();
mViewCache.mDirection.R(mViewCache.mDirection.R() + (fVar55 - mViewCache.mDirection.R()) * chase->field_0x74);
chase->field_0x64 = mViewCache.mCenter + mViewCache.mDirection.Xyz();
mViewCache.mEye = chase->field_0x64;
@@ -7444,6 +7470,58 @@ bool dCamera_c::test2Camera(s32 param_0) {
return false;
}
#if TARGET_PC
bool dCamera_c::freeCamera() {
if (!dusk::getSettings().game.freeCamera) {
mCamParam.mManualMode = 0;
return false;
}
mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
cXyz camMovement = {mPadInfo.mCStick.mLastPosX, mPadInfo.mCStick.mLastPosY, 0.0f};
f32 magnitude = sqrt(mPadInfo.mCStick.mLastPosX * mPadInfo.mCStick.mLastPosX + mPadInfo.mCStick.mLastPosY * mPadInfo.mCStick.mLastPosY);
if (mPadInfo.mCStick.mLastPosX != 0 || mPadInfo.mCStick.mLastPosY != 0) {
if (!mCamParam.mManualMode) {
mCamParam.mManualMode = 1;
mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
}
camMovement = camMovement.normalize();
camMovement.y *= dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f;
mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity * 4.0f;
mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity * 4.0f;
}
if (!mCamParam.mManualMode) {
return false;
}
f32 minYAngle = -10.0f;
f32 maxAngle = 50.0f;
mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, minYAngle, maxAngle);
mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle);
mViewCache.mDirection.mInclination = cSAngle(mCamParam.freeYAngle);
f32 currentLerp = (mCamParam.freeYAngle - minYAngle) / (maxAngle - minYAngle);
mViewCache.mDirection.mRadius = std::lerp(200.0f, 1000.0f, currentLerp);
cXyz finalCenter = mpPlayerActor->current.pos;
finalCenter.y += mIsWolf ? 90.0f : 100.0f;
mViewCache.mCenter = finalCenter;
cXyz finalEye = finalCenter + mViewCache.mDirection.Xyz();
mViewCache.mEye = finalEye;
mViewCache.mFovy = 60.0f;
return true;
}
#endif
bool dCamera_c::towerCamera(s32 param_0) {
cSAngle stack_444 = cSAngle(mCamSetup.ChargeLatitude());
f32 sp224 = mCamSetup.ChargeBRatio();
+14 -1
View File
@@ -14,6 +14,8 @@
#include <cstdio>
#include <cstring>
#include "dusk/version.hpp"
dFile_info_c::dFile_info_c(JKRArchive* i_archive, u8 param_1) {
mArchive = i_archive;
field_0x22 = param_1;
@@ -169,7 +171,18 @@ void dFile_info_c::setSaveDate(dSv_save_c* i_savedata) {
OSCalendarTime time;
OSTicksToCalendarTime(i_savedata->getPlayer().getPlayerStatusB().getDateIpl(), &time);
#if (VERSION == VERSION_GCN_JPN) || (VERSION == VERSION_WII_JPN)
#if TARGET_PC
if (dusk::version::isRegionJpn()) {
sprintf(mSaveDate, "%d.%02d.%02d %02d:%02d", time.year, time.mon + 1, time.mday,
time.hour, time.min);
} else if (dusk::version::isRegionPal() && dComIfGs_getPalLanguage() != dSv_player_config_c::LANGUAGE_ENGLISH) {
sprintf(mSaveDate, "%02d/%02d/%d %02d:%02d", time.mday, time.mon + 1, time.year, time.hour,
time.min);
} else {
sprintf(mSaveDate, "%02d/%02d/%d %02d:%02d", time.mon + 1, time.mday, time.year, time.hour,
time.min);
}
#elif (VERSION == VERSION_GCN_JPN) || (VERSION == VERSION_WII_JPN)
sprintf(mSaveDate, "%d.%02d.%02d %02d:%02d", time.year, time.mon + 1, time.mday,
time.hour, time.min);
#elif VERSION == VERSION_GCN_PAL
+56 -7
View File
@@ -5962,6 +5962,8 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) {
fopAc_ac_c* player = dComIfGp_getPlayer(0);
if (evil_packet != NULL) {
IF_DUSK(GXPushDebugGroup("dKyr_evil_draw2"));
j3dSys.reinitGX();
if (dComIfGd_getView() != NULL) {
MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx);
@@ -5986,7 +5988,12 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) {
TGXTexObj texobj;
dKyr_set_btitex(&texobj, (ResTIMG*)tex[1]);
rot += 0.7f;
#if TARGET_PC
if (dusk::frame_interp::get_ui_tick_pending())
#endif
{
rot += 0.7f;
}
MTXRotRad(rotMtx, 'Z', DEG_TO_RAD(rot));
MTXConcat(camMtx, rotMtx, camMtx);
@@ -6037,7 +6044,14 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) {
sp34.y = 80.0f;
sp34.z = 80.0f;
mDoLib_project(&sp7C, &proj);
if (!(proj.x > -sp34.x) || !(proj.x < (FB_WIDTH + sp34.x)) ||
#if TARGET_PC
f32 cullMinX = mDoGph_gInf_c::getSafeMinXF() - sp34.x;
f32 cullMaxX = mDoGph_gInf_c::getSafeMinXF() + mDoGph_gInf_c::getSafeWidthF() + sp34.x;
#else
f32 cullMinX = -sp34.x;
f32 cullMaxX = FB_WIDTH + sp34.x;
#endif
if (!(proj.x > cullMinX) || !(proj.x < cullMaxX) ||
!(proj.y > -sp34.y) || !(proj.y < (458.0f + sp34.z)))
{
continue;
@@ -6150,6 +6164,8 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) {
}
}
IF_DUSK(GXPopDebugGroup());
GXSetClipMode(GX_CLIP_ENABLE);
J3DShape::resetVcdVatCache();
}
@@ -6187,6 +6203,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
f32 sp60 = fabsf(cM_ssin(g_Counter.mCounter0 * 215));
if (evil_packet != NULL) {
IF_DUSK(GXPushDebugGroup("dKyr_evil_draw"));
j3dSys.reinitGX();
if (dComIfGd_getView() != NULL) {
MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx);
@@ -6208,14 +6226,19 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
TGXTexObj texobj;
dKyr_set_btitex(&texobj, (ResTIMG*)tex[0]);
rot += 1.0f;
#if TARGET_PC
if (dusk::frame_interp::get_ui_tick_pending())
#endif
{
rot += 1.0f;
}
MTXRotRad(rotMtx, 'Z', DEG_TO_RAD(rot));
MTXConcat(camMtx, rotMtx, camMtx);
GXLoadPosMtxImm(drawMtx, GX_PNMTX0);
GXSetCurrentMtx(GX_PNMTX0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBA4, 8);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_RGBA4, 8);
GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
@@ -6238,6 +6261,19 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
GXSetClipMode(GX_CLIP_DISABLE);
GXSetNumIndStages(0);
#if TARGET_PC
// move color_reg0 to vtx for perf
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
GXSetNumChans(1);
GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE);
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_C1, GX_CC_RASC, GX_CC_TEXC, GX_CC_ZERO);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
#endif
dComIfG_Ccsp()->PrepareMass();
for (int i = 0; i < g_env_light.field_0x1054; i++) {
@@ -6262,7 +6298,14 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
sp44.z = 80.0f;
mDoLib_project(&spA4, &proj);
if (!(proj.x > -sp44.x) || !(proj.x < (FB_WIDTH + sp44.x)) ||
#if TARGET_PC
f32 cullMinX = mDoGph_gInf_c::getSafeMinXF() - sp44.x;
f32 cullMaxX = mDoGph_gInf_c::getSafeMinXF() + mDoGph_gInf_c::getSafeWidthF() + sp44.x;
#else
f32 cullMinX = -sp44.x;
f32 cullMaxX = FB_WIDTH + sp44.x;
#endif
if (!(proj.x > cullMinX) || !(proj.x < cullMaxX) ||
!(proj.y > -sp44.y) || !(proj.y < (458.0f + sp44.z)))
{
continue;
@@ -6349,7 +6392,7 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
color_reg0.b = (115.0f * sp28) + (15.0f * fabsf(sp2C - sp64));
}
GXSetTevColor(GX_TEVREG0, color_reg0);
IF_NOT_DUSK(GXSetTevColor(GX_TEVREG0, color_reg0));
GXSetTevColor(GX_TEVREG1, color_reg1);
spC8 = spA4;
@@ -6388,12 +6431,16 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
GXPosition3f32(pos[0].x, pos[0].y, pos[0].z);
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
GXTexCoord2s16(0, 0);
GXPosition3f32(pos[1].x, pos[1].y, pos[1].z);
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
GXTexCoord2s16(0xFF, 0);
GXPosition3f32(pos[2].x, pos[2].y, pos[2].z);
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
GXTexCoord2s16(0xFF, 0xFF);
GXPosition3f32(pos[3].x, pos[3].y, pos[3].z);
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
GXTexCoord2s16(0, 0xFF);
GXEnd();
}
@@ -6401,6 +6448,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
}
}
IF_DUSK(GXPopDebugGroup());
J3DShape::resetVcdVatCache();
GXSetClipMode(GX_CLIP_ENABLE);
+10 -7
View File
@@ -13,6 +13,9 @@
#include "SSystem/SComponent/c_math.h"
#include "d/actor/d_a_player.h"
#include "d/d_com_inf_game.h"
#if TARGET_PC
#include <dolphin/gx/GXExtra.h>
#endif
#include <cstring>
#if DEBUG
@@ -539,17 +542,14 @@ void renderingAmap_c::rendering(dDrawPath_c::poly_class const* i_poly) {
}
}
/* Enabling the following definition will modify the following function to
* make the map look worse for extra speed in the emulator, especially in large
* areas such as hyrule field.
*/
#define HYRULE_FIELD_SPEEDHACK
bool renderingAmap_c::isDrawOutSideTrim() {
bool rt = false;
#ifdef HYRULE_FIELD_SPEEDHACK
return 0;
#if TARGET_PC
if (!dusk::getSettings().game.enableMapBackground) {
return 0;
}
#endif
if (getDispType() == 0 || getDispType() == 4 || getDispType() == 3 || getDispType() == 2 ||
@@ -1218,6 +1218,9 @@ void dMap_c::changeTextureSize(int param_1, int param_2, int param_3) {
void dMap_c::_remove() {
if (mImage_p != NULL) {
#if TARGET_PC
GXDestroyCopyTex(mImage_p);
#endif
JKR_DELETE_ARRAY(mImage_p);
mImage_p = NULL;
}
+69 -8
View File
@@ -16,6 +16,7 @@
#ifdef TARGET_PC
constexpr u16 kMapResolutionMultiplier = 4;
constexpr u16 kMapCircleSize = 16 * kMapResolutionMultiplier;
#endif
void dMpath_n::dTexObjAggregate_c::create() {
@@ -32,6 +33,48 @@ void dMpath_n::dTexObjAggregate_c::create() {
JUT_ASSERT(74, image->magFilter == GX_NEAR);
mDoLib_setResTimgObj(image, mp_texObj[lp1], 0, NULL);
}
#if TARGET_PC
auto hqCircle = JKR_NEW TGXTexObj();
static bool hqCircleDrawn = false;
static u8 hqCircleData[kMapCircleSize * kMapCircleSize];
if (!hqCircleDrawn) {
const auto center = kMapCircleSize / 2.0f;
const auto radiusSq = center * center;
const auto blocksAcross = kMapCircleSize >> 3;
const auto totalPixels = sizeof(hqCircleData);
for (size_t i = 0; i < totalPixels; i++) {
// 8x4 block swizzling for I8
const auto blockIdx = i >> 5;
const auto localIdx = i & 31;
const auto blockY = blockIdx / blocksAcross;
const auto blockX = blockIdx % blocksAcross;
const auto localY = localIdx >> 3;
const auto localX = localIdx & 7;
const auto x = (blockX << 3) + localX;
const auto y = (blockY << 2) + localY;
const auto dx = (x + 0.5f) - center;
const auto dy = (y + 0.5f) - center;
// the original texture is in I4 format and uses 1 to indicate if inside the circle
// so we scale to I8 range: 255 / 15 = 17
hqCircleData[i] = (dx * dx + dy * dy < radiusSq) ? 17 : 0;
}
hqCircleDrawn = true;
}
GXInitTexObj(hqCircle, hqCircleData, kMapCircleSize, kMapCircleSize, GX_TF_I8, GX_CLAMP,
GX_CLAMP, GX_FALSE);
GXInitTexObjLOD(hqCircle, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1);
mp_texObj[6] = hqCircle;
#endif
}
void dMpath_n::dTexObjAggregate_c::remove() {
@@ -497,12 +540,6 @@ void dRenderingFDAmap_c::postRenderingMap() {
dMpath_n::dTexObjAggregate_c dMpath_n::m_texObjAgg;
/* Enabling the following definition will modify the following function to
* make the map look worse for extra speed in the emulator, especially in large
* areas such as hyrule field.
*/
#define HYRULE_FIELD_SPEEDHACK
void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_line) {
s32 width = getDecorationLineWidth(p_line->field_0x1);
if (width <= 0) {
@@ -527,8 +564,32 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
lineColor.r = lineColor.r - 4;
GXSetTevColor(GX_TEVREG1, lineColor);
#if TARGET_PC
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_KONST);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXBegin(GX_LINESTRIP, GX_VTXFMT0, 2 * (data_num - 1));
for (int i = 0; i < data_num - 1; i++) {
GXPosition1x16(data_p[i]);
GXTexCoord2f32(0, 0);
GXPosition1x16(data_p[i + 1]);
GXTexCoord2f32(0, 0);
}
GXEnd();
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_KONST, GX_CC_TEXC, GX_CC_C1);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXBegin(GX_POINTS, GX_VTXFMT0, data_num);
for (int i = 0; i < data_num; i++) {
GXPosition1x16(data_p[i]);
GXTexCoord2f32(0, 0);
}
GXEnd();
#else
for (int i = 0; i < data_num; i++) {
#ifndef HYRULE_FIELD_SPEEDHACK
if (i < data_num - 1) {
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE,
@@ -547,7 +608,6 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
#endif
GXBegin(GX_POINTS, GX_VTXFMT0, 1);
GXPosition1x16(data_p[0]);
@@ -555,6 +615,7 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
GXEnd();
data_p++;
}
#endif
setTevSettingNonTextureDirectColor();
GXClearVtxDesc();
+6
View File
@@ -11,6 +11,9 @@
#include "d/d_menu_dmap_map.h"
#include "f_op/f_op_msg_mng.h"
#include "m_Do/m_Do_graphic.h"
#if TARGET_PC
#include <dolphin/gx/GXExtra.h>
#endif
struct dMdm_HIO_prm_res_dst_s {
static void* m_res;
@@ -291,6 +294,9 @@ void dMenu_DmapMap_c::_create(u16 param_0, u16 param_1, u16 param_2, u16 param_3
void dMenu_DmapMap_c::_delete() {
for (int i = 0; i < 2; i++) {
if (mMapImage_p[i] != NULL) {
#if TARGET_PC
GXDestroyCopyTex(mMapImage_p[i]);
#endif
JKR_DELETE_ARRAY(mMapImage_p[i]);
}
+5 -3
View File
@@ -16,6 +16,8 @@
#include "m_Do/m_Do_graphic.h"
#include <cstring>
#include "dusk/version.hpp"
typedef void (dMenu_Fishing_c::*initFunc)();
initFunc map_init_process[] = {
&dMenu_Fishing_c::wait_init,
@@ -135,9 +137,9 @@ bool dMenu_Fishing_c::isSync() {
}
void dMenu_Fishing_c::init() {
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
BOOL isEnglish = FALSE;
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH) {
if (dusk::version::isRegionUsa() || (dusk::version::isRegionPal() && dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_ENGLISH)) {
isEnglish = TRUE;
}
#endif
@@ -145,7 +147,7 @@ void dMenu_Fishing_c::init() {
for (int i = 0; i < MAX_FINDABLE_FISHES; i++) {
if (dComIfGs_getFishNum(i) != 0) {
// Fish has been caught once, display it along with it's params
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
if (isEnglish) {
setFishParam(i, dComIfGs_getFishNum(i), dComIfGs_getFishSize(i) / 2.54f);
} else {
+6
View File
@@ -8,6 +8,9 @@
#include "d/d_debug_viewer.h"
#include "d/d_menu_fmap_map.h"
#include "m_Do/m_Do_graphic.h"
#if TARGET_PC
#include <dolphin/gx/GXExtra.h>
#endif
#include <cstring>
static u8 twoValueLineInterpolation(u8 i_value1, u8 i_value2, f32 i_param) {
@@ -494,6 +497,9 @@ void dMenu_FmapMap_c::_delete() {
mResTIMG = NULL;
}
if (mMapImage_p != NULL) {
#if TARGET_PC
GXDestroyCopyTex(mMapImage_p);
#endif
JKR_DELETE_ARRAY(mMapImage_p);
mMapImage_p = NULL;
}
+8
View File
@@ -17,6 +17,10 @@
#include "d/d_msg_scrn_arrow.h"
#include "d/d_lib.h"
#ifdef TARGET_PC
#include "dusk/achievements.h"
#endif
#if VERSION == VERSION_GCN_JPN
#define D_MENU_LETTER_LINE_MAX 9
#else
@@ -514,6 +518,10 @@ void dMenu_Letter_c::read_open_init() {
setAButtonString(0);
setBButtonString(0);
mpBlackTex->setAlpha(0);
#ifdef TARGET_PC
dusk::AchievementSystem::get().signal("open_letter");
#endif
}
void dMenu_Letter_c::read_open_move() {
+6 -6
View File
@@ -316,6 +316,12 @@ int dMeter2_c::_execute() {
}
int dMeter2_c::_draw() {
#if TARGET_PC
if (dusk::getSettings().game.disableMainHUD) {
return 1;
}
#endif
if (mpMap != NULL) {
mpMap->_draw();
}
@@ -424,12 +430,6 @@ void dMeter2_c::setLifeZero() {
void dMeter2_c::checkStatus() {
mStatus = 0;
#if TARGET_PC
if (dusk::getSettings().game.disableMainHUD) {
mStatus |= 0xF0000000;
}
#endif
field_0x12c = field_0x128;
field_0x128 = daPy_py_c::checkNowWolf();
+15 -1
View File
@@ -368,8 +368,22 @@ void dMeterButton_c::draw() {
}
if (var_r3) {
#ifdef TARGET_PC
if (dusk::frame_interp::get_ui_tick_pending()) {
mWasListen[i] = var_r22;
mWasRepeat[i] = var_r23;
} else {
var_r22 = mWasListen[i];
var_r23 = mWasRepeat[i];
}
#endif
if (var_r22) {
if (field_0x2e8[i] == 18.0f) {
#ifdef TARGET_PC
if (field_0x2e8[i] == 18.0f && dusk::frame_interp::get_ui_tick_pending())
#else
if (field_0x2e8[i] == 18.0f)
#endif
{
mDoAud_seStart(Z2SE_SY_HINT_BUTTON_BLINK, NULL, 0, 0);
}
+8 -15
View File
@@ -307,7 +307,7 @@ static u8 getOutFontNumberType(int param_0) {
}
}
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
static void setPlayerName(char* i_player_name, u8 param_2) {
if (param_2 != 0) {
strcpy(i_player_name, dComIfGs_getPlayerName());
@@ -1485,7 +1485,7 @@ bool jmessage_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_siz
char buffer[40];
switch (i_tag & 0xFF00FFFF) {
case MSGTAG_PLAYER_GENITIV:
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) {
setPlayerName(buffer, 1);
} else {
@@ -1495,7 +1495,7 @@ bool jmessage_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u32 i_siz
push_word(buffer);
return true;
case MSGTAG_HORSE_GENITIV:
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) {
setHorseName(buffer, 1);
} else {
@@ -1987,13 +1987,6 @@ 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 &&
@@ -2066,7 +2059,7 @@ bool jmessage_tSequenceProcessor::do_isReady() {
case 0:
case 5:
case 6:
if (mDoCPd_c::getTrigA(PAD_1) || field_0xb2 != 0) {
if (mDoCPd_c::getTrigA(PAD_1) || field_0xb2 != 0 IF_DUSK(|| (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)))) {
field_0xa4 = 0;
pReference->onBatchFlag();
pReference->setCharCnt(D_MSG_CLASS_CHAR_CNT_MAX);
@@ -4270,7 +4263,7 @@ bool jmessage_string_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u3
char buffer[40];
switch (i_tag & 0xFF00FFFF) {
case MSGTAG_PLAYER_GENITIV:
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) {
setPlayerName(buffer, 1);
} else {
@@ -4281,7 +4274,7 @@ bool jmessage_string_tMeasureProcessor::do_tag(u32 i_tag, void const* i_data, u3
stack_pushCurrent(buffer);
break;
case MSGTAG_HORSE_GENITIV:
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) {
setHorseName(buffer, 1);
} else {
@@ -4878,7 +4871,7 @@ bool jmessage_string_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data,
char buffer[40];
switch (i_tag & 0xFF00FFFF) {
case MSGTAG_PLAYER_GENITIV:
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) {
setPlayerName(buffer, 1);
} else {
@@ -4889,7 +4882,7 @@ bool jmessage_string_tRenderingProcessor::do_tag(u32 i_tag, void const* i_data,
push_word(buffer);
break;
case MSGTAG_HORSE_GENITIV:
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
if (dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_GERMAN) {
setHorseName(buffer, 1);
} else {
+65 -3
View File
@@ -24,12 +24,17 @@
#include "f_op/f_op_msg_mng.h"
#include <cstdio>
#include <cstring>
#include "JSystem/JKernel/JKRExpHeap.h"
#include "dusk/version.hpp"
#include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_lib.h"
#include "JSystem/JKernel/JKRExpHeap.h"
#if TARGET_PC
#include "dusk/settings.h"
#include <vector>
#include <array>
#include <algorithm>
#endif
static void dMsgObject_addFundRaising(s16 param_0);
@@ -1592,7 +1597,7 @@ u8 dMsgObject_c::isSend() {
return 2;
}
} else {
if (IF_DUSK((dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) ||)
if (IF_DUSK((dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0) && !isShopItemMessage()) ||)
mDoCPd_c::getTrigA(0) != 0 || mDoCPd_c::getTrigB(0) != 0) {
return 2;
}
@@ -1643,7 +1648,30 @@ void dMsgObject_c::readMessageGroupLocal(mDoDvdThd_mountXArchive_c** p_arcMount)
#else
#if TARGET_PC
// Original game UB
snprintf(arcName, sizeof(arcName), "/res/Msgus/bmgres%d.arc", msgGroup);
if (dusk::version::isRegionPal()) {
switch (dComIfGs_getPalLanguage()) {
case dSv_player_config_c::LANGUAGE_GERMAN:
snprintf(arcName, sizeof(arcName), "/res/Msgde/bmgres%d.arc", msgGroup);
break;
case dSv_player_config_c::LANGUAGE_FRENCH:
snprintf(arcName, sizeof(arcName), "/res/Msgfr/bmgres%d.arc", msgGroup);
break;
case dSv_player_config_c::LANGUAGE_SPANISH:
snprintf(arcName, sizeof(arcName), "/res/Msgsp/bmgres%d.arc", msgGroup);
break;
case dSv_player_config_c::LANGUAGE_ITALIAN:
snprintf(arcName, sizeof(arcName), "/res/Msgit/bmgres%d.arc", msgGroup);
break;
default:
snprintf(arcName, sizeof(arcName), "/res/Msguk/bmgres%d.arc", msgGroup);
}
} else if (dusk::version::isRegionJpn()) {
snprintf(arcName, sizeof(arcName), "/res/Msgjp/bmgres%d.arc", msgGroup);
} else {
snprintf(arcName, sizeof(arcName), "/res/Msgus/bmgres%d.arc", msgGroup);
}
#else
sprintf(arcName, "/res/Msgus/bmgres%d.arc", msgGroup);
#endif
@@ -1841,6 +1869,40 @@ bool dMsgObject_c::isTalkMessage() {
return true;
}
#if TARGET_PC
bool dMsgObject_c::isShopItemMessage() {
// Probably a better way to do this than just listing every message id, but this works for now
// Note: Keep contents sorted so we can use binary search
const auto shopMsgIds = std::to_array<std::vector<s16>>({
{},
// zel_01.bmg - Seras Shop
{7001, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7013, 7014, 7022, 7023, 7028, 7029,
7044, 7045, 7053},
// zel_02.bmg - Kakariko Shops
{5251, 5253, 5254, 5256, 5258, 5259, 5653, 5654, 5656, 5660, 5661, 5664, 5665, 5697, 5698,
5699, 5803, 5804, 5806, 5810, 5811, 5812, 5814, 5821, 5823, 5824, 5987, 5988, 5989, 5990,
5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999},
// zel_03.bmg - Death Mountain Shop
{5303, 5304, 5306, 5310, 5311, 5314, 5315, 5322, 5323, 5324, 5496, 5497, 5498, 5499},
// zel_04.bmg - Castle Town Shops
{5407, 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5431,
5432, 5433, 5434, 5435, 5436, 5437, 5438, 5439, 5440, 5441, 5444, 5449, 5450, 5451, 5452,
5462},
// zel_05.bmg - Oocca Shop
{9428, 9429, 9430, 9431, 9432, 9437, 9443, 9448, 9449, 9451, 9459}
});
u16 id = mMessageID;
s16 group = dMsgObject_getGroupID();
if (group < shopMsgIds.size()) {
return std::ranges::binary_search(shopMsgIds[group], id);
}
return false;
}
#endif
const char* dMsgObject_c::getSmellName() {
JMSMesgInfo_c* info_header_p = (JMSMesgInfo_c*)((char*)mpMsgRes + 0x20);
char* data_ptr = (char*)info_header_p + info_header_p->header.size;
+9 -3
View File
@@ -20,6 +20,7 @@
#include "Z2AudioLib/Z2WolfHowlMgr.h"
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#include "dusk/settings.h"
#endif
@@ -580,9 +581,14 @@ void dMsgScrnHowl_c::drawWave() {
f17 = local_60;
f18 = local_64;
} else {
field_0x2134++;
if (field_0x2134 > 30) {
field_0x2134 = 0;
#if TARGET_PC
if (dusk::frame_interp::get_ui_tick_pending())
#endif
{
field_0x2134++;
if (field_0x2134 > 30) {
field_0x2134 = 0;
}
}
if (field_0x2134 < 15) {
local_dc = field_0x2134 / 15.0f;
+2 -2
View File
@@ -334,11 +334,11 @@ void dMsgUnit_c::setTag(int i_type, int i_value, char* o_buffer, bool param_4) {
vals[1] = ((dMsgUnit_inf1_section_t*)pInfoBlock)->entries[i_type].endFrame;
#endif
#if REGION_PAL
#if TARGET_PC || REGION_PAL
if (i_value == 1 ||
(dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_FRENCH &&
i_value == 0)) {
#elif !REGION_USA
#elif !REGION_USA // Dusk TODO: What? This checks for Spanish when *not* PAL or USA?
if (i_value == 1 ||
(dComIfGs_getPalLanguage() == dSv_player_config_c::LANGUAGE_SPANISH &&
i_value == 0)) {
+300 -99
View File
@@ -8,9 +8,15 @@
#include "m_Do/m_Do_controller_pad.h"
#include <cstdio>
#include <cstring>
#include "JSystem/J2DGraph/J2DAnmLoader.h"
#include "dusk/version.hpp"
#include "f_op/f_op_msg_mng.h"
static bool isPalOrJpn() {
return dusk::version::isRegionPal() || dusk::version::isRegionJpn();
}
static const char* l_mojiHira[65] = {
"", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "",
@@ -66,15 +72,31 @@ static const char* l_mojiEisu[65] = {
"X", "k", "x", ",", "L", "Y", "l", "y", ".", "M", "Z", "m", "z", " ",
};
#if REGION_PAL
static char* l_mojiEisuPal_1[65] = {
#if TARGET_PC
// The game normally mutates this string list to fill in the real character codes.
// That can't work on a modern platform, so instead I've filled them out ahead of time.
static const char* l_mojiEisuPal_1[65] = {
"A", "N", "\xC0", "\xCF", "1", "B", "O", "\xC1", "\xD0", "2", "C", "P", "\xC2", "\xD1", "3", "D", "Q",
"\xC3", "\xD2", "4", "E", "R", "\xC4", "\xD3", "5", "F", "S", "\xC5", "\xD4", "6", "G", "T", "\xC6", "\xD5",
"7", "H", "U", "\xC7", "\xD6", "8", "I", "V", "\xC8", "\xD7", "9", "J", "W", "\xC9", "\xD8", "0", "K",
"X", "\xCA", "\xD9", ",", "L", "Y", "\xCB", "\xDA", ".", "M", "Z", "\xCC", "\xDB", " ",
};
static const char* l_mojiEisuPal_2[65] = {
"a", "n", "\xE0", "\xEF", "1", "b", "o", "\xE1", "\xF0", "2", "c", "p", "\xE2", "\xF1", "3", "d", "q",
"\xE3", "\xF2", "4", "e", "r", "\xE4", "\xF3", "5", "f", "s", "\xE5", "\xF4", "6", "g", "t", "\xE6",
"\xF5", "7", "h", "u", "\xE7", "\xF6", "8", "i", "v", "\xE8", "\xF7", "9", "j", "w", "\xE9", "\xF8", "0",
"k", "x", "\xEA", "\xF9", ",", "l", "y", "\xEB", "\xFA", ".", "m", "z", "\xEC", "\xFB", " ",
};
#elif REGION_PAL
static const char* l_mojiEisuPal_1[65] = {
"A", "N", "AA", "BB", "1", "B", "O", "CC", "DD", "2", "C", "P", "EE", "FF", "3", "D", "Q",
"GG", "HH", "4", "E", "R", "II", "JJ", "5", "F", "S", "KK", "LL", "6", "G", "T", "MM", "NN",
"7", "H", "U", "OO", "PP", "8", "I", "V", "QQ", "RR", "9", "J", "W", "SS", "TT", "0", "K",
"X", "UU", "VV", ",", "L", "Y", "WW", "XX", ".", "M", "Z", "YY", "ZZ", " ",
};
static char* l_mojiEisuPal_2[65] = {
static const char* l_mojiEisuPal_2[65] = {
"a", "n", "aa", "bb", "1", "b", "o", "cc", "dd", "2", "c", "p", "ee", "ff", "3", "d", "q",
"gg", "hh", "4", "e", "r", "ii", "jj", "5", "f", "s", "kk", "ll", "6", "g", "t", "mm",
"nn", "7", "h", "u", "oo", "pp", "8", "i", "v", "qq", "rr", "9", "j", "w", "ss", "tt", "0",
@@ -82,6 +104,16 @@ static char* l_mojiEisuPal_2[65] = {
};
#endif
#if TARGET_PC
// ' ' (full-width space)
#define SPACE_MAYBE_FULL (dusk::version::isRegionJpn() ? '\x81\x40' : ' ')
#elif REGION_JPN
// ' ' (full-width space)
#define SPACE_MAYBE_FULL '\x81\x40'
#else
#define SPACE_MAYBE_FULL ' '
#endif
static dNm_HIO_c g_nmHIO;
typedef void (dName_c::*selProcFunc)(void);
@@ -163,13 +195,18 @@ void dName_c::init() {
field_0x2ac = mSelProc;
field_0x2ad = mSelProc;
field_0x2ae = field_0x2ac;
#if REGION_PAL || REGION_JPN
#if TARGET_PC
mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO;
#elif REGION_PAL || REGION_JPN
mMojiSet = MOJI_HIRA;
#else
mMojiSet = MOJI_EIGO;
#endif
mPrevMojiSet = 255;
#if REGION_PAL || REGION_JPN
#if TARGET_PC
mSelMenu = isPalOrJpn() ? MENU_HIRA : MENU_END;
mPrevSelMenu = isPalOrJpn() ? MENU_HIRA : MENU_END;
#elif REGION_PAL || REGION_JPN
mSelMenu = MENU_HIRA;
mPrevSelMenu = MENU_HIRA;
#else
@@ -187,7 +224,8 @@ void dName_c::initial() {
mNextNameStr[0] = 0;
}
#if REGION_PAL || REGION_JPN
#if TARGET_PC || REGION_PAL || REGION_JPN
IF_DUSK_BLOCK(isPalOrJpn())
if (mSelProc == PROC_MOJI_SELECT) {
mMenuIcon[mMojiSet]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale);
mMenuText[mMojiSet]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF));
@@ -196,6 +234,7 @@ void dName_c::initial() {
mMenuText[mPrevMojiSet]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF));
}
}
IF_DUSK_BLOCK_END
#endif
}
@@ -230,8 +269,8 @@ void dName_c::_move() {
stick->checkTrigger();
(this->*SelProc[mSelProc])();
#if REGION_PAL || REGION_JPN
if (mDoCPd_c::getTrigY(PAD_1)) {
#if TARGET_PC || REGION_PAL || REGION_JPN
if (IF_DUSK(isPalOrJpn() &&) mDoCPd_c::getTrigY(PAD_1)) {
mDoAud_seStart(Z2SE_SY_DUMMY, 0, 0, 0);
mPrevMojiSet = mMojiSet;
mMojiSet++;
@@ -245,8 +284,8 @@ void dName_c::_move() {
mojiListChange();
} else {
#endif
#if REGION_JPN
if (mDoCPd_c::getTrigX(PAD_1)) {
#if TARGET_PC || REGION_JPN
if (IF_DUSK(dusk::version::isRegionJpn() &&) mDoCPd_c::getTrigX(PAD_1)) {
if (mCurPos != 0) {
if (mojiChange(mCurPos - 1) == 1) {
mDoAud_seStart(Z2SE_SY_DUMMY, 0, 0, 0);
@@ -283,12 +322,14 @@ void dName_c::_move() {
backSpace();
}
} else if (mDoCPd_c::getTrigStart(PAD_1)) {
#define EIGO_OR_END DUSK_IF_ELSE((dusk::version::isRegionPal() ? MENU_EIGO : MENU_END), MENU_END)
#if REGION_PAL
if ((mSelProc != PROC_MENU_SELECT || mSelMenu != MENU_EIGO) &&
(mSelProc == PROC_MENU_SELECT || mSelProc == PROC_MOJI_SELECT))
{
#else
if ((mSelProc != PROC_MENU_SELECT || mSelMenu != MENU_END) &&
if ((mSelProc != PROC_MENU_SELECT || mSelMenu != EIGO_OR_END) &&
(mSelProc == PROC_MENU_SELECT || mSelProc == PROC_MOJI_SELECT))
{
#endif
@@ -297,7 +338,7 @@ void dName_c::_move() {
#if REGION_PAL
mSelMenu = MENU_EIGO;
#else
mSelMenu = MENU_END;
mSelMenu = EIGO_OR_END;
#endif
switch (mSelProc) {
@@ -314,10 +355,10 @@ void dName_c::_move() {
}
}
}
#if REGION_JPN
#if TARGET_PC || REGION_JPN
}
#endif
#if REGION_PAL || REGION_JPN
#if TARGET_PC || REGION_PAL || REGION_JPN
}
#endif
@@ -327,10 +368,9 @@ void dName_c::_move() {
int dName_c::nameCheck() {
for (int i = 8, len = 7; i > 0; i--) {
#if REGION_JPN
// ' ' (full-width space)
if (mChrInfo[len].mCharacter != ' ' && mChrInfo[len].mCharacter != '\x81\x40') {
#else
if (mChrInfo[len].mCharacter != ' ') {
if (mChrInfo[len].mCharacter != ' ' IF_DUSK(&& (!dusk::version::isRegionJpn() || mChrInfo[len].mCharacter != '\x81\x40'))) {
#endif
return len + 1;
}
@@ -344,8 +384,8 @@ void dName_c::playNameSet(int nameLength) {
char* str = mInputStr;
for (int i = 0; i < nameLength; i++) {
#if REGION_JPN
if (mChrInfo[i].mMojiSet == 2) {
#if TARGET_PC || REGION_JPN
if (!dusk::version::isRegionJpn() || mChrInfo[i].mMojiSet == 2) {
*str = mChrInfo[i].mCharacter;
str += 1;
} else {
@@ -727,7 +767,34 @@ int dName_c::getMoji() {
int result = -1;
const char* moji;
#if REGION_PAL
#if TARGET_PC
if (dusk::version::isRegionPal()) {
switch (mMojiSet) {
case MOJI_HIRA:
moji = l_mojiEisuPal_1[mCharRow + mCharColumn * 5];
break;
case MOJI_KATA:
moji = l_mojiEisuPal_2[mCharRow + mCharColumn * 5];
break;
default:
abort();
}
} else {
switch (mMojiSet) {
case MOJI_HIRA:
moji = l_mojiHira[mCharRow + mCharColumn * 5];
break;
case MOJI_KATA:
moji = l_mojikata[mCharRow + mCharColumn * 5];
break;
case MOJI_EIGO:
moji = l_mojiEisu[mCharRow + mCharColumn * 5];
break;
default:
abort();
}
}
#elif REGION_PAL
switch (mMojiSet) {
case MOJI_HIRA:
moji = l_mojiEisuPal_1[mCharRow + mCharColumn * 5];
@@ -750,7 +817,17 @@ int dName_c::getMoji() {
}
#endif
#if REGION_JPN
#if TARGET_PC
if (dusk::version::isRegionJpn()) {
if (*(u8*)moji >> 4 == 0x8 || *(u8*)moji >> 4 == 0x9) {
result = *(u16*)moji;
} else {
result = *moji;
}
} else {
result = *moji;
}
#elif REGION_JPN
if (*(u8*)moji >> 4 == 0x8 || *(u8*)moji >> 4 == 0x9) {
result = *(u16*)moji;
} else {
@@ -763,6 +840,14 @@ int dName_c::getMoji() {
return result;
}
#if TARGET_PC
#define CHAR_TRUNC(val) (dusk::version::isRegionPal() ? val & 0xFF : val)
#elif REGION_PAL
#define CHAR_TRUNC(val) (val & 0xFF)
#else
#define CHAR_TRUNC(val) val
#endif
void dName_c::setMoji(int moji) {
if (mCurPos == 8 || nameCheck() == 8) {
mDoAud_seStart(Z2SE_SYS_ERROR, NULL, 0, 0);
@@ -771,24 +856,14 @@ void dName_c::setMoji(int moji) {
s32 notEmpty = false;
for (int i = mCurPos; i < 8; i++) {
#if REGION_JPN
// ' ' (full-width space)
if (mChrInfo[i].mCharacter != '\x81\x40') {
#else
if (mChrInfo[i].mCharacter != ' ') {
#endif
if (mChrInfo[i].mCharacter != SPACE_MAYBE_FULL) {
notEmpty = true;
break;
}
}
if (notEmpty) {
#if REGION_JPN
// ' ' (full-width space)
if (mChrInfo[7].mCharacter == '\x81\x40') {
#else
if (mChrInfo[7].mCharacter == ' ') {
#endif
if (mChrInfo[7].mCharacter == SPACE_MAYBE_FULL) {
for (int i = 6; i >= mCurPos; i--) {
mChrInfo[i + 1] = mChrInfo[i];
}
@@ -797,11 +872,7 @@ void dName_c::setMoji(int moji) {
mChrInfo[mCurPos].mRow = mCharRow;
mChrInfo[mCurPos].mMojiSet = mMojiSet;
mChrInfo[mCurPos].field_0x3 = 1;
#if REGION_PAL
mChrInfo[mCurPos].mCharacter = moji & 0xFF;
#else
mChrInfo[mCurPos].mCharacter = moji;
#endif
mChrInfo[mCurPos].mCharacter = CHAR_TRUNC(moji);
if (mCurPos != 8) {
mLastCurPos = mCurPos;
@@ -814,11 +885,7 @@ void dName_c::setMoji(int moji) {
mChrInfo[mCurPos].mRow = mCharRow;
mChrInfo[mCurPos].mMojiSet = mMojiSet;
mChrInfo[mCurPos].field_0x3 = 1;
#if REGION_PAL
mChrInfo[mCurPos].mCharacter = moji & 0xFF;
#else
mChrInfo[mCurPos].mCharacter = moji;
#endif
mChrInfo[mCurPos].mCharacter = CHAR_TRUNC(moji);
if (mCurPos != 8) {
mLastCurPos = mCurPos;
@@ -844,13 +911,8 @@ void dName_c::setNameText() {
"CR\x1b"
"CC[000000]\x1bGM[0]%c\x1bHM\x1b"
"CC[ffffff]\x1bGM[0]%c",
#if REGION_PAL
(u8)mChrInfo[i].mCharacter & 0xFF,
(u8)mChrInfo[i].mCharacter & 0xFF
#else
(u8)mChrInfo[i].mCharacter,
(u8)mChrInfo[i].mCharacter
#endif
CHAR_TRUNC((u8)mChrInfo[i].mCharacter),
CHAR_TRUNC((u8)mChrInfo[i].mCharacter)
);
#if REGION_JPN
} else {
@@ -889,7 +951,29 @@ void dName_c::nameCursorMove() {
void dName_c::selectCursorMove() {
int idx;
#if REGION_PAL
#if TARGET_PC
if (dusk::version::isRegionPal()) {
if (mCharColumn < 3) {
idx = 0;
} else if (mCharColumn < 6) {
idx = 1;
} else if (mCharColumn >= 6) {
idx = 2;
}
} else if (dusk::version::isRegionJpn()) {
if (mCharColumn < 3) {
idx = 0;
} else if (mCharColumn < 6) {
idx = 1;
} else if (mCharColumn < 8) {
idx = 2;
} else if (mCharColumn >= 8) {
idx = 3;
}
} else {
idx = 3;
}
#elif REGION_PAL
if (mCharColumn < 3) {
idx = 0;
} else if (mCharColumn < 6) {
@@ -930,7 +1014,36 @@ void dName_c::selectCursorMove() {
void dName_c::menuCursorPosSet() {
mPrevSelMenu = mSelMenu;
#if REGION_PAL
#if TARGET_PC
if (dusk::version::isRegionPal()) {
if (mCharColumn < 3) {
mSelMenu = MENU_HIRA;
} else if (mCharColumn < 6) {
mSelMenu = MENU_KATA;
} else if (mCharColumn >= 6) {
mSelMenu = MENU_EIGO;
}
} else if (dusk::version::isRegionJpn()) {
if (mCharColumn < 3) {
mSelMenu = MENU_HIRA;
return;
}
if (mCharColumn < 6) {
mSelMenu = MENU_KATA;
return;
}
if (mCharColumn < 8) {
mSelMenu = MENU_EIGO;
return;
}
if (mCharColumn >= 8) {
mSelMenu = MENU_END;
return;
}
} else {
mSelMenu = MENU_END;
}
#elif REGION_PAL
if (mCharColumn < 3) {
mSelMenu = MENU_HIRA;
} else if (mCharColumn < 6) {
@@ -961,28 +1074,28 @@ void dName_c::menuCursorPosSet() {
}
void dName_c::MenuSelect() {
#if REGION_PAL || REGION_JPN
if (stick->checkRightTrigger()) {
#if TARGET_PC || REGION_PAL || REGION_JPN
if (isPalOrJpn() && stick->checkRightTrigger()) {
mDoAud_seStart(Z2SE_SY_CURSOR_OPTION, NULL, 0, 0);
mPrevSelMenu = mSelMenu;
mSelMenu++;
#if REGION_PAL
if (mSelMenu > MENU_EIGO) {
#else
if (mSelMenu > MENU_END) {
if (mSelMenu > EIGO_OR_END) {
#endif
mSelMenu = MENU_HIRA;
}
MenuSelectAnmInit();
mSelProc = PROC_MENU_SEL_ANM;
} else if (stick->checkLeftTrigger()) {
} else if (isPalOrJpn() && stick->checkLeftTrigger()) {
mDoAud_seStart(Z2SE_SY_CURSOR_OPTION, NULL, 0, 0);
mPrevSelMenu = mSelMenu;
if (mSelMenu == MENU_HIRA) {
#if REGION_JPN
mSelMenu = MENU_END;
#else
mSelMenu = MENU_EIGO;
mSelMenu = dusk::version::isRegionJpn() ? MENU_END : MENU_EIGO;
#endif
} else {
mSelMenu--;
@@ -1009,7 +1122,7 @@ void dName_c::MenuSelect() {
#if REGION_PAL
if (mSelMenu == MENU_EIGO) {
#else
if (mSelMenu == MENU_END) {
if (mSelMenu == EIGO_OR_END) {
#endif
if (nameCheck() != 0) {
mDoAud_seStart(Z2SE_SY_NAME_OK, NULL, 0, 0);
@@ -1024,7 +1137,7 @@ void dName_c::MenuSelect() {
#if REGION_PAL
if (mSelMenu == MENU_EIGO) {
#else
if (mSelMenu == MENU_END) {
if (mSelMenu == EIGO_OR_END) {
#endif
if (nameCheck() != 0) {
mDoAud_seStart(Z2SE_SY_NAME_OK, NULL, 0, 0);
@@ -1067,9 +1180,11 @@ void dName_c::MenuSelectAnm2() {
if (canMove == true) {
if (prevMenu_i != mojiSet_i) {
mMenuText[prevMenu_i]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF));
#if REGION_PAL || REGION_JPN
#if TARGET_PC || REGION_PAL || REGION_JPN
IF_DUSK_BLOCK(isPalOrJpn())
mMenuIcon[mojiSet_i]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale);
mMenuText[mojiSet_i]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF));
IF_DUSK_BLOCK_END
#endif
}
selectCursorMove();
@@ -1081,6 +1196,11 @@ void dName_c::MenuSelectAnm2() {
void dName_c::MenuSelectAnm3() {}
void dName_c::menuAbtnSelect() {
#if TARGET_PC
if (dusk::version::isRegionPal() && mSelMenu == MENU_EIGO) {
goto pal_eigo;
}
#endif
switch (mSelMenu) {
case MENU_HIRA:
case MENU_KATA:
@@ -1098,6 +1218,7 @@ void dName_c::menuAbtnSelect() {
#else
case MENU_END:
#endif
IF_DUSK(pal_eigo:)
int nameNum = nameCheck();
if (nameNum != 0) {
playNameSet(nameNum);
@@ -1116,44 +1237,33 @@ void dName_c::backSpace() {
if (mCurPos != 0) {
mDoAud_seStart(Z2SE_SY_NAME_DELETE, NULL, 0, 0);
#if REGION_JPN
// ' ' (full-width space)
if (mCurPos == 8 && mChrInfo[7].mCharacter != '\x81\x40') {
#else
if (mCurPos == 8 && mChrInfo[7].mCharacter != ' ') {
#endif
if (mCurPos == 8 && mChrInfo[7].mCharacter != SPACE_MAYBE_FULL) {
mChrInfo[7].mColumn = 7;
mChrInfo[7].mRow = 1;
#if REGION_PAL || REGION_JPN
#if TARGET_PC
mChrInfo[7].mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO;
#elif REGION_PAL || REGION_JPN
mChrInfo[7].mMojiSet = MOJI_HIRA;
#else
mChrInfo[7].mMojiSet = MOJI_EIGO;
#endif
mChrInfo[7].field_0x3 = 1;
#if REGION_JPN
// ' ' (full-width space)
mChrInfo[7].mCharacter = '\x81\x40';
#else
mChrInfo[7].mCharacter = ' ';
#endif
mChrInfo[7].mCharacter = SPACE_MAYBE_FULL;
} else {
for (int i = mCurPos - 1; i < 7; i++) {
mChrInfo[i] = mChrInfo[i + 1];
}
mChrInfo[7].mColumn = 7;
mChrInfo[7].mRow = 1;
#if REGION_PAL || REGION_JPN
#if TARGET_PC
mChrInfo[7].mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO;
#elif REGION_PAL || REGION_JPN
mChrInfo[7].mMojiSet = MOJI_HIRA;
#else
mChrInfo[7].mMojiSet = MOJI_EIGO;
#endif
mChrInfo[7].field_0x3 = 1;
#if REGION_JPN
// ' ' (full-width space)
mChrInfo[7].mCharacter = '\x81\x40';
#else
mChrInfo[7].mCharacter = ' ';
#endif
mChrInfo[7].mCharacter = SPACE_MAYBE_FULL;
}
setNameText();
@@ -1164,7 +1274,31 @@ void dName_c::backSpace() {
}
void dName_c::mojiListChange() {
#if REGION_PAL
#if TARGET_PC
const char** mojiSet;
if (dusk::version::isRegionPal()) {
switch (mMojiSet) {
case MOJI_HIRA:
mojiSet = l_mojiEisuPal_1;
break;
case MOJI_KATA:
mojiSet = l_mojiEisuPal_2;
break;
}
} else {
switch (mMojiSet) {
case MOJI_HIRA:
mojiSet = l_mojiHira;
break;
case MOJI_KATA:
mojiSet = l_mojikata;
break;
case MOJI_EIGO:
mojiSet = l_mojiEisu;
break;
}
}
#elif REGION_PAL
char** mojiSet;
switch (mMojiSet) {
@@ -1212,7 +1346,8 @@ void dName_c::mojiListChange() {
strcpy(mMojiText[i], buf);
}
#if REGION_PAL || REGION_JPN
#if TARGET_PC || REGION_PAL || REGION_JPN
IF_DUSK_BLOCK(isPalOrJpn())
if (mSelProc == PROC_MOJI_SELECT) {
mMenuIcon[mMojiSet]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale);
mMenuText[mMojiSet]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF));
@@ -1221,6 +1356,7 @@ void dName_c::mojiListChange() {
mMenuText[mPrevMojiSet]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF));
}
}
IF_DUSK_BLOCK_END
#endif
}
@@ -1241,9 +1377,11 @@ void dName_c::menuCursorMove2() {
if (menu_i != mojiSet_i) {
mMenuIcon[menu_i]->scale(g_nmHIO.mMenuScale, g_nmHIO.mMenuScale);
mMenuText[menu_i]->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF));
#if REGION_PAL || REGION_JPN
#if TARGET_PC || REGION_PAL || REGION_JPN
IF_DUSK_BLOCK(isPalOrJpn())
mMenuIcon[mojiSet_i]->scale(1.0f, 1.0f);
mMenuText[mojiSet_i]->setWhite(JUtility::TColor(0x96, 0x96, 0x96, 0xFF));
IF_DUSK_BLOCK_END
#endif
}
@@ -1265,7 +1403,9 @@ void dName_c::selectCursorPosSet(int row) {
mCharColumn = 3;
break;
case MENU_EIGO:
#if REGION_PAL
#if TARGET_PC
mCharColumn = dusk::version::isRegionPal() ? 8 : 6;
#elif REGION_PAL
mCharColumn = 8;
#else
mCharColumn = 6;
@@ -1481,9 +1621,11 @@ void dName_c::screenSet() {
#endif
}
#if !(REGION_PAL || REGION_JPN)
#if TARGET_PC || !(REGION_PAL || REGION_JPN)
IF_DUSK_BLOCK(!isPalOrJpn())
mMenuIcon[0]->hide();
mMenuIcon[1]->hide();
IF_DUSK_BLOCK_END
#endif
mMojiPane = nameIn.NameInScr->search(MULTI_CHAR('moji_n'));
@@ -1501,25 +1643,28 @@ void dName_c::screenSet() {
((J2DTextBox*)nameTagPane[i])->setFont(nameIn.font);
((J2DTextBox*)nameTagPane[i])->setString(72, "");
((J2DTextBox*)nameTagPane[i])->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF));
#if REGION_PAL
#if TARGET_PC || REGION_PAL
IF_DUSK_BLOCK(dusk::version::isRegionPal())
((J2DTextBox*)nameTagPane[i])->resize(24.0f, 23.0f);
IF_DUSK_BLOCK_END
#endif
mNameText[i] = ((J2DTextBox*)nameTagPane[i])->getStringPtr();
}
#if REGION_PAL
#if REGION_PAL // DUSK version note: this code mutates strings. We just edit the table.
IF_DUSK_BLOCK(dusk::version::isRegionPal())
int idx = 2;
static u8 palMoji00[13] = {
static const u8 palMoji00[13] = {
0xC0, 0xC1, 0xC2, 0xC4, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE,
};
static u8 palMoji01[13] = {
static const u8 palMoji01[13] = {
0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD6, 0x8C, 0xD9, 0xDA, 0xDB, 0xDC, 0x2D,
};
static u8 palMoji10[13] = {
static const u8 palMoji10[13] = {
0xE0, 0xE1, 0xE2, 0xE4, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE,
};
static u8 palMoji11[13] = {
static const u8 palMoji11[13] = {
0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF6, 0x9C, 0xF9, 0xFA, 0xFB, 0xFC, 0xDF,
};
@@ -1536,6 +1681,7 @@ void dName_c::screenSet() {
l_mojiEisuPal_2[idx + 1][0] = palMoji11[i];
l_mojiEisuPal_2[idx + 1][1] = 0;
}
IF_DUSK_BLOCK_END
#endif
mCharColumn = 0;
@@ -1574,18 +1720,15 @@ void dName_c::displayInit() {
mNameCursor[i]->hide();
mChrInfo[i].mColumn = 7;
mChrInfo[i].mRow = 1;
#if REGION_PAL || REGION_JPN
#if TARGET_PC
mChrInfo[i].mMojiSet = isPalOrJpn() ? MOJI_HIRA : MOJI_EIGO;
#elif REGION_PAL || REGION_JPN
mChrInfo[i].mMojiSet = MOJI_HIRA;
#else
mChrInfo[i].mMojiSet = MOJI_EIGO;
#endif
mChrInfo[i].field_0x3 = 1;
#if REGION_JPN
// ' ' (full-width space)
mChrInfo[i].mCharacter = '\x81\x40';
#else
mChrInfo[i].mCharacter = ' ';
#endif
mChrInfo[i].mCharacter = SPACE_MAYBE_FULL;
}
mIsInputEnd = false;
@@ -1596,7 +1739,63 @@ void dName_c::NameStrSet() {
int i = 0;
while (*moji != 0) {
#if REGION_PAL
#if TARGET_PC
if (dusk::version::isRegionPal()) {
mChrInfo[i].mCharacter = static_cast<u8>(*moji);
for (int j = 0; j < 65; j++) {
if (mChrInfo[i].mCharacter == *(u8*)l_mojiEisuPal_1[j] ||
mChrInfo[i].mCharacter == *(u16*)l_mojiEisuPal_2[j])
{
mChrInfo[i].mColumn = j / 5;
mChrInfo[i].mRow = j % 5;
mChrInfo[i].mMojiSet = MOJI_HIRA;
break;
}
}
moji++;
i++;
} else {
if (*(u8*)moji >> 4 == 8 || *(u8*)moji >> 4 == 9) {
mChrInfo[i].mCharacter = *(u16*)moji;
for (int j = 0; j < 65; j++) {
if (mChrInfo[i].mCharacter == *(u16*)l_mojiHira[j] ||
mChrInfo[i].mCharacter == *(u16*)l_mojiHira2[j] ||
mChrInfo[i].mCharacter == *(u16*)l_mojiHira3[j])
{
mChrInfo[i].mColumn = j / 5;
mChrInfo[i].mRow = j % 5;
mChrInfo[i].mMojiSet = MOJI_HIRA;
break;
} else if (mChrInfo[i].mCharacter == *(u16*)l_mojikata[j] ||
mChrInfo[i].mCharacter == *(u16*)l_mojikata2[j] ||
mChrInfo[i].mCharacter == *(u16*)l_mojikata3[j])
{
mChrInfo[i].mColumn = j / 5;
mChrInfo[i].mRow = j % 5;
mChrInfo[i].mMojiSet = MOJI_KATA;
break;
}
}
moji += 2;
i++;
} else {
mChrInfo[i].mCharacter = *moji;
for (int j = 0; j < 65; j++) {
if (mChrInfo[i].mCharacter == *(u8*)l_mojiEisu[j]) {
mChrInfo[i].mColumn = j / 5;
mChrInfo[i].mRow = j % 5;
mChrInfo[i].mMojiSet = MOJI_EIGO;
break;
}
}
moji++;
i++;
}
}
#elif REGION_PAL
mChrInfo[i].mCharacter = static_cast<u8>(*moji);
for (int j = 0; j < 65; j++) {
@@ -1669,7 +1868,9 @@ s32 dName_c::getMenuPosIdx(u8 selPos) {
result = 1;
break;
case 2:
#if REGION_PAL
#if TARGET_PC
result = dusk::version::isRegionPal() ? 3 : 2;
#elif REGION_PAL
result = 3;
#else
result = 2;
+6 -1
View File
@@ -1972,7 +1972,12 @@ void dPa_light8PcallBack::draw(JPABaseEmitter* param_1, JPABaseParticle* param_2
JGeometry::TVec3<f32> local_154;
JGeometry::TVec3<f32> local_160;
JGeometry::TVec3<f32> local_16c;
dPa_setWindPower(param_2);
#if TARGET_PC
if (dusk::frame_interp::is_sim_frame())
#endif
{
dPa_setWindPower(param_2);
}
MTXIdentity(local_60);
MTXIdentity(auStack_90);
param_2->getBaseAxis(&local_10c);
-4
View File
@@ -102,11 +102,7 @@ static void setIndirectTex(J3DModelData* i_modelData) {
texture->setResTIMG(i, *mDoGph_gInf_c::getFrameBufferTimg());
}
if (memcmp(textureName, "Zbuffer", 8) == 0) {
#if !TARGET_PC
texture->setResTIMG(i, *mDoGph_gInf_c::getZbufferTimg());
#else
DuskLog.warn("Zbuffer texture binding not yet supported");
#endif
}
}
}
+173 -9
View File
@@ -24,6 +24,7 @@
#include "JSystem/JUtility/JUTConsole.h"
#include "dusk/logging.h"
#include "dusk/version.hpp"
#if !PLATFORM_GCN
#include <revolution/os.h>
@@ -44,7 +45,12 @@ struct homeBtnData {
};
#endif
#if VERSION == VERSION_SHIELD
#if TARGET_PC
using namespace dusk::version;
#define LOGO_ARC versionSelect<const char*>({{GameVersion::GcnJpn, "Logo"}, {GameVersion::GcnPal, "LogoPal"}}, "LogoUs")
#define MSG_PATH versionSelect<const char*>({{GameVersion::GcnJpn, "/res/Msgjp/bmgres.arc"}}, "/res/Msgus/bmgres.arc")
#elif VERSION == VERSION_SHIELD
#define LOGO_ARC "LogoUs"
#define MSG_PATH "/res/Msgcn/bmgres.arc"
#elif VERSION == VERSION_GCN_JPN
@@ -789,7 +795,13 @@ dScnLogo_c::~dScnLogo_c() {
JKR_DELETE(mProgressiveNo);
JKR_DELETE(mProgressiveSel);
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC
if (getGameVersion() == GameVersion::GcnPal) {
mpPalLogoResCommand->getArchive()->removeResourceAll();
mpPalLogoResCommand->getArchive()->unmount();
mpPalLogoResCommand->destroy();
}
#elif VERSION == VERSION_GCN_PAL
mpPalLogoResCommand->getArchive()->removeResourceAll();
mpPalLogoResCommand->getArchive()->unmount();
mpPalLogoResCommand->destroy();
@@ -951,7 +963,8 @@ static int phase_0(dScnLogo_c* i_this) {
JUT_ASSERT(1528, i_this->mLogo01Heap != NULL);
JKRHEAP_NAME(i_this->mLogo01Heap, "Logo01");
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
IF_DUSK_BLOCK(getGameVersion() == GameVersion::GcnPal)
switch (i_this->getPalLanguage()) {
case 1:
i_this->mpPalLogoResCommand = mDoDvdThd_mountArchive_c::create("/res/Layout/LogoPalGm.arc", 0, NULL);
@@ -970,6 +983,7 @@ static int phase_0(dScnLogo_c* i_this) {
i_this->mpPalLogoResCommand = mDoDvdThd_mountArchive_c::create("/res/Layout/LogoPalUk.arc", 0, NULL);
break;
}
IF_DUSK_BLOCK_END
#endif
#if PLATFORM_WII || PLATFORM_SHIELD
@@ -990,7 +1004,8 @@ static int phase_1(dScnLogo_c* i_this) {
}
#endif
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
IF_DUSK_BLOCK(getGameVersion() == GameVersion::GcnPal)
if (!mDoDvdThd::SyncWidthSound) {
return cPhs_INIT_e;
}
@@ -998,6 +1013,7 @@ static int phase_1(dScnLogo_c* i_this) {
if (!i_this->mpPalLogoResCommand->sync()) {
return cPhs_INIT_e;
}
IF_DUSK_BLOCK_END
#endif
int rt;
@@ -1237,7 +1253,113 @@ void dScnLogo_c::logoInitGC() {
ResTIMG* dolbyImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 3);
mDolbyLogo = JKR_NEW dDlst_2D_c(dolbyImg, 189, 150, 232, 112, 255);
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC
if (getGameVersion() == GameVersion::GcnPal) {
u8 language = getPalLanguage();
if (language >= 5) {
language = 0;
}
static const char* choice[] = {
"50_60_choice_eng.bti",
"50_60_choice_ger.bti",
"50_60_choice_fra.bti",
"50_60_choice_spa.bti",
"50_60_choice_ita.bti",
};
static const char* yes[] = {
"60_set_eng.bti",
"60_set_ger.bti",
"60_set_fra.bti",
"60_set_spa.bti",
"60_set_ita.bti",
};
static const char* no[] = {
"50_set_eng.bti",
"50_set_ger.bti",
"50_set_fra.bti",
"50_set_spa.bti",
"50_set_ita.bti",
};
static const char* prog[] = {
"progressive_pro.bti",
"progressive_pro_gm.bti",
"progressive_pro_fr.bti",
"progressive_pro_sp.bti",
"progressive_pro_it.bti",
};
static const char* intr[] = {
"progressive_inter.bti",
"progressive_inter_gm.bti",
"progressive_inter_fr.bti",
"progressive_inter_sp.bti",
"progressive_inter_it.bti",
};
static const char* warning[] = {
"warning.bti",
"warning_gm.bti",
"warning_fr.bti",
"warning_sp.bti",
"warning_it.bti",
};
static const char* warningPs[] = {
"warning_pstart.bti",
"warning_pstart_gm.bti",
"warning_pstart_fr.bti",
"warning_pstart_sp.bti",
"warning_pstart_it.bti",
};
ResTIMG* warningImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', warning[language]);
mWarning = JKR_NEW dDlst_2D_c(warningImg, 0, 0, FB_WIDTH, FB_HEIGHT, 255);
ResTIMG* warnStartImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', warningPs[language]);
mWarningStart = JKR_NEW dDlst_2D_c(warnStartImg, 0, 359, FB_WIDTH, 48, 255);
ResTIMG* progChoiceImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', choice[language]);
mProgressiveChoice = JKR_NEW dDlst_2D_c(progChoiceImg, 113, 143, 416, 210, 255);
ResTIMG* progYesImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', yes[language]);
mProgressiveYes = JKR_NEW dDlst_2D_c(progYesImg, 121, 352, 200, 72, 255);
mProgressiveYes->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255));
ResTIMG* progNoImg = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', no[language]);
mProgressiveNo = JKR_NEW dDlst_2D_c(progNoImg, 320, 352, 200, 72, 255);
mProgressiveNo->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255));
mProgressivePro = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', prog[language]);
mProgressiveInter = (ResTIMG*)mpPalLogoResCommand->getArchive()->getResource('DAT ', intr[language]);
mProgressiveSel = JKR_NEW dDlst_2D_c(mProgressivePro, 153, 309, 336, 88, 255);
} else {
ResTIMG* warningImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 10);
mWarning = JKR_NEW dDlst_2D_c(warningImg, 0, 0, FB_WIDTH, FB_HEIGHT, 255);
ResTIMG* warnStartImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 11);
mWarningStart = JKR_NEW dDlst_2D_c(warnStartImg, 0, 359, FB_WIDTH, 48, 255);
ResTIMG* progChoiceImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 5);
mProgressiveChoice = JKR_NEW dDlst_2D_c(progChoiceImg, 113, 281, 416, 72, 255);
ResTIMG* progYesImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 9);
mProgressiveYes = JKR_NEW dDlst_2D_c(progYesImg, 211, 372, 80, 32, 255);
mProgressiveYes->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255));
ResTIMG* progNoImg = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 7);
mProgressiveNo = JKR_NEW dDlst_2D_c(progNoImg, 350, 372, 80, 32, 255);
mProgressiveNo->getPicture()->setWhite(JUtility::TColor(160, 160, 160, 255));
mProgressivePro = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 8);
mProgressiveInter = (ResTIMG*)dComIfG_getObjectRes(LOGO_ARC, 6);
mProgressiveSel = JKR_NEW dDlst_2D_c(mProgressivePro, 153, 309, 336, 88, 255);
}
#elif VERSION == VERSION_GCN_PAL
u8 language = getPalLanguage();
if (language >= 5) {
language = 0;
@@ -1395,7 +1517,30 @@ void dScnLogo_c::dvdDataLoad() {
mpButtonCommand = aramMount(BUTTON_RES_PATH, mDoExt_getJ2dHeap());
mpCardIconCommand = aramMount(ICON_RES_PATH, mDoExt_getJ2dHeap());
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC
if (getGameVersion() == GameVersion::GcnPal) {
switch (getPalLanguage()) {
case 1:
mpBmgResCommand = onMemMount("/res/Msgde/bmgres.arc");
break;
case 2:
mpBmgResCommand = onMemMount("/res/Msgfr/bmgres.arc");
break;
case 3:
mpBmgResCommand = onMemMount("/res/Msgsp/bmgres.arc");
break;
case 4:
mpBmgResCommand = onMemMount("/res/Msgit/bmgres.arc");
break;
case 0:
default:
mpBmgResCommand = onMemMount("/res/Msguk/bmgres.arc");
break;
}
} else {
mpBmgResCommand = onMemMount(MSG_PATH);
}
#elif VERSION == VERSION_GCN_PAL
switch (getPalLanguage()) {
case 1:
mpBmgResCommand = onMemMount("/res/Msgde/bmgres.arc");
@@ -1435,7 +1580,10 @@ void dScnLogo_c::dvdDataLoad() {
mpMsgResCommand[1] = aramMount(MSG_RES1_PATH, mDoExt_getJ2dHeap());
mpMsgResCommand[2] = aramMount(MSG_RES2_PATH, mDoExt_getJ2dHeap());
mpMsgResCommand[3] = aramMount(MSG_RES3_PATH, mDoExt_getJ2dHeap());
#if VERSION == VERSION_GCN_JPN
#if TARGET_PC
const auto res4Path = versionSelect<const char*>({{GameVersion::GcnJpn, "/res/Layout/msgres04.arc"}}, "/res/Layout/msgres04F.arc");
mpMsgResCommand[4] = aramMount( res4Path, mDoExt_getJ2dHeap());
#elif VERSION == VERSION_GCN_JPN
mpMsgResCommand[4] = aramMount("/res/Layout/msgres04.arc", mDoExt_getJ2dHeap());
#else
mpMsgResCommand[4] = aramMount("/res/Layout/msgres04F.arc", mDoExt_getJ2dHeap());
@@ -1445,7 +1593,23 @@ void dScnLogo_c::dvdDataLoad() {
mpMain2DCommand = onMemMount(MAIN2D_PATH);
#if VERSION == VERSION_GCN_JPN
#if TARGET_PC
const auto fontResPath = versionSelect<const char*>(
{
{GameVersion::GcnJpn, "/res/Fontjp/fontres.arc"},
{GameVersion::GcnPal, "/res/Fonteu/fontres.arc"},
}, "/res/Fontus/fontres.arc");
const auto fontRubyPath = versionSelect<const char*>(
{
{GameVersion::GcnJpn, "/res/Fontjp/rubyres.arc"},
{GameVersion::GcnPal, "/res/Fonteu/rubyres.arc"},
}, "/res/Fontus/rubyres.arc");
// Note: GCN_JPN mounts this archive as tail instead of head.
// I'm guessing this is fine since we have more RAM.
mpFontResCommand = onMemMount(fontResPath);
mpRubyResCommand = onMemMount(fontRubyPath);
#elif VERSION == VERSION_GCN_JPN
mpFontResCommand = mDoDvdThd_mountXArchive_c::create("/res/Fontjp/fontres.arc", 1, JKRArchive::MOUNT_MEM, NULL);
mpRubyResCommand = onMemMount("/res/Fontjp/rubyres.arc");
#elif VERSION == VERSION_GCN_PAL
@@ -1545,7 +1709,7 @@ static int dScnLogo_IsDelete(dScnLogo_c* i_this) {
return 1;
}
#if VERSION == VERSION_GCN_PAL || PLATFORM_WII || PLATFORM_SHIELD
#if TARGET_PC || VERSION == VERSION_GCN_PAL || PLATFORM_WII || PLATFORM_SHIELD
u8 dScnLogo_c::getPalLanguage() {
u8 language;
+16 -5
View File
@@ -5,19 +5,20 @@
#include "d/dolzel.h" // IWYU pragma: keep
#include "d/d_s_name.h"
#include "JSystem/JKernel/JKRExpHeap.h"
#include "d/d_com_inf_game.h"
#include "d/d_meter2_info.h"
#include "d/d_s_name.h"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/memory.h"
#include "dusk/settings.h"
#include "f_op/f_op_overlap_mng.h"
#include "f_op/f_op_scene_mng.h"
#include "m_Do/m_Do_Reset.h"
#include "m_Do/m_Do_graphic.h"
#include "m_Do/m_Do_machine.h"
#include "m_Do/m_Do_mtx.h"
#include "m_Do/m_Do_main.h"
#include "f_op/f_op_overlap_mng.h"
#include "dusk/memory.h"
#include "dusk/settings.h"
#include "m_Do/m_Do_mtx.h"
#if TARGET_PC
#define SHOW_TV_SETTINGS_SCREEN (this->mShowTvSettingsScreen)
@@ -412,6 +413,16 @@ void dScnName_c::changeGameScene() {
dKy_clear_game_init();
dComIfGs_resetDan();
dComIfGs_setRestartRoomParam(0);
#if TARGET_PC
if (dusk::getSettings().game.speedrunMode && dusk::getSettings().game.hideTvSettingsScreen) {
// start a new run on file load if a run isn't already in progress
if (!dusk::m_speedrunInfo.m_isRunStarted) {
dusk::ImGuiMenuGame::resetForSpeedrunMode();
dusk::m_speedrunInfo.startRun();
}
}
#endif
}
}
+6 -2
View File
@@ -16,6 +16,8 @@
#include <cstdio>
#include <cstring>
#include "dusk/version.hpp"
#if PLATFORM_WII || PLATFORM_SHIELD
#include <revolution/sc.h>
#include <revolution/wpad.h>
@@ -1035,7 +1037,7 @@ void dSv_player_config_c::init() {
mAttentionType = 0;
mVibration = 1;
#if DEBUG
#if DEBUG // DUSK VERSION SUPPORT: This field isn't used, so we can ignore it.
mLanguage = SCGetLanguage();
#elif REGION_PAL || VERSION >= VERSION_WII_USA_R2
mLanguage = OSGetLanguage();
@@ -1080,7 +1082,8 @@ void dSv_player_config_c::setVibration(u8 i_status) {
}
u8 dSv_player_config_c::getPalLanguage() const {
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC || VERSION == VERSION_GCN_PAL
IF_DUSK_BLOCK(dusk::version::getGameVersion() == dusk::version::GameVersion::GcnPal)
switch (OSGetLanguage()) {
case 0:
return LANGUAGE_ENGLISH;
@@ -1093,6 +1096,7 @@ u8 dSv_player_config_c::getPalLanguage() const {
case 4:
return LANGUAGE_ITALIAN;
}
IF_DUSK_BLOCK_END
#elif VERSION >= VERSION_WII_USA_R0
switch (SCGetLanguage()) {
case 1:
+586
View File
@@ -0,0 +1,586 @@
#include "dusk/achievements.h"
#include "dusk/io.hpp"
#include "dusk/main.h"
#include "d/d_com_inf_game.h"
#include "d/d_meter2_info.h"
#include "d/actor/d_a_alink.h"
#include "d/actor/d_a_npc4.h"
#include "d/actor/d_a_player.h"
#include "d/d_demo.h"
#include "f_pc/f_pc_name.h"
#include "f_op/f_op_actor_mng.h"
#include <filesystem>
#include <algorithm>
namespace dusk {
using json = nlohmann::json;
static void checkGoatHerding(Achievement& a, int32_t threshMs) {
if (dMeter2Info_getMaxCount() != 20 || dMeter2Info_getNowCount() != 20) {
return;
}
const int32_t elapsed = dMeter2Info_getTimeMs();
if (elapsed > 0 && elapsed <= threshMs) {
a.progress = 1;
}
}
static constexpr auto ACHIEVEMENTS_FILENAME = "achievements.json";
std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
return {
{
{
"hero_of_twilight",
"Hero of Twilight",
"Deliver the finishing blow to Ganondorf.",
AchievementCategory::Story,
false, 0, 0, false
},
[](Achievement& a, json&) {
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
if (link != nullptr && link->mProcID == daAlink_c::PROC_GANON_FINISH) {
a.progress = 1;
}
},
{}
},
{
{
"plumm_max",
"Thank You Berry Much",
"Score 61,454 points in the Plumm minigame.",
AchievementCategory::Minigame,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (dComIfGs_getBalloonScore() >= 61454) {
a.progress = 1;
}
},
{}
},
{
{
"rollgoal_8",
"Rollgoal Novice",
"Complete the first 8 rollgoal stages.",
AchievementCategory::Minigame,
true, 8, 0, false
},
[](Achievement& a, json&) {
a.progress = std::min((int)dComIfGs_getEventReg(0xf63f), 8);
},
{}
},
{
{
"rollgoal_all",
"Lost Your Marbles",
"Complete all rollgoal stages.",
AchievementCategory::Minigame,
true, 64, 0, false
},
[](Achievement& a, json&) {
if (dComIfGs_isEventBit(dSv_event_flag_c::KORO2_ALLCLEAR)) {
a.progress = 64;
} else {
a.progress = dComIfGs_getEventReg(0xf63f);
}
},
{}
},
{
{
"goat_30s",
"Ranch Hand",
"Herd all 20 goats into the pen in under 30 seconds.",
AchievementCategory::Minigame,
false, 0, 0, false
},
[](Achievement& a, json&) {
checkGoatHerding(a, 30000);
},
{}
},
{
{
"goat_20s",
"Bane of Howard",
"Herd all 20 goats into the pen in under 20 seconds.",
AchievementCategory::Minigame,
false, 0, 0, false
},
[](Achievement& a, json&) {
checkGoatHerding(a, 20000);
},
{}
},
{
{
"goat_18s",
"King of the Ranch",
"Herd all 20 goats into the pen in under 18 seconds.",
AchievementCategory::Minigame,
false, 0, 0, false
},
[](Achievement& a, json&) {
checkGoatHerding(a, 18000);
},
{}
},
{
{
"cave_of_ordeals",
"Conqueror of Ordeals",
"Clear all 50 floors of the Cave of Ordeals.",
AchievementCategory::Challenge,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (daNpcF_chkEvtBit(0x1F9)) {
a.progress = 1;
}
},
{}
},
{
{
"cave_of_ordeals_heartless",
"Indomitable",
"Clear all 50 floors of the Cave of Ordeals with only 3 heart containers.",
AchievementCategory::Challenge,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (daNpcF_chkEvtBit(0x1F9) && dComIfGs_getMaxLife() <= 15) {
a.progress = 1;
}
},
{}
},
{
{
"speedrun_12h",
"Been There Done That",
"Defeat Ganondorf with a total save file play time under 12 hours.",
AchievementCategory::Challenge,
false, 0, 0, false
},
[](Achievement& a, json&) {
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) {
return;
}
const int64_t ticks = (static_cast<int64_t>(OSGetTime()) - dComIfGs_getSaveStartTime()) + dComIfGs_getSaveTotalTime();
if (ticks / OS_TIMER_CLOCK < 12 * 3600) {
a.progress = 1;
}
},
{}
},
{
{
"speedrun_8h",
"Swift Blade",
"Defeat Ganondorf with a total save file play time under 6 hours.",
AchievementCategory::Challenge,
false, 0, 0, false
},
[](Achievement& a, json&) {
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) {
return;
}
const int64_t ticks = (static_cast<int64_t>(OSGetTime()) - dComIfGs_getSaveStartTime()) + dComIfGs_getSaveTotalTime();
if (ticks / OS_TIMER_CLOCK < 8 * 3600) {
a.progress = 1;
}
},
{}
},
{
{
"princess_of_bugs",
"The Princess of Bugs",
"Deliver all 24 golden bugs to Agitha.",
AchievementCategory::Collection,
true, 24, 0, false
},
[](Achievement& a, json&) {
a.progress = dComIfGs_checkGetInsectNum();
},
{}
},
{
{
"all_poes",
"Poe Collector",
"Collect all 60 Poe Souls.",
AchievementCategory::Collection,
true, 60, 0, false
},
[](Achievement& a, json&) {
a.progress = dComIfGs_getPohSpiritNum();
},
{}
},
{
{
"hylian_loach",
"Legendary Catch",
"Catch a Hylian Loach.",
AchievementCategory::Collection,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (dComIfGs_getFishNum(1) > 0) {
a.progress = 1;
}
},
{}
},
{
{
"all_fish",
"Gone Fishin'",
"Catch all 6 species of fish.",
AchievementCategory::Collection,
true, 6, 0, false
},
[](Achievement& a, json&) {
int nUniqueFish = 0;
for (int i = 0; i < 6; ++i) {
if (dComIfGs_getFishNum(i) != 0) {
nUniqueFish++;
}
}
a.progress = nUniqueFish;
},
{}
},
{
{
"a_big_heart",
"A Big Heart",
"Reach maximum health with all 20 heart containers.",
AchievementCategory::Collection,
true, 20, 0, false
},
[](Achievement& a, json&) {
a.progress = dComIfGs_getMaxLife() / 5;
},
{}
},
{
{
"friendly_fire",
"Friendly Fire",
"Get hit by your own cannonball.",
AchievementCategory::Misc,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (AchievementSystem::get().hasSignal("iron_ball_hit_player")) {
a.progress = 1;
}
},
{}
},
{
{
"long_jump_attack",
"Long Jump Attack",
"Travel more than 20 meters in a single jump attack before landing.",
AchievementCategory::Misc,
false, 0, 0, false
},
[](Achievement& a, json&) {
static bool inJump = false;
static float startX = 0.0f, startZ = 0.0f;
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
if (link == nullptr) {
inJump = false;
return;
}
if (!inJump) {
if (link->mProcID == daAlink_c::PROC_CUT_JUMP) {
inJump = true;
startX = link->current.pos.x;
startZ = link->current.pos.z;
}
} else if (link->mProcID == daAlink_c::PROC_CUT_JUMP_LAND) {
inJump = false;
const float dx = link->current.pos.x - startX;
const float dz = link->current.pos.z - startZ;
if (dx * dx + dz * dz >= 2000.0f * 2000.0f) {
a.progress = 1;
}
} else if (link->mProcID != daAlink_c::PROC_CUT_JUMP) {
inJump = false;
}
},
{}
},
{
{
"back_in_time",
"Back in Time",
"Perform the Back in Time glitch to play on the title screen.",
AchievementCategory::Glitched,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (fopAcM_SearchByName(fpcNm_TITLE_e) == nullptr) {
return;
}
const auto* player = static_cast<const daPy_py_c*>(daPy_getPlayerActorClass());
if (player != nullptr && player->mDemo.getDemoMode() == 1) {
a.progress = 1;
}
},
{}
},
{
{
"early_master_sword",
"Early Master Sword",
"Obtain the Master Sword before completing Midna's Desperate Hour.",
AchievementCategory::Glitched,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (dComIfGs_isCollectSword(COLLECT_MASTER_SWORD) && !dComIfGs_isEventBit(0x1E08)) {
a.progress = 1;
}
},
{}
},
{
{
"earliest_master_sword",
"Earliest Master Sword",
"Obtain the Master Sword before meeting Midna.",
AchievementCategory::Glitched,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (dComIfGs_isCollectSword(COLLECT_MASTER_SWORD) && !dComIfGs_isTransformLV(0)) {
a.progress = 1;
}
},
{}
},
{
{
"ultimate_delivery",
"The Ultimate Delivery",
"Have all 16 postman letters at the same time.",
AchievementCategory::Glitched,
true, 16, 0, false
},
[](Achievement& a, json&) {
a.progress = dMeter2Info_getRecieveLetterNum();
},
{}
},
{
{
"speedrun_4h",
"Hero of Time",
"Defeat Ganondorf with a total save file play time under 4 hours.",
AchievementCategory::Glitched,
false, 0, 0, false
},
[](Achievement& a, json&) {
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) {
return;
}
const int64_t ticks = (static_cast<int64_t>(OSGetTime()) - dComIfGs_getSaveStartTime()) + dComIfGs_getSaveTotalTime();
if (ticks / OS_TIMER_CLOCK < 4 * 3600) {
a.progress = 1;
}
},
{}
},
{
{
"email_me",
"Email Me",
"Read a letter during the Dark Beast Ganon fight.",
AchievementCategory::Misc,
false, 0, 0, false
},
[](Achievement& a, json&) {
void* dbgExists = fopAcM_SearchByName(fpcNm_B_MGN_e);
if (dbgExists && AchievementSystem::get().hasSignal("open_letter")) {
a.progress = 1;
}
},
{}
},
{
{
"heavy-hitter",
"Heavy Hitter",
"Wear the Iron Boots during the end credits.",
AchievementCategory::Misc,
false, 0, 0, false
},
[](Achievement& a, json&) {
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) {
return;
}
if (daPy_getPlayerActorClass()->checkEquipHeavyBoots()) {
a.progress = 1;
}
},
{}
}
};
}
AchievementSystem::AchievementSystem() : m_entries(makeEntries()) {}
AchievementSystem& AchievementSystem::get() {
static AchievementSystem instance;
return instance;
}
std::string AchievementSystem::consumePendingUnlock() {
std::string msg = std::move(m_pendingUnlocks.front());
m_pendingUnlocks.pop();
return msg;
}
std::vector<Achievement> AchievementSystem::getAchievements() const {
std::vector<Achievement> result;
result.reserve(m_entries.size());
for (const auto& e : m_entries) {
result.push_back(e.achievement);
}
return result;
}
void AchievementSystem::load() {
m_loaded = true;
const auto filePath = dusk::ConfigPath / ACHIEVEMENTS_FILENAME;
if (!std::filesystem::exists(filePath)) {
return;
}
try {
auto data = io::FileStream::ReadAllBytes(filePath.string().c_str());
auto j = json::parse(data);
if (!j.is_object()) {
return;
}
for (auto& e : m_entries) {
if (!j.contains(e.achievement.key)) {
continue;
}
const auto& entry = j[e.achievement.key];
if (entry.contains("progress")) {
e.achievement.progress = entry["progress"].get<int32_t>();
}
if (entry.contains("unlocked")) {
e.achievement.unlocked = entry["unlocked"].get<bool>();
}
if (entry.contains("extra")) {
e.extra = entry["extra"];
}
}
} catch (const std::exception&) {}
}
void AchievementSystem::save() {
json j = json::object();
for (const auto& e : m_entries) {
json entry = {
{"progress", e.achievement.progress},
{"unlocked", e.achievement.unlocked},
};
if (!e.extra.is_null()) {
entry["extra"] = e.extra;
}
j[e.achievement.key] = std::move(entry);
}
try {
io::FileStream::WriteAllText(
(dusk::ConfigPath / ACHIEVEMENTS_FILENAME).string().c_str(),
j.dump(2)
);
} catch (const std::exception&) {}
}
void AchievementSystem::clearAll() {
m_entries = makeEntries();
save();
}
void AchievementSystem::signal(const char* key) {
m_signals.insert(key);
}
bool AchievementSystem::hasSignal(const char* key) const {
return m_signals.count(key) > 0;
}
void AchievementSystem::clearOne(const char* key) {
for (auto& e : m_entries) {
if (std::string(e.achievement.key) == key) {
e.achievement.progress = 0;
e.achievement.unlocked = false;
e.extra = {};
break;
}
}
save();
}
void AchievementSystem::processEntry(Entry& e) {
if (e.achievement.unlocked) {
return;
}
const int32_t prevProgress = e.achievement.progress;
e.check(e.achievement, e.extra);
const bool progressChanged = e.achievement.progress != prevProgress;
const bool nowUnlocked = e.achievement.isCounter ?
e.achievement.progress >= e.achievement.goal :
e.achievement.progress > 0;
if (nowUnlocked) {
e.achievement.progress = e.achievement.isCounter ? e.achievement.goal : 1;
e.achievement.unlocked = true;
m_pendingUnlocks.push(e.achievement.name);
m_dirty = true;
} else if (progressChanged) {
m_dirty = true;
}
}
void AchievementSystem::tick() {
if (!m_loaded) {
load();
}
if (!dusk::IsGameLaunched) {
return;
}
for (auto& e : m_entries) {
processEntry(e);
}
m_signals.clear();
if (m_dirty) {
save();
m_dirty = false;
}
}
} // namespace dusk
+1 -1
View File
@@ -80,6 +80,6 @@ void waitingForWrite() {
}
void endAutoSave() {
dusk::g_imguiConsole.ShowToast("Saving...", 2.0f);
dusk::g_imguiConsole.AddToast("Saving...", 2.0f);
mAutoSaveProc = 0;
}
+1
View File
@@ -154,6 +154,7 @@ namespace dusk::config {
template class ConfigImpl<f64>;
template class ConfigImpl<std::string>;
template class ConfigImpl<dusk::BloomMode>;
template class ConfigImpl<dusk::GameLanguage>;
}
void dusk::config::Register(ConfigVarBase& configVar) {
-1
View File
@@ -167,7 +167,6 @@ void InitializeCrashReporting() {
sentry_set_tag("git_branch", DUSK_WC_BRANCH);
sentry_set_tag("build_type", DUSK_BUILD_TYPE);
sentry_set_tag("tp_version", DUSK_TP_VERSION);
g_sentryInitialized = true;
DuskLog.info("Initialized Sentry crash reporting");
+21 -7
View File
@@ -80,8 +80,19 @@ static s32 DolVaToFileOffset(u32 va) {
return -1;
}
bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size) {
s32 fileOffset = DolVaToFileOffset(virtualAddress);
static u32 GetOffsetForVersion(std::initializer_list<OffsetVersion> version) {
const auto gameVersion = dusk::version::getGameVersion();
for (auto elem : version) {
if (elem.mGameVersion == gameVersion) {
return elem.mOffset;
}
}
DuskLog.fatal("Unable to find offset for this game version!");
}
bool LoadDolAsset(void* dst, std::initializer_list<OffsetVersion> virtualAddress, s32 size) {
s32 fileOffset = DolVaToFileOffset(GetOffsetForVersion(virtualAddress));
if (fileOffset < 0) {
return false;
}
@@ -95,13 +106,16 @@ bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size) {
return true;
}
bool LoadRelAsset(void* dst, const char* dvdPath, s32 offset, s32 size) {
void* p = JKRDvdRipper::loadToMainRAM(dvdPath, (u8*)dst, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, (u32)offset, nullptr, nullptr);
if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, offset, size);
bool LoadRelAsset(void* dst, const char* dvdPath, std::initializer_list<OffsetVersion> offset, s32 size) {
auto resOffset = GetOffsetForVersion(offset);
void* p = JKRDvdRipper::loadToMainRAM(dvdPath, (u8*)dst, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, resOffset, nullptr, nullptr);
if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, resOffset, size);
return p != nullptr;
}
bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size) {
bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::initializer_list<OffsetVersion> offset, s32 size) {
auto resOffset = GetOffsetForVersion(offset);
// On TARGET_PC, cDyl_InitCallback skips DynamicModuleControl::initialize() due to static linking
// Mount RELS.arc on first use so sArchive is available
static bool s_mountAttempted = false;
@@ -118,7 +132,7 @@ bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 o
DuskLog.fatal("dvd_asset: {} not found in RELS archive", relFileName); return false;
}
std::memcpy(dst, rel + offset, size);
std::memcpy(dst, rel + resOffset, size);
return true;
}
+26 -12
View File
@@ -292,12 +292,20 @@ void interp_view(::view_class* view) {
return;
const f32 step = get_interpolation_step();
const bool is_cam_curr_authoritative = g_is_sim_frame && step <= 0.0f;
cXyz eye;
cXyz center;
cXyz up;
lerp_xyz(&eye, s_cam_prev.eye, s_cam_curr.eye, step);
lerp_xyz(&center, s_cam_prev.center, s_cam_curr.center, step);
lerp_xyz(&up, s_cam_prev.up, s_cam_curr.up, step);
if (is_cam_curr_authoritative) {
eye = s_cam_curr.eye;
center = s_cam_curr.center;
up = s_cam_curr.up;
} else {
lerp_xyz(&eye, s_cam_prev.eye, s_cam_curr.eye, step);
lerp_xyz(&center, s_cam_prev.center, s_cam_curr.center, step);
lerp_xyz(&up, s_cam_prev.up, s_cam_curr.up, step);
}
if (!up.normalizeRS()) {
up = s_cam_curr.up;
up.normalizeRS();
@@ -306,19 +314,25 @@ void interp_view(::view_class* view) {
view->lookat.eye = eye;
view->lookat.center = center;
view->lookat.up = up;
view->bank = lerp_bank(s_cam_prev.bank, s_cam_curr.bank, step);
view->fovy = s_cam_prev.fovy + (s_cam_curr.fovy - s_cam_prev.fovy) * step;
view->aspect = s_cam_prev.aspect + (s_cam_curr.aspect - s_cam_prev.aspect) * step;
view->near_ = s_cam_prev.near_ + (s_cam_curr.near_ - s_cam_prev.near_) * step;
view->far_ = s_cam_prev.far_ + (s_cam_curr.far_ - s_cam_prev.far_) * step;
if (is_cam_curr_authoritative) {
view->bank = s_cam_curr.bank;
view->fovy = s_cam_curr.fovy;
view->aspect = s_cam_curr.aspect;
view->near_ = s_cam_curr.near_;
view->far_ = s_cam_curr.far_;
} else {
view->bank = lerp_bank(s_cam_prev.bank, s_cam_curr.bank, step);
view->fovy = s_cam_prev.fovy + (s_cam_curr.fovy - s_cam_prev.fovy) * step;
view->aspect = s_cam_prev.aspect + (s_cam_curr.aspect - s_cam_prev.aspect) * step;
view->near_ = s_cam_prev.near_ + (s_cam_curr.near_ - s_cam_prev.near_) * step;
view->far_ = s_cam_prev.far_ + (s_cam_curr.far_ - s_cam_prev.far_) * step;
}
// FRAME INTERP TODO: It might be better if I rewired the game to not clear this flag until the
// next sim frame, but I don't care enough to right now
#if WIDESCREEN_SUPPORT
if (mDoGph_gInf_c::isWide() && !mDoGph_gInf_c::isWideZoom() && step >= 0.5f ?
s_cam_curr.wideZoom :
s_cam_prev.wideZoom)
{
const f32 wide_step = is_cam_curr_authoritative ? 1.0f : step;
if (mDoGph_gInf_c::isWide() && !mDoGph_gInf_c::isWideZoom() && wide_step >= 0.5f ? s_cam_curr.wideZoom : s_cam_prev.wideZoom) {
mDoGph_gInf_c::onWideZoom();
}
#endif
+245
View File
@@ -0,0 +1,245 @@
#include "ImGuiAchievements.hpp"
#include "ImGuiConfig.hpp"
#include "dusk/achievements.h"
#include "dusk/settings.h"
#include "fmt/format.h"
#include "imgui.h"
namespace dusk {
void ImGuiAchievements::notify(std::string name) {
if (m_notifyTimer <= 0.f) {
m_notifyName = std::move(name);
m_notifyTimer = NOTIFY_DURATION;
} else {
m_notifyQueue.push(std::move(name));
}
}
void ImGuiAchievements::showNotification() {
if (!getSettings().game.enableAchievementNotifications.getValue()) {
return;
}
if (m_notifyTimer <= 0.f) {
if (m_notifyQueue.empty()) {
return;
}
m_notifyName = std::move(m_notifyQueue.front());
m_notifyQueue.pop();
m_notifyTimer = NOTIFY_DURATION;
}
m_notifyTimer -= ImGui::GetIO().DeltaTime;
const float alpha = std::min({
m_notifyTimer / NOTIFY_FADE_TIME,
(NOTIFY_DURATION - m_notifyTimer) / NOTIFY_FADE_TIME,
1.0f
});
const ImGuiViewport* viewport = ImGui::GetMainViewport();
const float padding = 12.0f;
ImGui::SetNextWindowPos(
ImVec2(viewport->WorkPos.x + viewport->WorkSize.x - padding, viewport->WorkPos.y + padding),
ImGuiCond_Always, ImVec2(1.0f, 0.0f)
);
ImGui::SetNextWindowBgAlpha(alpha * 0.92f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.08f, 0.06f, 0.01f, alpha * 0.92f));
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(1.0f, 0.8f, 0.1f, alpha));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, alpha));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 2.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(14.0f, 10.0f));
constexpr ImGuiWindowFlags flags =
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize |
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing |
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs;
if (ImGui::Begin("##achievement_notify", nullptr, flags)) {
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.82f, 0.1f, alpha));
ImGui::TextUnformatted("Achievement Unlocked!");
ImGui::PopStyleColor();
ImGui::Spacing();
ImGui::TextUnformatted(m_notifyName.c_str());
}
ImGui::End();
ImGui::PopStyleVar(2);
ImGui::PopStyleColor(3);
}
void ImGuiAchievements::draw(bool& open) {
showNotification();
if (!open) {
return;
}
ImGui::SetNextWindowSizeConstraints(ImVec2(800, 200), ImVec2(1280, 900));
ImGui::SetNextWindowSize(ImVec2(800, 480), ImGuiCond_FirstUseEver);
if (!ImGui::Begin(
"Achievements", &open,
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav)
)
{
ImGui::End();
return;
}
const auto achievements = AchievementSystem::get().getAchievements();
int unlocked = 0;
for (const auto& a : achievements) {
if (a.unlocked) {
++unlocked;
}
}
ImGui::Text("%d / %d achievements unlocked", unlocked, (int)achievements.size());
ImGui::SameLine();
config::ImGuiCheckbox("Notifications", getSettings().game.enableAchievementNotifications);
ImGui::Separator();
static const struct {
AchievementCategory cat;
const char* label;
ImVec4 color;
} ACHIEVEMENT_CATEGORIES[] = {
{AchievementCategory::Story, "Story", ImVec4(1.0f, 0.82f, 0.1f, 1.0f)},
{AchievementCategory::Collection, "Collection", ImVec4(0.3f, 0.85f, 0.4f, 1.0f)},
{AchievementCategory::Challenge, "Challenge", ImVec4(1.0f, 0.65f, 0.15f, 1.0f)},
{AchievementCategory::Minigame, "Minigame", ImVec4(0.5f, 0.85f, 1.0f, 1.0f)},
{AchievementCategory::Misc, "Misc", ImVec4(0.65f, 0.65f, 0.65f, 1.0f)},
{AchievementCategory::Glitched, "Glitched", ImVec4(0.75f, 0.4f, 1.0f, 1.0f)},
};
const float footerHeight = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
if (ImGui::BeginTabBar("##achievement_tabs", ImGuiTabBarFlags_FittingPolicyScroll)) {
for (const auto& catInfo : ACHIEVEMENT_CATEGORIES) {
int catTotal = 0, catUnlocked = 0;
for (const auto& a : achievements) {
if (a.category == catInfo.cat) {
++catTotal;
if (a.unlocked) {
++catUnlocked;
}
}
}
if (catTotal == 0) {
continue;
}
const std::string tabLabel = fmt::format("{} ({}/{})###{}", catInfo.label, catUnlocked, catTotal, catInfo.label);
ImGui::PushStyleColor(ImGuiCol_Text, catInfo.color);
const bool tabOpen = ImGui::BeginTabItem(tabLabel.c_str());
ImGui::PopStyleColor();
if (tabOpen) {
ImGui::BeginChild(
"##cat_list",
ImVec2(0, -footerHeight),
ImGuiChildFlags_None,
ImGuiWindowFlags_NoBackground
);
ImGui::Spacing();
for (const auto& a : achievements) {
if (a.category != catInfo.cat) {
continue;
}
ImGui::PushID(a.key);
ImGui::BeginGroup();
ImGui::PushStyleColor(
ImGuiCol_Text,
a.unlocked ?
ImVec4(1.0f, 0.65f, 0.15f, 1.0f) :
ImGui::GetStyleColorVec4(ImGuiCol_Text)
);
ImGui::TextUnformatted(a.name);
ImGui::PopStyleColor();
const char* statusLabel = a.unlocked ? "[Unlocked]" : "[Locked]";
ImGui::SameLine(
ImGui::GetContentRegionMax().x -
ImGui::CalcTextSize(statusLabel).x
);
if (a.unlocked) {
ImGui::TextColored(ImVec4(0.2f, 0.8f, 0.2f, 1.0f), "%s", statusLabel);
} else {
ImGui::TextColored(ImVec4(0.8f, 0.2f, 0.2f, 1.0f), "%s", statusLabel);
}
ImGui::TextDisabled("%s", a.description);
if (a.isCounter) {
const float fraction = a.goal > 0 ? (float)(a.progress) / (float)(a.goal) : 1.0f;
const std::string overlay = fmt::format("{} / {}", a.progress, a.goal);
ImGui::PushStyleColor(
ImGuiCol_PlotHistogram,
a.unlocked ?
ImVec4(0.4f, 0.7f, 0.1f, 1.0f) :
ImVec4(0.2f, 0.45f, 0.8f, 1.0f)
);
ImGui::ProgressBar(fraction, ImVec2(-1.0f, 0.0f), overlay.c_str());
ImGui::PopStyleColor();
}
ImGui::EndGroup();
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("##ctx");
}
if (ImGui::BeginPopup("##ctx")) {
ImGui::TextDisabled("%s", a.name);
ImGui::Separator();
if (ImGui::MenuItem("Clear Achievement")) {
AchievementSystem::get().clearOne(a.key);
}
ImGui::EndPopup();
}
ImGui::Spacing();
ImGui::PopID();
}
ImGui::EndChild();
ImGui::EndTabItem();
}
}
ImGui::EndTabBar();
}
ImGui::Separator();
ImGui::Spacing();
if (ImGui::Button("Clear All Achievements")) {
ImGui::OpenPopup("##confirm_clear");
}
if (ImGui::BeginPopup("##confirm_clear")) {
ImGui::Text("Reset all achievement progress?");
ImGui::Spacing();
if (ImGui::Button("Yes, reset all")) {
AchievementSystem::get().clearAll();
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
ImGui::End();
}
} // namespace dusk
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include <queue>
#include <string>
namespace dusk {
class ImGuiAchievements {
public:
void draw(bool& open);
void notify(std::string name);
private:
void showNotification();
std::string m_notifyName;
float m_notifyTimer = 0.f;
std::queue<std::string> m_notifyQueue;
static constexpr float NOTIFY_DURATION = 4.0f;
static constexpr float NOTIFY_FADE_TIME = 0.5f;
};
} // namespace dusk
+34 -5
View File
@@ -14,10 +14,12 @@
#include "SDL3/SDL_events.h"
#include "SDL3/SDL_mouse.h"
#include "aurora/lib/window.hpp"
#include "dusk/achievements.h"
#include "dusk/audio/DuskAudioSystem.h"
#include "dusk/config.hpp"
#include "dusk/dusk.h"
#include "dusk/frame_interpolation.h"
#include "dusk/livesplit.h"
#include "dusk/main.h"
#include "dusk/settings.h"
#include "m_Do/m_Do_controller_pad.h"
@@ -64,6 +66,10 @@ namespace dusk {
ImGui::TextUnformatted(text.data(), text.data() + text.size());
}
void DuskToast(std::string_view message, float duration) {
g_imguiConsole.AddToast(message, duration);
}
void ImGuiTextCenter(std::string_view text) {
ImGui::NewLine();
float fontSize = ImGui::CalcTextSize(
@@ -295,6 +301,15 @@ namespace dusk {
UpdateSettings();
AchievementSystem::get().tick();
while (AchievementSystem::get().hasPendingUnlock()) {
if (getSettings().game.enableAchievementNotifications) {
m_menuTools.notifyAchievement(AchievementSystem::get().consumePendingUnlock());
} else {
AchievementSystem::get().consumePendingUnlock();
}
}
if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) &&
ImGui::IsKeyPressed(ImGuiKey_R))
{
@@ -350,18 +365,31 @@ namespace dusk {
}
if (dusk::IsGameLaunched && !m_isLaunchInitialized) {
ShowToast(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ?
AddToast(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ?
"Tap to toggle menu" :
"Press F1 to toggle menu",
2.5f);
m_isLaunchInitialized = true;
if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::connectLiveSplit();
}
}
UpdateDragScroll();
m_menuGame.windowControllerConfig();
m_menuGame.windowInputViewer();
if (dusk::IsGameLaunched) {
m_menuGame.drawSpeedrunTimerOverlay();
if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::updateLiveSplit();
if (dusk::speedrun::consumeConnectedEvent())
AddToast("LiveSplit connected");
else if (dusk::speedrun::consumeDisconnectedEvent())
AddToast("LiveSplit disconnected");
}
if (dusk::IsGameLaunched && !dusk::getSettings().game.speedrunMode) {
m_menuTools.ShowDebugOverlay();
m_menuTools.ShowCameraOverlay();
m_menuTools.ShowProcessManager();
@@ -372,8 +400,9 @@ namespace dusk {
m_menuTools.ShowPlayerInfo();
m_menuTools.ShowAudioDebug();
m_menuTools.ShowSaveEditor();
m_menuTools.ShowStateShare();
}
m_menuTools.ShowStateShare();
m_menuTools.ShowAchievements();
DuskDebugPad(); // temporary, remove later
// Hide mouse cursor if the F1 menu is not open and the cursor is idle for 3 seconds.
@@ -545,8 +574,8 @@ namespace dusk {
return false;
}
void ImGuiConsole::ShowToast(std::string text, float time) {
m_toasts.emplace_back(text, time);
void ImGuiConsole::AddToast(std::string_view message, float duration) {
m_toasts.emplace_back(std::string(message), duration);
}
void ImGuiConsole::ShowToasts() {
+2 -2
View File
@@ -26,9 +26,8 @@ public:
void PreDraw();
void PostDraw();
void ShowToast(std::string, float);
static bool CheckMenuViewToggle(ImGuiKey key, bool& active);
void AddToast(std::string_view message, float duration = 3.f);
private:
struct Toast {
@@ -72,6 +71,7 @@ std::string BytesToString(size_t bytes);
void SetOverlayWindowLocation(int corner);
bool ShowCornerContextMenu(int& corner, int avoidCorner);
void ImGuiStringViewText(std::string_view text);
void DuskToast(std::string_view message, float duration = 3.f);
void ImGuiBeginGroupPanel(const char* name, const ImVec2& size);
void ImGuiEndGroupPanel();
void ImGuiTextCenter(std::string_view text);
+3
View File
@@ -29,12 +29,15 @@ static void ApplyPresetHD() {
s.game.fastTears.setValue(true);
s.game.biggerWallets.setValue(true);
s.game.invertCameraXAxis.setValue(true);
s.game.freeCamera.setValue(true);
s.game.no2ndFishForCat.setValue(true);
}
static void ApplyPresetDusk() {
ApplyPresetHD();
auto& s = getSettings();
s.game.enableAchievementNotifications.setValue(true);
s.game.enableQuickTransform.setValue(true);
s.game.instantSaves.setValue(true);
s.game.midnasLamentNonStop.setValue(true);
+162 -5
View File
@@ -12,12 +12,15 @@
#include "dusk/main.h"
#include "dusk/hotkeys.h"
#include "dusk/settings.h"
#include "dusk/livesplit.h"
#include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_graphic.h"
#include <aurora/gfx.h>
#include <SDL3/SDL_gamepad.h>
#include "m_Do/m_Do_main.h"
namespace {
constexpr int kInternalResolutionScaleMax = 12;
} // namespace
@@ -167,6 +170,8 @@ namespace dusk {
config::ImGuiCheckbox("Enable Depth of Field", getSettings().game.enableDepthOfField);
config::ImGuiCheckbox("Enable Mini-Map Shadows", getSettings().game.enableMapBackground);
ImGui::EndMenu();
}
}
@@ -199,6 +204,7 @@ namespace dusk {
ImGui::SeparatorText("Difficulty");
ImGui::BeginDisabled(getSettings().game.speedrunMode);
config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d");
config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath);
@@ -211,6 +217,7 @@ namespace dusk {
ImGui::SetTooltip("Hearts will never drop from enemies,\n"
"pots and various other places.");
}
ImGui::EndDisabled();
ImGui::SeparatorText("Quality of Life");
@@ -271,6 +278,11 @@ namespace dusk {
ImGui::SetTooltip("Link won't recoil when his sword hits walls.");
}
config::ImGuiCheckbox("No 2nd Fish for Cat", getSettings().game.no2ndFishForCat);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Only need to fish once for Sera's cat to return.");
}
config::ImGuiCheckbox("Skip TV Settings Screen", getSettings().game.hideTvSettingsScreen);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Skip the TV calibration screen shown when loading a save.");
@@ -291,12 +303,39 @@ namespace dusk {
ImGui::SetTooltip("Transform instantly by pressing R and Y simultaneously.");
}
ImGui::SeparatorText("Speedrunning");
if (config::ImGuiCheckbox("Speedrun Mode", getSettings().game.speedrunMode)) {
resetForSpeedrunMode();
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Enables Speedrunning options, while restricting certain gameplay modifiers.");
}
ImGui::BeginDisabled(!getSettings().game.speedrunMode);
bool prevLiveSplit = getSettings().game.liveSplitEnabled;
config::ImGuiCheckbox("LiveSplit Connection", getSettings().game.liveSplitEnabled);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Connect to LiveSplit server on localhost:16834.");
}
ImGui::EndDisabled();
if ((bool)getSettings().game.liveSplitEnabled != prevLiveSplit) {
if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::connectLiveSplit();
} else {
dusk::speedrun::disconnectLiveSplit();
DuskToast("LiveSplit disconnected", 3.f);
}
}
ImGui::EndMenu();
}
}
void ImGuiMenuGame::drawCheatsMenu() {
if (ImGui::BeginMenu("Cheats")) {
ImGui::BeginDisabled(getSettings().game.speedrunMode);
ImGui::SeparatorText("Resources");
config::ImGuiCheckbox("Infinite Hearts", getSettings().game.infiniteHearts);
config::ImGuiCheckbox("Infinite Arrows", getSettings().game.infiniteArrows);
@@ -304,8 +343,8 @@ namespace dusk {
config::ImGuiCheckbox("Infinite Oil", getSettings().game.infiniteOil);
config::ImGuiCheckbox("Infinite Oxygen", getSettings().game.infiniteOxygen);
config::ImGuiCheckbox("Infinite Rupees", getSettings().game.infiniteRupees);
config::ImGuiCheckbox("Items Don't Despawn", getSettings().game.enableIndefiniteItemDrops);
ImGui::SetItemTooltip("Items Don't Despawn Unless You Load A Different Room In Which Case They Do But Even Under Some Circumstances They Don't, It Is Quite Rare Though");
config::ImGuiCheckbox("No Item Timer", getSettings().game.enableIndefiniteItemDrops);
ImGui::SetItemTooltip("Item drops such as Rupees, Hearts, etc. will never disappear after they drop.");
ImGui::SeparatorText("Abilities");
config::ImGuiCheckbox("Moon Jump (R+A)", getSettings().game.moonJump);
@@ -328,6 +367,8 @@ namespace dusk {
ImGui::SetTooltip("Makes the magic armor work without rupees.");
}
ImGui::EndDisabled();
ImGui::EndMenu();
}
}
@@ -394,7 +435,15 @@ namespace dusk {
ImGui::SeparatorText("Camera");
config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis);
config::ImGuiCheckbox("Free Camera", getSettings().game.freeCamera);
if (getSettings().game.freeCamera) {
config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis);
config::ImGuiCheckbox("Invert Camera Y Axis", getSettings().game.invertCameraYAxis);
config::ImGuiSliderFloat("Free Camera Sensitivity", getSettings().game.freeCameraSensitivity, 0.5f, 2.0f, "%.1f");
} else {
config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis);
}
ImGui::SeparatorText("Gyro");
@@ -442,10 +491,12 @@ namespace dusk {
ImGui::SeparatorText("Tools");
ImGui::BeginDisabled(getSettings().game.speedrunMode);
config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x.");
}
ImGui::EndDisabled();
ImGui::Checkbox("Show Input Viewer", &m_showInputViewer);
@@ -455,6 +506,7 @@ namespace dusk {
void ImGuiMenuGame::drawInterfaceMenu() {
if (ImGui::BeginMenu("Interface")) {
config::ImGuiCheckbox("Achievement Notifications", getSettings().game.enableAchievementNotifications);
config::ImGuiCheckbox("Skip Pre-Launch UI", getSettings().backend.skipPreLaunchUI);
config::ImGuiCheckbox("Show Pipeline Compilation", getSettings().backend.showPipelineCompilation);
#if DUSK_ENABLE_SENTRY_NATIVE
@@ -967,7 +1019,7 @@ namespace dusk {
ImGui::SameLine();
// Options panel
ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, 20 * scale));
ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, -1));
if (deadZones != nullptr) {
if (ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones)) {
@@ -977,9 +1029,114 @@ namespace dusk {
PADSerializeMappings();
}
}
if (PADSupportsRumbleIntensity(m_controllerConfig.m_selectedPort)) {
ImGuiBeginGroupPanel("Rumble Intensity", ImVec2(150 * scale, -1));
u16 low;
u16 high;
(void)PADGetRumbleIntensity(m_controllerConfig.m_selectedPort, &low, &high);
float fLow = (static_cast<float>(low) / 32767.f) * 100.f;
bool changed = ImGui::SliderFloat("Low", &fLow, 0.f, 100.f, "%.0f%%");
float fHigh = (static_cast<float>(high) / 32767.f) * 100.f;
changed |= ImGui::SliderFloat("High", &fHigh, 0.f, 100.f, "%.0f%%");
if (changed) {
PADSetRumbleIntensity(m_controllerConfig.m_selectedPort,
static_cast<u16>((fLow / 100) * 32767),
static_cast<u16>((fHigh / 100) * 32767));
PADSerializeMappings();
}
if (ImGui::Button(fmt::format("{0}...##rumbleTest", m_controllerConfig.m_isRumbling ? "Stop": "Test").c_str(), {-1, 0})) {
PADControlMotor(m_controllerConfig.m_selectedPort, !m_controllerConfig.m_isRumbling ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP_HARD);
m_controllerConfig.m_isRumbling ^= 1;
}
ImGuiEndGroupPanel();
}
ImGuiEndGroupPanel();
ImGui::End();
}
static std::string GetFormattedTime(OSTime ticks) {
OSCalendarTime time;
OSTicksToCalendarTime(ticks, &time);
return fmt::format("{0:02}:{1:02}:{2:02}.{3:03}", time.hour, time.min, time.sec, time.msec);
}
void ImGuiMenuGame::resetForSpeedrunMode() {
// reset settings that should be off for speedrun mode
mDoMain::developmentMode = -1;
getSettings().game.damageMultiplier.setValue(1);
getSettings().game.instantDeath.setValue(false);
getSettings().game.noHeartDrops.setValue(false);
getSettings().game.infiniteHearts.setValue(false);
getSettings().game.infiniteArrows.setValue(false);
getSettings().game.infiniteBombs.setValue(false);
getSettings().game.infiniteOil.setValue(false);
getSettings().game.infiniteOxygen.setValue(false);
getSettings().game.infiniteRupees.setValue(false);
getSettings().game.enableIndefiniteItemDrops.setValue(false);
getSettings().game.moonJump.setValue(false);
getSettings().game.superClawshot.setValue(false);
getSettings().game.alwaysGreatspin.setValue(false);
getSettings().game.enableFastIronBoots.setValue(false);
getSettings().game.canTransformAnywhere.setValue(false);
getSettings().game.fastSpinner.setValue(false);
getSettings().game.freeMagicArmor.setValue(false);
getSettings().game.enableTurboKeybind.setValue(false);
}
SpeedrunInfo m_speedrunInfo;
void ImGuiMenuGame::drawSpeedrunTimerOverlay() {
if (!getSettings().game.speedrunMode) {
return;
}
// L+R+A+Start to reset timer
if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigStart(PAD_1)) {
m_speedrunInfo.reset();
}
// L+R+A+Z to manually stop timer
if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigZ(PAD_1)) {
if (m_speedrunInfo.m_isRunStarted) {
m_speedrunInfo.m_endTimestamp = OSGetTime() - m_speedrunInfo.m_startTimestamp;
m_speedrunInfo.m_isRunStarted = false;
}
}
ImGui::SetNextWindowBgAlpha(0.65f);
ImGuiWindowFlags flags =
ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_NoDocking
| ImGuiWindowFlags_NoTitleBar
| ImGuiWindowFlags_NoScrollbar;
if (ImGui::Begin("##SpeedrunTimerWindow", nullptr, flags)) {
OSTime elapsedTime = 0;
if (m_speedrunInfo.m_isRunStarted) {
elapsedTime = OSGetTime() - m_speedrunInfo.m_startTimestamp;
} else if (m_speedrunInfo.m_endTimestamp != 0) {
elapsedTime = m_speedrunInfo.m_endTimestamp;
}
ImGui::Text("RTA");
ImGui::SameLine(60.0f);
ImGuiStringViewText(GetFormattedTime(elapsedTime));
if (!m_speedrunInfo.m_isPauseIGT) {
m_speedrunInfo.m_igtTimer = elapsedTime - m_speedrunInfo.m_totalLoadTime;
}
ImGui::Text("IGT");
ImGui::SameLine(60.0f);
ImGuiStringViewText(GetFormattedTime(m_speedrunInfo.m_igtTimer));
}
ImGui::End();
}
}
+39
View File
@@ -8,6 +8,39 @@
#include "imgui.h"
namespace dusk {
struct SpeedrunInfo {
void startRun() {
m_isRunStarted = true;
m_startTimestamp = OSGetTime();
}
void stopRun() {
m_isRunStarted = false;
m_endTimestamp = OSGetTime() - m_startTimestamp;
}
void reset() {
m_isRunStarted = false;
m_startTimestamp = 0;
m_endTimestamp = 0;
m_isPauseIGT = false;
m_loadStartTimestamp = 0;
m_totalLoadTime = 0;
m_igtTimer = 0;
}
bool m_isRunStarted = false;
OSTime m_startTimestamp = 0;
OSTime m_endTimestamp = 0;
bool m_isPauseIGT = false;
OSTime m_loadStartTimestamp = 0;
OSTime m_totalLoadTime = 0;
OSTime m_igtTimer = 0;
};
extern SpeedrunInfo m_speedrunInfo;
class ImGuiMenuGame {
public:
ImGuiMenuGame();
@@ -15,9 +48,12 @@ namespace dusk {
void windowInputViewer();
void windowControllerConfig();
void drawSpeedrunTimerOverlay();
static void ToggleFullscreen();
static void resetForSpeedrunMode();
private:
void drawAudioMenu();
void drawInputMenu();
@@ -32,6 +68,7 @@ namespace dusk {
PADButtonMapping* m_pendingButtonMapping = nullptr;
PADAxisMapping* m_pendingAxisMapping = nullptr;
int m_pendingPort = -1;
bool m_isRumbling = false;
} m_controllerConfig;
bool m_showControllerConfig = false;
@@ -40,6 +77,8 @@ namespace dusk {
bool m_showInputViewerGyro = false;
int m_inputOverlayCorner = 3;
std::string m_controllerName;
bool m_showTimerWindow = false;
};
}
+19
View File
@@ -50,14 +50,20 @@ namespace dusk {
ImGui::BeginDisabled();
}
ImGui::BeginDisabled(getSettings().game.speedrunMode);
ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor);
ImGui::MenuItem("Map Loader", hotkeys::SHOW_MAP_LOADER, &m_showMapLoader);
ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare);
ImGui::EndDisabled();
if (!dusk::IsGameLaunched) {
ImGui::EndDisabled();
}
ImGui::MenuItem("Achievements", nullptr, &m_showAchievements);
#if DUSK_CAN_OPEN_DATA_FOLDER
ImGui::Separator();
if (ImGui::MenuItem("Open Data Folder")) {
@@ -69,6 +75,8 @@ namespace dusk {
}
if (ImGui::BeginMenu("Debug")) {
ImGui::BeginDisabled(getSettings().game.speedrunMode);
bool developmentMode = mDoMain::developmentMode == 1;
if (ImGui::Checkbox("Development Mode", &developmentMode)) {
mDoMain::developmentMode = developmentMode ? 1 : -1;
@@ -117,6 +125,9 @@ namespace dusk {
}
ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable);
ImGui::EndDisabled();
ImGui::EndMenu();
}
}
@@ -252,4 +263,12 @@ namespace dusk {
ImGui::End();
ImGui::PopFont();
}
void ImGuiMenuTools::ShowAchievements() {
m_achievementsWindow.draw(m_showAchievements);
}
void ImGuiMenuTools::notifyAchievement(std::string name) {
m_achievementsWindow.notify(std::move(name));
}
}
+6
View File
@@ -5,6 +5,7 @@
#include <string>
#include "imgui.h"
#include "ImGuiAchievements.hpp"
#include "ImGuiSaveEditor.hpp"
#include "ImGuiStateShare.hpp"
@@ -26,6 +27,8 @@ namespace dusk {
void ShowAudioDebug();
void ShowSaveEditor();
void ShowStateShare();
void ShowAchievements();
void notifyAchievement(std::string name);
private:
bool m_showDebugOverlay = false;
@@ -65,6 +68,9 @@ namespace dusk {
bool m_showStateShare = false;
ImGuiStateShare m_stateShare;
bool m_showAchievements = false;
ImGuiAchievements m_achievementsWindow;
};
}
+21 -1
View File
@@ -22,6 +22,10 @@ typedef void (ImGuiPreLaunchWindow::*drawFunc)();
drawFunc drawTable[2] = {&ImGuiPreLaunchWindow::drawMainMenu, &ImGuiPreLaunchWindow::drawOptions};
static constexpr std::array<const char*, 5> skLanguageNames = {
"English", "German", "French", "Spanish", "Italian"
};
static constexpr std::array<SDL_DialogFileFilter, 2> skGameDiscFileFilters{{
{"Game Disc Images", "iso;gcm;ciso;gcz;nfs;rvz;wbfs;wia;tgc"},
{"All Files", "*"},
@@ -71,6 +75,7 @@ void fileDialogCallback(void* userdata, const char* path, const char* error) {
}
self->m_selectedIsoPath = path;
self->m_isPal = iso::isPal(path);
getSettings().backend.isoPath.setValue(self->m_selectedIsoPath);
config::Save();
}
@@ -88,6 +93,7 @@ bool ImGuiPreLaunchWindow::isSelectedPathValid() const {
void ImGuiPreLaunchWindow::draw() {
if (m_IsFirstDraw) {
m_selectedIsoPath = getSettings().backend.isoPath;
m_isPal = !m_selectedIsoPath.empty() && iso::isPal(m_selectedIsoPath.c_str());
m_initialGraphicsBackend = getSettings().backend.graphicsBackend;
m_IsFirstDraw = false;
}
@@ -189,12 +195,26 @@ void ImGuiPreLaunchWindow::drawOptions() {
ImGui::InputText("Game ISO Path", &m_selectedIsoPath, ImGuiInputTextFlags_ReadOnly);
ImGui::SameLine();
if (ImGui::Button("Set")) {
if (ImGui::Button(m_selectedIsoPath == "" ? "Set" : "Change")) {
ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(),
skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr,
false);
}
if (m_isPal) {
auto selectedLanguage = getSettings().game.language.getValue();
if (ImGui::BeginCombo("Language", skLanguageNames[static_cast<u8>(selectedLanguage)])) {
for (u8 i = 0; i < skLanguageNames.size(); ++i) {
if (ImGui::Selectable(skLanguageNames[i])) {
getSettings().game.language.setValue(static_cast<GameLanguage>(i));
config::Save();
}
}
ImGui::EndCombo();
}
}
AuroraBackend configuredBackend = BACKEND_AUTO;
const std::string& configuredBackendId = getSettings().backend.graphicsBackend;
if (!try_parse_backend(configuredBackendId, configuredBackend)) {
+1
View File
@@ -18,5 +18,6 @@ public:
std::string m_selectedIsoPath;
std::string m_errorString;
bool m_isPal = false;
};
} // namespace dusk
+76 -20
View File
@@ -1347,6 +1347,51 @@ namespace dusk {
}
}
template <typename T>
concept FlagIter = requires(T t) {
++t;
--t;
t + 1;
t < t;
{ t->flagID } -> std::convertible_to<u16>;
};
template <typename T>
concept FlagTester = requires(T t, u16 flagID) {
{ t(flagID) } -> std::convertible_to<bool>;
};
static void sortByFlags(FlagIter auto begin, FlagIter auto end, FlagTester auto&& flagTester) {
if (begin == end) return;
FlagIter auto fullEnd = end;
// We want to find the location of where we can swap our `On` flags to.
// We're gonna put the `Off` bits first, and the `On` bits last. 0 < 1
// We can achieve this by skipping all the `On` bits at the end.
// backtrack until we find a bit that is off
while (begin < --end && flagTester(end->flagID)) {
// move the end pointer back while we find on bits
}
// end should now be pointing to a bit that is off
while (begin < end) {
// if there's a flag that's on
if (flagTester(begin->flagID)) {
// move it to the end
std::rotate(begin, begin + 1, fullEnd);
// move back the end of where we're checking
--end;
// begin will now point to the next piece of data
// because we've rotated the data >= begin to the left
} else {
// not on, check next flag
++begin;
}
}
}
void ImGuiSaveEditor::drawFlagsTab() {
if (ImGui::TreeNode("Current Region Flags")) {
dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit;
@@ -1446,30 +1491,41 @@ namespace dusk {
sort != nullptr && sort->SpecsCount > 0 &&
(sort->SpecsDirty || sort->Specs[0].ColumnIndex == COLUMN_FLAG))
{
auto column = sort->Specs->ColumnIndex;
const auto cmp = [&](const duskImguiEventFlagEntry& l,
const duskImguiEventFlagEntry& r) -> bool {
switch (column) {
case COLUMN_FLAG:
return (bool)event.isEventBit(l.flagID) <
(bool)event.isEventBit(r.flagID);
case COLUMN_NAME:
return l.flagName < r.flagName;
case COLUMN_LOC:
return l.location < r.location;
case COLUMN_DESC:
return l.description < r.description;
}
return false;
};
const auto column = sort->Specs[0].ColumnIndex;
const auto direction = sort->Specs[0].SortDirection;
if (direction == ImGuiSortDirection_Ascending) {
std::sort(std::begin(duskImguiEventFlags), std::end(duskImguiEventFlags), cmp);
// if we're sorting by flags, do special sort, regular sort is bad for sorting bools
// it can swap values that are the same, and that causes constant reordering
if (column == COLUMN_FLAG) {
const auto testEventFunc = [&event](u16 flag) -> bool { return event.isEventBit(flag); };
if (direction == ImGuiSortDirection_Ascending) {
sortByFlags(std::begin(duskImguiEventFlags),
std::end(duskImguiEventFlags), testEventFunc);
} else {
sortByFlags(std::rbegin(duskImguiEventFlags),
std::rend(duskImguiEventFlags), testEventFunc);
}
} else {
std::sort(std::rbegin(duskImguiEventFlags), std::rend(duskImguiEventFlags), cmp);
const auto cmp = [column](const duskImguiEventFlagEntry& l,
const duskImguiEventFlagEntry& r) -> bool {
switch (column) {
case COLUMN_NAME: return l.flagName < r.flagName;
case COLUMN_LOC: return l.location < r.location;
case COLUMN_DESC: return l.description < r.description;
default: return false;
}
};
if (direction == ImGuiSortDirection_Ascending) {
std::sort(std::begin(duskImguiEventFlags),
std::end(duskImguiEventFlags), cmp);
} else {
std::sort(std::rbegin(duskImguiEventFlags),
std::rend(duskImguiEventFlags), cmp);
}
}
sort->SpecsDirty = false;
}
+32
View File
@@ -17,8 +17,14 @@ constexpr const char* TP_GAME_IDS[] = {
"RZDK01", // Wii KOR
};
constexpr const char* PAL_GAME_IDS[] = {
"GZ2P01", // GCN PAL
"RZDP01", // Wii PAL
};
constexpr const char* SUPPORTED_TP_GAME_IDS[] = {
"GZ2E01", // GCN USA
"GZ2P01", // GCN PAL
};
template <size_t N>
@@ -123,4 +129,30 @@ ValidationError validate(const char* path) {
return ValidationError::Success;
}
bool isPal(const char* path) {
NodHandleWrapper disc;
const auto sdlStream = SDL_IOFromFile(path, "rb");
if (sdlStream == nullptr) {
return false;
}
const NodDiscStream nod_stream{
.user_data = sdlStream,
.read_at = StreamReadAt,
.stream_len = StreamLength,
.close = StreamClose,
};
if (nod_disc_open_stream(&nod_stream, nullptr, &disc.handle) != NOD_RESULT_OK || disc.handle == nullptr) {
return false;
}
NodDiscHeader header{};
if (nod_disc_header(disc.handle, &header) != NOD_RESULT_OK) {
return false;
}
return matches(header.game_id, PAL_GAME_IDS);
}
} // namespace dusk::iso
+1
View File
@@ -13,6 +13,7 @@ namespace dusk::iso {
};
ValidationError validate(const char* path);
bool isPal(const char* path);
}
#endif // DUSK_ISO_VALIDATE_HPP
+183
View File
@@ -0,0 +1,183 @@
#if _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
using socket_t = SOCKET;
static void closeSocket(socket_t s) { closesocket(s); }
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
using socket_t = int;
static void closeSocket(socket_t s) { close(s); }
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#endif
#include <cstdio>
#include "dusk/livesplit.h"
#include "f_op/f_op_overlap_mng.h"
namespace dusk::speedrun {
static bool running = false;
static uint64_t frameCount = 0;
static socket_t sock = INVALID_SOCKET;
static bool wasLoading = false;
static bool connected = false;
static bool connectPending = false;
static bool disconnectPending = false;
static void sendCmd(const char* cmd) {
if (sock == INVALID_SOCKET) {
return;
}
char msg[64];
int len = snprintf(msg, sizeof(msg), "%s\r\n", cmd);
if (send(sock, msg, len, 0) >= 0) {
if (!connected) {
connected = connectPending = true;
}
return;
}
#if _WIN32
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK || err == WSAENOTCONN) {
return;
}
#else
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN) {
return;
}
#endif
if (connected) disconnectPending = true;
closeSocket(sock);
sock = INVALID_SOCKET;
connected = connectPending = false;
}
uint64_t getFrameCount() {
return frameCount;
}
void onGameFrame() {
if (!running) {
return;
}
bool loading = fopOvlpM_IsDoingReq() != 0;
if (loading != wasLoading) {
sendCmd(loading ? "pausegametime" : "unpausegametime");
wasLoading = loading;
}
if (!loading) {
++frameCount;
}
}
void start() {
if (running) {
return;
}
running = true;
frameCount = 0;
wasLoading = false;
sendCmd("initgametime");
sendCmd("reset");
sendCmd("starttimer");
}
void reset() {
running = false;
frameCount = 0;
wasLoading = false;
sendCmd("reset");
}
void connectLiveSplit(const char* host, int port) {
#if _WIN32
WSADATA wd{}; WSAStartup(MAKEWORD(2, 2), &wd);
#endif
if (sock != INVALID_SOCKET) {
closeSocket(sock); sock = INVALID_SOCKET;
}
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
return;
}
#if _WIN32
u_long nb = 1;
ioctlsocket(sock, FIONBIO, &nb);
#else
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
#endif
sockaddr_in addr{}; addr.sin_family = AF_INET;
addr.sin_port = htons((uint16_t)port);
inet_pton(AF_INET, host, &addr.sin_addr);
connect(sock, (sockaddr*)&addr, sizeof(addr));
sendCmd("initgametime");
}
void disconnectLiveSplit() {
if (sock != INVALID_SOCKET) {
closeSocket(sock);
sock = INVALID_SOCKET;
connected = false;
}
}
bool consumeConnectedEvent() { bool v = connectPending; connectPending = false; return v; }
bool consumeDisconnectedEvent() { bool v = disconnectPending; disconnectPending = false; return v; }
void updateLiveSplit() {
if (sock == INVALID_SOCKET) {
return;
}
if (!connected) {
sendCmd("initgametime");
return;
}
if (!running) {
return;
}
const uint64_t totalMs = frameCount * 1000 / 30;
const uint64_t totalSec = totalMs / 1000;
char cmd[32];
snprintf(cmd, sizeof(cmd), "setgametime %u:%02u:%02u.%03u",
(uint32_t)(totalSec / 3600),
(uint32_t)((totalSec / 60) % 60),
(uint32_t)(totalSec % 60),
(uint32_t)(totalMs % 1000)
);
sendCmd(cmd);
}
void shutdown() {
disconnectLiveSplit();
#if _WIN32
WSACleanup();
#endif
}
}
+23 -2
View File
@@ -20,6 +20,8 @@ UserSettings g_userSettings = {
},
.game = {
.language { "game.language", GameLanguage::English },
// Quality of Life
.enableQuickTransform {"game.enableQuickTransform", false},
.hideTvSettingsScreen {"game.hideTvSettingsScreen", false},
@@ -34,6 +36,7 @@ UserSettings g_userSettings = {
.fastClimbing {"game.fastClimbing", false},
.noMissClimbing {"game.noMissClimbing", false},
.fastTears {"game.fastTears", false},
.no2ndFishForCat {"game.no2ndFishForCat", false},
.instantSaves {"game.instantSaves", false},
.instantText {"game.instantText", false},
.sunsSong {"game.sunsSong", false},
@@ -41,10 +44,10 @@ UserSettings g_userSettings = {
// Preferences
.enableMirrorMode {"game.enableMirrorMode", false},
.invertCameraXAxis {"game.invertCameraXAxis", false},
.disableMainHUD {"game.disableMainHUD", false},
.pauseOnFocusLost {"game.pauseOnFocusLost", false},
.enableLinkDollRotation = {"game.enableLinkDollRotation", false },
.enableAchievementNotifications {"game.enableAchievementNotifications", false},
// Graphics
.bloomMode {"game.bloomMode", BloomMode::Classic},
@@ -54,6 +57,7 @@ UserSettings g_userSettings = {
.internalResolutionScale {"game.internalResolutionScale", 0},
.shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1},
.enableDepthOfField {"game.enableDepthOfField", true},
.enableMapBackground {"game.enableMapBackground", true},
// Audio
.noLowHpSound {"game.noLowHpSound", false},
@@ -69,6 +73,10 @@ UserSettings g_userSettings = {
.gyroDeadband {"game.gyroDeadband", 0.04f},
.gyroInvertPitch {"game.gyroInvertPitch", false},
.gyroInvertYaw {"game.gyroInvertYaw", false},
.freeCamera {"game.freeCamera", false},
.invertCameraXAxis {"game.invertCameraXAxis", false},
.invertCameraYAxis {"game.invertCameraYAxis", false},
.freeCameraSensitivity {"game.freeCameraSensitivity", 1.0f},
// Cheats
.infiniteHearts {"game.infiniteHearts", false},
@@ -90,7 +98,11 @@ UserSettings g_userSettings = {
.restoreWiiGlitches {"game.restoreWiiGlitches", false},
// Controls
.enableTurboKeybind {"game.enableTurboKeybind", false}
.enableTurboKeybind {"game.enableTurboKeybind", false},
// Tools
.speedrunMode {"game.speedrunMode", false},
.liveSplitEnabled {"game.liveSplitEnabled", false}
},
.backend = {
@@ -124,6 +136,7 @@ void registerSettings() {
Register(g_userSettings.audio.enableReverb);
// Game
Register(g_userSettings.game.language);
Register(g_userSettings.game.enableQuickTransform);
Register(g_userSettings.game.hideTvSettingsScreen);
Register(g_userSettings.game.skipWarningScreen);
@@ -136,12 +149,15 @@ void registerSettings() {
Register(g_userSettings.game.instantDeath);
Register(g_userSettings.game.fastClimbing);
Register(g_userSettings.game.fastTears);
Register(g_userSettings.game.no2ndFishForCat);
Register(g_userSettings.game.instantSaves);
Register(g_userSettings.game.instantText);
Register(g_userSettings.game.sunsSong);
Register(g_userSettings.game.autoSave);
Register(g_userSettings.game.enableMirrorMode);
Register(g_userSettings.game.invertCameraXAxis);
Register(g_userSettings.game.invertCameraYAxis);
Register(g_userSettings.game.freeCameraSensitivity);
Register(g_userSettings.game.disableMainHUD);
Register(g_userSettings.game.pauseOnFocusLost);
Register(g_userSettings.game.bloomMode);
@@ -150,15 +166,19 @@ void registerSettings() {
Register(g_userSettings.game.internalResolutionScale);
Register(g_userSettings.game.shadowResolutionMultiplier);
Register(g_userSettings.game.enableDepthOfField);
Register(g_userSettings.game.enableMapBackground);
Register(g_userSettings.game.enableFastIronBoots);
Register(g_userSettings.game.canTransformAnywhere);
Register(g_userSettings.game.freeMagicArmor);
Register(g_userSettings.game.restoreWiiGlitches);
Register(g_userSettings.game.enableLinkDollRotation);
Register(g_userSettings.game.enableAchievementNotifications);
Register(g_userSettings.game.noMissClimbing);
Register(g_userSettings.game.noLowHpSound);
Register(g_userSettings.game.midnasLamentNonStop);
Register(g_userSettings.game.enableTurboKeybind);
Register(g_userSettings.game.speedrunMode);
Register(g_userSettings.game.liveSplitEnabled);
Register(g_userSettings.game.fastSpinner);
Register(g_userSettings.game.infiniteHearts);
Register(g_userSettings.game.infiniteArrows);
@@ -180,6 +200,7 @@ void registerSettings() {
Register(g_userSettings.game.gyroSmoothing);
Register(g_userSettings.game.gyroInvertPitch);
Register(g_userSettings.game.gyroInvertYaw);
Register(g_userSettings.game.freeCamera);
Register(g_userSettings.backend.isoPath);
Register(g_userSettings.backend.graphicsBackend);
-4
View File
@@ -1020,10 +1020,6 @@ void GXInitTexCacheRegion(GXTexRegion* region, GXBool is_32b_mipmap, u32 tmem_ev
// XXX, this should be some struct?
// GXRenderModeObj GXNtsc480IntDf;
//GXRenderModeObj GXNtsc480Int;
void GXPeekZ(u16 x, u16 y, u32* z) {
STUB_LOG();
*z = 0;
}
void GXReadXfRasMetric(u32* xf_wait_in, u32* xf_wait_out, u32* ras_busy, u32* clocks) {
STUB_LOG();
*xf_wait_in = 0;
+82
View File
@@ -0,0 +1,82 @@
#include "dusk/version.hpp"
#include "dusk/logging.h"
namespace dusk::version {
using namespace std::string_view_literals;
static bool versionInitialized;
static GameVersion gameVersion;
static DVDDiskID diskId;
void init() {
versionInitialized = true;
if (!DVDLowReadDiskID(&diskId, nullptr)) {
DuskLog.fatal("DVDLowReadDiskID failed to return instantly.");
}
std::string_view company(diskId.company, sizeof(diskId.company));
std::string_view game(diskId.gameName, sizeof(diskId.gameName));
if (company != "01"sv) {
DuskLog.fatal("Wrong company ID in disc: {}", company);
}
if (game == "GZ2E"sv) {
gameVersion = GameVersion::GcnUsa;
} else if (game == "GZ2P") {
gameVersion = GameVersion::GcnPal;
} else {
// TODO: Handle remaining valid versions.
DuskLog.fatal("Unknown/unsupported game version in disc: {}", game);
}
DuskLog.info("Loaded game disc is {}{}", game, company);
}
bool isGcn() {
return getGameVersion() == GameVersion::GcnUsa
|| getGameVersion() == GameVersion::GcnPal
|| getGameVersion() == GameVersion::GcnJpn;
}
bool isWii() {
return getGameVersion() == GameVersion::WiiUsaRev0
|| getGameVersion() == GameVersion::WiiUsa
|| getGameVersion() == GameVersion::WiiPal
|| getGameVersion() == GameVersion::WiiJpn
|| getGameVersion() == GameVersion::WiiKor;
}
bool isPalOrAtLeastWiiR2() {
return getGameVersion() == GameVersion::GcnPal || getGameVersion() >= GameVersion::WiiUsa;
}
bool isRegionJpn() {
return getGameVersion() == GameVersion::WiiJpn || getGameVersion() == GameVersion::GcnJpn;
}
bool isRegionPal() {
return getGameVersion() == GameVersion::WiiPal || getGameVersion() == GameVersion::GcnPal;
}
bool isRegionUsa() {
return getGameVersion() == GameVersion::WiiUsa || getGameVersion() == GameVersion::WiiUsaRev0
|| getGameVersion() == GameVersion::GcnUsa;
}
GameVersion getGameVersion() {
if (!versionInitialized) {
abort();
}
return gameVersion;
}
const DVDDiskID& getDiskID() {
return diskId;
}
} // namespace dusk::version
+4
View File
@@ -15,6 +15,7 @@
#include "d/d_model.h"
#include "d/d_tresure.h"
#include "dusk/frame_interpolation.h"
#include "dusk/livesplit.h"
#include "dusk/logging.h"
#include "f_op/f_op_camera_mng.h"
#include "f_op/f_op_draw_tag.h"
@@ -821,6 +822,9 @@ void fapGm_Execute() {
#endif
cCt_Counter(0);
#ifdef TARGET_PC
dusk::speedrun::onGameFrame();
#endif
}
fapGm_HIO_c g_HIO;
+20
View File
@@ -7,6 +7,8 @@
#include "f_op/f_op_overlap_req.h"
#include "f_pc/f_pc_manager.h"
#include "dusk/imgui/ImGuiMenuGame.hpp"
void fopOvlpReq_SetPeektime(overlap_request_class*, u16);
static int fopOvlpReq_phase_Done(overlap_request_class* i_overlapReq) {
@@ -16,6 +18,16 @@ static int fopOvlpReq_phase_Done(overlap_request_class* i_overlapReq) {
i_overlapReq->peektime = 0;
i_overlapReq->field_0x8 = 0;
i_overlapReq->field_0xc = 0;
#if TARGET_PC
if (dusk::getSettings().game.speedrunMode) {
if (dusk::m_speedrunInfo.m_isRunStarted) {
dusk::m_speedrunInfo.m_isPauseIGT = false;
dusk::m_speedrunInfo.m_totalLoadTime += OSGetTime() - dusk::m_speedrunInfo.m_loadStartTimestamp;
dusk::m_speedrunInfo.m_loadStartTimestamp = OSGetTime();
}
}
#endif
return cPhs_NEXT_e;
}
@@ -81,6 +93,14 @@ static int fopOvlpReq_phase_Create(overlap_request_class* i_overlapReq) {
fpcLy_SetCurrentLayer(i_overlapReq->layer);
i_overlapReq->request_id =
fpcM_Create(i_overlapReq->procname, NULL, NULL);
#if TARGET_PC
if (dusk::m_speedrunInfo.m_isRunStarted) {
dusk::m_speedrunInfo.m_isPauseIGT = true;
dusk::m_speedrunInfo.m_loadStartTimestamp = OSGetTime();
}
#endif
return cPhs_NEXT_e;
}
+3 -2
View File
@@ -4,13 +4,14 @@
*/
#include "f_op/f_op_scene_req.h"
#include <cstdio>
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/logging.h"
#include "f_op/f_op_overlap_mng.h"
#include "f_op/f_op_scene.h"
#include "f_op/f_op_scene_pause.h"
#include "f_pc/f_pc_executor.h"
#include "f_pc/f_pc_manager.h"
#include <cstdio>
#include "dusk/logging.h"
static cPhs_Step fopScnRq_phase_ClearOverlap(scene_request_class* i_sceneReq) {
return fopOvlpM_ClearOfReq() == 1 ? cPhs_NEXT_e : cPhs_INIT_e;
+6 -1
View File
@@ -12,6 +12,7 @@
#include "os_report.h"
#include "dusk/os.h"
#include "dusk/main.h"
#include "dusk/version.hpp"
#if PLATFORM_WII || PLATFORM_SHIELD
#include <revolution/nand.h>
@@ -79,7 +80,11 @@ void mDoMemCd_Ctrl_c::ThdInit() {
#if !PLATFORM_SHIELD
CARDSetLoadType((CARDFileType)dusk::getSettings().backend.cardFileType.getValue());
CARDInit(DUSK_GAME_NAME, DUSK_GAME_VERSION);
char version[5] = {};
char maker[3] = {};
std::memcpy(version, dusk::version::getDiskID().gameName, 4);
std::memcpy(maker, dusk::version::getDiskID().company, 2);
CARDInit(version, maker);
#endif
mCopyToPos = 0;
+35 -1
View File
@@ -11,6 +11,8 @@
#include <cstdio>
#include <cstring>
#include "dusk/version.hpp"
#if VERSION == VERSION_GCN_JPN
#define HEADER_TITLE "ゼルダの伝説 トワイライトプリンセス"
#define HEADER_COMMENT "%d月%d日のセーブデータです"
@@ -313,12 +315,44 @@ s32 mDoMemCdRWm_StoreBannerNAND(NANDFileInfo* file) {
#endif
static void mDoMemCdRWm_BuildHeader(mDoMemCdRWm_HeaderData* header) {
#if !TARGET_PC
snprintf(header->mTitle, sizeof(header->mTitle), HEADER_TITLE);
#endif
OSCalendarTime time;
OSTicksToCalendarTime(OSGetTime(), &time);
#if VERSION == VERSION_GCN_PAL
#if TARGET_PC
if (dusk::version::isRegionPal()) {
snprintf(header->mTitle, sizeof(header->mTitle), HEADER_TITLE);
switch (dComIfGs_getPalLanguage()) {
case dSv_player_config_c::LANGUAGE_ENGLISH:
snprintf(header->mComment, sizeof(header->mComment), "%d/%d Save Data", time.mon + 1, time.mday);
break;
case dSv_player_config_c::LANGUAGE_GERMAN:
snprintf(header->mComment, sizeof(header->mComment), "%d/%d Spielstand", time.mday, time.mon + 1);
break;
case dSv_player_config_c::LANGUAGE_FRENCH:
snprintf(header->mComment, sizeof(header->mComment), "Donn%ces de jeu %d/%d", 0xE9, time.mday, time.mon + 1);
break;
case dSv_player_config_c::LANGUAGE_SPANISH:
snprintf(header->mComment, sizeof(header->mComment), "Datos guardados el %d/%d", time.mday, time.mon + 1);
break;
case dSv_player_config_c::LANGUAGE_ITALIAN:
snprintf(header->mComment, sizeof(header->mComment), "Dati salvati: %d/%d", time.mday, time.mon + 1);
break;
}
} else if (dusk::version::isRegionUsa()) {
snprintf(header->mTitle, sizeof(header->mTitle), HEADER_TITLE);
snprintf(header->mComment, sizeof(header->mComment), HEADER_COMMENT, time.mon + 1, time.mday);
} else {
// TODO JPN SHIFT-JIS
// snprintf(header->mTitle, sizeof(header->mTitle), "ゼルダの伝説 トワイライトプリンセス");
// snprintf(header->mComment, sizeof(header->mComment), "%d月%d日のセーブデータです", time.mon + 1, time.mday);
}
#elif VERSION == VERSION_GCN_PAL
switch (dComIfGs_getPalLanguage()) {
case dSv_player_config_c::LANGUAGE_ENGLISH:
snprintf(header->mComment, sizeof(header->mComment), "%d/%d Save Data", time.mon + 1, time.mday);
+1
View File
@@ -2146,6 +2146,7 @@ int mDoGph_Painter() {
// FRAME INTERP NOTE: Call setViewMtx earlier so that it's interpolated in time for draw_info to use it
j3dSys.setViewMtx(camera_p->view.viewMtx);
JPADrawInfo draw_info(j3dSys.getViewMtx(), camera_p->view.fovy, camera_p->view.aspect);
mDoGph_gInf_c::setWideZoomLightProjection(draw_info.mPrjMtx);
#else
JPADrawInfo draw_info(camera_p->view.viewMtx, camera_p->view.fovy, camera_p->view.aspect);
#endif
+21
View File
@@ -71,6 +71,7 @@
#include "dusk/config.hpp"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/settings.h"
#include "dusk/version.hpp"
#include "dusk/discord_presence.hpp"
#include "tracy/Tracy.hpp"
#include "f_pc/f_pc_draw.h"
@@ -465,6 +466,23 @@ static constexpr PADDefaultMapping defaultPadMapping = {
static bool mainCalled = false;
static u8 selectedLanguage;
u8 OSGetLanguage() {
return selectedLanguage;
}
static void LanguageInit() {
// Keep language at 0 (English) if not on a PAL disk.
// Doubt this matters, but avoid funky shit.
if (!dusk::version::isRegionPal()) {
return;
}
// Cache this to avoid funky shenanigans.
selectedLanguage = static_cast<u8>(dusk::getSettings().game.language.getValue());
}
// =========================================================================
// PC ENTRY POINT
// =========================================================================
@@ -597,6 +615,9 @@ int game_main(int argc, char* argv[]) {
}
}
dusk::version::init();
LanguageInit();
OSInit();
mDoMain::sPowerOnTime = OSGetTime();