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

Opportunist Ability #2994

Merged
merged 18 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 8 additions & 11 deletions data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -8899,17 +8899,6 @@ BattleScript_ActivateTerrainEffects_Increment:
restoretarget
return

BattleScript_ActivateSwitchInAbilities:
copybyte sBATTLER, gBattlerAttacker
setbyte gBattlerAttacker, 0
BattleScript_ActivateSwitchInAbilities_Loop:
switchinabilities BS_ATTACKER
BattleScript_ActivateSwitchInAbilities_Increment:
addbyte gBattlerAttacker, 1
jumpifbytenotequal gBattlerAttacker, gBattlersCount, BattleScript_ActivateSwitchInAbilities_Loop
copybyte gBattlerAttacker, sBATTLER
return

BattleScript_ElectricSurgeActivates::
pause B_WAIT_TIME_SHORT
call BattleScript_AbilityPopUp
Expand Down Expand Up @@ -10054,6 +10043,14 @@ BattleScript_MirrorHerbCopyStatChange::
copybyte gBattlerAttacker, sSAVED_BATTLER @ restore the original attacker just to be safe
return

BattleScript_OpportunistCopyStatChange::
call BattleScript_AbilityPopUp
printstring STRINGID_OPPORTUNISTCOPIED
waitmessage B_WAIT_TIME_LONG
call BattleScript_TotemVar_Ret
copybyte gBattlerAttacker, sSAVED_BATTLER @ restore the original attacker just to be safe
end3

BattleScript_TotemVar::
call BattleScript_TotemVar_Ret
end2
Expand Down
1 change: 1 addition & 0 deletions include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ struct ProtectStruct
u16 shellTrap:1;
u16 silkTrapped:1;
u16 eatMirrorHerb:1;
u16 activateOpportunist:2; // 2 - to copy stats. 1 - stats copied (do not repeat). 0 - no stats to copy
u32 physicalDmg;
u32 specialDmg;
u8 physicalBattlerId;
Expand Down
1 change: 1 addition & 0 deletions include/battle_scripts.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef GUARD_BATTLE_SCRIPTS_H
#define GUARD_BATTLE_SCRIPTS_H

extern const u8 BattleScript_OpportunistCopyStatChange[];
extern const u8 BattleScript_MirrorHerbCopyStatChange[];
extern const u8 BattleScript_MirrorHerbCopyStatChangeEnd2[];
extern const u8 BattleScript_NotAffected[];
Expand Down
1 change: 1 addition & 0 deletions include/battle_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#define ABILITYEFFECT_FIELD_SPORT 13 // Only used if B_SPORT_TURNS < GEN_6
#define ABILITYEFFECT_ON_WEATHER 14
#define ABILITYEFFECT_ON_TERRAIN 15
#define ABILITYEFFECT_OPPORTUNIST 16
// Special cases
#define ABILITYEFFECT_MUD_SPORT 252 // Only used if B_SPORT_TURNS < GEN_6
#define ABILITYEFFECT_WATER_SPORT 253 // Only used if B_SPORT_TURNS < GEN_6
Expand Down
5 changes: 3 additions & 2 deletions include/constants/battle_script_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,9 @@
#define MOVEEND_DANCER 31
#define MOVEEND_EMERGENCY_EXIT 32
#define MOVEEND_SYMBIOSIS 33
#define MOVEEND_CLEAR_BITS 34
#define MOVEEND_COUNT 35
#define MOVEEND_OPPORTUNIST 34 // Occurs after other stat change items/abilities to try and copy the boosts
#define MOVEEND_CLEAR_BITS 35
#define MOVEEND_COUNT 36

// switch cases
#define B_SWITCH_NORMAL 0
Expand Down
3 changes: 2 additions & 1 deletion include/constants/battle_string_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -664,8 +664,9 @@
#define STRINGID_SNOWCONTINUES 662
#define STRINGID_SNOWSTOPPED 663
#define STRINGID_SNOWWARNINGSNOW 664
#define STRINGID_OPPORTUNISTCOPIED 665

