Add critical capture (#402)

* add critical capture

* synax and format fixes
This commit is contained in:
ghoulslash 2020-07-14 09:47:15 -06:00 committed by GitHub
parent b32f3433ae
commit 8f669bb57d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 161 additions and 20 deletions

View File

@ -786,6 +786,7 @@ gBattleAnims_Special::
.4byte Special_SafariBallThrow @ B_ANIM_SAFARI_BALL_THROW
.4byte Special_SubstituteToMon @ B_ANIM_SUBSTITUTE_TO_MON
.4byte Special_MonToSubstitute @ B_ANIM_MON_TO_SUBSTITUTE
.4byte Special_CriticalCaptureBallThrow @ B_ANIM_CRITICAL_CAPTURE_THROW
Move_ROOST:
loadspritegfx ANIM_TAG_WHITE_FEATHER
@ -24449,3 +24450,13 @@ Special_SubstituteToMon:
Special_MonToSubstitute:
createvisualtask AnimTask_SwapMonSpriteToFromSubstitute, 2, FALSE
end
Special_CriticalCaptureBallThrow:
createvisualtask AnimTask_LoadBallGfx, 2
delay 0
playsewithpan SE_RU_HYUU, 0
createvisualtask AnimTask_ThrowBall, 2
createvisualtask AnimTask_IsBallBlockedByTrainer, 2
jumpreteq -1, BallThrowTrainerBlock
goto BallThrowEnd

View File

@ -642,7 +642,9 @@ struct BattleAnimationInfo
u8 field_5;
u8 field_6;
u8 field_7;
u8 ballThrowCaseId;
u8 ballThrowCaseId:6;
u8 isCriticalCapture:1;
u8 criticalCaptureSuccess:1;
u8 field_9_x1:1;
u8 field_9_x2:1;
u8 field_9_x1C:3;

View File

@ -219,6 +219,7 @@ void sub_8172EF0(u8 battler, struct Pokemon *mon);
u8 ItemIdToBallId(u16 itemId);
u8 AnimateBallOpenParticles(u8 x, u8 y, u8 priority, u8 subpriority, u8 ballId);
u8 LaunchBallFadeMonTask(bool8 unFadeLater, u8 battlerId, u32 selectedPalettes, u8 ballId);
bool32 IsCriticalCapture(void);
// battle_anim_utility_funcs.c
void sub_8116EB4(u8);

View File

@ -533,6 +533,7 @@
#define B_ANIM_SAFARI_BALL_THROW 0x4
#define B_ANIM_SUBSTITUTE_TO_MON 0x5
#define B_ANIM_MON_TO_SUBSTITUTE 0x6
#define B_ANIM_CRITICAL_CAPTURE_THROW 0x7
// status animation table
#define B_ANIM_STATUS_PSN 0x0

View File

@ -77,6 +77,7 @@ static void RepeatBallOpenParticleAnimation(u8);
static void TimerBallOpenParticleAnimation(u8);
static void PremierBallOpenParticleAnimation(u8);
static void sub_817330C(struct Sprite *);
static void CB_CriticalCaptureThrownBallMovement(struct Sprite *sprite);
struct BallCaptureSuccessStarData
{
@ -923,7 +924,10 @@ static void sub_817138C(struct Sprite *sprite)
angle = 0;
sprite->pos1.y += Cos(angle, 40);
sprite->pos2.y = -Cos(angle, sprite->data[4]);
sprite->callback = sub_81713D0;
if (IsCriticalCapture())
sprite->callback = CB_CriticalCaptureThrownBallMovement;
else
sprite->callback = sub_81713D0;
}
}
@ -1116,22 +1120,38 @@ static void sub_8171520(struct Sprite *sprite)
case 5:
sprite->data[3] += 0x100;
state = sprite->data[3] >> 8;
if (state == gBattleSpritesDataPtr->animationData->ballThrowCaseId)
if (IsCriticalCapture())
{
sprite->affineAnimPaused = 1;
sprite->callback = sub_81717B4;
}
else
{
if (gBattleSpritesDataPtr->animationData->ballThrowCaseId == BALL_3_SHAKES_SUCCESS && state == 3)
if (gBattleSpritesDataPtr->animationData->criticalCaptureSuccess)
{
sprite->callback = sub_81717D8;
sprite->affineAnimPaused = 1;
}
else
{
sprite->data[3]++;
sprite->affineAnimPaused = 1;
sprite->callback = sub_81717B4;
}
}
else
{
if (state == gBattleSpritesDataPtr->animationData->ballThrowCaseId)
{
sprite->affineAnimPaused = 1;
sprite->callback = sub_81717B4;
}
else
{
if (gBattleSpritesDataPtr->animationData->ballThrowCaseId == BALL_3_SHAKES_SUCCESS && state == 3)
{
sprite->callback = sub_81717D8;
sprite->affineAnimPaused = 1;
}
else
{
sprite->data[3]++;
sprite->affineAnimPaused = 1;
}
}
}
break;
@ -2271,3 +2291,53 @@ void AnimTask_GetBattlersFromArg(u8 taskId)
gBattleAnimTarget = gBattleSpritesDataPtr->animationData->animArg >> 8;
DestroyAnimVisualTask(taskId);
}
bool8 IsCriticalCapture(void)
{
return gBattleSpritesDataPtr->animationData->isCriticalCapture;
}
static void CB_CriticalCaptureThrownBallMovement(struct Sprite *sprite)
{
bool8 lastBounce = FALSE;
u8 maxBounces = 6;
int bounceCount = sprite->data[3] >> 8;
if (bounceCount == 0)
PlaySE(SE_BOWA);
switch (sprite->data[3] & 0xFF)
{
case 0:
if (bounceCount < 3)
sprite->pos2.x++;
if (++sprite->data[5] >= 3)
sprite->data[3] += 257;
break;
case 1:
if (bounceCount < 3 || sprite->pos2.x != 0)
sprite->pos2.x--;
if (--sprite->data[5] <= 0)
{
sprite->data[5] = 0;
sprite->data[3] &= -0x100;
}
if (bounceCount >= maxBounces)
lastBounce = TRUE;
break;
}
if (lastBounce)
{
sprite->data[3] = 0;
sprite->data[4] = 40; //starting max height
sprite->data[5] = 0;
sprite->callback = sub_81713D0;
}
}

