Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ABILITY_SYMBIOSIS #2117

Merged
merged 11 commits into from
Sep 24, 2022
5 changes: 5 additions & 0 deletions asm/macros/battle_script.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ BattleScript_EffectFlingConsumeBerry:
restorebattleritem BS_TARGET
BattleScript_FlingEnd:
tryfaintmon BS_TARGET
trysymbiosis
goto BattleScript_MoveEnd

BattleScript_FlingFlameOrb:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -1763,6 +1765,7 @@ BattleScript_EffectBestow:
waitanimation
printstring STRINGID_BESTOWITEMGIVING
waitmessage B_WAIT_TIME_LONG
trysymbiosis
goto BattleScript_MoveEnd

BattleScript_EffectAfterYou:
Expand Down Expand Up @@ -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
1 change: 1 addition & 0 deletions include/battle_scripts.h
Original file line number Diff line number Diff line change
Expand Up @@ -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[];
Expand Down
1 change: 1 addition & 0 deletions include/constants/battle_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 4 additions & 2 deletions include/constants/battle_script_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/battle_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -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!");
Expand Down
106 changes: 88 additions & 18 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down