diff --git a/asm/include/battle_commands.inc b/asm/include/battle_commands.inc index d8a75473a8..a135cae49f 100644 --- a/asm/include/battle_commands.inc +++ b/asm/include/battle_commands.inc @@ -1633,7 +1633,13 @@ .long (((\arg_2 - .) / 4) - 1) .endm - .equ BASE_ENGINE_BTL_SCR_CMDS_MAX, 298 + .macro TryActivateReceiver arg_0, arg_1 + .long 299 + .long \arg_0 + .long (((\arg_1 - .) / 4) - 1) + .endm + + .equ BASE_ENGINE_BTL_SCR_CMDS_MAX, 299 // .macro YourCustomCommand // .long (BASE_ENGINE_BTL_SCR_CMDS_MAX + 1) diff --git a/data/battle_scripts/subscripts/subscript_0006_FAINT_MON.s b/data/battle_scripts/subscripts/subscript_0006_FAINT_MON.s index 9edea4edd6..d3bbefd73b 100644 --- a/data/battle_scripts/subscripts/subscript_0006_FAINT_MON.s +++ b/data/battle_scripts/subscripts/subscript_0006_FAINT_MON.s @@ -14,6 +14,7 @@ _000: Wait WaitButtonABTime 30 Call BATTLE_SUBSCRIPT_TRY_CLEAR_PRIMAL_WEATHERS_FAINTING + Call BATTLE_SUBSCRIPT_RECEIVER Call BATTLE_SUBSCRIPT_SOUL_HEART CompareVarToValue OPCODE_FLAG_SET, BSCRIPT_VAR_BATTLE_STATUS_2, BATTLE_STATUS2_NO_EXP_GAINED, _025 diff --git a/data/battle_scripts/subscripts/subscript_0009_SWITCH_POKEMON.s b/data/battle_scripts/subscripts/subscript_0009_SWITCH_POKEMON.s index 8e9afe5369..fad7578165 100644 --- a/data/battle_scripts/subscripts/subscript_0009_SWITCH_POKEMON.s +++ b/data/battle_scripts/subscripts/subscript_0009_SWITCH_POKEMON.s @@ -49,6 +49,7 @@ _047: WaitTime 72 HealthbarSlideIn BATTLER_CATEGORY_SWITCHED_MON Wait + SetCurrentMoveSwitchingStatus CURRENT_MOVE_NO_SWITCH Call BATTLE_SUBSCRIPT_HEALING_WISH Call BATTLE_SUBSCRIPT_HAZARDS_CHECK CompareVarToValue OPCODE_GT, BSCRIPT_VAR_BATTLER_FAINTED, BATTLER_ENEMY2, _081 diff --git a/data/battle_scripts/subscripts/subscript_0523_RECEIVER.s b/data/battle_scripts/subscripts/subscript_0523_RECEIVER.s new file mode 100644 index 0000000000..53f4127581 --- /dev/null +++ b/data/battle_scripts/subscripts/subscript_0523_RECEIVER.s @@ -0,0 +1,24 @@ +#include "constants/battle_constants.h" +.include "battle_commands.inc" + +.data + +_000: + CheckAbility CHECK_OPCODE_HAVE, BATTLER_RELATIVE_ALLY|BATTLER_CATEGORY_FAINTED_MON, ABILITY_RECEIVER, _tryReceiver + CheckAbility CHECK_OPCODE_HAVE, BATTLER_RELATIVE_ALLY|BATTLER_CATEGORY_FAINTED_MON, ABILITY_POWER_OF_ALCHEMY, _tryReceiver + Goto _end + +_tryReceiver: + TryActivateReceiver BATTLER_CATEGORY_FAINTED_MON, _end + UpdateMonDataFromVar OPCODE_GET, BATTLER_CATEGORY_FAINTED_MON, BMON_DATA_ABILITY, BSCRIPT_VAR_CALC_TEMP + AbilityPopup BATTLER_CATEGORY_MSG_BATTLER_TEMP + UpdateMonDataFromVar OPCODE_SET, BATTLER_CATEGORY_MSG_BATTLER_TEMP, BMON_DATA_ABILITY, BSCRIPT_VAR_CALC_TEMP + AbilityPopup BATTLER_CATEGORY_MSG_BATTLER_TEMP + // {0}’s {1} was taken over! + PrintMessage 1795, TAG_NICKNAME_ABILITY, BATTLER_CATEGORY_FAINTED_MON, BATTLER_CATEGORY_FAINTED_MON + Wait + WaitButtonABTime 30 + Call BATTLE_SUBSCRIPT_SWITCH_IN_ABILITY_CHECK + +_end: + End diff --git a/data/battle_tests/abilities/good_as_gold/block_targeted_status.c b/data/battle_tests/abilities/good_as_gold/block_targeted_status.c index 9567f83b68..2d3cb2a9e7 100644 --- a/data/battle_tests/abilities/good_as_gold/block_targeted_status.c +++ b/data/battle_tests/abilities/good_as_gold/block_targeted_status.c @@ -66,7 +66,7 @@ BEGIN_TEST { .species = SPECIES_NONE } }, .playerScript = { { { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, - { ACTION_NONE, 0 }, + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, { ACTION_NONE, 0 }, { ACTION_NONE, 0 }, { ACTION_NONE, 0 }, @@ -76,7 +76,7 @@ BEGIN_TEST }, { { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, - { ACTION_NONE, 0 }, + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, { ACTION_NONE, 0 }, { ACTION_NONE, 0 }, { ACTION_NONE, 0 }, @@ -86,7 +86,7 @@ BEGIN_TEST } }, .enemyScript = { { { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, - { ACTION_NONE, 0 }, + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, { ACTION_NONE, 0 }, { ACTION_NONE, 0 }, { ACTION_NONE, 0 }, @@ -96,7 +96,7 @@ BEGIN_TEST }, { { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, - { ACTION_NONE, 0 }, + { ACTION_MOVE_SLOT_2, BATTLER_ENEMY_FIRST }, { ACTION_NONE, 0 }, { ACTION_NONE, 0 }, { ACTION_NONE, 0 }, @@ -112,6 +112,10 @@ BEGIN_TEST { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "It doesn't affect the opposing Gholdengo..." }, { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Primarina's HP is full!" }, { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Gholdengo's Sp. Atk rose sharply!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Primarina used Helping Hand!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Gholdengo's Good as Gold" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "It doesn't affect the opposing Gholdengo..." }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Gholdengo's Good as Gold" }, } } END_TEST diff --git a/data/battle_tests/abilities/receiver/doubles_valid_and_invalid_ability.c b/data/battle_tests/abilities/receiver/doubles_valid_and_invalid_ability.c new file mode 100644 index 0000000000..8c0b7de91c --- /dev/null +++ b/data/battle_tests/abilities/receiver/doubles_valid_and_invalid_ability.c @@ -0,0 +1,120 @@ +// Test: Receiver - Copy valid ability in doubles +// https://www.youtube.com/watch?v=ibfSvdIW3IE +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_DOUBLES, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_PASSIMIAN, + .level = 50, + .form = 0, + .ability = ABILITY_RECEIVER, + .item = ITEM_NONE, + .moves = { MOVE_CLOSE_COMBAT, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_MAGEARNA, + .level = 15, + .form = 0, + .ability = ABILITY_SOUL_HEART, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_KOMALA, + .level = 5, + .form = 0, + .ability = ABILITY_COMATOSE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_MUK, + .level = 60, + .form = 0, + .ability = ABILITY_POWER_OF_ALCHEMY, + .item = ITEM_CHOICE_BAND, + .moves = { MOVE_CRUNCH, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_SECOND }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_SECOND }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Komala fainted!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_DOES_NOT_CONTAIN, .expectationValue.message = "Muk's Power Of Alchemy" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Magearna's Sp. Atk rose!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Magearna fainted!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Passimian's Receiver" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Passimian's Soul-Heart" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Magearna's Soul-Heart was taken over!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Passimian's Soul-Heart" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Passimian's Sp. Atk rose!" }, + } +} +END_TEST diff --git a/data/battle_tests/abilities/receiver/singles.c b/data/battle_tests/abilities/receiver/singles.c new file mode 100644 index 0000000000..5ec0a387ce --- /dev/null +++ b/data/battle_tests/abilities/receiver/singles.c @@ -0,0 +1,101 @@ +// Test: Receiver - no activation in singles +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_TRAINER, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_PASSIMIAN, + .level = 50, + .form = 0, + .ability = ABILITY_NO_GUARD, + .item = ITEM_NONE, + .moves = { MOVE_CLOSE_COMBAT, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_STUNKY, + .level = 5, + .form = 0, + .ability = ABILITY_STENCH, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_GYARADOS, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_ENEMY_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Stunky fainted!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Gyarados's Intimidate" }, + } +} +END_TEST diff --git a/data/battle_tests/moves/copycat/call_last_success_move.c b/data/battle_tests/moves/copycat/call_last_success_move.c index eff13e82e3..e92fd3d351 100644 --- a/data/battle_tests/moves/copycat/call_last_success_move.c +++ b/data/battle_tests/moves/copycat/call_last_success_move.c @@ -113,7 +113,7 @@ BEGIN_TEST { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Palossand's HP is full!" },//failed move does not overwrite lastMove { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Meowstic used Copycat!" }, { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Meowstic used Thunder Wave!" }, - { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "It doesn’t affect the opposing" }, //random target + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "It doesn't affect the opposing" }, //random target { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Infernape used Ember!" }, { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Dedenne used Copycat!" }, { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Dedenne used Ember!" }, diff --git a/data/battle_tests/moves/flip_turn/doubles.c b/data/battle_tests/moves/flip_turn/doubles.c index f8014b7b58..57be2cbc28 100644 --- a/data/battle_tests/moves/flip_turn/doubles.c +++ b/data/battle_tests/moves/flip_turn/doubles.c @@ -1,4 +1,4 @@ -// Test: Feint - hit through Protect +// Test: Flip Turn - no switch on move failure #include "../../battle_tests.h" BEGIN_TEST { diff --git a/data/battle_tests/moves/flip_turn/hard_switch_prior.c b/data/battle_tests/moves/flip_turn/hard_switch_prior.c new file mode 100644 index 0000000000..ebda0a1820 --- /dev/null +++ b/data/battle_tests/moves/flip_turn/hard_switch_prior.c @@ -0,0 +1,117 @@ +// Test: Flip Turn - Hard switch does not prevent pivot move switching next turn +#include "../../battle_tests.h" +BEGIN_TEST +{ + .battleType = BATTLE_TYPE_TRAINER, + .weather = FIELD_CONDITION_NONE, + .fieldCondition = 0, + .terrain = TERRAIN_NONE, + .playerParty = { + { + .species = SPECIES_DONPHAN, + .level = 50, + .form = 0, + .ability = ABILITY_STURDY, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_PARASECT, + .level = 50, + .form = 0, + .ability = ABILITY_EFFECT_SPORE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } + }, + .enemyParty = { { + .species = SPECIES_QWILFISH, + .level = 50, + .form = 0, + .ability = ABILITY_TORRENT, + .item = ITEM_NONE, + .moves = { MOVE_FLIP_TURN, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { + .species = SPECIES_INCINEROAR, + .level = 50, + .form = 0, + .ability = ABILITY_INTIMIDATE, + .item = ITEM_NONE, + .moves = { MOVE_SLEEP_TALK, MOVE_NONE, MOVE_NONE, MOVE_NONE }, + .hp = FULL_HP, + .status = 0, + .condition2 = 0, + .moveEffectFlags = 0, + }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE }, + { .species = SPECIES_NONE } }, + .playerScript = { { + { ACTION_SWITCH_SLOT_1, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .enemyScript = { { + { ACTION_MOVE_SLOT_1, BATTLER_PLAYER_FIRST }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + }, + { + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + { ACTION_NONE, 0 }, + } }, + .expectations = { + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "Donphan" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Go! Parasect!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "The opposing Qwilfish used Flip Turn!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "It’s not very effective..." }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "The opposing Qwilfish went back" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE_CONTAINS, .expectationValue.message = "sent out Incineroar!" }, + { .expectationType = EXPECTATION_TYPE_MESSAGE, .expectationValue.message = "Incineroar's Intimidate" }, + } +} +END_TEST diff --git a/data/text/197.txt b/data/text/197.txt index 7cd6fbbf26..a88273d258 100644 --- a/data/text/197.txt +++ b/data/text/197.txt @@ -1793,3 +1793,6 @@ The healing wish came true for\nthe wild {STRVAR_1 1, 0, 0}! The healing wish came true for\nthe opposing {STRVAR_1 1, 0, 0}! It created a bizarre area in which\nPokémon’s held items lose\ftheir effects! Magic Room wore off, and held items’\neffects returned to normal! +{STRVAR_1 1, 0, 0}’s {STRVAR_1 5, 1, 0}\nwas taken over! +The wild {STRVAR_1 1, 0, 0}’s {STRVAR_1 5, 1, 0}\nwas taken over! +The opposing {STRVAR_1 1, 0, 0}’s {STRVAR_1 5, 1, 0}\nwas taken over! \ No newline at end of file diff --git a/include/battle.h b/include/battle.h index ffaba692f4..50ff255a8b 100644 --- a/include/battle.h +++ b/include/battle.h @@ -3801,4 +3801,9 @@ BOOL LONG_CALL sub_02017068(void *animManager, int battlerId); void LONG_CALL *ov12_0223B750(struct BattleSystem *battleSystem); void LONG_CALL ov12_022600F0(SysTask *task, void *data); // Task_PlayFaintingSequence +/// @brief Check if ability causes Receiver and Power of Alchemy to fail +/// @param ability +/// @return `TRUE` or `FALSE` +BOOL LONG_CALL AbilityNoReceiver(int ability); + #endif // BATTLE_H diff --git a/include/constants/battle_script_constants.h b/include/constants/battle_script_constants.h index 4bb435fec2..599c64ac81 100644 --- a/include/constants/battle_script_constants.h +++ b/include/constants/battle_script_constants.h @@ -529,8 +529,9 @@ #define BATTLE_SUBSCRIPT_MAGIC_ROOM_END (520) #define BATTLE_SUBSCRIPT_HEAVY_RECOIL (521) #define BATTLE_SUBSCRIPT_PREVENT_INTIMIDATE (522) +#define BATTLE_SUBSCRIPT_RECEIVER (523) -#define MAX_BASE_SUBSCRIPT_NUM 522 +#define MAX_BASE_SUBSCRIPT_NUM 523 // define your custom subscripts below like this // #define MOVE_SUBSCRIPT_CUSTOM_1 (MAX_BASE_SUBSCRIPT_NUM + 1) diff --git a/src/battle/battle_script_commands.c b/src/battle/battle_script_commands.c index 660f6b1db8..4c36fbc61a 100644 --- a/src/battle/battle_script_commands.c +++ b/src/battle/battle_script_commands.c @@ -140,6 +140,7 @@ BOOL btl_scr_cmd_127_ActivateHealingWish(void *bsys UNUSED, struct BattleStruct BOOL btl_scr_cmd_128_IsFieldCondition2On(void *bsys UNUSED, struct BattleStruct *ctx); BOOL btl_scr_cmd_129_SetFieldCondition2(void *bsys UNUSED, struct BattleStruct *ctx); BOOL btl_scr_cmd_12A_GoToIfMoveConditionFlagSet(void *bsys, struct BattleStruct *ctx); +BOOL btl_scr_cmd_12B_TryActivateReceiver(void *bsys, struct BattleStruct *ctx); BOOL BtlCmd_GoToMoveScript(struct BattleSystem *bsys, struct BattleStruct *ctx); BOOL BtlCmd_WeatherHPRecovery(void *bw, struct BattleStruct *sp); BOOL BtlCmd_CalcWeatherBallParams(void *bw, struct BattleStruct *sp); @@ -483,6 +484,7 @@ const u8 *BattleScrCmdNames[] = { "IsFieldCondition2On", "SetFieldCondition2", "GoToIfMoveConditionFlagSet", + "TryActivateReceiver" // "YourCustomCommand", }; @@ -490,7 +492,7 @@ u32 cmdAddress = 0; #pragma GCC diagnostic pop #endif // DEBUG_BATTLE_SCRIPT_COMMANDS -#define BASE_ENGINE_BTL_SCR_CMDS_MAX 0x12A +#define BASE_ENGINE_BTL_SCR_CMDS_MAX 0x12B // clang-format off const btl_scr_cmd_func NewBattleScriptCmdTable[] = { @@ -568,6 +570,7 @@ const btl_scr_cmd_func NewBattleScriptCmdTable[] = { [0x128 - START_OF_NEW_BTL_SCR_CMDS] = btl_scr_cmd_128_IsFieldCondition2On, [0x129 - START_OF_NEW_BTL_SCR_CMDS] = btl_scr_cmd_129_SetFieldCondition2, [0x12A - START_OF_NEW_BTL_SCR_CMDS] = btl_scr_cmd_12A_GoToIfMoveConditionFlagSet, + [0x12B - START_OF_NEW_BTL_SCR_CMDS] = btl_scr_cmd_12B_TryActivateReceiver, // [BASE_ENGINE_BTL_SCR_CMDS_MAX - START_OF_NEW_BTL_SCR_CMDS + 1] = btl_scr_cmd_custom_01_your_custom_command, }; @@ -5883,3 +5886,21 @@ BOOL btl_scr_cmd_12A_GoToIfMoveConditionFlagSet(void *bsys, struct BattleStruct return FALSE; } + +BOOL btl_scr_cmd_12B_TryActivateReceiver(void *bsys, struct BattleStruct *ctx) +{ + IncrementBattleScriptPtr(ctx, 1); + u32 side = read_battle_script_param(ctx); + int noReceiver = read_battle_script_param(ctx); + u32 faintedClient = GrabClientFromBattleScriptParam(bsys, ctx, side); + + int ability = ctx->battlemon[faintedClient].ability; + + if (AbilityNoReceiver(ability)) { + IncrementBattleScriptPtr(ctx, noReceiver); + } else { + ctx->battlerIdTemp = BATTLER_ALLY(faintedClient); + } + + return FALSE; +} diff --git a/src/battle/other_battle_calculators.c b/src/battle/other_battle_calculators.c index 133d2ee098..4ac93b5f56 100644 --- a/src/battle/other_battle_calculators.c +++ b/src/battle/other_battle_calculators.c @@ -4624,3 +4624,11 @@ BOOL LONG_CALL ShouldUseNormalTypeEffCalc(struct BattleStruct *ctx, int attack_c return ret; } + +/// @brief Check if ability causes Receiver and Power of Alchemy to fail +/// @param ability +/// @return `TRUE` or `FALSE` +BOOL LONG_CALL AbilityNoReceiver(int ability) +{ + return GetAbilityFlags(ability).failsReceiver; +} diff --git a/src/individual/BattleController_BeforeMove.c b/src/individual/BattleController_BeforeMove.c index d0f6242dd5..1827800cf5 100644 --- a/src/individual/BattleController_BeforeMove.c +++ b/src/individual/BattleController_BeforeMove.c @@ -162,11 +162,6 @@ BOOL LONG_CALL AbilityDisabledByNeutralizingGas(int ability); /// @return `TRUE` or `FALSE` BOOL LONG_CALL AbilityFailRolePlay(int ability); -/// @brief Check if ability causes Receiver and Power of Alchemy to fail -/// @param ability -/// @return `TRUE` or `FALSE` -BOOL LONG_CALL AbilityNoReceiver(int ability); - /// @brief Check if ability causes Entrainment to fail /// @param ability /// @return `TRUE` or `FALSE` @@ -5096,14 +5091,6 @@ BOOL LONG_CALL AbilityFailRolePlay(int ability) return GetAbilityFlags(ability).failsRolePlay; } -/// @brief Check if ability causes Receiver and Power of Alchemy to fail -/// @param ability -/// @return `TRUE` or `FALSE` -BOOL LONG_CALL AbilityNoReceiver(int ability) -{ - return GetAbilityFlags(ability).failsReceiver; -} - /// @brief Check if ability causes Entrainment to fail /// @param ability /// @return `TRUE` or `FALSE`