Merge branch 'battle_engine' of https://github.com/rh-hideout/pokeemerald into multistrike

This commit is contained in:
BuffelSaft 2021-09-23 16:41:35 +12:00
commit 530998c4b7
15 changed files with 420 additions and 58 deletions

View File

@ -1764,7 +1764,7 @@
various BS_ATTACKER, VARIOUS_TOTEM_BOOST
.4byte \ptr
.endm
.macro tryactivategrimneigh, battler:req
various \battler, VARIOUS_TRY_ACTIVATE_GRIM_NEIGH
.endm
@ -1797,6 +1797,25 @@
.4byte \ptr
.endm
.macro eeriespellppreduce ptr:req
various BS_TARGET, VARIOUS_EERIE_SPELL_PP_REDUCE
.4byte \ptr
.endm
.macro jumpifteamhealthy battler:req, ptr:req
various \battler, VARIOUS_JUMP_IF_TEAM_HEALTHY
.4byte \ptr
.endm
.macro tryhealquarterhealth battler:req, ptr:req
various \battler, VARIOUS_TRY_HEAL_QUARTER_HP
.4byte \ptr
.endm
.macro removeterrain
various BS_ATTACKER, VARIOUS_REMOVE_TERRAIN
.endm
@ helpful macros
.macro setstatchanger stat:req, stages:req, down:req
setbyte sSTATCHANGER \stat | \stages << 3 | \down << 7

View File

@ -13481,7 +13481,7 @@ Move_BODY_PRESS::
end
Move_DECORATE::
end @to do:
goto Move_FLOWER_SHIELD
Move_DRUM_BEATING::
loadspritegfx ANIM_TAG_MUSIC_NOTES
@ -13957,7 +13957,7 @@ Move_EXPANDING_FORCE::
end @to do:
Move_STEEL_ROLLER::
end @to do:
goto Move_GYRO_BALL
Move_SCALE_SHOT::
end @to do:
@ -13984,7 +13984,7 @@ Move_SKITTER_SMACK::
end @to do:
Move_BURNING_JEALOUSY::
end @to do:
goto Move_OVERHEAT
Move_LASH_OUT::
end @to do:
@ -14011,7 +14011,7 @@ Move_SCORCHING_SANDS::
end @to do:
Move_JUNGLE_HEALING::
end @to do:
goto Move_AROMATHERAPY
Move_WICKED_BLOW::
end @to do:

View File

