1#include "Enemy/EnemyCap.h"
2
3#include <math/seadMatrix.h>
4
5#include "Library/Base/StringUtil.h"
6#include "Library/LiveActor/ActorActionFunction.h"
7#include "Library/LiveActor/ActorClippingFunction.h"
8#include "Library/LiveActor/ActorFlagFunction.h"
9#include "Library/LiveActor/ActorInitFunction.h"
10#include "Library/LiveActor/ActorInitUtil.h"
11#include "Library/LiveActor/ActorModelFunction.h"
12#include "Library/LiveActor/ActorMovementFunction.h"
13#include "Library/LiveActor/ActorPoseUtil.h"
14#include "Library/LiveActor/ActorResourceFunction.h"
15#include "Library/LiveActor/LiveActorFunction.h"
16#include "Library/Math/MathUtil.h"
17#include "Library/Matrix/MatrixUtil.h"
18#include "Library/Movement/EnemyStateBlowDown.h"
19#include "Library/Nerve/NerveSetupUtil.h"
20#include "Library/Nerve/NerveUtil.h"
21#include "Library/Obj/PartsFunction.h"
22#include "Library/Placement/PlacementFunction.h"
23#include "Library/Yaml/ByamlUtil.h"
24
25namespace {
26NERVE_IMPL(EnemyCap, Wait);
27NERVE_IMPL(EnemyCap, BlowDown);
28
29NERVES_MAKE_STRUCT(EnemyCap, Wait, BlowDown);
30} // namespace
31
32EnemyCap* EnemyCap::createEnemyCap(const char* name) {
33 return new EnemyCap(name);
34}
35
36EnemyCap::EnemyCap(const char* name) : al::LiveActor(name) {}
37
38const al::EnemyStateBlowDownParam sEnemyCapBlowDownParam =
39 al::EnemyStateBlowDownParam(nullptr, 45.0f, 54.0f, 2.6f, 0.94f, 60, 1);
40
41void EnemyCap::initPartsFixFile(al::LiveActor* cap, const al::ActorInitInfo& info,
42 const char* archiveName, const char* suffix) {
43 mCap = cap;
44 mCapBaseMtx = mCap->getBaseMtx();
45 al::initChildActorWithArchiveNameNoPlacementInfo(actor: this, initInfo: info, archiveName, suffix: 0);
46 al::initNerve(actor: this, nerve: &NrvEnemyCap.Wait, maxStates: 1);
47 mStateBlowDown = new al::EnemyStateBlowDown(this, &sEnemyCapBlowDownParam, "吹き飛び状態");
48 al::initNerveState(user: this, state: mStateBlowDown, nerve: &NrvEnemyCap.BlowDown, hostName: "吹き飛び");
49
50 al::StringTmp<128> fileName;
51 al::createFileNameBySuffix(out: &fileName, name: "InitPartsFixInfo", suffix);
52 if (al::isExistModelResourceYaml(mCap, fileName.cstr(), 0)) {
53 al::ByamlIter resourceYaml(al::getModelResourceYaml(mCap, fileName.cstr(), 0));
54 const char* jointName = nullptr;
55 resourceYaml.tryGetStringByKey(string: &jointName, key: "JointName");
56 if (jointName)
57 mCapBaseMtx = al::getJointMtxPtr(actor: mCap, jointName);
58 al::tryGetByamlV3f(&mLocalTrans, resourceYaml, "LocalTrans");
59 al::tryGetByamlV3f(&mLocalRotate, resourceYaml, "LocalRotate");
60 al::tryGetByamlV3f(&mLocalScale, resourceYaml, "LocalScale");
61 if (!al::isNearZero(vec: mLocalTrans) || !al::isNearZero(vec: mLocalRotate))
62 mIsNotAtOrigin = true;
63 mIsUseFollowMtxScale = al::tryGetByamlKeyBoolOrFalse(resourceYaml, "UseFollowMtxScale");
64 mIsUseLocalScale = al::tryGetByamlKeyBoolOrFalse(resourceYaml, "UseLocalScale");
65 }
66 makeActorAlive();
67}
68
69void EnemyCap::makeActorAlive() {
70 al::invalidateClipping(actor: this);
71 al::offCollide(actor: this);
72 al::setVelocityZero(this);
73 updatePose();
74 al::LiveActor::makeActorAlive();
75 mIsCapVisible = false;
76 al::setNerve(user: this, nerve: &NrvEnemyCap.Wait);
77}
78
79void EnemyCap::updatePose() {
80 if (!mIsNotAtOrigin) {
81 sead::Matrix34f baseMtx = *mCapBaseMtx;
82 if (mIsUseFollowMtxScale) {
83 sead::Vector3f mtxScale;
84 al::calcMtxScale(outMtx: &mtxScale, mtx: baseMtx);
85 const sead::Vector3f& scale = sead::Vector3f::ones;
86 mtxScale.x *= scale.x;
87 mtxScale.y *= scale.y;
88 mtxScale.z *= scale.z;
89 al::setScale(actor: this, scale: mtxScale);
90 }
91 al::normalize(mtx: &baseMtx);
92 al::updatePoseMtx(actor: this, mtx: &baseMtx);
93 return;
94 }
95
96 sead::Matrix34f rotationMatrix;
97 sead::Vector3f rotate(sead::Mathf::deg2rad(deg: mLocalRotate.x),
98 sead::Mathf::deg2rad(deg: mLocalRotate.y),
99 sead::Mathf::deg2rad(deg: mLocalRotate.z));
100 rotationMatrix.makeR(r: rotate);
101
102 sead::Matrix34f translationMatrix;
103 translationMatrix.makeRT(r: {0.0f, 0.0f, 0.0f}, t: mLocalTrans);
104
105 sead::Matrix34f poseMatrix = translationMatrix * rotationMatrix;
106
107 sead::Matrix34f baseMtx = *mCapBaseMtx;
108
109 if (mIsUseFollowMtxScale) {
110 sead::Matrix34f rotBaseMtx = baseMtx * rotationMatrix;
111
112 sead::Vector3f mtxScale = {0.0f, 0.0f, 0.0f};
113 al::calcMtxScale(outMtx: &mtxScale, mtx: rotBaseMtx);
114
115 poseMatrix.m[0][3] *= mtxScale.x;
116 poseMatrix.m[1][3] *= mtxScale.y;
117 poseMatrix.m[2][3] *= mtxScale.z;
118
119 if (mIsUseLocalScale) {
120 mtxScale.x *= mLocalScale.x;
121 mtxScale.y *= mLocalScale.y;
122 mtxScale.z *= mLocalScale.z;
123 }
124
125 al::setScale(actor: this, scale: mtxScale);
126 } else if (mIsUseLocalScale) {
127 al::setScale(actor: this, scale: mLocalScale);
128 }
129
130 al::normalize(mtx: &baseMtx);
131 baseMtx = baseMtx * poseMatrix;
132 al::updatePoseMtx(actor: this, mtx: &baseMtx);
133}
134
135void EnemyCap::calcAnim() {
136 if (al::isNerve(user: this, nerve: &NrvEnemyCap.Wait))
137 updatePose();
138 al::LiveActor::calcAnim();
139}
140
141void EnemyCap::exeWait() {
142 if (!syncHostVisible())
143 return;
144 al::setModelAlphaMask(actor: this, al::getModelAlphaMask(actor: mCap));
145}
146
147bool EnemyCap::syncHostVisible() {
148 return al::updateSyncHostVisible(&mIsCapVisible, this, mCap, field_142);
149}
150
151void EnemyCap::exeBlowDown() {
152 if (al::isFirstStep(user: this)) {
153 al::onCollide(actor: this);
154 al::offSyncClippingSubActor(actor: mCap, subActor: this);
155 al::offSyncAlphaMaskSubActor(actor: mCap, subActor: this);
156 }
157 al::rotateQuatXDirDegree(actor: this, deg: -15.0f);
158 if (al::updateNerveState(user: this)) {
159 al::offCollide(actor: this);
160 al::startHitReaction(actor: this, name: "消滅");
161 al::onSyncClippingSubActor(actor: mCap, subActor: this);
162 al::onSyncAlphaMaskSubActor(actor: mCap, subActor: this);
163 kill();
164 }
165}
166
167void EnemyCap::startBlowDown(const al::HitSensor* source) {
168 if (isBlowDown())
169 return;
170 mStateBlowDown->start(source);
171 al::setNerve(user: this, nerve: &NrvEnemyCap.BlowDown);
172}
173
174void EnemyCap::startBlowDown() {
175 if (isBlowDown())
176 return;
177 mStateBlowDown->start(mCap);
178 al::setNerve(user: this, nerve: &NrvEnemyCap.BlowDown);
179}
180
181bool EnemyCap::isBlowDown() const {
182 return al::isNerve(user: this, nerve: &NrvEnemyCap.BlowDown);
183}
184
185void EnemyCap::setBlowDownParam(const al::EnemyStateBlowDownParam* param) {
186 mStateBlowDown->setParam(param);
187}
188
189namespace rs {
190EnemyCap* tryCreateEnemyCap(al::LiveActor* actor, const al::ActorInitInfo& info) {
191 const char* str = nullptr;
192 al::tryGetStringArg(arg: &str, initInfo: info, key: "CapName");
193 return tryCreateEnemyCap(actor, info, str);
194}
195
196EnemyCap* tryCreateEnemyCap(al::LiveActor* actor, const al::ActorInitInfo& info,
197 const char* archiveName) {
198 return tryCreateEnemyCapSuffix(actor, info, archiveName, archiveName);
199}
200
201EnemyCap* tryCreateEnemyCapSuffix(al::LiveActor* actor, const al::ActorInitInfo& info,
202 const char* archiveName, const char* suffix) {
203 if (!archiveName)
204 return nullptr;
205 EnemyCap* cap = new EnemyCap("帽子");
206 if (!al::isExistSubActorKeeper(actor))
207 al::initSubActorKeeperNoFile(actor, info, 1);
208 cap->initPartsFixFile(cap: actor, info, archiveName, suffix);
209 al::registerSubActor(actor, cap);
210 al::onSyncClippingSubActor(actor, subActor: cap);
211 al::onSyncAlphaMaskSubActor(actor, subActor: cap);
212 return cap;
213}
214
215bool tryStartEnemyCapBlowDown(EnemyCap* cap, const al::HitSensor* sensor) {
216 if (!isOnEnemyCap(cap))
217 return false;
218 cap->startBlowDown(source: sensor);
219 return true;
220}
221
222bool tryStartEnemyCapBlowDown(EnemyCap* cap) {
223 if (!isOnEnemyCap(cap))
224 return false;
225 cap->startBlowDown();
226 return true;
227}
228
229bool tryAppearEnemyCap(EnemyCap* cap) {
230 if (!cap)
231 return false;
232 cap->appear();
233 return true;
234}
235
236bool isOnEnemyCap(EnemyCap* cap) {
237 return cap && !cap->isBlowDown();
238}
239
240} // namespace rs
241