mirror of
https://github.com/MonsterDruide1/OdysseyDecomp
synced 2026-05-14 11:18:12 +00:00
677 lines
23 KiB
C++
677 lines
23 KiB
C++
#include "MapObj/HackFork.h"
|
|
|
|
#include "Library/Camera/CameraTicket.h"
|
|
#include "Library/Camera/CameraUtil.h"
|
|
#include "Library/Collision/PartsConnectorUtil.h"
|
|
#include "Library/Controller/PadRumbleFunction.h"
|
|
#include "Library/Event/EventFlowUtil.h"
|
|
#include "Library/Joint/JointControllerKeeper.h"
|
|
#include "Library/Joint/JointLocalAxisRotator.h"
|
|
#include "Library/Layout/LayoutActorUtil.h"
|
|
#include "Library/LiveActor/ActorActionFunction.h"
|
|
#include "Library/LiveActor/ActorAnimFunction.h"
|
|
#include "Library/LiveActor/ActorClippingFunction.h"
|
|
#include "Library/LiveActor/ActorFlagFunction.h"
|
|
#include "Library/LiveActor/ActorInitUtil.h"
|
|
#include "Library/LiveActor/ActorModelFunction.h"
|
|
#include "Library/LiveActor/ActorPoseUtil.h"
|
|
#include "Library/LiveActor/ActorResourceFunction.h"
|
|
#include "Library/LiveActor/ActorSensorUtil.h"
|
|
#include "Library/Math/MathUtil.h"
|
|
#include "Library/Nerve/NerveSetupUtil.h"
|
|
#include "Library/Nerve/NerveUtil.h"
|
|
#include "Library/Placement/PlacementFunction.h"
|
|
#include "Library/Play/Camera/ActorMatrixCameraTarget.h"
|
|
#include "Library/Se/SeFunction.h"
|
|
#include "Library/Yaml/ByamlUtil.h"
|
|
|
|
#include "Player/CapTargetInfo.h"
|
|
#include "Player/IUsePlayerHack.h"
|
|
#include "Player/PlayerHackStartShaderCtrl.h"
|
|
#include "Scene/GuidePosInfoHolder.h"
|
|
#include "System/GameDataUtil.h"
|
|
#include "Util/Hack.h"
|
|
#include "Util/NpcAnimUtil.h"
|
|
#include "Util/NpcEventFlowUtil.h"
|
|
#include "Util/PlayerUtil.h"
|
|
#include "Util/SensorMsgFunction.h"
|
|
|
|
namespace {
|
|
NERVE_IMPL(HackFork, Wait);
|
|
NERVE_IMPL(HackFork, HackStartWait);
|
|
NERVE_IMPL(HackFork, Damping);
|
|
NERVE_IMPL(HackFork, HackStart);
|
|
NERVE_IMPL(HackFork, HackWait);
|
|
NERVE_IMPL(HackFork, HackBend);
|
|
NERVE_IMPL(HackFork, HackShoot);
|
|
|
|
// TODO: Find a memory layout that fits these globals perfectly
|
|
struct {
|
|
NERVES_MAKE_STRUCT(HackFork, Wait, HackStartWait, Damping, HackStart, HackWait, HackBend,
|
|
HackShoot);
|
|
|
|
PlayerHackStartShaderParam sPlayerHackStartShaderParam = {true, 100.0f, 10, 20};
|
|
} HackForkData;
|
|
|
|
} // namespace
|
|
|
|
HackFork::HackFork(const char* name) : al::LiveActor(name) {}
|
|
|
|
void HackFork::init(const al::ActorInitInfo& info) {
|
|
const char* modelName = nullptr;
|
|
if (alPlacementFunction::tryGetModelName(&modelName, info))
|
|
al::initActorWithArchiveName(this, info, modelName, nullptr);
|
|
else
|
|
al::initActor(this, info);
|
|
|
|
al::calcSideDir(&mSideDir, this);
|
|
al::initJointControllerKeeper(this, 10);
|
|
mJointRotationHolder.allocBuffer(5, nullptr);
|
|
|
|
const char* jointNames[5] = {"Stick01", "Stick02", "Stick03", "Stick04", "Stick05"};
|
|
for (s32 i = 0; i < 5; i++) {
|
|
mJointRotationHolder.pushBack(
|
|
al::initJointLocalAxisRotator(this, mSideDir, &mDampingForce, jointNames[i], false));
|
|
al::initJointLocalXRotator(this, &mDampingStrength, jointNames[i]);
|
|
}
|
|
|
|
al::initNerve(this, &HackForkData.NrvHackFork.Wait, 0);
|
|
al::tryGetArg(&mIsLimitterFree, info, "LimitterFree");
|
|
bool hasCamera = false;
|
|
bool isValid = al::tryGetArg(&hasCamera, info, "Camera");
|
|
if (hasCamera && isValid)
|
|
mCameraTicket = al::initObjectCamera(this, info, nullptr, nullptr);
|
|
|
|
mMatrixCameraTarget = al::createActorMatrixCameraTarget(this, &mCameraTargetMtx);
|
|
if (!al::isEqualString(modelName, "HackBoard")) {
|
|
mCameraOffset = {0.0f, 0.0f, 100.0f};
|
|
mIsHackBoard = true;
|
|
}
|
|
|
|
bool hasBallon = false;
|
|
bool isBallonValid = al::tryGetArg(&hasBallon, info, "Balloon");
|
|
if (hasBallon && isBallonValid && !rs::isSequenceTimeBalloonOrRace(this)) {
|
|
mEventFlowExecutor = rs::initEventFlow(this, info, nullptr, nullptr);
|
|
rs::startEventFlow(mEventFlowExecutor, "Init");
|
|
}
|
|
if (al::isMtpAnimExist(this)) {
|
|
rs::setNpcMaterialAnimFromPlacementInfo(this, info);
|
|
al::tryStartMclAnimIfExist(this, al::getPlayingMtpAnimName(this));
|
|
}
|
|
mMtxConnector = al::tryCreateMtxConnector(this, info);
|
|
makeActorAlive();
|
|
mCapTargetInfo = rs::createCapTargetInfo(this, nullptr);
|
|
|
|
al::ByamlIter iter = {al::getModelResourceYaml(this, "InitHackCap", nullptr)};
|
|
mJointName = al::tryGetByamlKeyStringOrNULL(iter, "JointName");
|
|
sead::Vector3f localTrans = {0.0f, 0.0f, 0.0f};
|
|
al::tryGetByamlV3f(&localTrans, iter, "LocalTrans");
|
|
sead::Vector3f localRotate = {0.0f, 0.0f, 0.0f};
|
|
al::tryGetByamlV3f(&localRotate, iter, "LocalRotate");
|
|
|
|
sead::Matrix34f rotationMatrix;
|
|
sead::Vector3f rotateRad(sead::Mathf::deg2rad(localRotate.x),
|
|
sead::Mathf::deg2rad(localRotate.y),
|
|
sead::Mathf::deg2rad(localRotate.z));
|
|
rotationMatrix.makeR(rotateRad);
|
|
|
|
sead::Matrix34f translationMatrix;
|
|
translationMatrix.makeRT({0.0f, 0.0f, 0.0f}, localTrans * al::getScaleY(this));
|
|
|
|
mStartingPoseMtx = rotationMatrix * translationMatrix;
|
|
|
|
sead::Matrix34f jointMtx = *al::getJointMtxPtr(this, mJointName);
|
|
al::normalize(&jointMtx);
|
|
mInvJointMtx.setInverse(jointMtx);
|
|
|
|
mCapTargetInfo->setPoseMatrix(&mCapPoseMtx);
|
|
mInvInitialHackDir.setInverse(mUpsideDownInitialHackDir);
|
|
|
|
initBasicPoseInfo();
|
|
mHackStartShaderCtrl =
|
|
new PlayerHackStartShaderCtrl(this, &HackForkData.sPlayerHackStartShaderParam);
|
|
}
|
|
|
|
void HackFork::attackSensor(al::HitSensor* self, al::HitSensor* other) {
|
|
if (al::isSensorName(self, "Push") && !al::sendMsgPush(other, self) && !mIsHorizontal) {
|
|
const sead::Vector3f& velocity = al::getActorVelocity(other);
|
|
if (velocity.x * velocity.x + velocity.z * velocity.z < 4.999696f)
|
|
rs::sendMsgPushToPlayer(other, self);
|
|
}
|
|
}
|
|
|
|
bool HackFork::receiveMsg(const al::SensorMsg* message, al::HitSensor* other, al::HitSensor* self) {
|
|
if (rs::isMsgEnableMapCheckPointWarp(message))
|
|
return false;
|
|
|
|
if (rs::isMsgMotorcycleDashAttack(message))
|
|
return tryTouch(5.0f, "タッチ(強)");
|
|
if (al::isMsgPlayerObjTouch(message) || al::isMsgKickStoneAttackReflect(message) ||
|
|
rs::isMsgRadishReflect(message) || rs::isMsgSeedReflect(message)) {
|
|
return tryTouch(2.0f, "タッチ(弱)");
|
|
}
|
|
if (rs::isMsgHammerBrosHammerHackAttack(message) || al::isMsgPlayerFireBallAttack(message)) {
|
|
tryTouch(2.0f, "タッチ(弱)");
|
|
rs::requestHitReactionToAttacker(message, self, other);
|
|
return true;
|
|
}
|
|
if (rs::tryReceiveMsgInitCapTargetAndSetCapTargetInfo(message, mCapTargetInfo)) {
|
|
resetCapMtx(self);
|
|
return true;
|
|
}
|
|
if (rs::isMsgPlayerDisregardTargetMarker(message))
|
|
return mEventFlowExecutor && al::isActive(mEventFlowExecutor);
|
|
if (rs::isMsgTargetMarkerPosition(message)) {
|
|
sead::Vector3f position = al::getSensorPos(this, "Stick05") + 50.0f * sead::Vector3f::ey;
|
|
rs::setMsgTargetMarkerPosition(message, position);
|
|
return true;
|
|
}
|
|
if (isNerveHackable()) {
|
|
if (rs::isMsgCapEnableLockOn(message))
|
|
return true;
|
|
if (rs::isMsgStartHack(message)) {
|
|
al::invalidateClipping(this);
|
|
mPlayerHack = rs::startHack(self, other, nullptr);
|
|
rs::startHackStartDemo(mPlayerHack, this);
|
|
mDampingStrength = 0.0f;
|
|
mDampingForce = 0.0f;
|
|
mTouchForce = 0.0f;
|
|
resetCapMtx(self);
|
|
rs::setRouteHeadGuidePosPtr(this, &mHeadGuidePos);
|
|
al::setNerve(this, &HackForkData.NrvHackFork.HackStartWait);
|
|
al::startHitReaction(this, "ひょうい開始");
|
|
return true;
|
|
}
|
|
if (rs::isMsgCapCancelLockOn(message))
|
|
return true;
|
|
}
|
|
if (isHack()) {
|
|
if (rs::isMsgHackerDamageAndCancel(message)) {
|
|
if (al::isSensorName(self, "Body"))
|
|
return rs::requestDamage(mPlayerHack);
|
|
return false;
|
|
}
|
|
if (rs::isMsgHackSyncDamageVisibility(message)) {
|
|
rs::syncDamageVisibility(this, mPlayerHack);
|
|
return true;
|
|
}
|
|
|
|
if (rs::receiveMsgRequestTransferHack(message, mPlayerHack, other))
|
|
return true;
|
|
if (rs::isMsgCancelHack(message)) {
|
|
rs::tryEndHackStartDemo(mPlayerHack, this);
|
|
if (mIsHorizontal) {
|
|
rs::endHack(&mPlayerHack);
|
|
rs::resetRouteHeadGuidePosPtr(this);
|
|
al::tryStartAction(this, "HackEnd");
|
|
al::setNerve(this, &HackForkData.NrvHackFork.Damping);
|
|
return true;
|
|
}
|
|
|
|
if (mIsHackBoard) {
|
|
sead::Vector3f upDir;
|
|
al::calcUpDir(&upDir, this);
|
|
rs::endHackDir(&mPlayerHack, upDir);
|
|
} else {
|
|
sead::Vector3f front;
|
|
if (al::isNearZero(mPullDirection))
|
|
front.set(-mPullDirection2);
|
|
else
|
|
front.set(mPullDirection);
|
|
front.y = 0.0f;
|
|
al::tryNormalizeOrDirZ(&front);
|
|
sead::Quatf quat;
|
|
al::makeQuatUpFront(&quat, sead::Vector3f::ey, front);
|
|
rs::endHackTargetQuat(&mPlayerHack, quat, front);
|
|
}
|
|
rs::resetRouteHeadGuidePosPtr(this);
|
|
al::tryStartAction(this, "HackEnd");
|
|
al::setNerve(this, &HackForkData.NrvHackFork.Damping);
|
|
return true;
|
|
}
|
|
|
|
if (rs::isMsgHackMarioDemo(message) || rs::isMsgHackMarioDead(message)) {
|
|
rs::endHack(&mPlayerHack);
|
|
rs::resetRouteHeadGuidePosPtr(this);
|
|
al::tryStartAction(this, "HackEnd");
|
|
al::setNerve(this, &HackForkData.NrvHackFork.Damping);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void HackFork::initBasicPoseInfo() {
|
|
al::calcUpDir(&mUpDir, this);
|
|
|
|
mHackDir.set(al::getQuat(this));
|
|
|
|
sead::Vector3f frontDir;
|
|
al::calcFrontDir(&frontDir, this);
|
|
|
|
sead::Quatf rotation;
|
|
rotation.setAxisAngle(frontDir, 180.0f);
|
|
mUpsideDownInitialHackDir = rotation * mHackDir;
|
|
|
|
sead::Vector3f frontDir2;
|
|
al::calcFrontDir(&frontDir2, this);
|
|
if (sead::Mathf::abs(frontDir2.y) > 0.5f) {
|
|
al::invalidateShadow(this);
|
|
mIsHorizontal = false;
|
|
} else {
|
|
mIsHorizontal = true;
|
|
}
|
|
}
|
|
|
|
void HackFork::initAfterPlacement() {
|
|
if (mMtxConnector) {
|
|
sead::Vector3f frontDir;
|
|
al::calcFrontDir(&frontDir, this);
|
|
sead::Vector3f pos = al::getTrans(this) + frontDir * 100.0f;
|
|
frontDir *= -200.0f;
|
|
al::attachMtxConnectorToCollision(mMtxConnector, this, pos, frontDir);
|
|
}
|
|
}
|
|
|
|
bool HackFork::tryTouch(f32 force, const char* reactionName) {
|
|
if (mTouchDelay != 0) {
|
|
mTouchDelay = 30;
|
|
return false;
|
|
}
|
|
|
|
if (isNerveHackable()) {
|
|
mTouchForce = force;
|
|
mTouchDelay = 30;
|
|
al::setNerve(this, &HackForkData.NrvHackFork.Damping);
|
|
al::startHitReaction(this, reactionName);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void HackFork::resetCapMtx(al::HitSensor* sensor) {
|
|
calcHackDir(sensor);
|
|
sead::Matrix34f jointMtx = *al::getJointMtxPtr(this, mJointName);
|
|
al::normalize(&jointMtx);
|
|
|
|
sead::Matrix34f poseMtx = jointMtx * mStartingPoseMtx;
|
|
sead::Vector3f up = poseMtx.getBase(1);
|
|
|
|
sead::Vector3f normal;
|
|
if (mIsHorizontal)
|
|
normal.set({0.0f, 1.0f, 0.0f});
|
|
else
|
|
normal = -mPullDirection2;
|
|
|
|
al::verticalizeVec(&normal, up, normal);
|
|
|
|
if (!al::tryNormalizeOrZero(&normal)) {
|
|
mNextCapPoseMtx = mStartingPoseMtx;
|
|
} else {
|
|
sead::Matrix34f invPoseMtx;
|
|
invPoseMtx.setInverse(poseMtx);
|
|
|
|
normal.rotate(invPoseMtx);
|
|
|
|
sead::Quatf quatRotation;
|
|
al::makeQuatRotationRate(&quatRotation, sead::Vector3f::ez, normal, 1.0f);
|
|
sead::Matrix34f quatRotationMtx;
|
|
quatRotationMtx.fromQuat(quatRotation);
|
|
|
|
sead::Matrix34f invJointMtx;
|
|
invJointMtx.setInverse(jointMtx);
|
|
|
|
mNextCapPoseMtx = (invJointMtx * poseMtx) * quatRotationMtx;
|
|
}
|
|
updateCapMtx();
|
|
}
|
|
|
|
bool HackFork::isNerveHackable() const {
|
|
return al::isNerve(this, &HackForkData.NrvHackFork.Wait) ||
|
|
al::isNerve(this, &HackForkData.NrvHackFork.Damping);
|
|
}
|
|
|
|
bool HackFork::isHack() const {
|
|
return al::isNerve(this, &HackForkData.NrvHackFork.HackStartWait) ||
|
|
al::isNerve(this, &HackForkData.NrvHackFork.HackStart) ||
|
|
al::isNerve(this, &HackForkData.NrvHackFork.HackWait) ||
|
|
al::isNerve(this, &HackForkData.NrvHackFork.HackBend) ||
|
|
al::isNerve(this, &HackForkData.NrvHackFork.HackShoot);
|
|
}
|
|
|
|
void HackFork::controlSpring() {
|
|
f32 dampedForce = mDampingForce * 0.92f;
|
|
mTouchForce += dampedForce * -0.5f;
|
|
mDampingForce = dampedForce + mTouchForce;
|
|
}
|
|
|
|
void HackFork::checkSwing() {
|
|
if (rs::isTriggerHackSwing(mPlayerHack)) {
|
|
mIsHackSwing = true;
|
|
mTimeSinceSwingStart = 0;
|
|
return;
|
|
}
|
|
|
|
mTimeSinceSwingStart++;
|
|
}
|
|
|
|
bool HackFork::trySwingJump() {
|
|
if (rs::isTriggerHackSwing(mPlayerHack)) {
|
|
mIsHackSwing = true;
|
|
mTimeSinceSwingStart = 0;
|
|
} else {
|
|
bool isHackSwing = mIsHackSwing;
|
|
mTimeSinceSwingStart++;
|
|
if (!isHackSwing || 10 < mTimeSinceSwingStart)
|
|
return false;
|
|
}
|
|
|
|
if (mIsHorizontal) {
|
|
mPullDirection.set({0.0f, -1.0f, 0.0f});
|
|
} else {
|
|
sead::Vector3f pulldirection = mPullDirection2;
|
|
pulldirection.rotate(mHackDir * mInvInitialHackDir);
|
|
pulldirection.y = 0;
|
|
al::tryNormalizeOrDirZ(&pulldirection);
|
|
mPullDirection.set(pulldirection);
|
|
}
|
|
mIsPullDown = mPullDirection.dot(mUpDir) < 0.0f;
|
|
|
|
mDampingForce = 22.5f;
|
|
sead::Vector3f frontDir;
|
|
al::calcFrontDir(&frontDir, this);
|
|
bendAndTwist(mPullDirection, frontDir);
|
|
mIsSwingJump = true;
|
|
al::setNerve(this, &HackForkData.NrvHackFork.HackShoot);
|
|
return true;
|
|
}
|
|
|
|
bool HackFork::updateInput(sead::Vector3f* pullDirection, sead::Vector3f frontDir) {
|
|
sead::Vector3f lookdir;
|
|
al::calcCameraLookDir(&lookdir, this, 0);
|
|
|
|
if (frontDir.dot(sead::Vector3f::ey) < sead::Mathf::cos(sead::Mathf::deg2rad(45.0f)) &&
|
|
frontDir.dot(lookdir) > 0.0f)
|
|
frontDir = -frontDir;
|
|
|
|
sead::Vector3f moveDir = {0.0f, 0.0f, 0.0f};
|
|
bool isMovePossible = rs::calcHackerMoveDir(&moveDir, mPlayerHack, frontDir);
|
|
|
|
mInputBuffer.forcePushBack(moveDir);
|
|
|
|
*pullDirection = {0.0f, 0.0f, 0.0f};
|
|
for (s32 i = 0; i < mInputBuffer.size(); i++)
|
|
*pullDirection += mInputBuffer[i];
|
|
|
|
if (!al::tryNormalizeOrZero(pullDirection))
|
|
al::calcUpDir(pullDirection, this);
|
|
return isMovePossible;
|
|
}
|
|
|
|
f32 HackFork::getJumpRange() const {
|
|
return mIsLimitterFree ? 180.0f : 45.0f;
|
|
}
|
|
|
|
void HackFork::bendAndTwist(const sead::Vector3f& direction, const sead::Vector3f& front) {
|
|
mDampingForce = sead::Mathf::clampMax(mDampingForce + 1.0f, 22.5f);
|
|
mTouchForce = 0.0f;
|
|
|
|
mSideDir.setCross(front, direction);
|
|
if (!al::tryNormalizeOrZero(&mSideDir))
|
|
al::calcSideDir(&mSideDir, this);
|
|
|
|
for (s32 i = 0; i < mJointRotationHolder.size(); i++)
|
|
mJointRotationHolder[i]->setVector28(mSideDir);
|
|
}
|
|
|
|
// NON_MATCHING: Wrong loading order and registers https://decomp.me/scratch/8ReuA
|
|
void HackFork::shoot() {
|
|
sead::Vector3f frontDir;
|
|
al::calcFrontDir(&frontDir, this);
|
|
sead::Quatf quat;
|
|
al::makeQuatUpFront(&quat, frontDir, -mPullDirection);
|
|
|
|
sead::Quatf rotationQuat;
|
|
rotationQuat.makeVectorRotation(frontDir, sead::Vector3f::ey);
|
|
quat = rotationQuat * quat;
|
|
quat.normalize();
|
|
|
|
sead::Vector3f jointPos;
|
|
al::calcJointPos(&jointPos, this, "Stick05");
|
|
|
|
sead::Vector3f launchDir;
|
|
launchDir = mPullDirection;
|
|
if (launchDir.y < -sead::Mathf::cos(sead::Mathf::deg2rad(110.0f)))
|
|
launchDir += -sead::Vector3f::ey;
|
|
al::normalize(&launchDir);
|
|
|
|
f32 scale = mPullDirection.dot(-sead::Vector3f::ey);
|
|
f32 cos = sead::Mathf::cos(sead::Mathf::deg2rad(45.0f));
|
|
if (scale > cos) {
|
|
scale = sead::Mathf::clamp((scale - cos) / (1.0f - cos), 0.0f, 1.0f);
|
|
scale = (1.0f - sead::Mathf::square(1.0f - scale)) * -8.0f;
|
|
} else {
|
|
scale = -0.0f;
|
|
}
|
|
|
|
sead::Vector3f frontDir2;
|
|
al::calcFrontDir(&frontDir2, this);
|
|
frontDir2 *= scale;
|
|
f32 launchSpeed = mIsSwingJump ? 61.27f : 55.7f;
|
|
sead::Vector3f direction = frontDir2 - launchSpeed * launchDir;
|
|
|
|
rs::endHackAirVelocity(&mPlayerHack, jointPos, quat, direction, mAirVel);
|
|
rs::resetRouteHeadGuidePosPtr(this);
|
|
al::startHitReaction(this, "ジャンプ");
|
|
al::tryStartAction(this, "HackEnd");
|
|
}
|
|
|
|
void HackFork::control() {
|
|
mHackStartShaderCtrl->update();
|
|
if (mMtxConnector) {
|
|
al::connectPoseQT(this, mMtxConnector);
|
|
initBasicPoseInfo();
|
|
}
|
|
if (!isHack()) {
|
|
if (mCameraTicket && al::isActiveCamera(mCameraTicket))
|
|
al::endCamera(this, mCameraTicket, -1, false);
|
|
if (al::isActiveCameraTarget(mMatrixCameraTarget))
|
|
al::resetCameraTarget(this, mMatrixCameraTarget);
|
|
}
|
|
if (mTouchDelay != 0)
|
|
mTouchDelay--;
|
|
if (isHack()) {
|
|
if (mIsHorizontal) {
|
|
sead::Vector3f frontDir;
|
|
al::calcFrontDir(&frontDir, this);
|
|
frontDir.y = 0.0f;
|
|
al::tryNormalizeOrDirZ(&frontDir);
|
|
frontDir.negate();
|
|
sead::Vector3f sideDir;
|
|
sideDir.setCross(sead::Vector3f::ey, frontDir);
|
|
mCameraTargetMtx.setBase(0, sideDir);
|
|
mCameraTargetMtx.setBase(1, sead::Vector3f::ey);
|
|
mCameraTargetMtx.setBase(2, frontDir);
|
|
} else {
|
|
sead::Vector3f upDir;
|
|
al::calcUpDir(&upDir, this);
|
|
upDir.y = 0.0;
|
|
al::tryNormalizeOrDirZ(&upDir);
|
|
sead::Vector3f sideDir;
|
|
sideDir.setCross(sead::Vector3f::ey, upDir);
|
|
if ((al::getCameraPos(this, 0) - al::getTrans(this)).dot(upDir) >= 0.0f) {
|
|
upDir = -upDir;
|
|
sideDir = -sideDir;
|
|
}
|
|
mCameraTargetMtx.setBase(0, sideDir);
|
|
mCameraTargetMtx.setBase(1, sead::Vector3f::ey);
|
|
mCameraTargetMtx.setBase(2, upDir);
|
|
}
|
|
|
|
sead::Vector3f cameraOffset;
|
|
cameraOffset.setRotated(al::getQuat(this), mCameraOffset);
|
|
if (mIsHorizontal) {
|
|
sead::Vector3f frontDir;
|
|
al::calcFrontDir(&frontDir, this);
|
|
cameraOffset += frontDir * 100.0f;
|
|
}
|
|
mCameraTargetMtx.setBase(3, cameraOffset + al::getTrans(this));
|
|
al::calcJointPos(&mHeadGuidePos, this, "Stick05");
|
|
mHeadGuidePos.y = sead::Mathf::max(mHeadGuidePos.y, al::getTrans(this).y) + 100.0f;
|
|
}
|
|
}
|
|
|
|
void HackFork::calcAnim() {
|
|
al::LiveActor::calcAnim();
|
|
if (isHack())
|
|
updateCapMtx();
|
|
}
|
|
|
|
void HackFork::updateCapMtx() {
|
|
sead::Matrix34f mtx = *al::getJointMtxPtr(this, mJointName);
|
|
al::normalize(&mtx);
|
|
mCapPoseMtx = mtx * mNextCapPoseMtx;
|
|
}
|
|
|
|
void HackFork::calcHackDir(al::HitSensor* sensor) {
|
|
if (mIsHorizontal)
|
|
mPullDirection2.set({0.0f, -1.0f, 0.0f});
|
|
else
|
|
mPullDirection2 = rs::getPlayerPos(this) - al::getSensorPos(sensor);
|
|
|
|
sead::Vector3f frontDir;
|
|
al::calcFrontDir(&frontDir, this);
|
|
al::verticalizeVec(&mPullDirection2, frontDir, mPullDirection2);
|
|
if (!al::tryNormalizeOrZero(&mPullDirection2))
|
|
al::calcUpDir(&mPullDirection2, this);
|
|
|
|
mInvInitialHackDir.setInverse(mHackDir);
|
|
}
|
|
|
|
void HackFork::exeWait() {
|
|
if (al::isFirstStep(this)) {
|
|
al::startAction(this, "Wait");
|
|
al::showModelIfHide(this);
|
|
}
|
|
if (mEventFlowExecutor)
|
|
rs::updateEventFlow(mEventFlowExecutor);
|
|
}
|
|
|
|
void HackFork::exeHackStartWait() {
|
|
if (al::isFirstStep(this)) {
|
|
if (mCameraTicket) {
|
|
al::startCamera(this, mCameraTicket, -1);
|
|
al::requestStopCameraVerticalAbsorb(this);
|
|
}
|
|
al::setCameraTarget(this, mMatrixCameraTarget);
|
|
mIsHackSwing = false;
|
|
mTimeSinceSwingStart = 0;
|
|
mIsSwingJump = false;
|
|
mAirVel = 0;
|
|
}
|
|
|
|
checkSwing();
|
|
|
|
if (rs::isHackStartDemoEnterMario(mPlayerHack))
|
|
al::setNerve(this, &HackForkData.NrvHackFork.HackStart);
|
|
}
|
|
|
|
void HackFork::exeDamping() {
|
|
if (al::isFirstStep(this))
|
|
al::showModelIfHide(this);
|
|
|
|
if (al::isNearZero(mTouchForce) && al::isNearZero(mDampingForce)) {
|
|
if (al::isNearZero(mDampingStrength)) {
|
|
mDampingStrength = 0.0f;
|
|
mDampingForce = 0.0f;
|
|
mTouchForce = 0.0f;
|
|
al::validateClipping(this);
|
|
al::setNerve(this, &HackForkData.NrvHackFork.Wait);
|
|
return;
|
|
}
|
|
mDampingStrength *= 0.9f;
|
|
return;
|
|
}
|
|
controlSpring();
|
|
}
|
|
|
|
void HackFork::exeHackStart() {
|
|
if (al::isFirstStep(this)) {
|
|
al::startAction(this, "HackStart");
|
|
mHackStartShaderCtrl->start();
|
|
mPullDirection = {0.0f, 0.0f, 0.0f};
|
|
}
|
|
checkSwing();
|
|
if (al::isActionEnd(this)) {
|
|
rs::endHackStartDemo(mPlayerHack, this);
|
|
al::setNerve(this, &HackForkData.NrvHackFork.HackWait);
|
|
}
|
|
}
|
|
|
|
void HackFork::exeHackWait() {
|
|
controlSpring();
|
|
mInputBuffer.clear();
|
|
sead::Vector3f frontDir;
|
|
al::calcFrontDir(&frontDir, this);
|
|
sead::Vector3f pullDirection;
|
|
if (!trySwingJump() && updateInput(&pullDirection, frontDir) &&
|
|
sead::Mathf::abs(pullDirection.dot(mUpDir)) >
|
|
sead::Mathf::cos(sead::Mathf::deg2rad(getJumpRange()))) {
|
|
mPullDirection.set(pullDirection);
|
|
mIsPullDown = mPullDirection.dot(mUpDir) < 0.0f;
|
|
al::setNerve(this, &HackForkData.NrvHackFork.HackBend);
|
|
}
|
|
}
|
|
|
|
void HackFork::exeHackBend() {
|
|
if (al::isFirstStep(this))
|
|
mIsReadyToShoot = false;
|
|
|
|
if (al::isLessEqualStep(this, 15) && trySwingJump())
|
|
return;
|
|
sead::Vector3f frontDir;
|
|
al::calcFrontDir(&frontDir, this);
|
|
|
|
sead::Vector3f pullDirection;
|
|
bool isInput = updateInput(&pullDirection, frontDir);
|
|
if (!isInput || rs::isTriggerHackSwing(mPlayerHack)) {
|
|
if (mIsReadyToShoot) {
|
|
if (isInput) {
|
|
mAirVel = 60;
|
|
mIsSwingJump = true;
|
|
}
|
|
al::setNerve(this, &HackForkData.NrvHackFork.HackShoot);
|
|
} else {
|
|
al::setNerve(this, &HackForkData.NrvHackFork.HackWait);
|
|
}
|
|
}
|
|
sead::Vector3f oldPullDirection = mPullDirection;
|
|
f32 jumpDir = mIsPullDown ? -1.0f : 1.0f;
|
|
|
|
f32 cos = sead::Mathf::clamp((jumpDir * mUpDir).dot(pullDirection), -1.0f, 1.0f);
|
|
if (sead::Mathf::rad2deg(sead::Mathf::acos(cos)) < getJumpRange())
|
|
mPullDirection = mPullDirection * 0.5f + pullDirection * 0.5f;
|
|
al::normalize(&mPullDirection);
|
|
f32 oldDampingForce = mDampingForce;
|
|
bendAndTwist(mPullDirection, frontDir);
|
|
f32 rumbleVolume = (mDampingForce - oldDampingForce) * 0.5f +
|
|
(mPullDirection - oldPullDirection).length() * 3.3f;
|
|
if (!al::isNearZero(rumbleVolume)) {
|
|
al::holdSe(this, "PgBendLv");
|
|
sead::Vector3f jointPos;
|
|
al::calcJointPos(&jointPos, this, "Stick03");
|
|
al::PadRumbleParam param = al::PadRumbleParam(0.0f, 1300.0f, rumbleVolume, rumbleVolume);
|
|
alPadRumbleFunction::startPadRumbleWithParam(this, jointPos, "パルス(中)", param, -1);
|
|
}
|
|
if (mDampingForce >= 4.5f)
|
|
mIsReadyToShoot = true;
|
|
}
|
|
|
|
void HackFork::exeHackShoot() {
|
|
controlSpring();
|
|
if (mDampingForce < 0.0f) {
|
|
shoot();
|
|
al::setNerve(this, &HackForkData.NrvHackFork.Damping);
|
|
}
|
|
}
|