1#include "Layout/CounterLifeCtrl.h"
2
3#include "Library/Camera/CameraUtil.h"
4#include "Library/Draw/SubCameraRenderer.h"
5#include "Library/Layout/LayoutActionFunction.h"
6#include "Library/Layout/LayoutActorUtil.h"
7#include "Library/Math/MathUtil.h"
8#include "Library/Nerve/NerveSetupUtil.h"
9#include "Library/Nerve/NerveUtil.h"
10#include "Library/Player/PlayerUtil.h"
11#include "Library/Screen/ScreenFunction.h"
12#include "Library/Se/SeFunction.h"
13
14#include "Layout/CounterLife.h"
15#include "System/GameDataFunction.h"
16#include "System/GameDataUtil.h"
17#include "Util/PlayerUtil.h"
18
19namespace {
20NERVE_IMPL(CounterLifeCtrl, Dead);
21NERVE_IMPL(CounterLifeCtrl, CountStartFadeIn);
22NERVE_IMPL(CounterLifeCtrl, DemoLifeMaxUpStartFadeIn);
23NERVE_IMPL(CounterLifeCtrl, Appear);
24NERVE_IMPL(CounterLifeCtrl, Wait);
25NERVE_IMPL(CounterLifeCtrl, End);
26NERVE_IMPL(CounterLifeCtrl, Count);
27NERVE_IMPL(CounterLifeCtrl, CountEnd);
28NERVE_IMPL(CounterLifeCtrl, DemoLifeMaxUpAddLife);
29NERVE_IMPL(CounterLifeCtrl, DemoLifeMaxUpWaitForMove);
30NERVE_IMPL(CounterLifeCtrl, DemoLifeMaxUpMove);
31NERVE_IMPL(CounterLifeCtrl, DemoLifeMaxUpUnite);
32NERVE_IMPL(CounterLifeCtrl, CountStartFadeOut);
33
34NERVES_MAKE_NOSTRUCT(CounterLifeCtrl, Dead, CountStartFadeIn, End, DemoLifeMaxUpWaitForMove);
35NERVES_MAKE_STRUCT(CounterLifeCtrl, DemoLifeMaxUpStartFadeIn, Appear, Wait, Count, CountEnd,
36 DemoLifeMaxUpAddLife, DemoLifeMaxUpMove, DemoLifeMaxUpUnite, CountStartFadeOut);
37} // namespace
38
39CounterLifeCtrl::CounterLifeCtrl(const al::LayoutInitInfo& info,
40 const al::PlayerHolder* player_holder,
41 const al::SubCameraRenderer* sub_camera_renderer)
42 : al::NerveExecutor("ライフカウンタ更新"), mPlayerHolder(player_holder),
43 mSubCameraRenderer(sub_camera_renderer) {
44 mCounterLife = new CounterLife("[ライフ]ライフカウンタ", "CounterLife", info);
45 mCounterLife->kill();
46 mCounterLifeKids = new CounterLife("[ライフ]キッズ用ライフカウンタ", "CounterLifeKids", info);
47 mCounterLifeKids->kill();
48 mCounterLifeUp = new CounterLife("[ライフ]最大ライフカウンタ", "CounterLifeUp", info);
49 mCounterLifeUp->kill();
50 initNerve(nerve: &Dead, stateCount: 0);
51 setCount(GameDataFunction::getPlayerHitPoint(accessor: mCounterLife));
52 mCounterLifeInitTrans = al::getPaneLocalTrans(mCounterLife, "All");
53 mCounterLifeKidsInitTrans = al::getPaneLocalTrans(mCounterLifeKids, "All");
54}
55
56static bool isDemoLifeMaxUp(CounterLifeCtrl* ctrl) {
57 return al::isNerve(user: ctrl, nerve: &NrvCounterLifeCtrl.DemoLifeMaxUpStartFadeIn) ||
58 al::isNerve(user: ctrl, nerve: &NrvCounterLifeCtrl.DemoLifeMaxUpAddLife) ||
59 al::isNerve(user: ctrl, nerve: &NrvCounterLifeCtrl.DemoLifeMaxUpMove) ||
60 al::isNerve(user: ctrl, nerve: &NrvCounterLifeCtrl.DemoLifeMaxUpUnite);
61}
62
63static s32 calcLifeUpCount(const al::IUseSceneObjHolder* game_data_holder, s32 count) {
64 return sead::Mathi::clampMin(
65 val: count - GameDataFunction::getPlayerHitPointMaxNormal(accessor: game_data_holder), min_: 0);
66}
67
68static f32 calcGaugeFrame(CounterLife* counter, s32 count, s32 max) {
69 f32 max_frame = al::getActionFrameMax(layout: counter, actionName: "Gauge", paneName: "Gauge");
70 return max_frame - max_frame * (static_cast<f32>(count) / static_cast<f32>(max));
71}
72
73static void setGaugeCount(CounterLife* counter, s32 count, s32 max) {
74 counter->setCount(calcGaugeFrame(counter, count, max));
75}
76
77void CounterLifeCtrl::setCount(s32 count) {
78 mCount = count;
79 mTargetCount = count;
80
81 setGaugeCount(counter: mCounterLife, count: mCount, max: GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLife));
82 setGaugeCount(counter: mCounterLifeUp, count: calcLifeUpCount(game_data_holder: mCounterLifeUp, count: mCount), max: 3);
83 setGaugeCount(counter: mCounterLifeKids, count: sead::Mathi::clamp(value: mCount, low: 0, high: 6),
84 max: GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLifeKids));
85
86 if (!isDemoLifeMaxUp(ctrl: this)) {
87 al::setPaneStringFormat(mCounterLife, "TxtLife", al::StringTmp<32>("%d", count).cstr());
88 al::setPaneStringFormat(mCounterLifeUp, "TxtLife", al::StringTmp<32>("%d", count).cstr());
89 al::setPaneStringFormat(mCounterLifeKids, "TxtLife", al::StringTmp<32>("%d", count).cstr());
90 }
91}
92
93bool CounterLifeCtrl::tryUpdateCount(s32 count) {
94 if (count == mTargetCount)
95 return false;
96 setCount(mTargetCount);
97 mTargetCount = count;
98 al::setNerve(user: this, nerve: &CountStartFadeIn);
99 return true;
100}
101
102bool CounterLifeCtrl::tryStartDemoLifeUp(bool is_hack_koopa) {
103 if (!GameDataFunction::isPlayerHitPointMaxWithItem(accessor: mCounterLife) ||
104 mTargetCount == GameDataFunction::getPlayerHitPointMaxCurrent(accessor: mCounterLife))
105 return false;
106 mTargetCount = GameDataFunction::getPlayerHitPointMaxCurrent(accessor: mCounterLife);
107 mIsHackKoopa = is_hack_koopa;
108 if (is_hack_koopa) {
109 s32 count = GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLife);
110 mCount = count;
111 setCount(count);
112 }
113 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.DemoLifeMaxUpStartFadeIn);
114 return true;
115}
116
117void CounterLifeCtrl::appear() {
118 if (al::isNerve(user: this, nerve: &NrvCounterLifeCtrl.Appear) ||
119 al::isNerve(user: this, nerve: &NrvCounterLifeCtrl.Wait))
120 return;
121 al::setPaneLocalAlpha(mCounterLife, "Life", 255);
122 al::setPaneLocalAlpha(mCounterLifeKids, "Life", 255);
123 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.Appear);
124}
125
126void CounterLifeCtrl::end() {
127 al::setNerve(user: this, nerve: &End);
128}
129
130void CounterLifeCtrl::kill() {
131 killAllLayout();
132 al::setNerve(user: this, nerve: &Dead);
133}
134
135void CounterLifeCtrl::killAllLayout() {
136 al::killLayoutIfActive(mCounterLife);
137 al::killLayoutIfActive(mCounterLifeUp);
138 al::killLayoutIfActive(mCounterLifeKids);
139}
140
141bool CounterLifeCtrl::isEndLifeDemo() const {
142 return al::isNerve(user: this, nerve: &NrvCounterLifeCtrl.Wait);
143}
144
145void CounterLifeCtrl::exeAppear() {
146 if (al::isFirstStep(user: this)) {
147 setTransAllLayout(getInitTrans());
148 appearAllLayout();
149 startAllLayout();
150 setCount(GameDataFunction::getPlayerHitPoint(accessor: mCounterLife));
151 }
152 if (getCurrentLayout()->isWait())
153 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.Wait);
154}
155
156void CounterLifeCtrl::setTransAllLayout(const sead::Vector3f& trans) {
157 al::setPaneLocalTrans(mCounterLife, "All", trans);
158 al::setPaneLocalTrans(mCounterLifeUp, "All", trans);
159 al::setPaneLocalTrans(mCounterLifeKids, "All", trans);
160}
161
162const sead::Vector3f& CounterLifeCtrl::getInitTrans() const {
163 return rs::isKidsMode(layout: mCounterLife) ? mCounterLifeKidsInitTrans : mCounterLifeInitTrans;
164}
165
166static bool isActiveCounterLifeUp(const al::IUseSceneObjHolder* game_data_holder) {
167 return GameDataFunction::getPlayerHitPoint(accessor: game_data_holder) >
168 GameDataFunction::getPlayerHitPointMaxNormal(accessor: game_data_holder);
169}
170
171void CounterLifeCtrl::appearAllLayout() {
172 if (rs::isKidsMode(layout: mCounterLifeKids))
173 mCounterLifeKids->appear();
174 else
175 mCounterLife->appear();
176 if (isActiveCounterLifeUp(game_data_holder: mCounterLifeUp))
177 mCounterLifeUp->appear();
178}
179
180void CounterLifeCtrl::startAllLayout() {
181 if (rs::isKidsMode(layout: mCounterLifeKids))
182 mCounterLifeKids->start();
183 else
184 mCounterLife->start();
185 if (isActiveCounterLifeUp(game_data_holder: mCounterLifeUp))
186 mCounterLifeUp->start();
187}
188
189CounterLife* CounterLifeCtrl::getCurrentLayout() const {
190 return rs::isKidsMode(layout: mCounterLife) ? mCounterLifeKids : mCounterLife;
191}
192
193void CounterLifeCtrl::exeWait() {
194 if (al::isFirstStep(user: this))
195 waitAllLayout();
196 if (rs::isEmptyPlayerOxygen(al::getPlayerActor(mPlayerHolder, 0)))
197 updateTransAllLayout();
198 else
199 setTransAllLayout(getInitTrans());
200 if (rs::isPlayerCameraSubjective(al::getPlayerActor(mPlayerHolder, 0)))
201 mSubjectiveCameraWaitTime = 5;
202 else
203 mSubjectiveCameraWaitTime = sead::Mathi::clampMin(val: mSubjectiveCameraWaitTime - 1, min_: 0);
204 tryChangeCount();
205}
206
207void CounterLifeCtrl::waitAllLayout() {
208 if (rs::isKidsMode(layout: mCounterLifeKids))
209 mCounterLifeKids->wait();
210 else
211 mCounterLife->wait();
212 if (isActiveCounterLifeUp(game_data_holder: mCounterLifeUp))
213 mCounterLifeUp->wait();
214 else if (al::isActive(mCounterLifeUp) && !al::isActionPlaying(layout: mCounterLifeUp, actionName: "Break", paneName: "Life"))
215 al::startAction(layout: mCounterLifeUp, actionName: "Break", paneName: "Life");
216 setCount(GameDataFunction::getPlayerHitPoint(accessor: mCounterLife));
217}
218
219void CounterLifeCtrl::updateTransAllLayout() {
220 updateTrans(layout: mCounterLife);
221 updateTrans(layout: mCounterLifeUp);
222 updateTrans(layout: mCounterLifeKids);
223}
224
225bool CounterLifeCtrl::tryChangeCount() {
226 if (GameDataFunction::getPlayerHitPoint(accessor: mCounterLife) == mTargetCount)
227 return false;
228 mTargetCount = GameDataFunction::getPlayerHitPoint(accessor: mCounterLife);
229 if (rs::isEmptyPlayerOxygen(al::getPlayerActor(mPlayerHolder, 0)))
230 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.Count);
231 else
232 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.CountStartFadeOut);
233 return true;
234}
235
236void CounterLifeCtrl::exeEnd() {
237 if (al::isFirstStep(user: this)) {
238 mCounterLife->end();
239 mCounterLifeKids->end();
240 mCounterLifeUp->end();
241 }
242 if (al::isDead(getCurrentLayout()))
243 al::setNerve(user: this, nerve: &Dead);
244}
245
246void CounterLifeCtrl::exeDead() {
247 if (al::isFirstStep(user: this))
248 killAllLayout();
249}
250
251void CounterLifeCtrl::exeCountStartFadeOut() {
252 if (al::isFirstStep(user: this)) {
253 appearAllLayout();
254 startActionAllLayout(action_name: "FadeOut", pane_name: nullptr);
255 }
256 if (al::isActionEnd(layout: getCurrentLayout(), paneName: nullptr))
257 al::setNerve(user: this, nerve: &CountStartFadeIn);
258}
259
260void CounterLifeCtrl::exeCountStartFadeIn() {
261 updateTransAllLayout();
262 if (al::isFirstStep(user: this)) {
263 al::startAction(layout: mCounterLife, actionName: "FadeIn", paneName: nullptr);
264 al::startAction(layout: mCounterLifeKids, actionName: "FadeIn", paneName: nullptr);
265 al::startAction(layout: mCounterLifeUp, actionName: "FadeIn", paneName: nullptr);
266 appearAllLayout();
267 }
268 if (al::isActionEnd(layout: getCurrentLayout(), paneName: nullptr))
269 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.Count);
270}
271
272void CounterLifeCtrl::exeCount() {
273 if (al::isFirstStep(user: this))
274 startCountAnim(target: mTargetCount);
275 if (mTargetCount == mCount) {
276 if (mTargetCount != GameDataFunction::getPlayerHitPoint(accessor: mCounterLife)) {
277 mTargetCount = GameDataFunction::getPlayerHitPoint(accessor: mCounterLife);
278 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.Count);
279 return;
280 }
281 getCurrentLayout();
282 if (al::isGreaterEqualStep(user: this, step: 80)) {
283 if (rs::isEmptyPlayerOxygen(al::getPlayerActor(mPlayerHolder, 0)))
284 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.Wait);
285 else
286 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.CountEnd);
287 }
288 return;
289 }
290 if (al::isGreaterEqualStep(user: this, step: 12))
291 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.Count);
292}
293
294static void startGaugeAnim(CounterLifeCtrl* ctrl, CounterLife* counter, s32 count, s32 max) {
295 f32 frame = calcGaugeFrame(counter, count, max);
296 if (isDemoLifeMaxUp(ctrl))
297 counter->startGaugeWithFrame(goalFrame: frame, frames: al::getActionFrameMax(layout: counter, actionName: "AddMax", paneName: "Life"));
298 else
299 counter->startGauge(goalFrame: frame);
300}
301
302void CounterLifeCtrl::startCountAnim(s32 target) {
303 s32 count = mCount;
304 if (count == target) {
305 startGaugeAnim(ctrl: this, counter: mCounterLife, count: mCount,
306 max: GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLife));
307 startGaugeAnim(ctrl: this, counter: mCounterLifeUp, count: calcLifeUpCount(game_data_holder: mCounterLifeUp, count: mCount), max: 3);
308 startGaugeAnim(ctrl: this, counter: mCounterLifeKids, count: sead::Mathi::clamp(value: mCount, low: 0, high: 6),
309 max: GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLifeKids));
310 return;
311 }
312
313 mCount += target < mCount ? -1 : 1;
314 s32 new_count = mCount;
315 startGaugeAnim(ctrl: this, counter: mCounterLife, count: new_count,
316 max: GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLife));
317 startGaugeAnim(ctrl: this, counter: mCounterLifeUp, count: calcLifeUpCount(game_data_holder: mCounterLifeUp, count: new_count), max: 3);
318 startGaugeAnim(ctrl: this, counter: mCounterLifeKids, count: sead::Mathi::clamp(value: new_count, low: 0, high: 6),
319 max: GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLifeKids));
320
321 bool is_add_max = al::isNerve(user: this, nerve: &NrvCounterLifeCtrl.DemoLifeMaxUpAddLife);
322 if (count > target) {
323 if ((mCount == 3 && !rs::isKidsMode(layout: mCounterLife)) || mCount == 6) {
324 al::startAction(layout: mCounterLifeUp, actionName: "Break", paneName: "Life");
325 } else if (mCount >= GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLife)) {
326 al::startAction(layout: mCounterLifeUp, actionName: "Damage", paneName: "Life");
327 } else {
328 al::startAction(layout: getCurrentLayout(), actionName: "Damage", paneName: "Life");
329 if (mCount == 1) {
330 CounterLife* counter =
331 rs::isKidsMode(layout: mCounterLifeKids) ? mCounterLifeKids : mCounterLife;
332 al::startHitReaction(counter, "ライフ1警告", nullptr);
333 }
334 }
335 } else {
336 const char* action = "Add";
337 if (is_add_max && !mIsHackKoopa)
338 action = "AddMax";
339 if (mCount > GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLife)) {
340 al::startAction(layout: mCounterLifeUp, actionName: action, paneName: "Life");
341 } else {
342 al::startAction(layout: mCounterLife, actionName: action, paneName: "Life");
343 al::startAction(layout: mCounterLifeKids, actionName: action, paneName: "Life");
344 }
345 al::tryStopSe(mCounterLife, "LifeAlert", -1, nullptr);
346 }
347
348 if (isDemoLifeMaxUp(ctrl: this)) {
349 al::setPaneStringFormat(
350 mCounterLife, "TxtLife",
351 al::StringTmp<32>(
352 "%d", sead::Mathi::min(a: mCount,
353 b: GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLife)))
354 .cstr());
355 al::setPaneStringFormat(
356 mCounterLifeKids, "TxtLife",
357 al::StringTmp<32>(
358 "%d", sead::Mathi::min(a: mCount,
359 b: GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLife)))
360 .cstr());
361 al::setPaneStringFormat(
362 mCounterLifeUp, "TxtLife",
363 al::StringTmp<32>(
364 "%d", sead::Mathi::clampMin(
365 val: mCount - GameDataFunction::getPlayerHitPointMaxNormal(accessor: mCounterLife), min_: 0))
366 .cstr());
367 } else {
368 al::setPaneStringFormat(mCounterLife, "TxtLife", al::StringTmp<32>("%d", mCount).cstr());
369 al::setPaneStringFormat(mCounterLifeUp, "TxtLife", al::StringTmp<32>("%d", mCount).cstr());
370 al::setPaneStringFormat(mCounterLifeKids, "TxtLife",
371 al::StringTmp<32>("%d", mCount).cstr());
372 }
373
374 if (GameDataFunction::getPlayerHitPoint(accessor: mCounterLife) > 1) {
375 al::startFreezeAction(layout: mCounterLife, actionName: "Loop", frame: 0, paneName: "Loop");
376 al::startFreezeAction(layout: mCounterLifeKids, actionName: "Loop", frame: 0, paneName: "Loop");
377 }
378}
379
380void CounterLifeCtrl::exeCountEnd() {
381 if (al::isFirstStep(user: this))
382 mCountEndTrans = al::getPaneLocalTrans(mCounterLife, "All");
383 sead::Vector3f pos = sead::Vector3f::zero;
384 al::lerpVec(&pos, mCountEndTrans, getInitTrans(), al::calcNerveEaseInRate(user: this, max: 27));
385 setTransAllLayout(pos);
386 if (al::isGreaterEqualStep(user: this, step: 27)) {
387 setTransAllLayout(getInitTrans());
388 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.Wait);
389 }
390}
391
392void CounterLifeCtrl::exeDemoLifeMaxUpStartFadeIn() {
393 CounterLife* counter = mCounterLifeUp;
394 if (al::isFirstStep(user: this)) {
395 appearAllLayout();
396 getCurrentLayout()->start();
397 al::setPaneLocalTrans(getCurrentLayout(), "All", mCounterLifeInitTrans);
398 counter->setEmpty();
399 al::startAction(layout: counter, actionName: "FadeIn", paneName: nullptr);
400 startGaugeAnim(ctrl: this, counter, count: 0, max: 3);
401 updateTrans(layout: counter);
402 al::setPaneStringFormat(mCounterLifeUp, "TxtLife", al::StringTmp<32>("3").cstr());
403 }
404 if (al::isActionEnd(layout: counter, paneName: nullptr))
405 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.DemoLifeMaxUpAddLife);
406}
407
408void CounterLifeCtrl::updateTrans(al::LayoutActor* layout) {
409 sead::Vector3f pos = sead::Vector3f::zero;
410 calcLayoutTransByPlayer(out: &pos);
411 sead::Vector2f pos2 = {pos.x, pos.y};
412 al::setPaneLocalTrans(layout, "All", pos2);
413}
414
415void CounterLifeCtrl::exeDemoLifeMaxUpAddLife() {
416 if (al::isFirstStep(user: this))
417 mTargetCount = GameDataFunction::getPlayerHitPointMaxCurrent(accessor: mCounterLife);
418 if (al::isIntervalStep(user: this, interval: 12, offset: 0))
419 startCountAnim(target: mTargetCount);
420 if (mTargetCount == mCount)
421 al::setNerve(user: this, nerve: &DemoLifeMaxUpWaitForMove);
422}
423
424void CounterLifeCtrl::exeDemoLifeMaxUpWaitForMove() {
425 if (al::isGreaterEqualStep(user: this, step: 30))
426 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.DemoLifeMaxUpMove);
427}
428
429void CounterLifeCtrl::exeDemoLifeMaxUpMove() {
430 sead::Vector3f pos = sead::Vector3f::zero;
431 calcLayoutTransByPlayer(out: &pos);
432 al::lerpVec(&pos, pos, getInitTrans(), al::calcNerveEaseInRate(user: this, max: 27));
433 al::setPaneLocalTrans(mCounterLifeUp, "All", pos);
434 if (al::isGreaterEqualStep(user: this, step: 27))
435 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.DemoLifeMaxUpUnite);
436}
437
438void CounterLifeCtrl::calcLayoutTransByPlayer(sead::Vector3f* out) {
439 al::LiveActor* player = al::getPlayerActor(mPlayerHolder, 0);
440 if (rs::isPlayerCameraSubjective(player) || mSubjectiveCameraWaitTime > 0) {
441 out->set(getInitTrans());
442 return;
443 }
444 sead::Vector3f pos = sead::Vector3f::zero;
445 rs::calcPlayerFollowLayoutWorldPos(&pos, player);
446 if (rs::isPlayer2D(player) && al::isValidView(info: al::getSceneCameraInfo(user: player), viewIdx: 1))
447 mSubCameraRenderer->calcOnScreenPos(&pos, pos);
448 sead::Vector3f side = {0, 0, 0};
449 al::calcCameraSideDir(sideDir: &side, user: player, viewIdx: 0);
450 sead::Vector3f up = {0, 0, 0};
451 al::calcCameraUpDir(upDir: &up, user: player, viewIdx: 0);
452 sead::Vector2f layout_pos = {0, 0};
453 al::calcLayoutPosFromWorldPos(output: &layout_pos, player, pos + side * 30 + up * 25);
454 sead::Vector2f layout_offset = {0, 24};
455 out->x = layout_pos.x + layout_offset.x;
456 out->y = layout_pos.y + layout_offset.y;
457 f32 min_x = -0.5f * al::getLayoutDisplayWidth() + 100;
458 f32 max_x = 0.5f * al::getLayoutDisplayWidth() - 100;
459 out->x = sead::Mathf::clamp(value: out->x, low: min_x, high: max_x);
460 f32 min_y = -0.5f * al::getLayoutDisplayHeight() + 100;
461 f32 max_y = 0.5f * al::getLayoutDisplayHeight() - 100;
462 out->y = sead::Mathf::clamp(value: out->y, low: min_y, high: max_y);
463 out->z = getInitTrans().z;
464}
465
466void CounterLifeCtrl::exeDemoLifeMaxUpUnite() {
467 if (al::isFirstStep(user: this)) {
468 al::startAction(layout: mCounterLifeUp, actionName: "Unite", paneName: "Life");
469 al::startAction(layout: mCounterLife, actionName: "Unite", paneName: "Life");
470 al::startAction(layout: mCounterLifeKids, actionName: "Unite", paneName: "Life");
471 al::setPaneStringFormat(
472 mCounterLifeUp, "TxtLife",
473 al::StringTmp<32>("%d", GameDataFunction::getPlayerHitPointMaxCurrent(accessor: mCounterLife))
474 .cstr());
475 if (mIsHackKoopa)
476 al::startHitReaction(getCurrentLayout(), "合体[クッパ]", nullptr);
477 else
478 al::startHitReaction(getCurrentLayout(), "合体[通常]", nullptr);
479 return;
480 }
481 if (al::isActionEnd(layout: mCounterLifeUp, paneName: nullptr))
482 al::setNerve(user: this, nerve: &NrvCounterLifeCtrl.Wait);
483}
484
485void CounterLifeCtrl::startActionAllLayout(const char* action_name, const char* pane_name) {
486 al::startAction(layout: mCounterLife, actionName: action_name, paneName: pane_name);
487 al::startAction(layout: mCounterLifeUp, actionName: action_name, paneName: pane_name);
488 al::startAction(layout: mCounterLifeKids, actionName: action_name, paneName: pane_name);
489}
490