diff --git a/.gitignore b/.gitignore index 7f2152a0..02ab81e7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ venv/ *.bin .ninja_* build.ninja +CMakeLists.txt romc diff --git a/lib/libpm-jp.a b/lib/libpm-jp.a index 0017c803..ebe7fdc7 100644 --- a/lib/libpm-jp.a +++ b/lib/libpm-jp.a @@ -30,6 +30,8 @@ pm_gPopupState = 0x8010D800; pm_gPartnerStatus = 0x8010ED70; pm_gUiStatus = 0x8010F118; pm_gPlayerStatus = 0x8010F188; +pm_gPlayerSpinState = 0x8010F410; +pm_gPlayerData = 0x8010F450; pm_gHudElementSizes = 0x8015406C; pm_MusicCurrentVolume = 0x8015EA66; pm_gActionCommandStatus = 0x8029FED0; diff --git a/lib/libpm-us.a b/lib/libpm-us.a index 5da428e0..89ce6807 100644 --- a/lib/libpm-us.a +++ b/lib/libpm-us.a @@ -30,6 +30,8 @@ pm_gPopupState = 0x8010D640; pm_gPartnerStatus = 0x8010EBB0; pm_gUiStatus = 0x8010EF58; pm_gPlayerStatus = 0x8010EFC8; +pm_gPlayerSpinState = 0x8010F250; +pm_gPlayerData = 0x8010F290; pm_gHudElementSizes = 0x8014EFCC; pm_MusicCurrentVolume = 0x80159AE6; pm_gActionCommandStatus = 0x8029FBE0; diff --git a/src/enums.h b/src/enums.h index f285f662..5cb28c81 100644 --- a/src/enums.h +++ b/src/enums.h @@ -1,6 +1,65 @@ #ifndef ENUMS_H #define ENUMS_H +enum Abilities { + ABILITY_DODGE_MASTER = 0x00000000, + ABILITY_UNUSED = 0x00000001, + ABILITY_SPIKE_SHIELD = 0x00000002, + ABILITY_FIRST_ATTACK = 0x00000003, + ABILITY_HP_PLUS = 0x00000004, + ABILITY_DOUBLE_DIP = 0x00000005, + ABILITY_MYSTERY_SCROLL = 0x00000006, + ABILITY_FIRE_SHIELD = 0x00000007, + ABILITY_PRETTY_LUCKY = 0x00000008, + ABILITY_HP_DRAIN = 0x00000009, + ABILITY_ALL_OR_NOTHING = 0x0000000A, + ABILITY_SLOW_GO = 0x0000000B, + ABILITY_FP_PLUS = 0x0000000C, + ABILITY_ICE_POWER = 0x0000000D, + ABILITY_FEELING_FINE = 0x0000000E, + ABILITY_ATTACK_FX = 0x0000000F, + ABILITY_MONEY_MONEY = 0x00000010, + ABILITY_CHILL_OUT = 0x00000011, + ABILITY_HAPPY_HEART = 0x00000012, + ABILITY_ZAP_TAP = 0x00000013, + ABILITY_MEGA_RUSH = 0x00000014, + ABILITY_BERSERKER = 0x00000015, + ABILITY_RIGHT_ON = 0x00000016, + ABILITY_RUNAWAY_PAY = 0x00000017, + ABILITY_FLOWER_SAVER = 0x00000018, + ABILITY_PAY_OFF = 0x00000019, + ABILITY_QUICK_CHANGE = 0x0000001A, + ABILITY_DEFEND_PLUS = 0x0000001B, + ABILITY_POWER_PLUS = 0x0000001C, + ABILITY_REFUND = 0x0000001D, + ABILITY_POWER_RUSH = 0x0000001E, + ABILITY_CRAZY_HEART = 0x0000001F, + ABILITY_LAST_STAND = 0x00000020, + ABILITY_CLOSE_CALL = 0x00000021, + ABILITY_P_UP_D_DOWN = 0x00000022, + ABILITY_LUCKY_DAY = 0x00000023, + ABILITY_MEGA_HP_DRAIN = 0x00000024, + ABILITY_P_DOWN_D_UP = 0x00000025, + ABILITY_FLOWER_FANATIC = 0x00000026, + ABILITY_SPEEDY_SPIN = 0x00000027, + ABILITY_SPIN_ATTACK = 0x00000028, + ABILITY_I_SPY = 0x00000029, + ABILITY_BUMP_ATTACK = 0x0000002A, + ABILITY_HEART_FINDER = 0x0000002B, + ABILITY_FLOWER_FINDER = 0x0000002C, + ABILITY_DIZZY_ATTACK = 0x0000002D, + ABILITY_FINAL_GOOMPA = 0x0000002E, + ABILITY_FINAL_BOBOMB = 0x0000002F, + ABILITY_DEEP_FOCUS = 0x00000030, + ABILITY_SUPER_FOCUS = 0x00000031, + ABILITY_KAIDEN = 0x00000032, + ABILITY_DAMAGE_DODGE = 0x00000033, + ABILITY_HAPPY_FLOWER = 0x00000034, + ABILITY_GROUP_FOCUS = 0x00000035, + ABILITY_PEEKABOO = 0x00000036, + ABILITY_HEALTHY_HEALTHY = 0x00000037, +}; + enum ActionStates { ACTION_STATE_IDLE, ACTION_STATE_WALK, @@ -881,4 +940,51 @@ enum PlayerStatusFlags { PS_FLAG_ACTION_STATE_CHANGED = 0x80000000, }; +enum PlayerStatusAnimFlags { + /* Whether Mario is in the process of using Watt (but isn't necessarily holding them yet) */ + PA_FLAG_USING_WATT = 0x00000001, + /* Whether Watt is actually in Mario's hands at the moment */ + PA_FLAG_WATT_IN_HANDS = 0x00000002, + PA_FLAG_INTERRUPT_USE_PARTNER = + 0x00000004, ///< forces actions with bow, parakarry, watt, and lakilester to end (sushie not tested) + PA_FLAG_FORCE_USE_PARTNER = 0x00000008, ///< triggers partner use when set + PA_FLAG_INTERACT_PROMPT_AVAILABLE = 0x00000010, ///< ! prompt + PA_FLAG_SPEECH_PROMPT_AVAILABLE = 0x00000020, ///< (...) prompt + PA_FLAG_PULSE_STONE_VISIBLE = 0x00000040, ///< The pulse stone icon is being shown + PA_FLAG_USING_PULSE_STONE = 0x00000080, + PA_FLAG_ISPY_VISIBLE = 0x00000100, ///< The I Spy icon is being shown + PA_FLAG_RAISED_ARMS = 0x00000200, ///< Sets action state to ACTION_STATE_RAISE_ARMS on idle + PA_FLAG_SHIVERING = 0x00000400, + PA_FLAG_OPENED_HIDDEN_PANEL = 0x00000800, + PA_FLAG_USING_PEACH_PHYSICS = 0x00001000, + PA_FLAG_INVISIBLE = 0x00002000, + PA_FLAG_8BIT_MARIO = 0x00004000, + PA_FLAG_NPC_COLLIDED = 0x00008000, + PA_FLAG_SPINNING = 0x00010000, + /* Began an encounter by spinning into an enemy with the Dizzy Attack badge on */ + PA_FLAG_DIZZY_ATTACK_ENCOUNTER = 0x00020000, + PA_FLAG_INTERRUPT_SPIN = 0x00040000, + /* When Mario is in a transition to a new map, either through a loading zone or pipe */ + PA_FLAG_CHANGING_MAP = 0x00100000, + /* Occurs after PA_FLAG_FORCE_USE_PARTNER. Some partners - namely Bow and Lakilester, unset this immediately. + Not sure why - seems like it might contribute to being unable to *stop* using your partner during a cutscene. */ + PA_FLAG_PARTNER_USAGE_FORCED = 0x00200000, + PA_FLAG_RIDING_PARTNER = 0x00400000, + PA_FLAG_ABORT_PUSHING_BLOCK = 0x00800000, + /* Changes how Mario is rendered. Seems to be intended to make Mario's depth render properly when using Bow behind a + * switch (two translucent objects on top of eachother), but it doesn't actually work. */ + PA_FLAG_MAP_HAS_SWITCH = 0x01000000, + /* Usually, if Mario falls for too long, he eventually gets reset to his last safe position. This prevents that. + * Used by some scripts. */ + PA_FLAG_NO_OOB_RESPAWN = 0x10000000, + /* This allows dismounting from Lakilester, even if in a precarious situation (like over spikes, lava, or water). */ + PA_FLAG_DISMOUNTING_ALLOWED = 0x20000000, + /* This flag is set when partner usage was interrupted by a script, and it prevents menu sounds (like the error + * sound) from playing for script-initiated player actions */ + PA_FLAG_FORCED_PARTNER_ABILITY_END = 0x40000000, + /* This one's really weird. Seems to have something to do with the direction Mario is facing, but I'm not sure what + * it's actually supposed to be achieving. */ + PA_FLAG_80000000 = 0x80000000, +}; + #endif diff --git a/src/fp.c b/src/fp.c index cb2ee45e..cf63fed9 100644 --- a/src/fp.c +++ b/src/fp.c @@ -299,26 +299,26 @@ void fpDrawTimer(struct GfxFont *font, s32 cellWidth, s32 cellHeight, u8 menuAlp void fpUpdateCheats(void) { pm_gGameStatus.debugEnemyContact = settings->cheatEnemyContact; if (CHEAT_ACTIVE(CHEAT_HP)) { - pm_gPlayerStatus.playerData.curHP = pm_gPlayerStatus.playerData.curMaxHP; + pm_gPlayerData.curHP = pm_gPlayerData.curMaxHP; } if (CHEAT_ACTIVE(CHEAT_FP)) { - pm_gPlayerStatus.playerData.curFP = pm_gPlayerStatus.playerData.curMaxFP; + pm_gPlayerData.curFP = pm_gPlayerData.curMaxFP; } if (CHEAT_ACTIVE(CHEAT_ATTACK)) { pm_gBattleStatus.merleeAttackBoost = 127; } if (CHEAT_ACTIVE(CHEAT_COINS)) { - pm_gPlayerStatus.playerData.coins = 999; + pm_gPlayerData.coins = 999; } if (CHEAT_ACTIVE(CHEAT_STAR_POWER)) { - pm_gPlayerStatus.playerData.starPowerFullBars = pm_gPlayerStatus.playerData.maxStarPower; - pm_gPlayerStatus.playerData.starPowerPartialBars = 0; + pm_gPlayerData.starPowerFullBars = pm_gPlayerData.maxStarPower; + pm_gPlayerData.starPowerPartialBars = 0; } if (CHEAT_ACTIVE(CHEAT_STAR_PIECES)) { - pm_gPlayerStatus.playerData.starPieces = 160; + pm_gPlayerData.starPieces = 160; } if (CHEAT_ACTIVE(CHEAT_PERIL)) { - pm_gPlayerStatus.playerData.curHP = 1; + pm_gPlayerData.curHP = 1; } if (CHEAT_ACTIVE(CHEAT_AUTO_MASH)) { if (pm_gGameStatus.isBattle == 1) { @@ -559,6 +559,10 @@ void fpDraw(void) { trainerDrawPinned(settings->trainerX, settings->trainerY, font, cellWidth, cellHeight, 0xC0C0C0, menuAlpha); } + if (fp.spinTrainerMoving || (settings->trainerSpinBarEnabled && !fp.menuActive && pm_gGameStatus.isBattle == 0)) { + trainerDrawSpinBar(settings->trainerSpinX, settings->trainerSpinY, font, 0xC0C0C0, menuAlpha); + } + if (!fp.versionShown) { fpDrawVersion(font, cellWidth, cellHeight, menuAlpha); } diff --git a/src/fp.h b/src/fp.h index a0435948..c168fc6a 100644 --- a/src/fp.h +++ b/src/fp.h @@ -42,6 +42,7 @@ typedef struct { s32 cpuCounterFreq; bool timerMoving; bool trainerMoving; + bool spinTrainerMoving; bool menuActive; struct LogEntry log[SETTINGS_LOG_MAX]; Vec3f savedPos; diff --git a/src/fp/player/fp_player.c b/src/fp/player/fp_player.c index 399707a8..5286ef45 100644 --- a/src/fp/player/fp_player.c +++ b/src/fp/player/fp_player.c @@ -50,8 +50,8 @@ static struct GfxTexture **getItemTextureList(void) { } static s32 maxHpProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { - s8 *curMaxHP = &pm_gPlayerStatus.playerData.curMaxHP; - s8 *hardMaxHP = &pm_gPlayerStatus.playerData.hardMaxHP; + s8 *curMaxHP = &pm_gPlayerData.curMaxHP; + s8 *hardMaxHP = &pm_gPlayerData.hardMaxHP; if (reason == MENU_CALLBACK_THINK_INACTIVE) { if (menuIntinputGet(item) != *curMaxHP) { menuIntinputSet(item, *curMaxHP); @@ -69,8 +69,8 @@ static s32 maxHpProc(struct MenuItem *item, enum MenuCallbackReason reason, void } static s32 maxFpProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { - s8 *curMaxFP = &pm_gPlayerStatus.playerData.curMaxFP; - s8 *hardMaxFP = &pm_gPlayerStatus.playerData.hardMaxFP; + s8 *curMaxFP = &pm_gPlayerData.curMaxFP; + s8 *hardMaxFP = &pm_gPlayerData.hardMaxFP; if (reason == MENU_CALLBACK_THINK_INACTIVE) { if (menuIntinputGet(item) != *curMaxFP) { menuIntinputSet(item, *curMaxFP); @@ -89,16 +89,16 @@ static s32 maxFpProc(struct MenuItem *item, enum MenuCallbackReason reason, void static s32 currentPartnerProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { if (reason == MENU_CALLBACK_THINK_INACTIVE) { - menuOptionSet(item, partnerOrder[pm_gPlayerStatus.playerData.currentPartner]); + menuOptionSet(item, partnerOrder[pm_gPlayerData.currentPartner]); } else if (reason == MENU_CALLBACK_DEACTIVATE) { - pm_gPlayerStatus.playerData.currentPartner = partnerOrder[menuOptionGet(item)]; + pm_gPlayerData.currentPartner = partnerOrder[menuOptionGet(item)]; } return 0; } static s32 bootsProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { u32 trackedLevel = (u32)data; - s8 *bootsUpgrade = &pm_gPlayerStatus.playerData.bootsLevel; + s8 *bootsUpgrade = &pm_gPlayerData.bootsLevel; if (reason == MENU_CALLBACK_SWITCH_ON) { *bootsUpgrade = trackedLevel; } else if (reason == MENU_CALLBACK_THINK) { @@ -109,7 +109,7 @@ static s32 bootsProc(struct MenuItem *item, enum MenuCallbackReason reason, void static s32 hammerProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { u32 trackedLevel = (u32)data; - s8 *hammerUpgrade = &pm_gPlayerStatus.playerData.hammerLevel; + s8 *hammerUpgrade = &pm_gPlayerData.hammerLevel; if (reason == MENU_CALLBACK_SWITCH_ON) { *hammerUpgrade = trackedLevel; } else if (reason == MENU_CALLBACK_SWITCH_OFF) { @@ -149,8 +149,8 @@ static s32 ultraRankProc(struct MenuItem *item, enum MenuCallbackReason reason, } static s32 starSpiritSwitchProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { - s8 *ssSaved = &pm_gPlayerStatus.playerData.maxStarPower; - s16 *starPower = &pm_gPlayerStatus.playerData.starPower; + s8 *ssSaved = &pm_gPlayerData.maxStarPower; + s16 *starPower = &pm_gPlayerData.starPower; s32 ssIndex = (u32)data; if (reason == MENU_CALLBACK_SWITCH_ON) { *ssSaved = ssIndex; @@ -252,7 +252,7 @@ static void createStatsMenu(struct Menu *menu) { s32 hpX = 1; s32 hpY = 2; menuAddStaticIcon(menu, hpX, hpY, texHeart, 0, 0xFFFFFF, 1.0f); - item = menuAddIntinput(menu, hpX + 2, hpY, 10, 2, menuByteModProc, &pm_gPlayerStatus.playerData.curHP); + item = menuAddIntinput(menu, hpX + 2, hpY, 10, 2, menuByteModProc, &pm_gPlayerData.curHP); item->tooltip = strHp; menuAddStatic(menu, hpX + 4, hpY, "/", 0xC0C0C0); item = menuAddIntinput(menu, hpX + 5, hpY, 10, 2, maxHpProc, NULL); @@ -261,7 +261,7 @@ static void createStatsMenu(struct Menu *menu) { s32 fpX = 1; s32 fpY = 4; menuAddStaticIcon(menu, fpX, fpY, texFlower, 0, 0xFFFFFF, 1.0f); - item = menuAddIntinput(menu, fpX + 2, fpY, 10, 2, menuByteModProc, &pm_gPlayerStatus.playerData.curFP); + item = menuAddIntinput(menu, fpX + 2, fpY, 10, 2, menuByteModProc, &pm_gPlayerData.curFP); item->tooltip = strFp; menuAddStatic(menu, fpX + 4, fpY, "/", 0xC0C0C0); item = menuAddIntinput(menu, fpX + 5, fpY, 10, 2, maxFpProc, NULL); @@ -270,40 +270,37 @@ static void createStatsMenu(struct Menu *menu) { s32 bpX = 1; s32 bpY = 6; menuAddStaticIcon(menu, bpX, bpY, texBpIcon, 0, 0xFFFFFF, 1.0f); - item = menuAddIntinput(menu, bpX + 2, bpY, 10, 2, menuByteModProc, &pm_gPlayerStatus.playerData.maxBP); + item = menuAddIntinput(menu, bpX + 2, bpY, 10, 2, menuByteModProc, &pm_gPlayerData.maxBP); item->tooltip = strBp; s32 coinX = 10; s32 coinY = 2; menuAddStaticIcon(menu, coinX, coinY, texCoin, 0, 0xFFFFFF, 1.0f); - item = menuAddIntinput(menu, coinX + 2, coinY, 10, 3, menuHalfwordModProc, &pm_gPlayerStatus.playerData.coins); + item = menuAddIntinput(menu, coinX + 2, coinY, 10, 3, menuHalfwordModProc, &pm_gPlayerData.coins); item->tooltip = strCoins; s32 starPieceX = 10; s32 starPieceY = 4; menuAddStaticIcon(menu, starPieceX, starPieceY, texStarPiece, 0, 0xFFFFFF, 1.0f); - item = menuAddIntinput(menu, starPieceX + 2, starPieceY, 10, 3, menuByteModProc, - &pm_gPlayerStatus.playerData.starPieces); + item = menuAddIntinput(menu, starPieceX + 2, starPieceY, 10, 3, menuByteModProc, &pm_gPlayerData.starPieces); item->tooltip = strStarPieces; s32 levelX = 17; s32 levelY = 2; menuAddStaticIcon(menu, levelX, levelY, texMarioHead, 0, 0xFFFFFF, 1.0f); - item = menuAddIntinput(menu, levelX + 2, levelY, 10, 2, menuByteModProc, &pm_gPlayerStatus.playerData.level); + item = menuAddIntinput(menu, levelX + 2, levelY, 10, 2, menuByteModProc, &pm_gPlayerData.level); item->tooltip = strLevel; s32 starPointX = 17; s32 starPointY = 4; menuAddStaticIcon(menu, starPointX, starPointY, texStarPoint, 0, 0xFFFFFF, 1.0f); - item = menuAddIntinput(menu, starPointX + 2, starPointY, 10, 2, menuByteModProc, - &pm_gPlayerStatus.playerData.starPoints); + item = menuAddIntinput(menu, starPointX + 2, starPointY, 10, 2, menuByteModProc, &pm_gPlayerData.starPoints); item->tooltip = strStarPoints; s32 actionCommandX = 23; s32 actionCommandY = 2; - item = - menuAddSwitch(menu, actionCommandX, actionCommandY, texLuckyStar, 0, 0, 0xFFFFFF, texLuckyStar, 0, 1, 0xFFFFFF, - 0.7f, FALSE, menuByteSwitchToggleProc, &pm_gPlayerStatus.playerData.hasActionCommands); + item = menuAddSwitch(menu, actionCommandX, actionCommandY, texLuckyStar, 0, 0, 0xFFFFFF, texLuckyStar, 0, 1, + 0xFFFFFF, 0.7f, FALSE, menuByteSwitchToggleProc, &pm_gPlayerData.hasActionCommands); item->tooltip = strActionCommands; } @@ -348,19 +345,17 @@ static void createPartyMenu(struct Menu *menu) { partners[i] = menuAddSwitch(menu, partnerX, partnerY, texPartner, i + 1, 0, 0xFFFFFF, texPartner, i + 1, 1, 0xFFFFFF, scale, FALSE, menuByteSwitchToggleProc, - &pm_gPlayerStatus.playerData.partners[partnerOrder[i + 1]].enabled); + &pm_gPlayerData.partners[partnerOrder[i + 1]].enabled); partners[i]->tooltip = strPartnerNames[i]; // super tex - superRanks[i] = - menuAddSwitch(menu, partnerX + 2, partnerY, texRank, 0, 0, 0xFFFFFF, texRank, 0, 1, 0xFFFFFF, scale, FALSE, - superRankProc, &pm_gPlayerStatus.playerData.partners[partnerOrder[i + 1]]); + superRanks[i] = menuAddSwitch(menu, partnerX + 2, partnerY, texRank, 0, 0, 0xFFFFFF, texRank, 0, 1, 0xFFFFFF, + scale, FALSE, superRankProc, &pm_gPlayerData.partners[partnerOrder[i + 1]]); superRanks[i]->tooltip = strSuperRank; // ultra tex - ultraRanks[i] = - menuAddSwitch(menu, partnerX + 3, partnerY, texRank, 0, 0, 0xFFFFFF, texRank, 0, 1, 0xFFFFFF, scale, FALSE, - ultraRankProc, &pm_gPlayerStatus.playerData.partners[partnerOrder[i + 1]]); + ultraRanks[i] = menuAddSwitch(menu, partnerX + 3, partnerY, texRank, 0, 0, 0xFFFFFF, texRank, 0, 1, 0xFFFFFF, + scale, FALSE, ultraRankProc, &pm_gPlayerData.partners[partnerOrder[i + 1]]); ultraRanks[i]->tooltip = strUltraRank; } menuItemAddChainLink(activeItem, partners[0], MENU_NAVIGATE_DOWN); @@ -399,7 +394,7 @@ static void createStarSpiritMenu(struct Menu *menu) { s8 beamPalettes[] = {1, 0, 0}; u32 beamColors[] = {0xFFFFFF, 0xFFFFFF, 0xFFFFFF}; struct MenuItem *item = menuAddCycle(menu, ssX, ssY, 3, beamTextures, beamTiles, beamPalettes, beamColors, scale, - FALSE, menuByteCycleProc, &pm_gPlayerStatus.playerData.starBeamLevel); + FALSE, menuByteCycleProc, &pm_gPlayerData.starBeamLevel); item->tooltip = strStarPeachBeam; menuItemCreateChain(starSpirits, 8, MENU_NAVIGATE_RIGHT, FALSE, FALSE); menuItemCreateChain(starSpirits, 8, MENU_NAVIGATE_LEFT, FALSE, TRUE); @@ -438,13 +433,13 @@ static void createMerleeMenu(struct Menu *menu) { "+3 DEF\0" "EXP x2\0" "Coins x2\0", - menuByteOptionmodProc, &pm_gPlayerStatus.playerData.merleeSpellType); + menuByteOptionmodProc, &pm_gPlayerData.merleeSpellType); menuAddStatic(menu, 0, yValue, "casts remaining", 0xC0C0C0); - menuAddIntinput(menu, 16, yValue++, 10, 2, menuByteModProc, &pm_gPlayerStatus.playerData.merleeCastsRemaining); + menuAddIntinput(menu, 16, yValue++, 10, 2, menuByteModProc, &pm_gPlayerData.merleeCastsRemaining); menuAddStatic(menu, 0, yValue, "turns remaining", 0xC0C0C0); - menuAddIntinput(menu, 16, yValue++, 10, 3, menuHalfwordModProc, &pm_gPlayerStatus.playerData.merleeTurnCount); + menuAddIntinput(menu, 16, yValue++, 10, 3, menuHalfwordModProc, &pm_gPlayerData.merleeTurnCount); } struct Menu *createPlayerMenu(void) { diff --git a/src/fp/player/items.c b/src/fp/player/items.c index c292ed92..033c95a9 100644 --- a/src/fp/player/items.c +++ b/src/fp/player/items.c @@ -442,7 +442,7 @@ static s16 *itemSlotToUpdate; static s32 badgeProcSwitch(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { u32 badgeId = (u32)data; - s16 *badgeList = pm_gPlayerStatus.playerData.badges; + s16 *badgeList = pm_gPlayerData.badges; if (reason == MENU_CALLBACK_SWITCH_ON) { for (u16 i = 0; i < 128; i++) { if (badgeList[i] == 0) { @@ -457,8 +457,8 @@ static s32 badgeProcSwitch(struct MenuItem *item, enum MenuCallbackReason reason } } for (u16 i = 0; i < 64; i++) { - if (pm_gPlayerStatus.playerData.equippedBadges[i] == badgeId) { - pm_gPlayerStatus.playerData.equippedBadges[i] = 0; + if (pm_gPlayerData.equippedBadges[i] == badgeId) { + pm_gPlayerData.equippedBadges[i] = 0; } } } else if (reason == MENU_CALLBACK_THINK) { diff --git a/src/fp/practice/trainer.c b/src/fp/practice/trainer.c index cbf34a88..c6f2fd84 100644 --- a/src/fp/practice/trainer.c +++ b/src/fp/practice/trainer.c @@ -5,6 +5,7 @@ #include "sys/resource.h" #include "sys/settings.h" #include +#include enum BowserVariant { BOWSER_VARIANT_HALLWAY = 0xC1, @@ -76,6 +77,23 @@ static u16 acLastValidFrame = 0; static u16 clippyFramesSinceBattle = 0; static u8 clippyStatus = 0; +// spin trainer vars +static enum ActionStates spinPrevActionState = ACTION_STATE_IDLE; +static bool spinPrevCanSpin = FALSE; +static s8 spinCanceled = FALSE; +static s8 spinEndTiming = 0; +static bool spinIsJumping = FALSE; +static u16 spinJumpStart = 0; +static s16 spinJumpLast = 1; +static u16 spinDelayStart = 0; +static u16 spinDelayLast = 0; +static s8 spinBufferAttempt = 0; +static s8 spinBufferLast = 0; +static struct GfxTexture *spinAButtonTex = NULL; +static struct GfxTexture *spinBootTex = NULL; +static struct GfxTexture *spinClockTex = NULL; +static struct GfxTexture *spinZButtonTex = NULL; + extern void setACEHook(void); s32 getMatrixTotal(void) { @@ -153,6 +171,15 @@ static s32 pinnedTrainerProc(struct MenuItem *item, enum MenuCallbackReason reas return 0; } +static s32 trainerPositionProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { + if (reason == MENU_CALLBACK_ACTIVATE) { + fp.trainerMoving = TRUE; + } else if (reason == MENU_CALLBACK_DEACTIVATE) { + fp.trainerMoving = FALSE; + } + return menuGenericPositionProc(item, reason, &settings->trainerX); +} + static void lzsDraw(s32 x, s32 y, struct GfxFont *font, s32 chWidth, s32 chHeight, u32 color, u8 alpha) { gfxModeSet(GFX_MODE_COLOR, GPACK_RGB24A8(color, alpha)); s32 menuY = 0; @@ -166,6 +193,157 @@ static s32 lzsDrawProc(struct MenuItem *item, struct MenuDrawParams *drawParams) return 1; } +static s32 spinVisualPositionProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { + if (reason == MENU_CALLBACK_ACTIVATE) { + fp.spinTrainerMoving = TRUE; + } else if (reason == MENU_CALLBACK_DEACTIVATE) { + fp.spinTrainerMoving = FALSE; + } + return menuGenericPositionProc(item, reason, &settings->trainerSpinX); +} + +static void spinDraw(s32 x, s32 y, struct GfxFont *font, s32 chWidth, s32 chHeight, u32 color, u8 alpha) { + if (pm_gGameStatus.isBattle != 0) { + return; + } + + u32 colorInput = GPACK_RGB24A8(color, alpha); + u32 colorBlackT = GPACK_RGB24A8(0x000000, 0x60); + u32 colorWhite = GPACK_RGB24A8(0xFFFFFF, alpha); + u32 colorGreen = GPACK_RGB24A8(0x00FF00, alpha); + u32 colorYellow = GPACK_RGB24A8(0xFFFF00, alpha); + u32 colorRed = GPACK_RGB24A8(0xFF0000, alpha); + + // black background + s32 bgY = y - 11; + s32 bgHeight = 0; + u8 count = 0; + if (settings->trainerSpinJumpTiming) { + count++; + bgHeight += 14; + } + if (settings->trainerSpinJumpLength) { + count++; + bgHeight += 14; + } + if (settings->trainerSpinStartDelay) { + if (count == 0) { + bgY -= 1; + bgHeight += 15; + } else { + bgHeight += 14; + } + } + if (settings->trainerSpinZBuffer) { + bgHeight += 16; + } + if (bgHeight > 0) { + bgHeight += 3; + } + gfxModeSet(GFX_MODE_COLOR, colorBlackT); + gfxModeReplace(GFX_MODE_COMBINE, G_CC_MODE(G_CC_PRIMITIVE, G_CC_PRIMITIVE)); + gfxDisp(gsSPScisTextureRectangle(qs102(x - 2), qs102(bgY), qs102(x + 86), qs102(bgY + bgHeight), 0, 0, 0, 0, 0)); + gfxModePop(GFX_MODE_COMBINE); + + s32 textX = x + 17; + s32 textY = y; + s32 iconY = y; + // jump (and hammer) timing + if (settings->trainerSpinJumpTiming) { + iconY = textY - 9; + gfxModeSet(GFX_MODE_COLOR, colorWhite); + gfxModeReplace(GFX_MODE_DROPSHADOW, 0); + struct GfxSprite aButtonSprite = {spinAButtonTex, 0, 0, x, iconY, 0.3f, 0.3f}; + gfxSpriteDraw(&aButtonSprite); + gfxModePop(GFX_MODE_DROPSHADOW); + if (spinCanceled) { + gfxModeSet(GFX_MODE_COLOR, colorInput); + gfxPrintf(font, textX, textY, "-"); + } else if (spinEndTiming == 0) { + gfxModeSet(GFX_MODE_COLOR, colorGreen); + gfxPrintf(font, textX, textY, "good"); + } else if (spinEndTiming > 0) { + if (spinEndTiming == 1) { + gfxModeSet(GFX_MODE_COLOR, colorYellow); + } else { + gfxModeSet(GFX_MODE_COLOR, colorRed); + } + gfxPrintf(font, textX, textY, "%d early", spinEndTiming); + } else if (spinEndTiming < 0) { + if (spinEndTiming == -1) { + gfxModeSet(GFX_MODE_COLOR, colorYellow); + } else { + gfxModeSet(GFX_MODE_COLOR, colorRed); + } + gfxPrintf(font, textX, textY, "%d late", abs(spinEndTiming)); + } + textY += 14; + } + + // jump length + if (settings->trainerSpinJumpLength) { + iconY = textY - 11; + gfxModeSet(GFX_MODE_COLOR, colorWhite); + gfxModeReplace(GFX_MODE_DROPSHADOW, 0); + struct GfxSprite bootSprite = {spinBootTex, 0, 0, x, iconY, 0.5f, 0.5f}; + gfxSpriteDraw(&bootSprite); + gfxModePop(GFX_MODE_DROPSHADOW); + if (spinCanceled) { + gfxModeSet(GFX_MODE_COLOR, colorInput); + gfxPrintf(font, textX, textY, "-"); + } else { + if (spinJumpLast == 1) { + gfxModeSet(GFX_MODE_COLOR, colorGreen); + } else if (spinJumpLast == 2) { + gfxModeSet(GFX_MODE_COLOR, colorYellow); + } else { + gfxModeSet(GFX_MODE_COLOR, colorRed); + } + gfxPrintf(font, textX, textY, "%d", spinJumpLast); + } + textY += 14; + } + + // start delay + if (settings->trainerSpinStartDelay) { + iconY = textY - 11; + gfxModeSet(GFX_MODE_COLOR, colorWhite); + gfxModeReplace(GFX_MODE_DROPSHADOW, 0); + struct GfxSprite clockSprite = {spinClockTex, 0, 0, x, iconY, 1.f, 1.f}; + gfxSpriteDraw(&clockSprite); + gfxModePop(GFX_MODE_DROPSHADOW); + if (spinDelayLast == 0) { + gfxModeSet(GFX_MODE_COLOR, colorGreen); + } else if (spinDelayLast == 1) { + gfxModeSet(GFX_MODE_COLOR, colorYellow); + } else { + gfxModeSet(GFX_MODE_COLOR, colorRed); + } + gfxPrintf(font, textX, textY, "%d", spinDelayLast); + textY += 14; + } + + // z buffer offset + if (settings->trainerSpinZBuffer) { + iconY = textY - 9; + gfxModeSet(GFX_MODE_COLOR, colorWhite); + gfxModeReplace(GFX_MODE_DROPSHADOW, 0); + struct GfxSprite zButtonSprite = {spinZButtonTex, 0, 0, x + 2, iconY, 1.f, 1.f}; + gfxSpriteDraw(&zButtonSprite); + gfxModePop(GFX_MODE_DROPSHADOW); + if (spinBufferLast == -1) { + gfxModeSet(GFX_MODE_COLOR, colorInput); + gfxPrintf(font, textX, textY, "-"); + } else if (spinBufferLast < 10) { + gfxModeSet(GFX_MODE_COLOR, colorGreen); + gfxPrintf(font, textX, textY, "good"); + } else { + gfxModeSet(GFX_MODE_COLOR, colorRed); + gfxPrintf(font, textX, textY, "%d early", spinBufferLast - 9); + } + } +} + static void issDraw(s32 x, s32 y, struct GfxFont *font, s32 chWidth, s32 chHeight, u32 color, u8 alpha) { gfxModeSet(GFX_MODE_COLOR, GPACK_RGB24A8(color, alpha)); @@ -451,6 +629,68 @@ static void updateLzsTrainer(void) { } } +static void updateSpinTrainer(void) { + if (!(pm_gGameStatus.isBattle != 1 && + (settings->trainerSpinBarEnabled || settings->pinnedTrainer == TRAINER_SPIN))) { + return; + } + + enum ActionStates actionState = pm_gPlayerStatus.actionState; + pm_PlayerSpinState *spinState = &pm_gPlayerSpinState; + + // end timing and jump length + if (spinPrevActionState == ACTION_STATE_SPIN) { + if (actionState == ACTION_STATE_JUMP || actionState == ACTION_STATE_HAMMER) { + spinCanceled = FALSE; + spinBufferLast = spinBufferAttempt; + s8 perfectEndTiming = 7; + if (pm_is_ability_active(ABILITY_SPEEDY_SPIN)) { + perfectEndTiming = 8; + } + spinEndTiming = spinState->spinCountdown - perfectEndTiming; + + if (pm_gPlayerStatus.actionState == ACTION_STATE_JUMP) { + spinIsJumping = TRUE; + spinJumpStart = pm_gGameStatus.frameCounter; + } + } else if (actionState != ACTION_STATE_SPIN) { + spinCanceled = TRUE; + spinBufferLast = spinBufferAttempt; + } + } else if (spinIsJumping && (!pm_gGameStatus.currentButtons[0].a || actionState != ACTION_STATE_JUMP)) { + spinIsJumping = FALSE; + spinJumpLast = pm_gGameStatus.frameCounter - spinJumpStart; + } + + // delay between spins + bool canSpin = !(pm_gPlayerStatus.flags & (PS_FLAG_NO_STATIC_COLLISION | PS_FLAG_CUTSCENE_MOVEMENT | + PS_FLAG_INPUT_DISABLED | PS_FLAG_PAUSED) || + pm_gPlayerStatus.animFlags & (PA_FLAG_USING_WATT | PA_FLAG_SPINNING)) && + actionState < ACTION_STATE_JUMP; + if (canSpin && !spinPrevCanSpin) { + spinDelayStart = pm_gGameStatus.frameCounter; + if (!(actionState == ACTION_STATE_RUN && pm_gPlayerStatus.prevActionState == ACTION_STATE_WALK && + spinPrevActionState == ACTION_STATE_IDLE)) { + // note that there are a lot of rare edge cases here that just aren't worth handling + spinDelayStart += 1; + } + } + if (actionState == ACTION_STATE_SPIN && spinState->initialSpinTime - spinState->spinCountdown == 1) { + // start of new spin + if (!spinPrevCanSpin) { + spinDelayLast = 0; + } else { + spinDelayLast = pm_gGameStatus.frameCounter - spinDelayStart; + } + spinBufferAttempt = -1; + } else if (actionState == ACTION_STATE_SPIN && pm_gGameStatus.pressedButtons[0].z) { + spinBufferAttempt = spinState->spinCountdown; + } + + spinPrevActionState = actionState; + spinPrevCanSpin = canSpin; +} + static void blockCheckSuccessOrEarly(void) { const u32 mashWindow = 10; u32 blockWindow = 3; @@ -520,7 +760,7 @@ static void updateBlockTrainer(void) { } // Either goombario or mario attacking - if ((pm_gBattleSubState == 3 && pm_gPlayerStatus.playerData.currentPartner == PARTNER_GOOMBARIO) || + if ((pm_gBattleSubState == 3 && pm_gPlayerData.currentPartner == PARTNER_GOOMBARIO) || pm_gBattleSubState == 4) { if (pm_gActionCommandStatus.state == 10 && pm_gGameStatus.pressedButtons[0].a) { acLastAPress = pm_gGameStatus.frameCounter; @@ -668,9 +908,105 @@ static void updateHammerCancelTrainer(void) { } } +void trainerDrawSpinBar(s32 x, s32 y, struct GfxFont *font, u32 color, u8 alpha) { + u32 colorInput = GPACK_RGB24A8(color, alpha); + u32 colorWhite = GPACK_RGB24A8(0xFFFFFF, alpha); + u32 colorBlackT = GPACK_RGB24A8(0x000000, 0x60); + u32 colorGreen = GPACK_RGB24A8(0x00FF00, alpha); + u32 colorYellow = GPACK_RGB24A8(0xFFFF00, alpha); + u32 colorRed = GPACK_RGB24A8(0xFF0000, alpha); + u32 colorBackground = GPACK_RGB24A8(0x000000, alpha); + u32 colorEmpty = GPACK_RGB24A8(0x000095, alpha); + u32 colorFull = GPACK_RGB24A8(0x00E486, alpha); + + u8 barMult = 3; + s8 spinFrame = 25 - pm_gPlayerSpinState.spinCountdown; + u16 barWidth = 25; + u16 barGoal = 18; + if (pm_is_ability_active(ABILITY_SPEEDY_SPIN)) { + spinFrame = 30 - pm_gPlayerSpinState.spinCountdown; + barWidth = 30; + barGoal = 22; + } + barWidth *= barMult; + barGoal *= barMult; + u16 barX = x - barWidth / 2; + u16 barGoalX = barX + barGoal; + u16 barFullX = barX + spinFrame * barMult; + u16 barYBottom = y + 10; + + s32 iconY = y + 12; + s32 textY = iconY + 11; + s32 jumpIconX = x - 30; + s32 jumpTextX = jumpIconX + 17; + s32 delayIconX = x + 2; + s32 delayTextX = delayIconX + 17; + + // draw background + gfxModeSet(GFX_MODE_COLOR, colorBlackT); + gfxModeReplace(GFX_MODE_COMBINE, G_CC_MODE(G_CC_PRIMITIVE, G_CC_PRIMITIVE)); + gfxDisp(gsSPScisTextureRectangle(qs102(barX - 4), qs102(y - 4), qs102(barX + barWidth + 4), qs102(y + 30), 0, 0, 0, + 0, 0)); + + // draw bar + // background + gfxModeSet(GFX_MODE_COLOR, colorBackground); + gfxDisp(gsSPScisTextureRectangle(qs102(barX - 1), qs102(y - 1), qs102(barX + barWidth + 1), qs102(barYBottom + 1), + 0, 0, 0, 0, 0)); + // empty bar + gfxModeSet(GFX_MODE_COLOR, colorEmpty); + gfxDisp(gsSPScisTextureRectangle(qs102(barX), qs102(y), qs102(barX + barWidth), qs102(barYBottom), 0, 0, 0, 0, 0)); + // full bar + gfxModeSet(GFX_MODE_COLOR, colorFull); + gfxDisp(gsSPScisTextureRectangle(qs102(barX), qs102(y), qs102(barFullX), qs102(barYBottom), 0, 0, 0, 0, 0)); + // goal marker + gfxModeSet(GFX_MODE_COLOR, colorYellow); + gfxDisp( + gsSPScisTextureRectangle(qs102(barGoalX - 1), qs102(y), qs102(barGoalX + 1), qs102(barYBottom), 0, 0, 0, 0, 0)); + gfxModePop(GFX_MODE_COMBINE); + + gfxModeSet(GFX_MODE_COLOR, colorWhite); + gfxModeReplace(GFX_MODE_DROPSHADOW, 0); + struct GfxSprite bootSprite = {spinBootTex, 0, 0, jumpIconX, iconY, 0.5f, 0.5f}; + struct GfxSprite clockSprite = {spinClockTex, 0, 0, delayIconX, iconY, 1.f, 1.f}; + gfxSpriteDraw(&bootSprite); + gfxSpriteDraw(&clockSprite); + gfxModePop(GFX_MODE_DROPSHADOW); + + // jump length + if (spinCanceled) { + gfxModeSet(GFX_MODE_COLOR, colorInput); + gfxPrintf(font, jumpTextX, textY, "-"); + } else { + if (spinJumpLast == 1) { + gfxModeSet(GFX_MODE_COLOR, colorGreen); + } else if (spinJumpLast == 2) { + gfxModeSet(GFX_MODE_COLOR, colorYellow); + } else { + gfxModeSet(GFX_MODE_COLOR, colorRed); + } + gfxPrintf(font, jumpTextX, textY, "%d", spinJumpLast); + } + + // start delay + if (spinDelayLast == 0) { + gfxModeSet(GFX_MODE_COLOR, colorGreen); + } else if (spinDelayLast == 1) { + gfxModeSet(GFX_MODE_COLOR, colorYellow); + } else { + gfxModeSet(GFX_MODE_COLOR, colorRed); + } + if (spinDelayLast < 100) { + gfxPrintf(font, delayTextX, textY, "%d", spinDelayLast); + } else { + gfxPrintf(font, delayTextX, textY, "99"); + } +} + void trainerUpdate(void) { updateBowserBlockTrainer(); updateLzsTrainer(); + updateSpinTrainer(); updateBlockTrainer(); updateClippyTrainer(); updateQuickJumpTrainer(); @@ -680,6 +1016,7 @@ void trainerUpdate(void) { void trainerDrawPinned(s32 x, s32 y, struct GfxFont *font, s32 chWidth, s32 chHeight, u32 color, u8 alpha) { switch (settings->pinnedTrainer) { case TRAINER_LZS: lzsDraw(x, y, font, chWidth, chHeight, color, alpha); break; + case TRAINER_SPIN: spinDraw(x, y, font, chWidth, chHeight, color, alpha); break; case TRAINER_ISS: issDraw(x, y, font, chWidth, chHeight, color, alpha); break; case TRAINER_ACE: aceDraw(x, y, font, chWidth, chHeight, color, alpha); break; } @@ -687,12 +1024,14 @@ void trainerDrawPinned(s32 x, s32 y, struct GfxFont *font, s32 chWidth, s32 chHe void createTrainerMenu(struct Menu *menu) { static struct Menu lzsMenu; + static struct Menu spinMenu; static struct Menu issMenu; static struct Menu aceMenu; /* initialize menu */ menuInit(menu, MENU_NOVALUE, MENU_NOVALUE, MENU_NOVALUE); menuInit(&lzsMenu, MENU_NOVALUE, MENU_NOVALUE, MENU_NOVALUE); + menuInit(&spinMenu, MENU_NOVALUE, MENU_NOVALUE, MENU_NOVALUE); menuInit(&issMenu, MENU_NOVALUE, MENU_NOVALUE, MENU_NOVALUE); menuInit(&aceMenu, MENU_NOVALUE, MENU_NOVALUE, MENU_NOVALUE); @@ -731,8 +1070,10 @@ void createTrainerMenu(struct Menu *menu) { menuAddCheckbox(menu, xOffset, y++, menuByteCheckboxProc, &settings->trainerHammerCancelsEnabled); menuAddStatic(menu, 0, y, "clippy", 0xC0C0C0); - struct MenuItem *lastOption = - menuAddCheckbox(menu, xOffset, y++, menuByteCheckboxProc, &settings->trainerClippyEnabled); + menuAddCheckbox(menu, xOffset, y++, menuByteCheckboxProc, &settings->trainerClippyEnabled); + + menuAddStatic(menu, 0, y, "spin", 0xC0C0C0); + struct MenuItem *lastOption = menuAddSubmenuIcon(menu, xOffset, y++, &spinMenu, wrench, 0, 0, 1.0f); #if PM64_VERSION == JP menuAddStatic(menu, 0, y, "ice staircase skip", 0xC0C0C0); menuAddSubmenuIcon(menu, xOffset, y++, &issMenu, wrench, 0, 0, 1.0f); @@ -755,6 +1096,29 @@ void createTrainerMenu(struct Menu *menu) { y++; menuAddStaticCustom(&lzsMenu, 0, y++, lzsDrawProc, NULL, 0xC0C0C0); + /*build spin menu*/ + y = 0; + xOffset = 15; + spinAButtonTex = resourceLoadPmiconGlobal(ICON_A_BUTTON, 1); + spinBootTex = resourceLoadPmiconGlobal(ICON_MENU_BOOTS_1, 1); + spinClockTex = resourceGet(RES_PMICON_CLOCK); + spinZButtonTex = resourceGet(RES_PMICON_Z_BUTTON); + spinMenu.selector = menuAddSubmenu(&spinMenu, 0, y++, NULL, "return"); + menuAddStatic(&spinMenu, 0, y, "timing bar", 0xC0C0C0); + menuAddCheckbox(&spinMenu, xOffset, y, menuByteCheckboxProc, &settings->trainerSpinBarEnabled); + menuAddPositioning(&spinMenu, xOffset + 2, y++, spinVisualPositionProc, NULL); + menuAddStatic(&spinMenu, 0, y, "detailed stats", 0xC0C0C0); + menuAddCheckbox(&spinMenu, xOffset, y, pinnedTrainerProc, (void *)TRAINER_SPIN); + menuAddPositioning(&spinMenu, xOffset + 2, y++, trainerPositionProc, NULL); + menuAddStatic(&spinMenu, 1, y, "jump timing", 0xC0C0C0); + menuAddCheckbox(&spinMenu, xOffset, y++, menuByteCheckboxProc, &settings->trainerSpinJumpTiming); + menuAddStatic(&spinMenu, 1, y, "jump length", 0xC0C0C0); + menuAddCheckbox(&spinMenu, xOffset, y++, menuByteCheckboxProc, &settings->trainerSpinJumpLength); + menuAddStatic(&spinMenu, 1, y, "start delay", 0xC0C0C0); + menuAddCheckbox(&spinMenu, xOffset, y++, menuByteCheckboxProc, &settings->trainerSpinStartDelay); + menuAddStatic(&spinMenu, 1, y, "z buffer", 0xC0C0C0); + menuAddCheckbox(&spinMenu, xOffset, y++, menuByteCheckboxProc, &settings->trainerSpinZBuffer); + /*build iss menu*/ y = 0; issMenu.selector = menuAddSubmenu(&issMenu, 0, y++, NULL, "return"); diff --git a/src/fp/practice/trainer.h b/src/fp/practice/trainer.h index e3c994c0..a4a2fb9b 100644 --- a/src/fp/practice/trainer.h +++ b/src/fp/practice/trainer.h @@ -4,10 +4,12 @@ enum PinnedTrainer { TRAINER_LZS, + TRAINER_SPIN, TRAINER_ISS, TRAINER_ACE, }; +void trainerDrawSpinBar(s32 x, s32 y, struct GfxFont *font, u32 color, u8 alpha); void trainerUpdate(void); void trainerDrawPinned(s32 x, s32 y, struct GfxFont *font, s32 chWidth, s32 chHeight, u32 color, u8 alpha); void createTrainerMenu(struct Menu *menu); diff --git a/src/menu/menu_item_button.c b/src/menu/menu_item_button.c index a0d16b0f..1f60646a 100644 --- a/src/menu/menu_item_button.c +++ b/src/menu/menu_item_button.c @@ -28,11 +28,11 @@ static s16 getEmptyIcon(enum ItemType type) { static s16 *getItemSlot(enum ItemType type, s16 itemIndex) { switch (type) { - case ITEM_TYPE_NORMAL: return &pm_gPlayerStatus.playerData.invItems[itemIndex]; - case ITEM_TYPE_KEY: return &pm_gPlayerStatus.playerData.keyItems[itemIndex]; - case ITEM_TYPE_STORED: return &pm_gPlayerStatus.playerData.storedItems[itemIndex]; + case ITEM_TYPE_NORMAL: return &pm_gPlayerData.invItems[itemIndex]; + case ITEM_TYPE_KEY: return &pm_gPlayerData.keyItems[itemIndex]; + case ITEM_TYPE_STORED: return &pm_gPlayerData.storedItems[itemIndex]; case ITEM_TYPE_BADGE: - default: return &pm_gPlayerStatus.playerData.badges[itemIndex]; + default: return &pm_gPlayerData.badges[itemIndex]; } } diff --git a/src/pm64.h b/src/pm64.h index 5e9a6aca..d5908200 100644 --- a/src/pm64.h +++ b/src/pm64.h @@ -15,16 +15,20 @@ #if PM64_VERSION == US #define SCRIPTS_GLOBAL_START 0x801049B0 -#define ICONS_ITEMS_ROM_START 0x1CC310 -#define ICONS_PARTNERS_ROM_START 0x97890 #define ICONS_STAR_SPIRITS_ROM_START 0x963B0 +#define ICONS_PARTNERS_ROM_START 0x97890 #define ICONS_BP_ROM_START 0x134520 +#define ICONS_CLOCK_ROM_START 0x134660 +#define ICONS_Z_BUTTON_ROM_START 0x1B8A60 +#define ICONS_ITEMS_ROM_START 0x1CC310 #else #define SCRIPTS_GLOBAL_START 0x80104b40 -#define ICONS_ITEMS_ROM_START 0x1D4720 -#define ICONS_PARTNERS_ROM_START 0x97A20 #define ICONS_STAR_SPIRITS_ROM_START 0x96540 +#define ICONS_PARTNERS_ROM_START 0x97A20 #define ICONS_BP_ROM_START 0x13C820 +#define ICONS_CLOCK_ROM_START 0x13C960 +#define ICONS_Z_BUTTON_ROM_START 0x1C0E70 +#define ICONS_ITEMS_ROM_START 0x1D4720 #endif #define SCRIPT_BOWSER_HALLWAY_TAKE_TURN 0x80222B48 @@ -403,9 +407,9 @@ typedef struct pm_PlayerStatus { /* 0x0AC */ char unk_0xAC[4]; /* 0x0B0 */ s16 colliderHeight; /* 0x0B2 */ s16 colliderDiameter; - /* 0x0B4 */ u8 actionState; - /* 0x0B5 */ u8 prevActionState; - /* 0x0B6 */ s8 fallState; /*also used as sleep state in Peach idle action*/ + /* 0x0B4 */ s8 actionState; + /* 0x0B5 */ s8 prevActionState; + /* 0x0B6 */ s8 actionSubstate; /* 0x0B7 */ char unk_B7; /* 0x0B8 */ u32 anim; /* 0x0BC */ u16 unk_BC; @@ -432,19 +436,28 @@ typedef struct pm_PlayerStatus { /* 0x168 */ s32 stickAxisXBuffer[10]; /* 0x190 */ s32 stickAxisYBuffer[10]; /* 0x1B8 */ s32 inputBufPos; - /* 0x1BC */ char unk_0x1BC[0xCC]; - /* 0x288 */ u8 spinCooldownTimer; /*4 frames at the end of spin*/ - /* 0x289 */ char unk_0x289[0x02]; - /* 0x28B */ u8 spinTimer; - /* 0x28C */ char unk_0x28C[0x20]; - /* 0x2AC */ f32 spinSpeed; - /* 0x2B0 */ char unk_0x2B0[0x04]; - /* 0x2B4 */ char unk_0x2B4[0x01]; - /* 0x2B5 */ u8 spinDuration; - /* 0x2B6 */ char unk_0x228[0x02]; - /* 0x2B8 */ char unk_0x2B8[0x10]; - /* 0x2C8 */ pm_PlayerData playerData; -} pm_PlayerStatus; // size = 0x6F0 + /* 0x1BC */ char unk_0x1BC[196]; + /* 0x280 */ s8 poundImpactDelay; // governs period of immobility after landing a ground pound + /* 0x281 */ char unk_281[7]; +} pm_PlayerStatus; // size = 0x288 + +typedef struct pm_PlayerSpinState { + /* 0x00 */ s8 stopSoundTimer; + /* 0x01 */ s8 hasBufferedSpin; + /* 0x02 */ s8 hitWallTime; // incremented while blocked by a wall + /* 0x03 */ s8 spinCountdown; + /* 0x04 */ s32 prevActionState; + /* 0x08 */ Vec2i bufferedStickAxis; + /* 0x10 */ f32 spinDirectionMagnitude; + /* 0x14 */ Vec2f spinDirection; + /* 0x1C */ f32 inputMagnitude; + /* 0x20 */ f32 spinRate; + /* 0x24 */ f32 speedScale; + /* 0x28 */ f32 frictionScale; + /* 0x2C */ s16 initialSpinTime; + /* 0x2E */ s16 fullSpeedSpinTime; + /* 0x30 */ s32 spinSoundID; +} pm_PlayerSpinState; // size = 0x34 typedef struct pm_SaveMetadata { /* 0x00 */ s32 timePlayed; @@ -1381,6 +1394,8 @@ extern_data s32 pm_gPopupState; extern_data pm_PartnerStatus pm_gPartnerStatus; extern_data pm_UiStatus pm_gUiStatus; extern_data pm_PlayerStatus pm_gPlayerStatus; +extern_data pm_PlayerSpinState pm_gPlayerSpinState; +extern_data pm_PlayerData pm_gPlayerData; extern_data pm_HudElementSize pm_gHudElementSizes[26]; extern_data s16 pm_MusicCurrentVolume; extern_data pm_ActionCommandStatus pm_gActionCommandStatus; @@ -1432,7 +1447,7 @@ s32 pm_player_raycast_general(s32 mode, f32 startX, f32 startY, f32 startZ, f32 f32 *hitY, f32 *hitZ, f32 *hitDepth, f32 *hitNx, f32 *hitNy, f32 *hitNz); void pm_disable_player_input(void); void pm_update_player_input(void); -s32 pm_is_ability_active(s32 arg0); +s32 pm_is_ability_active(enum Abilities ability); void pm_hide_popup_menu(void); void pm_destroy_popup_menu(void); void pm_state_render_frontUI(void); diff --git a/src/sys/resource.c b/src/sys/resource.c index 6b86d49e..ce2c01e4 100644 --- a/src/sys/resource.c +++ b/src/sys/resource.c @@ -217,6 +217,20 @@ static void *rcPmiconBp(void) { return gfxTextureLoad(&td, NULL); } +static void *rcPmiconClock(void) { + struct GfxTexdesc td = { + G_IM_FMT_CI, G_IM_SIZ_4b, 0, 16, 16, 1, 1, ICONS_CLOCK_ROM_START, VSIZE(16, 16, G_IM_SIZ_4b, 1, 1), 1, + }; + return gfxTextureLoad(&td, NULL); +} + +static void *rcPmiconZButton(void) { + struct GfxTexdesc td = { + G_IM_FMT_CI, G_IM_SIZ_4b, 0, 16, 16, 1, 1, ICONS_Z_BUTTON_ROM_START, VSIZE(16, 16, G_IM_SIZ_4b, 1, 1), 1, + }; + return gfxTextureLoad(&td, NULL); +} + static void *rcIconCheck(void) { return resourceLoadGrcTexture("check_icons"); } @@ -270,11 +284,11 @@ static void rdFontGeneric(void *data) { /* resource management tables */ static void *(*resCtor[RES_MAX])(void) = { - rcFontFipps, rcFontNotalot35, rcFontOrigamimommy, rcFontPcsenior, rcFontPixelintv, - rcFontPressstart2p, rcFontSmwtextnc, rcFontWerdnasreturn, rcFontPixelzim, rcPmiconPartner, - rcPmiconStarSpirits, rcPmiconBp, rcIconCheck, rcIconButtons, rcIconPause, - rcIconMacro, rcIconMovie, rcIconArrow, rcIconFile, rcIconSave, - rcIconOsk, rcTextureCrosshair, rcTextureControlStick, + rcFontFipps, rcFontNotalot35, rcFontOrigamimommy, rcFontPcsenior, rcFontPixelintv, + rcFontPressstart2p, rcFontSmwtextnc, rcFontWerdnasreturn, rcFontPixelzim, rcPmiconPartner, + rcPmiconStarSpirits, rcPmiconBp, rcPmiconClock, rcPmiconZButton, rcIconCheck, + rcIconButtons, rcIconPause, rcIconMacro, rcIconMovie, rcIconArrow, + rcIconFile, rcIconSave, rcIconOsk, rcTextureCrosshair, rcTextureControlStick, }; static void (*resDtor[RES_MAX])() = { diff --git a/src/sys/resource.h b/src/sys/resource.h index e7eb574b..7ebf761e 100644 --- a/src/sys/resource.h +++ b/src/sys/resource.h @@ -16,6 +16,8 @@ enum ResourceId { RES_PMICON_PARTNERS, RES_PMICON_STAR_SPIRITS, RES_PMICON_BP, + RES_PMICON_CLOCK, + RES_PMICON_Z_BUTTON, RES_ICON_CHECK, RES_ICON_BUTTONS, RES_ICON_PAUSE, diff --git a/src/sys/settings.c b/src/sys/settings.c index 977aba85..653e6af3 100644 --- a/src/sys/settings.c +++ b/src/sys/settings.c @@ -49,6 +49,11 @@ void settingsLoadDefault(void) { d->trainerBowserEnabled = 0; d->trainerClippyEnabled = 0; d->trainerLzsEnabled = 0; + d->trainerSpinBarEnabled = 0; + d->trainerSpinJumpTiming = 1; + d->trainerSpinJumpLength = 1; + d->trainerSpinStartDelay = 1; + d->trainerSpinZBuffer = 1; d->trainerDisplayPinned = 0; d->menuX = 16; d->menuY = 60; @@ -60,6 +65,8 @@ void settingsLoadDefault(void) { d->timerY = 68; d->trainerX = 16; d->trainerY = 68; + d->trainerSpinX = SCREEN_WIDTH / 2; + d->trainerSpinY = SCREEN_HEIGHT - 65; d->binds[COMMAND_MENU] = bindMake(2, BUTTON_R, BUTTON_D_UP); d->binds[COMMAND_RETURN] = bindMake(2, BUTTON_R, BUTTON_D_LEFT); d->binds[COMMAND_LEVITATE] = bindMake(1, BUTTON_D_UP); diff --git a/src/sys/settings.h b/src/sys/settings.h index f5bd7ae3..347e1429 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 8 +#define SETTINGS_VERSION 9 #define SETTINGS_FIO_PAGE 7 #define SETTINGS_WATCHES_MAX 18 @@ -55,6 +55,8 @@ struct SettingsData { s16 timerY; s16 trainerX; s16 trainerY; + s16 trainerSpinX; + s16 trainerSpinY; s16 watchX[SETTINGS_WATCHES_MAX]; s16 watchY[SETTINGS_WATCHES_MAX]; u16 binds[SETTINGS_BIND_MAX]; @@ -76,6 +78,11 @@ struct SettingsData { u8 trainerClippyEnabled; u8 trainerQuickJumpsEnabled; u8 trainerHammerCancelsEnabled; + u8 trainerSpinBarEnabled; + u8 trainerSpinJumpTiming; + u8 trainerSpinJumpLength; + u8 trainerSpinStartDelay; + u8 trainerSpinZBuffer; u8 trainerDisplayPinned; u8 battleDebug; u8 quickLaunch; diff --git a/src/types.h b/src/types.h index ac74024b..e029cb3e 100644 --- a/src/types.h +++ b/src/types.h @@ -46,6 +46,16 @@ typedef struct { /* 0x04 */ s16 z; } Vec3s; // size = 0x06 +typedef struct Vec2i { + /* 0x00 */ s32 x; + /* 0x04 */ s32 y; +} Vec2i; // size = 0x08 + +typedef struct Vec2f { + /* 0x00 */ f32 x; + /* 0x04 */ f32 y; +} Vec2f; // size = 0x08 + typedef f32 Matrix4f[4][4]; // size = 0x40 typedef struct Matrix4s {