@ -369,6 +369,131 @@ gBattleScriptsForMoveEffects::
.4byte BattleScript_EffectSleepHit @ EFFECT_SLEEP_HIT
.4byte BattleScript_EffectAttackerDefenseDownHit @ EFFECT_ATTACKER_DEFENSE_DOWN_HIT
.4byte BattleScript_EffectHit @ EFFECT_BODY_PRESS
.4byte BattleScript_EffectEerieSpell @ EFFECT_EERIE_SPELL
.4byte BattleScript_EffectJungleHealing @ EFFECT_JUNGLE_HEALING
.4byte BattleScript_EffectCoaching @ EFFECT_COACHING
.4byte BattleScript_EffectHit @ EFFECT_LASH_OUT
.4byte BattleScript_EffectHit @ EFFECT_GRASSY_GLIDE
.4byte BattleScript_EffectRemoveTerrain @ EFFECT_REMOVE_TERRAIN
.4byte BattleScript_EffectHit @ EFFECT_DYNAMAX_DOUBLE_DMG
.4byte BattleScript_EffectDecorate @ EFFECT_DECORATE
.4byte BattleScript_EffectHit @ EFFECT_SNIPE_SHOT
BattleScript_EffectDecorate:
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring
ppreduce
jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_ATK, 12, BattleScript_DecorateBoost
jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_SPATK, 12, BattleScript_DecorateBoost
goto BattleScript_ButItFailed
BattleScript_DecorateBoost:
attackanimation
waitanimation
setbyte sSTAT_ANIM_PLAYED, FALSE
playstatchangeanimation BS_TARGET, BIT_ATK | BIT_SPATK, 0x0
setstatchanger STAT_ATK, 2, FALSE
statbuffchange STAT_BUFF_ALLOW_PTR | STAT_BUFF_NOT_PROTECT_AFFECTED, BattleScript_DecorateBoostSpAtk
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, 0x2, BattleScript_DecorateBoostSpAtk
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_DecorateBoostSpAtk:
setstatchanger STAT_SPATK, 2, FALSE
statbuffchange STAT_BUFF_ALLOW_PTR | STAT_BUFF_NOT_PROTECT_AFFECTED, BattleScript_MoveEnd
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, 0x2, BattleScript_MoveEnd
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_EffectRemoveTerrain:
attackcanceler
attackstring
ppreduce
jumpifword CMP_NO_COMMON_BITS, gFieldStatuses, STATUS_FIELD_TERRAIN_ANY, BattleScript_ButItFailed
critcalc
damagecalc
adjustdamage
attackanimation
waitanimation
effectivenesssound
hitanimation BS_TARGET
waitstate
healthbarupdate BS_TARGET
datahpupdate BS_TARGET
critmessage
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
removeterrain
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, 4, BattleScript_MoveEnd
printfromtable gTerrainEndingStringIds
waitmessage B_WAIT_TIME_LONG
playanimation BS_ATTACKER, B_ANIM_RESTORE_BG, NULL
tryfaintmon BS_TARGET, FALSE, NULL
goto BattleScript_MoveEnd
BattleScript_EffectCoaching:
attackcanceler
attackstring
ppreduce
jumpifnoally BS_ATTACKER, BattleScript_ButItFailed
copybyte gBattlerTarget, gBattlerAttacker
setallytonexttarget EffectCoaching_CheckAllyStats
goto BattleScript_ButItFailed
EffectCoaching_CheckAllyStats:
jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_ATK, MAX_STAT_STAGE, BattleScript_CoachingWorks
jumpifstat BS_TARGET, CMP_NOT_EQUAL, STAT_DEF, MAX_STAT_STAGE, BattleScript_CoachingWorks
goto BattleScript_ButItFailed @ ally at max atk, def
BattleScript_CoachingWorks:
attackanimation
waitanimation
setbyte sSTAT_ANIM_PLAYED, FALSE
playstatchangeanimation BS_TARGET, BIT_ATK | BIT_DEF, 0x0
setstatchanger STAT_ATK, 1, FALSE
statbuffchange STAT_BUFF_ALLOW_PTR | STAT_BUFF_NOT_PROTECT_AFFECTED, BattleScript_CoachingBoostDef
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, 0x2, BattleScript_CoachingBoostDef
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
BattleScript_CoachingBoostDef:
setstatchanger STAT_DEF, 1, FALSE
statbuffchange STAT_BUFF_ALLOW_PTR | STAT_BUFF_NOT_PROTECT_AFFECTED, BattleScript_MoveEnd
jumpifbyte CMP_EQUAL, cMULTISTRING_CHOOSER, 0x2, BattleScript_MoveEnd
printfromtable gStatUpStringIds
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_EffectJungleHealing:
attackcanceler
attackstring
ppreduce
jumpifteamhealthy BS_ATTACKER, BattleScript_ButItFailed
attackanimation
waitanimation
copybyte gBattlerTarget, gBattlerAttacker
setbyte gBattleCommunication, 0
JungleHealing_RestoreTargetHealth:
copybyte gBattlerAttacker, gBattlerTarget
tryhealquarterhealth BS_TARGET, BattleScript_JungleHealing_TryCureStatus
orword gHitMarker, HITMARKER_IGNORE_SUBSTITUTE
healthbarupdate BS_TARGET
datahpupdate BS_TARGET
printstring STRINGID_PKMNREGAINEDHEALTH
waitmessage B_WAIT_TIME_LONG
BattleScript_JungleHealing_TryCureStatus:
jumpifmove MOVE_LIFE_DEW, BattleScript_JungleHealingTryRestoreAlly @ life dew only heals
jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_JungleHealingCureStatus
goto BattleScript_JungleHealingTryRestoreAlly
BattleScript_JungleHealingCureStatus:
curestatus BS_TARGET
updatestatusicon BS_TARGET
printstring STRINGID_PKMNSTATUSNORMAL
waitmessage B_WAIT_TIME_LONG
BattleScript_JungleHealingTryRestoreAlly:
jumpifbyte CMP_NOT_EQUAL, gBattleCommunication, 0x0, BattleScript_MoveEnd
addbyte gBattleCommunication, 1
jumpifnoally BS_TARGET, BattleScript_MoveEnd
setallytonexttarget JungleHealing_RestoreTargetHealth
goto BattleScript_MoveEnd
BattleScript_EffectAttackerDefenseDownHit:
setmoveeffect MOVE_EFFECT_DEF_MINUS_1 | MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN
@ -2815,6 +2940,16 @@ BattleScript_EffectTrap::
setmoveeffect MOVE_EFFECT_WRAP
goto BattleScript_EffectHit
BattleScript_EffectTripleHit::
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
attackstring
ppreduce
setmultihitcounter 3
initmultihitstring
sethword sMULTIHIT_EFFECT, 0
goto BattleScript_MultiHitLoop
BattleScript_EffectDoubleHit::
attackcanceler
accuracycheck BattleScript_PrintMoveMissed, ACC_CURR_MOVE
@ -3467,6 +3602,33 @@ BattleScript_EffectDestinyBond::
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_EffectEerieSpell::
attackcanceler
attackstring
ppreduce
accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE
attackstring
ppreduce
critcalc
damagecalc
adjustdamage
attackanimation
waitanimation
effectivenesssound
hitanimation BS_TARGET
waitstate
healthbarupdate BS_TARGET
datahpupdate BS_TARGET
critmessage
waitmessage B_WAIT_TIME_LONG
resultmessage
waitmessage B_WAIT_TIME_LONG
tryfaintmon BS_TARGET, FALSE, NULL
eeriespellppreduce BattleScript_MoveEnd
printstring STRINGID_PKMNREDUCEDPP
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_EffectSpite::
attackcanceler
attackstring
@ -8097,4 +8259,3 @@ BattleScript_EjectPackActivate_End2::
BattleScript_EjectPackActivates::
jumpifcantswitch BS_SCRIPTING, BattleScript_EjectButtonEnd
goto BattleScript_EjectPackActivate_Ret

