Files
ss/src/d/d_pad.cpp
T
robojumper ec6979b211 More
2025-10-17 21:24:27 +02:00

1446 lines
39 KiB
C++

#include "d/d_pad.h"
#include "c/c_math.h"
#include "common.h"
#include "d/a/d_a_player.h"
#include "d/col/c/c_m3d_g_aab.h"
#include "d/d_cs_game.h"
#include "d/d_gfx.h"
#include "d/d_hbm.h"
#include "d/d_pad_manager.h"
#include "d/d_pad_nav.h"
#include "d/d_reset.h"
#include "d/d_sc_game.h"
#include "d/lyt/d_lyt_control_game.h"
#include "d/lyt/d_lyt_map.h"
#include "d/lyt/meter/d_lyt_meter.h"
#include "d/snd/d_snd_player_mgr.h"
#include "d/snd/d_snd_small_effect_mgr.h"
#include "d/snd/d_snd_wzsound.h"
#include "egg/core/eggController.h"
#include "egg/core/eggHeap.h"
#include "egg/math/eggMath.h"
#include "egg/math/eggVector.h"
#include "m/m_angle.h"
#include "m/m_mtx.h"
#include "m/m_pad.h"
#include "m/m_vec.h"
#include "nw4r/math/math_types.h"
#include "rvl/KPAD/KPAD.h"
#include "rvl/MTX/mtx.h"
#include "rvl/MTX/mtxvec.h"
#include "rvl/MTX/vec.h"
#include "rvl/WPAD/WPAD.h"
#include <cmath>
namespace dPad {
ex_c ex_c::m_ex[4];
ex_c *ex_c::m_current_ex = ex_c::m_ex;
WPADInfo ex_c::m_info[2][4];
bool ex_c::m_connected[4];
// TODO - the SDK decomp uses WPAD error codes for this
// callback, but I think they have different semantics.
// Refer to https://github.com/doldecomp/sdk_2009-12-11/blob/main/source/kpad/KPAD.c#L3607-L3639
// for logic.
void control_mpls_callback(s32 idx, s32 code) {
switch (code) {
// Called first
case 0: {
ex_c::on_0x54(idx);
break;
}
// Called when Mpls configuration failed - not actually reached?
case -1: {
ex_c::on_0x55(idx);
break;
}
// Called when Mpls + Nunchuk configuration failed -- called a bunch of times
case -2: {
ex_c::on_0x56(idx);
break;
}
// not sure - called last
case 1: {
ex_c::on_0x57(idx);
break;
}
}
}
bool isDeviceTypeMpls(u32 type) {
switch (type) {
case WPAD_DEV_MOTION_PLUS:
case WPAD_DEV_MPLS_PT_FS:
case WPAD_DEV_MPLS_PT_CLASSIC:
case WPAD_DEV_MPLS_PT_UNKNOWN: return true;
default: return false;
}
}
void initMpls(s32 chan) {
KPADResetMpls(chan);
KPADDisableMplsZeroPlay(chan);
KPADSetMplsZeroPlayParam(chan, 0.005f);
KPADSetMplsZeroDriftMode(chan, 2);
disableMplsDirRevise(chan);
KPADSetMplsDirReviseParam(chan, 0.35f);
KPADEnableMplsAccRevise(chan);
KPADSetMplsAccReviseParam(chan, 0.03f, 0.4f);
KPADEnableMplsDpdRevise(chan);
KPADSetMplsDpdReviseParam(chan, 0.5f);
}
extern "C" void fn_80194080();
void create() {
mPad::create();
KPADSetBtnRepeat(mPad::getCore(0)->getChannelID(), 0.5f, 0.1f);
ex_c::resetInfo();
KPADSetMplsWorkarea(new (0x20) u8[KPADGetMplsWorkSize()]);
for (int i = 0; i < 4; ++i) {
ex_c::m_ex[i].mMotion.init();
KPADSetReviseMode(i, 1);
KPADSetControlMplsCallback(i, control_mpls_callback);
ex_c::m_ex[i].gotoStateWaitForConnect(i);
}
fn_80194080();
}
void setMpls(bool enable, s32 chan) {
if (enable) {
if (ex_c::m_ex[chan].mMplsEnabled == false) {
ex_c::m_ex[chan].mMplsEnabled = true;
// WPAD_DEV_MODE_MPLS_PT_FS
// i.e. Skyward Sword wants both MotionPlus and Nunchuk
KPADEnableMpls(chan, 5);
initMpls(chan);
}
} else {
if (ex_c::m_ex[chan].mMplsEnabled) {
ex_c::m_ex[chan].mMplsEnabled = false;
KPADDisableMpls(chan);
}
}
}
void convertDpdPosToScreenPos(mVec2_c &in, mVec2_c &out) {
out.x = dGfx_c::getWidth4x3F() * 0.5f * (1.f + in.x) + dGfx_c::getWidth4x3LeftF();
out.y = dGfx_c::getCurrentScreenHeightF() * -0.5f * (1.f + in.y) + dGfx_c::getCurrentScreenTopF();
}
void beginPad_BR() {
mPad::beginPad();
if (mPad::getCore(0)->isConnected()) {
WPADSetAcceptConnection(0);
} else {
WPADSetAcceptConnection(1);
}
// Forces only first controller to be active
for (int i = 1; i < 4; ++i) {
if (mPad::getCore(i)->isConnected()) {
WPADDisconnect(i);
}
}
dPad::ex_c &ex = ex_c::m_ex[0];
ex.fn_800572A0(0);
if (mPad::getCore(0)->isConnected()) {
ex.getUnifiedWpadStatus(0);
ex.fn_80059300(0);
ex.fn_80056AF0(0);
ex.fn_80056B90(0);
ex.fn_80056CE0(0);
ex.workMplsCalibration(0);
bool isDpdReviseEnabled = KPADIsEnableMplsDpdRevise(0) >= 0.f;
if (ex.field_0x22CE) {
if (isDpdReviseEnabled) {
KPADDisableMplsDpdRevise(0);
}
} else {
if (!isDpdReviseEnabled) {
KPADEnableMplsDpdRevise(0);
}
}
ex.field_0x22CE = false;
const dAcPy_c *player = dAcPy_c::GetLink();
if (player && player->isAttacking()) {
mMtx_c m;
mVec3_c baseX;
mVec3_c baseY;
mVec3_c baseZ;
KPADVec kpadvec;
m.XrotS(mAng::deg2short(-30.f));
baseZ.z = m.m[2][2];
baseZ.y = m.m[1][2];
baseZ.x = m.m[0][2];
kpadvec[2].x = baseZ.x;
kpadvec[2].y = baseZ.y;
kpadvec[2].z = baseZ.z;
VECCrossProduct(ex_c::m_ex[0].mMPLS.mY, baseZ, baseX);
if (VECMag(baseX) > 0.05f) {
baseX.normalize();
kpadvec[0].z = baseX.z;
kpadvec[0].y = baseX.y;
kpadvec[0].x = baseX.x;
} else {
baseX = baseZ;
kpadvec[0].z = baseX.z;
kpadvec[0].y = baseX.y;
kpadvec[0].x = baseX.x;
}
VECCrossProduct(baseZ, baseX, baseY);
if (VECMag(baseY) > 0.05f) {
baseY.normalize();
kpadvec[1].z = baseY.z;
kpadvec[1].y = baseY.y;
kpadvec[1].x = baseY.x;
} else {
baseY = baseZ;
kpadvec[1].z = baseY.z;
kpadvec[1].y = baseY.y;
kpadvec[1].x = baseY.x;
}
KPADSetMplsDirReviseBase(0, kpadvec);
enableMplsDirRevise(0);
} else {
disableMplsDirRevise(0);
}
KPADEnableMplsAccRevise(0);
KPADSetMplsAccReviseParam(0, 0.03f, 0.4f);
if ((dCsGame_c::GetInstance() != nullptr && dCsGame_c::GetInstance()->shouldDraw() && !ex.field_0x22D0) ||
(dAcPy_c::GetLink() != nullptr &&
dAcPy_c::GetLink()->checkActionFlagsCont(0x400 | 0x100 | 0x80 | 0x40 | 0x10 | 0x4 | 0x2 | 0x1) &&
!dAcPy_c::GetLink()->vt_0x1C0() && !dLytMeter_c::GetMain()->getField_0x1377F()) ||
ex.field_0x22CF) {
if (dLytControlGame_c::getInstance() && dLytControlGame_c::getInstance()->isStateNormal()) {
if (!(dPadManager_c::GetInstance() && dPadManager_c::GetInstance()->getField_0x25())) {
KPADDisableMplsDpdRevise(0);
KPADDisableMplsAccRevise(0);
}
}
KPADDisableMplsDirRevise(0);
}
if (ex.mIsCalibrating || ex.field_0x48 != 0) {
KPADEnableMplsAccRevise(0);
KPADSetMplsAccReviseParam(0, 1.f, 0.6f);
if (--ex.field_0x48 < 0) {
ex.field_0x48 = 0;
}
}
ex.field_0x22CF = false;
ex.mFSStick.x = mPad::getCore(0)->getFreeStickX();
ex.mFSStick.y = mPad::getCore(0)->getFreeStickY();
ex.mFSStickDistance = ex.mFSStick.length();
ex.mFSStickAngle = -ex.mFSStick.ang();
ex.calcFSStickDirMask();
bool isMpls = mPad::isMpls(0) || mPad::isMplsPtFS(0);
if (isMpls) {
ex.mMPLSVelocity.copyFrom(&mPad::getCore(0)->getCoreStatus()->mpls_rot);
ex.mMPLS.mX.copyFrom(&mPad::getCore(0)->getCoreStatus()->mpls_basis_x);
ex.mMPLS.mY.copyFrom(&mPad::getCore(0)->getCoreStatus()->mpls_basis_y);
ex.mMPLS.mZ.copyFrom(&mPad::getCore(0)->getCoreStatus()->mpls_basis_z);
} else {
ex.mMPLSVelocity.set(0.f, 0.f, 0.f);
ex.mMPLS.mX = mVec3_c::Ex;
ex.mMPLS.mY = mVec3_c::Ey;
ex.mMPLS.mZ = mVec3_c::Ez;
}
ex.fn_80056790(0);
if (ex.field_0x50) {
ex.mDpdPos = ex.field_0x5C;
} else {
if (mPad::getCore(0)->getDpdValidFlag() > 0) {
ex.mDpdPos = mPad::getDpdRawPos(0);
} else {
ex.mDpdPos.set(-2.f, -2.f);
}
}
convertDpdPosToScreenPos(ex.mDpdPos, ex.mDpdPosScreen);
ex.updateStatus(0);
}
ex_c::m_current_ex = &ex_c::m_ex[mPad::getCurrentCoreID()];
if (dReset::Manage_c::GetInstance()->isSoftResetOrSafetyWait()) {
for (int i = 0; i < 4; ++i) {
EGG::CoreController *core = mPad::g_core[i];
core->getCoreStatus()->hold &= EGG::cCORE_BUTTON_HOME;
core->getCoreStatus()->trig &= EGG::cCORE_BUTTON_HOME;
core->getCoreStatus()->release &= EGG::cCORE_BUTTON_HOME;
}
}
dPadNav::calc();
}
void endPad_BR() {
mPad::endPad();
}
void connectCallback(const EGG::CoreControllerConnectArg &rArg) {
switch (rArg.result) {
case WPAD_ERR_OK: {
dSndPlayerMgr_c::GetInstance()->setupRmtSpeaker(rArg.chan);
ex_c::m_ex[rArg.chan].mDidConnect = true;
break;
}
case WPAD_ERR_NO_CONTROLLER: {
dSndPlayerMgr_c::GetInstance()->shutdownRmtSpeaker(rArg.chan);
ex_c::m_ex[rArg.chan].mDidDisconnect = true;
break;
}
}
}
void setConnectCallback() {
EGG::CoreControllerMgr::setConnectCallback(connectCallback);
}
void enableMplsDirRevise(s32 chan) {
KPADEnableMplsDirRevise(chan);
}
void disableMplsDirRevise(s32 chan) {
KPADDisableMplsDirRevise(chan);
}
ex_c::ex_c()
: mDpdPos(0.f, 0.f),
mDpdPosScreen(0.f, 0.f),
mFSStick(0.f, 0.f),
mFSStickDistance(0.f),
mFSStickAngle(0),
mWPADProbeResult(0),
mWPADProbeResultStable(0),
mWPADProbeStableTimer(0),
mWPADDeviceType(0),
mWPADDeviceTypeStable(0xFF),
mWPADDeviceTypeStableTimer(0),
mConnectedStableTimer(0),
field_0x3C(0),
mCalibrationWork(0.f),
field_0x44(false),
field_0x45(false),
field_0x46(false),
mIsCalibrating(false),
field_0x48(0),
mDidConnect(false),
mDidDisconnect(false),
mNeedMplsCalibration(true),
field_0x4F(false),
field_0x50(true),
field_0x51(0),
mMplsEnabled(false),
field_0x53(false),
field_0x54(false),
field_0x55(false),
field_0x56(false),
field_0x57(false),
field_0x58(false),
field_0x59(false),
field_0x5A(false),
field_0x5B(false),
field_0x5C(0.f, 0.f),
field_0x64(0.f, 0.f),
mIsWPADDeviceTypeMplsStableTimer(0),
field_0x70(0x1200),
field_0x74(1.f, 0.f, 0.f),
field_0x80(0.f, 1.f, 0.f),
field_0x8C(0.f, 0.f, 1.f),
mState(0),
mOutOfHbmStableTimer(0),
field_0x2288(0),
field_0x22CE(0),
field_0x22CF(0),
field_0x22D0(0),
mFSStickMaskChanged(false),
mFSStickMask(0),
field_0x22D8(0) {
memset(&mStatus, 0, sizeof(mStatus));
}
void ex_c::fn_80055EF0(s32 chan) {
const s32 readLen = mPad::getCore(chan)->getReadLength();
// Shift all old acceleration values back
for (int i = 120 - 1; i >= readLen; i--) {
mMotion.mAccVecs[i] = mMotion.mAccVecs[i - readLen];
mMotion.mAccValues[i] = mMotion.mAccValues[i - readLen];
mFSMotion.mAccVecs[i] = mFSMotion.mAccVecs[i - readLen];
mFSMotion.mAccValues[i] = mFSMotion.mAccValues[i - readLen];
}
// Write newly read Wiimote acceleration values
// TODO - Missing an implicit != 0 check before the loop
for (int i = 0; i < readLen; i++) {
EGG::CoreStatus status = *mPad::getCore(chan)->getCoreStatus(i);
mMotion.mAccVecs[i].copyFrom(&status.acc);
mMotion.mAccValues[i] = status.acc_value;
}
mMotion.fn_80058AE0(chan, true);
// Write newly read Nunchuk acceleration values
for (int i = 0; i < readLen; ++i) {
if (mPad::getCore(chan)->getDevType() == EGG::cDEV_FREESTYLE ||
(mPad::isMplsPtFS(chan) && (u8)KPADGetMplsStatus(chan) == 5)) {
EGG::CoreStatus status = *mPad::getCore(chan)->getCoreStatus(i);
mFSMotion.mAccVecs[i].copyFrom(&status.acc);
mFSMotion.mAccValues[i] = status.acc_value;
} else {
mFSMotion.mAccVecs[i].set(0.f, 0.f, 0.f);
mFSMotion.mAccValues[i] = 0.f;
}
}
if (mPad::getCore(chan)->getDevType() == EGG::cDEV_FREESTYLE ||
(mPad::isMplsPtFS(chan) && (u8)KPADGetMplsStatus(chan) == 5)) {
mFSMotion.fn_80058AE0(chan, false);
}
}
void float_order_d_pad() {
EGG::Math<f32>::epsilon();
}
void ex_c::fn_800562B0(s32 chan, mVec3_c &mpls) {
if (field_0x53) {
mpls = m_ex[chan].mMPLS.mY;
mpls *= -1.f;
} else {
mpls = m_ex[chan].mMPLS.mZ;
}
}
void ex_c::fn_80056330(s32 chan) {
f32 mult = cM::minMaxLimit(1.f - field_0x8C.y * field_0x8C.y, 0.f, 1.f);
mVec3_c basis;
if (field_0x53) {
basis = m_ex[chan].mMPLS.mZ;
} else {
basis = m_ex[chan].mMPLS.mY;
}
// ??
field_0x74 = (mult * (mVec3_c::Ey - basis) + basis).cross(field_0x8C);
f32 mag = field_0x74.mag();
bool b = std::abs(mag) <= EGG::Math<f32>::epsilon();
if (b) {
field_0x74 = mVec3_c::Ex;
} else {
field_0x74 *= 1.f / mag;
}
field_0x80 = field_0x8C.cross(field_0x74);
field_0x80.normalize();
}
void ex_c::fn_80056580(s32 chan, const mVec2_c &vec) {
field_0x5C = vec;
field_0x53 = false;
mMtx_c m;
m.ZXYrotS(-field_0x5C.y * field_0x70, field_0x5C.x * field_0x70, 0);
MTXMultVecSR(m, m_ex[chan].mMPLS.mZ, field_0x8C);
fn_80056330(chan);
}
void ex_c::centerCursor(s32 chan, bool b) {
if (field_0x51 != 0 && b) {
return;
}
field_0x64 = field_0x5C;
// NON-MATCHING
bool tmp = false;
const EGG::Vector3f acc = mPad::getCore()->getAccelBad();
if (dAcPy_c::GetLink() && dAcPy_c::GetLink()->checkActionFlagsCont(0x2) && acc.z < -0.9f) {
tmp = true;
}
field_0x53 = tmp;
fn_800562B0(chan, field_0x8C);
fn_80056330(chan);
if (b) {
dSndSmallEffectMgr_c::GetInstance()->playSound(SE_S_POINTER_RESET);
field_0x51 = 3;
} else {
field_0x51 = 0;
field_0x5C.set(0.f, 0.f);
mDpdPos.set(0.f, 0.f);
convertDpdPosToScreenPos(mDpdPos, mDpdPosScreen);
}
}
void ex_c::fn_80056790(s32 chan) {
mVec2_c dpdRawPos = mPad::getDpdRawPos(chan);
f32 f;
if (dScGame_c::GetInstance() != nullptr && dLytMap_c::GetInstance() != nullptr &&
!dLytMap_c::GetInstance()->isVisible()) {
f = dScGame_c::GetInstance()->targetingScreenFn_801BBEC0();
} else {
f = 1.0f;
}
field_0x22D8 = 0;
EGG::CoreStatus coreStatus = *mPad::getCore(chan)->getCoreStatus(0);
if (coreStatus.dpd_valid_fg == 2) {
field_0x22D8 = 1;
}
mVec3_c v;
fn_800562B0(chan, v);
mVec3_c v2(v.dot(field_0x74), v.dot(field_0x80), v.dot(field_0x8C));
v2.z = nw4r::ut::Max(v2.z, field_0x70.cos());
s16 b1 = cM::atan2s(-v2.x, v2.z);
field_0x5C.x = cM::minMaxLimit(b1 * (1.0f / field_0x70), -1.0f, 1.0f);
s16 b2 = cM::atan2s(-v2.y, v2.z);
field_0x5C.y = cM::minMaxLimit(b2 * (1.0f / field_0x70), -f, f);
if (field_0x51 != 0) {
field_0x51--;
}
f32 f4 = field_0x51 * (1 / 3.0f);
// lerp
field_0x5C = field_0x5C * (1.0f - f4) + field_0x64 * f4;
}
void ex_c::setField_0x70(mAng ang) {
field_0x70 = ang;
}
void ex_c::setField_0x70() {
field_0x70.set(0x1200);
}
void ex_c::fn_80056AF0(s32 chan) {
if (mDidConnect) {
mDidConnect = false;
mConnectedStableTimer = 90;
field_0x44 = true;
m_ex[chan].field_0x46 = true;
m_ex[chan].field_0x3C = 120;
} else {
field_0x44 = false;
}
if (mDidDisconnect) {
mDidDisconnect = false;
field_0x45 = true;
m_ex[chan].mWPADDeviceTypeStable = WPAD_DEV_UNKNOWN;
} else {
field_0x45 = false;
}
}
bool ex_c::checkWPADProbeStable() {
return mWPADProbeResultStable == WPAD_ERR_OK;
}
void ex_c::fn_80056B90(s32 chan) {
u32 prevType = mWPADDeviceType;
WPADResult prevResult = mWPADProbeResult;
mWPADProbeResult = WPADProbe(chan, &mWPADDeviceType);
if (prevResult == mWPADProbeResult) {
mWPADProbeStableTimer++;
if (mWPADProbeStableTimer >= 5) {
mWPADProbeStableTimer = 5;
}
} else {
mWPADProbeStableTimer = 0;
}
if (mWPADProbeStableTimer >= 5) {
mWPADProbeResultStable = mWPADProbeResult;
}
if (mConnectedStableTimer > 0) {
mConnectedStableTimer--;
if (mConnectedStableTimer < 0) {
mConnectedStableTimer = 0;
}
}
if (prevType != mWPADDeviceType) {
mWPADDeviceTypeStableTimer = 0;
} else {
mWPADDeviceTypeStableTimer++;
if (mWPADDeviceTypeStableTimer > 20) {
mWPADDeviceTypeStableTimer = 20;
}
}
if (mWPADDeviceType != mWPADDeviceTypeStable && mWPADDeviceTypeStableTimer >= 20) {
mWPADDeviceTypeStable = mWPADDeviceType;
}
if (!isDeviceTypeMpls(mWPADDeviceTypeStable)) {
mNeedMplsCalibration = true;
mIsWPADDeviceTypeMplsStableTimer = 0;
}
if (isDeviceTypeMpls(mWPADDeviceTypeStable) && mIsWPADDeviceTypeMplsStableTimer < 8) {
mIsWPADDeviceTypeMplsStableTimer++;
}
}
void ex_c::fn_80056CE0(s32 chan) {
if (field_0x46 == false) {
return;
}
if (field_0x3C == 1) {
if (WPADCanSendStreamData(chan) && WPADGetRadioSensitivity(chan) > 50) {
WPADResult res = getInfo(chan);
if (res == WPAD_ERR_OK || res == WPAD_ERR_NO_CONTROLLER) {
field_0x46 = false;
} else {
field_0x3C = 120;
}
} else {
field_0x3C = 120;
}
}
field_0x3C--;
if (field_0x3C < 0) {
field_0x3C = 0;
}
}
void ex_c::startMplsCalibration(s32 chan) {
KPADStartMplsCalibration(chan);
mIsCalibrating = true;
mCalibrationWork = 1.0f;
field_0x48 = 0;
}
void ex_c::workMplsCalibration(s32 chan) {
if (!mIsCalibrating) {
return;
}
mCalibrationWork = KPADWorkMplsCalibration(chan);
if (mCalibrationWork == 0.0f) {
mIsCalibrating = false;
field_0x48 = 60;
}
}
f32 ex_c::getCalibrationWork() {
return mCalibrationWork;
}
void ex_c::stopMplsCalibration(s32 chan) {
mIsCalibrating = false;
mCalibrationWork = 0.0f;
KPADStopMplsCalibration(chan);
field_0x48 = 0;
}
void ex_c::centerCursor(s32 chan) {
centerCursor(chan, false);
field_0x48 = 0;
}
void ex_c::gotoStateWaitForConnect(s32 chan) {
mState = EX_STATE_WAITING_FOR_CONNECT;
}
void ex_c::executeStateWaitForConnect(s32 chan) {
if (mPad::getCore(chan)->isConnected()) {
gotoStatePostConnect(chan);
}
}
void ex_c::gotoStatePostConnect(s32 chan) {
mState = EX_STATE_POST_CONNECT;
}
void ex_c::executeStatePostConnect(s32 chan) {
if (dHbm::Manage_c::GetInstance()->getState() == dHbm::Manage_c::HBM_MANAGE_ACTIVE) {
// If we are in HBM, set some sort of cooldown
mOutOfHbmStableTimer = 110;
field_0x4F = true;
}
if (mPad::getCore(chan)->isConnected()) {
if (ex_c::checkWPADProbeStable() &&
dHbm::Manage_c::GetInstance()->getState() != dHbm::Manage_c::HBM_MANAGE_ACTIVE) {
// Enable Mpls after we leave HBM
gotoStateEnableMpls(chan);
}
}
if (!mPad::getCore(chan)->isConnected()) {
gotoStateWaitForConnect(chan);
}
}
void ex_c::gotoStateEnableMpls(s32 chan) {
mState = EX_STATE_ENABLE_MPLS;
setMpls(true, chan);
}
void ex_c::executeStateEnableMpls(s32 chan) {
if (fn_80059350(chan) || fn_80059370(chan)) {
gotoStateMplsConfigError(chan);
} else if (fn_80059390(chan)) {
gotoStateMplsConfigured(chan);
}
}
void ex_c::gotoStateDisconnectWpad(s32 chan) {
mState = EX_STATE_DISCONECT_WPAD;
WPADDisconnect(chan);
}
void ex_c::executeStateDisconnectWpad(s32 chan) {
gotoStatePostConnect(chan);
}
void ex_c::gotoStateMplsConfigError(s32 chan) {
mState = EX_STATE_MPLS_CONFIG_ERROR;
setMpls(false, chan);
field_0x2288 = 0;
}
void ex_c::executeStateMplsConfigError(s32 chan) {
if (fn_80059390(chan)) {
if (dHbm::Manage_c::GetInstance()->getState() == dHbm::Manage_c::HBM_MANAGE_ACTIVE) {
gotoStatePostConnect(chan);
} else {
gotoStateEnableMpls(chan);
}
} else {
if (dHbm::Manage_c::GetInstance()->getState() != dHbm::Manage_c::HBM_MANAGE_ACTIVE) {
if (field_0x2288 > 120) {
gotoStateDisconnectWpad(chan);
} else {
field_0x2288++;
}
}
}
}
void ex_c::gotoStateMplsConfigured(s32 chan) {
mState = EX_STATE_MPLS_CONFIGURED;
}
void ex_c::executeStateMplsConfigured(s32 chan) {
if (!mPad::getCore(chan)->isConnected()) {
setMpls(false, chan);
gotoStateWaitForConnect(chan);
} else {
if (fn_80059330(chan) || fn_80059350(chan) || fn_80059370(chan)) {
setMpls(false, chan);
}
}
if (!mMplsEnabled) {
gotoStatePostConnect(chan);
}
if (dHbm::Manage_c::GetInstance()->getState() == dHbm::Manage_c::HBM_MANAGE_ACTIVE) {
field_0x4F = false;
}
}
void ex_c::fn_800572A0(s32 chan) {
switch (mState) {
case EX_STATE_WAITING_FOR_CONNECT: executeStateWaitForConnect(chan); break;
case EX_STATE_POST_CONNECT: executeStatePostConnect(chan); break;
case EX_STATE_ENABLE_MPLS: executeStateEnableMpls(chan); break;
case EX_STATE_DISCONECT_WPAD: executeStateDisconnectWpad(chan); break;
case EX_STATE_MPLS_CONFIG_ERROR: executeStateMplsConfigError(chan); break;
case EX_STATE_MPLS_CONFIGURED: executeStateMplsConfigured(chan); break;
}
if (mState != EX_STATE_POST_CONNECT &&
dHbm::Manage_c::GetInstance()->getState() != dHbm::Manage_c::HBM_MANAGE_ACTIVE) {
if (mOutOfHbmStableTimer > 0) {
mOutOfHbmStableTimer--;
} else {
mOutOfHbmStableTimer = 0;
}
}
}
void ex_c::acc_c::init() {
for (int i = 0; i < 120; ++i) {
mAccVecs[i].set(0.f, 0.f, 0.f);
field_0x5A0[i].set(0.f, 0.f, 0.f);
mAccValues[i] = 0.f;
}
for (int i = 0; i < 39; ++i) {
field_0xD20[i].set(0.f, 0.f, 0.f);
}
for (int i = 0; i < 33; ++i) {
field_0xEF4[i].set(0.f, 0.f, 0.f);
}
field_0x1080.set(0.f, 0.f, 0.f);
field_0x108C.set(0.f, 0.f, 0.f);
MTXIdentity(field_0x1098);
field_0x10C8 = 0;
field_0x10CC = 0;
field_0x10D0 = 0;
field_0x10D4 = 0;
field_0x10D8 = 31;
}
f32 ex_c::acc_c::getMaxAccValue(s32 chan) {
s32 readLen = mPad::getCore(chan)->getReadLength();
if (readLen == 0) {
return 0.0f;
}
f32 max = 0.0f;
for (int i = 0; i < readLen; i++) {
if (max < mAccValues[i]) {
max = mAccValues[i];
}
}
return max;
}
void ex_c::acc_c::fn_800576D0(s32 chan) {
// unused
(void)nw4r::math::FSqrt(mAccVecs[0].squaredLength());
f32 maxAccValue = getMaxAccValue(chan);
if (maxAccValue <= 1.1f && mAccVecs[0].y < 0.35f) {
field_0x10D0++;
if (field_0x10D0 >= 6) {
field_0x10D0 = 6;
field_0x108C = mAccVecs[0];
mVec3_c dir(0.0f, -1.0f, 0.0f);
f32 len = mAccVecs[0].squaredLength();
if (!cM3d_IsZero(len)) {
// TODO - bad part start
mVec3_c acc = mAccVecs[0];
acc.normalize();
mVec3_c cross = acc.cross(dir);
f32 f = acc.dot(dir);
if (!cM3d_IsZero(cross.squaredLength())) {
cross.normalize();
f32 acos = std::acosf(f);
MTXRotAxisRad(field_0x1098, cross, acos);
// TODO - bad part end
} else {
MTXIdentity(field_0x1098);
}
} else {
MTXIdentity(field_0x1098);
}
}
} else {
field_0x10D0 = 0;
}
}
void ex_c::acc_c::fn_800578E0(s32 chan) {
const s32 readLen = mPad::getCore(chan)->getReadLength();
// Shift old values back
for (int i = readLen; i < 120; i++) {
field_0x5A0[i] = field_0x5A0[i - readLen];
}
// TODO - loop strength reduction too strong
f32 max = -8.0f;
bool b = false;
for (int i = 0; i < readLen; i++) {
if (max < mAccVecs[i].y) {
max = mAccVecs[i].y;
b = true;
}
MTXMultVec(field_0x1098, mAccVecs[i], field_0x5A0[i]);
field_0x5A0[i].y += 1.0f;
}
if (b) {
field_0x10D4 = max;
}
}
void ex_c::acc_c::fn_80057AC0(s32 chan, bool b) {
const s32 readLen = mPad::getCore(chan)->getReadLength();
// Shift field_0xD20 back by one
for (int i = 38; i > 0; i--) {
field_0xD20[i] = field_0xD20[i - 1];
}
for (int i = 0; i < readLen; i++) {
field_0x1080.x += mAccVecs[i].x;
field_0x1080.y += mAccVecs[i].y;
field_0x1080.z += mAccVecs[i].z;
}
if (b) {
field_0x1080 *= 0.96f;
} else {
field_0x1080 *= 0.98f;
}
// TODO - problematic part start
field_0xD20[0] = field_0x1080;
for (int i = 3; i < 36;) {
int k = i++ - 3;
f32 x = 0.0f;
f32 y = 0.0f;
f32 z = 0.0f;
for (int j = 0; j < 7; j++) {
x += field_0xD20[k + j].x / 7.0f;
y += field_0xD20[k + j].y / 7.0f;
z += field_0xD20[k + j].z / 7.0f;
}
field_0xEF4[k].set(x, y, z);
}
// TODO - problematic part end
}
f32 ex_c::acc_c::fn_80057F00(s32 chan) {
s32 offs = chan + 3;
return field_0xD20[offs].x - field_0xEF4[chan].x;
}
f32 ex_c::acc_c::fn_80057F30(s32 chan) {
s32 offs = chan + 3;
return field_0xD20[offs].y - field_0xEF4[chan].y;
}
f32 ex_c::acc_c::fn_80057F60(s32 chan) {
s32 offs = chan + 3;
return field_0xD20[offs].z - field_0xEF4[chan].z;
}
bool ex_c::acc_c::fn_80057F90(s32 idx, bool b) {
if ((b && ((fn_80057F00(idx) < -13.5f) || fn_80057F00(idx + 1) < -13.5f) &&
std::fabsf(fn_80057F00(idx + 1) - fn_80057F00(idx)) > 3.75f) ||
(!b && ((fn_80057F00(idx) < -5.0f) || fn_80057F00(idx + 1) < -5.0f) &&
std::fabsf(fn_80057F00(idx + 1) - fn_80057F00(idx)) > 2.75f)) {
return true;
}
return false;
}
bool ex_c::acc_c::fn_800580C0(s32 idx, bool b) {
if ((b && ((fn_80057F00(idx) > 13.5f) || fn_80057F00(idx + 1) > 13.5f) &&
std::fabsf(fn_80057F00(idx + 1) - fn_80057F00(idx)) > 3.75f) ||
(!b && ((fn_80057F00(idx) > 5.0f) || fn_80057F00(idx + 1) > 5.0f) &&
std::fabsf(fn_80057F00(idx + 1) - fn_80057F00(idx)) > 2.75f)) {
return true;
}
return false;
}
bool ex_c::acc_c::fn_800581F0(s32 idx, bool b) {
if ((b && ((fn_80057F30(idx) < -13.5f) || fn_80057F30(idx + 1) < -13.5f) &&
std::fabsf(fn_80057F30(idx + 1) - fn_80057F30(idx)) > 3.75f) ||
(!b && ((fn_80057F30(idx) < -5.0f) || fn_80057F30(idx + 1) < -5.0f) &&
std::fabsf(fn_80057F30(idx + 1) - fn_80057F30(idx)) > 2.75f)) {
return true;
}
return false;
}
bool ex_c::acc_c::fn_80058320(s32 idx, bool b) {
if ((b && ((fn_80057F30(idx) > 13.5f) || fn_80057F30(idx + 1) > 13.5f) &&
std::fabsf(fn_80057F30(idx + 1) - fn_80057F30(idx)) > 3.75f) ||
(!b && ((fn_80057F30(idx) > 5.0f) || fn_80057F30(idx + 1) > 5.0f) &&
std::fabsf(fn_80057F30(idx + 1) - fn_80057F30(idx)) > 2.75f)) {
return true;
}
return false;
}
bool ex_c::acc_c::fn_80058450(s32 idx, bool b) {
// Note - same behavior, whether b is set or not
if ((b && (fn_80057F60(idx) > 2.0f) && (fn_80057F60(idx + 1) - fn_80057F60(idx)) < -2.0f) ||
(!b && (fn_80057F60(idx) > 2.0f) && (fn_80057F60(idx + 1) - fn_80057F60(idx)) < -2.0f)) {
return true;
}
return false;
}
void ex_c::acc_c::fn_80058540(s32 chan, bool b) {
bool b1 = false;
bool b2 = false;
bool b3 = false;
bool b4 = false;
// TODO condition
if (b && (mPad::isMpls(chan) || mPad::isMplsPtFS(chan))) {
if (m_ex[chan].mMPLSVelocity.x > 2.0f) {
b4 = true;
} else if (m_ex[chan].mMPLSVelocity.x < -2.0f) {
b3 = true;
} else if (m_ex[chan].mMPLSVelocity.y > 2.0f) {
b1 = true;
} else if (m_ex[chan].mMPLSVelocity.y < -2.0f) {
b2 = true;
}
} else {
int i1 = 0;
int i2 = 0;
int i3 = 0;
field_0x10D8++;
if (field_0x10D8 > 31) {
field_0x10D8 = 31;
}
bool b1_ = false;
bool b2_ = false;
bool b3_ = false;
bool b4_ = false;
int start = field_0x10D8;
for (int i = field_0x10D8; i >= 0; i--) {
if (fn_80057F90(i, b)) {
b1_ = true;
b2_ = false;
}
if (fn_800580C0(i, b)) {
b2_ = true;
b1_ = false;
}
if (fn_80057F90(i, b) || fn_800580C0(i, b)) {
i1 = 2;
} else {
i1--;
if (i1 < 0) {
i1 = 0;
b1_ = false;
b2_ = false;
}
}
if (fn_800581F0(i, b)) {
b3_ = true;
b4_ = false;
}
if (fn_80058320(i, b)) {
b4_ = true;
b3_ = false;
}
if (fn_800581F0(i, b) || fn_80058320(i, b)) {
i2 = 2;
} else {
i2--;
if (i2 < 0) {
i2 = 0;
b3_ = false;
b4_ = false;
}
}
if (fn_80058450(i, b)) {
i3 = 2;
} else {
i3--;
if (i3 < 0) {
i3 = 0;
}
}
}
if (start != 0 && i3 > 0) {
if (b1_) {
field_0x10D8 = 0;
b1 = true;
}
if (b2_) {
field_0x10D8 = 0;
b2 = true;
}
if (b3_) {
field_0x10D8 = 0;
b3 = true;
}
if (b4_) {
field_0x10D8 = 0;
b4 = true;
}
}
}
fn_80058990(0x1, b1);
fn_80058990(0x2, b2);
fn_80058990(0x4, b3);
fn_80058990(0x8, b4);
fn_80058990(0x10, b1 || b2 || b3 || b4);
bool b6;
if (b) {
b6 = getMaxAccValue(chan) > (field_0x10CC ? 2.0f : 3.0f);
} else {
b6 = getMaxAccValue(chan) > (field_0x10CC ? 1.5f : 2.0f);
}
fn_80058990(0x20, b6);
}
void ex_c::acc_c::fn_80058990(u32 mask, bool b) {
if (b) {
if ((field_0x10CC & mask) != 0) {
field_0x10C8 &= ~mask;
} else {
field_0x10C8 |= mask;
}
field_0x10CC |= mask;
} else {
field_0x10CC &= ~mask;
field_0x10C8 &= ~mask;
}
}
bool ex_c::acc_c::fn_800589F0() {
return true;
}
f32 ex_c::acc_c::fn_80058A00() {
cM3dGAab aab;
aab.ClearForMinMax();
for (int i = 0; i < 120; i++) {
aab.SetMinMax(mAccVecs[i]);
}
f32 lenSq = nw4r::math::VEC3LenSq(aab.GetMax() - aab.GetMin()) - 0.017f;
if (lenSq < 0.0f) {
lenSq = 0.0f;
}
return lenSq;
}
void ex_c::acc_c::fn_80058AE0(s32 chan, bool b) {
fn_800576D0(chan);
fn_800578E0(chan);
fn_80057AC0(chan, b);
fn_80058540(chan, b);
}
mMtx_c ex_c::mpls_c::getMtx() const {
mMtx_c m;
m.setBase(0, mX);
m.setBase(1, mY);
m.setBase(2, mZ);
m.setBase(3, mVec3_c::Zero);
return m;
}
bool ex_c::isMissingMpls() {
if (m_current_ex->mConnectedStableTimer != 0) {
return false;
}
if (m_current_ex->mOutOfHbmStableTimer != 0) {
return false;
}
return !isDeviceTypeMpls(m_current_ex->mWPADDeviceTypeStable);
}
bool ex_c::isMissingNunchuk() {
if (m_current_ex->mConnectedStableTimer != 0) {
return false;
}
if (m_current_ex->mOutOfHbmStableTimer != 0) {
return false;
}
if (m_current_ex->mState != EX_STATE_MPLS_CONFIGURED) {
return false;
}
if (m_current_ex->mWPADDeviceTypeStable == WPAD_DEV_FREESTYLE) {
return false;
}
if (m_current_ex->mWPADDeviceTypeStable == WPAD_DEV_MPLS_PT_FS) {
return false;
}
return true;
}
void ex_c::fn_80058C90(s32 chan) {
m_ex[chan].field_0x46 = true;
m_ex[chan].field_0x3C = 1;
}
bool ex_c::isLowBattery() {
return getBatteryLevel() == 1;
}
bool ex_c::isOutOfBattery() {
return getBatteryLevel() == 0;
}
void ex_c::resetInfo() {
for (int i = 0; i < 4; ++i) {
clearInfo(i);
}
}
void ex_c::clearInfo(s32 chan) {
m_connected[chan] = false;
m_info[0][chan].dpd = FALSE;
m_info[0][chan].speaker = FALSE;
m_info[0][chan].attach = FALSE;
m_info[0][chan].lowBat = FALSE;
m_info[0][chan].nearempty = FALSE;
m_info[0][chan].battery = 0;
m_info[0][chan].led = 0;
m_info[0][chan].protocol = 0;
m_info[0][chan].firmware = 0;
}
extern "C" void async_info_callback(WPADChannel chan, WPADResult result) {
switch (result) {
case WPAD_ERR_OK: {
ex_c::setInfo(chan, &ex_c::m_info[0][chan]);
break;
}
case WPAD_ERR_NO_CONTROLLER: {
ex_c::clearInfo(chan);
break;
}
case WPAD_ERR_BUSY: {
ex_c::m_ex[chan].field_0x46 = true;
ex_c::m_ex[chan].field_0x3C = 120;
break;
}
case WPAD_ERR_TRANSFER: {
ex_c::m_ex[chan].field_0x46 = true;
ex_c::m_ex[chan].field_0x3C = 120;
break;
}
}
}
s32 ex_c::getInfo(s32 chan) {
WPADResult res = WPADGetInfoAsync(chan, &ex_c::m_info[0][chan], async_info_callback);
if (res == WPAD_ERR_NO_CONTROLLER) {
clearInfo(chan);
}
return res;
}
s32 ex_c::getBatteryLevel() {
return getBatteryLevel(mPad::g_currentCoreId);
}
s32 ex_c::getBatteryLevel(s32 chan) {
if (m_connected[chan]) {
return m_info[0][chan].battery;
}
return -1;
}
void ex_c::setInfo(s32 chan, const WPADInfo *pInfo) {
m_info[0][chan] = *pInfo;
m_connected[chan] = true;
}
f32 ex_c::fn_80058F50() {
return m_current_ex->mMotion.fn_80058A00();
}
bool ex_c::startCurrentMplsCalibration() {
if (m_current_ex->mIsWPADDeviceTypeMplsStableTimer < 8) {
return true;
}
if (!m_current_ex->mMotion.fn_800589F0()) {
return true;
}
m_current_ex->mNeedMplsCalibration = false;
m_current_ex->startMplsCalibration(mPad::getCurrentCoreID());
m_current_ex->fn_80058C90(mPad::getCurrentCoreID());
initMpls(mPad::getCurrentCoreID());
return false;
}
f32 ex_c::getCurrentCalibrationWork() {
return m_current_ex->getCalibrationWork();
}
void ex_c::stopCurrentMplsCalibration() {
m_current_ex->stopMplsCalibration(mPad::getCurrentCoreID());
}
void ex_c::centerCurrentCursor() {
m_current_ex->centerCursor(mPad::getCurrentCoreID());
}
bool ex_c::needMplsCalibration() {
if (!mPad::getCore()->isConnected()) {
return false;
}
if (isMissingMpls()) {
return false;
}
if (m_current_ex->mOutOfHbmStableTimer != 0) {
return false;
}
if (isMissingNunchuk()) {
return false;
}
if (m_current_ex->mIsWPADDeviceTypeMplsStableTimer >= 8) {
return m_current_ex->mNeedMplsCalibration;
}
return false;
}
void ex_c::setCalibrateMpls() {
m_current_ex->mNeedMplsCalibration = true;
}
bool ex_c::fn_800590B0() {
bool ret = false;
switch (m_current_ex->mState) {
case EX_STATE_POST_CONNECT:
case EX_STATE_ENABLE_MPLS:
case EX_STATE_DISCONECT_WPAD:
case EX_STATE_MPLS_CONFIG_ERROR:
// TODO - one uneliminated dead branch in here
ret = m_current_ex->mState == EX_STATE_MPLS_CONFIG_ERROR || m_current_ex->mState == EX_STATE_ENABLE_MPLS ||
m_current_ex->mState == EX_STATE_POST_CONNECT;
}
return ret;
}
bool ex_c::fn_800590E0() {
return m_current_ex->field_0x4F;
}
void ex_c::fn_800590F0() {
m_current_ex->field_0x4F = false;
}
bool ex_c::fn_80059100() {
return fn_80059110(mPad::g_currentCoreId);
}
bool ex_c::fn_80059110(s32 chan) {
return nw4r::math::VEC3LenSq(m_ex[chan].mMPLSVelocity) >= 0.01f || m_ex[chan].mFSStickDistance >= 0.0001f ||
mPad::g_core[chan]->getCoreStatus()->getHold() || mPad::g_core[chan]->getCoreStatus()->getTrigger() ||
m_ex[chan].mMotion.field_0x10C8 != 0;
}
void ex_c::fn_80059210() {
m_current_ex->field_0x22CE = 1;
}
void ex_c::fn_80059220() {
m_current_ex->field_0x22CF = 1;
}
void ex_c::fn_80059230() {
m_current_ex->field_0x22D0 = 1;
}
void ex_c::fn_80059240() {
m_current_ex->field_0x22D0 = 0;
}
void ex_c::on_0x54(s32 idx) {
m_ex[idx].field_0x54 = true;
}
void ex_c::on_0x55(s32 idx) {
m_ex[idx].field_0x55 = true;
}
void ex_c::on_0x56(s32 idx) {
m_ex[idx].field_0x56 = true;
}
void ex_c::on_0x57(s32 idx) {
m_ex[idx].field_0x57 = true;
}
void ex_c::fn_800592D0(s32 chan) {
m_ex[chan].field_0x54 = false;
m_ex[chan].field_0x55 = false;
m_ex[chan].field_0x56 = false;
m_ex[chan].field_0x57 = false;
}
void ex_c::fn_80059300(s32 chan) {
field_0x58 = field_0x54;
field_0x59 = field_0x55;
field_0x5A = field_0x56;
field_0x5B = field_0x57;
fn_800592D0(chan);
}
bool ex_c::fn_80059330(s32 chan) {
return m_ex[chan].field_0x58;
}
bool ex_c::fn_80059350(s32 chan) {
return m_ex[chan].field_0x59;
}
bool ex_c::fn_80059370(s32 chan) {
return m_ex[chan].field_0x5A;
}
bool ex_c::fn_80059390(s32 chan) {
return m_ex[chan].field_0x5B;
}
void ex_c::getUnifiedWpadStatus(s32 chan) {
KPADGetUnifiedWpadStatus(chan, &mStatus, 1);
}
void ex_c::calcFSStickDirMask() {
mFSStickMaskChanged = false;
if (mFSStickDistance < 0.8f) {
mFSStickMask = 0;
return;
}
u32 prevFSStickMask = mFSStickMask;
s32 ang = mFSStickAngle;
ang = ((ang + 0x11000) / 0x2000) % 8;
mFSStickMask = 1 << ang;
if (mFSStickMask != 0 && mFSStickMask != prevFSStickMask) {
mFSStickMaskChanged = true;
}
}
void ex_c::setNoSleep() {
WPADSetAutoSleepTime(0);
}
void ex_c::setAutoSleepTime() {
WPADSetAutoSleepTime(5);
WPADResetAutoSleepTimeCount(0);
}
} // namespace dPad