diff --git a/docs/tutorials/how_to_new_trainer_slide.md b/docs/tutorials/how_to_new_trainer_slide.md index f8fa345ba6..67c29a437d 100644 --- a/docs/tutorials/how_to_new_trainer_slide.md +++ b/docs/tutorials/how_to_new_trainer_slide.md @@ -70,11 +70,11 @@ If your new Trainer Slide needs to check for beforen initalized, a function is d ```diff void SetTrainerSlideMessage(enum DifficultyLevel, u32, u32); -void TryInitalizeFirstSTABMoveTrainerSlide(u32, u32, u32); -void TryInitalizeTrainerSlidePlayerLandsFirstCriticalHit(u32); -+ void TryInitalizeTrainerSlideEnemyLandsFirstCriticalHit(u32); -void TryInitalizeTrainerSlidePlayerLandsFirstSuperEffectiveHit(u32); -void TryInitalizeTrainerSlideEnemyMonUnaffected(u32); +void TryInitializeFirstSTABMoveTrainerSlide(u32, u32, u32); +void TryInitializeTrainerSlidePlayerLandsFirstCriticalHit(u32); ++ void TryInitializeTrainerSlideEnemyLandsFirstCriticalHit(u32); +void TryInitializeTrainerSlidePlayerLandsFirstSuperEffectiveHit(u32); +void TryInitializeTrainerSlideEnemyMonUnaffected(u32); bool32 IsTrainerSlideInitialized(enum TrainerSlideType); ``` ### `src/trainer_slide.c` @@ -111,7 +111,7 @@ The function that determines if a Slide should play has different function for m InitalizeTrainerSlide(slideId); } -+void TryInitalizeTrainerSlideEnemyLandsFirstCriticalHit(u32 target) ++void TryInitializeTrainerSlideEnemyLandsFirstCriticalHit(u32 target) +{ + enum TrainerSlideType slideId = TRAINER_SLIDE_ENEMY_LANDS_FIRST_CRITICAL_HIT; + @@ -150,13 +150,13 @@ In `BattleTurnPassed`, most Trainer Slides are checked to see if they should run { PrepareStringBattle(STRINGID_CRITICALHIT, gBattlerAttacker); -+ TryInitalizeTrainerSlideEnemyLandsFirstCriticalHit(gBattlerTarget); - TryInitalizeTrainerSlidePlayerLandsFirstCriticalHit(gBattlerTarget); ++ TryInitializeTrainerSlideEnemyLandsFirstCriticalHit(gBattlerTarget); + TryInitializeTrainerSlidePlayerLandsFirstCriticalHit(gBattlerTarget); gBattleCommunication[MSG_DISPLAY] = 1; ``` -The actual usage of `TryInitalizeTrainerSlideEnemyLandsFirstCriticalHit` is added and is checked whenever a critical hit is scored. +The actual usage of `TryInitializeTrainerSlideEnemyLandsFirstCriticalHit` is added and is checked whenever a critical hit is scored. ### `test/battle/trainer_slides.c` ```diff diff --git a/include/battle.h b/include/battle.h index 573283972a..13fc659768 100644 --- a/include/battle.h +++ b/include/battle.h @@ -128,7 +128,7 @@ struct DisableStruct u16 overwrittenAbility; // abilities overwritten during battle (keep separate from battle history in case of switching) u8 boosterEnergyActivates:1; u8 roostActive:1; - u8 unbrudenActive:1; + u8 unburdenActive:1; u8 startEmergencyExit:1; u8 neutralizingGas:1; u8 iceFaceActivationPrevention:1; // fixes hit escape move edge case diff --git a/include/trainer_slide.h b/include/trainer_slide.h index c6f7b745e8..19fdf7c24a 100644 --- a/include/trainer_slide.h +++ b/include/trainer_slide.h @@ -12,11 +12,11 @@ struct MessageStatus void SetTrainerSlideMessage(enum DifficultyLevel difficulty, u32 trainerId, u32 slideId); enum TrainerSlideTargets ShouldDoTrainerSlide(u32 battler, enum TrainerSlideType slideId); -void TryInitalizeFirstSTABMoveTrainerSlide(u32 battlerDef, u32 battlerAtk, u32 moveType); -void TryInitalizeTrainerSlidePlayerLandsFirstCriticalHit(u32 target); -void TryInitalizeTrainerSlideEnemyLandsFirstCriticalHit(u32 target); -void TryInitalizeTrainerSlidePlayerLandsFirstSuperEffectiveHit(u32 target); -void TryInitalizeTrainerSlideEnemyMonUnaffected(u32 target); +void TryInitializeFirstSTABMoveTrainerSlide(u32 battlerDef, u32 battlerAtk, u32 moveType); +void TryInitializeTrainerSlidePlayerLandsFirstCriticalHit(u32 target); +void TryInitializeTrainerSlideEnemyLandsFirstCriticalHit(u32 target); +void TryInitializeTrainerSlidePlayerLandsFirstSuperEffectiveHit(u32 target); +void TryInitializeTrainerSlideEnemyMonUnaffected(u32 target); bool32 IsTrainerSlideInitialized(enum TrainerSlideType slideId); bool32 IsTrainerSlidePlayed(enum TrainerSlideType slideId); void InitalizeTrainerSlide(enum TrainerSlideType slideId); diff --git a/src/battle_main.c b/src/battle_main.c index 3d3c70b37b..81e1e9821d 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3777,6 +3777,7 @@ static void TryDoEventsBeforeFirstTurn(void) #endif // TESTING gBattleStruct->speedTieBreaks = RandomUniform(RNG_SPEED_TIE, 0, Factorial(MAX_BATTLERS_COUNT) - 1); + gBattleTurnCounter = 0; for (i = 0; i < gBattlersCount; i++) gBattlerByTurnOrder[i] = i; @@ -3901,7 +3902,6 @@ static void TryDoEventsBeforeFirstTurn(void) gBattleScripting.moveendState = 0; gBattleStruct->faintedActionsState = 0; gBattleStruct->turnCountersTracker = 0; - gBattleTurnCounter = 0; memset(gQueuedStatBoosts, 0, sizeof(gQueuedStatBoosts)); SetShellSideArmCategory(); @@ -4778,7 +4778,7 @@ u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect) // various effects if (gSideStatuses[GetBattlerSide(battler)] & SIDE_STATUS_TAILWIND) speed *= 2; - if (gDisableStructs[battler].unbrudenActive) + if (gDisableStructs[battler].unburdenActive) speed *= 2; // paralysis drop diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 2faa37564d..76211934c0 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -2698,8 +2698,8 @@ static void Cmd_critmessage(void) { PrepareStringBattle(STRINGID_CRITICALHIT, gBattlerAttacker); - TryInitalizeTrainerSlideEnemyLandsFirstCriticalHit(gBattlerTarget); - TryInitalizeTrainerSlidePlayerLandsFirstCriticalHit(gBattlerTarget); + TryInitializeTrainerSlideEnemyLandsFirstCriticalHit(gBattlerTarget); + TryInitializeTrainerSlidePlayerLandsFirstCriticalHit(gBattlerTarget); gBattleCommunication[MSG_DISPLAY] = 1; } @@ -2846,7 +2846,7 @@ static void Cmd_resultmessage(void) stringId = STRINGID_SUPEREFFECTIVE; } if (stringId == STRINGID_SUPEREFFECTIVE || stringId == STRINGID_SUPEREFFECTIVETWOFOES) - TryInitalizeTrainerSlidePlayerLandsFirstSuperEffectiveHit(gBattlerTarget); + TryInitializeTrainerSlidePlayerLandsFirstSuperEffectiveHit(gBattlerTarget); break; case MOVE_RESULT_NOT_VERY_EFFECTIVE: if (IsDoubleSpreadMove()) @@ -3051,7 +3051,7 @@ static void CheckSetUnburden(u8 battler) { if (GetBattlerAbility(battler) == ABILITY_UNBURDEN) { - gDisableStructs[battler].unbrudenActive = TRUE; + gDisableStructs[battler].unburdenActive = TRUE; RecordAbilityBattle(battler, ABILITY_UNBURDEN); } } @@ -3074,7 +3074,7 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem) RecordItemEffectBattle(battlerStealer, ItemId_GetHoldEffect(gLastUsedItem)); gBattleMons[battlerStealer].item = gLastUsedItem; - gDisableStructs[battlerStealer].unbrudenActive = FALSE; + gDisableStructs[battlerStealer].unburdenActive = FALSE; BtlController_EmitSetMonData(battlerStealer, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gLastUsedItem), &gLastUsedItem); // set attacker item MarkBattlerForControllerExec(battlerStealer); } @@ -8606,7 +8606,7 @@ static void BestowItem(u32 battlerAtk, u32 battlerDef) gBattleMons[battlerDef].item = gLastUsedItem; BtlController_EmitSetMonData(battlerDef, BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[battlerDef].item), &gBattleMons[battlerDef].item); MarkBattlerForControllerExec(battlerDef); - gDisableStructs[battlerDef].unbrudenActive = FALSE; + gDisableStructs[battlerDef].unburdenActive = FALSE; } // Called by Cmd_removeitem. itemId represents the item that was removed, not being given. @@ -14658,8 +14658,8 @@ static void Cmd_tryswapitems(void) } else if (oldItemAtk == ITEM_NONE && *newItemAtk != ITEM_NONE) { - if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNBURDEN && gDisableStructs[gBattlerAttacker].unbrudenActive) - gDisableStructs[gBattlerAttacker].unbrudenActive = FALSE; + if (GetBattlerAbility(gBattlerAttacker) == ABILITY_UNBURDEN && gDisableStructs[gBattlerAttacker].unburdenActive) + gDisableStructs[gBattlerAttacker].unburdenActive = FALSE; gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_ITEM_SWAP_TAKEN; // nothing -> <- target's item } @@ -16958,7 +16958,7 @@ void BS_SetRemoveTerrain(void) gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; gFieldStatuses |= statusFlag; - gFieldTimers.terrainTimer = (atkHoldEffect == HOLD_EFFECT_TERRAIN_EXTENDER) ? 8 : 5; + gFieldTimers.terrainTimer = gBattleTurnCounter + (atkHoldEffect == HOLD_EFFECT_TERRAIN_EXTENDER) ? 8 : 5; gBattlescriptCurrInstr = cmd->nextInstr; } } diff --git a/src/battle_util.c b/src/battle_util.c index ed3f74f7b4..a3874c68c3 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1134,7 +1134,7 @@ void PrepareStringBattle(u16 stringId, u32 battler) } if ((stringId == STRINGID_ITDOESNTAFFECT || stringId == STRINGID_PKMNWASNTAFFECTED || stringId == STRINGID_PKMNUNAFFECTED)) - TryInitalizeTrainerSlideEnemyMonUnaffected(gBattlerTarget); + TryInitializeTrainerSlideEnemyMonUnaffected(gBattlerTarget); BtlController_EmitPrintString(battler, BUFFER_A, stringId); MarkBattlerForControllerExec(battler); @@ -3135,6 +3135,18 @@ static inline bool32 TryFormChangeBeforeMove(void) return TRUE; } +static inline bool32 TryActivatePowderStatus(u32 move) +{ + u32 partnerMove = gBattleMons[BATTLE_PARTNER(gBattlerAttacker)].moves[gBattleStruct->chosenMovePositions[BATTLE_PARTNER(gBattlerAttacker)]]; + if (GetBattleMoveType(move) == TYPE_FIRE && !gBattleStruct->pledgeMove) + return TRUE; + if (move == MOVE_FIRE_PLEDGE && partnerMove == MOVE_GRASS_PLEDGE) + return TRUE; + if (move == MOVE_GRASS_PLEDGE && partnerMove == MOVE_FIRE_PLEDGE && gBattleStruct->pledgeMove) + return TRUE; + return FALSE; +} + void SetAtkCancellerForCalledMove(void) { gBattleStruct->atkCancellerTracker = CANCELLER_HEAL_BLOCKED; @@ -3550,7 +3562,7 @@ static void CancellerWeatherPrimal(u32 *effect) if (HasWeatherEffect() && GetMovePower(gCurrentMove) > 0) { u32 moveType = GetBattleMoveType(gCurrentMove); - if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL)) + if (moveType == TYPE_FIRE && (gBattleWeather & B_WEATHER_RAIN_PRIMAL) && (B_POWDER_RAIN >= GEN_7 || !TryActivatePowderStatus(gCurrentMove))) { gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PRIMAL_WEATHER_FIZZLED_BY_RAIN; *effect = 1; @@ -3606,14 +3618,10 @@ static void CancellerPowderStatus(u32 *effect) { if (gBattleMons[gBattlerAttacker].status2 & STATUS2_POWDER) { - u32 partnerMove = gBattleMons[BATTLE_PARTNER(gBattlerAttacker)].moves[gBattleStruct->chosenMovePositions[BATTLE_PARTNER(gBattlerAttacker)]]; - if ((GetBattleMoveType(gCurrentMove) == TYPE_FIRE && !gBattleStruct->pledgeMove) - || (gCurrentMove == MOVE_FIRE_PLEDGE && partnerMove == MOVE_GRASS_PLEDGE) - || (gCurrentMove == MOVE_GRASS_PLEDGE && partnerMove == MOVE_FIRE_PLEDGE && gBattleStruct->pledgeMove)) + if (TryActivatePowderStatus(gCurrentMove)) { gProtectStructs[gBattlerAttacker].powderSelfDmg = TRUE; - if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD - && (B_POWDER_RAIN < GEN_7 || !IsBattlerWeatherAffected(gBattlerAttacker, B_WEATHER_RAIN_PRIMAL))) + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_MAGIC_GUARD) gBattleStruct->moveDamage[gBattlerAttacker] = GetNonDynamaxMaxHP(gBattlerAttacker) / 4; if (GetActiveGimmick(gBattlerAttacker) != GIMMICK_Z_MOVE @@ -4058,9 +4066,9 @@ static bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag, u16 *timer) gDisableStructs[battler].terrainAbilityDone = FALSE; if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_TERRAIN_EXTENDER) - *timer = 8; + *timer = gBattleTurnCounter + 8; else - *timer = 5; + *timer = gBattleTurnCounter + 5; gBattleScripting.battler = battler; return TRUE; @@ -10736,7 +10744,7 @@ static inline uq4_12_t CalcTypeEffectivenessMultiplierInternal(u32 move, u32 mov } if (recordAbilities) - TryInitalizeFirstSTABMoveTrainerSlide(battlerDef, battlerAtk, moveType); + TryInitializeFirstSTABMoveTrainerSlide(battlerDef, battlerAtk, moveType); return modifier; } diff --git a/src/trainer_slide.c b/src/trainer_slide.c index 074f6259d2..a4788c3a95 100644 --- a/src/trainer_slide.c +++ b/src/trainer_slide.c @@ -300,7 +300,7 @@ static bool32 IsSlideInitalizedOrPlayed(enum TrainerSlideType slideId) return FALSE; } -void TryInitalizeFirstSTABMoveTrainerSlide(u32 battlerDef, u32 battlerAtk, u32 moveType) +void TryInitializeFirstSTABMoveTrainerSlide(u32 battlerDef, u32 battlerAtk, u32 moveType) { enum TrainerSlideType slideId = TRAINER_SLIDE_PLAYER_LANDS_FIRST_STAB_MOVE; @@ -316,7 +316,7 @@ void TryInitalizeFirstSTABMoveTrainerSlide(u32 battlerDef, u32 battlerAtk, u32 m InitalizeTrainerSlide(slideId); } -void TryInitalizeTrainerSlidePlayerLandsFirstCriticalHit(u32 target) +void TryInitializeTrainerSlidePlayerLandsFirstCriticalHit(u32 target) { enum TrainerSlideType slideId = TRAINER_SLIDE_PLAYER_LANDS_FIRST_CRITICAL_HIT; @@ -329,7 +329,7 @@ void TryInitalizeTrainerSlidePlayerLandsFirstCriticalHit(u32 target) InitalizeTrainerSlide(slideId); } -void TryInitalizeTrainerSlideEnemyLandsFirstCriticalHit(u32 target) +void TryInitializeTrainerSlideEnemyLandsFirstCriticalHit(u32 target) { enum TrainerSlideType slideId = TRAINER_SLIDE_ENEMY_LANDS_FIRST_CRITICAL_HIT; @@ -342,7 +342,7 @@ void TryInitalizeTrainerSlideEnemyLandsFirstCriticalHit(u32 target) InitalizeTrainerSlide(slideId); } -void TryInitalizeTrainerSlidePlayerLandsFirstSuperEffectiveHit(u32 target) +void TryInitializeTrainerSlidePlayerLandsFirstSuperEffectiveHit(u32 target) { enum TrainerSlideType slideId = TRAINER_SLIDE_PLAYER_LANDS_FIRST_SUPER_EFFECTIVE_HIT; @@ -355,7 +355,7 @@ void TryInitalizeTrainerSlidePlayerLandsFirstSuperEffectiveHit(u32 target) InitalizeTrainerSlide(slideId); } -void TryInitalizeTrainerSlideEnemyMonUnaffected(u32 target) +void TryInitializeTrainerSlideEnemyMonUnaffected(u32 target) { enum TrainerSlideType slideId = TRAINER_SLIDE_ENEMY_MON_UNAFFECTED;