diff --git a/charmap.txt b/charmap.txt index 89ca96f558..8c7a99c364 100644 --- a/charmap.txt +++ b/charmap.txt @@ -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 diff --git a/include/battle.h b/include/battle.h index 9be4a745bb..cb13251d5f 100644 --- a/include/battle.h +++ b/include/battle.h @@ -581,6 +581,7 @@ struct BattleStruct u32 debugAIFlags; bool8 notfirstTimeAIFlags; u8 activeAbilityPopUps; // as bits for each battler + bool8 throwingPokeBall; struct MegaEvolutionData mega; }; diff --git a/include/battle_message.h b/include/battle_message.h index 9923230c02..449df1fb33 100644 --- a/include/battle_message.h +++ b/include/battle_message.h @@ -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 diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index e4083f567e..12f1f37afb 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -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; } diff --git a/src/battle_main.c b/src/battle_main.c index 184435024b..13f90aa053 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -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++; diff --git a/src/battle_message.c b/src/battle_message.c index 5594fd7fb4..e16ffcac18 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -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[] = _("someone’s"); static const u8 sText_Lanettes[] = _("LANETTE’s"); -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 can’t 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; diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index f4debb8fef..ef8c0b582e 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -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; diff --git a/src/item_use.c b/src/item_use.c index 6099c0b65c..b218012875 100755 --- a/src/item_use.c +++ b/src/item_use.c @@ -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);