1#include "Item/CoinChameleon.h"
2
3#include "Library/Collision/PartsConnector.h"
4#include "Library/LiveActor/ActorClippingFunction.h"
5#include "Library/LiveActor/ActorInitUtil.h"
6#include "Library/LiveActor/ActorModelFunction.h"
7#include "Library/LiveActor/ActorMovementFunction.h"
8#include "Library/LiveActor/ActorPoseUtil.h"
9#include "Library/LiveActor/ActorSensorUtil.h"
10#include "Library/Nerve/NerveSetupUtil.h"
11#include "Library/Nerve/NerveUtil.h"
12#include "Library/Placement/PlacementFunction.h"
13
14#include "Item/Coin.h"
15#include "Item/CoinRotateCalculator.h"
16#include "Item/CoinStateAppearRotate.h"
17#include "Util/PlayerUtil.h"
18#include "Util/SensorMsgFunction.h"
19
20namespace {
21NERVE_IMPL(CoinChameleon, Wait);
22NERVE_IMPL(CoinChameleon, Visible);
23NERVE_IMPL(CoinChameleon, Appear);
24
25NERVES_MAKE_STRUCT(CoinChameleon, Wait, Appear, Visible);
26} // namespace
27
28CoinChameleon::CoinChameleon(const char* name) : al::LiveActor(name) {}
29
30void CoinChameleon::init(const al::ActorInitInfo& initInfo) {
31 al::initActor(actor: this, initInfo);
32 al::initNerve(actor: this, nerve: &NrvCoinChameleon.Wait, maxStates: 1);
33
34 Coin* coin = new Coin("コイン", false);
35 al::initCreateActorWithPlacementInfo(actor: coin, initInfo);
36 mCoin = coin;
37 mCoin->makeActorDead();
38
39 mQuat.set(al::getQuat(actor: this));
40 mRotateCalculator = new CoinRotateCalculator(this);
41 al::setModelMaterialParameterF32(actor: this, "CoinW6Mat00", "const_single0", 0.0f);
42 al::hideModel(actor: this);
43 al::setMaterialProgrammable(this);
44
45 mMtxConnector = al::tryCreateMtxConnector(actor: this, info: initInfo);
46 if (mMtxConnector != nullptr)
47 mCoin->setMtxConnector(mMtxConnector);
48
49 al::tryAddDisplayOffset(actor: this, initInfo);
50 al::tryGetDisplayOffset(offset: &mDisplayOffset, initInfo);
51
52 mStateAppearRotate = new CoinStateAppearRotate(this, mMtxConnector, mDisplayOffset, "出現");
53 al::initNerveState(user: this, state: mStateAppearRotate, nerve: &NrvCoinChameleon.Appear, hostName: "出現");
54
55 if (al::isPlaced(initInfo)) {
56 f32 shadowLength = 1500.0f;
57 al::tryGetArg(arg: &shadowLength, initInfo, key: "ShadowLength");
58 mCoin->setShadowDropLength(shadowLength);
59 }
60 makeActorAlive();
61}
62
63void CoinChameleon::initAfterPlacement() {
64 if (mMtxConnector != nullptr)
65 al::attachMtxConnectorToCollision(mtxConnector: mMtxConnector, actor: this, false);
66}
67
68void CoinChameleon::endClipped() {
69 mRotateCalculator->reset();
70 al::LiveActor::endClipped();
71}
72
73bool CoinChameleon::receiveMsg(const al::SensorMsg* message, al::HitSensor* other,
74 al::HitSensor* self) {
75 if (rs::isMsgPlayerDisregardTargetMarker(message))
76 return true;
77 if (al::isNerve(user: this, nerve: &NrvCoinChameleon.Wait) || al::isNerve(user: this, nerve: &NrvCoinChameleon.Visible)) {
78 if (rs::isMsgItemGetAll(message) && al::isSensorName(self, "Body")) {
79 al::invalidateClipping(actor: this);
80 al::setNerve(user: this, nerve: &NrvCoinChameleon.Appear);
81 return true;
82 }
83 if (rs::isVisibleChameleon(message) && al::isSensorName(self, "Hipdrop")) {
84 al::invalidateClipping(actor: this);
85 al::setNerve(user: this, nerve: &NrvCoinChameleon.Visible);
86 return true;
87 }
88 }
89 return false;
90}
91
92void CoinChameleon::rotate() {
93 if (mMtxConnector == nullptr)
94 al::setQuat(actor: this, quat: mQuat);
95
96 bool checkWater = false;
97 if (al::isNerve(user: this, nerve: &NrvCoinChameleon.Appear) || mMtxConnector != nullptr)
98 checkWater = true;
99
100 mRotateCalculator->update(force: sead::Vector3f::zero, checkWater);
101 al::rotateQuatYDirDegree(actor: this, deg: mRotateCalculator->getRotate());
102}
103
104void CoinChameleon::exeWait() {
105 if (al::isFirstStep(user: this)) {
106 al::validateClipping(actor: this);
107 mWaitTime = 0;
108 }
109 if (mMtxConnector != nullptr) {
110 al::connectPoseQT(actor: this, mtxConnector: mMtxConnector);
111 *al::getTransPtr(actor: this) += mDisplayOffset;
112 }
113
114 if (!rs::isPlayerEnableToSeeOddSpace(this)) {
115 mWaitTime = sead::Mathi::clampMin(val: mWaitTime - 1, min_: 0);
116 al::setModelMaterialParameterF32(actor: this, "CoinW6Mat00", "const_single0", mWaitTime / 15.0f);
117 if (mWaitTime == 0)
118 al::hideModelIfShow(actor: this);
119 } else {
120 al::showModelIfHide(actor: this);
121 mWaitTime = sead::Mathi::clampMax(val: 15, max_: mWaitTime + 1);
122 al::setModelMaterialParameterF32(actor: this, "CoinW6Mat00", "const_single0", mWaitTime / 15.0f);
123 }
124
125 rotate();
126}
127
128void CoinChameleon::exeVisible() {
129 if (al::isFirstStep(user: this)) {
130 mWaitTime = 0;
131 al::showModelIfHide(actor: this);
132 }
133
134 if (mMtxConnector != nullptr) {
135 al::connectPoseQT(actor: this, mtxConnector: mMtxConnector);
136 *al::getTransPtr(actor: this) += mDisplayOffset;
137 }
138
139 al::setModelMaterialParameterF32(actor: this, "CoinW6Mat00", "const_single0",
140 1.0f - al::getNerveStep(user: this) / 120.0f);
141
142 if (al::isGreaterEqualStep(user: this, step: 120)) {
143 al::hideModelIfShow(actor: this);
144 al::setNerve(user: this, nerve: &NrvCoinChameleon.Wait);
145 return;
146 }
147
148 rotate();
149}
150
151void CoinChameleon::exeAppear() {
152 if (al::updateNerveState(user: this)) {
153 mCoin->appearCoinChameleon(trans: al::getTrans(actor: this), quat: al::getQuat(actor: this), position: mDisplayOffset);
154 kill();
155 return;
156 }
157
158 if (rs::isPlayerEnableToSeeOddSpace(this)) {
159 al::setModelMaterialParameterF32(actor: this, "CoinW6Mat00", "const_single0", 1.0f);
160 return;
161 }
162
163 al::setModelMaterialParameterF32(actor: this, "CoinW6Mat00", "const_single0",
164 al::getNerveStep(user: this) / 20.0f);
165}
166