#define BATTLESTRINGS_COUNT 665
#define BATTLESTRINGS_COUNT 666

// This is the string id that gBattleStringsTable starts with.
// String ids before this (e.g. STRINGID_INTROMSG) are not in the table,
Expand Down
8 changes: 6 additions & 2 deletions src/battle_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3823,14 +3823,13 @@ static void TryDoEventsBeforeFirstTurn(void)
// Totem boosts
for (i = 0; i < gBattlersCount; i++)
{
if (gTotemBoosts[i].stats != 0)
if (gTotemBoosts[i].stats != 0 && !gProtectStructs[i].eatMirrorHerb && gProtectStructs[i].activateOpportunist == 0)
{
gBattlerAttacker = i;
BattleScriptExecute(BattleScript_TotemVar);
return;
}
}
memset(gTotemBoosts, 0, sizeof(gTotemBoosts)); // erase all totem boosts just to be safe

// Check neutralizing gas
if (AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, 0, 0, 0, 0) != 0)
Expand Down Expand Up @@ -3859,6 +3858,9 @@ static void TryDoEventsBeforeFirstTurn(void)
if (ItemBattleEffects(ITEMEFFECT_ON_SWITCH_IN, gBattlerByTurnOrder[gBattleStruct->switchInItemsCounter++], FALSE))
return;
}

if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
return;

for (i = 0; i < MAX_BATTLERS_COUNT; i++)
{
Expand Down Expand Up @@ -3892,6 +3894,8 @@ static void TryDoEventsBeforeFirstTurn(void)
gMoveResultFlags = 0;

gRandomTurnNumber = Random();

memset(gTotemBoosts, 0, sizeof(gTotemBoosts)); // erase all totem boosts just to be safe

GetAiLogicData(); // get assumed abilities, hold effects, etc of all battlers

Expand Down
2 changes: 2 additions & 0 deletions src/battle_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -799,9 +799,11 @@ static const u8 sText_ItemCuredSpeciesStatus[] = _("{B_BUFF1} had\nits status he
static const u8 sText_ItemRestoredSpeciesPP[] = _("{B_BUFF1} had its\nPP restored!");
static const u8 sText_AtkTrappedDef[] = _("{B_ATK_NAME_WITH_PREFIX} trapped\nthe {B_DEF_NAME_WITH_PREFIX}!");
static const u8 sText_MirrorHerbCopied[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} used its {B_LAST_ITEM}\nto mirror its opponent's stat changes!");
static const u8 sText_OpportunistCopied[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} copied its\nopponent's stat changes!");

const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
{
[STRINGID_OPPORTUNISTCOPIED - BATTLESTRINGS_TABLE_START] = sText_OpportunistCopied,
[STRINGID_MIRRORHERBCOPIED - BATTLESTRINGS_TABLE_START] = sText_MirrorHerbCopied,
[STRINGID_THUNDERCAGETRAPPED - BATTLESTRINGS_TABLE_START] = sText_AtkTrappedDef,
[STRINGID_ITEMRESTOREDSPECIESHEALTH - BATTLESTRINGS_TABLE_START] = sText_ItemRestoredSpeciesHealth,
Expand Down
21 changes: 17 additions & 4 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -5672,6 +5672,12 @@ static void Cmd_moveend(void)
effect = TRUE;
gBattleScripting.moveendState++;
break;
case MOVEEND_OPPORTUNIST:
if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, 0, 0, 0, 0))
effect = TRUE; // it loops through all battlers, so we increment after its done with all battlers
else
gBattleScripting.moveendState++;
break;
case MOVEEND_STATUS_IMMUNITY_ABILITIES: // status immunities
if (AbilityBattleEffects(ABILITYEFFECT_IMMUNITY, 0, 0, 0, 0))
effect = TRUE; // it loops through all battlers, so we increment after its done with all battlers
Expand Down Expand Up @@ -7209,6 +7215,8 @@ static void Cmd_switchineffects(void)
{
if (DoSwitchInAbilitiesItems(gActiveBattler))
return;
else if (AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, gActiveBattler, 0, 0, 0))
return;
}

