Added new trainer slide-in msg conditions

Now they can say something:
-When their last Pokémon's HP is between 25% and 50%.
-When a critical hit is dealt to their first Pokémon for the first time.
-When a super effective hit is dealt to their first Pokémon for the first time.
-When a STAB move is used against (but doesn't faint) the opponent's Pokémon.
-When the Player's Pokémon's move doesn't affect the opponent's Pokémon.
-When they're about to trigger a Mega Evolution.
-When they're about to trigger a Z-Move.

Misc. changes:
-Split GetEnemyMonCount for readability's sake.
-Optimized the size allocated to trainerSlideLowHpMsgDone.
This commit is contained in:
LOuroboros 2023-02-17 12:53:24 -03:00
parent 6e134bb7dc
commit 3a91a5c930
9 changed files with 356 additions and 178 deletions

View File

@ -2049,6 +2049,14 @@
.4byte \jumpInstr
.endm
.macro trytrainerslidezmovemsg battler:req
various \battler, VARIOUS_TRY_TRAINER_SLIDE_MSG_Z_MOVE
.endm
.macro trytrainerslidemegaevolutionmsg battler:req
various \battler, VARIOUS_TRY_TRAINER_SLIDE_MSG_MEGA_EVOLUTION
.endm
@ helpful macros
.macro setstatchanger stat:req, stages:req, down:req
setbyte sSTATCHANGER, \stat | \stages << 3 | \down << 7

View File

@ -7763,6 +7763,8 @@ BattleScript_FocusPunchSetUp::
end2
BattleScript_MegaEvolution::
printstring STRINGID_EMPTYSTRING3
trytrainerslidemegaevolutionmsg BS_ATTACKER
printstring STRINGID_MEGAEVOREACTING
waitmessage B_WAIT_TIME_LONG
setbyte gIsCriticalHit, 0
@ -7777,6 +7779,8 @@ BattleScript_MegaEvolution::
end2
BattleScript_WishMegaEvolution::
printstring STRINGID_EMPTYSTRING3
trytrainerslidemegaevolutionmsg BS_ATTACKER
printstring STRINGID_FERVENTWISHREACHED
waitmessage B_WAIT_TIME_LONG
setbyte gIsCriticalHit, 0
@ -9989,6 +9993,8 @@ BattleScript_JabocaRowapBerryActivate_Dmg:
@ z moves / effects
BattleScript_ZMoveActivateDamaging::
printstring STRINGID_EMPTYSTRING3
trytrainerslidezmovemsg BS_ATTACKER
printstring STRINGID_ZPOWERSURROUNDS
playanimation BS_ATTACKER, B_ANIM_ZMOVE_ACTIVATE, NULL
printstring STRINGID_ZMOVEUNLEASHED
@ -9996,6 +10002,8 @@ BattleScript_ZMoveActivateDamaging::
return
BattleScript_ZMoveActivateStatus::
printstring STRINGID_EMPTYSTRING3
trytrainerslidezmovemsg BS_ATTACKER
savetarget
printstring STRINGID_ZPOWERSURROUNDS
playanimation BS_ATTACKER, B_ANIM_ZMOVE_ACTIVATE, NULL

View File

@ -620,7 +620,7 @@ struct BattleStruct
struct MegaEvolutionData mega;
struct ZMoveData zmove;
const u8 *trainerSlideMsg;
bool8 trainerSlideLowHpMsgDone;
bool8 trainerSlideLowHpMsgDone:1;
u8 introState;
u8 ateBerry[2]; // array id determined by side, each party pokemon as bit
u8 stolenStats[NUM_BATTLE_STATS]; // hp byte is used for which stats to raise, other inform about by how many stages
@ -655,6 +655,13 @@ struct BattleStruct
u16 overwrittenAbilities[MAX_BATTLERS_COUNT]; // abilities overwritten during battle (keep separate from battle history in case of switching)
bool8 allowedToChangeFormInWeather[PARTY_SIZE][2]; // For each party member and side, used by Ice Face.
u8 battleBondTransformed[NUM_BATTLE_SIDES]; // Bitfield for each party.
bool8 trainerSlideHalfHpMsgDone:1;
u8 trainerSlideFirstCriticalHitMsgState:2;
u8 trainerSlideFirstSuperEffectiveHitMsgState:2;
u8 trainerSlideFirstSTABMoveMsgState:2;
u8 trainerSlidePlayerMonUnaffectedMsgState:2;
bool8 trainerSlideMegaEvolutionMsgDone:1;
bool8 trainerSlideZMoveMsgDone:1;
};
#define F_DYNAMIC_TYPE_1 (1 << 6)