View File

@ -119,6 +119,7 @@ struct ProtectStruct
u32 spikyShielded:1;
u32 kingsShielded:1;
u32 banefulBunkered:1;
u32 obstructed:1;
u32 endured:1;
u32 noValidMoves:1;
u32 helpingHand:1;
@ -142,10 +143,12 @@ struct ProtectStruct
u32 usedGravityPreventedMove:1;
u32 powderSelfDmg:1;
u32 usedThroatChopPreventedMove:1;
u32 statRaised:1;
u32 micle:1;
u32 custap:1; // also quick claw
u32 touchedProtectLike:1;
u32 disableEjectPack:1;
u32 statFell:1;
u32 physicalDmg;
u32 specialDmg;
u8 physicalBattlerId;
@ -154,7 +157,6 @@ struct ProtectStruct
struct SpecialStatus
{
u8 statFell:1;
u8 statLowered:1;
u8 lightningRodRedirected:1;
u8 restoredBattlerSprite: 1;

View File

@ -47,7 +47,7 @@ struct TypePower
extern const struct TypePower gNaturalGiftTable[];
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide);
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move);
void HandleAction_UseMove(void);
void HandleAction_Switch(void);
void HandleAction_UseItem(void);

View File

@ -239,7 +239,7 @@
#define STATUS_FIELD_FAIRY_LOCK (1 << 11)
#define STATUS_FIELD_TERRAIN_PERMANENT (1 << 12) // Overworld thunderstorm generates electric terrain
#define STATUS_TERRAIN_ANY (STATUS_FIELD_GRASSY_TERRAIN | STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_PSYCHIC_TERRAIN)
#define STATUS_FIELD_TERRAIN_ANY (STATUS_FIELD_GRASSY_TERRAIN | STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_PSYCHIC_TERRAIN)
// Flags describing move's result
#define MOVE_RESULT_MISSED (1 << 0)

View File

@ -353,7 +353,17 @@
#define EFFECT_SLEEP_HIT 347
#define EFFECT_ATTACKER_DEFENSE_DOWN_HIT 348
#define EFFECT_BODY_PRESS 349
#define EFFECT_EERIE_SPELL 350
#define EFFECT_JUNGLE_HEALING 351
#define EFFECT_COACHING 352
#define EFFECT_LASH_OUT 353
#define EFFECT_GRASSY_GLIDE 354
#define EFFECT_REMOVE_TERRAIN 355
#define EFFECT_DYNAMAX_DOUBLE_DMG 356
#define EFFECT_DECORATE 357
#define EFFECT_SNIPE_SHOT 358
#define EFFECT_TRIPLE_HIT 359
#define NUM_BATTLE_MOVE_EFFECTS 350
#define NUM_BATTLE_MOVE_EFFECTS 360
#endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H

View File

@ -179,6 +179,10 @@
#define VARIOUS_MAKE_INVISIBLE 107
#define VARIOUS_ROOM_SERVICE 108
#define VARIOUS_JUMP_IF_TERRAIN_AFFECTED 109
#define VARIOUS_EERIE_SPELL_PP_REDUCE 110
#define VARIOUS_JUMP_IF_TEAM_HEALTHY 111
#define VARIOUS_TRY_HEAL_QUARTER_HP 112
#define VARIOUS_REMOVE_TERRAIN 113
// Cmd_manipulatedamage
#define DMG_CHANGE_SIGN 0

View File

@ -3227,7 +3227,7 @@ static void LoadDefaultBg(void)
if (IsContest())
LoadContestBgAfterMoveAnim();
#if B_TERRAIN_BG_CHANGE == TRUE
else if (gFieldStatuses & STATUS_TERRAIN_ANY)
else if (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)
DrawTerrainTypeBattleBackground();
#endif
else

View File

