diff --git a/lib/libpm-jp.a b/lib/libpm-jp.a index 27dc5ee..0017c80 100644 --- a/lib/libpm-jp.a +++ b/lib/libpm-jp.a @@ -34,6 +34,7 @@ pm_gHudElementSizes = 0x8015406C; pm_MusicCurrentVolume = 0x8015EA66; pm_gActionCommandStatus = 0x8029FED0; pm_battle_move_power_bounce_BaseHitChance = 0x802A2730; +pm_HammerHit = 0x802B6E90; pm_gNumScripts = 0x802DA488; pm_gCurrentScriptListPtr = 0x802DA890; pm_gScriptIndexList = 0x802DA898; diff --git a/lib/libpm-us.a b/lib/libpm-us.a index bdbd93f..5da428e 100644 --- a/lib/libpm-us.a +++ b/lib/libpm-us.a @@ -34,6 +34,7 @@ pm_gHudElementSizes = 0x8014EFCC; pm_MusicCurrentVolume = 0x80159AE6; pm_gActionCommandStatus = 0x8029FBE0; pm_battle_move_power_bounce_BaseHitChance = 0x802A2730; +pm_HammerHit = 0x802B6E90; pm_gNumScripts = 0x802DA488; pm_gCurrentScriptListPtr = 0x802DA890; pm_gScriptIndexList = 0x802DA898; diff --git a/src/enums.h b/src/enums.h index 9b64d98..f285f66 100644 --- a/src/enums.h +++ b/src/enums.h @@ -826,4 +826,59 @@ enum EvtOps { /* 0x5E */ EVT_OP_94, }; +enum PlayerStatusFlags { + PS_FLAG_AIRBORNE = 0x0000000E, + PS_FLAG_HAS_REFLECTION = 0x00000001, + PS_FLAG_JUMPING = 0x00000002, + PS_FLAG_FALLING = 0x00000004, + PS_FLAG_FLYING = 0x00000008, + PS_FLAG_SLIDING = 0x00000010, + /* Paused either via the start menu, or through another menu that causes a pause (like the item menu) */ + PS_FLAG_PAUSED = 0x00000020, + PS_FLAG_NO_CHANGE_PARTNER = 0x00000040, + PS_FLAG_NO_PARTNER_USAGE = 0x00000080, + /* Prevents opening menus that would require a game-time pause (start menu, item menu, etc) */ + PS_FLAG_PAUSE_DISABLED = 0x00000100, + /* Doing either a spin jump or a tornado jump */ + PS_FLAG_SPECIAL_JUMP = 0x00000200, + /* Landing from either a spin jump or a tornado jump */ + PS_FLAG_SPECIAL_LAND = 0x00000400, + /* Burning from touching a fire hazard of some kind */ + PS_FLAG_HIT_FIRE = 0x00000800, + PS_FLAG_NO_STATIC_COLLISION = 0x00001000, + PS_FLAG_INPUT_DISABLED = 0x00002000, + /* Indicates that Mario's lateral movement is currently commandeered by a cutscene or script */ + PS_FLAG_CUTSCENE_MOVEMENT = 0x00004000, + /* Either outta sight with Bow, or temporarily damage boosted - makes Mario ignore fire bars */ + PS_FLAG_HAZARD_INVINCIBILITY = 0x00008000, + /* Spinning either through pressing Z or the tornado jump - causes a ghost trail to render */ + PS_FLAG_SPINNING = 0x00020000, + /* Slows Mario's physics and animations to half speed - responsible for the dramatic slowdown when starting an + encounter by jumping on an enemy. Also stops Mario from successfully completing a hammer. */ + PS_FLAG_ENTERING_BATTLE = 0x00040000, + /* Occurs after hitting a heart block - temporarily prevents encounters from starting */ + PS_FLAG_ARMS_RAISED = 0x00080000, + /* Stops Mario's sprite yaw from being adjusted, usually so a cutscene can do it instead. */ + PS_FLAG_ROTATION_LOCKED = 0x00100000, + /* Forces Mario's sprite to either face exactly left or right, without transitioning. */ + PS_FLAG_NO_FLIPPING = 0x00200000, + /* Prevents Mario from moving laterally */ + PS_FLAG_MOVEMENT_LOCKED = 0x00400000, // TODO misnamed + /* Stops Mario from air steering or using a special jump during a scripted fall */ + PS_FLAG_SCRIPTED_FALL = 0x00800000, + /* Not fully sure about this one, but appears to mark the frame that the check for what to hammer occurs */ + PS_FLAG_HAMMER_CHECK = 0x01000000, + PS_FLAG_HAS_CONVERSATION_NPC = 0x02000000, + PS_FLAG_CAMERA_DOESNT_FOLLOW = 0x04000000, + /* Mario just interacted with something (usually cleared on the same frame) */ + PS_FLAG_INTERACTED = 0x08000000, + /* Makes Mario face forwards, used when talking to NPCs, or when on Lakilester */ + PS_FLAG_FACE_FORWARD = 0x10000000, + /* Freezes physics and animations - is usually reset at the start of a frame so often does nothing */ + PS_FLAG_TIME_STOPPED = 0x20000000, + /* Indicates that Mario needs his sprite redrawn */ + PS_FLAG_SPRITE_REDRAW = 0x40000000, + PS_FLAG_ACTION_STATE_CHANGED = 0x80000000, +}; + #endif diff --git a/src/fp/practice/trainer.c b/src/fp/practice/trainer.c index 95f0ef6..cbf34a8 100644 --- a/src/fp/practice/trainer.c +++ b/src/fp/practice/trainer.c @@ -1,6 +1,7 @@ #include "trainer.h" #include "fp.h" #include "menu/menu.h" +#include "sys/input.h" #include "sys/resource.h" #include "sys/settings.h" #include @@ -570,11 +571,110 @@ static void updateClippyTrainer(void) { } } +static void updateQuickJumpTrainer(void) { + static s8 jumpFrame; + static u8 crouchFrame; + static u8 frame; + static bool waitForNextTurn; + static u8 frameWindow; + + if (settings->trainerQuickJumpsEnabled && pm_gGameStatus.isBattle && pm_gBattleStatus.playerActor) { + if (pm_gBattleStatus.playerActor->partsTable->curAnimation == 0x10004) { + waitForNextTurn = FALSE; + jumpFrame = -1; + crouchFrame = 0; + frame = 0; + frameWindow = 0; + return; + } + + if (waitForNextTurn) { + return; + } + + if (pm_gBattleStatus.playerActor->partsTable->curAnimation == 0x10005 && frame <= 13) { + if (frameWindow == 0) { + if (pm_gBattleStatus.playerActor->state.moveTime < 13) { + frameWindow = 5; + } else { + frameWindow = pm_gBattleStatus.playerActor->state.moveTime - 9; + } + } + if (inputPressed().a && jumpFrame == -1) { + jumpFrame = frame; + } + frame++; + } else if (pm_gBattleStatus.playerActor->partsTable->curAnimation == 0x10008) { + waitForNextTurn = TRUE; + } else if (frame > 0) { + if (jumpFrame != -1) { + u8 framesSinceJump = frame - jumpFrame; + if (framesSinceJump == 1) { + fpLog("jumped frame 1 out of %d", frameWindow); + } else { + fpLog("jumped %d frame%s early", framesSinceJump - 1, framesSinceJump - 1 == 1 ? "" : "s"); + } + waitForNextTurn = TRUE; + return; + } + + if (crouchFrame == 0) { + crouchFrame = frame; + } + + if (inputPressed().a) { + u8 framesAfterCrouch = frame - crouchFrame + 2; + if (framesAfterCrouch <= frameWindow) { + fpLog("jumped frame %d out of %d", framesAfterCrouch, frameWindow); + } else { + fpLog("jumped %d frame%s late", framesAfterCrouch - frameWindow, + framesAfterCrouch - frameWindow == 1 ? "" : "s"); + } + waitForNextTurn = TRUE; + } + + frame++; + } + } +} + +static void updateHammerCancelTrainer(void) { + static bool canCancel; + + if (settings->trainerHammerCancelsEnabled) { + if (pm_HammerHit.timer == 3) { + canCancel = TRUE; + } + + if (pm_HammerHit.timer > 10) { + canCancel = FALSE; + } + + if (inputPressed().b && canCancel) { + canCancel = FALSE; + + if (pm_gPlayerStatus.flags & PS_FLAG_ENTERING_BATTLE) { + return; + } + + if (pm_HammerHit.timer < 7) { + fpLog("hammered %d frame%s early", 7 - pm_HammerHit.timer, 7 - pm_HammerHit.timer == 1 ? "" : "s"); + } else if (pm_HammerHit.timer > 7) { + fpLog("hammered %d frame%s late", pm_HammerHit.timer - 7, pm_HammerHit.timer - 7 == 1 ? "" : "s"); + } else { + fpLog("hammered correct frame"); + } + } + } +} + void trainerUpdate(void) { updateBowserBlockTrainer(); updateLzsTrainer(); updateBlockTrainer(); updateClippyTrainer(); + updateQuickJumpTrainer(); + updateHammerCancelTrainer(); } void trainerDrawPinned(s32 x, s32 y, struct GfxFont *font, s32 chWidth, s32 chHeight, u32 color, u8 alpha) { @@ -624,6 +724,12 @@ void createTrainerMenu(struct Menu *menu) { menuAddStatic(menu, 0, y, "action commands", 0xC0C0C0); menuAddCheckbox(menu, xOffset, y++, menuByteCheckboxProc, &settings->trainerAcEnabled); + menuAddStatic(menu, 0, y, "quick jumps", 0xC0C0C0); + menuAddCheckbox(menu, xOffset, y++, menuByteCheckboxProc, &settings->trainerQuickJumpsEnabled); + + menuAddStatic(menu, 0, y, "hammer cancels", 0xC0C0C0); + menuAddCheckbox(menu, xOffset, y++, menuByteCheckboxProc, &settings->trainerHammerCancelsEnabled); + menuAddStatic(menu, 0, y, "clippy", 0xC0C0C0); struct MenuItem *lastOption = menuAddCheckbox(menu, xOffset, y++, menuByteCheckboxProc, &settings->trainerClippyEnabled); diff --git a/src/pm64.h b/src/pm64.h index 893a231..5e9a6ac 100644 --- a/src/pm64.h +++ b/src/pm64.h @@ -545,6 +545,46 @@ typedef struct pm_ActorMovement { /* 0x4C */ f32 distance; } pm_ActorMovement; // size = 0x50; +typedef struct pm_ActorPart { + /* 0x00 */ s32 flags; + /* 0x04 */ s32 targetFlags; /* initialized to 0 */ + /* 0x08 */ void *staticData; // ActorPartBlueprint* + /* 0x0C */ struct pm_ActorPart *nextPart; + /* 0x10 */ void *movement; // ActorPartMovement* + /* 0x14 */ Vec3s partOffset; + /* 0x1A */ Vec3s visualOffset; + /* 0x20 */ Vec3f partOffsetFloat; + /* 0x2C */ Vec3f absolutePos; + /* 0x38 */ Vec3f rot; + /* 0x44 */ Vec3s rotPivotOffset; + /* 0x4A */ char unk_4A[2]; + /* 0x4C */ Vec3f scale; + /* 0x58 */ Vec3f curPos; + /* 0x64 */ f32 yaw; + /* 0x68 */ s16 palAnimPosOffset[2]; // used by some palette animations to slightly adjust the screen position + /* 0x6C */ Vec2s targetOffset; + /* 0x70 */ s16 targetPriorityOffset; + /* 0x72 */ Vec2bu size; + /* 0x74 */ s8 verticalStretch; + /* 0x75 */ Vec2b projectileTargetOffset; + /* 0x77 */ char unk_77[1]; + /* 0x78 */ u32 *defenseTable; + /* 0x7C */ s32 eventFlags; + /* 0x80 */ s32 elementalImmunities; // bits from Elements, i.e., ELEMENT_FIRE | ELEMENT_QUAKE + /* 0x84 */ s32 spriteInstanceID; + /* 0x88 */ u32 curAnimation; + /* 0x8C */ s32 animNotifyValue; + /* 0x90 */ f32 animationRate; + /* 0x94 */ u32 *idleAnimations; + /* 0x98 */ s16 opacity; + /* 0x9A */ char unk_9A[2]; + /* 0x9C */ s32 shadowIndex; + /* 0xA0 */ f32 shadowScale; + /* 0xA4 */ s32 partTypeData[6]; + /* 0xBC */ s16 actorTypeData2b[2]; + /* 0xC0 */ void *decorationTable; // struct DecorationTable*, initialized to 0 +} pm_ActorPart; // size = 0xC4 + typedef struct pm_Actor { /* 0x000 */ s32 flags; /* 0x004 */ s32 flags2; @@ -603,7 +643,7 @@ typedef struct pm_Actor { /* 0x1F1 */ s8 turnPriority; /* 0x1F2 */ s8 enemyIndex; /* actorID = this | 200 */ /* 0x1F3 */ s8 numParts; - /* 0x1F4 */ void *partsTable; // ActorPart + /* 0x1F4 */ pm_ActorPart *partsTable; /* 0x1F8 */ s16 lastDamageTaken; /* 0x1FA */ s16 hpChangeCounter; /* 0x1FC */ u16 damageCounter; @@ -1296,6 +1336,15 @@ typedef struct pm_Action { /* 0x0C */ s8 flag; } pm_Action; // size = 0x10 +typedef struct pm_HammerHitData { + /* 0x00 */ Vec3f hitPos; + /* 0x0C */ s32 unk_0C; + /* 0x10 */ s32 hitID; + /* 0x14 */ s32 unk_14; + /* 0x18 */ s32 timer; + /* 0x1C */ s32 unk_1C; +} pm_HammerHitData; + typedef void *(*PrintCallback)(void *, const char *, u32); typedef pm_Evt *pm_ScriptList[128]; @@ -1336,6 +1385,7 @@ extern_data pm_HudElementSize pm_gHudElementSizes[26]; extern_data s16 pm_MusicCurrentVolume; extern_data pm_ActionCommandStatus pm_gActionCommandStatus; extern_data s32 pm_battle_move_power_bounce_BaseHitChance; +extern_data pm_HammerHitData pm_HammerHit; extern_data s32 pm_gNumScripts; extern_data pm_ScriptList *pm_gCurrentScriptListPtr; extern_data s32 pm_gScriptIndexList[128]; diff --git a/src/sys/settings.h b/src/sys/settings.h index dc562a1..f5bd7ae 100644 --- a/src/sys/settings.h +++ b/src/sys/settings.h @@ -7,7 +7,7 @@ #define SETTINGS_SAVE_FILE_SIZE 0x1380 #define SETTINGS_PROFILE_MAX 4 -#define SETTINGS_VERSION 7 +#define SETTINGS_VERSION 8 #define SETTINGS_FIO_PAGE 7 #define SETTINGS_WATCHES_MAX 18 @@ -74,6 +74,8 @@ struct SettingsData { u8 trainerLzsEnabled; u8 trainerAcEnabled; u8 trainerClippyEnabled; + u8 trainerQuickJumpsEnabled; + u8 trainerHammerCancelsEnabled; u8 trainerDisplayPinned; u8 battleDebug; u8 quickLaunch; diff --git a/src/types.h b/src/types.h index 47f80f3..ac74024 100644 --- a/src/types.h +++ b/src/types.h @@ -29,6 +29,11 @@ typedef struct { /* 0x04 */ f32 z; } Vec2XZf; // size = 0x08 +typedef struct Vec2s { + /* 0x00 */ s16 x; + /* 0x02 */ s16 y; +} Vec2s; // size = 0x04 + typedef struct { /* 0x00 */ f32 x; /* 0x04 */ f32 y;