View File

@ -229,6 +229,13 @@ enum
TRAINER_SLIDE_LAST_SWITCHIN,
TRAINER_SLIDE_LAST_LOW_HP,
TRAINER_SLIDE_FIRST_DOWN,
TRAINER_SLIDE_LAST_HALF_HP,
TRAINER_SLIDE_FIRST_CRITICAL_HIT,
TRAINER_SLIDE_FIRST_SUPER_EFFECTIVE_HIT,
TRAINER_SLIDE_FIRST_STAB_MOVE,
TRAINER_SLIDE_PLAYER_MON_UNAFFECTED,
TRAINER_SLIDE_MEGA_EVOLUTION,
TRAINER_SLIDE_Z_MOVE,
};
void BufferStringBattle(u16 stringID);

View File

@ -257,6 +257,8 @@
#define VARIOUS_ACTIVATE_TERRAIN_CHANGE_ABILITIES 165
#define VARIOUS_JUMP_IF_NO_VALID_TARGETS 166
#define VARIOUS_JUMP_IF_EMERGENCY_EXITED 167
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_Z_MOVE 168
#define VARIOUS_TRY_TRAINER_SLIDE_MSG_MEGA_EVOLUTION 169
// Cmd_manipulatedamage
#define DMG_CHANGE_SIGN 0

View File

@ -3868,6 +3868,16 @@ void BattleTurnPassed(void)
BattleScriptExecute(BattleScript_ArenaTurnBeginning);
else if (ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), gTrainerBattleOpponent_A, TRAINER_SLIDE_LAST_LOW_HP))
BattleScriptExecute(BattleScript_TrainerSlideMsgEnd2);
else if (ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), gTrainerBattleOpponent_A, TRAINER_SLIDE_LAST_HALF_HP))
BattleScriptExecute(BattleScript_TrainerSlideMsgEnd2);
else if (ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), gTrainerBattleOpponent_A, TRAINER_SLIDE_FIRST_CRITICAL_HIT))
BattleScriptExecute(BattleScript_TrainerSlideMsgEnd2);
else if (ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), gTrainerBattleOpponent_A, TRAINER_SLIDE_FIRST_SUPER_EFFECTIVE_HIT))
BattleScriptExecute(BattleScript_TrainerSlideMsgEnd2);
else if (ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), gTrainerBattleOpponent_A, TRAINER_SLIDE_FIRST_STAB_MOVE))
BattleScriptExecute(BattleScript_TrainerSlideMsgEnd2);
else if (ShouldDoTrainerSlide(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), gTrainerBattleOpponent_A, TRAINER_SLIDE_PLAYER_MON_UNAFFECTED))
BattleScriptExecute(BattleScript_TrainerSlideMsgEnd2);
}
u8 IsRunningFromBattleImpossible(void)

View File

