Merge branch '_RHH/master' into _RHH/upcoming

This commit is contained in:
Eduardo Quezada 2025-01-12 08:42:57 -03:00
commit ce40c3356c
21 changed files with 448 additions and 400 deletions

View File

@ -478,9 +478,10 @@
.byte \battler
.endm
.macro switchinanim battler:req, dontClearSubstitute:req
.macro switchinanim battler:req, dontClearTransform:req, dontClearSubstitute:req
.byte 0x4e
.byte \battler
.byte \dontClearTransform
.byte \dontClearSubstitute
.endm

File diff suppressed because it is too large Load Diff

View File

@ -330,7 +330,7 @@ BattleScript_MoveSwitchOpenPartyScreen::
printstring STRINGID_EMPTYSTRING3
waitmessage 1
printstring STRINGID_SWITCHINMON
switchinanim BS_ATTACKER, TRUE
switchinanim BS_ATTACKER, FALSE, TRUE
waitstate
switchineffects BS_ATTACKER
BattleScript_MoveSwitchEnd:
@ -477,7 +477,7 @@ BattleScript_EffectRevivalBlessingSendOut:
getswitchedmondata BS_SCRIPTING
switchindataupdate BS_SCRIPTING
hpthresholds BS_SCRIPTING
switchinanim BS_SCRIPTING, FALSE
switchinanim BS_SCRIPTING, FALSE, FALSE
waitstate
switchineffects BS_SCRIPTING
goto BattleScript_MoveEnd
@ -2398,7 +2398,7 @@ BattleScript_EffectHealingWish::
trytoclearprimalweather
flushtextbox
printstring STRINGID_SWITCHINMON
switchinanim BS_ATTACKER, TRUE
switchinanim BS_ATTACKER, FALSE, TRUE
waitstate
switchineffects BS_ATTACKER
.endif
@ -4408,7 +4408,7 @@ BattleScript_EffectBatonPass::
trytoclearprimalweather
flushtextbox
printstring STRINGID_SWITCHINMON
switchinanim BS_ATTACKER, TRUE
switchinanim BS_ATTACKER, FALSE, TRUE
waitstate
switchineffects BS_ATTACKER
goto BattleScript_MoveEnd
@ -5512,7 +5512,7 @@ BattleScript_FaintedMonTryChoose:
flushtextbox
printstring STRINGID_SWITCHINMON
hidepartystatussummary BS_ATTACKER
switchinanim BS_ATTACKER, 0
switchinanim BS_ATTACKER, FALSE, FALSE
waitstate
setbyte sSHIFT_SWITCHED, 1
BattleScript_FaintedMonSendOutNew:
@ -5524,7 +5524,7 @@ BattleScript_FaintedMonSendOutNew:
flushtextbox
printstring STRINGID_SWITCHINMON
hidepartystatussummary BS_FAINTED
switchinanim BS_FAINTED, FALSE
switchinanim BS_FAINTED, FALSE, FALSE
waitstate
resetplayerfainted
trytrainerslidelastonmsg BS_FAINTED
@ -5558,7 +5558,7 @@ BattleScript_HandleFaintedMonLoop::
flushtextbox
printstring STRINGID_SWITCHINMON
hidepartystatussummary BS_FAINTED
switchinanim BS_FAINTED, FALSE
switchinanim BS_FAINTED, FALSE, FALSE
waitstate
switchineffects BS_FAINTED_MULTIPLE_1
jumpifbytenotequal gBattlerFainted, gBattlersCount, BattleScript_HandleFaintedMonLoop
@ -5774,7 +5774,7 @@ BattleScript_DoSwitchOut::
flushtextbox
printstring STRINGID_SWITCHINMON
hidepartystatussummary BS_ATTACKER
switchinanim BS_ATTACKER, FALSE
switchinanim BS_ATTACKER, FALSE, FALSE
waitstate
switchineffects BS_ATTACKER
moveendcase MOVEEND_STATUS_IMMUNITY_ABILITIES
@ -6028,7 +6028,7 @@ BattleScript_RoarSuccessSwitch::
switchindataupdate BS_TARGET
trytoclearprimalweather
flushtextbox
switchinanim BS_TARGET, FALSE
switchinanim BS_TARGET, FALSE, FALSE
waitstate
printstring STRINGID_PKMNWASDRAGGEDOUT
switchineffects BS_TARGET
@ -7593,7 +7593,7 @@ BattleScript_EmergencyExitNoPopUp::
switchindataupdate BS_TARGET
hpthresholds BS_TARGET
printstring STRINGID_SWITCHINMON
switchinanim BS_TARGET, TRUE
switchinanim BS_TARGET, FALSE, TRUE
waitstate
switchineffects BS_TARGET
BattleScript_EmergencyExitRet:
@ -9555,7 +9555,7 @@ BattleScript_EjectButtonActivates::
trytoclearprimalweather
flushtextbox
printstring 0x3
switchinanim BS_SCRIPTING 0x1
switchinanim BS_SCRIPTING, FALSE, TRUE
waitstate
switchineffects BS_SCRIPTING
BattleScript_EjectButtonEnd:
@ -9919,7 +9919,7 @@ BattleScript_DynamaxBegins::
returnatktoball
pause B_WAIT_TIME_SHORT
returntoball BS_SCRIPTING, TRUE
switchinanim BS_SCRIPTING, TRUE
switchinanim BS_SCRIPTING, TRUE, TRUE
updatedynamax
playanimation BS_SCRIPTING, B_ANIM_DYNAMAX_GROWTH
waitanimation

