Implement double wild battle functionality

This commit is contained in:
DizzyEggg 2018-10-15 21:19:52 +02:00
parent ef11706dc7
commit 67384c08be
8 changed files with 88 additions and 43 deletions

View File

@ -399,6 +399,7 @@ B_BUFF3 = FD 34
B_ATK_TRAINER_NAME = FD 35
B_ATK_TRAINER_CLASS = FD 36
B_ATK_TEAM = FD 37
B_DEF_NAME = FD 38
@ indicates the end of a town/city name (before " TOWN" or " CITY")
NAME_END = FC 00

View File

@ -581,6 +581,7 @@ struct BattleStruct
u32 debugAIFlags;
bool8 notfirstTimeAIFlags;
u8 activeAbilityPopUps; // as bits for each battler
bool8 throwingPokeBall;
struct MegaEvolutionData mega;
};

View File

@ -60,6 +60,7 @@
#define B_TXT_ATK_TRAINER_NAME 0x35
#define B_TXT_ATK_TRAINER_CLASS 0x36
#define B_TXT_ATK_TEAM 0x37
#define B_TXT_DEF_NAME 0x38
// for B_TXT_BUFF1, B_TXT_BUFF2 and B_TXT_BUFF3

View File

@ -2452,7 +2452,7 @@ static void PlayerHandleSuccessBallThrowAnim(void)
{
gBattleSpritesDataPtr->animationData->ballThrowCaseId = BALL_3_SHAKES_SUCCESS;
gDoingBattleAnim = TRUE;
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), B_ANIM_BALL_THROW);
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gBattlerTarget, B_ANIM_BALL_THROW);
gBattlerControllerFuncs[gActiveBattler] = CompleteOnSpecialAnimDone;
}
@ -2462,7 +2462,7 @@ static void PlayerHandleBallThrowAnim(void)
gBattleSpritesDataPtr->animationData->ballThrowCaseId = ballThrowCaseId;
gDoingBattleAnim = TRUE;
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT), B_ANIM_BALL_THROW);
InitAndLaunchSpecialAnimation(gActiveBattler, gActiveBattler, gBattlerTarget, B_ANIM_BALL_THROW);
gBattlerControllerFuncs[gActiveBattler] = CompleteOnSpecialAnimDone;
}

View File

@ -4063,6 +4063,19 @@ u8 IsRunningFromBattleImpossible(void)
gPotentialItemEffectBattler = gActiveBattler;
if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE) // Cannot ever run from saving Birch's battle.
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
return 1;
}
if (GetBattlerPosition(gActiveBattler) == B_POSITION_PLAYER_RIGHT
&& gBattleTypeFlags & BATTLE_TYPE_DOUBLE
&& !(gBattleTypeFlags & (BATTLE_TYPE_TRAINER | BATTLE_TYPE_LINK))) // The second pokemon cannot run from a double wild battle.
{
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
return 1;
}
if (holdEffect == HOLD_EFFECT_CAN_ALWAYS_RUN)
return 0;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
@ -4107,11 +4120,6 @@ u8 IsRunningFromBattleImpossible(void)
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
return 1;
}
if (gBattleTypeFlags & BATTLE_TYPE_FIRST_BATTLE)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
return 1;
}
return 0;
}
@ -4197,6 +4205,13 @@ static void HandleTurnActionSelectionState(void)
gChosenActionByBattler[gActiveBattler] = B_ACTION_USE_MOVE;
gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
}
else if (position == B_POSITION_PLAYER_RIGHT
&& (gBattleStruct->throwingPokeBall || gChosenActionByBattler[GetBattlerAtPosition(B_POSITION_PLAYER_LEFT)] == B_ACTION_RUN))
{
gBattleStruct->throwingPokeBall = FALSE;
gChosenActionByBattler[gActiveBattler] = B_ACTION_NOTHING_FAINTED; // Not fainted, but it cannot move, because of the throwing ball.
gBattleCommunication[gActiveBattler] = STATE_WAIT_ACTION_CONFIRMED_STANDBY;
}
else
{
BtlController_EmitChooseAction(0, gChosenActionByBattler[0], gBattleBufferB[0][1] | (gBattleBufferB[0][2] << 8));
@ -4454,6 +4469,8 @@ static void HandleTurnActionSelectionState(void)
else
{
gLastUsedItem = (gBattleBufferB[gActiveBattler][1] | (gBattleBufferB[gActiveBattler][2] << 8));
if (ItemId_GetPocket(gLastUsedItem) == POCKET_POKE_BALLS)
gBattleStruct->throwingPokeBall = TRUE;
gBattleCommunication[gActiveBattler]++;
}
break;
@ -5804,25 +5821,26 @@ bool8 TryRunFromBattle(u8 battler)
}
else
{
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
u8 runningFromBattler = BATTLE_OPPOSITE(battler);
if (!IsBattlerAlive(runningFromBattler))
runningFromBattler |= BIT_FLANK;
if (InBattlePyramid())
{
if (InBattlePyramid())
{
pyramidMultiplier = sub_81A9E28();
speedVar = (gBattleMons[battler].speed * pyramidMultiplier) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30);
if (speedVar > (Random() & 0xFF))
effect++;
}
else if (gBattleMons[battler].speed < gBattleMons[BATTLE_OPPOSITE(battler)].speed)
{
speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[BATTLE_OPPOSITE(battler)].speed) + (gBattleStruct->runTries * 30);
if (speedVar > (Random() & 0xFF))
effect++;
}
else // same speed or faster
{
pyramidMultiplier = sub_81A9E28();
speedVar = (gBattleMons[battler].speed * pyramidMultiplier) / (gBattleMons[runningFromBattler].speed) + (gBattleStruct->runTries * 30);
if (speedVar > (Random() & 0xFF))
effect++;
}
}
else if (gBattleMons[battler].speed < gBattleMons[runningFromBattler].speed)
{
speedVar = (gBattleMons[battler].speed * 128) / (gBattleMons[runningFromBattler].speed) + (gBattleStruct->runTries * 30);
if (speedVar > (Random() & 0xFF))
effect++;
}
else // same speed or faster
{
effect++;
}
gBattleStruct->runTries++;