@ -1422,7 +1422,7 @@ bool8 LoadChosenBattleElement(u8 caseId)
void DrawTerrainTypeBattleBackground(void)
{
switch (gFieldStatuses & STATUS_TERRAIN_ANY)
switch (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)
{
case STATUS_FIELD_GRASSY_TERRAIN:
LoadMoveBg(BG_GRASSY_TERRAIN);

View File

@ -3072,6 +3072,7 @@ void FaintClearSetData(void)
gProtectStructs[gActiveBattler].spikyShielded = 0;
gProtectStructs[gActiveBattler].kingsShielded = 0;
gProtectStructs[gActiveBattler].banefulBunkered = 0;
gProtectStructs[gActiveBattler].obstructed = 0;
gProtectStructs[gActiveBattler].endured = 0;
gProtectStructs[gActiveBattler].noValidMoves = 0;
gProtectStructs[gActiveBattler].helpingHand = 0;
@ -3093,6 +3094,7 @@ void FaintClearSetData(void)
gProtectStructs[gActiveBattler].usesBouncedMove = 0;
gProtectStructs[gActiveBattler].usedGravityPreventedMove = 0;
gProtectStructs[gActiveBattler].usedThroatChopPreventedMove = 0;
gProtectStructs[gActiveBattler].statRaised = 0;
gDisableStructs[gActiveBattler].isFirstTurn = 2;
@ -4324,6 +4326,10 @@ s8 GetMovePriority(u32 battlerId, u16 move)
{
priority++;
}
else if (gBattleMoves[move].effect == EFFECT_GRASSY_GLIDE && gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battlerId))
{
priority++;
}
else if (GetBattlerAbility(battlerId) == ABILITY_TRIAGE)
{
switch (gBattleMoves[move].effect)

View File

@ -1290,6 +1290,11 @@ const u16 gTerrainStringIds[] =
STRINGID_TERRAINBECOMESMISTY, STRINGID_TERRAINBECOMESGRASSY, STRINGID_TERRAINBECOMESELECTRIC, STRINGID_TERRAINBECOMESPSYCHIC
};
const u16 gTerrainEndingStringIds[] =
{
STRINGID_MISTYTERRAINENDS, STRINGID_GRASSYTERRAINENDS, STRINGID_ELECTRICTERRAINENDS, STRINGID_PSYCHICTERRAINENDS
};
const u16 gTerrainPreventsStringIds[] =
{
[B_MSG_TERRAINPREVENTS_MISTY] = STRINGID_MISTYTERRAINPREVENTS,

View File

@ -1274,6 +1274,15 @@ static const u8 sBattlePalaceNatureToFlavorTextId[NUM_NATURES] =
bool32 IsBattlerProtected(u8 battlerId, u16 move)
{
// Decorate bypasses protect and detect, but not crafty shield
if (move == MOVE_DECORATE)
{
if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD)
return TRUE;
else if (gProtectStructs[battlerId].protected)
return FALSE;
}
if (!(gBattleMoves[move].flags & FLAG_PROTECT_AFFECTED))
return FALSE;
else if (gBattleMoves[move].effect == MOVE_EFFECT_FEINT)
@ -1285,6 +1294,8 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move)
return TRUE;
else if (gProtectStructs[battlerId].banefulBunkered)
return TRUE;
else if (gProtectStructs[battlerId].obstructed && !IS_MOVE_STATUS(move))
return TRUE;
else if (gProtectStructs[battlerId].spikyShielded)
return TRUE;
else if (gProtectStructs[battlerId].kingsShielded && gBattleMoves[move].power != 0)
@ -1293,10 +1304,10 @@ bool32 IsBattlerProtected(u8 battlerId, u16 move)
&& GetChosenMovePriority(gBattlerAttacker) > 0)
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_CRAFTY_SHIELD
&& gBattleMoves[move].power == 0)
&& IS_MOVE_STATUS(move))
return TRUE;
else if (gSideStatuses[GetBattlerSide(battlerId)] & SIDE_STATUS_MAT_BLOCK
&& gBattleMoves[move].power != 0)
&& !IS_MOVE_STATUS(move))
return TRUE;
else
return FALSE;
@ -1856,7 +1867,8 @@ s32 CalcCritChanceStage(u8 battlerAtk, u8 battlerDef, u32 move, bool32 recordAbi
}
else if (gStatuses3[battlerAtk] & STATUS3_LASER_FOCUS
|| gBattleMoves[move].effect == EFFECT_ALWAYS_CRIT
|| (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY))
|| (abilityAtk == ABILITY_MERCILESS && gBattleMons[battlerDef].status1 & STATUS1_PSN_ANY)
|| move == MOVE_SURGING_STRIKES)
{
critChance = -2;
}
@ -2693,8 +2705,11 @@ void SetMoveEffect(bool32 primary, u32 certain)
statusChanged = TRUE;
break;
case STATUS1_BURN:
if (gCurrentMove == MOVE_BURNING_JEALOUSY && gProtectStructs[gEffectBattler].statRaised == 0)
break;
if ((GetBattlerAbility(gEffectBattler) == ABILITY_WATER_VEIL || GetBattlerAbility(gEffectBattler) == ABILITY_WATER_BUBBLE)
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
&& (primary == TRUE || certain == MOVE_EFFECT_CERTAIN))
{
gLastUsedAbility = GetBattlerAbility(gEffectBattler);
RecordAbilityBattle(gEffectBattler, GetBattlerAbility(gEffectBattler));
@ -3153,7 +3168,8 @@ void SetMoveEffect(bool32 primary, u32 certain)
|| gSideStatuses[GetBattlerSide(gBattlerTarget)] & SIDE_STATUS_MAT_BLOCK
|| gProtectStructs[gBattlerTarget].spikyShielded
|| gProtectStructs[gBattlerTarget].kingsShielded
|| gProtectStructs[gBattlerTarget].banefulBunkered)
|| gProtectStructs[gBattlerTarget].banefulBunkered
|| gProtectStructs[gBattlerTarget].obstructed)
{
gProtectStructs[gBattlerTarget].protected = 0;
gSideStatuses[GetBattlerSide(gBattlerTarget)] &= ~(SIDE_STATUS_WIDE_GUARD);
@ -3163,6 +3179,7 @@ void SetMoveEffect(bool32 primary, u32 certain)
gProtectStructs[gBattlerTarget].spikyShielded = 0;
gProtectStructs[gBattlerTarget].kingsShielded = 0;
gProtectStructs[gBattlerTarget].banefulBunkered = 0;
gProtectStructs[gBattlerTarget].obstructed = 0;
if (gCurrentMove == MOVE_FEINT)
{
BattleScriptPush(gBattlescriptCurrInstr + 1);
@ -4729,6 +4746,17 @@ static void Cmd_moveend(void)
gBattlescriptCurrInstr = BattleScript_BanefulBunkerEffect;
effect = 1;
}
else if (gProtectStructs[gBattlerTarget].obstructed && gCurrentMove != MOVE_SUCKER_PUNCH)
{
gProtectStructs[gBattlerAttacker].touchedProtectLike = 0;
i = gBattlerAttacker;
gBattlerAttacker = gBattlerTarget;
gBattlerTarget = i; // gBattlerTarget and gBattlerAttacker are swapped in order to activate Defiant, if applicable
gBattleScripting.moveEffect = MOVE_EFFECT_DEF_MINUS_2;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_KingsShieldEffect;
effect = 1;
}
}
gBattleScripting.moveendState++;
break;
@ -5253,12 +5281,12 @@ static void Cmd_moveend(void)
{
u8 battler = battlers[i];
if (IsBattlerAlive(battler)
&& gSpecialStatuses[battler].statFell
&& gProtectStructs[battler].statFell
&& GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_EJECT_PACK
&& !(gCurrentMove == MOVE_PARTING_SHOT && CanBattlerSwitch(gBattlerAttacker)) // Does not activate if attacker used Parting Shot and can switch out
&& CountUsablePartyMons(battler) > 0) // Has mon to switch into
{
gSpecialStatuses[battler].statFell = FALSE;
gProtectStructs[battler].statFell = FALSE;
gActiveBattler = gBattleScripting.battler = battler;
gLastUsedItem = gBattleMons[battler].item;
BattleScriptPushCursor();
@ -7244,7 +7272,7 @@ static void HandleTerrainMove(u32 moveEffect)
}
else
{
gFieldStatuses &= ~STATUS_TERRAIN_ANY;
gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY;
gFieldStatuses |= statusFlag;
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_TERRAIN_EXTENDER)
*timer = 8;
@ -7619,7 +7647,7 @@ static void Cmd_various(void)
case VARIOUS_SET_MAGIC_COAT_TARGET:
gBattlerAttacker = gBattlerTarget;
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
if (IsAffectedByFollowMe(gBattlerAttacker, side))
if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove))
gBattlerTarget = gSideTimers[side].followmeTarget;
else
gBattlerTarget = gActiveBattler;
@ -7959,7 +7987,9 @@ static void Cmd_various(void)
}
return;
case VARIOUS_SUCKER_PUNCH_CHECK:
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
if (gProtectStructs[gBattlerTarget].obstructed)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
else if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget))
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
else if (gBattleMoves[gBattleMons[gBattlerTarget].moves[gBattleStruct->chosenMovePositions[gBattlerTarget]]].power == 0)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3);
@ -8692,6 +8722,104 @@ static void Cmd_various(void)
gBattlescriptCurrInstr += 11;
}
return;
case VARIOUS_EERIE_SPELL_PP_REDUCE:
if (gLastMoves[gActiveBattler] != 0 && gLastMoves[gActiveBattler] != 0xFFFF)
{
s32 i;
for (i = 0; i < MAX_MON_MOVES; i++)
{
if (gLastMoves[gActiveBattler] == gBattleMons[gActiveBattler].moves[i])
break;
}
if (i != MAX_MON_MOVES && gBattleMons[gActiveBattler].pp[i] != 0)
{
s32 ppToDeduct = 3;
if (gBattleMons[gActiveBattler].pp[i] < ppToDeduct)
ppToDeduct = gBattleMons[gActiveBattler].pp[i];
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gLastMoves[gActiveBattler])
ConvertIntToDecimalStringN(gBattleTextBuff2, ppToDeduct, STR_CONV_MODE_LEFT_ALIGN, 1);
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff2, 1, ppToDeduct)
gBattleMons[gActiveBattler].pp[i] -= ppToDeduct;
if (!(gDisableStructs[gActiveBattler].mimickedMoves & gBitTable[i])
&& !(gBattleMons[gActiveBattler].status2 & STATUS2_TRANSFORMED))
{
BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBattler].pp[i]);
MarkBattlerForControllerExec(gActiveBattler);
}
if (gBattleMons[gActiveBattler].pp[i] == 0)
CancelMultiTurnMoves(gActiveBattler);
gBattlescriptCurrInstr += 7; // continue
}
else
{
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); // cant reduce pp
}
}
else
{
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); // cant reduce pp
}
return;
case VARIOUS_JUMP_IF_TEAM_HEALTHY:
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && IsBattlerAlive(BATTLE_PARTNER(gActiveBattler)))
{
u8 partner = BATTLE_PARTNER(gActiveBattler);
if ((gBattleMons[gActiveBattler].hp == gBattleMons[gActiveBattler].maxHP && !(gBattleMons[gActiveBattler].status1 & STATUS1_ANY))
&& (gBattleMons[partner].hp == gBattleMons[partner].maxHP && !(gBattleMons[partner].status1 & STATUS1_ANY)))
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); // fail
else
gBattlescriptCurrInstr += 7;
}
else // single battle
{
if (gBattleMons[gActiveBattler].hp == gBattleMons[gActiveBattler].maxHP && !(gBattleMons[gActiveBattler].status1 & STATUS1_ANY))
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); // fail
else
gBattlescriptCurrInstr += 7;
}
return;
case VARIOUS_TRY_HEAL_QUARTER_HP:
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
if (gBattleMons[gActiveBattler].hp == gBattleMons[gActiveBattler].maxHP)
gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 3); // fail
else
gBattlescriptCurrInstr += 7; // can heal
return;
case VARIOUS_REMOVE_TERRAIN:
switch (gFieldStatuses & STATUS_FIELD_TERRAIN_ANY)
{
case STATUS_FIELD_MISTY_TERRAIN:
gFieldTimers.mistyTerrainTimer = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
break;
case STATUS_FIELD_GRASSY_TERRAIN:
gFieldTimers.grassyTerrainTimer = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
break;
case STATUS_FIELD_ELECTRIC_TERRAIN:
gFieldTimers.electricTerrainTimer = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
break;
case STATUS_FIELD_PSYCHIC_TERRAIN:
gFieldTimers.psychicTerrainTimer = 0;
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
break;
default:
gBattleCommunication[MULTISTRING_CHOOSER] = 4; // failsafe
break;
}
gFieldStatuses &= ~STATUS_FIELD_TERRAIN_ANY; // remove the terrain
break;
}
gBattlescriptCurrInstr += 3;
@ -8737,6 +8865,11 @@ static void Cmd_setprotectlike(void)
gProtectStructs[gBattlerAttacker].banefulBunkered = 1;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_PROTECTED_ITSELF;
}
else if (gCurrentMove == MOVE_OBSTRUCT)
{
gProtectStructs[gBattlerAttacker].obstructed = 1;
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
}
gDisableStructs[gBattlerAttacker].protectUses++;
fail = FALSE;
@ -9393,7 +9526,7 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr
{
// Check eject pack. disableEjectPack set for edge cases (e.g. attacking weak armor'd eject pack holder with u-turn)
if (gProtectStructs[gActiveBattler].disableEjectPack == 0)
gSpecialStatuses[gActiveBattler].statFell = TRUE;
gProtectStructs[gActiveBattler].statFell = 1;
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler); // B_MSG_ATTACKER_STAT_FELL or B_MSG_DEFENDER_STAT_FELL
}
}
@ -9430,9 +9563,14 @@ static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr
gBattleTextBuff2[index] = B_BUFF_EOS;
if (gBattleMons[gActiveBattler].statStages[statId] == MAX_STAT_STAGE)
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_STAT_WONT_INCREASE;
}
else
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler); // B_MSG_ATTACKER_STAT_ROSE or B_MSG_DEFENDER_STAT_ROSE
{
gBattleCommunication[MULTISTRING_CHOOSER] = (gBattlerTarget == gActiveBattler);
gProtectStructs[gActiveBattler].statRaised = 1;
}
}
gBattleMons[gActiveBattler].statStages[statId] += statValue;
@ -10296,7 +10434,7 @@ static void Cmd_counterdamagecalculator(void)
{
gBattleMoveDamage = gProtectStructs[gBattlerAttacker].physicalDmg * 2;
if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget))
if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget, gCurrentMove))
gBattlerTarget = gSideTimers[sideTarget].followmeTarget;
else
gBattlerTarget = gProtectStructs[gBattlerAttacker].physicalBattlerId;
@ -10321,7 +10459,7 @@ static void Cmd_mirrorcoatdamagecalculator(void) // a copy of atkA1 with the phy
{
gBattleMoveDamage = gProtectStructs[gBattlerAttacker].specialDmg * 2;
if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget))
if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget, gCurrentMove))
gBattlerTarget = gSideTimers[sideTarget].followmeTarget;
else
gBattlerTarget = gProtectStructs[gBattlerAttacker].specialBattlerId;
@ -12923,7 +13061,7 @@ static void Cmd_metalburstdamagecalculator(void)
{
gBattleMoveDamage = gProtectStructs[gBattlerAttacker].physicalDmg * 150 / 100;
if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget))
if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget, gCurrentMove))
gBattlerTarget = gSideTimers[sideTarget].followmeTarget;
else
gBattlerTarget = gProtectStructs[gBattlerAttacker].physicalBattlerId;
@ -12936,7 +13074,7 @@ static void Cmd_metalburstdamagecalculator(void)
{
gBattleMoveDamage = gProtectStructs[gBattlerAttacker].specialDmg * 150 / 100;
if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget))
if (IsAffectedByFollowMe(gBattlerAttacker, sideTarget, gCurrentMove))
gBattlerTarget = gSideTimers[sideTarget].followmeTarget;
else
gBattlerTarget = gProtectStructs[gBattlerAttacker].specialBattlerId;