View File

@ -75,7 +75,7 @@ BattleScript_ItemRestoreHP_Party::
return
BattleScript_ItemRestoreHP_SendOutRevivedBattler:
switchinanim BS_SCRIPTING, FALSE
switchinanim BS_SCRIPTING, FALSE, FALSE
waitstate
switchineffects BS_SCRIPTING
end

View File

@ -210,7 +210,7 @@ void PrepareBufferDataTransferLink(u32 battler, u32 bufferId, u16 size, u8 *data
void BtlController_EmitGetMonData(u32 battler, u32 bufferId, u8 requestId, u8 monToCheck);
void BtlController_EmitSetMonData(u32 battler, u32 bufferId, u8 requestId, u8 monToCheck, u8 bytes, void *data);
void BtlController_EmitLoadMonSprite(u32 battler, u32 bufferId);
void BtlController_EmitSwitchInAnim(u32 battler, u32 bufferId, u8 partyId, bool8 dontClearSubstituteBit);
void BtlController_EmitSwitchInAnim(u32 battler, u32 bufferId, u8 partyId, bool8 dontClearTransform, bool8 dontClearSubstituteBit);
void BtlController_EmitReturnMonToBall(u32 battler, u32 bufferId, bool8 skipAnim);
void BtlController_EmitDrawTrainerPic(u32 battler, u32 bufferId);
void BtlController_EmitTrainerSlide(u32 battler, u32 bufferId);
@ -255,7 +255,7 @@ void BattleControllerComplete(u32 battler); // Can be used for all the controlle
void BtlController_Empty(u32 battler); // Empty command, does nothing, only completes the execution.
void BtlController_TerminatorNop(u32 battler); // Dummy function at the end of the table.
void BattleControllerDummy(u32 battler);
void StartSendOutAnim(u32 battler, bool32 dontClearSubstituteBit, bool32 doSlideIn);
void StartSendOutAnim(u32 battler, bool32 dontClearTransform, bool32 dontClearSubstituteBit, bool32 doSlideIn);
void Controller_WaitForString(u32 battler);
void Controller_WaitForHealthBar(u32 battler);

View File

@ -38,7 +38,7 @@ void SpriteCB_SetInvisible(struct Sprite *sprite);
void SetBattlerShadowSpriteCallback(u8 battler, u16 species);
void HideBattlerShadowSprite(u8 battler);
void FillAroundBattleWindows(void);
void ClearTemporarySpeciesSpriteData(u8 battler, bool8 dontClearSubstitute);
void ClearTemporarySpeciesSpriteData(u32 battler, bool32 dontClearTransform, bool32 dontClearSubstitute);
void AllocateMonSpritesGfx(void);
void FreeMonSpritesGfx(void);
bool32 ShouldPlayNormalMonCry(struct Pokemon *mon);

View File

@ -720,6 +720,7 @@ u8 GetItemEffectParamOffset(u32 battler, u16 itemId, u8 effectByte, u8 effectBit
u8 *UseStatIncreaseItem(u16 itemId);
u8 GetNature(struct Pokemon *mon);
u8 GetNatureFromPersonality(u32 personality);
u32 GetGMaxTargetSpecies(u32 species);
u16 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 evolutionItem, struct Pokemon *tradePartner);
bool8 IsMonPastEvolutionLevel(struct Pokemon *mon);
u16 NationalPokedexNumToSpecies(u16 nationalNum);

View File

@ -257,6 +257,10 @@ const struct SpriteTemplate gPunishmentImpactSpriteTemplate =
.callback = AnimPunishment,
};
// arg 0: x pixel offset
// arg 1: y pixel offset
// arg 2: Something
// arg 3: Something
static void AnimPunishment(struct Sprite *sprite)
{
StartSpriteAffineAnim(sprite, gBattleAnimArgs[3]);

View File

@ -657,6 +657,13 @@ static void AnimUnusedCirclingShock(struct Sprite *sprite)
sprite->callback = TranslateSpriteInCircle;
}
// arg 0:
// arg 1:
// arg 2:
// arg 3: duration
// arg 4: target
// arg 5:
// arg 6:
void AnimSparkElectricity(struct Sprite *sprite)
{
u8 battler;

View File

@ -908,7 +908,7 @@ static void AnimTask_SlideOffScreen_Step(u8 taskId)
// arg 1: wave amplitude
// arg 2: wave period
// arg 3: num sways
// arg 4: which mon (0 = attacker, 1`= target)
// arg 4: which mon (0 = attacker, 1 = target)
void AnimTask_SwayMon(u8 taskId)
{
u8 spriteId;

View File

@ -2117,24 +2117,26 @@ s16 GetBattlerSpriteCoordAttr(u8 battlerId, u8 attr)
}
else
{
struct Pokemon *mon = GetPartyBattlerData(battlerId);
spriteInfo = gBattleSpritesDataPtr->battlerData;
if (!spriteInfo[battlerId].transformSpecies)
{
species = GetMonData(mon, MON_DATA_SPECIES);
personality = GetMonData(mon, MON_DATA_PERSONALITY);
}
else
{
species = spriteInfo[battlerId].transformSpecies;
personality = gTransformedPersonalities[battlerId];
}
species = SanitizeSpeciesId(species);
if (species == SPECIES_UNOWN)
species = GetUnownSpeciesId(personality);
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
{
spriteInfo = gBattleSpritesDataPtr->battlerData;
if (!spriteInfo[battlerId].transformSpecies)
{
species = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
personality = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PERSONALITY);
}
else
{
species = spriteInfo[battlerId].transformSpecies;
personality = gTransformedPersonalities[battlerId];
}
species = SanitizeSpeciesId(species);
if (species == SPECIES_UNOWN)
species = GetUnownSpeciesId(personality);
#if P_GENDER_DIFFERENCES
if (gSpeciesInfo[species].backPicFemale != NULL && IsPersonalityFemale(species, personality))
size = gSpeciesInfo[species].backPicSizeFemale;
@ -2146,22 +2148,6 @@ s16 GetBattlerSpriteCoordAttr(u8 battlerId, u8 attr)
}
else
{
spriteInfo = gBattleSpritesDataPtr->battlerData;
if (!spriteInfo[battlerId].transformSpecies)
{
species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES);
personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerId]], MON_DATA_PERSONALITY);
}
else
{
species = spriteInfo[battlerId].transformSpecies;
personality = gTransformedPersonalities[battlerId];
}
species = SanitizeSpeciesId(species);
if (species == SPECIES_UNOWN)
species = GetUnownSpeciesId(personality);
#if P_GENDER_DIFFERENCES
if (gSpeciesInfo[species].frontPicFemale != NULL && IsPersonalityFemale(species, personality))
size = gSpeciesInfo[species].frontPicSizeFemale;