View File

@ -477,13 +477,13 @@ static const u8 sText_PkmnBrokeFree[] = _("Oh, no!\nThe POKéMON broke free!");
static const u8 sText_ItAppearedCaught[] = _("Aww!\nIt appeared to be caught!");
static const u8 sText_AarghAlmostHadIt[] = _("Aargh!\nAlmost had it!");
static const u8 sText_ShootSoClose[] = _("Shoot!\nIt was so close, too!");
static const u8 sText_GotchaPkmnCaught[] = _("Gotcha!\n{B_OPPONENT_MON1_NAME} was caught!{UNKNOWN_A}{PLAY_BGM MUS_KACHI22}\p");
static const u8 sText_GotchaPkmnCaught2[] = _("Gotcha!\n{B_OPPONENT_MON1_NAME} was caught!{UNKNOWN_A}{PLAY_BGM MUS_KACHI22}{PAUSE 127}");
static const u8 sText_GiveNicknameCaptured[] = _("Give a nickname to the\ncaptured {B_OPPONENT_MON1_NAME}?");
static const u8 sText_PkmnSentToPC[] = _("{B_OPPONENT_MON1_NAME} was sent to\n{B_PC_CREATOR_NAME} PC.");
static const u8 sText_GotchaPkmnCaught[] = _("Gotcha!\n{B_DEF_NAME} was caught!{UNKNOWN_A}{PLAY_BGM MUS_KACHI22}\p");
static const u8 sText_GotchaPkmnCaught2[] = _("Gotcha!\n{B_DEF_NAME} was caught!{UNKNOWN_A}{PLAY_BGM MUS_KACHI22}{PAUSE 127}");
static const u8 sText_GiveNicknameCaptured[] = _("Give a nickname to the\ncaptured {B_DEF_NAME}?");
static const u8 sText_PkmnSentToPC[] = _("{B_DEF_NAME} was sent to\n{B_PC_CREATOR_NAME} PC.");
static const u8 sText_Someones[] = _("someones");
static const u8 sText_Lanettes[] = _("LANETTEs");
static const u8 sText_PkmnDataAddedToDex[] = _("{B_OPPONENT_MON1_NAME}s data was\nadded to the POKéDEX.\p");
static const u8 sText_PkmnDataAddedToDex[] = _("{B_DEF_NAME}s data was\nadded to the POKéDEX.\p");
static const u8 sText_ItIsRaining[] = _("It is raining.");
static const u8 sText_SandstormIsRaging[] = _("A sandstorm is raging.");
static const u8 sText_BoxIsFull[] = _("The BOX is full!\nYou cant catch any more!\p");
@ -2858,6 +2858,15 @@ u32 BattleStringExpandPlaceholders(const u8 *src, u8 *dst)
case B_TXT_DEF_NAME_WITH_PREFIX: // target name with prefix
HANDLE_NICKNAME_STRING_CASE(gBattlerTarget, gBattlerPartyIndexes[gBattlerTarget])
break;
case B_TXT_DEF_NAME: // target name
if (GetBattlerSide(gBattlerTarget) == B_SIDE_PLAYER)
GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_NICKNAME, text);
else
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_NICKNAME, text);
StringGetEnd10(text);
toCpy = text;
break;
case B_TXT_EFF_NAME_WITH_PREFIX: // effect battlerId name with prefix
HANDLE_NICKNAME_STRING_CASE(gEffectBattler, gBattlerPartyIndexes[gEffectBattler])
break;

