diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 25222740fc98..1935e87a783e 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -2132,3 +2132,8 @@ .macro skydropyawn various 0, VARIOUS_SKY_DROP_YAWN .endm + + @ Used by effects that may proc Symbiosis but do not call removeitem. + .macro trysymbiosis + various BS_ATTACKER, VARIOUS_TRY_SYMBIOSIS + .endm diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 3c4b0ef2b73b..96f832d855b7 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -706,6 +706,7 @@ BattleScript_EffectFlingConsumeBerry: restorebattleritem BS_TARGET BattleScript_FlingEnd: tryfaintmon BS_TARGET + trysymbiosis goto BattleScript_MoveEnd BattleScript_FlingFlameOrb: @@ -1392,6 +1393,7 @@ BattleScript_MoveEffectBugBite:: consumeberry BS_ATTACKER, TRUE @ consume the berry, then restore the item from changedItems bicword gHitMarker, HITMARKER_NO_ANIMATIONS setbyte sBERRY_OVERRIDE, FALSE + trysymbiosis return BattleScript_EffectCoreEnforcer: @@ -1763,6 +1765,7 @@ BattleScript_EffectBestow: waitanimation printstring STRINGID_BESTOWITEMGIVING waitmessage B_WAIT_TIME_LONG + trysymbiosis goto BattleScript_MoveEnd BattleScript_EffectAfterYou: @@ -9841,3 +9844,9 @@ BattleScript_MagicianActivates:: call BattleScript_AbilityPopUp call BattleScript_ItemSteal return + +BattleScript_SymbiosisActivates:: + call BattleScript_AbilityPopUp + printstring STRINGID_SYMBIOSISITEMPASS + waitmessage B_WAIT_TIME_LONG + return diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 00a0747bdbf8..2d6364fb962b 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -428,6 +428,7 @@ extern const u8 BattleScript_BeakBlastBurn[]; extern const u8 BattleScript_DefDownSpeedUp[]; extern const u8 BattleScript_AffectionBasedStatusHeal[]; extern const u8 BattleScript_AffectionBasedEndurance[]; +extern const u8 BattleScript_SymbiosisActivates[]; // zmoves extern const u8 BattleScript_ZMoveActivateDamaging[]; diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 4b6c0cc1ec06..dfd4fd3d0457 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -103,6 +103,7 @@ #define B_STURDY GEN_LATEST // In Gen5+, Sturdy causes the Pokémon to have 1 HP remaining if another Pokémon's attack or confusion damage would have brought it from full health to 0 HP. #define B_PLUS_MINUS_INTERACTION GEN_LATEST // In Gen5+, Plus and Minus can be activated with themselves and the opposite ability. Before, only the opposing ability could activate it. #define B_WEATHER_FORMS GEN_LATEST // In Gen5+, Castform and Cherrim revert to their base form upon losing their respective ability. Cherrim needs Flower Gift to swap forms. +#define B_SYMBIOSIS_GEMS GEN_LATEST // In Gen7+, Symbiosis passes an item after a gem-boosted attack. Previously, items are passed before the gem-boosted attack hits, making the item effect apply. // Item settings #define B_HP_BERRIES GEN_LATEST // In Gen4+, berries which restore hp activate immediately after HP drops to half. In Gen3, the effect occurs at the end of the turn. diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 47b0dbe79fdb..e9a091129885 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -242,6 +242,7 @@ #define VARIOUS_SET_BEAK_BLAST 151 #define VARIOUS_SWAP_SIDE_STATUSES 152 #define VARIOUS_SET_Z_EFFECT 153 +#define VARIOUS_TRY_SYMBIOSIS 154 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 @@ -312,8 +313,9 @@ #define MOVEEND_DANCER 28 #define MOVEEND_EMERGENCY_EXIT 29 #define MOVEEND_WEATHER_FORM 30 -#define MOVEEND_CLEAR_BITS 31 -#define MOVEEND_COUNT 32 +#define MOVEEND_SYMBIOSIS 31 +#define MOVEEND_CLEAR_BITS 32 +#define MOVEEND_COUNT 33 // switch cases #define B_SWITCH_NORMAL 0 diff --git a/src/battle_message.c b/src/battle_message.c index e56269eb5f22..568aac774dc3 100644 --- a/src/battle_message.c +++ b/src/battle_message.c @@ -607,7 +607,7 @@ static const u8 sText_HarvestBerry[] = _("{B_ATK_NAME_WITH_PREFIX} harvested\nit static const u8 sText_LastAbilityRaisedBuff1[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_LAST_ABILITY}\nraised its {B_BUFF1}!"); static const u8 sText_MagicBounceActivates[] = _("The {B_DEF_NAME_WITH_PREFIX} bounced the\n{B_ATK_NAME_WITH_PREFIX} back!"); static const u8 sText_ProteanTypeChange[] = _("{B_ATK_NAME_WITH_PREFIX}'s {B_ATK_ABILITY} transformed\nit into the {B_BUFF1} type!"); -static const u8 sText_SymbiosisItemPass[] = _("{B_ATK_NAME_WITH_PREFIX} passed its {B_LAST_ITEM}\nto {B_SCR_ACTIVE_NAME_WITH_PREFIX} through {B_ATK_ABILITY}!"); +static const u8 sText_SymbiosisItemPass[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} passed its {B_LAST_ITEM}\nto {B_ATK_NAME_WITH_PREFIX} through {B_LAST_ABILITY}!"); static const u8 sText_StealthRockDmg[] = _("Pointed stones dug into\n{B_SCR_ACTIVE_NAME_WITH_PREFIX}!"); static const u8 sText_ToxicSpikesAbsorbed[] = _("The poison spikes disappeared\nfrom around the opposing team's feet!"); static const u8 sText_ToxicSpikesPoisoned[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} was poisoned!"); diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index f5884d206dbd..71088540e0fe 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -317,6 +317,7 @@ static void PutMonIconOnLvlUpBanner(void); static void DrawLevelUpBannerText(void); static void SpriteCB_MonIconOnLvlUpBanner(struct Sprite *sprite); static bool32 CriticalCapture(u32 odds); +static void BestowItem(u32 battlerAtk, u32 battlerDef); static void Cmd_attackcanceler(void); static void Cmd_accuracycheck(void); @@ -5084,6 +5085,15 @@ static bool32 TryKnockOffBattleScript(u32 battlerDef) return FALSE; } +#define SYMBIOSIS_CHECK(battler, ally) \ + GetBattlerAbility(ally) == ABILITY_SYMBIOSIS \ + && gBattleMons[battler].item == ITEM_NONE \ + && gBattleMons[ally].item != ITEM_NONE \ + && CanBattlerGetOrLoseItem(battler, gBattleMons[ally].item) \ + && CanBattlerGetOrLoseItem(ally, gBattleMons[ally].item) \ + && gBattleMons[battler].hp != 0 \ + && gBattleMons[ally].hp != 0 + static u32 GetNextTarget(u32 moveTarget) { u32 i; @@ -5748,13 +5758,11 @@ static void Cmd_moveend(void) switch (gBattleMons[i].species) { case SPECIES_CASTFORM: - case SPECIES_CHERRIM: -#ifdef POKEMON_EXPANSION case SPECIES_CASTFORM_RAINY: case SPECIES_CASTFORM_SNOWY: case SPECIES_CASTFORM_SUNNY: + case SPECIES_CHERRIM: case SPECIES_CHERRIM_SUNSHINE: -#endif effect = TryWeatherFormChange(i); if (effect) { @@ -5766,6 +5774,26 @@ static void Cmd_moveend(void) } gBattleScripting.moveendState++; break; + case MOVEEND_SYMBIOSIS: + for (i = 0; i < gBattlersCount; i++) + { + if ((gSpecialStatuses[i].berryReduced + #if B_SYMBIOSIS_GEMS >= GEN_7 + || gSpecialStatuses[i].gemBoost + #endif + ) && SYMBIOSIS_CHECK(i, BATTLE_PARTNER(i))) + { + BestowItem(BATTLE_PARTNER(i), i); + gLastUsedAbility = gBattleMons[BATTLE_PARTNER(i)].ability; + gBattleScripting.battler = gBattlerAbility = BATTLE_PARTNER(i); + gBattlerAttacker = i; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SymbiosisActivates; + effect = TRUE; + } + } + gBattleScripting.moveendState++; + break; case MOVEEND_CLEAR_BITS: // Clear/Set bits for things like using a move for all targets and all hits. if (gSpecialStatuses[gBattlerAttacker].instructedChosenTarget) *(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].instructedChosenTarget & 0x3; @@ -7244,6 +7272,49 @@ static bool32 TryCheekPouch(u32 battlerId, u32 itemId) return FALSE; } +// Used by Bestow and Symbiosis to take an item from one battler and give to another. +static void BestowItem(u32 battlerAtk, u32 battlerDef) +{ + gLastUsedItem = gBattleMons[battlerAtk].item; + + gActiveBattler = battlerAtk; + gBattleMons[battlerAtk].item = ITEM_NONE; + BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[battlerAtk].item), &gBattleMons[battlerAtk].item); + MarkBattlerForControllerExec(battlerAtk); + CheckSetUnburden(battlerAtk); + + gActiveBattler = battlerDef; + gBattleMons[battlerDef].item = gLastUsedItem; + BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[battlerDef].item), &gBattleMons[battlerDef].item); + MarkBattlerForControllerExec(battlerDef); + gBattleResources->flags->flags[battlerDef] &= ~RESOURCE_FLAG_UNBURDEN; +} + +// Called by Cmd_removeitem. itemId represents the item that was removed, not being given. +static bool32 TrySymbiosis(u32 battler, u32 itemId) +{ + if (!gBattleStruct->itemStolen[gBattlerPartyIndexes[battler]].stolen + && gBattleStruct->changedItems[battler] == ITEM_NONE + && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_EJECT_BUTTON + && GetBattlerHoldEffect(battler, TRUE) != HOLD_EFFECT_EJECT_PACK + #if B_SYMBIOSIS_GEMS >= GEN_7 + && !(gSpecialStatuses[battler].gemBoost) + #endif + && gCurrentMove != MOVE_FLING //Fling and damage-reducing berries are handled separately. + && !gSpecialStatuses[battler].berryReduced + && SYMBIOSIS_CHECK(battler, BATTLE_PARTNER(battler))) + { + BestowItem(BATTLE_PARTNER(battler), battler); + gLastUsedAbility = gBattleMons[BATTLE_PARTNER(battler)].ability; + gBattleScripting.battler = gBattlerAbility = BATTLE_PARTNER(battler); + gBattlerAttacker = battler; + BattleScriptPush(gBattlescriptCurrInstr + 2); + gBattlescriptCurrInstr = BattleScript_SymbiosisActivates; + return TRUE; + } + return FALSE; +} + static void Cmd_removeitem(void) { u16 itemId = 0; @@ -7262,7 +7333,7 @@ static void Cmd_removeitem(void) MarkBattlerForControllerExec(gActiveBattler); ClearBattlerItemEffectHistory(gActiveBattler); - if (!TryCheekPouch(gActiveBattler, itemId)) + if (!TryCheekPouch(gActiveBattler, itemId) && !TrySymbiosis(gActiveBattler, itemId)) gBattlescriptCurrInstr += 2; } @@ -9045,20 +9116,7 @@ static void Cmd_various(void) } else { - gLastUsedItem = gBattleMons[gBattlerAttacker].item; - - gActiveBattler = gBattlerAttacker; - gBattleMons[gActiveBattler].item = ITEM_NONE; - BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gActiveBattler].item), &gBattleMons[gActiveBattler].item); - MarkBattlerForControllerExec(gActiveBattler); - CheckSetUnburden(gBattlerAttacker); - - gActiveBattler = gBattlerTarget; - gBattleMons[gActiveBattler].item = gLastUsedItem; - BtlController_EmitSetMonData(BUFFER_A, REQUEST_HELDITEM_BATTLE, 0, sizeof(gBattleMons[gActiveBattler].item), &gBattleMons[gActiveBattler].item); - MarkBattlerForControllerExec(gActiveBattler); - gBattleResources->flags->flags[gBattlerTarget] &= ~RESOURCE_FLAG_UNBURDEN; - + BestowItem(gBattlerAttacker, gBattlerTarget); gBattlescriptCurrInstr += 7; } return; @@ -9788,6 +9846,18 @@ static void Cmd_various(void) case VARIOUS_SWAP_SIDE_STATUSES: CourtChangeSwapSideStatuses(); break; + case VARIOUS_TRY_SYMBIOSIS: //called by Bestow, Fling, and Bug Bite, which don't work with Cmd_removeitem. + if (SYMBIOSIS_CHECK(gActiveBattler, BATTLE_PARTNER(gActiveBattler))) + { + BestowItem(BATTLE_PARTNER(gActiveBattler), gActiveBattler); + gLastUsedAbility = gBattleMons[BATTLE_PARTNER(gActiveBattler)].ability; + gBattleScripting.battler = gBattlerAbility = BATTLE_PARTNER(gActiveBattler); + gBattlerAttacker = gActiveBattler; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_SymbiosisActivates; + return; + } + break; } // End of switch (gBattlescriptCurrInstr[2]) gBattlescriptCurrInstr += 3;