Battle Transition: mugshots for multibattles (#6567)

Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com>
This commit is contained in:
grintoul1 2025-04-17 15:18:20 +01:00 committed by GitHub
parent 85ecc91532
commit ec2aef2eff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 164 additions and 42 deletions

View File

@ -171,6 +171,7 @@ extern const union AnimCmd *const gAnims_MonPic[];
extern const union AnimCmd *const gAnims_Trainer[]; extern const union AnimCmd *const gAnims_Trainer[];
extern const struct TrainerSprite gTrainerSprites[]; extern const struct TrainerSprite gTrainerSprites[];
extern const struct TrainerBacksprite gTrainerBacksprites[]; extern const struct TrainerBacksprite gTrainerBacksprites[];
extern const u16 gTrainerPicToTrainerBackPic[];
extern const struct Trainer gTrainers[DIFFICULTY_COUNT][TRAINERS_COUNT]; extern const struct Trainer gTrainers[DIFFICULTY_COUNT][TRAINERS_COUNT];
extern const struct Trainer gBattlePartners[DIFFICULTY_COUNT][PARTNER_COUNT]; extern const struct Trainer gBattlePartners[DIFFICULTY_COUNT][PARTNER_COUNT];
@ -239,6 +240,10 @@ static inline const u8 GetTrainerPicFromId(u16 trainerId)
{ {
u32 sanitizedTrainerId = SanitizeTrainerId(trainerId); u32 sanitizedTrainerId = SanitizeTrainerId(trainerId);
enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId); enum DifficultyLevel difficulty = GetTrainerDifficultyLevel(sanitizedTrainerId);
enum DifficultyLevel partnerDifficulty = GetBattlePartnerDifficultyLevel(trainerId);
if (trainerId > TRAINER_PARTNER(PARTNER_NONE))
return gBattlePartners[partnerDifficulty][trainerId - TRAINER_PARTNER(PARTNER_NONE)].trainerPic;
return gTrainers[difficulty][sanitizedTrainerId].trainerPic; return gTrainers[difficulty][sanitizedTrainerId].trainerPic;
} }

View File

@ -613,8 +613,8 @@ extern bool32 consumeItem;
extern u32 removeBagItem; extern u32 removeBagItem;
extern u32 removeBagItemCount; extern u32 removeBagItemCount;
extern const u8 gFacilityClassToPicIndex[]; extern const u16 gFacilityClassToPicIndex[];
extern const u8 gFacilityClassToTrainerClass[]; extern const u16 gFacilityClassToTrainerClass[];
extern const struct SpeciesInfo gSpeciesInfo[]; extern const struct SpeciesInfo gSpeciesInfo[];
extern const u32 gExperienceTables[][MAX_LEVEL + 1]; extern const u32 gExperienceTables[][MAX_LEVEL + 1];
extern const u8 gPPUpGetMask[]; extern const u8 gPPUpGetMask[];

View File