View File

@ -776,6 +776,7 @@ void HandleInputChooseMove(u32 battler)
if (gBattleStruct->zmove.viewing)
{
ReloadMoveNames(battler);
ChangeGimmickTriggerSprite(gBattleStruct->gimmick.triggerSpriteId, gBattleStruct->gimmick.playerSelect);
}
else
{

View File

@ -976,12 +976,12 @@ void BtlController_EmitLoadMonSprite(u32 battler, u32 bufferId)
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4);
}
void BtlController_EmitSwitchInAnim(u32 battler, u32 bufferId, u8 partyId, bool8 dontClearSubstituteBit)
void BtlController_EmitSwitchInAnim(u32 battler, u32 bufferId, u8 partyId, bool8 dontClearTransform, bool8 dontClearSubstituteBit)
{
gBattleResources->transferBuffer[0] = CONTROLLER_SWITCHINANIM;
gBattleResources->transferBuffer[1] = partyId;
gBattleResources->transferBuffer[2] = dontClearSubstituteBit;
gBattleResources->transferBuffer[3] = 5;
gBattleResources->transferBuffer[2] = dontClearTransform;
gBattleResources->transferBuffer[3] = dontClearSubstituteBit;
PrepareBufferDataTransfer(battler, bufferId, gBattleResources->transferBuffer, 4);
}
@ -2111,13 +2111,13 @@ static bool8 ShouldDoSlideInAnim(void)
return TRUE;
}
void StartSendOutAnim(u32 battler, bool32 dontClearSubstituteBit, bool32 doSlideIn)
void StartSendOutAnim(u32 battler, bool32 dontClearTransform, bool32 dontClearSubstituteBit, bool32 doSlideIn)
{
u16 species;
u32 side = GetBattlerSide(battler);
struct Pokemon *party = GetBattlerParty(battler);
ClearTemporarySpeciesSpriteData(battler, dontClearSubstituteBit);
ClearTemporarySpeciesSpriteData(battler, dontClearTransform, dontClearSubstituteBit);
gBattlerPartyIndexes[battler] = gBattleResources->bufferA[battler][1];
species = GetIllusionMonSpecies(battler);
if (species == SPECIES_NONE)
@ -2462,11 +2462,11 @@ void BtlController_HandleLoadMonSprite(u32 battler, void (*controllerCallback)(u
void BtlController_HandleSwitchInAnim(u32 battler, bool32 isPlayerSide, void (*controllerCallback)(u32 battler))
{
if (isPlayerSide)
ClearTemporarySpeciesSpriteData(battler, gBattleResources->bufferA[battler][2]);
ClearTemporarySpeciesSpriteData(battler, gBattleResources->bufferA[battler][2], gBattleResources->bufferA[battler][3]);
gBattlerPartyIndexes[battler] = gBattleResources->bufferA[battler][1];
if (isPlayerSide)
BattleLoadMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battler]], battler);
StartSendOutAnim(battler, gBattleResources->bufferA[battler][2], FALSE);
StartSendOutAnim(battler, gBattleResources->bufferA[battler][2], gBattleResources->bufferA[battler][3], FALSE);
gBattlerControllerFuncs[battler] = controllerCallback;
}
@ -2965,17 +2965,17 @@ static void Task_StartSendOutAnim(u8 taskId)
if (TwoMonsAtSendOut(battler))
{
gBattleResources->bufferA[battler][1] = gBattlerPartyIndexes[battler];
StartSendOutAnim(battler, FALSE, ShouldDoSlideInAnim());
StartSendOutAnim(battler, FALSE, FALSE, ShouldDoSlideInAnim());
battlerPartner = battler ^ BIT_FLANK;
gBattleResources->bufferA[battlerPartner][1] = gBattlerPartyIndexes[battlerPartner];
BattleLoadMonSpriteGfx(&gPlayerParty[gBattlerPartyIndexes[battlerPartner]], battlerPartner);
StartSendOutAnim(battlerPartner, FALSE, ShouldDoSlideInAnim());
StartSendOutAnim(battlerPartner, FALSE, FALSE, ShouldDoSlideInAnim());
}
else
{
gBattleResources->bufferA[battler][1] = gBattlerPartyIndexes[battler];
StartSendOutAnim(battler, FALSE, ShouldDoSlideInAnim());
StartSendOutAnim(battler, FALSE, FALSE, ShouldDoSlideInAnim());
}
gBattlerControllerFuncs[battler] = (void*)(GetWordTaskArg(taskId, tControllerFunc_1));
DestroyTask(taskId);