@ -3868,6 +3868,13 @@ struct TrainerSlide
const u8 *msgLastSwitchIn;
const u8 *msgLastLowHp;
const u8 *msgFirstDown;
const u8 *msgLastHalfHp;
const u8 *msgFirstCriticalHit;
const u8 *msgFirstSuperEffectiveHit;
const u8 *msgFirstSTABMove;
const u8 *msgPlayerMonUnaffected;
const u8 *msgMegaEvolution;
const u8 *msgZMove;
};
static const struct TrainerSlide sTrainerSlides[] =
@ -3879,20 +3886,39 @@ static const struct TrainerSlide sTrainerSlides[] =
.msgLastSwitchIn = sText_AarghAlmostHadIt,
.msgLastLowHp = sText_BoxIsFull,
.msgFirstDown = sText_123Poof,
.msgLastHalfHp = sText_ShootSoClose,
.msgFirstCriticalHit = sText_CriticalHit,
.msgFirstSuperEffectiveHit = sText_SuperEffective,
.msgFirstSTABMove = sText_ABoosted,
.msgPlayerMonUnaffected = sText_ButNoEffect,
.msgMegaEvolution = sText_PowderExplodes,
.msgZMove = sText_Electromagnetism,
},
*/
};
static u32 GetEnemyMonCount(bool32 onlyAlive)
static u32 GetAliveEnemyMonCount(void)
{
u32 i, count = 0;
for (i = 0; i < PARTY_SIZE; i++)
{
u32 species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2, NULL);
if (species != SPECIES_NONE
&& species != SPECIES_EGG
&& (!onlyAlive || GetMonData(&gEnemyParty[i], MON_DATA_HP, NULL)))
if (species != SPECIES_NONE && species != SPECIES_EGG && GetMonData(&gEnemyParty[i], MON_DATA_HP, NULL))
count++;
}
return count;
}
static u32 GetTotalEnemyMonCount(void)
{
u32 i, count = 0;
for (i = 0; i < PARTY_SIZE; i++)
{
u32 species = GetMonData(&gEnemyParty[i], MON_DATA_SPECIES2, NULL);
if (species != SPECIES_NONE && species != SPECIES_EGG)
count++;
}
@ -3914,7 +3940,7 @@ bool32 ShouldDoTrainerSlide(u32 battlerId, u32 trainerId, u32 which)
switch (which)
{
case TRAINER_SLIDE_LAST_SWITCHIN:
if (sTrainerSlides[i].msgLastSwitchIn != NULL && GetEnemyMonCount(TRUE) == 1)
if (sTrainerSlides[i].msgLastSwitchIn != NULL && GetAliveEnemyMonCount() == 1)
{
gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgLastSwitchIn;
return TRUE;
@ -3922,7 +3948,7 @@ bool32 ShouldDoTrainerSlide(u32 battlerId, u32 trainerId, u32 which)
break;
case TRAINER_SLIDE_LAST_LOW_HP:
if (sTrainerSlides[i].msgLastLowHp != NULL
&& GetEnemyMonCount(TRUE) == 1
&& GetAliveEnemyMonCount() == 1
&& gBattleMons[battlerId].hp <= (gBattleMons[battlerId].maxHP / 4)
&& !gBattleStruct->trainerSlideLowHpMsgDone)
{
@ -3932,12 +3958,77 @@ bool32 ShouldDoTrainerSlide(u32 battlerId, u32 trainerId, u32 which)
}
break;
case TRAINER_SLIDE_FIRST_DOWN:
if (sTrainerSlides[i].msgFirstDown != NULL && GetEnemyMonCount(TRUE) == GetEnemyMonCount(FALSE) - 1)
if (sTrainerSlides[i].msgFirstDown != NULL && GetAliveEnemyMonCount() == GetTotalEnemyMonCount() - 1)
{
gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgFirstDown;
return TRUE;
}
break;
case TRAINER_SLIDE_LAST_HALF_HP:
if (sTrainerSlides[i].msgLastHalfHp != NULL
&& GetAliveEnemyMonCount() == 1
&& (gBattleMons[battlerId].hp <= (gBattleMons[battlerId].maxHP / 2) && gBattleMons[battlerId].hp > (gBattleMons[battlerId].maxHP / 4))
&& !gBattleStruct->trainerSlideHalfHpMsgDone)
{
gBattleStruct->trainerSlideHalfHpMsgDone = TRUE;
gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgLastHalfHp;
return TRUE;
}
break;
case TRAINER_SLIDE_FIRST_CRITICAL_HIT:
if (sTrainerSlides[i].msgFirstCriticalHit != NULL && gBattleStruct->trainerSlideFirstCriticalHitMsgState == 1)
{
gBattleStruct->trainerSlideFirstCriticalHitMsgState = 2;
gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgFirstCriticalHit;
return TRUE;
}
break;
case TRAINER_SLIDE_FIRST_SUPER_EFFECTIVE_HIT:
if (sTrainerSlides[i].msgFirstSuperEffectiveHit != NULL
&& gBattleStruct->trainerSlideFirstSuperEffectiveHitMsgState == 1
&& gBattleMons[battlerId].hp)
{
gBattleStruct->trainerSlideFirstSuperEffectiveHitMsgState = 2;
gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgFirstSuperEffectiveHit;
return TRUE;
}
break;
case TRAINER_SLIDE_FIRST_STAB_MOVE:
if (sTrainerSlides[i].msgFirstSTABMove != NULL
&& gBattleStruct->trainerSlideFirstSTABMoveMsgState == 1
&& GetAliveEnemyMonCount() == GetTotalEnemyMonCount())
{
gBattleStruct->trainerSlideFirstSTABMoveMsgState = 2;
gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgFirstSTABMove;
return TRUE;
}
break;
case TRAINER_SLIDE_PLAYER_MON_UNAFFECTED:
if (sTrainerSlides[i].msgPlayerMonUnaffected != NULL
&& gBattleStruct->trainerSlidePlayerMonUnaffectedMsgState == 1
&& GetAliveEnemyMonCount() == GetTotalEnemyMonCount())
{
gBattleStruct->trainerSlidePlayerMonUnaffectedMsgState = 2;
gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgPlayerMonUnaffected;
return TRUE;
}
break;
case TRAINER_SLIDE_MEGA_EVOLUTION:
if (sTrainerSlides[i].msgMegaEvolution != NULL && !gBattleStruct->trainerSlideMegaEvolutionMsgDone)
{
gBattleStruct->trainerSlideMegaEvolutionMsgDone = TRUE;
gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgMegaEvolution;
return TRUE;
}
break;
case TRAINER_SLIDE_Z_MOVE:
if (sTrainerSlides[i].msgZMove != NULL && !gBattleStruct->trainerSlideZMoveMsgDone)
{
gBattleStruct->trainerSlideZMoveMsgDone = TRUE;
gBattleStruct->trainerSlideMsg = sTrainerSlides[i].msgZMove;
return TRUE;
}
break;
}
break;
}

View File

@ -2540,6 +2540,11 @@ static void Cmd_critmessage(void)
if (gIsCriticalHit == TRUE && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT))
{
PrepareStringBattle(STRINGID_CRITICALHIT, gBattlerAttacker);
// Signal for the trainer slide-in system.
if (GetBattlerSide(gBattlerTarget) != B_SIDE_PLAYER && gBattleStruct->trainerSlideFirstCriticalHitMsgState != 2)
gBattleStruct->trainerSlideFirstCriticalHitMsgState = 1;
gBattleCommunication[MSG_DISPLAY] = 1;
}
gBattlescriptCurrInstr = cmd->nextInstr;
@ -2619,7 +2624,13 @@ static void Cmd_resultmessage(void)
{
case MOVE_RESULT_SUPER_EFFECTIVE:
if (!gMultiHitCounter) // Don't print effectiveness on each hit in a multi hit attack
{
// Signal for the trainer slide-in system.
if (GetBattlerSide(gBattlerTarget) != B_SIDE_PLAYER && gBattleStruct->trainerSlideFirstSuperEffectiveHitMsgState != 2)
gBattleStruct->trainerSlideFirstSuperEffectiveHitMsgState = 1;
stringId = STRINGID_SUPEREFFECTIVE;
}
break;
case MOVE_RESULT_NOT_VERY_EFFECTIVE:
if (!gMultiHitCounter)
@ -11040,6 +11051,30 @@ static void Cmd_various(void)
gBattlescriptCurrInstr = cmd->nextInstr;
return;
}
case VARIOUS_TRY_TRAINER_SLIDE_MSG_Z_MOVE:
{
VARIOUS_ARGS();
if (ShouldDoTrainerSlide(gActiveBattler, gTrainerBattleOpponent_A, TRAINER_SLIDE_Z_MOVE))
{
gBattleScripting.battler = gActiveBattler;
BattleScriptPush(cmd->nextInstr);
gBattlescriptCurrInstr = BattleScript_TrainerSlideMsgRet;
return;
}
break;
}
case VARIOUS_TRY_TRAINER_SLIDE_MSG_MEGA_EVOLUTION:
{
VARIOUS_ARGS();
if (ShouldDoTrainerSlide(gActiveBattler, gTrainerBattleOpponent_A, TRAINER_SLIDE_MEGA_EVOLUTION))
{
gBattleScripting.battler = gActiveBattler;
BattleScriptPush(cmd->nextInstr);
gBattlescriptCurrInstr = BattleScript_TrainerSlideMsgRet;
return;
}
break;
}
} // End of switch (cmd->id)
gBattlescriptCurrInstr = cmd->nextInstr;

View File

@ -1607,6 +1607,12 @@ void PrepareStringBattle(u16 stringId, u8 battler)
}
#endif
// Signal for the trainer slide-in system.
if ((stringId == STRINGID_ITDOESNTAFFECT || stringId == STRINGID_PKMNWASNTAFFECTED || stringId == STRINGID_PKMNUNAFFECTED)
&& GetBattlerSide(gBattlerTarget) == B_SIDE_OPPONENT
&& gBattleStruct->trainerSlidePlayerMonUnaffectedMsgState != 2)
gBattleStruct->trainerSlidePlayerMonUnaffectedMsgState = 1;
gActiveBattler = battler;
BtlController_EmitPrintString(BUFFER_A, stringId);
MarkBattlerForControllerExec(gActiveBattler);
@ -9884,6 +9890,10 @@ static u16 CalcTypeEffectivenessMultiplierInternal(u16 move, u8 moveType, u8 bat
}
}
// Signal for the trainer slide-in system.
if (GetBattlerSide(battlerDef) != B_SIDE_PLAYER && modifier && gBattleStruct->trainerSlideFirstSTABMoveMsgState != 2)
gBattleStruct->trainerSlideFirstSTABMoveMsgState = 1;
return modifier;
}