View File

@ -10480,6 +10480,14 @@ static void atkEE_removelightscreenreflect(void) // brick break
gBattlescriptCurrInstr++;
}
static u8 GetCatchingBattler(void)
{
if (IsBattlerAlive(GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT)))
return GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
else
return GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
}
static void atkEF_handleballthrow(void)
{
u8 ballMultiplier = 0;
@ -10488,9 +10496,7 @@ static void atkEF_handleballthrow(void)
return;
gActiveBattler = gBattlerAttacker;
gBattlerTarget = gBattlerAttacker ^ BIT_SIDE;
if (!IsBattlerAlive(gBattlerTarget))
gBattlerTarget ^= BIT_FLANK;
gBattlerTarget = GetCatchingBattler();
if (gBattleTypeFlags & BATTLE_TYPE_TRAINER)
{
@ -10632,18 +10638,18 @@ static void atkEF_handleballthrow(void)
static void atkF0_givecaughtmon(void)
{
if (GiveMonToPlayer(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]]) != MON_GIVEN_TO_PARTY)
if (GiveMonToPlayer(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]]) != MON_GIVEN_TO_PARTY)
{
if (!sub_813B21C())
{
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN)));
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_NICKNAME, gStringVar2);
GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_NICKNAME, gStringVar2);
}
else
{
StringCopy(gStringVar1, GetBoxNamePtr(VarGet(VAR_STORAGE_UNKNOWN)));
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_NICKNAME, gStringVar2);
GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_NICKNAME, gStringVar2);
StringCopy(gStringVar3, GetBoxNamePtr(get_unknown_box_id()));
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
}
@ -10652,17 +10658,17 @@ static void atkF0_givecaughtmon(void)
gBattleCommunication[MULTISTRING_CHOOSER]++;
}
gBattleResults.caughtMonSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_SPECIES, NULL);
GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_NICKNAME, gBattleResults.caughtMonNick);
gBattleResults.caughtMonBall = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_POKEBALL, NULL);
gBattleResults.caughtMonSpecies = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_SPECIES, NULL);
GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_NICKNAME, gBattleResults.caughtMonNick);
gBattleResults.caughtMonBall = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_POKEBALL, NULL);
gBattlescriptCurrInstr++;
}
static void atkF1_trysetcaughtmondexflags(void)
{
u16 species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_SPECIES, NULL);
u32 personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_PERSONALITY, NULL);
u16 species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_SPECIES, NULL);
u32 personality = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_PERSONALITY, NULL);
if (GetSetPokedexFlag(SpeciesToNationalPokedexNum(species), FLAG_GET_CAUGHT))
{
@ -10677,7 +10683,7 @@ static void atkF1_trysetcaughtmondexflags(void)
static void atkF2_displaydexinfo(void)
{
u16 species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[gBattlerTarget]], MON_DATA_SPECIES, NULL);
u16 species = GetMonData(&gEnemyParty[gBattlerPartyIndexes[GetCatchingBattler()]], MON_DATA_SPECIES, NULL);
switch (gBattleCommunication[0])
{
@ -10690,8 +10696,8 @@ static void atkF2_displaydexinfo(void)
{
FreeAllWindowBuffers();
gBattleCommunication[TASK_ID] = CreateDexDisplayMonDataTask(SpeciesToNationalPokedexNum(species),
gBattleMons[gBattlerTarget].otId,
gBattleMons[gBattlerTarget].personality);
gBattleMons[GetCatchingBattler()].otId,
gBattleMons[GetCatchingBattler()].personality);
gBattleCommunication[0]++;
}
break;

View File

@ -941,6 +941,15 @@ void ItemUseInBattle_PokeBall(u8 taskId)
else
DisplayItemMessageInBattlePyramid(taskId, textCantThrowPokeBall, sub_81C6714);
}
else if (gBattlerInMenuId == GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT)) // Attempting to throw a ball with the second pokemon.
{
u8 textCantThrowPokeBall[] = _("Cannot throw a ball!\p");
if (!InBattlePyramid())
DisplayItemMessage(taskId, 1, textCantThrowPokeBall, bag_menu_inits_lists_menu);
else
DisplayItemMessageInBattlePyramid(taskId, textCantThrowPokeBall, sub_81C6714);
}
else if (IsPlayerPartyAndPokemonStorageFull() == FALSE) // have room for mon?
{
RemoveBagItem(gSpecialVar_ItemId, 1);