View File

@ -248,12 +248,13 @@ static u8 CalcBeatUpPower(void)
return basePower;
}
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide)
bool32 IsAffectedByFollowMe(u32 battlerAtk, u32 defSide, u32 move)
{
u32 ability = GetBattlerAbility(battlerAtk);
if (gSideTimers[defSide].followmeTimer == 0
|| gBattleMons[gSideTimers[defSide].followmeTarget].hp == 0
|| gBattleMoves[move].effect == EFFECT_SNIPE_SHOT
|| ability == ABILITY_PROPELLER_TAIL || ability == ABILITY_STALWART)
return FALSE;
@ -339,7 +340,7 @@ void HandleAction_UseMove(void)
// choose target
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
if (IsAffectedByFollowMe(gBattlerAttacker, side)
if (IsAffectedByFollowMe(gBattlerAttacker, side, gCurrentMove)
&& gBattleMoves[gCurrentMove].target == MOVE_TARGET_SELECTED
&& GetBattlerSide(gBattlerAttacker) != GetBattlerSide(gSideTimers[side].followmeTarget))
{
@ -359,6 +360,7 @@ void HandleAction_UseMove(void)
&& ((GetBattlerAbility(gActiveBattler) == ABILITY_LIGHTNING_ROD && moveType == TYPE_ELECTRIC)
|| (GetBattlerAbility(gActiveBattler) == ABILITY_STORM_DRAIN && moveType == TYPE_WATER))
&& GetBattlerTurnOrderNum(gActiveBattler) < var
&& gBattleMoves[gCurrentMove].effect != EFFECT_SNIPE_SHOT
&& (GetBattlerAbility(gBattlerAttacker) != ABILITY_PROPELLER_TAIL
|| GetBattlerAbility(gBattlerAttacker) != ABILITY_STALWART))
{
@ -3959,11 +3961,11 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move
switch (gLastUsedAbility)
{
case ABILITYEFFECT_SWITCH_IN_TERRAIN:
if (VarGet(VAR_TERRAIN) & STATUS_TERRAIN_ANY)
if (VarGet(VAR_TERRAIN) & STATUS_FIELD_TERRAIN_ANY)
{
u16 terrainFlags = VarGet(VAR_TERRAIN) & STATUS_TERRAIN_ANY; // only works for status flag (1 << 15)
u16 terrainFlags = VarGet(VAR_TERRAIN) & STATUS_FIELD_TERRAIN_ANY; // only works for status flag (1 << 15)
gFieldStatuses = terrainFlags | STATUS_FIELD_TERRAIN_PERMANENT; // terrain is permanent
switch (VarGet(VAR_TERRAIN) & STATUS_TERRAIN_ANY)
switch (VarGet(VAR_TERRAIN) & STATUS_FIELD_TERRAIN_ANY)
{
case STATUS_FIELD_ELECTRIC_TERRAIN:
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
@ -6118,10 +6120,10 @@ u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
}
break;
case HOLD_EFFECT_EJECT_PACK:
if (gSpecialStatuses[battlerId].statFell
if (gProtectStructs[battlerId].statFell
&& !(gCurrentMove == MOVE_PARTING_SHOT && CanBattlerSwitch(gBattlerAttacker))) // Does not activate if attacker used Parting Shot and can switch out
{
gSpecialStatuses[battlerId].statFell = FALSE;
gProtectStructs[battlerId].statFell = FALSE;
gActiveBattler = gBattleScripting.battler = battlerId;
effect = ITEM_STATS_CHANGE;
if (moveTurn)
@ -6962,7 +6964,7 @@ u8 GetMoveTarget(u16 move, u8 setTarget)
{
case MOVE_TARGET_SELECTED:
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
if (IsAffectedByFollowMe(gBattlerAttacker, side))
if (IsAffectedByFollowMe(gBattlerAttacker, side, move))
{
targetBattler = gSideTimers[side].followmeTarget;
}
@ -6997,7 +6999,7 @@ u8 GetMoveTarget(u16 move, u8 setTarget)
break;
case MOVE_TARGET_RANDOM:
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
if (IsAffectedByFollowMe(gBattlerAttacker, side))
if (IsAffectedByFollowMe(gBattlerAttacker, side, move))
targetBattler = gSideTimers[side].followmeTarget;
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & MOVE_TARGET_RANDOM)
targetBattler = SetRandomTarget(gBattlerAttacker);
@ -7589,11 +7591,26 @@ static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef)
if (gBattleMoves[gLastUsedMove].effect == EFFECT_FUSION_COMBO && move != gLastUsedMove)
basePower *= 2;
break;
#if B_BEAT_UP_DMG >= GEN_5
case EFFECT_BEAT_UP:
basePower = CalcBeatUpPower();
case EFFECT_LASH_OUT:
if (gProtectStructs[battlerAtk].statFell)
basePower *= 2;
break;
#endif
case EFFECT_EXPLOSION:
if (move == MOVE_MISTY_EXPLOSION && gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN && IsBattlerGrounded(battlerAtk))
MulModifier(&basePower, UQ_4_12(1.5));
break;
case EFFECT_DYNAMAX_DOUBLE_DMG:
#ifdef B_DYNAMAX
if (IsDynamaxed(battlerDef))
basePower *= 2;
#endif
break;
case EFFECT_BEAT_UP:
#if B_BEAT_UP_DMG >= GEN_5
basePower = CalcBeatUpPower();
#endif
break;
}
if (basePower == 0)

View File

@ -10743,7 +10743,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_SNIPE_SHOT] =
{
.effect = EFFECT_PLACEHOLDER, //TODO
.effect = EFFECT_SNIPE_SHOT,
.power = 80,
.type = TYPE_WATER,
.accuracy = 100,
@ -10751,7 +10751,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
.secondaryEffectChance = 0,
.target = MOVE_TARGET_SELECTED,
.priority = 0,
.flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED,
.flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_HIGH_CRIT,
.split = SPLIT_SPECIAL,
},
@ -10940,7 +10940,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_DECORATE] =
{
.effect = EFFECT_PLACEHOLDER, // TODO .. EFFECT_DECORATE
.effect = EFFECT_DECORATE,
.power = 0,
.type = TYPE_FAIRY,
.accuracy = 0,
@ -10996,7 +10996,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_BEHEMOTH_BLADE] =
{
.effect = EFFECT_HIT, //TODO: 2x damage if dynamaxed? meh...
.effect = EFFECT_DYNAMAX_DOUBLE_DMG,
.power = 100,
.type = TYPE_STEEL,
.accuracy = 100,
@ -11010,7 +11010,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_BEHEMOTH_BASH] =
{
.effect = EFFECT_HIT, //TODO: 2x damage if dynamaxed? meh...
.effect = EFFECT_DYNAMAX_DOUBLE_DMG,
.power = 100,
.type = TYPE_STEEL,
.accuracy = 100,
@ -11136,7 +11136,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_LIFE_DEW] =
{
.effect = EFFECT_RESTORE_HP,
.effect = EFFECT_JUNGLE_HEALING,
.power = 0,
.type = TYPE_WATER,
.accuracy = 0,
@ -11150,7 +11150,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_OBSTRUCT] =
{
.effect = EFFECT_PLACEHOLDER, //TODO. EFFECT_PROTECT?
.effect = EFFECT_PROTECT,
.power = 0,
.type = TYPE_DARK,
.accuracy = 100,
@ -11158,7 +11158,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
.secondaryEffectChance = 0,
.target = MOVE_TARGET_USER,
.priority = 4,
.flags = 0,
.flags = FLAG_PROTECTION_MOVE,
.split = SPLIT_STATUS,
},
@ -11234,7 +11234,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_STEEL_ROLLER] =
{
.effect = EFFECT_PLACEHOLDER, //TODO
.effect = EFFECT_REMOVE_TERRAIN,
.power = 130,
.type = TYPE_STEEL,
.accuracy = 100,
@ -11290,7 +11290,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_MISTY_EXPLOSION] =
{
.effect = EFFECT_PLACEHOLDER, //TODO
.effect = EFFECT_EXPLOSION,
.power = 100,
.type = TYPE_FAIRY,
.accuracy = 100,
@ -11304,7 +11304,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_GRASSY_GLIDE] =
{
.effect = EFFECT_PLACEHOLDER, //TODO
.effect = EFFECT_GRASSY_GLIDE,
.power = 70,
.type = TYPE_GRASS,
.accuracy = 100,
@ -11360,12 +11360,12 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_BURNING_JEALOUSY] =
{
.effect = EFFECT_PLACEHOLDER, //TODO
.effect = EFFECT_BURN_HIT,
.power = 70,
.type = TYPE_FIRE,
.accuracy = 100,
.pp = 5,
.secondaryEffectChance = 0,
.secondaryEffectChance = 100,
.target = MOVE_TARGET_BOTH,
.priority = 0,
.flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_SHEER_FORCE_BOOST,
@ -11374,7 +11374,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_LASH_OUT] =
{
.effect = EFFECT_PLACEHOLDER, //TODO
.effect = EFFECT_LASH_OUT,
.power = 75,
.type = TYPE_DARK,
.accuracy = 100,
@ -11416,7 +11416,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_COACHING] =
{
.effect = EFFECT_PLACEHOLDER, //TODO
.effect = EFFECT_COACHING,
.power = 0,
.type = TYPE_FIGHTING,
.accuracy = 0,
@ -11486,7 +11486,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_JUNGLE_HEALING] =
{
.effect = EFFECT_PLACEHOLDER, //TODO
.effect = EFFECT_JUNGLE_HEALING,
.power = 0,
.type = TYPE_GRASS,
.accuracy = 0,
@ -11625,7 +11625,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] =
[MOVE_EERIE_SPELL] =
{
.effect = EFFECT_HIT, // To do. It's a copy of Spite that inflicts damage and reduced the target's last move's PP by 3 instead of 4.
.effect = EFFECT_EERIE_SPELL,
.power = 80,
.type = TYPE_PSYCHIC,
.accuracy = 100,