diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 387ec7b00..b838cb6d2 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1731,6 +1731,14 @@ .4byte \ptr .endm + .macro photongeysercheck + various BS_ATTACKER, VARIOUS_PHOTON_GEYSER_CHECK + .endm + + .macro shellsidearmcheck + various BS_ATTACKER, VARIOUS_SHELL_SIDE_ARM_CHECK + .endm + .macro trysetfairylock ptr:req various BS_ATTACKER, VARIOUS_TRY_FAIRY_LOCK .4byte \ptr diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 2b94ffff5..447c329e0 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -390,6 +390,16 @@ gBattleScriptsForMoveEffects:: .4byte BattleScript_EffectFreezyFrost @ EFFECT_FREEZY_FROST .4byte BattleScript_EffectSparklySwirl @ EFFECT_SPARKLY_SWIRL .4byte BattleScript_EffectPlasmaFists @ EFFECT_PLASMA_FISTS + .4byte BattleScript_EffectPhotonGeyser @ EFFECT_PHOTON_GEYSER + .4byte BattleScript_EffectShellSideArm @ EFFECT_SHELL_SIDE_ARM + +BattleScript_EffectShellSideArm: + shellsidearmcheck + setmoveeffect MOVE_EFFECT_POISON + goto BattleScript_EffectHit + +BattleScript_EffectPhotonGeyser: + photongeysercheck BattleScript_EffectPlasmaFists: attackcanceler diff --git a/include/battle.h b/include/battle.h index c1ac57686..00b2c2f25 100644 --- a/include/battle.h +++ b/include/battle.h @@ -919,4 +919,6 @@ extern bool8 gHasFetchedBall; extern u8 gLastUsedBall; extern u16 gLastThrownBall; +extern bool8 gSwapDamageCategory; // Photon Geyser, Shell Side Arm, Light That Burns the Sky + #endif // GUARD_BATTLE_H diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index f405c32c6..31bd7c884 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -374,7 +374,9 @@ #define EFFECT_FREEZY_FROST 368 #define EFFECT_SPARKLY_SWIRL 369 #define EFFECT_PLASMA_FISTS 370 +#define EFFECT_PHOTON_GEYSER 371 +#define EFFECT_SHELL_SIDE_ARM 372 -#define NUM_BATTLE_MOVE_EFFECTS 371 +#define NUM_BATTLE_MOVE_EFFECTS 373 #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 637c695f5..110aaf6f0 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -193,6 +193,8 @@ #define VARIOUS_JUMP_IF_CANT_REVERT_TO_PRIMAL 120 #define VARIOUS_HANDLE_PRIMAL_REVERSION 121 #define VARIOUS_APPLY_PLASMA_FISTS 122 +#define VARIOUS_PHOTON_GEYSER_CHECK 123 +#define VARIOUS_SHELL_SIDE_ARM_CHECK 124 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_main.c b/src/battle_main.c index 271e97731..e2e504e3c 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -232,6 +232,7 @@ EWRAM_DATA struct TotemBoost gTotemBoosts[MAX_BATTLERS_COUNT] = {0}; EWRAM_DATA bool8 gHasFetchedBall = FALSE; EWRAM_DATA u8 gLastUsedBall = 0; EWRAM_DATA u16 gLastThrownBall = 0; +EWRAM_DATA bool8 gSwapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky // IWRAM common vars void (*gPreBattleCallback1)(void); @@ -2936,6 +2937,8 @@ static void BattleStartClearSetData(void) for (i = 0; i < PARTY_SIZE; i++) gBattleStruct->itemStolen[i].originalItem = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); + + gSwapDamageCategory = FALSE; // Photon Geyser, Shell Side Arm, Light That Burns the Sky } void SwitchInClearSetData(void) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 9a3f0bf01..2e25eb8ba 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -54,6 +54,7 @@ #include "constants/rgb.h" #include "data.h" #include "constants/party_menu.h" +#include "battle_util.h" extern struct MusicPlayerInfo gMPlayInfo_BGM; extern struct Evolution gEvolutionTable[][EVOS_PER_MON]; @@ -1498,7 +1499,7 @@ static void Cmd_attackcanceler(void) && ((!IsTwoTurnsMove(gCurrentMove) || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS))) && gBattleMoves[gCurrentMove].effect != EFFECT_SUCKER_PUNCH) { - if (gBattleMoves[gCurrentMove].flags & FLAG_MAKES_CONTACT) + if (IsMoveMakingContact(gCurrentMove, gBattlerAttacker)) gProtectStructs[gBattlerAttacker].touchedProtectLike = 1; CancelMultiTurnMoves(gBattlerAttacker); gMoveResultFlags |= MOVE_RESULT_MISSED; @@ -8977,6 +8978,57 @@ static void Cmd_various(void) for (i = 0; i < gBattlersCount; i++) gStatuses4[i] |= STATUS4_PLASMA_FISTS; break; + case VARIOUS_PHOTON_GEYSER_CHECK: + { + u32 attStat = gBattleMons[gActiveBattler].attack; + u8 atkStage = gBattleMons[gActiveBattler].statStages[STAT_ATK]; + u32 spaStat = gBattleMons[gActiveBattler].spAttack; + + attStat *= gStatStageRatios[atkStage][0]; + attStat /= gStatStageRatios[atkStage][1]; + + atkStage = gBattleMons[gActiveBattler].statStages[STAT_SPATK]; + spaStat *= gStatStageRatios[atkStage][0]; + spaStat /= gStatStageRatios[atkStage][1]; + + if (attStat > spaStat) + gSwapDamageCategory = TRUE; + break; + } + case VARIOUS_SHELL_SIDE_ARM_CHECK: // 0% chance GameFreak actually checks this way according to DaWobblefet, but this is the only functional explanation at the moment + { + u32 attStat = gBattleMons[gBattlerAttacker].attack; + u8 atkStage = gBattleMons[gBattlerAttacker].statStages[STAT_ATK]; + u32 attStatDef = gBattleMons[gBattlerTarget].attack; + u32 physical; + + u32 spaStat = gBattleMons[gBattlerAttacker].spAttack; + u32 spaStatDef = gBattleMons[gBattlerTarget].spAttack; + u32 special; + + attStat *= gStatStageRatios[atkStage][0]; + attStat /= gStatStageRatios[atkStage][1]; + + atkStage = gBattleMons[gBattlerTarget].statStages[STAT_ATK]; + attStatDef *= gStatStageRatios[atkStage][0]; + attStatDef /= gStatStageRatios[atkStage][1]; + + physical = ((((2 * gBattleMons[gBattlerAttacker].level / 5 + 2) * gBattleMoves[gCurrentMove].power * attStat) / attStatDef) / 50); + + atkStage = gBattleMons[gBattlerAttacker].statStages[STAT_SPATK]; + spaStat *= gStatStageRatios[atkStage][0]; + spaStat /= gStatStageRatios[atkStage][1]; + + atkStage = gBattleMons[gBattlerTarget].statStages[STAT_SPATK]; + spaStatDef *= gStatStageRatios[atkStage][0]; + spaStatDef /= gStatStageRatios[atkStage][1]; + + special = ((((2 * gBattleMons[gBattlerAttacker].level / 5 + 2) * gBattleMoves[gCurrentMove].power * spaStat) / spaStatDef) / 50); + + if (((physical > special) || (physical == special && (Random() % 2) == 0))) + gSwapDamageCategory = TRUE; + break; + } } gBattlescriptCurrInstr += 3; @@ -13272,4 +13324,3 @@ static bool32 CriticalCapture(u32 odds) return FALSE; #endif } - diff --git a/src/battle_util.c b/src/battle_util.c index 275139f4f..f79ce62b2 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -4813,7 +4813,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && IsBattlerAlive(gBattlerAttacker) && TARGET_TURN_DAMAGED - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)) + && (IsMoveMakingContact(move, gBattlerAttacker))) { switch (gBattleMons[gBattlerAttacker].ability) { @@ -4996,7 +4996,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && gBattleMons[gBattlerAttacker].hp != 0 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && (IsMoveMakingContact(move, gBattlerAttacker)) && TARGET_TURN_DAMAGED && CanBeBurned(gBattlerAttacker) && (Random() % 3) == 0) @@ -5012,7 +5012,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && gBattleMons[gBattlerAttacker].hp != 0 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && (IsMoveMakingContact(move, gBattlerAttacker)) && TARGET_TURN_DAMAGED && gBattleMons[gBattlerTarget].hp != 0 && (Random() % 3) == 0 @@ -5088,7 +5088,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u16 ability, u8 special, u16 move && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && TARGET_TURN_DAMAGED && IsBattlerAlive(battler) - && (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + && (IsMoveMakingContact(move, gBattlerAttacker)) && !(gStatuses3[gBattlerAttacker] & STATUS3_PERISH_SONG)) { if (!(gStatuses3[battler] & STATUS3_PERISH_SONG)) @@ -7270,13 +7270,24 @@ u32 GetBattlerHoldEffectParam(u8 battlerId) bool32 IsMoveMakingContact(u16 move, u8 battlerAtk) { if (!(gBattleMoves[move].flags & FLAG_MAKES_CONTACT)) - return FALSE; + { + if (gBattleMoves[move].effect == EFFECT_SHELL_SIDE_ARM && gSwapDamageCategory == TRUE) + return TRUE; + else + return FALSE; + } else if (GetBattlerAbility(battlerAtk) == ABILITY_LONG_REACH) + { return FALSE; + } else if (GetBattlerHoldEffect(battlerAtk, TRUE) == HOLD_EFFECT_PROTECTIVE_PADS) + { return FALSE; + } else + { return TRUE; + } } bool32 IsBattlerGrounded(u8 battlerId) @@ -7784,7 +7795,7 @@ static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDe MulModifier(&modifier, UQ_4_12(1.3)); break; case ABILITY_TOUGH_CLAWS: - if (gBattleMoves[move].flags & FLAG_MAKES_CONTACT) + if (IsMoveMakingContact(move, battlerAtk)) MulModifier(&modifier, UQ_4_12(1.3)); break; case ABILITY_STRONG_JAW: @@ -9066,7 +9077,9 @@ bool8 ShouldGetStatBadgeBoost(u16 badgeFlag, u8 battlerId) u8 GetBattleMoveSplit(u32 moveId) { - if (IS_MOVE_STATUS(moveId) || B_PHYSICAL_SPECIAL_SPLIT >= GEN_4) + if (gSwapDamageCategory == TRUE) // Photon Geyser, Shell Side Arm, Light That Burns the Sky + return SPLIT_PHYSICAL; + else if (IS_MOVE_STATUS(moveId) || B_PHYSICAL_SPECIAL_SPLIT >= GEN_4) return gBattleMoves[moveId].split; else if (gBattleMoves[moveId].type < TYPE_MYSTERY) return SPLIT_PHYSICAL; diff --git a/src/data/battle_moves.h b/src/data/battle_moves.h index 1079cd608..38c531b23 100644 --- a/src/data/battle_moves.h +++ b/src/data/battle_moves.h @@ -10453,7 +10453,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_PHOTON_GEYSER] = { - .effect = EFFECT_PLACEHOLDER, // Needs a custom move effect + .effect = EFFECT_PHOTON_GEYSER, .power = 100, .type = TYPE_PSYCHIC, .accuracy = 100, @@ -10461,7 +10461,7 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = .secondaryEffectChance = 0, .target = MOVE_TARGET_FOES_AND_ALLY, .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_TARGET_ABILITY_IGNORED, .split = SPLIT_SPECIAL, }, @@ -11289,12 +11289,12 @@ const struct BattleMove gBattleMoves[MOVES_COUNT] = [MOVE_SHELL_SIDE_ARM] = { - .effect = EFFECT_PLACEHOLDER, //TODO + .effect = EFFECT_SHELL_SIDE_ARM, .power = 90, .type = TYPE_POISON, .accuracy = 100, .pp = 10, - .secondaryEffectChance = 0, + .secondaryEffectChance = 20, .target = MOVE_TARGET_SELECTED, .priority = 0, .flags = FLAG_PROTECT_AFFECTED | FLAG_MIRROR_MOVE_AFFECTED | FLAG_KINGS_ROCK_AFFECTED | FLAG_SHEER_FORCE_BOOST,