View File

@ -2512,7 +2512,11 @@ static void PlayerHandleSuccessBallThrowAnim(void)
{
gBattleSpritesDataPtr->animationData->ballThrowCaseId = BALL_3_SHAKES_SUCCESS;
gDoingBattleAnim = TRUE;
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gBattlerTarget, B_ANIM_BALL_THROW);
if (IsCriticalCapture())
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gBattlerTarget, B_ANIM_CRITICAL_CAPTURE_THROW);
else
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gBattlerTarget, B_ANIM_BALL_THROW);
gBattlerControllerFuncs[gActiveBattler] = CompleteOnSpecialAnimDone;
}
@ -2522,7 +2526,11 @@ static void PlayerHandleBallThrowAnim(void)
gBattleSpritesDataPtr->animationData->ballThrowCaseId = ballThrowCaseId;
gDoingBattleAnim = TRUE;
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gBattlerTarget, B_ANIM_BALL_THROW);
if (IsCriticalCapture())
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gBattlerTarget, B_ANIM_CRITICAL_CAPTURE_THROW);
else
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gBattlerTarget, B_ANIM_BALL_THROW);
gBattlerControllerFuncs[gActiveBattler] = CompleteOnSpecialAnimDone;
}

View File

@ -75,6 +75,7 @@ static void DrawLevelUpWindow2(void);
static bool8 sub_804F344(void);
static void PutMonIconOnLvlUpBox(void);
static void PutLevelAndGenderOnLvlUpBox(void);
static bool32 CriticalCapture(u32 odds);
static void SpriteCB_MonIconOnLvlUpBox(struct Sprite* sprite);
@ -11668,23 +11669,41 @@ static void Cmd_handleballthrow(void)
else // mon may be caught, calculate shakes
{
u8 shakes;
u8 maxShakes;
odds = Sqrt(Sqrt(16711680 / odds));
odds = 1048560 / odds;
for (shakes = 0; shakes < BALL_3_SHAKES_SUCCESS && Random() < odds; shakes++);
gBattleSpritesDataPtr->animationData->isCriticalCapture = 0; //initialize
gBattleSpritesDataPtr->animationData->criticalCaptureSuccess = 0;
if (CriticalCapture(odds))
{
maxShakes = 1; //critical capture doesn't gauarantee capture
gBattleSpritesDataPtr->animationData->isCriticalCapture = 1;
}
else
{
maxShakes = 4;
}
if (gLastUsedItem == ITEM_MASTER_BALL)
shakes = BALL_3_SHAKES_SUCCESS; // why calculate the shakes before that check?
{
shakes = maxShakes;
}
else
{
odds = Sqrt(Sqrt(16711680 / odds));
odds = 1048560 / odds;
for (shakes = 0; shakes < maxShakes && Random() < odds; shakes++);
}
BtlController_EmitBallThrowAnim(0, shakes);
MarkBattlerForControllerExec(gActiveBattler);
if (shakes == BALL_3_SHAKES_SUCCESS) // mon caught, copy of the code above
if (shakes == maxShakes) // mon caught, copy of the code above
{
if (IsCriticalCapture())
gBattleSpritesDataPtr->animationData->criticalCaptureSuccess = 1;
gBattlescriptCurrInstr = BattleScript_SuccessBallThrow;
SetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, &gLastUsedItem);
if (CalculatePlayerPartyCount() == PARTY_SIZE)
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
else
@ -11692,7 +11711,11 @@ static void Cmd_handleballthrow(void)
}
else // not caught
{
gBattleCommunication[MULTISTRING_CHOOSER] = shakes;
if (IsCriticalCapture())
gBattleCommunication[MULTISTRING_CHOOSER] = shakes + 3;
else
gBattleCommunication[MULTISTRING_CHOOSER] = shakes;
gBattlescriptCurrInstr = BattleScript_ShakeBallThrow;
}
}
@ -12094,3 +12117,28 @@ static void Cmd_metalburstdamagecalculator(void)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 1);
}
}
static bool32 CriticalCapture(u32 odds)
{
u16 numCaught = GetNationalPokedexCount(FLAG_GET_CAUGHT);
if (numCaught <= 30)
odds = 0;
else if (numCaught <= 150)
odds /= 2;
else if (numCaught <= 300)
;
else if (numCaught <= 450)
odds = (odds * 150) / 100;
else if (numCaught <= 600)
odds *= 2;
else
odds = (odds * 250) / 100;
odds /= 6;
if ((Random() % 255) < odds)
return TRUE;
return FALSE;
}