forked from PhlexPlexico/mm3dr
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Include twinmold fixes from project restoration. (#50)
- Loading branch information
1 parent
29388ce
commit 088ee2c
Showing
9 changed files
with
337 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
#ifndef _GAME_ACTORS_BOSS_TWINMOLD_H | ||
#define _GAME_ACTORS_BOSS_TWINMOLD_H | ||
#include <cstddef> | ||
|
||
#include "common/types.h" | ||
#include "common/utils.h" | ||
#include "game/actor.h" | ||
#include "game/collision.h" | ||
#include "z3d/z3DVec.h" | ||
|
||
namespace game { | ||
class GlobalContext; | ||
} | ||
|
||
namespace game::act { | ||
|
||
struct BossTwinmold : Actor { | ||
// Probably incomplete. | ||
enum class Status : u16 { | ||
Buried = 0, | ||
BlueRisingOutOfSand = 1, | ||
// Also resets the hit counter. | ||
RedBurrowingIntoSand = 3, | ||
|
||
Flying = 4, | ||
Unk6 = 6, | ||
// The most commonly seen state for Blue Twinmold. | ||
FlyingAimlessly = 7, | ||
|
||
Unk8 = 8, | ||
Unk9 = 9, | ||
|
||
// These states are entered after receiving enough hits. | ||
BlueStunnedByShootingEyes = 11, | ||
BlueStunnedEyeOut = 12, | ||
BlueStunnedBurrowingIntoSand = 13, | ||
|
||
Stunned = 15, | ||
StunnedAndOnGround = 16, | ||
|
||
TauntingLink = 18, | ||
AfterTaunting = 19, | ||
|
||
// Only for Red Twinmold? | ||
TauntingAndAttacking = 21, | ||
AfterTauntingAndAttacking = 22, | ||
FlyingAndAttacking = 23, | ||
|
||
BeingGrabbedByLink = 24, | ||
BeingChokedByLink = 25, | ||
|
||
PreparingToRiseOutOfSand = 26, | ||
|
||
// ? | ||
AfterTaunting2 = 98, | ||
|
||
Inactive = 100, | ||
FirstTimeRisingOutOfSand = 102, | ||
|
||
DyingStart = 200, | ||
DyingExploding = 201, | ||
DyingFallingToGround = 202, | ||
DyingTouchedGround = 203, | ||
}; | ||
|
||
void* resource; | ||
Status status; | ||
u16 some_status_change_countdown; | ||
u16 field_200; | ||
u16 field_202; | ||
u16 frame_counter; | ||
u16 field_206; | ||
u16 field_208; | ||
u16 field_20A; | ||
u16 field_20C; | ||
u8 gap_20E[14]; | ||
u16 field_21C; | ||
u8 gap_21E[14]; | ||
z3dVec3f field_22C; | ||
z3dVec3f field_238; | ||
u8 gap244[1]; | ||
u8 field_245; | ||
u8 gap246[3]; | ||
u8 gap_249[27]; | ||
float field_264; | ||
float field_268; | ||
signed int field_26C; | ||
z3dVec3f field_270; | ||
u8 gap27C[15748]; | ||
u32 field_4000; | ||
u8 gap_4004[3448]; | ||
u32 field_4D7C; | ||
u32 field_4D80; | ||
u8 gap_4D84[56]; | ||
u32 status_anim; | ||
u8 gap_4DC0[8]; | ||
float field_4DC8; | ||
signed int field_4DCC; | ||
u8 gap_4DD0[560]; | ||
u32 field_5000; | ||
u8 gap_5004[3448]; | ||
z3dVec3f field_5D7C; | ||
z3dVec3f field_5D88; | ||
z3dVec3f field_5D94; | ||
z3dVec3f field_5DA0; | ||
u8 gap5DAC[120]; | ||
void (*field_5E24)(BossTwinmold*, GlobalContext*); | ||
/// Points to Blue Twinmold for Red Twinmold, and vice versa. | ||
BossTwinmold* other_twinmold_actor; | ||
int field_5E2C; | ||
u8 gap_5E30[12]; | ||
/// one for each segment of Twinmold's body, | ||
/// starting at the head (0) and ending at the tail (13) | ||
CollisionBodies<CollisionBodyCylinderCollection, 14> collision_1; | ||
CollisionBodies<CollisionBodyCylinderCollection, 14> collision_main; | ||
CollisionBodyCylinder collision_2; | ||
u8 gap_6794[8]; | ||
u32 field_679C; | ||
u16 field_67A0; | ||
u8 gap_67A2[26]; | ||
float field_67BC; | ||
u16 field_67C0; | ||
signed int field_67C4; | ||
u8 gap_67C8[44]; | ||
float field_67F4; | ||
float field_67F8; | ||
u8 gap_67FC[8]; | ||
int (*field_6804)(BossTwinmold*, GlobalContext*, act::Actor*); | ||
u8 gap_6808[6136]; | ||
u32 field_8000; | ||
u8 gap_8004[784]; | ||
char field_8314; | ||
char field_8315; | ||
char field_8316; | ||
char field_8317; | ||
u8 gap_8318[3304]; | ||
u32 field_9000; | ||
u8 gap_9004[208]; | ||
char field_90D4; | ||
__attribute__((aligned(4))) u8 field_90D8; | ||
u8 gap_90D9[11]; | ||
u16 hit_counter; | ||
u16 field_90E6; | ||
u8 gap_90E8[12]; | ||
u32 field_90F4; | ||
int field_90F8; | ||
u8 gap_90FC[16]; | ||
u32 field_910C; | ||
u32 field_9110; | ||
u8 gap_9114[4]; | ||
u32 field_9118; | ||
u8 gap_911C[8]; | ||
u32 field_9124; | ||
u8 gap_9128[4]; | ||
float eye_scale; | ||
float field_9130; | ||
u8 gap_9134[8]; | ||
float field_913C; | ||
u8 gap_9140[24]; | ||
z3dVec3f field_9158; | ||
z3dVec3f field_9164; | ||
u8 gap9170[36]; | ||
CollisionBodies<CollisionBodyCylinderCollection, 1> collision_eye; | ||
CollisionBodies<CollisionBodyCylinderCollection, 1> collision_3; | ||
u32 field_9274; | ||
u8 gap_9278[308]; | ||
u32 field_93AC; | ||
u8 gap_93B0[308]; | ||
CollisionBodies<CollisionBodyCylinderCollection, 1> collision_4; | ||
CollisionBodies<CollisionBodyCylinderCollection, 1> collision_5; | ||
z3dVec3f field_95C4; | ||
u8 gap_95D0[8]; | ||
int field_95D8; | ||
int field_95DC; | ||
int field_95E0; | ||
u8 gap_95E4[60]; | ||
int field_9620; | ||
int field_9624; | ||
}; | ||
static_assert(sizeof(BossTwinmold) == 0x9628); | ||
static_assert(offsetof(BossTwinmold, other_twinmold_actor) == 0x5E28); | ||
static_assert(offsetof(BossTwinmold, gap_93B0) == 0x93B0); | ||
|
||
} // namespace game::act | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#ifndef _RND_BOSS_H_ | ||
#define _RND_BOSS_H_ | ||
#include "common/advanced_context.h" | ||
#include "rnd/settings.h" | ||
#include "game/actors/boss/twinmold.h" | ||
|
||
#include <algorithm> | ||
#include <array> | ||
#include <cmath> | ||
#include <optional> | ||
#include <type_traits> | ||
#if defined ENABLE_DEBUG || defined DEBUG_PRINT | ||
#include "common/debug.h" | ||
extern "C" { | ||
#include <3ds/svc.h> | ||
} | ||
#endif | ||
|
||
namespace rnd { | ||
void FixBosses(); | ||
} // namespace rnd | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
.arm | ||
.text | ||
|
||
.global hook_PostActorCalc | ||
hook_PostActorCalc: | ||
push {r0-r12, lr} | ||
bl PostActorCalc @ found in main.cpp | ||
pop {r0-r12,lr} | ||
add r3,r5,#0x10 | ||
bx lr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
.arm | ||
|
||
.section .patch_PostActorCalc | ||
.global patch_PostActorCalc | ||
patch_PostActorCalc: | ||
bl hook_PostActorCalc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#include "rnd/boss.h" | ||
/** | ||
* @file boss.cpp | ||
* @author leoetlino (https://github.com/leoetlino/) | ||
* @brief | ||
* @date 2021-09-15 | ||
* | ||
* Brought in from the Project Restoration libraries. Edited to adjust for the randomizer. | ||
*/ | ||
namespace rnd { | ||
|
||
struct TwinmoldFixState { | ||
s8 blue_prev_life; | ||
s8 red_prev_life; | ||
game::act::BossTwinmold::Status red_prev_status; | ||
u16 red_prev_hit_counter; | ||
bool is_hit_counter_sane; | ||
}; | ||
|
||
void FixTwinmold() { | ||
static std::optional<TwinmoldFixState> state{}; | ||
const game::GlobalContext* gctx = GetContext().gctx; | ||
|
||
auto* red_twinmold = | ||
gctx->FindActorWithId<game::act::BossTwinmold>(game::act::Id::BossTwinmold, game::act::Type::Boss); | ||
if (!red_twinmold) { | ||
state.reset(); | ||
return; | ||
} | ||
|
||
auto* blue_twinmold = red_twinmold->other_twinmold_actor; | ||
|
||
if (state) { | ||
// Red Twinmold has 12 HP (after killing their blue friend). | ||
// | ||
// Spinning it deals 3-5 damage points based on lin_vel_xxx: | ||
// boss->life -= 3 + (5 - 2) * player->lin_vel_xxx; | ||
// It is possible to deal 5 damage to the boss by spinning the main stick, | ||
// but that's not obvious at all... | ||
// | ||
// If the player spins the main stick (which is not an obvious thing to do...), | ||
// killing Red Twinmold takes 3 identical cycles. | ||
// If not, 4 cycles (!) are required. | ||
// | ||
// Let's make that less tedious and less boring by reducing the number of required cycles | ||
// (1 if the player touches the stick, 2 otherwise). | ||
if (state->red_prev_life > red_twinmold->life) { | ||
#if defined ENABLE_DEBUG || defined DEBUG_PRINT | ||
util::Print("%s: dealing more damage to Red Twinmold\n", __func__); | ||
#endif | ||
red_twinmold->life -= 8; | ||
} | ||
|
||
// Only update the hit counter if it is sane. One way of ensuring that condition is satisfied | ||
// is to only consider the counter to be sane after the player has hit Twinmold once. | ||
if (red_twinmold->hit_counter == 8) | ||
state->is_hit_counter_sane = true; | ||
|
||
// 10 hits are required to stun Red or Blue Twinmold. This would have been acceptable | ||
// if it weren't for the fact that Red Twinmold regularly burrows back into sand during phase | ||
// 2 and the hit counter is reset every time that happens. This makes for a confusing | ||
// experience the first time the player fights Twinmold, as there is nothing in the game that | ||
// indicates that the hit counter resets every time (and it's still frustrating on subsequent | ||
// playthroughs). | ||
// | ||
// Fix that by restoring the previous hit counter after it's been reset by the game. | ||
const bool was_reset = red_twinmold->hit_counter == 9 && state->red_prev_hit_counter != 9; | ||
const bool is_legit_reset = red_twinmold->status == game::act::BossTwinmold::Status::Stunned; | ||
if (state->is_hit_counter_sane && was_reset && !is_legit_reset) { | ||
#if defined ENABLE_DEBUG || defined DEBUG_PRINT | ||
util::Print("%s: restoring hit counter (%u)\n", __func__, state->red_prev_hit_counter); | ||
#endif | ||
|
||
red_twinmold->hit_counter = state->red_prev_hit_counter; | ||
} | ||
} else { | ||
#if defined ENABLE_DEBUG || defined DEBUG_PRINT | ||
util::Print("%s: initialising state\n", __func__); | ||
#endif | ||
state.emplace(); | ||
state->is_hit_counter_sane = false; | ||
} | ||
|
||
state->blue_prev_life = blue_twinmold->life; | ||
state->red_prev_life = red_twinmold->life; | ||
state->red_prev_status = red_twinmold->status; | ||
if (state->is_hit_counter_sane) | ||
state->red_prev_hit_counter = red_twinmold->hit_counter; | ||
} | ||
void FixBosses() { | ||
FixTwinmold(); | ||
} | ||
} // namespace rnd |
Oops, something went wrong.