gSideStatuses[GetBattlerSide(gActiveBattler)] &= ~(SIDE_STATUS_SPIKES_DAMAGED | SIDE_STATUS_TOXIC_SPIKES_DAMAGED | SIDE_STATUS_STEALTH_ROCK_DAMAGED | SIDE_STATUS_STICKY_WEB_DAMAGED);
Expand Down Expand Up @@ -9436,6 +9444,7 @@ static void Cmd_various(void)
AbilityBattleEffects(ABILITYEFFECT_NEUTRALIZINGGAS, gActiveBattler, 0, 0, 0);
AbilityBattleEffects(ABILITYEFFECT_ON_SWITCHIN, gActiveBattler, 0, 0, 0);
AbilityBattleEffects(ABILITYEFFECT_TRACE2, gActiveBattler, 0, 0, 0);
AbilityBattleEffects(ABILITYEFFECT_OPPORTUNIST, gActiveBattler, 0, 0, 0);
return;
}
case VARIOUS_SAVE_TARGET:
Expand Down Expand Up @@ -12133,17 +12142,21 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler);
gProtectStructs[gActiveBattler].statRaised = TRUE;

// check mirror herb
// check mirror herb / opportunist
for (index = 0; index < gBattlersCount; index++)
{
if (GetBattlerSide(index) == GetBattlerSide(gActiveBattler))
continue; // Only triggers on opposing side
if (GetBattlerHoldEffect(index, TRUE) == HOLD_EFFECT_MIRROR_HERB
if (GetBattlerAbility(index) == ABILITY_OPPORTUNIST && gProtectStructs[gActiveBattler].activateOpportunist == 0) {
gProtectStructs[index].activateOpportunist = 2; // set stats to copy
gTotemBoosts[index].stats |= (1 << (statId - 1)); // -1 to start at atk
gTotemBoosts[index].statChanges[statId - 1] += statValue; // cumulative in case of multiple opponent boosts
} else if (GetBattlerHoldEffect(index, TRUE) == HOLD_EFFECT_MIRROR_HERB
&& gBattleMons[index].statStages[statId] < MAX_STAT_STAGE)
{
gProtectStructs[index].eatMirrorHerb = 1;
gProtectStructs[index].eatMirrorHerb = TRUE;
gTotemBoosts[index].stats |= (1 << (statId - 1)); // -1 to start at atk
gTotemBoosts[index].statChanges[statId - 1] = statValue;
gTotemBoosts[index].statChanges[statId - 1] += statValue;
}
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -5890,6 +5890,27 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
break;
}
break;
case ABILITYEFFECT_OPPORTUNIST:
/* Similar to ABILITYEFFECT_IMMUNITY in that it loops through all battlers.
* Is called after ABILITYEFFECT_ON_SWITCHIN to copy any boosts
* from switch in abilities e.g. intrepid sword, as
*/
for (battler = 0; battler < gBattlersCount; battler++)
{
switch (GetBattlerAbility(battler))
{
case ABILITY_OPPORTUNIST:
if (gProtectStructs[battler].activateOpportunist == 2) {
gBattleScripting.savedBattler = gBattlerAttacker;
gBattleScripting.battler = gBattlerAttacker = gBattlerAbility = battler;
gProtectStructs[battler].activateOpportunist--;
BattleScriptPushCursorAndCallback(BattleScript_OpportunistCopyStatChange);
effect = 1;
}
break;
}
}
break;
case ABILITYEFFECT_IMMUNITY: // 5
for (battler = 0; battler < gBattlersCount; battler++)
{
Expand Down Expand Up @@ -5948,6 +5969,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
effect = 4;
break;
}

if (effect != 0)
{
switch (effect)
Expand Down