diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 3cf79d634..86dd652f4 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -150,7 +150,7 @@ .macro jumpifability param0:req, ability:req, ptr:req .byte 0x1e .byte \param0 - .byte \ability + .2byte \ability .4byte \ptr .endm @@ -372,7 +372,7 @@ .macro jumpifabilitypresent ability:req, ptr:req .byte 0x43 - .byte \ability + .2byte \ability .4byte \ptr .endm diff --git a/data/maps/ViridianCity_Mart/scripts.inc b/data/maps/ViridianCity_Mart/scripts.inc index 568c7dd32..5a3a54d7e 100644 --- a/data/maps/ViridianCity_Mart/scripts.inc +++ b/data/maps/ViridianCity_Mart/scripts.inc @@ -92,12 +92,8 @@ ViridianCity_Mart_Items:: .2byte ITEM_FIRE_STONE .2byte ITEM_ICE_STONE .2byte ITEM_BLACK_AUGURITE - .2byte ITEM_POMEG_BERRY - .2byte ITEM_KELPSY_BERRY - .2byte ITEM_QUALOT_BERRY - .2byte ITEM_HONDEW_BERRY - .2byte ITEM_GREPA_BERRY - .2byte ITEM_TAMATO_BERRY + .2byte ITEM_ABILITY_CAPSULE + .2byte ITEM_ABILITY_PATCH .2byte ITEM_NONE release end diff --git a/include/battle.h b/include/battle.h index 1f5d9abcb..f5c4ef286 100644 --- a/include/battle.h +++ b/include/battle.h @@ -296,7 +296,7 @@ struct UsedMoves struct BattleHistory { /*0x00*/ u16 usedMoves[2][8]; // 0xFFFF means move not used (confuse self hit, etc) - /*0x20*/ u8 abilities[MAX_BATTLERS_COUNT / 2]; + /*0x20*/ u16 abilities[MAX_BATTLERS_COUNT / 2]; /*0x22*/ u8 itemEffects[MAX_BATTLERS_COUNT / 2]; /*0x24*/ u16 trainerItems[MAX_BATTLERS_COUNT]; /*0x2C*/ u8 itemsNo; @@ -426,7 +426,7 @@ struct BattleStruct u8 simulatedInputState[4]; // used by Oak/Old Man/Pokedude controllers u8 lastTakenMove[MAX_BATTLERS_COUNT * 2 * 2]; // ask gamefreak why they declared it that way u16 hpOnSwitchout[2]; - u8 abilityPreventingSwitchout; + u16 abilityPreventingSwitchout; u8 hpScale; u16 savedBattleTypeFlags; void (*savedCallback)(void); @@ -656,7 +656,7 @@ extern u16 gChosenMove; extern u16 gCalledMove; extern u8 gCritMultiplier; extern u16 gBattleWeather; -extern u8 gLastUsedAbility; +extern u16 gLastUsedAbility; extern u8 gBattlerInMenuId; extern u8 gPotentialItemEffectBattler; extern u8 gBattlersCount; diff --git a/include/battle_ai_script_commands.h b/include/battle_ai_script_commands.h index 94cbcce15..6e7cdd653 100644 --- a/include/battle_ai_script_commands.h +++ b/include/battle_ai_script_commands.h @@ -12,7 +12,7 @@ void BattleAI_HandleItemUseBeforeAISetup(void); void BattleAI_SetupAIData(void); u8 BattleAI_ChooseMoveOrAction(void); void ClearBankMoveHistory(u8 bank); -void RecordAbilityBattle(u8 bank, u8 abilityId); +void RecordAbilityBattle(u8 bank, u16 abilityId); void ClearBankAbilityHistory(u8 bank); void RecordItemEffectBattle(u8 bank, u8 itemEffect); void ClearBankItemEffectHistory(u8 bank); diff --git a/include/battle_controllers.h b/include/battle_controllers.h index 334485c15..4d543ea8a 100644 --- a/include/battle_controllers.h +++ b/include/battle_controllers.h @@ -224,7 +224,7 @@ void BtlController_EmitPrintSelectionString(u8 bufferId, u16 stringId); void BtlController_EmitChooseAction(u8 bufferId, u8 action, u16 itemId); void BtlController_EmitChooseMove(u8 bufferId, bool8 isDoubleBattle, bool8 NoPpNumber, struct ChooseMoveStruct *movePpData); void BtlController_EmitChooseItem(u8 bufferId, u8 *arg1); -void BtlController_EmitChoosePokemon(u8 bufferId, u8 caseId, u8 arg2, u8 abilityId, u8 *arg4); +void BtlController_EmitChoosePokemon(u8 bufferId, u8 caseId, u8 arg2, u16 abilityId, u8 *arg4); void BtlController_EmitHealthBarUpdate(u8 bufferId, u16 hpValue); void BtlController_EmitExpUpdate(u8 bufferId, u8 partyId, u16 expPoints); void BtlController_EmitStatusIconUpdate(u8 bufferId, u32 status1, u32 status2); diff --git a/include/battle_message.h b/include/battle_message.h index ef5cbcd88..ffe8710d0 100644 --- a/include/battle_message.h +++ b/include/battle_message.h @@ -198,13 +198,13 @@ struct BattleMsgData u16 currentMove; u16 originallyUsedMove; u16 lastItem; - u8 lastAbility; + u16 lastAbility; u8 scrActive; u8 bakScriptPartyIdx; u8 hpScale; u8 itemEffectBattler; u8 moveType; - u8 abilities[4]; + u16 abilities[4]; u8 textBuffs[3][0x10]; }; diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 67d9c5faa..44378aa8f 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -9,7 +9,7 @@ void AI_CalcDmg(u8 attacker, u8 defender); u8 TypeCalc(u16 move, u8 attacker, u8 defender); -u8 AI_TypeCalc(u16 move, u16 targetSpecies, u8 targetAbility); +u8 AI_TypeCalc(u16 move, u16 targetSpecies, u16 targetAbility); u8 GetBattlerTurnOrderNum(u8 battlerId); void SetMoveEffect(bool8 primary, u8 certain); bool32 IsMonGettingExpSentOut(void); diff --git a/include/battle_util.h b/include/battle_util.h index 11f5e049a..08556c659 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -85,7 +85,7 @@ void TryClearRageStatuses(void); u8 AtkCanceller_UnableToUseMove(void); bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2); u8 CastformDataTypeChange(u8 battler); -u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveArg); +u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 moveArg); void BattleScriptExecute(const u8 *BS_ptr); void BattleScriptPushCursorAndCallback(const u8 *BS_ptr); u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn); diff --git a/include/constants/pokemon.h b/include/constants/pokemon.h index 9513a8962..856b43e5b 100644 --- a/include/constants/pokemon.h +++ b/include/constants/pokemon.h @@ -81,16 +81,16 @@ #define MON_DATA_NATIONAL_RIBBON 76 #define MON_DATA_EARTH_RIBBON 77 #define MON_DATA_WORLD_RIBBON 78 -#define MON_DATA_UNUSED_RIBBONS 79 -#define MON_DATA_MODERN_FATEFUL_ENCOUNTER 80 -#define MON_DATA_KNOWN_MOVES 81 -#define MON_DATA_RIBBON_COUNT 82 -#define MON_DATA_RIBBONS 83 -#define MON_DATA_ATK2 84 -#define MON_DATA_DEF2 85 -#define MON_DATA_SPEED2 86 -#define MON_DATA_SPATK2 87 -#define MON_DATA_SPDEF2 88 +// #define MON_DATA_UNUSED_RIBBONS 79 +#define MON_DATA_MODERN_FATEFUL_ENCOUNTER 79 +#define MON_DATA_KNOWN_MOVES 80 +#define MON_DATA_RIBBON_COUNT 81 +#define MON_DATA_RIBBONS 82 +#define MON_DATA_ATK2 83 +#define MON_DATA_DEF2 84 +#define MON_DATA_SPEED2 85 +#define MON_DATA_SPATK2 86 +#define MON_DATA_SPDEF2 87 // Pokemon types #define TYPE_NONE 255 diff --git a/include/item_use.h b/include/item_use.h index 43b693130..0b9fca97d 100644 --- a/include/item_use.h +++ b/include/item_use.h @@ -7,6 +7,8 @@ void Task_ItemUse_CloseMessageBoxAndReturnToField_VsSeeker(u8); void Task_UseDigEscapeRopeOnField(u8 taskId); void ItemUse_SetQuestLogEvent(u8, struct Pokemon *, u16, u16); +void ItemUseOutOfBattle_AbilityCapsule(u8); +void ItemUseOutOfBattle_AbilityPatch(u8); void ItemUseOutOfBattle_BerryPouch(u8 taskId); void ItemUseOutOfBattle_Bike(u8 taskId); void ItemUseOutOfBattle_BlackWhiteFlute(u8 taskId); @@ -34,7 +36,6 @@ void ItemUseOutOfBattle_TownMap(u8 taskId); void ItemUseOutOfBattle_VsSeeker(u8 taskId); void ItemUseOutOfBattle_CannotUse(u8 taskId); void ItemUseInBattle_BagMenu(u8 taskId); -// void ItemUseInBattle_BerryPouch(u8 taskId); void ItemUseInBattle_PartyMenu(u8 taskId); void ItemUseInBattle_PartyMenuChooseMove(u8 taskId); u8 CanUseEscapeRopeOnCurrMap(void); diff --git a/include/party_menu.h b/include/party_menu.h index f0d645c7e..fbc9d7236 100644 --- a/include/party_menu.h +++ b/include/party_menu.h @@ -51,6 +51,8 @@ bool8 FieldCallback_PrepareFadeInFromMenu(void); void CB2_ReturnToPartyMenuFromFlyMap(void); void SetUsedFlyQuestLogEvent(const u8 *healLocCtrlData); void CB2_ShowPartyMenuForItemUse(void); +void ItemUseCB_AbilityCapsule(u8 taskId, TaskFunc task); +void ItemUseCB_AbilityPatch(u8 taskId, TaskFunc task); void ItemUseCB_BattleScript(u8 taskId, TaskFunc task); void ItemUseCB_Medicine(u8 taskId, TaskFunc func); void ItemUseCB_ReduceEV(u8 taskId, TaskFunc task); diff --git a/include/pokemon.h b/include/pokemon.h index eb9eca110..a2b718926 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -58,7 +58,7 @@ struct PokemonSubstruct3 /* 0x05 */ u32 spAttackIV:5; /* 0x06 */ u32 spDefenseIV:5; /* 0x07 */ u32 isEgg:1; - /* 0x07 */ u32 abilityNum:1; + /* 0x07 */ u32 abilityNum:2; /* 0x08 */ u32 coolRibbon:3; // Stores the highest contest rank achieved in the Cool category. /* 0x08 */ u32 beautyRibbon:3; // Stores the highest contest rank achieved in the Beauty category. @@ -77,7 +77,7 @@ struct PokemonSubstruct3 /* 0x0B */ u32 nationalRibbon:1; // Given to purified Shadow Pokémon in Colosseum/XD. /* 0x0B */ u32 earthRibbon:1; // Given to teams that have beaten Mt. Battle's 100-battle challenge in Colosseum/XD. /* 0x0B */ u32 worldRibbon:1; // Distributed during Pokémon Festa '04 and '05 to tournament winners. - /* 0x0B */ u32 unusedRibbons:4; // Discarded in Gen 4. + /* 0x0B */ u32 unusedRibbons:3; // Discarded in Gen 4. // The functionality of this bit changed in FRLG: // In RS, this bit does nothing, is never set, & is accidentally unset when hatching Eggs. @@ -187,9 +187,9 @@ struct BattlePokemon /*0x16*/ u32 spAttackIV:5; /*0x17*/ u32 spDefenseIV:5; /*0x17*/ u32 isEgg:1; - /*0x17*/ u32 abilityNum:1; + /*0x17*/ u32 abilityNum:2; /*0x18*/ s8 statStages[NUM_BATTLE_STATS]; - /*0x20*/ u8 ability; + /*0x20*/ u16 ability; /*0x21*/ u8 type1; /*0x22*/ u8 type2; /*0x23*/ u8 unknown; @@ -440,8 +440,8 @@ u8 GiveMonToPlayer(struct Pokemon *mon); u8 CalculatePlayerPartyCount(void); u8 CalculateEnemyPartyCount(void); u8 GetMonsStateToDoubles(void); -u8 GetAbilityBySpecies(u16 species, bool8 abilityNum); -u8 GetMonAbility(struct Pokemon *mon); +u16 GetAbilityBySpecies(u16 species, bool8 abilityNum); +u16 GetMonAbility(struct Pokemon *mon); u8 GetSecretBaseTrainerPicIndex(void); u8 GetSecretBaseTrainerNameIndex(void); bool8 IsPlayerPartyAndPokemonStorageFull(void); diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 892e726de..7e6cf423f 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -482,7 +482,7 @@ static void ClearBattlerMoveHistory(u8 battlerId) BATTLE_HISTORY->usedMoves[battlerId / 2][i] = MOVE_NONE; } -void RecordAbilityBattle(u8 battlerId, u8 abilityId) +void RecordAbilityBattle(u8 battlerId, u16 abilityId) { if (GetBattlerSide(battlerId) == 0) BATTLE_HISTORY->abilities[GET_BATTLER_SIDE(battlerId)] = abilityId; @@ -1152,7 +1152,7 @@ static void Cmd_get_ability(void) { u16 side = GET_BATTLER_SIDE(battlerId); - if (BATTLE_HISTORY->abilities[side] != 0) + if (BATTLE_HISTORY->abilities[side] != ABILITY_NONE) { AI_THINKING_STRUCT->funcResult = BATTLE_HISTORY->abilities[side]; sAIScriptPtr += 2; diff --git a/src/battle_ai_switch_items.c b/src/battle_ai_switch_items.c index 95d527c8f..0fc72bbca 100644 --- a/src/battle_ai_switch_items.c +++ b/src/battle_ai_switch_items.c @@ -83,7 +83,7 @@ static bool8 ShouldSwitchIfWonderGuard(void) static bool8 FindMonThatAbsorbsOpponentsMove(void) { u8 battlerIn1, battlerIn2; - u8 absorbingTypeAbility; + u16 absorbingTypeAbility; s32 i; if ((HasSuperEffectiveMoveAgainstOpponents(TRUE) && Random() % 3) @@ -118,7 +118,7 @@ static bool8 FindMonThatAbsorbsOpponentsMove(void) for (i = 0; i < PARTY_SIZE; ++i) { u16 species; - u8 monAbility; + u16 monAbility; if ((GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) || (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE) @@ -263,7 +263,7 @@ static bool8 FindMonWithFlagsAndSuperEffective(u8 flags, u8 moduloPercent) for (i = 0; i < PARTY_SIZE; ++i) { u16 species; - u8 monAbility; + u16 monAbility; if ((GetMonData(&gEnemyParty[i], MON_DATA_HP) == 0) || (GetMonData(&gEnemyParty[i], MON_DATA_SPECIES_OR_EGG) == SPECIES_NONE) diff --git a/src/battle_controller_oak_old_man.c b/src/battle_controller_oak_old_man.c index 71926e579..1d821aec9 100644 --- a/src/battle_controller_oak_old_man.c +++ b/src/battle_controller_oak_old_man.c @@ -1888,7 +1888,7 @@ static void OakOldManHandleChoosePokemon(void) gTasks[gBattleControllerData[gActiveBattler]].data[0] = gBattleBufferA[gActiveBattler][1] & 0xF; *(&gBattleStruct->battlerPreventingSwitchout) = gBattleBufferA[gActiveBattler][1] >> 4; *(&gBattleStruct->playerPartyIdx) = gBattleBufferA[gActiveBattler][2]; - *(&gBattleStruct->abilityPreventingSwitchout) = gBattleBufferA[gActiveBattler][3]; + *(&gBattleStruct->abilityPreventingSwitchout) = (gBattleBufferA[gActiveBattler][3] & 0xFF) | (gBattleBufferA[gActiveBattler][7] << 8); for (i = 0; i < 3; ++i) gBattlePartyCurrentOrder[i] = gBattleBufferA[gActiveBattler][4 + i]; BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); diff --git a/src/battle_controller_player.c b/src/battle_controller_player.c index 1422fa13b..0924f5506 100644 --- a/src/battle_controller_player.c +++ b/src/battle_controller_player.c @@ -2466,7 +2466,7 @@ static void PlayerHandleChoosePokemon(void) gTasks[gBattleControllerData[gActiveBattler]].data[0] = gBattleBufferA[gActiveBattler][1] & 0xF; *(&gBattleStruct->battlerPreventingSwitchout) = gBattleBufferA[gActiveBattler][1] >> 4; *(&gBattleStruct->playerPartyIdx) = gBattleBufferA[gActiveBattler][2]; - *(&gBattleStruct->abilityPreventingSwitchout) = gBattleBufferA[gActiveBattler][3]; + *(&gBattleStruct->abilityPreventingSwitchout) = (gBattleBufferA[gActiveBattler][3] & 0xFF) | (gBattleBufferA[gActiveBattler][7] << 8); for (i = 0; i < 3; ++i) gBattlePartyCurrentOrder[i] = gBattleBufferA[gActiveBattler][4 + i]; BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); diff --git a/src/battle_controller_pokedude.c b/src/battle_controller_pokedude.c index 62c259c04..2455d747b 100644 --- a/src/battle_controller_pokedude.c +++ b/src/battle_controller_pokedude.c @@ -1624,7 +1624,7 @@ static void PokedudeHandleChoosePokemon(void) gTasks[gBattleControllerData[gActiveBattler]].data[0] = gBattleBufferA[gActiveBattler][1] & 0xF; *(&gBattleStruct->battlerPreventingSwitchout) = gBattleBufferA[gActiveBattler][1] >> 4; *(&gBattleStruct->playerPartyIdx) = gBattleBufferA[gActiveBattler][2]; - *(&gBattleStruct->abilityPreventingSwitchout) = gBattleBufferA[gActiveBattler][3]; + *(&gBattleStruct->abilityPreventingSwitchout) = (gBattleBufferA[gActiveBattler][3] & 0xFF) | (gBattleBufferA[gActiveBattler][7] << 8); for (i = 0; i < 3; ++i) gBattlePartyCurrentOrder[i] = gBattleBufferA[gActiveBattler][4 + i]; BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, RGB_BLACK); diff --git a/src/battle_controllers.c b/src/battle_controllers.c index a2662c39a..ce772cab5 100644 --- a/src/battle_controllers.c +++ b/src/battle_controllers.c @@ -872,14 +872,15 @@ void BtlController_EmitChooseItem(u8 bufferId, u8 *battlePartyOrder) PrepareBufferDataTransfer(bufferId, sBattleBuffersTransferData, 4); } -void BtlController_EmitChoosePokemon(u8 bufferId, u8 caseId, u8 slotId, u8 abilityId, u8 *data) +void BtlController_EmitChoosePokemon(u8 bufferId, u8 caseId, u8 slotId, u16 abilityId, u8 *data) { s32 i; sBattleBuffersTransferData[0] = CONTROLLER_CHOOSEPOKEMON; sBattleBuffersTransferData[1] = caseId; sBattleBuffersTransferData[2] = slotId; - sBattleBuffersTransferData[3] = abilityId; + sBattleBuffersTransferData[3] = abilityId & 0xFF; + sBattleBuffersTransferData[7] = (abilityId >> 8) & 0xFF; for (i = 0; i < 3; i++) sBattleBuffersTransferData[4 + i] = data[i]; PrepareBufferDataTransfer(bufferId, sBattleBuffersTransferData, 8); // Only 7 bytes were written. diff --git a/src/battle_main.c b/src/battle_main.c index aa3be3e35..c2e723a7b 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -159,7 +159,7 @@ EWRAM_DATA s32 gBattleMoveDamage = 0; EWRAM_DATA s32 gHpDealt = 0; EWRAM_DATA s32 gTakenDmg[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA u16 gLastUsedItem = 0; -EWRAM_DATA u8 gLastUsedAbility = 0; +EWRAM_DATA u16 gLastUsedAbility = 0; EWRAM_DATA u8 gBattlerAttacker = 0; EWRAM_DATA u8 gBattlerTarget = 0; EWRAM_DATA u8 gBattlerFainted = 0; diff --git a/src/battle_message.c b/src/battle_message.c index 5bd7065fa..6f1c6935f 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -35,7 +35,7 @@ struct BattleWindowText u8 shadowColor; }; -static EWRAM_DATA u8 sBattlerAbilities[MAX_BATTLERS_COUNT] = {}; +static EWRAM_DATA u16 sBattlerAbilities[MAX_BATTLERS_COUNT] = {}; static EWRAM_DATA struct BattleMsgData *sBattleMsgDataPtr = NULL; static void ChooseMoveUsedParticle(u8 *textPtr); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 9d37d371b..8658f7afa 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1552,7 +1552,7 @@ u8 TypeCalc(u16 move, u8 attacker, u8 defender) return flags; } -u8 AI_TypeCalc(u16 move, u16 targetSpecies, u8 targetAbility) +u8 AI_TypeCalc(u16 move, u16 targetSpecies, u16 targetAbility) { s32 i = 0; u8 flags = 0; @@ -3022,48 +3022,49 @@ static void Cmd_jumpifstatus2(void) static void Cmd_jumpifability(void) { - u8 battlerId; - u8 ability = gBattlescriptCurrInstr[2]; - const u8 *jumpPtr = T2_READ_PTR(gBattlescriptCurrInstr + 3); + CMD_ARGS(u8 battler, u16 ability, const u8 *jumpInstr); + u32 battlerId; + bool32 hasAbility = FALSE; + u32 ability = cmd->ability; - if (gBattlescriptCurrInstr[1] == BS_ATTACKER_SIDE) + if (cmd->battler == BS_ATTACKER_SIDE) { battlerId = AbilityBattleEffects(ABILITYEFFECT_CHECK_BATTLER_SIDE, gBattlerAttacker, ability, 0, 0); if (battlerId) { gLastUsedAbility = ability; - gBattlescriptCurrInstr = jumpPtr; + gBattlescriptCurrInstr = cmd->jumpInstr; RecordAbilityBattle(battlerId - 1, gLastUsedAbility); gBattleScripting.battlerWithAbility = battlerId - 1; } else - gBattlescriptCurrInstr += 7; + gBattlescriptCurrInstr = cmd->nextInstr; } - else if (gBattlescriptCurrInstr[1] == BS_NOT_ATTACKER_SIDE) + else if (cmd->battler == BS_NOT_ATTACKER_SIDE) { battlerId = AbilityBattleEffects(ABILITYEFFECT_CHECK_OTHER_SIDE, gBattlerAttacker, ability, 0, 0); if (battlerId) { gLastUsedAbility = ability; - gBattlescriptCurrInstr = jumpPtr; + gBattlescriptCurrInstr = cmd->jumpInstr; RecordAbilityBattle(battlerId - 1, gLastUsedAbility); gBattleScripting.battlerWithAbility = battlerId - 1; } else - gBattlescriptCurrInstr += 7; + gBattlescriptCurrInstr = cmd->nextInstr; } else { - battlerId = GetBattlerForBattleScript(gBattlescriptCurrInstr[1]); + battlerId = GetBattlerForBattleScript(cmd->battler); if (gBattleMons[battlerId].ability == ability) { gLastUsedAbility = ability; - gBattlescriptCurrInstr = jumpPtr; + gBattlescriptCurrInstr = cmd->jumpInstr; RecordAbilityBattle(battlerId, gLastUsedAbility); gBattleScripting.battlerWithAbility = battlerId; } else - gBattlescriptCurrInstr += 7; + gBattlescriptCurrInstr = cmd->nextInstr; } } @@ -3889,10 +3890,13 @@ static void Cmd_jumpiftype2(void) static void Cmd_jumpifabilitypresent(void) { - if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, gBattlescriptCurrInstr[1], 0, 0)) - gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 2); + CMD_ARGS(u16 ability, const u8 *jumpInstr); + u16 ability = cmd->ability; + + if (AbilityBattleEffects(ABILITYEFFECT_CHECK_ON_FIELD, 0, ability, 0, 0)) + gBattlescriptCurrInstr = cmd->jumpInstr; else - gBattlescriptCurrInstr += 6; + gBattlescriptCurrInstr = cmd->nextInstr; } static void Cmd_endselectionscript(void) @@ -8108,7 +8112,7 @@ static void Cmd_healpartystatus(void) if (species != SPECIES_NONE && species != SPECIES_EGG) { - u8 ability; + u16 ability; if (gBattlerPartyIndexes[gBattlerAttacker] == i) ability = gBattleMons[gBattlerAttacker].ability; @@ -9070,7 +9074,7 @@ static void Cmd_tryswapabilities(void) } else { - u8 abilityAtk = gBattleMons[gBattlerAttacker].ability; + u16 abilityAtk = gBattleMons[gBattlerAttacker].ability; gBattleMons[gBattlerAttacker].ability = gBattleMons[gBattlerTarget].ability; gBattleMons[gBattlerTarget].ability = abilityAtk; diff --git a/src/battle_util.c b/src/battle_util.c index 4b6124198..fe9e9e850 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -1643,7 +1643,7 @@ u8 CastformDataTypeChange(u8 battler) return formChange; } -u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveArg) +u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 moveArg) { u8 effect = 0; struct Pokemon *pokeAtk; diff --git a/src/data/items.h b/src/data/items.h index f26a2e246..465066b56 100644 --- a/src/data/items.h +++ b/src/data/items.h @@ -1357,7 +1357,7 @@ const struct Item gItems[] = "mon's ability."), .pocket = POCKET_ITEMS, .type = ITEM_TYPE_PARTY_MENU, - .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .fieldUseFunc = ItemUseOutOfBattle_AbilityCapsule, }, [ITEM_ABILITY_PATCH] = @@ -1372,7 +1372,7 @@ const struct Item gItems[] = "a rare ability."), .pocket = POCKET_ITEMS, .type = ITEM_TYPE_PARTY_MENU, - .fieldUseFunc = ItemUseOutOfBattle_CannotUse, + .fieldUseFunc = ItemUseOutOfBattle_AbilityPatch, }, // Mints @@ -9363,7 +9363,7 @@ const struct Item gItems[] = [ITEM_TM10] = { .name = _("TM10"), - .price = 2, + .price = 10000, .description = COMPOUND_STRING( "The attack power\n" "varies among\n" diff --git a/src/evolution_scene.c b/src/evolution_scene.c index 10c9c3e4a..36bb65ce9 100644 --- a/src/evolution_scene.c +++ b/src/evolution_scene.c @@ -560,7 +560,7 @@ static void CreateShedinja(u16 preEvoSpecies, struct Pokemon* mon) for (i = MON_DATA_COOL_RIBBON; i < MON_DATA_COOL_RIBBON + CONTEST_CATEGORIES_COUNT; i++) SetMonData(&gPlayerParty[gPlayerPartyCount], i, &data); - for (i = MON_DATA_CHAMPION_RIBBON; i <= MON_DATA_UNUSED_RIBBONS; i++) + for (i = MON_DATA_CHAMPION_RIBBON; i <= MON_DATA_WORLD_RIBBON; i++) SetMonData(&gPlayerParty[gPlayerPartyCount], i, &data); SetMonData(&gPlayerParty[gPlayerPartyCount], MON_DATA_STATUS, &data); diff --git a/src/item_use.c b/src/item_use.c index 669a499b0..3a4bb5a3a 100644 --- a/src/item_use.c +++ b/src/item_use.c @@ -178,6 +178,18 @@ static void Task_ItemUseWaitForFade(u8 taskId) } } +void ItemUseOutOfBattle_AbilityCapsule(u8 taskId) +{ + gItemUseCB = ItemUseCB_AbilityCapsule; + SetUpItemUseCallback(taskId); +} + +void ItemUseOutOfBattle_AbilityPatch(u8 taskId) +{ + gItemUseCB = ItemUseCB_AbilityPatch; + SetUpItemUseCallback(taskId); +} + void ItemUseOutOfBattle_Mail(u8 taskId) { ItemMenu_SetExitCallback(CB2_CheckMail); diff --git a/src/new_game.c b/src/new_game.c index ab5fa9958..feaa543fe 100644 --- a/src/new_game.c +++ b/src/new_game.c @@ -125,7 +125,7 @@ void NewGameInitData(void) ClearPokedexFlags(); InitEventData(); ResetFameChecker(); - SetMoney(&gSaveBlock1Ptr->money, 3000); + SetMoney(&gSaveBlock1Ptr->money, 900000); // change back to 3000 ResetGameStats(); ClearPlayerLinkBattleRecords(); InitHeracrossSizeRecord(); diff --git a/src/party_menu.c b/src/party_menu.c index c0d30150a..f14d0c3b9 100644 --- a/src/party_menu.c +++ b/src/party_menu.c @@ -4428,6 +4428,209 @@ static bool8 IsItemFlute(u16 item) return FALSE; } + +#define tState data[0] +#define tSpecies data[1] +#define tAbilityNum data[2] +#define tMonId data[3] +#define tOldFunc 4 + +void Task_AbilityCapsule(u8 taskId) +{ + static const u8 askText[] = _("Would you like to change {STR_VAR_1}'s\nability to {STR_VAR_2}?"); + static const u8 doneText[] = _("{STR_VAR_1}'s ability became\n{STR_VAR_2}!{PAUSE_UNTIL_PRESS}"); + s16 *data = gTasks[taskId].data; + + DebugPrintfLevel(MGBA_LOG_ERROR, "species: %s", gSpeciesInfo[tSpecies].speciesName); + DebugPrintfLevel(MGBA_LOG_ERROR, "ability1: %s", gAbilityNames[gSpeciesInfo[tSpecies].abilities[0]]); + DebugPrintfLevel(MGBA_LOG_ERROR, "ability2: %s", gAbilityNames[gSpeciesInfo[tSpecies].abilities[1]]); + DebugPrintfLevel(MGBA_LOG_ERROR, "ability3: %s", gAbilityNames[gSpeciesInfo[tSpecies].abilities[2]]); + + switch (tState) + { + case 0: + // Can't use. + if (gSpeciesInfo[tSpecies].abilities[0] == gSpeciesInfo[tSpecies].abilities[1] + || gSpeciesInfo[tSpecies].abilities[1] == ABILITY_NONE + || tAbilityNum > 1 + || !tSpecies) + { + gPartyMenuUseExitCallback = FALSE; + PlaySE(SE_SELECT); + DisplayPartyMenuMessage(gText_WontHaveEffect, 1); + ScheduleBgCopyTilemapToVram(2); + gTasks[taskId].func = Task_ClosePartyMenuAfterText; + return; + } + gPartyMenuUseExitCallback = TRUE; + GetMonNickname(&gPlayerParty[tMonId], gStringVar1); + StringCopy(gStringVar2, gAbilityNames[GetAbilityBySpecies(tSpecies, tAbilityNum)]); + StringExpandPlaceholders(gStringVar4, askText); + PlaySE(SE_SELECT); + DisplayPartyMenuMessage(gStringVar4, 1); + ScheduleBgCopyTilemapToVram(2); + tState++; + break; + case 1: + if (!IsPartyMenuTextPrinterActive()) + { + PartyMenuDisplayYesNoMenu(); + tState++; + } + break; + case 2: + switch (Menu_ProcessInputNoWrapClearOnChoose()) + { + case 0: + tState++; + break; + case 1: + case MENU_B_PRESSED: + gPartyMenuUseExitCallback = FALSE; + PlaySE(SE_SELECT); + ScheduleBgCopyTilemapToVram(2); + // Don't exit party selections screen, return to choosing a mon. + ClearStdWindowAndFrameToTransparent(6, 0); + ClearWindowTilemap(6); + DisplayPartyMenuStdMessage(5); + gTasks[taskId].func = (void *)GetWordTaskArg(taskId, tOldFunc); + return; + } + break; + case 3: + PlaySE(SE_USE_ITEM); + StringExpandPlaceholders(gStringVar4, doneText); + DisplayPartyMenuMessage(gStringVar4, 1); + ScheduleBgCopyTilemapToVram(2); + tState++; + break; + case 4: + if (!IsPartyMenuTextPrinterActive()) + tState++; + break; + case 5: + SetMonData(&gPlayerParty[tMonId], MON_DATA_ABILITY_NUM, &tAbilityNum); + RemoveBagItem(gSpecialVar_ItemId, 1); + gTasks[taskId].func = Task_ClosePartyMenu; + break; + } +} + +void ItemUseCB_AbilityCapsule(u8 taskId, TaskFunc task) +{ + s16 *data = gTasks[taskId].data; + + tState = 0; + tMonId = gPartyMenu.slotId; + tSpecies = GetMonData(&gPlayerParty[tMonId], MON_DATA_SPECIES, NULL); + tAbilityNum = GetMonData(&gPlayerParty[tMonId], MON_DATA_ABILITY_NUM, NULL) ^ 1; + SetWordTaskArg(taskId, tOldFunc, (uintptr_t)(gTasks[taskId].func)); + gTasks[taskId].func = Task_AbilityCapsule; +} + +void Task_AbilityPatch(u8 taskId) +{ + static const u8 askText[] = _("Would you like to change {STR_VAR_1}'s\nability to {STR_VAR_2}?"); + static const u8 doneText[] = _("{STR_VAR_1}'s ability became\n{STR_VAR_2}!{PAUSE_UNTIL_PRESS}"); + s16 *data = gTasks[taskId].data; + + DebugPrintfLevel(MGBA_LOG_ERROR, "species: %S", gSpeciesInfo[tSpecies].speciesName); + DebugPrintfLevel(MGBA_LOG_ERROR, "ability1: %S", gAbilityNames[gSpeciesInfo[tSpecies].abilities[0]]); + DebugPrintfLevel(MGBA_LOG_ERROR, "ability2: %S", gAbilityNames[gSpeciesInfo[tSpecies].abilities[1]]); + DebugPrintfLevel(MGBA_LOG_ERROR, "ability3: %S", gAbilityNames[gSpeciesInfo[tSpecies].abilities[2]]); + + switch (tState) + { + case 0: + // Can't use. + if (gSpeciesInfo[tSpecies].abilities[tAbilityNum] == 0 + || !tSpecies + ) + { + gPartyMenuUseExitCallback = FALSE; + PlaySE(SE_SELECT); + DisplayPartyMenuMessage(gText_WontHaveEffect, 1); + ScheduleBgCopyTilemapToVram(2); + gTasks[taskId].func = Task_ClosePartyMenuAfterText; + return; + } + gPartyMenuUseExitCallback = TRUE; + GetMonNickname(&gPlayerParty[tMonId], gStringVar1); + DebugPrintfLevel(MGBA_LOG_ERROR, "tAbilityNum: %d", tAbilityNum); + DebugPrintfLevel(MGBA_LOG_ERROR, "abilityName: %S", gAbilityNames[GetAbilityBySpecies(tSpecies, tAbilityNum)]); + StringCopy(gStringVar2, gAbilityNames[GetAbilityBySpecies(tSpecies, tAbilityNum)]); + StringExpandPlaceholders(gStringVar4, askText); + PlaySE(SE_SELECT); + DisplayPartyMenuMessage(gStringVar4, 1); + ScheduleBgCopyTilemapToVram(2); + tState++; + break; + case 1: + if (!IsPartyMenuTextPrinterActive()) + { + PartyMenuDisplayYesNoMenu(); + tState++; + } + break; + case 2: + switch (Menu_ProcessInputNoWrapClearOnChoose()) + { + case 0: + tState++; + break; + case 1: + case MENU_B_PRESSED: + gPartyMenuUseExitCallback = FALSE; + PlaySE(SE_SELECT); + ScheduleBgCopyTilemapToVram(2); + // Don't exit party selections screen, return to choosing a mon. + ClearStdWindowAndFrameToTransparent(6, 0); + ClearWindowTilemap(6); + DisplayPartyMenuStdMessage(5); + gTasks[taskId].func = (void *)GetWordTaskArg(taskId, tOldFunc); + return; + } + break; + case 3: + PlaySE(SE_USE_ITEM); + StringExpandPlaceholders(gStringVar4, doneText); + DisplayPartyMenuMessage(gStringVar4, 1); + ScheduleBgCopyTilemapToVram(2); + tState++; + break; + case 4: + if (!IsPartyMenuTextPrinterActive()) + tState++; + break; + case 5: + SetMonData(&gPlayerParty[tMonId], MON_DATA_ABILITY_NUM, &tAbilityNum); + RemoveBagItem(gSpecialVar_ItemId, 1); + gTasks[taskId].func = Task_ClosePartyMenu; + break; + } +} + +void ItemUseCB_AbilityPatch(u8 taskId, TaskFunc task) +{ + s16 *data = gTasks[taskId].data; + + tState = 0; + tMonId = gPartyMenu.slotId; + tSpecies = GetMonData(&gPlayerParty[tMonId], MON_DATA_SPECIES, NULL); + if (GetMonData(&gPlayerParty[tMonId], MON_DATA_ABILITY_NUM, NULL) == 2) + tAbilityNum = 0; + else + tAbilityNum = 2; + SetWordTaskArg(taskId, tOldFunc, (uintptr_t)(gTasks[taskId].func)); + gTasks[taskId].func = Task_AbilityPatch; +} + +#undef tState +#undef tSpecies +#undef tAbilityNum +#undef tMonId +#undef tOldFunc + static bool32 CannotUsePartyBattleItem(u16 itemId, struct Pokemon* mon) { u8 i; diff --git a/src/pokemon.c b/src/pokemon.c index 0c8a8272b..972232371 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -2240,9 +2240,6 @@ u32 GetBoxMonData(struct BoxPokemon *boxMon, s32 field, u8 *data) case MON_DATA_WORLD_RIBBON: retVal = substruct3->worldRibbon; break; - case MON_DATA_UNUSED_RIBBONS: - retVal = substruct3->unusedRibbons; - break; case MON_DATA_MODERN_FATEFUL_ENCOUNTER: retVal = substruct3->modernFatefulEncounter; break; @@ -2394,7 +2391,6 @@ void SetMonData(struct Pokemon *mon, s32 field, const void *dataArg) case MON_DATA_NATIONAL_RIBBON: case MON_DATA_EARTH_RIBBON: case MON_DATA_WORLD_RIBBON: - case MON_DATA_UNUSED_RIBBONS: case MON_DATA_MODERN_FATEFUL_ENCOUNTER: case MON_DATA_KNOWN_MOVES: case MON_DATA_RIBBON_COUNT: @@ -2648,9 +2644,6 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg) case MON_DATA_WORLD_RIBBON: SET8(substruct3->worldRibbon); break; - case MON_DATA_UNUSED_RIBBONS: - SET8(substruct3->unusedRibbons); - break; case MON_DATA_MODERN_FATEFUL_ENCOUNTER: SET8(substruct3->modernFatefulEncounter); break; @@ -2790,17 +2783,32 @@ u8 GetMonsStateToDoubles(void) return (aliveCount > 1) ? PLAYER_HAS_TWO_USABLE_MONS : PLAYER_HAS_ONE_USABLE_MON; } -u8 GetAbilityBySpecies(u16 species, bool8 abilityNum) +u16 GetAbilityBySpecies(u16 species, bool8 abilityNum) { - if (abilityNum) - gLastUsedAbility = gSpeciesInfo[species].abilities[1]; + int i; + + if (abilityNum < NUM_ABILITY_SLOTS) + gLastUsedAbility = gSpeciesInfo[species].abilities[abilityNum]; else - gLastUsedAbility = gSpeciesInfo[species].abilities[0]; + gLastUsedAbility = ABILITY_NONE; + + if (abilityNum >= NUM_NORMAL_ABILITY_SLOTS) // if abilityNum is empty hidden ability, look for other hidden abilities + { + for (i = NUM_NORMAL_ABILITY_SLOTS; i < NUM_ABILITY_SLOTS && gLastUsedAbility == ABILITY_NONE; i++) + { + gLastUsedAbility = gSpeciesInfo[species].abilities[i]; + } + } + + for (i = 0; i < NUM_ABILITY_SLOTS && gLastUsedAbility == ABILITY_NONE; i++) // look for any non-empty ability + { + gLastUsedAbility = gSpeciesInfo[species].abilities[i]; + } return gLastUsedAbility; } -u8 GetMonAbility(struct Pokemon *mon) +u16 GetMonAbility(struct Pokemon *mon) { u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL); u8 abilityNum = GetMonData(mon, MON_DATA_ABILITY_NUM, NULL); diff --git a/src/trade_scene.c b/src/trade_scene.c index c6d0de3aa..1ae7c922e 100644 --- a/src/trade_scene.c +++ b/src/trade_scene.c @@ -2759,7 +2759,7 @@ static void CheckPartnersMonForRibbons(void) { u8 numRibbons = 0; u8 i; - for (i = 0; i < (MON_DATA_UNUSED_RIBBONS - MON_DATA_CHAMPION_RIBBON); i++) + for (i = 0; i < (MON_DATA_WORLD_RIBBON - MON_DATA_CHAMPION_RIBBON); i++) numRibbons += GetMonData(&gEnemyParty[gSelectedTradeMonPositions[TRADE_PARTNER] % PARTY_SIZE], MON_DATA_CHAMPION_RIBBON + i); if (numRibbons != 0) diff --git a/src/wild_encounter.c b/src/wild_encounter.c index 125cdac6a..df17d55ef 100644 --- a/src/wild_encounter.c +++ b/src/wild_encounter.c @@ -336,7 +336,7 @@ static u8 GetAbilityEncounterRateModType(void) sWildEncounterData.abilityEffect = 0; if (!GetMonData(&gPlayerParty[0], MON_DATA_SANITY_IS_EGG)) { - u8 ability = GetMonAbility(&gPlayerParty[0]); + u16 ability = GetMonAbility(&gPlayerParty[0]); if (ability == ABILITY_STENCH) sWildEncounterData.abilityEffect = 1; else if (ability == ABILITY_ILLUMINATE)