From 939127bfff1fb86458ddc5230ea2bcd22df527a7 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Sat, 14 Jul 2018 16:41:14 +0200 Subject: [PATCH] Important battle util functions --- asm/macros/battle_ai_script.inc | 4 +- data/battle_ai_scripts.s | 4 +- include/battle.h | 4 +- include/battle_util.h | 7 + include/constants/battle.h | 7 +- include/constants/battle_move_effects.h | 25 +++ include/constants/hold_effects.h | 8 + src/battle_ai_script_commands.c | 12 +- src/battle_util.c | 235 ++++++++++++++++++++++++ 9 files changed, 297 insertions(+), 9 deletions(-) diff --git a/asm/macros/battle_ai_script.inc b/asm/macros/battle_ai_script.inc index 40b01d1ec5..bc6e3e5a06 100644 --- a/asm/macros/battle_ai_script.inc +++ b/asm/macros/battle_ai_script.inc @@ -473,8 +473,10 @@ .word \jumpptr .endm - .macro nullsub_53 + .macro if_field_status flag jumpptr .byte 0x53 + .word \flag + .word \jumpptr .endm .macro nullsub_54 diff --git a/data/battle_ai_scripts.s b/data/battle_ai_scripts.s index 77be2f3549..502a3028ad 100644 --- a/data/battle_ai_scripts.s +++ b/data/battle_ai_scripts.s @@ -570,7 +570,7 @@ AI_CBM_Refresh: @ 82DC713 end AI_CBM_MudSport: @ 82DC71E - if_status3 AI_USER, STATUS3_MUDSPORT, Score_Minus10 + if_field_status STATUS_FIELD_MUDSPORT, Score_Minus10 end AI_CBM_Tickle: @ 82DC729 @@ -589,7 +589,7 @@ AI_CBM_BulkUp: @ 82DC74B end AI_CBM_WaterSport: @ 82DC75C - if_status3 AI_USER, STATUS3_WATERSPORT, Score_Minus10 + if_field_status STATUS_FIELD_WATERSPORT, Score_Minus10 end AI_CBM_CalmMind: @ 82DC767 diff --git a/include/battle.h b/include/battle.h index 22080e3382..d2f592f129 100644 --- a/include/battle.h +++ b/include/battle.h @@ -171,7 +171,8 @@ struct DisableStruct /*0x18*/ u8 unk18_a_2:2; /*0x18*/ u8 unk18_b:4; /*0x19*/ u8 rechargeCounter; - /*0x1A*/ u8 unk1A[2]; + /*0x1A*/ u8 autonomizeCount; + /*0x1B*/ u8 slowStartTimer; }; struct ProtectStruct @@ -259,6 +260,7 @@ struct FieldTimer u8 mistyTerrainTimer; u8 electricTerrainTimer; u8 psychicTerrainTimer; + u8 echoVoiceCounter; }; struct WishFutureKnock diff --git a/include/battle_util.h b/include/battle_util.h index df44b6fac1..74b43d55e0 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -72,5 +72,12 @@ void ClearFuryCutterDestinyBondGrudge(u8 battlerId); void HandleAction_RunBattleScript(void); u8 GetMoveTarget(u16 move, u8 setTarget); u8 IsMonDisobedient(void); +u32 GetBattlerAbility(u8 battlerId); +u32 GetBattlerHoldEffect(u8 battlerId, bool32 checkNegating); +u32 GetBattlerHoldEffectParam(u8 battlerId); +bool32 IsMoveMakingContact(u16 move, u8 battlerAtk); +bool32 IsBattlerGrounded(u8 battlerId); +u8 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u16 move); +u32 GetBattlerWeight(u8 battlerId); #endif // GUARD_BATTLE_UTIL_H diff --git a/include/constants/battle.h b/include/constants/battle.h index baad2712ac..31cdbb6cee 100644 --- a/include/constants/battle.h +++ b/include/constants/battle.h @@ -143,11 +143,14 @@ #define STATUS3_IMPRISONED_OTHERS 0x2000 #define STATUS3_GRUDGE 0x4000 #define STATUS3_CANT_SCORE_A_CRIT 0x8000 -// #define STATUS3_MUDSPORT 0x10000 -// #define STATUS3_WATERSPORT 0x20000 +#define STATUS3_GASTRO_ACID 0x10000 +#define STATUS3_EMBARGO 0x20000 #define STATUS3_UNDERWATER 0x40000 #define STATUS3_INTIMIDATE_POKES 0x80000 #define STATUS3_TRACE 0x100000 +#define STATUS3_SMACKED_DOWN 0x200000 +#define STATUS3_ME_FIRST 0x400000 +#define STATUS3_TELEKINESIS 0x800000 #define STATUS3_SEMI_INVULNERABLE (STATUS3_UNDERGROUND | STATUS3_ON_AIR | STATUS3_UNDERWATER) // Not really sure what a "hitmarker" is. diff --git a/include/constants/battle_move_effects.h b/include/constants/battle_move_effects.h index 4f71dbe879..9a8ed60fc2 100644 --- a/include/constants/battle_move_effects.h +++ b/include/constants/battle_move_effects.h @@ -216,4 +216,29 @@ #define EFFECT_DRAGON_DANCE 212 #define EFFECT_CAMOUFLAGE 213 +// New move effects +#define EFFECT_PLEDGE 214 +#define EFFECT_FLING 215 +#define EFFECT_NATURAL_GIFT 216 +#define EFFECT_WAKE_UP_SLAP 217 +#define EFFECT_WRING_OUT 218 +#define EFFECT_HEX 219 +#define EFFECT_ASSURANCE 220 +#define EFFECT_TRUMP_CARD 221 +#define EFFECT_ACROBATICS 222 +#define EFFECT_HEAT_CRASH 223 +#define EFFECT_PUNISHMENT 224 +#define EFFECT_STORED_POWER 225 +#define EFFECT_ELECTRO_BALL 226 +#define EFFECT_GYRO_BALL 227 +#define EFFECT_ECHOED_VOICE 228 +#define EFFECT_PAYBACK 229 +#define EFFECT_ROUND 230 +#define EFFECT_BRINE 231 +#define EFFECT_VENOSHOCK 232 +#define EFFECT_RETALITATE 233 +#define EFFECT_BULLDOZE 234 +#define EFFECT_FOUL_PLAY 235 +#define EFFECT_PSYSHOCK 236 + #endif // GUARD_CONSTANTS_BATTLE_MOVE_EFFECTS_H diff --git a/include/constants/hold_effects.h b/include/constants/hold_effects.h index 4dc9e80487..60c65e0394 100644 --- a/include/constants/hold_effects.h +++ b/include/constants/hold_effects.h @@ -97,5 +97,13 @@ #define HOLD_EFFECT_DESTINY_KNOT 91 #define HOLD_EFFECT_SHED_SHELL 92 +// Gen5 hold effects +#define HOLD_EFFECT_FLOAT_STONE 115 + +// Gen6 hold effects +#define HOLD_EFFECT_FAIRY_POWER 130 + +// Gen7 hold effects +#define HOLD_EFFECT_PROTECTIVE_PADS 150 #endif // GUARD_HOLD_EFFECTS_H diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 1fc13c65bf..2f7f79df23 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -136,7 +136,7 @@ static void BattleAICmd_get_move_power_from_result(void); static void BattleAICmd_get_move_effect_from_result(void); static void BattleAICmd_get_protect_count(void); static void BattleAICmd_if_move_flag(void); -static void BattleAICmd_nullsub_53(void); +static void BattleAICmd_if_field_status(void); static void BattleAICmd_nullsub_54(void); static void BattleAICmd_nullsub_55(void); static void BattleAICmd_nullsub_56(void); @@ -245,7 +245,7 @@ static const BattleAICmdFunc sBattleAICmdTable[] = BattleAICmd_get_move_effect_from_result, // 0x50 BattleAICmd_get_protect_count, // 0x51 BattleAICmd_if_move_flag, // 0x52 - BattleAICmd_nullsub_53, // 0x53 + BattleAICmd_if_field_status, // 0x53 BattleAICmd_nullsub_54, // 0x54 BattleAICmd_nullsub_55, // 0x55 BattleAICmd_nullsub_56, // 0x56 @@ -2133,8 +2133,14 @@ static void BattleAICmd_if_move_flag(void) gAIScriptPtr += 7; } -static void BattleAICmd_nullsub_53(void) +static void BattleAICmd_if_field_status(void) { + u32 fieldFlags = T1_READ_32(gAIScriptPtr + 1); + + if (gFieldStatuses & fieldFlags) + gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 5); + else + gAIScriptPtr += 9; } static void BattleAICmd_nullsub_54(void) diff --git a/src/battle_util.c b/src/battle_util.c index df5fb9232d..f8b726eb47 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -22,6 +22,7 @@ #include "event_data.h" #include "link.h" #include "berry.h" +#include "pokedex.h" extern u8 weather_get_current(void); @@ -3369,3 +3370,237 @@ u8 IsMonDisobedient(void) } } } + +static const u8 sAbilitiesAffectedByMoldBreaker[] = +{ + [ABILITY_BATTLE_ARMOR] = 1, + [ABILITY_CLEAR_BODY] = 1, + [ABILITY_DAMP] = 1, + [ABILITY_DRY_SKIN] = 1, + [ABILITY_FILTER] = 1, + [ABILITY_FLASH_FIRE] = 1, + [ABILITY_FLOWER_GIFT] = 1, + [ABILITY_HEATPROOF] = 1, + [ABILITY_HYPER_CUTTER] = 1, + [ABILITY_IMMUNITY] = 1, + [ABILITY_INNER_FOCUS] = 1, + [ABILITY_INSOMNIA] = 1, + [ABILITY_KEEN_EYE] = 1, + [ABILITY_LEAF_GUARD] = 1, + [ABILITY_LEVITATE] = 1, + [ABILITY_LIGHTNING_ROD] = 1, + [ABILITY_LIMBER] = 1, + [ABILITY_MAGMA_ARMOR] = 1, + [ABILITY_MARVEL_SCALE] = 1, + [ABILITY_MOTOR_DRIVE] = 1, + [ABILITY_OBLIVIOUS] = 1, + [ABILITY_OWN_TEMPO] = 1, + [ABILITY_SAND_VEIL] = 1, + [ABILITY_SHELL_ARMOR] = 1, + [ABILITY_SHIELD_DUST] = 1, + [ABILITY_SIMPLE] = 1, + [ABILITY_SNOW_CLOAK] = 1, + [ABILITY_SOLID_ROCK] = 1, + [ABILITY_SOUNDPROOF] = 1, + [ABILITY_STICKY_HOLD] = 1, + [ABILITY_STORM_DRAIN] = 1, + [ABILITY_STURDY] = 1, + [ABILITY_SUCTION_CUPS] = 1, + [ABILITY_TANGLED_FEET] = 1, + [ABILITY_THICK_FAT] = 1, + [ABILITY_UNAWARE] = 1, + [ABILITY_VITAL_SPIRIT] = 1, + [ABILITY_VOLT_ABSORB] = 1, + [ABILITY_WATER_ABSORB] = 1, + [ABILITY_WATER_VEIL] = 1, + [ABILITY_WHITE_SMOKE] = 1, + [ABILITY_WONDER_GUARD] = 1, + [ABILITY_BIG_PECKS] = 1, + [ABILITY_CONTRARY] = 1, + [ABILITY_FRIEND_GUARD] = 1, + [ABILITY_HEAVY_METAL] = 1, + [ABILITY_LIGHT_METAL] = 1, + [ABILITY_MAGIC_BOUNCE] = 1, + [ABILITY_MULTISCALE] = 1, + [ABILITY_SAP_SIPPER] = 1, + [ABILITY_TELEPATHY] = 1, + [ABILITY_WONDER_SKIN] = 1, + [ABILITY_AROMA_VEIL] = 1, + [ABILITY_BULLETPROOF] = 1, + [ABILITY_FLOWER_VEIL] = 1, + [ABILITY_FUR_COAT] = 1, + [ABILITY_OVERCOAT] = 1, + [ABILITY_SWEET_VEIL] = 1, + [ABILITY_DAZZLING] = 1, + [ABILITY_DISGUISE] = 1, + [ABILITY_FLUFFY] = 1, + [ABILITY_QUEENLY_MAJESTY] = 1, + [ABILITY_WATER_BUBBLE] = 1, +}; + +u32 GetBattlerAbility(u8 battlerId) +{ + if (gStatuses3[battlerId] & STATUS3_GASTRO_ACID) + return ABILITY_NONE; + else if ((gBattleMons[gBattlerAttacker].ability == ABILITY_MOLD_BREAKER + || gBattleMons[gBattlerAttacker].ability == ABILITY_TERAVOLT + || gBattleMons[gBattlerAttacker].ability == ABILITY_TURBOBLAZE) + && sAbilitiesAffectedByMoldBreaker[gBattleMons[battlerId].ability] + && gBattlerByTurnOrder[gCurrentTurnActionNumber] == gBattlerAttacker + && gActionsByTurnOrder[gBattlerByTurnOrder[gBattlerAttacker]] == B_ACTION_USE_MOVE + && gCurrentTurnActionNumber < gBattlersCount + && !(gStatuses3[gBattlerAttacker] & STATUS3_GASTRO_ACID)) + return ABILITY_NONE; + else + return gBattleMons[battlerId].ability; +} + +u32 GetBattlerHoldEffect(u8 battlerId, bool32 checkNegating) +{ + if (checkNegating) + { + if (gStatuses3[battlerId] & STATUS3_EMBARGO) + return HOLD_EFFECT_NONE; + if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM) + return HOLD_EFFECT_NONE; + if (gBattleMons[battlerId].ability == ABILITY_KLUTZ && !(gStatuses3[battlerId] & STATUS3_GASTRO_ACID)) + return HOLD_EFFECT_NONE; + } + + gPotentialItemEffectBattler = battlerId; + + if (gBattleMons[battlerId].item == ITEM_ENIGMA_BERRY) + return gEnigmaBerries[battlerId].holdEffect; + else + return ItemId_GetHoldEffect(gBattleMons[battlerId].item); +} + +u32 GetBattlerHoldEffectParam(u8 battlerId) +{ + if (gBattleMons[battlerId].item == ITEM_ENIGMA_BERRY) + return gEnigmaBerries[battlerId].holdEffectParam; + else + return ItemId_GetHoldEffectParam(gBattleMons[battlerId].item); +} + +bool32 IsMoveMakingContact(u16 move, u8 battlerAtk) +{ + if (!(gBattleMoves[move].flags & FLAG_MAKES_CONTACT)) + 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) +{ + if (GetBattlerHoldEffect(battlerId, TRUE) == HOLD_EFFECT_IRON_BALL) + return TRUE; + else if (gFieldStatuses & STATUS_FIELD_GRAVITY) + return TRUE; + else if (gStatuses3[battlerId] & STATUS3_ROOTED) + return TRUE; + else if (gStatuses3[battlerId] & STATUS3_SMACKED_DOWN) + return TRUE; + + else if (gStatuses3[battlerId] & STATUS3_TELEKINESIS) + return FALSE; + else if (GetBattlerAbility(battlerId) == ABILITY_LEVITATE) + return FALSE; + else if (IS_BATTLER_OF_TYPE(battlerId, TYPE_FLYING)) + return FALSE; + + else + return TRUE; +} + +bool32 IsBattlerAlive(u8 battlerId) +{ + if (gBattleMons[battlerId].hp == 0) + return FALSE; + else if (battlerId >= gBattlersCount) + return FALSE; + else if (gAbsentBattlerFlags & gBitTable[battlerId]) + return FALSE; + else + return TRUE; +} + +u8 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u16 move) +{ + u8 i; + + for (i = 0; i < 4; i++) + { + if (battleMon->moves[i] == move) + break; + } + return i; +} + +u32 GetBattlerWeight(u8 battlerId) +{ + u32 weight = GetPokedexHeightWeight(SpeciesToNationalPokedexNum(gBattleMons[battlerId].species), 1); + u32 ability = GetBattlerAbility(battlerId); + u32 holdEffect = GetBattlerHoldEffect(battlerId, TRUE); + + if (ability == ABILITY_HEAVY_METAL) + weight *= 2; + else if (ability == ABILITY_LIGHT_METAL) + weight /= 2; + + if (holdEffect == HOLD_EFFECT_FLOAT_STONE) + weight /= 2; + + if (gDisableStructs[battlerId].autonomizeCount) + weight -= 1000 * gDisableStructs[battlerId].autonomizeCount; + + if (weight == 0) + weight = 1; + + return weight; +} + +u32 CountBattlerStatIncreases(u8 battlerId, bool32 countEvasionAcc) +{ + u32 i; + u32 count = 0; + + for (i = 0; i < BATTLE_STATS_NO; i++) + { + if ((i == STAT_ACC || i == STAT_EVASION) && !countEvasionAcc) + continue; + if (gBattleMons[battlerId].statStages[i] > 6) // Stat is increased. + count += gBattleMons[battlerId].statStages[i] - 6; + } + + return count; +} + +u32 GetMoveTargetCount(u16 move, u8 battlerAtk, u8 battlerDef) +{ + switch (gBattleMoves[move].target) + { + case MOVE_TARGET_BOTH: + return IsBattlerAlive(battlerDef) + + IsBattlerAlive(BATTLE_PARTNER(battlerDef)); + case MOVE_TARGET_FOES_AND_ALLY: + return IsBattlerAlive(battlerDef) + + IsBattlerAlive(BATTLE_PARTNER(battlerDef)) + + IsBattlerAlive(BATTLE_PARTNER(battlerAtk)); + case MOVE_TARGET_OPPONENTS_FIELD: + return 1; + case MOVE_TARGET_DEPENDS: + case MOVE_TARGET_SELECTED: + case MOVE_TARGET_RANDOM: + case MOVE_TARGET_USER_OR_SELECTED: + return IsBattlerAlive(battlerDef); + case MOVE_TARGET_USER: + return IsBattlerAlive(battlerAtk); + default: + return 0; + } +}