diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 20071fc36b..315c8c327d 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1715,7 +1715,13 @@ .endm .macro trypoisontype attacker:req, target:req, ptr:req - various \attacker, VARIOUS_HANDLE_TYPE_IMMUNITY + various \attacker, VARIOUS_POISON_TYPE_IMMUNITY + .byte \target + .4byte \ptr + .endm + + .macro tryparalyzetype attacker:req, target:req, ptr:req + various \attacker, VARIOUS_PARALYZE_TYPE_IMMUNITY .byte \target .4byte \ptr .endm diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 06642142e8..bd55ca97c7 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -2996,7 +2996,7 @@ BattleScript_EffectParalyze: typecalc jumpifmovehadnoeffect BattleScript_ButItFailed jumpifstatus BS_TARGET, STATUS1_PARALYSIS, BattleScript_AlreadyParalyzed - jumpiftype BS_TARGET, TYPE_ELECTRIC, BattleScript_NotAffected + tryparalyzetype BS_ATTACKER, BS_TARGET, BattleScript_NotAffected jumpifstatus BS_TARGET, STATUS1_ANY, BattleScript_ButItFailed accuracycheck BattleScript_ButItFailed, ACC_CURR_MOVE jumpifsafeguard BattleScript_SafeguardProtected diff --git a/include/battle_script_commands.h b/include/battle_script_commands.h index 2376c5a865..d06bba8e2e 100644 --- a/include/battle_script_commands.h +++ b/include/battle_script_commands.h @@ -18,6 +18,7 @@ bool8 UproarWakeUpCheck(u8 battlerId); bool32 DoesSubstituteBlockMove(u8 battlerAtk, u8 battlerDef, u32 move); bool32 DoesDisguiseBlockMove(u8 battlerAtk, u8 battlerDef, u32 move); bool32 CanPoisonType(u8 battlerAttacker, u8 battlerTarget); +bool32 CanParalyzeType(u8 battlerAttacker, u8 battlerTarget); bool32 CanUseLastResort(u8 battlerId); u32 IsFlowerVeilProtected(u32 battler); u32 IsLeafGuardProtected(u32 battler); diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index 8472c3531f..0b48fa1d27 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -64,6 +64,9 @@ #define B_TERRAIN_TYPE_BOOST GEN_6 // In Gen8+, speed is boosted by 30% instead of 50%. #define B_BINDING_DAMAGE GEN_6 // In Gen6+, binding damage is 1/8 of max HP instead of 1/16. (With Binding Band, 1/6 and 1/8 respectively.) #define B_CONFUSION_SELF_DMG_CHANCE GEN_6 // In Gen7+, confusion has a 33.3% of self-damage, instead of 50%. +#define B_MULTI_HIT_CHANCE GEN_6 // In Gen5+, multi-hit moves have different %. See Cmd_setmultihitcounter for values. +#define B_RECOIL_IF_MISS_DMG GEN_6 // In Gen5+, Jump Kick and Hi Jump Kick will always do half of the user's max HP when missing. +#define B_PSYWAVE_DMG GEN_6 // Psywave's damage formula. See Cmd_psywavedamageeffect. // Move settings #define B_FELL_STINGER_STAT_RAISE GEN_6 // In Gen7+, it raises Atk by 3 stages instead of 2 if it causes the target to faint. @@ -72,7 +75,10 @@ #define B_PAYBACK_SWITCH_BOOST GEN_6 // In Gen5+, if the opponent switches out, Payback's damage will no longer be doubled. #define B_KINGS_SHIELD_LOWER_ATK GEN_6 // In Gen7+, it lowers Atk by 1 stage instead of 2 of oponents that hit it. #define B_BINDING_TURNS GEN_6 // In Gen5+, binding moves last for 4-5 turns instead of 2-5 turns. (With Grip Claw, 7 and 5 turns respectively.) +#define B_UPROAR_TURNS GEN_6 // In Gen5+, Uproar lasts for 3 turns instead of 2-5 turns. +#define B_DISABLE_TURNS GEN_6 // Disable's turns. See Cmd_disablelastusedattack. #define B_INCINERATE_GEMS GEN_6 // In Gen6+, Incinerate can destroy Gems. +#define B_MINIMIZE_DMG_ACC GEN_6 // In Gen6+, moves that causes double damage to minimized Pokémon will also skip accuracy checks. // Ability settings #define B_ABILITY_POP_UP GEN_6 // In Gen5+, the Pokémon abilities are displayed in a pop-up, when they activate in battle. @@ -87,6 +93,8 @@ // Other #define B_FAST_INTRO TRUE // If set to TRUE, battle intro texts print at the same time as animation of a Pokémon, as opposing to waiting for the animation to end. #define B_SLEEP_TURNS GEN_6 // In Gen5+, sleep lasts for 1-3 turns instead of 2-5 turns. +#define B_PARALYZE_ELECTRIC GEN_6 // In Gen6+, Electric type Pokémon can't be paralyzed. +#define B_POWDER_GRASS GEN_6 // In Gen6+, Grass type Pokémon are immune to powder and spore moves. // Animation Settings #define NEW_SWORD_PARTICLE // update swords dance particle diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 71b3b1fca2..4e6e56650f 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -156,10 +156,11 @@ #define VARIOUS_JUMP_IF_SHIELDS_DOWN_PROTECTED 93 #define VARIOUS_TRY_FAIRY_LOCK 94 #define VARIOUS_JUMP_IF_NO_ALLY 95 -#define VARIOUS_HANDLE_TYPE_IMMUNITY 96 +#define VARIOUS_POISON_TYPE_IMMUNITY 96 #define VARIOUS_JUMP_IF_NO_HOLD_EFFECT 97 #define VARIOUS_INFATUATE_WITH_BATTLER 98 #define VARIOUS_SET_LAST_USED_ITEM 99 +#define VARIOUS_PARALYZE_TYPE_IMMUNITY 100 // Cmd_manipulatedamage #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_pike.c b/src/battle_pike.c index 6b31419a5c..0476b9adb7 100644 --- a/src/battle_pike.c +++ b/src/battle_pike.c @@ -17,6 +17,7 @@ #include "constants/battle_frontier.h" #include "constants/frontier_util.h" #include "constants/abilities.h" +#include "constants/battle_config.h" #include "constants/easy_chat.h" #include "constants/layouts.h" #include "constants/rgb.h" @@ -856,8 +857,9 @@ static bool8 DoesTypePreventStatus(u16 species, u32 status) ret = TRUE; break; case STATUS1_PARALYSIS: - if (gBaseStats[species].type1 == TYPE_GROUND || gBaseStats[species].type1 == TYPE_ELECTRIC - || gBaseStats[species].type2 == TYPE_GROUND || gBaseStats[species].type2 == TYPE_ELECTRIC) + if (gBaseStats[species].type1 == TYPE_GROUND || gBaseStats[species].type2 == TYPE_GROUND + || (B_PARALYZE_ELECTRIC >= GEN_6 && + (gBaseStats[species].type1 == TYPE_ELECTRIC || gBaseStats[species].type2 == TYPE_ELECTRIC))) ret = TRUE; break; case STATUS1_BURN: diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 81fde7c45a..3f457b7e5f 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -1275,7 +1275,8 @@ static bool32 AccuracyCalcHelper(u16 move) (((gBattleWeather & WEATHER_RAIN_ANY) && (gBattleMoves[move].effect == EFFECT_THUNDER || gBattleMoves[move].effect == EFFECT_HURRICANE)) || (((gBattleWeather & WEATHER_HAIL_ANY) && move == MOVE_BLIZZARD)))) || (gBattleMoves[move].effect == EFFECT_VITAL_THROW) - || (gBattleMoves[move].accuracy == 0)) + || (gBattleMoves[move].accuracy == 0) + || ((B_MINIMIZE_DMG_ACC >= GEN_6) && (gStatuses3[gBattlerTarget] & STATUS3_MINIMIZED) && (gBattleMoves[move].flags & FLAG_DMG_MINIMIZE))) { JumpIfMoveFailed(7, move); return TRUE; @@ -2369,7 +2370,7 @@ void SetMoveEffect(bool32 primary, u32 certain) else break; } - if ((IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_ELECTRIC)) + if (!CanParalyzeType(gBattleScripting.battler, gEffectBattler) && (gHitMarker & HITMARKER_IGNORE_SAFEGUARD) && (primary == TRUE || certain == MOVE_EFFECT_CERTAIN)) { @@ -2379,7 +2380,7 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattleCommunication[MULTISTRING_CHOOSER] = 2; RESET_RETURN } - if (IS_BATTLER_OF_TYPE(gEffectBattler, TYPE_ELECTRIC)) + if (!CanParalyzeType(gBattleScripting.battler, gEffectBattler)) break; if (GetBattlerAbility(gEffectBattler) == ABILITY_LIMBER || GetBattlerAbility(gEffectBattler) == ABILITY_COMATOSE @@ -2538,7 +2539,7 @@ void SetMoveEffect(bool32 primary, u32 certain) gBattleMons[gEffectBattler].status2 |= STATUS2_MULTIPLETURNS; gLockedMoves[gEffectBattler] = gCurrentMove; - gBattleMons[gEffectBattler].status2 |= ((Random() & 3) + 2) << 4; + gBattleMons[gEffectBattler].status2 |= (B_UPROAR_TURNS >= GEN_5 ? 3 : ((Random() & 3) + 2) ) << 4; BattleScriptPush(gBattlescriptCurrInstr + 1); gBattlescriptCurrInstr = sMoveEffectBS_Ptrs[gBattleScripting.moveEffect]; @@ -6686,6 +6687,11 @@ bool32 CanPoisonType(u8 battlerAttacker, u8 battlerTarget) || IS_BATTLER_OF_TYPE(battlerTarget, TYPE_STEEL))); } +bool32 CanParalyzeType(u8 battlerAttacker, u8 battlerTarget) +{ + return !(B_PARALYZE_ELECTRIC >= GEN_6 && IS_BATTLER_OF_TYPE(battlerTarget, TYPE_ELECTRIC)); +} + bool32 CanUseLastResort(u8 battlerId) { u32 i; @@ -6913,12 +6919,18 @@ static void Cmd_various(void) gBattleStruct->friskedBattler = 0; gBattleStruct->friskedAbility = FALSE; break; - case VARIOUS_HANDLE_TYPE_IMMUNITY: + case VARIOUS_POISON_TYPE_IMMUNITY: if (!CanPoisonType(gActiveBattler, GetBattlerForBattleScript(gBattlescriptCurrInstr[3]))) gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 4); else gBattlescriptCurrInstr += 8; return; + case VARIOUS_PARALYZE_TYPE_IMMUNITY: + if (!CanParalyzeType(gActiveBattler, GetBattlerForBattleScript(gBattlescriptCurrInstr[3]))) + gBattlescriptCurrInstr = T1_READ_PTR(gBattlescriptCurrInstr + 4); + else + gBattlescriptCurrInstr += 8; + return; case VARIOUS_TRACE_ABILITY: gBattleMons[gActiveBattler].ability = gBattleStruct->tracedAbility[gActiveBattler]; RecordAbilityBattle(gActiveBattler, gBattleMons[gActiveBattler].ability); @@ -8273,7 +8285,7 @@ static void Cmd_manipulatedamage(void) gBattleMoveDamage /= 2; if (gBattleMoveDamage == 0) gBattleMoveDamage = 1; - if ((gBattleMons[gBattlerTarget].maxHP / 2) < gBattleMoveDamage) + if (B_RECOIL_IF_MISS_DMG >= GEN_5 || ((gBattleMons[gBattlerTarget].maxHP / 2) < gBattleMoveDamage)) gBattleMoveDamage = gBattleMons[gBattlerTarget].maxHP / 2; break; case DMG_DOUBLED: @@ -8780,14 +8792,36 @@ static void Cmd_setmultihitcounter(void) } else { - gMultiHitCounter = Random() & 3; - if (gMultiHitCounter > 1) - gMultiHitCounter = (Random() & 3) + 2; - else - gMultiHitCounter += 2; - if (GetBattlerAbility(gBattlerAttacker) == ABILITY_SKILL_LINK) + { gMultiHitCounter = 5; + } + else if (B_MULTI_HIT_CHANCE >= GEN_5) + { + // 2 and 3 hits: 33.3% + // 4 and 5 hits: 16.7% + gMultiHitCounter = Random() % 4; + if (gMultiHitCounter > 2) + { + gMultiHitCounter = (Random() % 3); + if (gMultiHitCounter < 2) + gMultiHitCounter = 2; + else + gMultiHitCounter = 3; + } + else + gMultiHitCounter += 3; + } + else + { + // 2 and 3 hits: 37.5% + // 4 and 5 hits: 12.5% + gMultiHitCounter = Random() % 4; + if (gMultiHitCounter > 1) + gMultiHitCounter = (Random() % 4) + 2; + else + gMultiHitCounter += 2; + } } gBattlescriptCurrInstr += 2; @@ -9486,10 +9520,10 @@ static void Cmd_dmgtolevel(void) static void Cmd_psywavedamageeffect(void) { s32 randDamage; - - while ((randDamage = (Random() & 0xF)) > 10); - - randDamage *= 10; + if (B_PSYWAVE_DMG >= GEN_6) + randDamage = (Random() % 101); + else + randDamage = (Random() % 11) * 10; gBattleMoveDamage = gBattleMons[gBattlerAttacker].level * (randDamage + 50) / 100; gBattlescriptCurrInstr++; } @@ -9557,7 +9591,12 @@ static void Cmd_disablelastusedattack(void) PREPARE_MOVE_BUFFER(gBattleTextBuff1, gBattleMons[gBattlerTarget].moves[i]) gDisableStructs[gBattlerTarget].disabledMove = gBattleMons[gBattlerTarget].moves[i]; - gDisableStructs[gBattlerTarget].disableTimer = (Random() & 3) + 2; + if (B_DISABLE_TURNS == GEN_3) + gDisableStructs[gBattlerTarget].disableTimer = (Random() & 3) + 2; + else if (B_DISABLE_TURNS == GEN_4) + gDisableStructs[gBattlerTarget].disableTimer = (Random() & 3) + 4; + else + gDisableStructs[gBattlerTarget].disableTimer = 4; gDisableStructs[gBattlerTarget].disableTimerStartValue = gDisableStructs[gBattlerTarget].disableTimer; // used to save the random amount of turns? gBattlescriptCurrInstr += 5; } diff --git a/src/battle_util.c b/src/battle_util.c index d6730d3314..d8dcbf3e57 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -2415,7 +2415,7 @@ u8 AtkCanceller_UnableToUseMove(void) case CANCELLER_POWDER_MOVE: if (gBattleMoves[gCurrentMove].flags & FLAG_POWDER) { - if (IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS) + if ((B_POWDER_GRASS >= GEN_6 && IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_GRASS)) || GetBattlerAbility(gBattlerTarget) == ABILITY_OVERCOAT) { gBattlerAbility = gBattlerTarget; @@ -3732,7 +3732,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA && gBattleMons[gBattlerAttacker].hp != 0 && !gProtectStructs[gBattlerAttacker].confusionSelfDmg && TARGET_TURN_DAMAGED - && !IS_BATTLER_OF_TYPE(gBattlerAttacker, TYPE_ELECTRIC) + && CanParalyzeType(gBattlerTarget, gBattlerAttacker) && GetBattlerAbility(gBattlerAttacker) != ABILITY_LIMBER && !(gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY) && !IsAbilityStatusProtected(gBattlerAttacker)