@ -88,6 +88,7 @@ struct RectangularSpiralLine
typedef bool8 (*TransitionStateFunc)(struct Task *task); typedef bool8 (*TransitionStateFunc)(struct Task *task);
typedef bool8 (*TransitionSpriteCallback)(struct Sprite *sprite); typedef bool8 (*TransitionSpriteCallback)(struct Sprite *sprite);
typedef bool8 (*TransitionSpriteCallbackPartner)(struct Sprite *sprite);
static bool8 Transition_StartIntro(struct Task *); static bool8 Transition_StartIntro(struct Task *);
static bool8 Transition_WaitForIntro(struct Task *); static bool8 Transition_WaitForIntro(struct Task *);
@ -277,11 +278,13 @@ static bool8 IsIntroTaskDone(void);
static bool16 UpdateRectangularSpiralLine(const s16 * const *, struct RectangularSpiralLine *); static bool16 UpdateRectangularSpiralLine(const s16 * const *, struct RectangularSpiralLine *);
static void SpriteCB_FldEffPokeballTrail(struct Sprite *); static void SpriteCB_FldEffPokeballTrail(struct Sprite *);
static void SpriteCB_MugshotTrainerPic(struct Sprite *); static void SpriteCB_MugshotTrainerPic(struct Sprite *);
static void SpriteCB_MugshotTrainerPicPartner(struct Sprite *);
static void SpriteCB_WhiteBarFade(struct Sprite *); static void SpriteCB_WhiteBarFade(struct Sprite *);
static bool8 MugshotTrainerPic_Pause(struct Sprite *); static bool8 MugshotTrainerPic_Pause(struct Sprite *);
static bool8 MugshotTrainerPic_Init(struct Sprite *); static bool8 MugshotTrainerPic_Init(struct Sprite *);
static bool8 MugshotTrainerPic_Slide(struct Sprite *); static bool8 MugshotTrainerPic_Slide(struct Sprite *);
static bool8 MugshotTrainerPic_SlideSlow(struct Sprite *); static bool8 MugshotTrainerPic_SlideSlow(struct Sprite *);
static bool8 MugshotTrainerPic_SlidePartner(struct Sprite *);
static bool8 MugshotTrainerPic_SlideOffscreen(struct Sprite *); static bool8 MugshotTrainerPic_SlideOffscreen(struct Sprite *);
static s16 sDebug_RectangularSpiralData; static s16 sDebug_RectangularSpiralData;
@ -544,6 +547,17 @@ static const TransitionSpriteCallback sMugshotTrainerPicFuncs[] =
MugshotTrainerPic_Pause MugshotTrainerPic_Pause
}; };
static const TransitionSpriteCallbackPartner sMugshotTrainerPicFuncsPartner[] =
{
MugshotTrainerPic_Pause,
MugshotTrainerPic_Init,
MugshotTrainerPic_SlidePartner,
MugshotTrainerPic_SlideSlow,
MugshotTrainerPic_Pause,
MugshotTrainerPic_SlideOffscreen,
MugshotTrainerPic_Pause
};
// One element per slide direction. // One element per slide direction.
// Sign of acceleration is opposite speed, so slide decelerates. // Sign of acceleration is opposite speed, so slide decelerates.
static const s16 sTrainerPicSlideSpeeds[2] = {12, -12}; static const s16 sTrainerPicSlideSpeeds[2] = {12, -12};
@ -2217,8 +2231,10 @@ static void VBlankCB_Wave(void)
#define tBottomBannerX data[3] #define tBottomBannerX data[3]
#define tTimer data[3] // Re-used #define tTimer data[3] // Re-used
#define tFadeSpread data[4] #define tFadeSpread data[4]
#define tOpponentSpriteId data[13] #define tOpponentSpriteAId data[11]
#define tOpponentSpriteBId data[12]
#define tPlayerSpriteId data[14] #define tPlayerSpriteId data[14]
#define tPartnerSpriteId data[13]
// Sprite data for trainer sprites in mugshots // Sprite data for trainer sprites in mugshots
#define sState data[0] #define sState data[0]
@ -2359,14 +2375,18 @@ static bool8 Mugshot_StartOpponentSlide(struct Task *task)
sTransitionData->BG0HOFS_Lower -= 8; sTransitionData->BG0HOFS_Lower -= 8;
sTransitionData->BG0HOFS_Upper += 8; sTransitionData->BG0HOFS_Upper += 8;
SetTrainerPicSlideDirection(task->tOpponentSpriteId, 0); SetTrainerPicSlideDirection(task->tOpponentSpriteAId, 0);
SetTrainerPicSlideDirection(task->tOpponentSpriteBId, 0);
SetTrainerPicSlideDirection(task->tPlayerSpriteId, 1); SetTrainerPicSlideDirection(task->tPlayerSpriteId, 1);
SetTrainerPicSlideDirection(task->tPartnerSpriteId, 1);
// Start opponent slide // Start opponent slide
IncrementTrainerPicState(task->tOpponentSpriteId); IncrementTrainerPicState(task->tOpponentSpriteAId);
PlaySE(SE_MUGSHOT); PlaySE(SE_MUGSHOT);
IncrementTrainerPicState(task->tOpponentSpriteBId);
sTransitionData->VBlank_DMA++; sTransitionData->VBlank_DMA++;
return FALSE; return FALSE;
} }
@ -2377,9 +2397,10 @@ static bool8 Mugshot_WaitStartPlayerSlide(struct Task *task)
sTransitionData->BG0HOFS_Upper += 8; sTransitionData->BG0HOFS_Upper += 8;
// Start player's slide in once the opponent is finished // Start player's slide in once the opponent is finished
if (IsTrainerPicSlideDone(task->tOpponentSpriteId)) if (IsTrainerPicSlideDone(task->tOpponentSpriteAId))
{ {
task->tState++; task->tState++;
IncrementTrainerPicState(task->tPartnerSpriteId);
IncrementTrainerPicState(task->tPlayerSpriteId); IncrementTrainerPicState(task->tPlayerSpriteId);
} }
return FALSE; return FALSE;
@ -2390,20 +2411,49 @@ static bool8 Mugshot_WaitPlayerSlide(struct Task *task)
sTransitionData->BG0HOFS_Lower -= 8; sTransitionData->BG0HOFS_Lower -= 8;
sTransitionData->BG0HOFS_Upper += 8; sTransitionData->BG0HOFS_Upper += 8;
if (IsTrainerPicSlideDone(task->tPlayerSpriteId)) if (gPartnerTrainerId != TRAINER_PARTNER(PARTNER_NONE) && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{ {
sTransitionData->VBlank_DMA = FALSE; if (IsTrainerPicSlideDone(task->tPartnerSpriteId))
SetVBlankCallback(NULL); {
DmaStop(0); sTransitionData->VBlank_DMA = FALSE;
memset(gScanlineEffectRegBuffers[0], 0, DISPLAY_HEIGHT * 2); SetVBlankCallback(NULL);
memset(gScanlineEffectRegBuffers[1], 0, DISPLAY_HEIGHT * 2); DmaStop(0);
SetGpuReg(REG_OFFSET_WIN0H, DISPLAY_WIDTH); memset(gScanlineEffectRegBuffers[0], 0, DISPLAY_HEIGHT * 2);
SetGpuReg(REG_OFFSET_BLDY, 0); memset(gScanlineEffectRegBuffers[1], 0, DISPLAY_HEIGHT * 2);
task->tState++; SetGpuReg(REG_OFFSET_WIN0H, DISPLAY_WIDTH);
task->tTimer = 0; SetGpuReg(REG_OFFSET_BLDY, 0);
task->tFadeSpread = 0; task->tState++;
sTransitionData->BLDCNT = BLDCNT_TGT1_ALL | BLDCNT_EFFECT_LIGHTEN; task->tTimer = 0;
SetVBlankCallback(VBlankCB_MugshotsFadeOut); task->tFadeSpread = 0;
sTransitionData->BLDCNT = BLDCNT_TGT1_ALL | BLDCNT_EFFECT_LIGHTEN;
SetVBlankCallback(VBlankCB_MugshotsFadeOut);
}
else
{
return FALSE;
}
}
else
{
if (IsTrainerPicSlideDone(task->tPlayerSpriteId))
{
sTransitionData->VBlank_DMA = FALSE;
SetVBlankCallback(NULL);
DmaStop(0);
memset(gScanlineEffectRegBuffers[0], 0, DISPLAY_HEIGHT * 2);
memset(gScanlineEffectRegBuffers[1], 0, DISPLAY_HEIGHT * 2);
SetGpuReg(REG_OFFSET_WIN0H, DISPLAY_WIDTH);
SetGpuReg(REG_OFFSET_BLDY, 0);
task->tState++;
task->tTimer = 0;
task->tFadeSpread = 0;
sTransitionData->BLDCNT = BLDCNT_TGT1_ALL | BLDCNT_EFFECT_LIGHTEN;
SetVBlankCallback(VBlankCB_MugshotsFadeOut);
}
else
{
return FALSE;
}
} }
return FALSE; return FALSE;
} }
@ -2518,48 +2568,83 @@ static void HBlankCB_Mugshots(void)
static void Mugshots_CreateTrainerPics(struct Task *task) static void Mugshots_CreateTrainerPics(struct Task *task)
{ {
struct Sprite *opponentSprite, *playerSprite; struct Sprite *opponentSpriteA, *opponentSpriteB=0, *playerSprite, *partnerSprite=0;
u8 trainerPicId = GetTrainerPicFromId(TRAINER_BATTLE_PARAM.opponentA); u8 trainerAPicId = GetTrainerPicFromId(TRAINER_BATTLE_PARAM.opponentA);
s16 opponentRotationScales = 0; u8 trainerBPicId = GetTrainerPicFromId(TRAINER_BATTLE_PARAM.opponentB);
u8 partnerPicId = gTrainerPicToTrainerBackPic[GetTrainerPicFromId(gPartnerTrainerId)];
s16 opponentARotationScales = 0;
s16 opponentBRotationScales = 0;
gReservedSpritePaletteCount = 10; gReservedSpritePaletteCount = 10;
task->tOpponentSpriteId = CreateTrainerSprite(trainerPicId, if (TRAINER_BATTLE_PARAM.opponentB != TRAINER_NONE && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
gTrainerSprites[trainerPicId].mugshotCoords.x - 32, {
gTrainerSprites[trainerPicId].mugshotCoords.y + 42, task->tOpponentSpriteBId = CreateTrainerSprite(trainerBPicId,
gTrainerSprites[trainerBPicId].mugshotCoords.x - 240,
gTrainerSprites[trainerBPicId].mugshotCoords.y + 42,
0, NULL);
opponentSpriteB = &gSprites[task->tOpponentSpriteBId];
opponentSpriteB->callback = SpriteCB_MugshotTrainerPicPartner;
opponentSpriteB->oam.affineMode = ST_OAM_AFFINE_DOUBLE;
opponentSpriteB->oam.matrixNum = AllocOamMatrix();
opponentSpriteB->oam.shape = SPRITE_SHAPE(64x32);
opponentSpriteB->oam.size = SPRITE_SIZE(64x32);
CalcCenterToCornerVec(opponentSpriteB, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ST_OAM_AFFINE_DOUBLE);
opponentBRotationScales = gTrainerSprites[trainerBPicId].mugshotRotation;
SetOamMatrixRotationScaling(opponentSpriteB->oam.matrixNum, opponentBRotationScales, opponentBRotationScales, 0);
}
task->tOpponentSpriteAId = CreateTrainerSprite(trainerAPicId,
gTrainerSprites[trainerAPicId].mugshotCoords.x - 32,
gTrainerSprites[trainerAPicId].mugshotCoords.y + 42,
0, NULL); 0, NULL);
gReservedSpritePaletteCount = 12; gReservedSpritePaletteCount = 12;
if (gPartnerTrainerId != TRAINER_PARTNER(PARTNER_NONE) && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
task->tPlayerSpriteId = CreateTrainerSprite(PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender), {
DISPLAY_WIDTH + 32, task->tPartnerSpriteId = CreateTrainerSprite(partnerPicId,
106, DISPLAY_WIDTH + 240,
106,
0, NULL); 0, NULL);
partnerSprite = &gSprites[task->tPartnerSpriteId];
partnerSprite->callback = SpriteCB_MugshotTrainerPicPartner;
partnerSprite->oam.affineMode = ST_OAM_AFFINE_DOUBLE;
partnerSprite->oam.matrixNum = AllocOamMatrix();
partnerSprite->oam.shape = SPRITE_SHAPE(64x32);
partnerSprite->oam.size = SPRITE_SIZE(64x32);
CalcCenterToCornerVec(partnerSprite, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ST_OAM_AFFINE_DOUBLE);
SetOamMatrixRotationScaling(partnerSprite->oam.matrixNum, -512, 512, 0);
}
opponentSprite = &gSprites[task->tOpponentSpriteId]; task->tPlayerSpriteId = CreateTrainerSprite(PlayerGenderToFrontTrainerPicId(gSaveBlock2Ptr->playerGender),
DISPLAY_WIDTH + 32,
106,
0, NULL);
opponentSpriteA = &gSprites[task->tOpponentSpriteAId];
playerSprite = &gSprites[task->tPlayerSpriteId]; playerSprite = &gSprites[task->tPlayerSpriteId];
opponentSprite->callback = SpriteCB_MugshotTrainerPic; opponentSpriteA->callback = SpriteCB_MugshotTrainerPic;
playerSprite->callback = SpriteCB_MugshotTrainerPic; playerSprite->callback = SpriteCB_MugshotTrainerPic;
opponentSprite->oam.affineMode = ST_OAM_AFFINE_DOUBLE; opponentSpriteA->oam.affineMode = ST_OAM_AFFINE_DOUBLE;
playerSprite->oam.affineMode = ST_OAM_AFFINE_DOUBLE; playerSprite->oam.affineMode = ST_OAM_AFFINE_DOUBLE;
opponentSprite->oam.matrixNum = AllocOamMatrix(); opponentSpriteA->oam.matrixNum = AllocOamMatrix();
playerSprite->oam.matrixNum = AllocOamMatrix(); playerSprite->oam.matrixNum = AllocOamMatrix();
opponentSprite->oam.shape = SPRITE_SHAPE(64x32); opponentSpriteA->oam.shape = SPRITE_SHAPE(64x32);
playerSprite->oam.shape = SPRITE_SHAPE(64x32); playerSprite->oam.shape = SPRITE_SHAPE(64x32);
opponentSprite->oam.size = SPRITE_SIZE(64x32); opponentSpriteA->oam.size = SPRITE_SIZE(64x32);
playerSprite->oam.size = SPRITE_SIZE(64x32); playerSprite->oam.size = SPRITE_SIZE(64x32);
CalcCenterToCornerVec(opponentSprite, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ST_OAM_AFFINE_DOUBLE); CalcCenterToCornerVec(opponentSpriteA, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ST_OAM_AFFINE_DOUBLE);
CalcCenterToCornerVec(playerSprite, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ST_OAM_AFFINE_DOUBLE); CalcCenterToCornerVec(playerSprite, SPRITE_SHAPE(64x32), SPRITE_SIZE(64x32), ST_OAM_AFFINE_DOUBLE);
opponentRotationScales = gTrainerSprites[trainerPicId].mugshotRotation; opponentARotationScales = gTrainerSprites[trainerAPicId].mugshotRotation;
SetOamMatrixRotationScaling(opponentSprite->oam.matrixNum, opponentRotationScales, opponentRotationScales, 0);
SetOamMatrixRotationScaling(opponentSpriteA->oam.matrixNum, opponentARotationScales, opponentARotationScales, 0);
SetOamMatrixRotationScaling(playerSprite->oam.matrixNum, -512, 512, 0); SetOamMatrixRotationScaling(playerSprite->oam.matrixNum, -512, 512, 0);
} }
@ -2568,6 +2653,12 @@ static void SpriteCB_MugshotTrainerPic(struct Sprite *sprite)
while (sMugshotTrainerPicFuncs[sprite->sState](sprite)); while (sMugshotTrainerPicFuncs[sprite->sState](sprite));
} }
static void SpriteCB_MugshotTrainerPicPartner(struct Sprite *sprite)
{
while (sMugshotTrainerPicFuncsPartner[sprite->sState](sprite));
}
// Wait until IncrementTrainerPicState is called // Wait until IncrementTrainerPicState is called
static bool8 MugshotTrainerPic_Pause(struct Sprite *sprite) static bool8 MugshotTrainerPic_Pause(struct Sprite *sprite)
{ {
@ -2600,6 +2691,18 @@ static bool8 MugshotTrainerPic_Slide(struct Sprite *sprite)
return FALSE; return FALSE;
} }
static bool8 MugshotTrainerPic_SlidePartner(struct Sprite *sprite)
{
sprite->x += sprite->sSlideSpeed;
// Advance state when pic passes ~40% of screen
if (sprite->sSlideDir && sprite->x < DISPLAY_WIDTH - 60)
sprite->sState++;
else if (!sprite->sSlideDir && sprite->x > 60)
sprite->sState++;
return FALSE;
}
static bool8 MugshotTrainerPic_SlideSlow(struct Sprite *sprite) static bool8 MugshotTrainerPic_SlideSlow(struct Sprite *sprite)
{ {
// Add acceleration value to speed, then add speed. // Add acceleration value to speed, then add speed.
@ -2654,8 +2757,10 @@ static s16 IsTrainerPicSlideDone(s16 spriteId)
#undef tBottomBannerX #undef tBottomBannerX
#undef tTimer #undef tTimer
#undef tFadeSpread #undef tFadeSpread
#undef tOpponentSpriteId #undef tOpponentSpriteAId
#undef tOpponentSpriteBId
#undef tPlayerSpriteId #undef tPlayerSpriteId
#undef tPartnerSpriteId
//-------------------- //--------------------
// B_TRANSITION_SLICE // B_TRANSITION_SLICE

View File

@ -1,4 +1,4 @@
const u8 gFacilityClassToPicIndex[] = const u16 gFacilityClassToPicIndex[] =
{ {
[FACILITY_CLASS_HIKER] = TRAINER_PIC_HIKER, [FACILITY_CLASS_HIKER] = TRAINER_PIC_HIKER,
[FACILITY_CLASS_AQUA_GRUNT_M] = TRAINER_PIC_AQUA_GRUNT_M, [FACILITY_CLASS_AQUA_GRUNT_M] = TRAINER_PIC_AQUA_GRUNT_M,
@ -84,7 +84,19 @@ const u8 gFacilityClassToPicIndex[] =
[FACILITY_CLASS_RS_MAY] = TRAINER_PIC_RS_MAY, [FACILITY_CLASS_RS_MAY] = TRAINER_PIC_RS_MAY,
}; };
const u8 gFacilityClassToTrainerClass[] = const u16 gTrainerPicToTrainerBackPic[] =
{
[TRAINER_BACK_PIC_BRENDAN] = TRAINER_PIC_BRENDAN,
[TRAINER_BACK_PIC_MAY] = TRAINER_PIC_MAY,
[TRAINER_BACK_PIC_RED] = TRAINER_PIC_RED,
[TRAINER_BACK_PIC_LEAF] = TRAINER_PIC_LEAF,
[TRAINER_BACK_PIC_RUBY_SAPPHIRE_BRENDAN] = TRAINER_PIC_RS_BRENDAN,
[TRAINER_BACK_PIC_RUBY_SAPPHIRE_MAY] = TRAINER_PIC_RS_MAY,
[TRAINER_BACK_PIC_WALLY] = TRAINER_PIC_WALLY,
[TRAINER_BACK_PIC_STEVEN] = TRAINER_PIC_STEVEN,
};
const u16 gFacilityClassToTrainerClass[] =
{ {
[FACILITY_CLASS_HIKER] = TRAINER_CLASS_HIKER, [FACILITY_CLASS_HIKER] = TRAINER_CLASS_HIKER,
[FACILITY_CLASS_AQUA_GRUNT_M] = TRAINER_CLASS_TEAM_AQUA, [FACILITY_CLASS_AQUA_GRUNT_M] = TRAINER_CLASS_TEAM_AQUA,