View File

@ -609,7 +609,7 @@ bool8 IsBattleSEPlaying(u8 battler)
void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler)
{
u32 monsPersonality, currentPersonality, isShiny, species, paletteOffset, position;
u32 personalityValue, isShiny, species, paletteOffset, position;
const void *lzPaletteData;
struct Pokemon *illusionMon = GetIllusionMonPtr(battler);
if (illusionMon != NULL)
@ -618,48 +618,42 @@ void BattleLoadMonSpriteGfx(struct Pokemon *mon, u32 battler)
if (GetMonData(mon, MON_DATA_IS_EGG) || GetMonData(mon, MON_DATA_SPECIES) == SPECIES_NONE) // Don't load GFX of egg pokemon.
return;
monsPersonality = GetMonData(mon, MON_DATA_PERSONALITY);
isShiny = GetMonData(mon, MON_DATA_IS_SHINY);
if (gBattleSpritesDataPtr->battlerData[battler].transformSpecies == SPECIES_NONE)
{
species = GetMonData(mon, MON_DATA_SPECIES);
currentPersonality = monsPersonality;
personalityValue = GetMonData(mon, MON_DATA_PERSONALITY);
}
else
{
species = gBattleSpritesDataPtr->battlerData[battler].transformSpecies;
// If battler has Gigantamax factor, try convert gfx to G-Max version
if (GetActiveGimmick(battler) == GIMMICK_DYNAMAX && GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR))
gBattleSpritesDataPtr->battlerData[battler].transformSpecies = species = GetGMaxTargetSpecies(species);
if (B_TRANSFORM_SHINY >= GEN_4)
{
currentPersonality = gTransformedPersonalities[battler];
personalityValue = gTransformedPersonalities[battler];
isShiny = gTransformedShininess[battler];
}
else
{
currentPersonality = monsPersonality;
personalityValue = GetMonData(mon, MON_DATA_PERSONALITY);
}
}
position = GetBattlerPosition(battler);
if (GetBattlerSide(battler) == B_SIDE_OPPONENT)
{
HandleLoadSpecialPokePic(TRUE,
gMonSpritesGfxPtr->spritesGfx[position],
species, currentPersonality);
}
else
{
HandleLoadSpecialPokePic(FALSE,
gMonSpritesGfxPtr->spritesGfx[position],
species, currentPersonality);
}
HandleLoadSpecialPokePic((GetBattlerSide(battler) == B_SIDE_OPPONENT),
gMonSpritesGfxPtr->spritesGfx[position],
species, personalityValue);
paletteOffset = OBJ_PLTT_ID(battler);
if (gBattleSpritesDataPtr->battlerData[battler].transformSpecies == SPECIES_NONE)
lzPaletteData = GetMonFrontSpritePal(mon);
else
lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, currentPersonality);
lzPaletteData = GetMonSpritePalFromSpeciesAndPersonality(species, isShiny, personalityValue);
LZDecompressWram(lzPaletteData, gDecompressionBuffer);
LoadPalette(gDecompressionBuffer, paletteOffset, PLTT_SIZE_4BPP);
@ -925,8 +919,10 @@ void CopyBattleSpriteInvisibility(u8 battler)
void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bool8 trackEnemyPersonality)
{
u32 personalityValue, position, paletteOffset, targetSpecies;
bool8 isShiny;
bool32 isShiny;
const void *lzPaletteData, *src;
struct Pokemon *monAtk = GetPartyBattlerData(battlerAtk);
struct Pokemon *monDef = GetPartyBattlerData(battlerDef);
void *dst;
if (IsContest())
@ -944,48 +940,35 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
else
{
position = GetBattlerPosition(battlerAtk);
if (GetBattlerSide(battlerDef) == B_SIDE_OPPONENT)
targetSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_SPECIES);
else
targetSpecies = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_SPECIES);
if (GetBattlerSide(battlerAtk) == B_SIDE_PLAYER)
if (gBattleSpritesDataPtr->battlerData[battlerAtk].transformSpecies == SPECIES_NONE)
{
if (B_TRANSFORM_SHINY >= GEN_4 && trackEnemyPersonality && !megaEvo)
{
personalityValue = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_PERSONALITY);
isShiny = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_IS_SHINY);
}
// Get base form if its currently Gigantamax
if (IsGigantamaxed(battlerDef))
targetSpecies = gBattleStruct->changedSpecies[GetBattlerSide(battlerDef)][gBattlerPartyIndexes[battlerDef]];
else
{
personalityValue = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_PERSONALITY);
isShiny = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_IS_SHINY);
}
HandleLoadSpecialPokePic(FALSE,
gMonSpritesGfxPtr->spritesGfx[position],
targetSpecies,
personalityValue);
targetSpecies = GetMonData(monDef, MON_DATA_SPECIES);
personalityValue = GetMonData(monAtk, MON_DATA_PERSONALITY);
isShiny = GetMonData(monAtk, MON_DATA_IS_SHINY);
}
else
{
targetSpecies = gBattleSpritesDataPtr->battlerData[battlerAtk].transformSpecies;
if (B_TRANSFORM_SHINY >= GEN_4 && trackEnemyPersonality && !megaEvo)
{
personalityValue = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_PERSONALITY);
isShiny = GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerDef]], MON_DATA_IS_SHINY);
personalityValue = GetMonData(monDef, MON_DATA_PERSONALITY);
isShiny = GetMonData(monDef, MON_DATA_IS_SHINY);
}
else
{
personalityValue = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_PERSONALITY);
isShiny = GetMonData(&gEnemyParty[gBattlerPartyIndexes[battlerAtk]], MON_DATA_IS_SHINY);
personalityValue = GetMonData(monAtk, MON_DATA_PERSONALITY);
isShiny = GetMonData(monAtk, MON_DATA_IS_SHINY);
}
HandleLoadSpecialPokePic(TRUE,
gMonSpritesGfxPtr->spritesGfx[position],
targetSpecies,
personalityValue);
}
HandleLoadSpecialPokePic((GetBattlerSide(battlerAtk) != B_SIDE_PLAYER),
gMonSpritesGfxPtr->spritesGfx[position],
targetSpecies,
personalityValue);
}
src = gMonSpritesGfxPtr->spritesGfx[position];
dst = (void *)(OBJ_VRAM0 + gSprites[gBattlerSpriteIds[battlerAtk]].oam.tileNum * 32);
@ -1005,6 +988,24 @@ void HandleSpeciesGfxDataChange(u8 battlerAtk, u8 battlerDef, bool32 megaEvo, bo
}
}
// dynamax tint
if (GetActiveGimmick(battlerAtk) == GIMMICK_DYNAMAX)
{
// Calyrex and its forms have a blue dynamax aura instead of red.
if (GET_BASE_SPECIES_ID(targetSpecies) == SPECIES_CALYREX)
BlendPalette(paletteOffset, 16, 4, RGB(12, 0, 31));
else
BlendPalette(paletteOffset, 16, 4, RGB(31, 0, 12));
CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, PLTT_SIZEOF(16));
}
// Terastallization's tint
if (GetActiveGimmick(battlerAtk) == GIMMICK_TERA)
{
BlendPalette(paletteOffset, 16, 8, GetTeraTypeRGB(GetBattlerTeraType(battlerAtk)));
CpuCopy32(gPlttBufferFaded + paletteOffset, gPlttBufferUnfaded + paletteOffset, PLTT_SIZEOF(16));
}
gSprites[gBattlerSpriteIds[battlerAtk]].y = GetBattlerSpriteDefault_Y(battlerAtk);
StartSpriteAnim(&gSprites[gBattlerSpriteIds[battlerAtk]], 0);
}
@ -1385,9 +1386,10 @@ void FillAroundBattleWindows(void)
}
}
void ClearTemporarySpeciesSpriteData(u8 battler, bool8 dontClearSubstitute)
void ClearTemporarySpeciesSpriteData(u32 battler, bool32 dontClearTransform, bool32 dontClearSubstitute)
{
gBattleSpritesDataPtr->battlerData[battler].transformSpecies = SPECIES_NONE;
if (!dontClearTransform)
gBattleSpritesDataPtr->battlerData[battler].transformSpecies = SPECIES_NONE;
if (!dontClearSubstitute)
ClearBehindSubstituteBit(battler);
}

View File

@ -7202,7 +7202,7 @@ static void Cmd_switchinanim(void)
{
u32 battler;
CMD_ARGS(u8 battler, bool8 dontClearSubstitute);
CMD_ARGS(u8 battler, bool8 dontClearTransform, bool8 dontClearSubstitute);
if (gBattleControllerExecFlags)
return;
@ -7219,7 +7219,7 @@ static void Cmd_switchinanim(void)
gAbsentBattlerFlags &= ~(1u << battler);
BtlController_EmitSwitchInAnim(battler, BUFFER_A, gBattlerPartyIndexes[battler], cmd->dontClearSubstitute);
BtlController_EmitSwitchInAnim(battler, BUFFER_A, gBattlerPartyIndexes[battler], cmd->dontClearTransform, cmd->dontClearSubstitute);
MarkBattlerForControllerExec(battler);
gBattlescriptCurrInstr = cmd->nextInstr;

View File

@ -9656,7 +9656,10 @@ static inline u32 CalcMoveBasePowerAfterModifiers(struct DamageCalculationData *
&& (moveType == GetBattlerTeraType(battlerAtk)
|| (GetBattlerTeraType(battlerAtk) == TYPE_STELLAR && IsTypeStellarBoosted(battlerAtk, moveType)))
&& uq4_12_multiply_by_int_half_down(modifier, basePower) < 60
&& GetMovePower(move) > 1
&& GetMoveStrikeCount(move) < 2
&& moveEffect != EFFECT_POWER_BASED_ON_USER_HP
&& moveEffect != EFFECT_POWER_BASED_ON_TARGET_HP
&& moveEffect != EFFECT_MULTI_HIT
&& GetMovePriority(move) == 0)
{

View File

@ -3714,7 +3714,7 @@ void CopyPartyMonToBattleData(u32 battlerId, u32 partyIndex)
PokemonToBattleMon(&party[partyIndex], &gBattleMons[battlerId]);
gBattleStruct->hpOnSwitchout[side] = gBattleMons[battlerId].hp;
UpdateSentPokesToOpponentValue(battlerId);
ClearTemporarySpeciesSpriteData(battlerId, FALSE);
ClearTemporarySpeciesSpriteData(battlerId, FALSE, FALSE);
}
bool8 ExecuteTableBasedItemEffect(struct Pokemon *mon, u16 item, u8 partyIndex, u8 moveIndex)
@ -4438,7 +4438,7 @@ u8 GetNatureFromPersonality(u32 personality)
return personality % NUM_NATURES;
}
static u32 GetGMaxTargetSpecies(u32 species)
u32 GetGMaxTargetSpecies(u32 species)
{
const struct FormChange *formChanges = GetSpeciesFormChanges(species);
u32 i;
@ -4447,7 +4447,7 @@ static u32 GetGMaxTargetSpecies(u32 species)
if (formChanges[i].method == FORM_CHANGE_BATTLE_GIGANTAMAX)
return formChanges[i].targetSpecies;
}
return SPECIES_NONE;
return species;
}
u16 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16 evolutionItem, struct Pokemon *tradePartner)
@ -4885,8 +4885,8 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, enum EvolutionMode mode, u16
// Gigantamax Factor. We assume that is because their evolutions
// do not have a Gigantamax Form.
if (GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR, NULL)
&& GetGMaxTargetSpecies(species) != SPECIES_NONE
&& GetGMaxTargetSpecies(targetSpecies) == SPECIES_NONE)
&& GetGMaxTargetSpecies(species) != species
&& GetGMaxTargetSpecies(targetSpecies) == targetSpecies)
{
return SPECIES_NONE;
}

View File

@ -458,7 +458,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Max Moves deal 1/4 damage through protect", s16 da
}
}
// This test will fail if it's the first test a thread runs
SINGLE_BATTLE_TEST("(DYNAMAX) Max Moves don't bypass Max Guard")
{
GIVEN {
@ -1537,7 +1536,6 @@ SINGLE_BATTLE_TEST("(DYNAMAX) Moxie clones can be triggered by Max Moves faintin
}
}
// This test will fail if it's the first test a thread runs
SINGLE_BATTLE_TEST("(DYNAMAX) Max Attacks prints a message when hitting into Max Guard")
{
GIVEN {

View File

@ -186,6 +186,25 @@ SINGLE_BATTLE_TEST("(TERA) Terastallization's 60 BP floor does not apply to prio
}
}
SINGLE_BATTLE_TEST("(TERA) Terastallization's 60 BP floor does not apply to dynamic base power moves", s16 damage)
{
bool32 tera;
PARAMETRIZE { tera = GIMMICK_NONE; }
PARAMETRIZE { tera = GIMMICK_TERA; }
GIVEN {
ASSUME(gMovesInfo[MOVE_WATER_SPOUT].effect == EFFECT_POWER_BASED_ON_USER_HP);
PLAYER(SPECIES_WOBBUFFET) { HP(1); TeraType(TYPE_WATER); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_WATER_SPOUT, gimmick: tera); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_SPOUT, player);
HP_BAR(opponent, captureDamage: &results[i].damage);
} FINALLY {
EXPECT_EQ(results[0].damage, results[1].damage);
}
}
// Defensive Type Checks
SINGLE_BATTLE_TEST("(TERA) Terastallization changes type effectiveness", s16 damage)

View File

@ -150,7 +150,6 @@ SINGLE_BATTLE_TEST("Shell Bell doesn't restore HP for damage dealt by a foreseen
}
}
SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original user is not on the field")
{
GIVEN {
@ -172,5 +171,32 @@ SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original
}
}
SINGLE_BATTLE_TEST("Shell Bell does not activate on Future Sight if the original user is on the field")
{
s16 damage = 0;
s16 healed = 0;
GIVEN {
PLAYER(SPECIES_WOBBUFFET) { HP(1); Item(ITEM_SHELL_BELL); }
OPPONENT(SPECIES_WYNAUT);
} WHEN {
TURN { MOVE(player, MOVE_FUTURE_SIGHT); }
TURN {}
TURN {}
TURN { MOVE(player, MOVE_DRAGON_RAGE); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FUTURE_SIGHT, player);
MESSAGE("The opposing Wynaut took the Future Sight attack!");
HP_BAR(opponent);
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_RAGE, player);
HP_BAR(opponent, captureDamage: &damage);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
HP_BAR(player, captureDamage: &healed);
} THEN {
EXPECT_MUL_EQ(damage, Q_4_12(-0.25), healed);
}
}
TO_DO_BATTLE_TEST("If a Pokémon steals a Shell Bell with Thief or Covet, it will recover HP for the use of that move that stole the Shell Bell")
TO_DO_BATTLE_TEST("If a Pokémon steals a Shell Bell with Magician, it will recover HP for the use of that move that stole the Shell Bell")

View File

@ -2118,7 +2118,7 @@ void MoveGetIdAndSlot(s32 battlerId, struct MoveContext *ctx, u32 *moveId, u32 *
u32 item = GetMonData(mon, MON_DATA_HELD_ITEM);
u32 holdEffect = ItemId_GetHoldEffect(item);
u32 species = GetMonData(mon, MON_DATA_SPECIES);
u32 side = GetBattlerSide(battlerId);
u32 side = battlerId & BIT_SIDE;
// Check invalid item usage.
INVALID_IF(ctx->gimmick == GIMMICK_MEGA && holdEffect != HOLD_EFFECT_MEGA_STONE && species != SPECIES_RAYQUAZA, "Cannot Mega Evolve without a Mega Stone");