pokeemerald/src/battle_util.c

5652 lines
217 KiB
C
Raw Normal View History

2017-09-17 14:10:32 +02:00
#include "global.h"
#include "battle.h"
2018-07-14 22:56:03 +02:00
#include "battle_interface.h"
2018-02-08 11:17:41 +01:00
#include "constants/battle_script_commands.h"
2017-12-05 18:55:48 +01:00
#include "constants/abilities.h"
2017-12-11 19:27:51 +01:00
#include "constants/moves.h"
2017-12-05 18:55:48 +01:00
#include "constants/hold_effects.h"
2017-12-31 16:28:57 +01:00
#include "constants/battle_anim.h"
2017-09-17 14:10:32 +02:00
#include "pokemon.h"
2017-12-11 19:27:51 +01:00
#include "constants/species.h"
2017-09-17 14:10:32 +02:00
#include "item.h"
2017-12-05 18:55:48 +01:00
#include "constants/items.h"
2017-09-17 14:10:32 +02:00
#include "util.h"
2017-12-05 18:55:48 +01:00
#include "constants/battle_move_effects.h"
#include "battle_scripts.h"
#include "random.h"
2017-09-17 14:10:32 +02:00
#include "text.h"
#include "string_util.h"
#include "battle_message.h"
2018-02-08 00:35:13 +01:00
#include "constants/battle_string_ids.h"
2017-09-28 17:38:07 +02:00
#include "battle_ai_script_commands.h"
2017-09-20 00:28:00 +02:00
#include "battle_controllers.h"
2017-09-17 17:14:32 +02:00
#include "event_data.h"
2017-10-06 17:06:45 +02:00
#include "link.h"
#include "berry.h"
2018-07-14 16:41:14 +02:00
#include "pokedex.h"
#include "constants/battle_config.h"
2017-09-17 14:10:32 +02:00
2017-09-17 15:19:15 +02:00
extern u8 weather_get_current(void);
2017-10-06 17:06:45 +02:00
2017-10-06 19:09:37 +02:00
// rom const data
2018-07-14 18:58:45 +02:00
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,
};
static const u8 sFlailHpScaleToPowerTable[] =
{
1, 200,
4, 150,
9, 100,
16, 80,
32, 40,
48, 20
};
// format: min. weight (hectograms), base power
static const u16 sWeightToDamageTable[] =
{
100, 20,
250, 40,
500, 60,
1000, 80,
2000, 100,
0xFFFF, 0xFFFF
};
static const u16 sSpeedDiffToDmgTable[] =
{
40, 60, 80, 120, 150
};
static const u8 sHoldEffectToType[][2] =
{
{HOLD_EFFECT_BUG_POWER, TYPE_BUG},
{HOLD_EFFECT_STEEL_POWER, TYPE_STEEL},
{HOLD_EFFECT_GROUND_POWER, TYPE_GROUND},
{HOLD_EFFECT_ROCK_POWER, TYPE_ROCK},
{HOLD_EFFECT_GRASS_POWER, TYPE_GRASS},
{HOLD_EFFECT_DARK_POWER, TYPE_DARK},
{HOLD_EFFECT_FIGHTING_POWER, TYPE_FIGHTING},
{HOLD_EFFECT_ELECTRIC_POWER, TYPE_ELECTRIC},
{HOLD_EFFECT_WATER_POWER, TYPE_WATER},
{HOLD_EFFECT_FLYING_POWER, TYPE_FLYING},
{HOLD_EFFECT_POISON_POWER, TYPE_POISON},
{HOLD_EFFECT_ICE_POWER, TYPE_ICE},
{HOLD_EFFECT_GHOST_POWER, TYPE_GHOST},
{HOLD_EFFECT_PSYCHIC_POWER, TYPE_PSYCHIC},
{HOLD_EFFECT_FIRE_POWER, TYPE_FIRE},
{HOLD_EFFECT_DRAGON_POWER, TYPE_DRAGON},
{HOLD_EFFECT_NORMAL_POWER, TYPE_NORMAL},
{HOLD_EFFECT_FAIRY_POWER, TYPE_FAIRY},
};
2018-07-14 22:56:03 +02:00
// percent in UQ_4_12 format
static const u16 sPercentToModifier[] =
{
UQ_4_12(0.00), // 0
UQ_4_12(0.01), // 1
UQ_4_12(0.02), // 2
UQ_4_12(0.03), // 3
UQ_4_12(0.04), // 4
UQ_4_12(0.05), // 5
UQ_4_12(0.06), // 6
UQ_4_12(0.07), // 7
UQ_4_12(0.08), // 8
UQ_4_12(0.09), // 9
UQ_4_12(0.10), // 10
UQ_4_12(0.11), // 11
UQ_4_12(0.12), // 12
UQ_4_12(0.13), // 13
UQ_4_12(0.14), // 14
UQ_4_12(0.15), // 15
UQ_4_12(0.16), // 16
UQ_4_12(0.17), // 17
UQ_4_12(0.18), // 18
UQ_4_12(0.19), // 19
UQ_4_12(0.20), // 20
UQ_4_12(0.21), // 21
UQ_4_12(0.22), // 22
UQ_4_12(0.23), // 23
UQ_4_12(0.24), // 24
UQ_4_12(0.25), // 25
UQ_4_12(0.26), // 26
UQ_4_12(0.27), // 27
UQ_4_12(0.28), // 28
UQ_4_12(0.29), // 29
UQ_4_12(0.30), // 30
UQ_4_12(0.31), // 31
UQ_4_12(0.32), // 32
UQ_4_12(0.33), // 33
UQ_4_12(0.34), // 34
UQ_4_12(0.35), // 35
UQ_4_12(0.36), // 36
UQ_4_12(0.37), // 37
UQ_4_12(0.38), // 38
UQ_4_12(0.39), // 39
UQ_4_12(0.40), // 40
UQ_4_12(0.41), // 41
UQ_4_12(0.42), // 42
UQ_4_12(0.43), // 43
UQ_4_12(0.44), // 44
UQ_4_12(0.45), // 45
UQ_4_12(0.46), // 46
UQ_4_12(0.47), // 47
UQ_4_12(0.48), // 48
UQ_4_12(0.49), // 49
UQ_4_12(0.50), // 50
UQ_4_12(0.51), // 51
UQ_4_12(0.52), // 52
UQ_4_12(0.53), // 53
UQ_4_12(0.54), // 54
UQ_4_12(0.55), // 55
UQ_4_12(0.56), // 56
UQ_4_12(0.57), // 57
UQ_4_12(0.58), // 58
UQ_4_12(0.59), // 59
UQ_4_12(0.60), // 60
UQ_4_12(0.61), // 61
UQ_4_12(0.62), // 62
UQ_4_12(0.63), // 63
UQ_4_12(0.64), // 64
UQ_4_12(0.65), // 65
UQ_4_12(0.66), // 66
UQ_4_12(0.67), // 67
UQ_4_12(0.68), // 68
UQ_4_12(0.69), // 69
UQ_4_12(0.70), // 70
UQ_4_12(0.71), // 71
UQ_4_12(0.72), // 72
UQ_4_12(0.73), // 73
UQ_4_12(0.74), // 74
UQ_4_12(0.75), // 75
UQ_4_12(0.76), // 76
UQ_4_12(0.77), // 77
UQ_4_12(0.78), // 78
UQ_4_12(0.79), // 79
UQ_4_12(0.80), // 80
UQ_4_12(0.81), // 81
UQ_4_12(0.82), // 82
UQ_4_12(0.83), // 83
UQ_4_12(0.84), // 84
UQ_4_12(0.85), // 85
UQ_4_12(0.86), // 86
UQ_4_12(0.87), // 87
UQ_4_12(0.88), // 88
UQ_4_12(0.89), // 89
UQ_4_12(0.90), // 90
UQ_4_12(0.91), // 91
UQ_4_12(0.92), // 92
UQ_4_12(0.93), // 93
UQ_4_12(0.94), // 94
UQ_4_12(0.95), // 95
UQ_4_12(0.96), // 96
UQ_4_12(0.97), // 97
UQ_4_12(0.98), // 98
UQ_4_12(0.99), // 99
UQ_4_12(1.00), // 100
};
#define X UQ_4_12
static const u16 sTypeEffectivenessTable[NUMBER_OF_MON_TYPES][NUMBER_OF_MON_TYPES] =
{
// normal fight flying poison ground rock bug ghost steel mystery fire water grass electric psychic ice dragon dark fairy
{X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(0.5), X(1.0), X(0.0), X(0.5), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0)}, // normal
{X(2.0), X(1.0), X(0.5), X(0.5), X(1.0), X(2.0), X(0.5), X(0.0), X(2.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(0.5), X(2.0), X(1.0), X(2.0), X(0.5)}, // fight
{X(1.0), X(2.0), X(1.0), X(1.0), X(1.0), X(0.5), X(2.0), X(1.0), X(0.5), X(1.0), X(1.0), X(1.0), X(2.0), X(0.5), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0)}, // flying
{X(1.0), X(1.0), X(1.0), X(0.5), X(0.5), X(0.5), X(1.0), X(0.5), X(0.0), X(1.0), X(1.0), X(1.0), X(2.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0)}, // poison
{X(1.0), X(1.0), X(0.0), X(2.0), X(1.0), X(2.0), X(0.5), X(1.0), X(2.0), X(1.0), X(2.0), X(1.0), X(0.5), X(2.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0)}, // ground
{X(1.0), X(0.5), X(2.0), X(1.0), X(0.5), X(1.0), X(2.0), X(1.0), X(0.5), X(1.0), X(2.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(1.0), X(1.0), X(1.0)}, // rock
{X(1.0), X(0.5), X(0.5), X(0.5), X(1.0), X(1.0), X(1.0), X(0.5), X(0.5), X(1.0), X(0.5), X(1.0), X(2.0), X(1.0), X(2.0), X(1.0), X(1.0), X(2.0), X(0.5)}, // bug
{X(0.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(1.0), X(1.0), X(0.5), X(1.0)}, // ghost
{X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(1.0), X(1.0), X(0.5), X(1.0), X(0.5), X(0.5), X(1.0), X(0.5), X(1.0), X(2.0), X(1.0), X(1.0), X(2.0)}, // steel
{X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0)}, // mystery
{X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(0.5), X(2.0), X(1.0), X(2.0), X(1.0), X(0.5), X(0.5), X(2.0), X(1.0), X(1.0), X(2.0), X(0.5), X(1.0), X(1.0)}, // fire
{X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(2.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(0.5), X(0.5), X(1.0), X(1.0), X(1.0), X(0.5), X(1.0), X(1.0)}, // water
{X(1.0), X(1.0), X(0.5), X(0.5), X(2.0), X(2.0), X(0.5), X(1.0), X(0.5), X(1.0), X(0.5), X(2.0), X(0.5), X(1.0), X(1.0), X(1.0), X(0.5), X(1.0), X(1.0)}, // grass
{X(1.0), X(1.0), X(2.0), X(1.0), X(0.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(0.5), X(0.5), X(1.0), X(1.0), X(0.5), X(1.0), X(1.0)}, // electric
{X(1.0), X(2.0), X(1.0), X(2.0), X(1.0), X(1.0), X(1.0), X(1.0), X(0.5), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(0.5), X(1.0), X(1.0), X(0.0), X(1.0)}, // psychic
{X(1.0), X(1.0), X(2.0), X(1.0), X(2.0), X(1.0), X(1.0), X(1.0), X(0.5), X(1.0), X(0.5), X(0.5), X(2.0), X(1.0), X(1.0), X(0.5), X(2.0), X(1.0), X(1.0)}, // ice
{X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(0.5), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(1.0), X(0.0)}, // dragon
{X(1.0), X(0.5), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(1.0), X(1.0), X(0.5), X(0.5)}, // dark
{X(1.0), X(2.0), X(1.0), X(0.5), X(1.0), X(1.0), X(1.0), X(1.0), X(0.5), X(1.0), X(0.5), X(1.0), X(1.0), X(1.0), X(1.0), X(1.0), X(2.0), X(2.0), X(1.0)}, // fairy
};
#undef X
2018-07-14 18:58:45 +02:00
// code
2018-02-08 11:17:41 +01:00
u8 GetBattlerForBattleScript(u8 caseId)
2017-10-06 17:06:45 +02:00
{
u8 ret = 0;
switch (caseId)
{
2018-02-08 11:17:41 +01:00
case BS_TARGET:
2018-02-06 23:09:39 +01:00
ret = gBattlerTarget;
2017-10-06 17:06:45 +02:00
break;
2018-02-08 11:17:41 +01:00
case BS_ATTACKER:
2018-02-06 23:09:39 +01:00
ret = gBattlerAttacker;
2017-10-06 17:06:45 +02:00
break;
2018-02-08 11:17:41 +01:00
case BS_EFFECT_BATTLER:
ret = gEffectBattler;
2017-10-06 17:06:45 +02:00
break;
2018-07-01 11:15:42 +02:00
case BS_BATTLER_0:
2017-10-06 17:06:45 +02:00
ret = 0;
break;
2018-02-08 11:17:41 +01:00
case BS_SCRIPTING:
2018-02-06 02:46:59 +01:00
ret = gBattleScripting.battler;
2017-10-06 17:06:45 +02:00
break;
2018-02-08 11:17:41 +01:00
case BS_FAINTED:
ret = gBattlerFainted;
2017-10-06 17:06:45 +02:00
break;
case 5:
2018-02-08 11:17:41 +01:00
ret = gBattlerFainted;
2017-10-06 17:06:45 +02:00
break;
case 4:
case 6:
case 8:
case 9:
2018-02-08 11:17:41 +01:00
case BS_PLAYER1:
2018-02-06 02:46:59 +01:00
ret = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
2017-10-06 17:06:45 +02:00
break;
2018-02-08 11:17:41 +01:00
case BS_OPPONENT1:
2018-02-06 02:46:59 +01:00
ret = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
2017-10-06 17:06:45 +02:00
break;
2018-02-08 11:17:41 +01:00
case BS_PLAYER2:
2018-02-06 02:46:59 +01:00
ret = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
2017-10-06 17:06:45 +02:00
break;
2018-02-08 11:17:41 +01:00
case BS_OPPONENT2:
2018-02-06 02:46:59 +01:00
ret = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
2017-10-06 17:06:45 +02:00
break;
}
return ret;
}
2018-02-06 02:46:59 +01:00
void PressurePPLose(u8 defender, u8 attacker, u16 move)
2017-10-06 17:06:45 +02:00
{
s32 i;
2018-02-06 02:46:59 +01:00
if (gBattleMons[defender].ability != ABILITY_PRESSURE)
2017-10-06 17:06:45 +02:00
return;
for (i = 0; i < 4; i++)
{
2018-02-06 02:46:59 +01:00
if (gBattleMons[attacker].moves[i] == move)
2017-10-06 17:06:45 +02:00
break;
}
if (i == 4) // mons don't share any moves
return;
2018-02-06 02:46:59 +01:00
if (gBattleMons[attacker].pp[i] != 0)
gBattleMons[attacker].pp[i]--;
2017-10-06 17:06:45 +02:00
2018-02-06 02:46:59 +01:00
if (!(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED)
&& !(gDisableStructs[attacker].unk18_b & gBitTable[i]))
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
gActiveBattler = attacker;
2018-02-06 20:48:02 +01:00
BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + i, 0, 1, &gBattleMons[gActiveBattler].pp[i]);
MarkBattlerForControllerExec(gActiveBattler);
2017-10-06 17:06:45 +02:00
}
}
2018-02-06 02:46:59 +01:00
void PressurePPLoseOnUsingImprision(u8 attacker)
2017-10-06 17:06:45 +02:00
{
s32 i, j;
s32 imprisionPos = 4;
2018-02-06 02:46:59 +01:00
u8 atkSide = GetBattlerSide(attacker);
2017-10-06 17:06:45 +02:00
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
if (atkSide != GetBattlerSide(i) && gBattleMons[i].ability == ABILITY_PRESSURE)
2017-10-06 17:06:45 +02:00
{
for (j = 0; j < 4; j++)
{
2018-02-06 02:46:59 +01:00
if (gBattleMons[attacker].moves[j] == MOVE_IMPRISON)
2017-10-06 17:06:45 +02:00
break;
}
if (j != 4)
{
imprisionPos = j;
2018-02-06 02:46:59 +01:00
if (gBattleMons[attacker].pp[j] != 0)
gBattleMons[attacker].pp[j]--;
2017-10-06 17:06:45 +02:00
}
}
}
if (imprisionPos != 4
2018-02-06 02:46:59 +01:00
&& !(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED)
&& !(gDisableStructs[attacker].unk18_b & gBitTable[imprisionPos]))
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
gActiveBattler = attacker;
2018-02-06 20:48:02 +01:00
BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + imprisionPos, 0, 1, &gBattleMons[gActiveBattler].pp[imprisionPos]);
MarkBattlerForControllerExec(gActiveBattler);
2017-10-06 17:06:45 +02:00
}
}
2018-02-06 02:46:59 +01:00
void PressurePPLoseOnUsingPerishSong(u8 attacker)
2017-10-06 17:06:45 +02:00
{
s32 i, j;
s32 perishSongPos = 4;
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
if (gBattleMons[i].ability == ABILITY_PRESSURE && i != attacker)
2017-10-06 17:06:45 +02:00
{
for (j = 0; j < 4; j++)
{
2018-02-06 02:46:59 +01:00
if (gBattleMons[attacker].moves[j] == MOVE_PERISH_SONG)
2017-10-06 17:06:45 +02:00
break;
}
if (j != 4)
{
perishSongPos = j;
2018-02-06 02:46:59 +01:00
if (gBattleMons[attacker].pp[j] != 0)
gBattleMons[attacker].pp[j]--;
2017-10-06 17:06:45 +02:00
}
}
}
if (perishSongPos != 4
2018-02-06 02:46:59 +01:00
&& !(gBattleMons[attacker].status2 & STATUS2_TRANSFORMED)
&& !(gDisableStructs[attacker].unk18_b & gBitTable[perishSongPos]))
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
gActiveBattler = attacker;
2018-02-06 20:48:02 +01:00
BtlController_EmitSetMonData(0, REQUEST_PPMOVE1_BATTLE + perishSongPos, 0, 1, &gBattleMons[gActiveBattler].pp[perishSongPos]);
MarkBattlerForControllerExec(gActiveBattler);
2017-10-06 17:06:45 +02:00
}
}
2018-02-06 20:48:02 +01:00
void MarkAllBattlersForControllerExec(void) // unused
2017-10-06 17:06:45 +02:00
{
s32 i;
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
{
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2018-02-06 20:48:02 +01:00
gBattleControllerExecFlags |= gBitTable[i] << 0x1C;
2017-10-06 17:06:45 +02:00
}
else
{
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2018-02-06 20:48:02 +01:00
gBattleControllerExecFlags |= gBitTable[i];
2017-10-06 17:06:45 +02:00
}
}
2018-02-06 20:48:02 +01:00
void MarkBattlerForControllerExec(u8 battlerId)
2017-10-06 17:06:45 +02:00
{
if (gBattleTypeFlags & BATTLE_TYPE_LINK)
2018-02-06 20:48:02 +01:00
gBattleControllerExecFlags |= gBitTable[battlerId] << 0x1C;
2017-10-06 17:06:45 +02:00
else
2018-02-06 20:48:02 +01:00
gBattleControllerExecFlags |= gBitTable[battlerId];
2017-10-06 17:06:45 +02:00
}
void sub_803F850(u8 arg0)
{
s32 i;
Decompile TV (#80) * ClearTVShowData * special_0x44 * DoTVShow (nonmatching because align) * DoTVShowBravoTrainerPokemonProfile * Update field names * DoTVShowBravoTrainerBattleTower * Renaming of struct fields * sub_80EBFF4 and UpdateTVScreensOnMap * SetTVMetatilesOnMap * Power buttons for the TV screens on the map * special_0x45 * sub_80EC18C * special_0x4a * ResetGabbyAndTy * GabbyAndTyBeforeInterview * GabbyAndTyAfterInterview * Through IsTVShowInSearchOfTrainersAiring * GabbyAndTyGetLastQuote * GabbyAndTyGetLastBattleTrivia * GabbyAndTySetScriptVarsToFieldObjectLocalIds * InterviewAfter; use TVShow as a precursor for making the individual show structs anonymous * Make TV structs anonymous within the union * Move the TV union to its own subheader * Move TV show enums to the global.tv.h subheader * Funcion renaming * Apply static attributes where able * PutPokemonTodayCaughtOnAir * sub_80EC8A4 * PutPokemonTodayFailedOnTheAir * sub_80EC9E8, sub_80ECA10 * sub_80ECA38 * sub_80ECB00 * Put3CheersForPokeblocksOnTheAir * PutFanClubSpecialOnTheAir * ContestLiveUpdates_BeforeInterview * Other before-interview Contest Live Updates functions * ContestLiveUpdates_BeforeInterview_5 * InterviewAfter_BravoTrainerPokemonProfile * BravoTrainerPokemonProfile_BeforeInterview1 * BravoTrainerPokemonProfile_BeforeInterview2 * Disassemble TV data * Decompile TV data * InterviewAfter_BravoTrainerBattleTowerProfile * SaveRecordedItemPurchasesForTVShow * PutNameRaterShowOnTheAir * StartMassOutbreak * PutLilycoveContestLadyShowOnTheAir * InterviewAfter_FanClubLetter * Rip TV strings * InterviewAfter_RecentHappenings * InterviewAfter_PkmnFanClubOpinions * sub_80ED718 * EndMassOutbreak * sub_80ED888 * sub_80ED8B4 * UpdateMassOutbreakTimeLeft * sub_80ED950 * PutFishingAdviceShowOnTheAir * through sub_80EDA80 * ewram and common syms are now fetched from the object files * BSS symbols are taken from the tv.o file * through sub_80EDC60 * sub_80EDCE8 * sub_80EDD78 * through sub_80EDE84 * nomatching sub_80EDE98 * sub_80EDFB4 * sub_80EE104 * sub_80EE104 * sub_80EE184 * sub_80EE2CC * sub_80EE35C * sub_80EE44C * sub_80EE4DC * sub_80EE5A4 * sub_80EE69C * sub_80EE72C * sub_80EE7C0 * sub_80EE818 * sub_80EE8C8 * sub_80EEA70 * sub_80EEB98 * sub_80EEBF4 * through sub_80EED60 * Functions relating to Pokemon News * sub_80EEF6C * GetPriceReduction * IsPriceDiscounted * sub_80EF120 * through sub_80EF370 * sub_80EF40C * HasMixableShowAlreadyBeenSpawnedWithPlayerID * TV_SortPurchasesByQuantity * FindActiveBroadcastByShowType_SetScriptResult * InterviewBefore * through sub_80EF88C * through sub_80EF93C * through sub_80EFA24 * through TV_BernoulliTrial * sub_80EFB58 * sub_80EFBA4 * sub_80EFBDC * through sub_80EFD98 * ChangePokemonNickname * ChangeBoxPokemonNickname * sub_80EFF9C * through player_id_to_dword * CheckForBigMovieOrEmergencyNewsOnTV * GetMomOrDadStringForTVMessage * sub_80F01E8 * sub_80F0358 * sub_80F049C * TV record mixing functions * sub_80F06D0 * sub_80F0708 nonmatching * through sub_80F0B24 * sub_80F0B64 * through sub_80F0C04 * sub_80F0C7C * sub_80F0D60 * sub_80F0E58 * sub_80F0E84 * through sub_80F0F24 * sub_80F0F64 * sub_80F1208 * sub_80F1254 * sub_80F1290 * sub_80F12A4 * sub_80F14F8 * DoTVShowTodaysSmartShopper * DoTVShowTheNameRaterShow * DoTVShowPokemonTodaySuccessfulCapture * DoTVShowPokemonTodayFailedCapture * DoTVShowPokemonFanClubLetter * DoTVShowRecentHappenings * DoTVShowPokemonFanClubOpinions * DoTVShowPokemonNewsMassOutbreak * DoTVShowPokemonContestLiveUpdates * DoTVShowPokemonBattleUpdate * DoTVShow3CheersForPokeblocks * DoTVShowInSearchOfTrainers * Label GabbyAndTyData fields; remove ddump comments from data/text/tv.inc * DoTVShowPokemonAngler * DoTVShowTheWorldOfMasters; update RAM symbols and field names * Decorate static functions * DoTVShowTodaysRivalTrainer; region map enums * TVDewfordTrendWatcherNetworkTextGroup * DoTVShowHoennTreasureInvestigators * DoTVShowFindThatGamer * DoTVShowBreakingNewsTV * DoTVShowSecretBaseVisit * DoTVShowPokemonLotterWinnerFlashReport * DoTVShowThePokemonBattleSeminar * DoTVShowTrainerFanClubSpecial, DoTVShowTrainerFanClub * DoTVShowSpotTheCuties * DoTVShowPokemonNewsBattleFrontier * DoTVShowWhatsNo1InHoennToday * Helpers for DoTVShowSecretBaseSecrets * DoTVShowSecretBaseSecrets * DoTVShowSafariFanClub * Finish decompilation of tv.s * Some renaming * Rename text group pointers * revoke statis; pokenews enums * Labels are number one * Label all TV struct fields * Make data/text/tv.inc more readable * Split data/text/tv.inc * Rename pokenews text pointers * Frontier Symbol constants; indicate static rodata objects with 's' prefix * Fix leading spaces/tabs F*** CLion sometimes * Fix inconsequential warning
2017-10-13 17:09:36 +02:00
for (i = 0; i < GetLinkPlayerCount(); i++)
2018-02-06 20:48:02 +01:00
gBattleControllerExecFlags |= gBitTable[arg0] << (i << 2);
2017-10-06 17:06:45 +02:00
2018-02-06 20:48:02 +01:00
gBattleControllerExecFlags &= ~(0x10000000 << arg0);
2017-10-06 17:06:45 +02:00
}
2018-02-06 02:46:59 +01:00
void CancelMultiTurnMoves(u8 battler)
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
gBattleMons[battler].status2 &= ~(STATUS2_MULTIPLETURNS);
gBattleMons[battler].status2 &= ~(STATUS2_LOCK_CONFUSE);
gBattleMons[battler].status2 &= ~(STATUS2_UPROAR);
gBattleMons[battler].status2 &= ~(STATUS2_BIDE);
2017-10-06 17:06:45 +02:00
2018-02-06 02:46:59 +01:00
gStatuses3[battler] &= ~(STATUS3_SEMI_INVULNERABLE);
2017-10-06 17:06:45 +02:00
2018-02-06 02:46:59 +01:00
gDisableStructs[battler].rolloutCounter1 = 0;
gDisableStructs[battler].furyCutterCounter = 0;
2017-10-06 17:06:45 +02:00
}
2018-02-06 02:46:59 +01:00
bool8 WasUnableToUseMove(u8 battler)
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
if (gProtectStructs[battler].prlzImmobility
|| gProtectStructs[battler].targetNotAffected
|| gProtectStructs[battler].usedImprisionedMove
|| gProtectStructs[battler].loveImmobility
|| gProtectStructs[battler].usedDisabledMove
|| gProtectStructs[battler].usedTauntedMove
|| gProtectStructs[battler].usedGravityPreventedMove
|| gProtectStructs[battler].usedHealBlockedMove
2018-02-06 02:46:59 +01:00
|| gProtectStructs[battler].flag2Unknown
|| gProtectStructs[battler].flinchImmobility
|| gProtectStructs[battler].confusionSelfDmg)
2017-10-06 17:06:45 +02:00
return TRUE;
else
return FALSE;
}
2018-02-06 02:46:59 +01:00
void PrepareStringBattle(u16 stringId, u8 battler)
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
gActiveBattler = battler;
2018-02-06 20:48:02 +01:00
BtlController_EmitPrintString(0, stringId);
MarkBattlerForControllerExec(gActiveBattler);
2017-10-06 17:06:45 +02:00
}
void ResetSentPokesToOpponentValue(void)
{
s32 i;
u32 bits = 0;
gSentPokesToOpponent[0] = 0;
gSentPokesToOpponent[1] = 0;
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i += 2)
2018-02-06 20:48:02 +01:00
bits |= gBitTable[gBattlerPartyIndexes[i]];
2017-10-06 17:06:45 +02:00
2018-02-06 02:46:59 +01:00
for (i = 1; i < gBattlersCount; i += 2)
gSentPokesToOpponent[(i & BIT_FLANK) >> 1] = bits;
2017-10-06 17:06:45 +02:00
}
2018-02-06 02:46:59 +01:00
void sub_803F9EC(u8 battler)
2017-10-06 17:06:45 +02:00
{
s32 i = 0;
u32 bits = 0;
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(battler) == B_SIDE_OPPONENT)
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
u8 flank = ((battler & BIT_FLANK) >> 1);
gSentPokesToOpponent[flank] = 0;
2017-10-06 17:06:45 +02:00
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i += 2)
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
if (!(gAbsentBattlerFlags & gBitTable[i]))
2018-02-06 20:48:02 +01:00
bits |= gBitTable[gBattlerPartyIndexes[i]];
2017-10-06 17:06:45 +02:00
}
2018-02-06 02:46:59 +01:00
gSentPokesToOpponent[flank] = bits;
2017-10-06 17:06:45 +02:00
}
}
2018-02-06 02:46:59 +01:00
void sub_803FA70(u8 battler)
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(battler) == B_SIDE_OPPONENT)
2017-10-06 17:06:45 +02:00
{
2018-02-06 02:46:59 +01:00
sub_803F9EC(battler);
2017-10-06 17:06:45 +02:00
}
else
{
s32 i;
2018-02-06 02:46:59 +01:00
for (i = 1; i < gBattlersCount; i++)
2018-02-06 20:48:02 +01:00
gSentPokesToOpponent[(i & BIT_FLANK) >> 1] |= gBitTable[gBattlerPartyIndexes[battler]];
2017-10-06 17:06:45 +02:00
}
}
2017-09-17 14:10:32 +02:00
2018-07-01 11:15:42 +02:00
void BattleScriptPush(const u8 *bsPtr)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattleResources->battleScriptsStack->ptr[gBattleResources->battleScriptsStack->size++] = bsPtr;
2017-09-17 14:10:32 +02:00
}
2017-09-22 21:33:49 +02:00
void BattleScriptPushCursor(void)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattleResources->battleScriptsStack->ptr[gBattleResources->battleScriptsStack->size++] = gBattlescriptCurrInstr;
2017-09-17 14:10:32 +02:00
}
2017-09-22 21:33:49 +02:00
void BattleScriptPop(void)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattlescriptCurrInstr = gBattleResources->battleScriptsStack->ptr[--gBattleResources->battleScriptsStack->size];
2017-09-17 14:10:32 +02:00
}
2018-07-31 23:09:47 +02:00
static bool32 IsGravityPreventingMove(u32 move)
{
if (!(gFieldStatuses & STATUS_FIELD_GRAVITY))
return FALSE;
switch (move)
{
case MOVE_BOUNCE:
case MOVE_FLY:
case MOVE_FLYING_PRESS:
case MOVE_HI_JUMP_KICK:
case MOVE_JUMP_KICK:
case MOVE_MAGNET_RISE:
case MOVE_SKY_DROP:
case MOVE_SPLASH:
case MOVE_TELEKINESIS:
return TRUE;
default:
return FALSE;
}
}
static bool32 IsHealBlockPreventingMove(u8 battler, u32 move)
{
if (!(gStatuses3[battler] & STATUS3_HEAL_BLOCK))
return FALSE;
switch (gBattleMoves[move].effect)
{
case EFFECT_ABSORB:
case EFFECT_MORNING_SUN:
case EFFECT_MOONLIGHT:
case EFFECT_RESTORE_HP:
case EFFECT_REST:
case EFFECT_ROOST:
case EFFECT_HEALING_WISH:
case EFFECT_WISH:
return TRUE;
default:
return FALSE;
}
}
u8 TrySetCantSelectMoveBattleScript(void)
2017-09-17 14:10:32 +02:00
{
u8 limitations = 0;
u8 moveId = gBattleBufferB[gActiveBattler][2] & ~(RET_MEGA_EVOLUTION);
u32 move = gBattleMons[gActiveBattler].moves[moveId];
2018-07-31 23:09:47 +02:00
u32 holdEffect = GetBattlerHoldEffect(gActiveBattler, TRUE);
2018-02-06 02:46:59 +01:00
u16* choicedMove = &gBattleStruct->choicedMove[gActiveBattler];
2017-09-17 14:10:32 +02:00
2018-02-06 02:46:59 +01:00
if (gDisableStructs[gActiveBattler].disabledMove == move && move != 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gBattleScripting.battler = gActiveBattler;
2017-09-17 14:10:32 +02:00
gCurrentMove = move;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
2018-02-06 02:46:59 +01:00
gPalaceSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingDisabledMoveInPalace;
gProtectStructs[gActiveBattler].flag_x10 = 1;
2017-09-17 14:10:32 +02:00
}
else
{
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingDisabledMove;
2018-07-31 23:09:47 +02:00
limitations++;
2017-09-17 14:10:32 +02:00
}
}
2018-02-06 02:46:59 +01:00
if (move == gLastMoves[gActiveBattler] && move != MOVE_STRUGGLE && (gBattleMons[gActiveBattler].status2 & STATUS2_TORMENT))
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
CancelMultiTurnMoves(gActiveBattler);
2017-09-17 14:10:32 +02:00
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
2018-02-06 02:46:59 +01:00
gPalaceSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingTormentedMoveInPalace;
gProtectStructs[gActiveBattler].flag_x10 = 1;
2017-09-17 14:10:32 +02:00
}
else
{
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingTormentedMove;
2017-09-17 14:10:32 +02:00
limitations++;
}
}
2018-02-06 02:46:59 +01:00
if (gDisableStructs[gActiveBattler].tauntTimer1 != 0 && gBattleMoves[move].power == 0)
2017-09-17 14:10:32 +02:00
{
gCurrentMove = move;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
2018-02-06 02:46:59 +01:00
gPalaceSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveTauntInPalace;
gProtectStructs[gActiveBattler].flag_x10 = 1;
2017-09-17 14:10:32 +02:00
}
else
{
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveTaunt;
2017-09-17 14:10:32 +02:00
limitations++;
}
}
2018-02-06 02:46:59 +01:00
if (GetImprisonedMovesCount(gActiveBattler, move))
2017-09-17 14:10:32 +02:00
{
gCurrentMove = move;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
2018-02-06 02:46:59 +01:00
gPalaceSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingImprisionedMoveInPalace;
gProtectStructs[gActiveBattler].flag_x10 = 1;
2017-09-17 14:10:32 +02:00
}
else
{
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingImprisionedMove;
2017-09-17 14:10:32 +02:00
limitations++;
}
}
2018-07-31 23:09:47 +02:00
if (IsGravityPreventingMove(move))
{
gCurrentMove = move;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
gPalaceSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveGravityInPalace;
gProtectStructs[gActiveBattler].flag_x10 = 1;
}
else
{
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveGravity;
limitations++;
}
}
2017-09-17 14:10:32 +02:00
2018-07-31 23:09:47 +02:00
if (IsHealBlockPreventingMove(gActiveBattler, move))
{
gCurrentMove = move;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
gPalaceSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveHealBlockInPalace;
gProtectStructs[gActiveBattler].flag_x10 = 1;
}
else
{
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveHealBlock;
limitations++;
}
}
2017-09-17 14:10:32 +02:00
2018-07-31 23:09:47 +02:00
gPotentialItemEffectBattler = gActiveBattler;
if (HOLD_EFFECT_CHOICE(holdEffect) && *choicedMove != 0 && *choicedMove != 0xFFFF && *choicedMove != move)
2017-09-17 14:10:32 +02:00
{
gCurrentMove = *choicedMove;
2018-02-06 02:46:59 +01:00
gLastUsedItem = gBattleMons[gActiveBattler].item;
2017-09-17 14:10:32 +02:00
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
2018-02-06 02:46:59 +01:00
gProtectStructs[gActiveBattler].flag_x10 = 1;
2017-09-17 14:10:32 +02:00
}
else
{
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveChoiceItem;
2017-09-17 14:10:32 +02:00
limitations++;
}
}
2018-07-31 23:09:47 +02:00
else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && gBattleMoves[move].power == 0)
{
gCurrentMove = move;
gLastUsedItem = gBattleMons[gActiveBattler].item;
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
gProtectStructs[gActiveBattler].flag_x10 = 1;
}
else
{
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingNotAllowedMoveAssaultVest;
limitations++;
}
}
2017-09-17 14:10:32 +02:00
if (gBattleMons[gActiveBattler].pp[moveId] == 0)
2017-09-17 14:10:32 +02:00
{
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
{
2018-02-06 02:46:59 +01:00
gProtectStructs[gActiveBattler].flag_x10 = 1;
2017-09-17 14:10:32 +02:00
}
else
{
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_SelectingMoveWithNoPP;
2017-09-17 14:10:32 +02:00
limitations++;
}
}
return limitations;
}
2018-02-08 11:17:41 +01:00
u8 CheckMoveLimitations(u8 battlerId, u8 unusableMoves, u8 check)
2017-09-17 14:10:32 +02:00
{
2018-07-31 23:09:47 +02:00
u8 holdEffect = GetBattlerHoldEffect(battlerId, TRUE);
2018-02-08 11:17:41 +01:00
u16 *choicedMove = &gBattleStruct->choicedMove[battlerId];
2017-09-17 14:10:32 +02:00
s32 i;
2018-02-08 12:13:29 +01:00
gPotentialItemEffectBattler = battlerId;
2017-09-17 14:10:32 +02:00
2018-07-31 23:09:47 +02:00
for (i = 0; i < 4; i++)
2017-09-17 14:10:32 +02:00
{
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].moves[i] == 0 && check & MOVE_LIMITATION_ZEROMOVE)
2017-09-17 14:10:32 +02:00
unusableMoves |= gBitTable[i];
2018-07-31 23:09:47 +02:00
else if (gBattleMons[battlerId].pp[i] == 0 && check & MOVE_LIMITATION_PP)
unusableMoves |= gBitTable[i];
else if (gBattleMons[battlerId].moves[i] == gDisableStructs[battlerId].disabledMove && check & MOVE_LIMITATION_DISABLED)
unusableMoves |= gBitTable[i];
else if (gBattleMons[battlerId].moves[i] == gLastMoves[battlerId] && check & MOVE_LIMITATION_TORMENTED && gBattleMons[battlerId].status2 & STATUS2_TORMENT)
unusableMoves |= gBitTable[i];
else if (gDisableStructs[battlerId].tauntTimer1 && check & MOVE_LIMITATION_TAUNT && gBattleMoves[gBattleMons[battlerId].moves[i]].power == 0)
2017-09-17 14:10:32 +02:00
unusableMoves |= gBitTable[i];
2018-07-31 23:09:47 +02:00
else if (GetImprisonedMovesCount(battlerId, gBattleMons[battlerId].moves[i]) && check & MOVE_LIMITATION_IMPRISION)
2017-09-17 14:10:32 +02:00
unusableMoves |= gBitTable[i];
2018-07-31 23:09:47 +02:00
else if (gDisableStructs[battlerId].encoreTimer1 && gDisableStructs[battlerId].encoredMove != gBattleMons[battlerId].moves[i])
2017-09-17 14:10:32 +02:00
unusableMoves |= gBitTable[i];
2018-07-31 23:09:47 +02:00
else if (HOLD_EFFECT_CHOICE(holdEffect) && *choicedMove != 0 && *choicedMove != 0xFFFF && *choicedMove != gBattleMons[battlerId].moves[i])
2017-09-17 14:10:32 +02:00
unusableMoves |= gBitTable[i];
2018-07-31 23:09:47 +02:00
else if (holdEffect == HOLD_EFFECT_ASSAULT_VEST && gBattleMoves[gBattleMons[battlerId].moves[i]].power == 0)
2017-09-17 14:10:32 +02:00
unusableMoves |= gBitTable[i];
2018-07-31 23:09:47 +02:00
else if (IsGravityPreventingMove(gBattleMons[battlerId].moves[i]))
2017-09-17 14:10:32 +02:00
unusableMoves |= gBitTable[i];
2018-07-31 23:09:47 +02:00
else if (IsHealBlockPreventingMove(battlerId, gBattleMons[battlerId].moves[i]))
2017-09-17 14:10:32 +02:00
unusableMoves |= gBitTable[i];
}
return unusableMoves;
}
bool8 AreAllMovesUnusable(void)
{
u8 unusable;
2018-02-06 02:46:59 +01:00
unusable = CheckMoveLimitations(gActiveBattler, 0, 0xFF);
2017-09-17 14:10:32 +02:00
2018-07-01 11:15:42 +02:00
if (unusable == 0xF) // All moves are unusable.
2017-09-17 14:10:32 +02:00
{
2018-07-07 19:57:09 +02:00
gProtectStructs[gActiveBattler].noValidMoves = 1;
2018-02-06 02:46:59 +01:00
gSelectionBattleScripts[gActiveBattler] = BattleScript_NoMovesLeft;
2017-09-17 14:10:32 +02:00
}
else
{
2018-07-07 19:57:09 +02:00
gProtectStructs[gActiveBattler].noValidMoves = 0;
2017-09-17 14:10:32 +02:00
}
return (unusable == 0xF);
}
2018-02-08 11:17:41 +01:00
u8 GetImprisonedMovesCount(u8 battlerId, u16 move)
2017-09-17 14:10:32 +02:00
{
s32 i;
u8 imprisionedMoves = 0;
2018-07-16 20:47:30 +02:00
u8 battlerSide = GetBattlerSide(battlerId);
2017-09-17 14:10:32 +02:00
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-09-17 14:10:32 +02:00
{
2018-07-16 20:47:30 +02:00
if (battlerSide != GetBattlerSide(i) && gStatuses3[i] & STATUS3_IMPRISONED_OTHERS)
2017-09-17 14:10:32 +02:00
{
s32 j;
for (j = 0; j < 4; j++)
{
if (move == gBattleMons[i].moves[j])
break;
}
if (j < 4)
imprisionedMoves++;
}
}
return imprisionedMoves;
}
2018-07-21 12:10:08 +02:00
enum
{
ENDTURN_ORDER,
ENDTURN_REFLECT,
ENDTURN_LIGHT_SCREEN,
2018-07-21 12:56:07 +02:00
ENDTURN_AURORA_VEIL,
2018-07-21 12:10:08 +02:00
ENDTURN_MIST,
2018-07-21 12:56:07 +02:00
ENDTURN_LUCKY_CHANT,
2018-07-21 12:10:08 +02:00
ENDTURN_SAFEGUARD,
2018-07-21 12:56:07 +02:00
ENDTURN_TAILWIND,
2018-07-21 12:10:08 +02:00
ENDTURN_WISH,
ENDTURN_RAIN,
ENDTURN_SANDSTORM,
ENDTURN_SUN,
ENDTURN_HAIL,
ENDTURN_GRAVITY,
2018-07-21 13:24:20 +02:00
ENDTURN_WATER_SPORT,
ENDTURN_MUD_SPORT,
ENDTURN_TRICK_ROOM,
ENDTURN_WONDER_ROOM,
ENDTURN_MAGIC_ROOM,
ENDTURN_ELECTRIC_TERRAIN,
ENDTURN_MISTY_TERRAIN,
ENDTURN_GRASSY_TERRAIN,
ENDTURN_PSYCHIC_TERRAIN,
2018-08-04 23:34:29 +02:00
ENDTURN_ION_DELUGE,
2018-07-21 12:10:08 +02:00
ENDTURN_FIELD_COUNT,
};
u8 DoFieldEndTurnEffects(void)
2017-09-17 14:10:32 +02:00
{
u8 effect = 0;
2018-02-06 23:09:39 +01:00
for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount && gAbsentBattlerFlags & gBitTable[gBattlerAttacker]; gBattlerAttacker++)
2017-09-17 14:10:32 +02:00
{
}
2018-02-06 23:09:39 +01:00
for (gBattlerTarget = 0; gBattlerTarget < gBattlersCount && gAbsentBattlerFlags & gBitTable[gBattlerTarget]; gBattlerTarget++)
2017-09-17 14:10:32 +02:00
{
}
do
{
2018-07-21 13:24:20 +02:00
s32 i;
2018-07-01 11:15:42 +02:00
u8 side;
2017-09-17 14:10:32 +02:00
2018-02-07 22:53:40 +01:00
switch (gBattleStruct->turnCountersTracker)
2017-09-17 14:10:32 +02:00
{
2018-07-21 12:10:08 +02:00
case ENDTURN_ORDER:
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-09-17 14:10:32 +02:00
{
2018-06-28 21:06:32 +02:00
gBattlerByTurnOrder[i] = i;
2017-09-17 14:10:32 +02:00
}
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount - 1; i++)
2017-09-17 14:10:32 +02:00
{
s32 j;
2018-02-06 02:46:59 +01:00
for (j = i + 1; j < gBattlersCount; j++)
2017-09-17 14:10:32 +02:00
{
2018-06-28 21:06:32 +02:00
if (GetWhoStrikesFirst(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], 0))
2017-10-04 19:25:14 +02:00
SwapTurnOrder(i, j);
2017-09-17 14:10:32 +02:00
}
}
2018-07-21 12:10:08 +02:00
gBattleStruct->turnCountersTracker++;
gBattleStruct->turnEffectsSide = 0;
2017-09-17 14:10:32 +02:00
// fall through
2018-07-21 12:10:08 +02:00
case ENDTURN_REFLECT:
while (gBattleStruct->turnEffectsSide < 2)
2017-09-17 14:10:32 +02:00
{
2018-07-21 12:10:08 +02:00
side = gBattleStruct->turnEffectsSide;
2018-07-01 11:15:42 +02:00
gActiveBattler = gBattlerAttacker = gSideTimers[side].reflectBattlerId;
if (gSideStatuses[side] & SIDE_STATUS_REFLECT)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
if (--gSideTimers[side].reflectTimer == 0)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
gSideStatuses[side] &= ~SIDE_STATUS_REFLECT;
2017-11-26 17:15:28 +01:00
BattleScriptExecute(BattleScript_SideStatusWoreOff);
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_REFLECT);
2017-09-17 14:10:32 +02:00
effect++;
}
}
2018-07-21 12:10:08 +02:00
gBattleStruct->turnEffectsSide++;
2017-09-17 14:10:32 +02:00
if (effect)
break;
}
if (!effect)
{
2018-02-07 22:53:40 +01:00
gBattleStruct->turnCountersTracker++;
2018-07-21 12:10:08 +02:00
gBattleStruct->turnEffectsSide = 0;
2017-09-17 14:10:32 +02:00
}
break;
2018-07-21 12:10:08 +02:00
case ENDTURN_LIGHT_SCREEN:
while (gBattleStruct->turnEffectsSide < 2)
2017-09-17 14:10:32 +02:00
{
2018-07-21 12:10:08 +02:00
side = gBattleStruct->turnEffectsSide;
2018-07-01 11:15:42 +02:00
gActiveBattler = gBattlerAttacker = gSideTimers[side].lightscreenBattlerId;
if (gSideStatuses[side] & SIDE_STATUS_LIGHTSCREEN)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
if (--gSideTimers[side].lightscreenTimer == 0)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
gSideStatuses[side] &= ~SIDE_STATUS_LIGHTSCREEN;
2017-11-26 17:15:28 +01:00
BattleScriptExecute(BattleScript_SideStatusWoreOff);
2018-07-01 11:15:42 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = side;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_LIGHT_SCREEN);
2017-09-17 14:10:32 +02:00
effect++;
}
}
2018-07-21 12:10:08 +02:00
gBattleStruct->turnEffectsSide++;
2017-09-17 14:10:32 +02:00
if (effect)
break;
}
if (!effect)
{
2018-02-07 22:53:40 +01:00
gBattleStruct->turnCountersTracker++;
2018-07-21 12:10:08 +02:00
gBattleStruct->turnEffectsSide = 0;
2017-09-17 14:10:32 +02:00
}
break;
2018-07-21 12:56:07 +02:00
case ENDTURN_AURORA_VEIL:
while (gBattleStruct->turnEffectsSide < 2)
{
side = gBattleStruct->turnEffectsSide;
gActiveBattler = gBattlerAttacker = gSideTimers[side].auroraVeilBattlerId;
if (gSideStatuses[side] & SIDE_STATUS_AURORA_VEIL)
{
if (--gSideTimers[side].auroraVeilTimer == 0)
{
gSideStatuses[side] &= ~SIDE_STATUS_AURORA_VEIL;
BattleScriptExecute(BattleScript_AuroraVeilEnds);
effect++;
}
}
gBattleStruct->turnEffectsSide++;
if (effect)
break;
}
if (!effect)
{
gBattleStruct->turnCountersTracker++;
gBattleStruct->turnEffectsSide = 0;
}
break;
2018-07-21 12:10:08 +02:00
case ENDTURN_MIST:
while (gBattleStruct->turnEffectsSide < 2)
2017-09-17 14:10:32 +02:00
{
2018-07-21 12:10:08 +02:00
side = gBattleStruct->turnEffectsSide;
2018-07-01 11:15:42 +02:00
gActiveBattler = gBattlerAttacker = gSideTimers[side].mistBattlerId;
if (gSideTimers[side].mistTimer != 0
&& --gSideTimers[side].mistTimer == 0)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
gSideStatuses[side] &= ~SIDE_STATUS_MIST;
2017-11-26 17:15:28 +01:00
BattleScriptExecute(BattleScript_SideStatusWoreOff);
2018-07-01 11:15:42 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = side;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, MOVE_MIST);
2017-09-17 14:10:32 +02:00
effect++;
}
2018-07-21 12:10:08 +02:00
gBattleStruct->turnEffectsSide++;
2017-09-17 14:10:32 +02:00
if (effect)
break;
}
if (!effect)
{
2018-02-07 22:53:40 +01:00
gBattleStruct->turnCountersTracker++;
2018-07-21 12:10:08 +02:00
gBattleStruct->turnEffectsSide = 0;
2017-09-17 14:10:32 +02:00
}
break;
2018-07-21 12:10:08 +02:00
case ENDTURN_SAFEGUARD:
while (gBattleStruct->turnEffectsSide < 2)
2017-09-17 14:10:32 +02:00
{
2018-07-21 12:10:08 +02:00
side = gBattleStruct->turnEffectsSide;
2018-07-01 11:15:42 +02:00
gActiveBattler = gBattlerAttacker = gSideTimers[side].safeguardBattlerId;
if (gSideStatuses[side] & SIDE_STATUS_SAFEGUARD)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
if (--gSideTimers[side].safeguardTimer == 0)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
gSideStatuses[side] &= ~SIDE_STATUS_SAFEGUARD;
2017-11-26 17:15:28 +01:00
BattleScriptExecute(BattleScript_SafeguardEnds);
2017-09-17 14:10:32 +02:00
effect++;
}
}
2018-07-21 12:10:08 +02:00
gBattleStruct->turnEffectsSide++;
2017-09-17 14:10:32 +02:00
if (effect)
break;
}
if (!effect)
{
2018-02-07 22:53:40 +01:00
gBattleStruct->turnCountersTracker++;
2018-07-21 12:10:08 +02:00
gBattleStruct->turnEffectsSide = 0;
2017-09-17 14:10:32 +02:00
}
break;
2018-07-21 12:56:07 +02:00
case ENDTURN_LUCKY_CHANT:
while (gBattleStruct->turnEffectsSide < 2)
{
side = gBattleStruct->turnEffectsSide;
gActiveBattler = gBattlerAttacker = gSideTimers[side].luckyChantBattlerId;
if (gSideStatuses[side] & SIDE_STATUS_LUCKY_CHANT)
{
if (--gSideTimers[side].luckyChantTimer == 0)
{
gSideStatuses[side] &= ~SIDE_STATUS_LUCKY_CHANT;
BattleScriptExecute(BattleScript_LuckyChantEnds);
effect++;
}
}
gBattleStruct->turnEffectsSide++;
if (effect)
break;
}
if (!effect)
{
gBattleStruct->turnCountersTracker++;
gBattleStruct->turnEffectsSide = 0;
}
break;
case ENDTURN_TAILWIND:
while (gBattleStruct->turnEffectsSide < 2)
{
side = gBattleStruct->turnEffectsSide;
gActiveBattler = gBattlerAttacker = gSideTimers[side].tailwindBattlerId;
if (gSideStatuses[side] & SIDE_STATUS_TAILWIND)
{
if (--gSideTimers[side].tailwindTimer == 0)
{
gSideStatuses[side] &= ~SIDE_STATUS_TAILWIND;
BattleScriptExecute(BattleScript_TailwindEnds);
effect++;
}
}
gBattleStruct->turnEffectsSide++;
if (effect)
break;
}
if (!effect)
{
gBattleStruct->turnCountersTracker++;
gBattleStruct->turnEffectsSide = 0;
}
break;
2018-07-21 12:10:08 +02:00
case ENDTURN_WISH:
while (gBattleStruct->turnEffectsSide < gBattlersCount)
2017-09-17 14:10:32 +02:00
{
2018-07-21 12:10:08 +02:00
gActiveBattler = gBattlerByTurnOrder[gBattleStruct->turnEffectsSide];
2018-02-06 02:46:59 +01:00
if (gWishFutureKnock.wishCounter[gActiveBattler] != 0
&& --gWishFutureKnock.wishCounter[gActiveBattler] == 0
&& gBattleMons[gActiveBattler].hp != 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattlerTarget = gActiveBattler;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_WishComesTrue);
2017-09-17 14:10:32 +02:00
effect++;
}
2018-07-21 12:10:08 +02:00
gBattleStruct->turnEffectsSide++;
2017-09-17 14:10:32 +02:00
if (effect)
break;
}
if (!effect)
{
2018-02-07 22:53:40 +01:00
gBattleStruct->turnCountersTracker++;
2017-09-17 14:10:32 +02:00
}
break;
2018-07-21 12:10:08 +02:00
case ENDTURN_RAIN:
2017-09-17 14:10:32 +02:00
if (gBattleWeather & WEATHER_RAIN_ANY)
{
if (!(gBattleWeather & WEATHER_RAIN_PERMANENT))
{
if (--gWishFutureKnock.weatherDuration == 0)
{
gBattleWeather &= ~WEATHER_RAIN_TEMPORARY;
gBattleWeather &= ~WEATHER_RAIN_DOWNPOUR;
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
}
else if (gBattleWeather & WEATHER_RAIN_DOWNPOUR)
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
else
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
}
else if (gBattleWeather & WEATHER_RAIN_DOWNPOUR)
2017-11-26 17:15:28 +01:00
{
2017-09-17 14:10:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
2017-11-26 17:15:28 +01:00
}
2017-09-17 14:10:32 +02:00
else
2017-11-26 17:15:28 +01:00
{
2017-09-17 14:10:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
2017-11-26 17:15:28 +01:00
}
BattleScriptExecute(BattleScript_RainContinuesOrEnds);
2017-09-17 14:10:32 +02:00
effect++;
}
2018-02-07 22:53:40 +01:00
gBattleStruct->turnCountersTracker++;
2017-09-17 14:10:32 +02:00
break;
2018-07-21 12:10:08 +02:00
case ENDTURN_SANDSTORM:
2017-09-17 14:10:32 +02:00
if (gBattleWeather & WEATHER_SANDSTORM_ANY)
{
if (!(gBattleWeather & WEATHER_SANDSTORM_PERMANENT) && --gWishFutureKnock.weatherDuration == 0)
{
gBattleWeather &= ~WEATHER_SANDSTORM_TEMPORARY;
2017-11-26 17:15:28 +01:00
gBattlescriptCurrInstr = BattleScript_SandStormHailEnds;
2017-09-17 14:10:32 +02:00
}
else
2017-11-26 17:15:28 +01:00
{
gBattlescriptCurrInstr = BattleScript_DamagingWeatherContinues;
}
2017-09-17 14:10:32 +02:00
2017-11-26 17:15:28 +01:00
gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES;
2017-09-17 14:10:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(gBattlescriptCurrInstr);
2017-09-17 14:10:32 +02:00
effect++;
}
2018-02-07 22:53:40 +01:00
gBattleStruct->turnCountersTracker++;
2017-09-17 14:10:32 +02:00
break;
2018-07-21 12:10:08 +02:00
case ENDTURN_SUN:
2017-09-17 14:10:32 +02:00
if (gBattleWeather & WEATHER_SUN_ANY)
{
if (!(gBattleWeather & WEATHER_SUN_PERMANENT) && --gWishFutureKnock.weatherDuration == 0)
{
gBattleWeather &= ~WEATHER_SUN_TEMPORARY;
2017-11-26 17:15:28 +01:00
gBattlescriptCurrInstr = BattleScript_SunlightFaded;
2017-09-17 14:10:32 +02:00
}
else
2017-11-26 17:15:28 +01:00
{
gBattlescriptCurrInstr = BattleScript_SunlightContinues;
}
2017-09-17 14:10:32 +02:00
2017-09-28 15:34:21 +02:00
BattleScriptExecute(gBattlescriptCurrInstr);
2017-09-17 14:10:32 +02:00
effect++;
}
2018-02-07 22:53:40 +01:00
gBattleStruct->turnCountersTracker++;
2017-09-17 14:10:32 +02:00
break;
2018-07-21 12:10:08 +02:00
case ENDTURN_HAIL:
if (gBattleWeather & WEATHER_HAIL_ANY)
2017-09-17 14:10:32 +02:00
{
if (!(gBattleWeather & WEATHER_HAIL_PERMANENT) && --gWishFutureKnock.weatherDuration == 0)
2017-09-17 14:10:32 +02:00
{
gBattleWeather &= ~WEATHER_HAIL_TEMPORARY;
2017-11-26 17:15:28 +01:00
gBattlescriptCurrInstr = BattleScript_SandStormHailEnds;
2017-09-17 14:10:32 +02:00
}
else
{
2017-11-26 17:15:28 +01:00
gBattlescriptCurrInstr = BattleScript_DamagingWeatherContinues;
}
2017-09-17 14:10:32 +02:00
gBattleScripting.animArg1 = B_ANIM_HAIL_CONTINUES;
2017-09-17 14:10:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(gBattlescriptCurrInstr);
2017-09-17 14:10:32 +02:00
effect++;
}
2018-02-07 22:53:40 +01:00
gBattleStruct->turnCountersTracker++;
2017-09-17 14:10:32 +02:00
break;
2018-07-21 13:24:20 +02:00
case ENDTURN_TRICK_ROOM:
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM && --gFieldTimers.trickRoomTimer == 0)
{
gFieldStatuses &= ~(STATUS_FIELD_TRICK_ROOM);
BattleScriptExecute(BattleScript_TrickRoomEnds);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;
case ENDTURN_WONDER_ROOM:
if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM && --gFieldTimers.wonderRoomTimer == 0)
{
gFieldStatuses &= ~(STATUS_FIELD_WONDER_ROOM);
BattleScriptExecute(BattleScript_WonderRoomEnds);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;
case ENDTURN_MAGIC_ROOM:
if (gFieldStatuses & STATUS_FIELD_MAGIC_ROOM && --gFieldTimers.magicRoomTimer == 0)
{
gFieldStatuses &= ~(STATUS_FIELD_MAGIC_ROOM);
BattleScriptExecute(BattleScript_MagicRoomEnds);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;
case ENDTURN_ELECTRIC_TERRAIN:
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && --gFieldTimers.electricTerrainTimer == 0)
{
gFieldStatuses &= ~(STATUS_FIELD_ELECTRIC_TERRAIN);
BattleScriptExecute(BattleScript_ElectricTerrainEnds);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;
case ENDTURN_MISTY_TERRAIN:
if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN && --gFieldTimers.mistyTerrainTimer == 0)
{
gFieldStatuses &= ~(STATUS_FIELD_MISTY_TERRAIN);
BattleScriptExecute(BattleScript_MistyTerrainEnds);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;
case ENDTURN_GRASSY_TERRAIN:
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && --gFieldTimers.grassyTerrainTimer == 0)
{
gFieldStatuses &= ~(STATUS_FIELD_GRASSY_TERRAIN);
BattleScriptExecute(BattleScript_GrassyTerrainEnds);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;
case ENDTURN_PSYCHIC_TERRAIN:
if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN && --gFieldTimers.psychicTerrainTimer == 0)
{
gFieldStatuses &= ~(STATUS_FIELD_PSYCHIC_TERRAIN);
BattleScriptExecute(BattleScript_PsychicTerrainEnds);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;
case ENDTURN_WATER_SPORT:
if (gFieldStatuses & STATUS_FIELD_WATERSPORT && --gFieldTimers.waterSportTimer == 0)
{
gFieldStatuses &= ~(STATUS_FIELD_WATERSPORT);
BattleScriptExecute(BattleScript_WaterSportEnds);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;
case ENDTURN_MUD_SPORT:
if (gFieldStatuses & STATUS_FIELD_MUDSPORT && --gFieldTimers.mudSportTimer == 0)
{
gFieldStatuses &= ~(STATUS_FIELD_MUDSPORT);
BattleScriptExecute(BattleScript_MudSportEnds);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;
case ENDTURN_GRAVITY:
if (gFieldStatuses & STATUS_FIELD_GRAVITY && --gFieldTimers.gravityTimer == 0)
{
gFieldStatuses &= ~(STATUS_FIELD_GRAVITY);
BattleScriptExecute(BattleScript_GravityEnds);
effect++;
}
gBattleStruct->turnCountersTracker++;
break;
2018-08-04 23:34:29 +02:00
case ENDTURN_ION_DELUGE:
gFieldStatuses &= ~(STATUS_FIELD_ION_DELUGE);
gBattleStruct->turnCountersTracker++;
break;
2018-07-21 12:10:08 +02:00
case ENDTURN_FIELD_COUNT:
2017-09-17 14:10:32 +02:00
effect++;
break;
}
} while (effect == 0);
2018-07-21 13:24:20 +02:00
2017-09-17 14:10:32 +02:00
return (gBattleMainFunc != BattleTurnPassed);
}
2018-07-18 22:07:48 +02:00
enum
{
ENDTURN_INGRAIN,
ENDTURN_AQUA_RING,
ENDTURN_ABILITIES,
ENDTURN_ITEMS1,
ENDTURN_LEECH_SEED,
ENDTURN_POISON,
ENDTURN_BAD_POISON,
ENDTURN_BURN,
ENDTURN_NIGHTMARES,
ENDTURN_CURSE,
ENDTURN_WRAP,
ENDTURN_UPROAR,
ENDTURN_THRASH,
ENDTURN_DISABLE,
ENDTURN_ENCORE,
ENDTURN_MAGNET_RISE,
ENDTURN_TELEKINESIS,
ENDTURN_HEALBLOCK,
ENDTURN_EMBARGO,
ENDTURN_LOCK_ON,
ENDTURN_CHARGE,
2018-07-23 21:36:05 +02:00
ENDTURN_LASER_FOCUS,
2018-07-18 22:07:48 +02:00
ENDTURN_TAUNT,
ENDTURN_YAWN,
ENDTURN_ITEMS2,
2018-07-19 21:18:20 +02:00
ENDTURN_ROOST,
ENDTURN_ELECTRIFY,
2018-07-18 22:07:48 +02:00
ENDTURN_BATTLER_COUNT
};
2017-09-17 14:10:32 +02:00
2018-07-18 22:07:48 +02:00
u8 DoBattlerEndTurnEffects(void)
2017-09-17 14:10:32 +02:00
{
2018-07-18 22:07:48 +02:00
u8 effect = FALSE;
2017-09-17 14:10:32 +02:00
gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_x20);
2018-07-18 22:07:48 +02:00
while (gBattleStruct->turnEffectsBattlerId < gBattlersCount && gBattleStruct->turnEffectsTracker <= ENDTURN_BATTLER_COUNT)
2017-09-17 14:10:32 +02:00
{
2018-06-28 21:06:32 +02:00
gActiveBattler = gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->turnEffectsBattlerId];
2018-02-06 02:46:59 +01:00
if (gAbsentBattlerFlags & gBitTable[gActiveBattler])
2017-09-17 14:10:32 +02:00
{
2018-02-07 22:53:40 +01:00
gBattleStruct->turnEffectsBattlerId++;
2017-09-17 14:10:32 +02:00
}
else
{
2018-07-22 18:40:18 +02:00
u8 ability = GetBattlerAbility(gActiveBattler);
2017-09-17 14:10:32 +02:00
switch (gBattleStruct->turnEffectsTracker)
{
2018-07-18 22:07:48 +02:00
case ENDTURN_INGRAIN: // ingrain
2018-02-06 02:46:59 +01:00
if ((gStatuses3[gActiveBattler] & STATUS3_ROOTED)
2018-07-18 22:07:48 +02:00
&& !BATTLER_MAX_HP(gActiveBattler)
&& !(gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK)
2018-02-06 02:46:59 +01:00
&& gBattleMons[gActiveBattler].hp != 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
2017-09-17 14:10:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_IngrainTurnHeal);
2017-09-17 14:10:32 +02:00
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_AQUA_RING: // aqua ring
if ((gStatuses3[gActiveBattler] & STATUS3_AQUA_RING)
&& !BATTLER_MAX_HP(gActiveBattler)
&& !(gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK)
&& gBattleMons[gActiveBattler].hp != 0)
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
BattleScriptExecute(BattleScript_AquaRingHeal);
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_ABILITIES: // end turn abilities
2018-02-06 02:46:59 +01:00
if (AbilityBattleEffects(ABILITYEFFECT_ENDTURN, gActiveBattler, 0, 0, 0))
2017-09-17 14:10:32 +02:00
effect++;
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_ITEMS1: // item effects
2018-09-01 20:00:13 +02:00
if (ItemBattleEffects(1, gActiveBattler, FALSE))
2017-09-17 14:10:32 +02:00
effect++;
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_ITEMS2: // item effects again
2018-09-01 20:00:13 +02:00
if (ItemBattleEffects(1, gActiveBattler, TRUE))
2017-09-17 14:10:32 +02:00
effect++;
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_LEECH_SEED: // leech seed
2018-02-06 02:46:59 +01:00
if ((gStatuses3[gActiveBattler] & STATUS3_LEECHSEED)
2018-07-01 11:15:42 +02:00
&& gBattleMons[gStatuses3[gActiveBattler] & STATUS3_LEECHSEED_BATTLER].hp != 0
2018-02-06 02:46:59 +01:00
&& gBattleMons[gActiveBattler].hp != 0)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
gBattlerTarget = gStatuses3[gActiveBattler] & STATUS3_LEECHSEED_BATTLER; // Notice gBattlerTarget is actually the HP receiver.
2018-02-06 02:46:59 +01:00
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
2017-09-17 14:10:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2018-02-06 23:09:39 +01:00
gBattleScripting.animArg1 = gBattlerTarget;
gBattleScripting.animArg2 = gBattlerAttacker;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_LeechSeedTurnDrain);
2017-09-17 14:10:32 +02:00
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_POISON: // poison
2018-07-22 18:40:18 +02:00
if ((gBattleMons[gActiveBattler].status1 & STATUS1_POISON)
&& gBattleMons[gActiveBattler].hp != 0
&& ability != ABILITY_MAGIC_GUARD)
2017-09-17 14:10:32 +02:00
{
2018-07-22 18:40:18 +02:00
if (ability == ABILITY_POISON_HEAL)
{
2018-07-31 23:09:47 +02:00
if (!BATTLER_MAX_HP(gActiveBattler) && !(gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK))
2018-07-22 18:40:18 +02:00
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
BattleScriptExecute(BattleScript_PoisonHealActivates);
effect++;
}
}
else
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptExecute(BattleScript_PoisonTurnDmg);
effect++;
}
2017-09-17 14:10:32 +02:00
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_BAD_POISON: // toxic poison
2018-07-22 18:40:18 +02:00
if ((gBattleMons[gActiveBattler].status1 & STATUS1_TOXIC_POISON)
&& gBattleMons[gActiveBattler].hp != 0
&& ability != ABILITY_MAGIC_GUARD)
2017-09-17 14:10:32 +02:00
{
2018-07-22 18:40:18 +02:00
if (ability == ABILITY_POISON_HEAL)
{
2018-07-31 23:09:47 +02:00
if (!BATTLER_MAX_HP(gActiveBattler) && !(gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK))
2018-07-22 18:40:18 +02:00
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
BattleScriptExecute(BattleScript_PoisonHealActivates);
effect++;
}
}
else
{
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
if ((gBattleMons[gActiveBattler].status1 & STATUS1_TOXIC_COUNTER) != STATUS1_TOXIC_COUNTER) // not 16 turns
gBattleMons[gActiveBattler].status1 += 0x100;
gBattleMoveDamage *= (gBattleMons[gActiveBattler].status1 & STATUS1_TOXIC_COUNTER) >> 8;
BattleScriptExecute(BattleScript_PoisonTurnDmg);
effect++;
}
2017-09-17 14:10:32 +02:00
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_BURN: // burn
2018-07-22 18:40:18 +02:00
if ((gBattleMons[gActiveBattler].status1 & STATUS1_BURN)
&& gBattleMons[gActiveBattler].hp != 0
&& ability != ABILITY_MAGIC_GUARD)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 8;
2017-09-17 14:10:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BurnTurnDmg);
2017-09-17 14:10:32 +02:00
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_NIGHTMARES: // spooky nightmares
2018-07-22 18:40:18 +02:00
if ((gBattleMons[gActiveBattler].status2 & STATUS2_NIGHTMARE)
&& gBattleMons[gActiveBattler].hp != 0
&& ability != ABILITY_MAGIC_GUARD)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
// R/S does not perform this sleep check, which causes the nightmare effect to
// persist even after the affected Pokemon has been awakened by Shed Skin.
2018-02-06 02:46:59 +01:00
if (gBattleMons[gActiveBattler].status1 & STATUS1_SLEEP)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 4;
2017-09-17 14:10:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_NightmareTurnDmg);
2017-09-17 14:10:32 +02:00
effect++;
}
else
{
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].status2 &= ~STATUS2_NIGHTMARE;
2017-09-17 14:10:32 +02:00
}
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_CURSE: // curse
2018-07-22 18:40:18 +02:00
if ((gBattleMons[gActiveBattler].status2 & STATUS2_CURSED)
&& gBattleMons[gActiveBattler].hp != 0
&& ability != ABILITY_MAGIC_GUARD)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 4;
2017-09-17 14:10:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_CurseTurnDmg);
2017-09-17 14:10:32 +02:00
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_WRAP: // wrap
2018-02-06 02:46:59 +01:00
if ((gBattleMons[gActiveBattler].status2 & STATUS2_WRAPPED) && gBattleMons[gActiveBattler].hp != 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].status2 -= 0x2000;
if (gBattleMons[gActiveBattler].status2 & STATUS2_WRAPPED) // damaged by wrap
2017-09-17 14:10:32 +02:00
{
// This is the only way I could get this array access to match.
2018-02-06 02:46:59 +01:00
gBattleScripting.animArg1 = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 0);
gBattleScripting.animArg2 = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 1);
gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN;
gBattleTextBuff1[1] = B_BUFF_MOVE;
2018-02-06 02:46:59 +01:00
gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 0);
gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 1);
2017-09-17 14:10:32 +02:00
gBattleTextBuff1[4] = EOS;
gBattlescriptCurrInstr = BattleScript_WrapTurnDmg;
2018-02-06 02:46:59 +01:00
gBattleMoveDamage = gBattleMons[gActiveBattler].maxHP / 16;
2017-09-17 14:10:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
}
else // broke free
{
gBattleTextBuff1[0] = B_BUFF_PLACEHOLDER_BEGIN;
gBattleTextBuff1[1] = B_BUFF_MOVE;
2018-02-06 02:46:59 +01:00
gBattleTextBuff1[2] = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 0);
gBattleTextBuff1[3] = *(gBattleStruct->wrappedMove + gActiveBattler * 2 + 1);
2017-09-17 14:10:32 +02:00
gBattleTextBuff1[4] = EOS;
gBattlescriptCurrInstr = BattleScript_WrapEnds;
}
2017-09-28 15:34:21 +02:00
BattleScriptExecute(gBattlescriptCurrInstr);
2017-09-17 14:10:32 +02:00
effect++;
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_UPROAR: // uproar
2018-02-06 02:46:59 +01:00
if (gBattleMons[gActiveBattler].status2 & STATUS2_UPROAR)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
for (gBattlerAttacker = 0; gBattlerAttacker < gBattlersCount; gBattlerAttacker++)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
&& gBattleMons[gBattlerAttacker].ability != ABILITY_SOUNDPROOF)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_SLEEP);
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE);
2017-09-17 14:10:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
2017-11-26 17:26:11 +01:00
BattleScriptExecute(BattleScript_MonWokeUpInUproar);
2018-02-06 23:09:39 +01:00
gActiveBattler = gBattlerAttacker;
2018-02-06 20:48:02 +01:00
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1);
MarkBattlerForControllerExec(gActiveBattler);
2017-09-17 14:10:32 +02:00
break;
}
}
2018-02-06 23:09:39 +01:00
if (gBattlerAttacker != gBattlersCount)
2017-09-17 14:10:32 +02:00
{
effect = 2; // a pokemon was awaken
break;
}
else
{
2018-02-06 23:09:39 +01:00
gBattlerAttacker = gActiveBattler;
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].status2 -= 0x10; // uproar timer goes down
if (WasUnableToUseMove(gActiveBattler))
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
CancelMultiTurnMoves(gActiveBattler);
2017-09-17 14:10:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
}
2018-02-06 02:46:59 +01:00
else if (gBattleMons[gActiveBattler].status2 & STATUS2_UPROAR)
2017-09-17 14:10:32 +02:00
{
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].status2 |= STATUS2_MULTIPLETURNS;
2017-09-17 14:10:32 +02:00
}
else
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
2018-02-06 02:46:59 +01:00
CancelMultiTurnMoves(gActiveBattler);
2017-09-17 14:10:32 +02:00
}
2017-11-26 17:26:11 +01:00
BattleScriptExecute(BattleScript_PrintUproarOverTurns);
2017-09-17 14:10:32 +02:00
effect = 1;
}
}
if (effect != 2)
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_THRASH: // thrash
2018-02-06 02:46:59 +01:00
if (gBattleMons[gActiveBattler].status2 & STATUS2_LOCK_CONFUSE)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].status2 -= 0x400;
if (WasUnableToUseMove(gActiveBattler))
CancelMultiTurnMoves(gActiveBattler);
else if (!(gBattleMons[gActiveBattler].status2 & STATUS2_LOCK_CONFUSE)
&& (gBattleMons[gActiveBattler].status2 & STATUS2_MULTIPLETURNS))
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gBattleMons[gActiveBattler].status2 &= ~(STATUS2_MULTIPLETURNS);
if (!(gBattleMons[gActiveBattler].status2 & STATUS2_CONFUSION))
2017-09-17 14:10:32 +02:00
{
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_CONFUSION | MOVE_EFFECT_AFFECTS_USER;
2017-09-17 14:10:32 +02:00
SetMoveEffect(1, 0);
2018-02-06 02:46:59 +01:00
if (gBattleMons[gActiveBattler].status2 & STATUS2_CONFUSION)
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_ThrashConfuses);
2017-09-17 14:10:32 +02:00
effect++;
}
}
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_DISABLE: // disable
2018-02-06 02:46:59 +01:00
if (gDisableStructs[gActiveBattler].disableTimer1 != 0)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
s32 i;
2017-09-17 14:10:32 +02:00
for (i = 0; i < 4; i++)
{
2018-02-06 02:46:59 +01:00
if (gDisableStructs[gActiveBattler].disabledMove == gBattleMons[gActiveBattler].moves[i])
2017-09-17 14:10:32 +02:00
break;
}
if (i == 4) // pokemon does not have the disabled move anymore
{
2018-02-06 02:46:59 +01:00
gDisableStructs[gActiveBattler].disabledMove = 0;
gDisableStructs[gActiveBattler].disableTimer1 = 0;
2017-09-17 14:10:32 +02:00
}
2018-02-06 02:46:59 +01:00
else if (--gDisableStructs[gActiveBattler].disableTimer1 == 0) // disable ends
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gDisableStructs[gActiveBattler].disabledMove = 0;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_DisabledNoMore);
2017-09-17 14:10:32 +02:00
effect++;
}
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_ENCORE: // encore
2018-02-06 02:46:59 +01:00
if (gDisableStructs[gActiveBattler].encoreTimer1 != 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
if (gBattleMons[gActiveBattler].moves[gDisableStructs[gActiveBattler].encoredMovePos] != gDisableStructs[gActiveBattler].encoredMove) // pokemon does not have the encored move anymore
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gDisableStructs[gActiveBattler].encoredMove = 0;
gDisableStructs[gActiveBattler].encoreTimer1 = 0;
2017-09-17 14:10:32 +02:00
}
2018-02-06 02:46:59 +01:00
else if (--gDisableStructs[gActiveBattler].encoreTimer1 == 0
|| gBattleMons[gActiveBattler].pp[gDisableStructs[gActiveBattler].encoredMovePos] == 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gDisableStructs[gActiveBattler].encoredMove = 0;
gDisableStructs[gActiveBattler].encoreTimer1 = 0;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_EncoredNoMore);
2017-09-17 14:10:32 +02:00
effect++;
}
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_LOCK_ON: // lock-on decrement
2018-02-06 02:46:59 +01:00
if (gStatuses3[gActiveBattler] & STATUS3_ALWAYS_HITS)
gStatuses3[gActiveBattler] -= 0x8;
2017-09-17 14:10:32 +02:00
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_CHARGE: // charge
2018-02-06 02:46:59 +01:00
if (gDisableStructs[gActiveBattler].chargeTimer1 && --gDisableStructs[gActiveBattler].chargeTimer1 == 0)
gStatuses3[gActiveBattler] &= ~STATUS3_CHARGED_UP;
2017-09-17 14:10:32 +02:00
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_TAUNT: // taunt
2018-02-06 02:46:59 +01:00
if (gDisableStructs[gActiveBattler].tauntTimer1)
gDisableStructs[gActiveBattler].tauntTimer1--;
2017-09-17 14:10:32 +02:00
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_YAWN: // yawn
2018-02-06 02:46:59 +01:00
if (gStatuses3[gActiveBattler] & STATUS3_YAWN)
{
gStatuses3[gActiveBattler] -= 0x800;
if (!(gStatuses3[gActiveBattler] & STATUS3_YAWN) && !(gBattleMons[gActiveBattler].status1 & STATUS1_ANY)
&& gBattleMons[gActiveBattler].ability != ABILITY_VITAL_SPIRIT
&& gBattleMons[gActiveBattler].ability != ABILITY_INSOMNIA && !UproarWakeUpCheck(gActiveBattler))
{
CancelMultiTurnMoves(gActiveBattler);
gBattleMons[gActiveBattler].status1 |= (Random() & 3) + 2;
2018-02-06 20:48:02 +01:00
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1);
MarkBattlerForControllerExec(gActiveBattler);
2018-02-08 11:17:41 +01:00
gEffectBattler = gActiveBattler;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_YawnMakesAsleep);
2017-09-17 14:10:32 +02:00
effect++;
}
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-23 21:36:05 +02:00
case ENDTURN_LASER_FOCUS:
if (gStatuses3[gActiveBattler] & STATUS3_LASER_FOCUS)
{
if (gDisableStructs[gActiveBattler].laserFocusTimer != 0)
gDisableStructs[gActiveBattler].laserFocusTimer--;
if (gDisableStructs[gActiveBattler].laserFocusTimer == 0)
gStatuses3[gActiveBattler] &= ~(STATUS3_LASER_FOCUS);
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_EMBARGO:
if (gStatuses3[gActiveBattler] & STATUS3_EMBARGO)
{
if (gDisableStructs[gActiveBattler].embargoTimer != 0)
gDisableStructs[gActiveBattler].embargoTimer--;
if (gDisableStructs[gActiveBattler].embargoTimer == 0)
{
gStatuses3[gActiveBattler] &= ~(STATUS3_EMBARGO);
BattleScriptExecute(BattleScript_EmbargoEndTurn);
effect++;
}
}
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_MAGNET_RISE:
if (gStatuses3[gActiveBattler] & STATUS3_MAGNET_RISE)
{
if (gDisableStructs[gActiveBattler].magnetRiseTimer != 0)
gDisableStructs[gActiveBattler].magnetRiseTimer--;
if (gDisableStructs[gActiveBattler].magnetRiseTimer == 0)
{
gStatuses3[gActiveBattler] &= ~(STATUS3_MAGNET_RISE);
BattleScriptExecute(BattleScript_MagnetRiseEndTurn);
effect++;
}
}
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_TELEKINESIS:
if (gStatuses3[gActiveBattler] & STATUS3_TELEKINESIS)
{
if (gDisableStructs[gActiveBattler].telekinesisTimer != 0)
gDisableStructs[gActiveBattler].telekinesisTimer--;
if (gDisableStructs[gActiveBattler].telekinesisTimer == 0)
{
gStatuses3[gActiveBattler] &= ~(STATUS3_TELEKINESIS);
BattleScriptExecute(BattleScript_TelekinesisEndTurn);
effect++;
}
}
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_HEALBLOCK:
if (gStatuses3[gActiveBattler] & STATUS3_HEAL_BLOCK)
{
if (gDisableStructs[gActiveBattler].healBlockTimer != 0)
gDisableStructs[gActiveBattler].healBlockTimer--;
if (gDisableStructs[gActiveBattler].healBlockTimer == 0)
{
gStatuses3[gActiveBattler] &= ~(STATUS3_HEAL_BLOCK);
BattleScriptExecute(BattleScript_HealBlockEndTurn);
effect++;
}
}
gBattleStruct->turnEffectsTracker++;
break;
2018-07-19 21:18:20 +02:00
case ENDTURN_ROOST: // Return flying type.
if (gBattleResources->flags->flags[gActiveBattler] & RESOURCE_FLAG_ROOST)
{
gBattleResources->flags->flags[gActiveBattler] &= ~(RESOURCE_FLAG_ROOST);
gBattleMons[gActiveBattler].type1 = gBattleStruct->roostTypes[gActiveBattler][0];
gBattleMons[gActiveBattler].type2 = gBattleStruct->roostTypes[gActiveBattler][1];
}
gBattleStruct->turnEffectsTracker++;
break;
case ENDTURN_ELECTRIFY:
gStatuses3[gActiveBattler] &= ~(STATUS3_ELECTRIFIED);
gBattleStruct->turnEffectsTracker++;
break;
2018-07-18 22:07:48 +02:00
case ENDTURN_BATTLER_COUNT: // done
2017-09-17 14:10:32 +02:00
gBattleStruct->turnEffectsTracker = 0;
2018-02-07 22:53:40 +01:00
gBattleStruct->turnEffectsBattlerId++;
2017-09-17 14:10:32 +02:00
break;
}
if (effect != 0)
return effect;
}
}
gHitMarker &= ~(HITMARKER_GRUDGE | HITMARKER_x20);
return 0;
}
2017-12-02 14:08:55 +01:00
bool8 HandleWishPerishSongOnTurnEnd(void)
2017-09-17 14:10:32 +02:00
{
gHitMarker |= (HITMARKER_GRUDGE | HITMARKER_x20);
2017-12-02 14:08:55 +01:00
switch (gBattleStruct->wishPerishSongState)
2017-09-17 14:10:32 +02:00
{
case 0:
2018-02-07 22:53:40 +01:00
while (gBattleStruct->wishPerishSongBattlerId < gBattlersCount)
2017-09-17 14:10:32 +02:00
{
2018-02-07 22:53:40 +01:00
gActiveBattler = gBattleStruct->wishPerishSongBattlerId;
2018-02-06 02:46:59 +01:00
if (gAbsentBattlerFlags & gBitTable[gActiveBattler])
2017-09-17 14:10:32 +02:00
{
2018-02-07 22:53:40 +01:00
gBattleStruct->wishPerishSongBattlerId++;
2017-09-17 14:10:32 +02:00
continue;
}
2018-02-07 22:53:40 +01:00
gBattleStruct->wishPerishSongBattlerId++;
2018-02-06 02:46:59 +01:00
if (gWishFutureKnock.futureSightCounter[gActiveBattler] != 0
&& --gWishFutureKnock.futureSightCounter[gActiveBattler] == 0
&& gBattleMons[gActiveBattler].hp != 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
if (gWishFutureKnock.futureSightMove[gActiveBattler] == MOVE_FUTURE_SIGHT)
2017-09-17 14:10:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
else
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
2018-02-06 02:46:59 +01:00
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gWishFutureKnock.futureSightMove[gActiveBattler]);
2018-02-06 23:09:39 +01:00
gBattlerTarget = gActiveBattler;
gBattlerAttacker = gWishFutureKnock.futureSightAttacker[gActiveBattler];
2018-02-06 02:46:59 +01:00
gBattleMoveDamage = gWishFutureKnock.futureSightDmg[gActiveBattler];
2018-02-07 22:53:40 +01:00
gSpecialStatuses[gBattlerTarget].dmg = 0xFFFF;
2017-11-26 17:26:11 +01:00
BattleScriptExecute(BattleScript_MonTookFutureAttack);
2017-09-17 14:10:32 +02:00
2018-02-06 02:46:59 +01:00
if (gWishFutureKnock.futureSightCounter[gActiveBattler] == 0
&& gWishFutureKnock.futureSightCounter[gActiveBattler ^ BIT_FLANK] == 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)] &= ~(SIDE_STATUS_FUTUREATTACK);
2017-09-17 14:10:32 +02:00
}
return TRUE;
2017-09-17 14:10:32 +02:00
}
}
// Why do I have to keep doing this to match?
{
2017-12-02 14:08:55 +01:00
u8 *state = &gBattleStruct->wishPerishSongState;
*state = 1;
2018-02-07 22:53:40 +01:00
gBattleStruct->wishPerishSongBattlerId = 0;
2017-09-17 14:10:32 +02:00
}
// fall through
case 1:
2018-02-07 22:53:40 +01:00
while (gBattleStruct->wishPerishSongBattlerId < gBattlersCount)
2017-09-17 14:10:32 +02:00
{
2018-06-28 21:06:32 +02:00
gActiveBattler = gBattlerAttacker = gBattlerByTurnOrder[gBattleStruct->wishPerishSongBattlerId];
2018-02-06 02:46:59 +01:00
if (gAbsentBattlerFlags & gBitTable[gActiveBattler])
2017-09-17 14:10:32 +02:00
{
2018-02-07 22:53:40 +01:00
gBattleStruct->wishPerishSongBattlerId++;
2017-09-17 14:10:32 +02:00
continue;
}
2018-02-07 22:53:40 +01:00
gBattleStruct->wishPerishSongBattlerId++;
2018-02-06 02:46:59 +01:00
if (gStatuses3[gActiveBattler] & STATUS3_PERISH_SONG)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
PREPARE_BYTE_NUMBER_BUFFER(gBattleTextBuff1, 1, gDisableStructs[gActiveBattler].perishSongTimer1);
if (gDisableStructs[gActiveBattler].perishSongTimer1 == 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 02:46:59 +01:00
gStatuses3[gActiveBattler] &= ~STATUS3_PERISH_SONG;
gBattleMoveDamage = gBattleMons[gActiveBattler].hp;
2017-11-26 17:26:11 +01:00
gBattlescriptCurrInstr = BattleScript_PerishSongTakesLife;
2017-09-17 14:10:32 +02:00
}
else
{
2018-02-06 02:46:59 +01:00
gDisableStructs[gActiveBattler].perishSongTimer1--;
2017-11-26 17:26:11 +01:00
gBattlescriptCurrInstr = BattleScript_PerishSongCountGoesDown;
2017-09-17 14:10:32 +02:00
}
2017-09-28 15:34:21 +02:00
BattleScriptExecute(gBattlescriptCurrInstr);
return TRUE;
2017-09-17 14:10:32 +02:00
}
}
// Hm...
{
2017-12-02 14:08:55 +01:00
u8 *state = &gBattleStruct->wishPerishSongState;
*state = 2;
2018-02-07 22:53:40 +01:00
gBattleStruct->wishPerishSongBattlerId = 0;
2017-09-17 14:10:32 +02:00
}
// fall through
case 2:
if ((gBattleTypeFlags & BATTLE_TYPE_ARENA)
2017-09-17 15:19:15 +02:00
&& gBattleStruct->field_DA == 2
2017-09-17 14:10:32 +02:00
&& gBattleMons[0].hp != 0 && gBattleMons[1].hp != 0)
{
s32 i;
for (i = 0; i < 2; i++)
CancelMultiTurnMoves(i);
gBattlescriptCurrInstr = BattleScript_82DB8F3;
BattleScriptExecute(BattleScript_82DB8F3);
2017-12-02 14:08:55 +01:00
gBattleStruct->wishPerishSongState++;
return TRUE;
2017-09-17 14:10:32 +02:00
}
break;
}
gHitMarker &= ~(HITMARKER_GRUDGE | HITMARKER_x20);
return FALSE;
2017-09-17 14:10:32 +02:00
}
2017-12-02 14:08:55 +01:00
#define FAINTED_ACTIONS_MAX_CASE 7
2017-09-17 14:10:32 +02:00
2017-12-02 14:08:55 +01:00
bool8 HandleFaintedMonActions(void)
2017-09-17 14:10:32 +02:00
{
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
return FALSE;
do
{
2018-07-01 11:15:42 +02:00
s32 i;
2017-12-02 14:08:55 +01:00
switch (gBattleStruct->faintedActionsState)
2017-09-17 14:10:32 +02:00
{
case 0:
2018-02-07 22:53:40 +01:00
gBattleStruct->faintedActionsBattlerId = 0;
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState++;
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
if (gAbsentBattlerFlags & gBitTable[i] && !HasNoMonsToSwitch(i, 6, 6))
2018-02-06 02:46:59 +01:00
gAbsentBattlerFlags &= ~(gBitTable[i]);
2017-09-17 14:10:32 +02:00
}
// fall through
case 1:
do
{
2018-02-08 11:17:41 +01:00
gBattlerFainted = gBattlerTarget = gBattleStruct->faintedActionsBattlerId;
2018-02-07 22:53:40 +01:00
if (gBattleMons[gBattleStruct->faintedActionsBattlerId].hp == 0
&& !(gBattleStruct->field_DF & gBitTable[gBattlerPartyIndexes[gBattleStruct->faintedActionsBattlerId]])
&& !(gAbsentBattlerFlags & gBitTable[gBattleStruct->faintedActionsBattlerId]))
2017-09-17 14:10:32 +02:00
{
2017-12-02 14:08:55 +01:00
BattleScriptExecute(BattleScript_GiveExp);
gBattleStruct->faintedActionsState = 2;
2017-09-17 14:10:32 +02:00
return TRUE;
}
2018-02-07 22:53:40 +01:00
} while (++gBattleStruct->faintedActionsBattlerId != gBattlersCount);
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState = 3;
2017-09-17 14:10:32 +02:00
break;
case 2:
2018-02-08 11:17:41 +01:00
sub_803F9EC(gBattlerFainted);
2018-02-07 22:53:40 +01:00
if (++gBattleStruct->faintedActionsBattlerId == gBattlersCount)
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState = 3;
2017-09-17 14:10:32 +02:00
else
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState = 1;
2017-09-17 14:10:32 +02:00
break;
case 3:
2018-02-07 22:53:40 +01:00
gBattleStruct->faintedActionsBattlerId = 0;
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState++;
2017-09-17 14:10:32 +02:00
// fall through
case 4:
do
{
2018-02-08 11:17:41 +01:00
gBattlerFainted = gBattlerTarget = gBattleStruct->faintedActionsBattlerId;
2018-02-07 22:53:40 +01:00
if (gBattleMons[gBattleStruct->faintedActionsBattlerId].hp == 0
&& !(gAbsentBattlerFlags & gBitTable[gBattleStruct->faintedActionsBattlerId]))
2017-09-17 14:10:32 +02:00
{
2017-12-02 14:08:55 +01:00
BattleScriptExecute(BattleScript_HandleFaintedMon);
gBattleStruct->faintedActionsState = 5;
2017-09-17 14:10:32 +02:00
return TRUE;
}
2018-02-07 22:53:40 +01:00
} while (++gBattleStruct->faintedActionsBattlerId != gBattlersCount);
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState = 6;
2017-09-17 14:10:32 +02:00
break;
case 5:
2018-02-07 22:53:40 +01:00
if (++gBattleStruct->faintedActionsBattlerId == gBattlersCount)
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState = 6;
2017-09-17 14:10:32 +02:00
else
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState = 4;
2017-09-17 14:10:32 +02:00
break;
case 6:
2018-09-01 20:00:13 +02:00
if (AbilityBattleEffects(ABILITYEFFECT_INTIMIDATE1, 0, 0, 0, 0) || AbilityBattleEffects(ABILITYEFFECT_TRACE, 0, 0, 0, 0) || ItemBattleEffects(1, 0, TRUE) || AbilityBattleEffects(ABILITYEFFECT_FORECAST, 0, 0, 0, 0))
2017-09-17 14:10:32 +02:00
return TRUE;
2017-12-02 14:08:55 +01:00
gBattleStruct->faintedActionsState++;
2017-09-17 14:10:32 +02:00
break;
2017-12-02 14:08:55 +01:00
case FAINTED_ACTIONS_MAX_CASE:
2017-09-17 14:10:32 +02:00
break;
}
2017-12-02 14:08:55 +01:00
} while (gBattleStruct->faintedActionsState != FAINTED_ACTIONS_MAX_CASE);
2017-09-17 14:10:32 +02:00
return FALSE;
}
2018-08-11 12:16:00 +02:00
void TryClearRageAndFuryCutter(void)
2017-09-17 14:10:32 +02:00
{
2018-07-01 11:15:42 +02:00
s32 i;
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
if ((gBattleMons[i].status2 & STATUS2_RAGE) && gChosenMoveByBattler[i] != MOVE_RAGE)
2017-09-17 14:10:32 +02:00
gBattleMons[i].status2 &= ~(STATUS2_RAGE);
2018-08-11 12:16:00 +02:00
if (gDisableStructs[i].furyCutterCounter != 0 && gChosenMoveByBattler[i] != MOVE_FURY_CUTTER)
gDisableStructs[i].furyCutterCounter = 0;
2017-09-17 14:10:32 +02:00
}
}
enum
{
CANCELLER_FLAGS,
CANCELLER_ASLEEP,
CANCELLER_FROZEN,
CANCELLER_TRUANT,
CANCELLER_RECHARGE,
CANCELLER_FLINCH,
CANCELLER_DISABLED,
CANCELLER_GRAVITY,
CANCELLER_HEAL_BLOCKED,
CANCELLER_TAUNTED,
CANCELLER_IMPRISONED,
CANCELLER_CONFUSED,
CANCELLER_PARALYSED,
CANCELLER_IN_LOVE,
CANCELLER_BIDE,
CANCELLER_THAW,
CANCELLER_END,
};
2017-09-17 14:10:32 +02:00
u8 AtkCanceller_UnableToUseMove(void)
{
u8 effect = 0;
2017-12-03 00:47:21 +01:00
s32 *bideDmg = &gBattleScripting.bideDmg;
2017-09-17 14:10:32 +02:00
do
{
switch (gBattleStruct->atkCancellerTracker)
{
case CANCELLER_FLAGS: // flags clear
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_DESTINY_BOND);
gStatuses3[gBattlerAttacker] &= ~(STATUS3_GRUDGE);
2017-09-17 14:10:32 +02:00
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_ASLEEP: // check being asleep
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
if (UproarWakeUpCheck(gBattlerAttacker))
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_SLEEP);
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 14:10:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp;
effect = 2;
}
else
{
u8 toSub;
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].ability == ABILITY_EARLY_BIRD)
2017-09-17 14:10:32 +02:00
toSub = 2;
else
toSub = 1;
2018-02-06 23:09:39 +01:00
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP) < toSub)
gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_SLEEP);
2017-09-17 14:10:32 +02:00
else
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status1 -= toSub;
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP)
2017-09-17 14:10:32 +02:00
{
if (gCurrentMove != MOVE_SNORE && gCurrentMove != MOVE_SLEEP_TALK)
{
gBattlescriptCurrInstr = BattleScript_MoveUsedIsAsleep;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 2;
}
}
else
{
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_NIGHTMARE);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 14:10:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
gBattlescriptCurrInstr = BattleScript_MoveUsedWokeUp;
effect = 2;
}
}
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_FROZEN: // check being frozen
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE)
2017-09-17 14:10:32 +02:00
{
if (Random() % 5)
{
if (gBattleMoves[gCurrentMove].effect != EFFECT_THAW_HIT) // unfreezing via a move effect happens in case 13
{
gBattlescriptCurrInstr = BattleScript_MoveUsedIsFrozen;
gHitMarker |= HITMARKER_NO_ATTACKSTRING;
}
else
{
gBattleStruct->atkCancellerTracker++;
break;
}
}
else // unfreeze
{
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_FREEZE);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze;
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
}
effect = 2;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_TRUANT: // truant
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].ability == ABILITY_TRUANT && gDisableStructs[gBattlerAttacker].truantCounter)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
CancelMultiTurnMoves(gBattlerAttacker);
2017-09-17 14:10:32 +02:00
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
2018-01-16 22:12:38 +01:00
gMoveResultFlags |= MOVE_RESULT_MISSED;
2017-09-17 14:10:32 +02:00
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_RECHARGE: // recharge
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_RECHARGE)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_RECHARGE);
gDisableStructs[gBattlerAttacker].rechargeCounter = 0;
CancelMultiTurnMoves(gBattlerAttacker);
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_MoveUsedMustRecharge;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_FLINCH: // flinch
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_FLINCHED)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_FLINCHED);
gProtectStructs[gBattlerAttacker].flinchImmobility = 1;
CancelMultiTurnMoves(gBattlerAttacker);
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_MoveUsedFlinched;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_DISABLED: // disabled move
2018-02-06 23:09:39 +01:00
if (gDisableStructs[gBattlerAttacker].disabledMove == gCurrentMove && gDisableStructs[gBattlerAttacker].disabledMove != 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gProtectStructs[gBattlerAttacker].usedDisabledMove = 1;
gBattleScripting.battler = gBattlerAttacker;
CancelMultiTurnMoves(gBattlerAttacker);
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_MoveUsedIsDisabled;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_HEAL_BLOCKED:
if (gStatuses3[gBattlerAttacker] & STATUS3_HEAL_BLOCK && IsHealBlockPreventingMove(gBattlerAttacker, gCurrentMove))
{
gProtectStructs[gBattlerAttacker].usedHealBlockedMove = 1;
gBattleScripting.battler = gBattlerAttacker;
CancelMultiTurnMoves(gBattlerAttacker);
gBattlescriptCurrInstr = BattleScript_MoveUsedHealBlockPrevents;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_GRAVITY:
if (gFieldStatuses & STATUS_FIELD_GRAVITY && IsGravityPreventingMove(gCurrentMove))
{
gProtectStructs[gBattlerAttacker].usedGravityPreventedMove = 1;
gBattleScripting.battler = gBattlerAttacker;
CancelMultiTurnMoves(gBattlerAttacker);
gBattlescriptCurrInstr = BattleScript_MoveUsedGravityPrevents;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_TAUNTED: // taunt
2018-02-06 23:09:39 +01:00
if (gDisableStructs[gBattlerAttacker].tauntTimer1 && gBattleMoves[gCurrentMove].power == 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gProtectStructs[gBattlerAttacker].usedTauntedMove = 1;
CancelMultiTurnMoves(gBattlerAttacker);
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_MoveUsedIsTaunted;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_IMPRISONED: // imprisoned
2018-02-06 23:09:39 +01:00
if (GetImprisonedMovesCount(gBattlerAttacker, gCurrentMove))
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gProtectStructs[gBattlerAttacker].usedImprisionedMove = 1;
CancelMultiTurnMoves(gBattlerAttacker);
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_MoveUsedIsImprisoned;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_CONFUSED: // confusion
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status2--;
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_CONFUSION)
2017-09-17 14:10:32 +02:00
{
if (Random() & 1)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 14:10:32 +02:00
}
else // confusion dmg
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
2018-02-06 23:09:39 +01:00
gBattlerTarget = gBattlerAttacker;
2018-07-14 22:56:03 +02:00
gBattleMoveDamage = CalculateMoveDamage(MOVE_NONE, gBattlerAttacker, gBattlerAttacker, TYPE_MYSTERY, 40, FALSE, FALSE);
2018-02-06 23:09:39 +01:00
gProtectStructs[gBattlerAttacker].confusionSelfDmg = 1;
2017-09-17 14:10:32 +02:00
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
}
gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfused;
}
else // snapped out of confusion
{
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_MoveUsedIsConfusedNoMore;
}
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_PARALYSED: // paralysis
2018-02-06 23:09:39 +01:00
if ((gBattleMons[gBattlerAttacker].status1 & STATUS1_PARALYSIS) && (Random() % 4) == 0)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gProtectStructs[gBattlerAttacker].prlzImmobility = 1;
2017-09-17 14:10:32 +02:00
// This is removed in Emerald for some reason
2018-02-06 23:09:39 +01:00
//CancelMultiTurnMoves(gBattlerAttacker);
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_MoveUsedIsParalyzed;
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_IN_LOVE: // infatuation
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattleScripting.battler = CountTrailingZeroBits((gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION) >> 0x10);
2017-09-17 14:10:32 +02:00
if (Random() & 1)
2018-07-01 11:15:42 +02:00
{
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2018-07-01 11:15:42 +02:00
}
2017-09-17 14:10:32 +02:00
else
{
2017-09-22 21:33:49 +02:00
BattleScriptPush(BattleScript_MoveUsedIsParalyzedCantAttack);
2017-09-17 14:10:32 +02:00
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
2018-02-06 23:09:39 +01:00
gProtectStructs[gBattlerAttacker].loveImmobility = 1;
CancelMultiTurnMoves(gBattlerAttacker);
2017-09-17 14:10:32 +02:00
}
gBattlescriptCurrInstr = BattleScript_MoveUsedIsInLove;
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_BIDE: // bide
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_BIDE)
2017-09-17 14:10:32 +02:00
{
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status2 -= 0x100;
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_BIDE)
2018-07-01 11:15:42 +02:00
{
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_BideStoringEnergy;
2018-07-01 11:15:42 +02:00
}
2017-09-17 14:10:32 +02:00
else
{
// This is removed in Emerald for some reason
2018-02-06 23:09:39 +01:00
//gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_MULTIPLETURNS);
if (gTakenDmg[gBattlerAttacker])
2017-09-17 14:10:32 +02:00
{
gCurrentMove = MOVE_BIDE;
2018-02-06 23:09:39 +01:00
*bideDmg = gTakenDmg[gBattlerAttacker] * 2;
2018-02-07 22:53:40 +01:00
gBattlerTarget = gTakenDmgByBattler[gBattlerAttacker];
2018-02-06 23:09:39 +01:00
if (gAbsentBattlerFlags & gBitTable[gBattlerTarget])
gBattlerTarget = GetMoveTarget(MOVE_BIDE, 1);
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_BideAttack;
}
else
2018-07-01 11:15:42 +02:00
{
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_BideNoEnergyToAttack;
2018-07-01 11:15:42 +02:00
}
2017-09-17 14:10:32 +02:00
}
effect = 1;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_THAW: // move thawing
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_FREEZE)
2017-09-17 14:10:32 +02:00
{
if (gBattleMoves[gCurrentMove].effect == EFFECT_THAW_HIT)
{
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status1 &= ~(STATUS1_FREEZE);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 14:10:32 +02:00
gBattlescriptCurrInstr = BattleScript_MoveUsedUnfroze;
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
}
effect = 2;
}
gBattleStruct->atkCancellerTracker++;
break;
case CANCELLER_END:
2017-09-17 14:10:32 +02:00
break;
}
} while (gBattleStruct->atkCancellerTracker != CANCELLER_END && effect == 0);
2017-09-17 14:10:32 +02:00
if (effect == 2)
{
2018-02-06 23:09:39 +01:00
gActiveBattler = gBattlerAttacker;
2018-02-06 20:48:02 +01:00
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1);
MarkBattlerForControllerExec(gActiveBattler);
2017-09-17 14:10:32 +02:00
}
return effect;
}
2017-09-17 15:19:15 +02:00
2018-07-01 11:15:42 +02:00
bool8 HasNoMonsToSwitch(u8 battler, u8 partyIdBattlerOn1, u8 partyIdBattlerOn2)
2017-09-17 15:19:15 +02:00
{
2018-07-01 11:15:42 +02:00
struct Pokemon *party;
u8 id1, id2;
2017-09-17 15:19:15 +02:00
s32 i;
2018-07-01 11:15:42 +02:00
2017-09-17 15:19:15 +02:00
if (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE))
return FALSE;
2018-07-01 11:15:42 +02:00
2017-09-17 15:19:15 +02:00
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
{
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
2017-09-17 15:19:15 +02:00
party = gPlayerParty;
else
party = gEnemyParty;
2018-07-01 11:15:42 +02:00
id1 = ((battler & BIT_FLANK) / 2);
for (i = id1 * 3; i < id1 * 3 + 3; i++)
2017-09-17 15:19:15 +02:00
{
if (GetMonData(&party[i], MON_DATA_HP) != 0
2018-07-01 11:15:42 +02:00
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE
2017-09-17 15:19:15 +02:00
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG)
break;
}
2018-07-01 11:15:42 +02:00
return (i == id1 * 3 + 3);
2017-09-17 15:19:15 +02:00
}
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
{
if (gBattleTypeFlags & BATTLE_TYPE_x800000)
{
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
2017-09-17 15:19:15 +02:00
{
party = gPlayerParty;
2018-07-01 11:15:42 +02:00
id2 = GetBattlerMultiplayerId(battler);
id1 = GetLinkTrainerFlankId(id2);
2017-09-17 15:19:15 +02:00
}
else
{
2018-07-01 11:15:42 +02:00
// FIXME: Compiler insists on moving r4 into r1 before doing the eor.
2017-09-17 15:19:15 +02:00
#ifndef NONMATCHING
2018-07-01 11:15:42 +02:00
register u32 var asm("r1");
2017-09-17 15:19:15 +02:00
#else
2018-07-01 11:15:42 +02:00
u32 var;
2017-09-17 15:19:15 +02:00
#endif // NONMATCHING
party = gEnemyParty;
2018-07-01 11:15:42 +02:00
var = battler ^ BIT_SIDE;
if (var == 0)
id1 = 0;
else
id1 = 1;
2017-09-17 15:19:15 +02:00
}
}
else
{
2018-07-01 11:15:42 +02:00
id2 = GetBattlerMultiplayerId(battler);
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(battler) == B_SIDE_PLAYER)
2017-09-17 15:19:15 +02:00
party = gPlayerParty;
else
party = gEnemyParty;
2018-07-01 11:15:42 +02:00
id1 = GetLinkTrainerFlankId(id2);
2017-09-17 15:19:15 +02:00
}
2018-07-01 11:15:42 +02:00
for (i = id1 * 3; i < id1 * 3 + 3; i++)
2017-09-17 15:19:15 +02:00
{
if (GetMonData(&party[i], MON_DATA_HP) != 0
2018-07-01 11:15:42 +02:00
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE
2017-09-17 15:19:15 +02:00
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG)
break;
}
2018-07-01 11:15:42 +02:00
return (i == id1 * 3 + 3);
2017-09-17 15:19:15 +02:00
}
2018-02-06 02:46:59 +01:00
else if ((gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS) && GetBattlerSide(battler) == B_SIDE_OPPONENT)
2017-09-17 15:19:15 +02:00
{
party = gEnemyParty;
2018-02-06 02:46:59 +01:00
if (battler == 1)
2018-07-01 11:15:42 +02:00
id1 = 0;
2017-09-17 15:19:15 +02:00
else
2018-07-01 11:15:42 +02:00
id1 = 3;
for (i = id1; i < id1 + 3; i++)
2017-09-17 15:19:15 +02:00
{
if (GetMonData(&party[i], MON_DATA_HP) != 0
2018-07-01 11:15:42 +02:00
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE
2017-09-17 15:19:15 +02:00
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG)
break;
}
2018-07-01 11:15:42 +02:00
return (i == id1 + 3);
2017-09-17 15:19:15 +02:00
}
else
{
2018-02-06 02:46:59 +01:00
if (GetBattlerSide(battler) == B_SIDE_OPPONENT)
2017-09-17 15:19:15 +02:00
{
2018-07-01 11:15:42 +02:00
id2 = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
id1 = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
2017-09-17 15:19:15 +02:00
party = gEnemyParty;
}
else
{
2018-07-01 11:15:42 +02:00
id2 = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
id1 = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
2017-09-17 15:19:15 +02:00
party = gPlayerParty;
}
2018-07-01 11:15:42 +02:00
if (partyIdBattlerOn1 == PARTY_SIZE)
partyIdBattlerOn1 = gBattlerPartyIndexes[id2];
if (partyIdBattlerOn2 == PARTY_SIZE)
partyIdBattlerOn2 = gBattlerPartyIndexes[id1];
for (i = 0; i < PARTY_SIZE; i++)
2017-09-17 15:19:15 +02:00
{
if (GetMonData(&party[i], MON_DATA_HP) != 0
2018-07-01 11:15:42 +02:00
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_NONE
2017-09-17 15:19:15 +02:00
&& GetMonData(&party[i], MON_DATA_SPECIES2) != SPECIES_EGG
2018-07-01 11:15:42 +02:00
&& i != partyIdBattlerOn1 && i != partyIdBattlerOn2
&& i != *(gBattleStruct->monToSwitchIntoId + id2) && i != id1[gBattleStruct->monToSwitchIntoId])
2017-09-17 15:19:15 +02:00
break;
}
2018-07-01 11:15:42 +02:00
return (i == PARTY_SIZE);
2017-09-17 15:19:15 +02:00
}
}
enum
{
CASTFORM_NO_CHANGE, //0
CASTFORM_TO_NORMAL, //1
CASTFORM_TO_FIRE, //2
CASTFORM_TO_WATER, //3
CASTFORM_TO_ICE, //4
};
2018-02-06 02:46:59 +01:00
u8 CastformDataTypeChange(u8 battler)
2017-09-17 15:19:15 +02:00
{
u8 formChange = 0;
2018-02-06 02:46:59 +01:00
if (gBattleMons[battler].species != SPECIES_CASTFORM || gBattleMons[battler].ability != ABILITY_FORECAST || gBattleMons[battler].hp == 0)
2017-09-17 15:19:15 +02:00
return CASTFORM_NO_CHANGE;
2018-03-01 00:59:52 +01:00
if (!WEATHER_HAS_EFFECT && !IS_BATTLER_OF_TYPE(battler, TYPE_NORMAL))
2017-09-17 15:19:15 +02:00
{
2018-03-01 00:59:52 +01:00
SET_BATTLER_TYPE(battler, TYPE_NORMAL);
2017-09-17 15:19:15 +02:00
return CASTFORM_TO_NORMAL;
}
if (!WEATHER_HAS_EFFECT)
return CASTFORM_NO_CHANGE;
2018-03-01 00:59:52 +01:00
if (!(gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_SUN_ANY | WEATHER_HAIL_ANY)) && !IS_BATTLER_OF_TYPE(battler, TYPE_NORMAL))
2017-09-17 15:19:15 +02:00
{
2018-03-01 00:59:52 +01:00
SET_BATTLER_TYPE(battler, TYPE_NORMAL);
2017-09-17 15:19:15 +02:00
formChange = CASTFORM_TO_NORMAL;
}
2018-03-01 00:59:52 +01:00
if (gBattleWeather & WEATHER_SUN_ANY && !IS_BATTLER_OF_TYPE(battler, TYPE_FIRE))
2017-09-17 15:19:15 +02:00
{
2018-03-01 00:59:52 +01:00
SET_BATTLER_TYPE(battler, TYPE_FIRE);
2017-09-17 15:19:15 +02:00
formChange = CASTFORM_TO_FIRE;
}
2018-03-01 00:59:52 +01:00
if (gBattleWeather & WEATHER_RAIN_ANY && !IS_BATTLER_OF_TYPE(battler, TYPE_WATER))
2017-09-17 15:19:15 +02:00
{
2018-03-01 00:59:52 +01:00
SET_BATTLER_TYPE(battler, TYPE_WATER);
2017-09-17 15:19:15 +02:00
formChange = CASTFORM_TO_WATER;
}
2018-03-01 00:59:52 +01:00
if (gBattleWeather & WEATHER_HAIL_ANY && !IS_BATTLER_OF_TYPE(battler, TYPE_ICE))
2017-09-17 15:19:15 +02:00
{
2018-03-01 00:59:52 +01:00
SET_BATTLER_TYPE(battler, TYPE_ICE);
2017-09-17 15:19:15 +02:00
formChange = CASTFORM_TO_ICE;
}
return formChange;
}
static const u16 sWeatherFlagsInfo[][3] =
{
[ENUM_WEATHER_RAIN] = {WEATHER_RAIN_TEMPORARY, WEATHER_RAIN_PERMANENT, HOLD_EFFECT_DAMP_ROCK},
[ENUM_WEATHER_SUN] = {WEATHER_SUN_TEMPORARY, WEATHER_SUN_PERMANENT, HOLD_EFFECT_HEAT_ROCK},
[ENUM_WEATHER_SANDSTORM] = {WEATHER_SANDSTORM_TEMPORARY, WEATHER_SANDSTORM_PERMANENT, HOLD_EFFECT_SMOOTH_ROCK},
[ENUM_WEATHER_HAIL] = {WEATHER_HAIL_TEMPORARY, WEATHER_HAIL_PERMANENT, HOLD_EFFECT_ICY_ROCK},
};
bool32 TryChangeBattleWeather(u8 battler, u32 weatherEnumId, bool32 viaAbility)
{
if (viaAbility && B_ABILITY_WEATHER <= GEN_5
&& !(gBattleWeather & sWeatherFlagsInfo[weatherEnumId][1]))
{
gBattleWeather = (sWeatherFlagsInfo[weatherEnumId][0] | sWeatherFlagsInfo[weatherEnumId][1]);
return TRUE;
}
else if (B_ABILITY_WEATHER > GEN_5
&& !(gBattleWeather & (sWeatherFlagsInfo[weatherEnumId][0] | sWeatherFlagsInfo[weatherEnumId][1])))
{
gBattleWeather = (sWeatherFlagsInfo[weatherEnumId][0]);
if (GetBattlerHoldEffect(battler, TRUE) == sWeatherFlagsInfo[weatherEnumId][2])
gWishFutureKnock.weatherDuration = 8;
else
gWishFutureKnock.weatherDuration = 5;
return TRUE;
}
else
{
return FALSE;
}
}
2018-02-06 02:46:59 +01:00
u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveArg)
2017-09-17 15:19:15 +02:00
{
u8 effect = 0;
2018-07-22 18:40:18 +02:00
u32 speciesAtk, speciesDef;
u32 pidAtk, pidDef;
u32 moveType;
u32 i;
u32 move;
u8 side;
u8 target1;
if (gBattleTypeFlags & BATTLE_TYPE_SAFARI)
return;
2017-09-17 15:19:15 +02:00
2018-02-06 23:09:39 +01:00
if (gBattlerAttacker >= gBattlersCount)
gBattlerAttacker = battler;
2018-07-01 11:15:42 +02:00
2018-07-22 18:40:18 +02:00
speciesAtk = gBattleMons[gBattlerAttacker].species;
pidAtk = gBattleMons[gBattlerAttacker].personality;
2017-09-17 15:19:15 +02:00
2018-07-22 18:40:18 +02:00
speciesDef = gBattleMons[gBattlerTarget].species;
pidDef = gBattleMons[gBattlerTarget].personality;
2018-07-01 11:15:42 +02:00
2018-07-22 18:40:18 +02:00
gLastUsedAbility = GetBattlerAbility(battler);
2017-09-17 15:19:15 +02:00
2018-07-22 18:40:18 +02:00
if (moveArg)
move = moveArg;
else
move = gCurrentMove;
2017-09-17 15:19:15 +02:00
2018-07-22 18:40:18 +02:00
GET_MOVE_TYPE(move, moveType);
2017-09-17 15:19:15 +02:00
2018-07-22 18:40:18 +02:00
switch (caseID)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
case ABILITYEFFECT_ON_SWITCHIN: // 0
switch (gLastUsedAbility)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
case ABILITYEFFECT_SWITCH_IN_WEATHER:
if (!(gBattleTypeFlags & BATTLE_TYPE_RECORDED))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
switch (weather_get_current())
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
case 3:
case 5:
case 13:
if (!(gBattleWeather & WEATHER_RAIN_ANY))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gBattleWeather = (WEATHER_RAIN_TEMPORARY | WEATHER_RAIN_PERMANENT);
gBattleScripting.animArg1 = B_ANIM_RAIN_CONTINUES;
gBattleScripting.battler = battler;
2017-09-17 15:19:15 +02:00
effect++;
}
break;
2018-07-22 18:40:18 +02:00
case 8:
if (!(gBattleWeather & WEATHER_SANDSTORM_ANY))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gBattleWeather = (WEATHER_SANDSTORM_PERMANENT | WEATHER_SANDSTORM_TEMPORARY);
gBattleScripting.animArg1 = B_ANIM_SANDSTORM_CONTINUES;
gBattleScripting.battler = battler;
2017-09-17 15:19:15 +02:00
effect++;
}
break;
2018-07-22 18:40:18 +02:00
case 12:
if (!(gBattleWeather & WEATHER_SUN_ANY))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gBattleWeather = (WEATHER_SUN_PERMANENT | WEATHER_SUN_TEMPORARY);
gBattleScripting.animArg1 = B_ANIM_SUN_CONTINUES;
2018-02-06 02:46:59 +01:00
gBattleScripting.battler = battler;
2017-09-17 15:19:15 +02:00
effect++;
}
break;
}
}
2018-07-22 18:40:18 +02:00
if (effect)
{
gBattleCommunication[MULTISTRING_CHOOSER] = weather_get_current();
BattleScriptPushCursorAndCallback(BattleScript_OverworldWeatherStarts);
}
2017-09-17 15:19:15 +02:00
break;
2018-07-29 12:21:28 +02:00
case ABILITY_IMPOSTER:
if (IsBattlerAlive(BATTLE_OPPOSITE(battler))
&& !(gBattleMons[BATTLE_OPPOSITE(battler)].status2 & (STATUS2_TRANSFORMED | STATUS2_SUBSTITUTE))
&& !(gBattleMons[battler].status2 & STATUS2_TRANSFORMED))
{
gBattlerTarget = BATTLE_OPPOSITE(battler);
BattleScriptPushCursorAndCallback(BattleScript_ImposterActivates);
effect++;
}
break;
2018-07-22 22:21:47 +02:00
case ABILITY_MOLD_BREAKER:
if (!gSpecialStatuses[battler].switchInAbilityDone)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
gSpecialStatuses[battler].switchInAbilityDone = 1;
BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg);
effect++;
}
break;
case ABILITY_TERAVOLT:
if (!gSpecialStatuses[battler].switchInAbilityDone)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
gSpecialStatuses[battler].switchInAbilityDone = 1;
BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg);
effect++;
}
break;
case ABILITY_TURBOBLAZE:
if (!gSpecialStatuses[battler].switchInAbilityDone)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 2;
gSpecialStatuses[battler].switchInAbilityDone = 1;
BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg);
effect++;
}
break;
case ABILITY_SLOW_START:
if (!gSpecialStatuses[battler].switchInAbilityDone)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 3;
gSpecialStatuses[battler].switchInAbilityDone = 1;
BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg);
effect++;
}
break;
case ABILITY_UNNERVE:
if (!gSpecialStatuses[battler].switchInAbilityDone)
{
gBattleCommunication[MULTISTRING_CHOOSER] = 4;
gSpecialStatuses[battler].switchInAbilityDone = 1;
BattleScriptPushCursorAndCallback(BattleScript_SwitchInAbilityMsg);
effect++;
}
break;
2018-07-22 18:40:18 +02:00
case ABILITY_DOWNLOAD:
2018-07-22 22:21:47 +02:00
if (!gSpecialStatuses[battler].switchInAbilityDone)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
u8 statId;
u32 opposingBattler = BATTLE_OPPOSITE(battler);
u32 opposingDef = gBattleMons[opposingBattler].defense
* gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_DEF]][0]
/ gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_DEF]][1];
u32 opposingSpDef = gBattleMons[opposingBattler].spDefense
* gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_SPDEF]][0]
/ gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_SPDEF]][1];
opposingBattler = BATTLE_PARTNER(opposingBattler);
if (IsBattlerAlive(opposingBattler))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
opposingDef += gBattleMons[opposingBattler].defense
* gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_DEF]][0]
/ gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_DEF]][1];
opposingSpDef += gBattleMons[opposingBattler].spDefense
* gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_SPDEF]][0]
/ gStatStageRatios[gBattleMons[opposingBattler].statStages[STAT_SPDEF]][1];
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
if (opposingSpDef > opposingDef)
statId = STAT_SPATK;
else
statId = STAT_ATK;
2018-07-22 22:21:47 +02:00
gSpecialStatuses[battler].switchInAbilityDone = 1;
2018-07-22 18:40:18 +02:00
if (gBattleMons[battler].statStages[statId] != 0xC)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gBattleMons[battler].statStages[statId]++;
SET_STATCHANGER(statId, 1, FALSE);
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
BattleScriptPushCursorAndCallback(BattleScript_AttackerAbilityStatRaiseEnd3);
effect++;
2017-09-17 15:19:15 +02:00
}
}
break;
2018-07-22 18:40:18 +02:00
case ABILITY_DRIZZLE:
if (TryChangeBattleWeather(battler, ENUM_WEATHER_RAIN, TRUE))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates);
gBattleScripting.battler = battler;
effect++;
}
break;
case ABILITY_SAND_STREAM:
if (TryChangeBattleWeather(battler, ENUM_WEATHER_SANDSTORM, TRUE))
2018-07-22 18:40:18 +02:00
{
BattleScriptPushCursorAndCallback(BattleScript_DrizzleActivates);
2018-07-22 18:40:18 +02:00
gBattleScripting.battler = battler;
effect++;
}
break;
case ABILITY_DROUGHT:
if (TryChangeBattleWeather(battler, ENUM_WEATHER_SUN, TRUE))
2018-07-22 18:40:18 +02:00
{
BattleScriptPushCursorAndCallback(BattleScript_DroughtActivates);
gBattleScripting.battler = battler;
effect++;
}
break;
case ABILITY_SNOW_WARNING:
if (TryChangeBattleWeather(battler, ENUM_WEATHER_HAIL, TRUE))
{
BattleScriptPushCursorAndCallback(BattleScript_SnowWarningActivates);
gBattleScripting.battler = battler;
effect++;
}
break;
2018-07-22 18:40:18 +02:00
case ABILITY_INTIMIDATE:
if (!(gSpecialStatuses[battler].intimidatedMon))
{
gStatuses3[battler] |= STATUS3_INTIMIDATE_POKES;
gSpecialStatuses[battler].intimidatedMon = 1;
}
break;
case ABILITY_FORECAST:
effect = CastformDataTypeChange(battler);
if (effect != 0)
{
BattleScriptPushCursorAndCallback(BattleScript_CastformChange);
gBattleScripting.battler = battler;
*(&gBattleStruct->formToChangeInto) = effect - 1;
}
break;
case ABILITY_TRACE:
if (!(gSpecialStatuses[battler].traced))
{
gStatuses3[battler] |= STATUS3_TRACE;
gSpecialStatuses[battler].traced = 1;
}
break;
case ABILITY_CLOUD_NINE:
case ABILITY_AIR_LOCK:
2018-07-22 22:21:47 +02:00
// that's a weird choice for a variable, why not use i or battler?
for (target1 = 0; target1 < gBattlersCount; target1++)
2018-07-22 18:40:18 +02:00
{
2018-07-22 22:21:47 +02:00
effect = CastformDataTypeChange(target1);
if (effect != 0)
2017-09-17 15:19:15 +02:00
{
2018-07-22 22:21:47 +02:00
BattleScriptPushCursorAndCallback(BattleScript_CastformChange);
gBattleScripting.battler = target1;
*(&gBattleStruct->formToChangeInto) = effect - 1;
break;
2017-09-17 15:19:15 +02:00
}
}
break;
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_ENDTURN: // 1
if (gBattleMons[battler].hp != 0)
{
gBattlerAttacker = battler;
2017-09-17 15:19:15 +02:00
switch (gLastUsedAbility)
{
2018-07-28 17:13:47 +02:00
case ABILITY_HARVEST:
if (((WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY) || Random() % 2 == 0)
&& gBattleMons[battler].item == ITEM_NONE
&& gBattleStruct->changedItems[battler] == ITEM_NONE
&& ItemId_GetPocket(gBattleStruct->usedHeldItems[battler]) == POCKET_BERRIES)
{
gLastUsedItem = gBattleStruct->changedItems[battler] = gBattleStruct->usedHeldItems[battler];
gBattleStruct->usedHeldItems[battler] = ITEM_NONE;
BattleScriptPushCursorAndCallback(BattleScript_HarvestActivates);
effect++;
}
break;
2018-07-22 18:40:18 +02:00
case ABILITY_RAIN_DISH:
2018-07-22 19:34:13 +02:00
if (WEATHER_HAS_EFFECT
&& (gBattleWeather & WEATHER_RAIN_ANY)
2018-07-31 23:09:47 +02:00
&& !BATTLER_MAX_HP(battler)
&& !(gStatuses3[battler] & STATUS3_HEAL_BLOCK))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
BattleScriptPushCursorAndCallback(BattleScript_RainDishActivates);
gBattleMoveDamage = gBattleMons[battler].maxHP / 16;
2017-09-17 15:19:15 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2018-07-22 18:40:18 +02:00
gBattleMoveDamage *= -1;
2017-09-17 15:19:15 +02:00
effect++;
}
break;
2018-07-22 19:34:13 +02:00
case ABILITY_HYDRATION:
if (WEATHER_HAS_EFFECT
&& (gBattleWeather & WEATHER_RAIN_ANY)
&& gBattleMons[battler].status1 & STATUS1_ANY)
{
goto ABILITY_HEAL_MON_STATUS;
}
break;
2018-07-22 18:40:18 +02:00
case ABILITY_SHED_SKIN:
if ((gBattleMons[battler].status1 & STATUS1_ANY) && (Random() % 3) == 0)
{
2018-07-22 19:34:13 +02:00
ABILITY_HEAL_MON_STATUS:
2018-07-22 18:40:18 +02:00
if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON))
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
if (gBattleMons[battler].status1 & STATUS1_PARALYSIS)
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
if (gBattleMons[battler].status1 & STATUS1_BURN)
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
if (gBattleMons[battler].status1 & STATUS1_FREEZE)
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
2018-07-22 19:34:13 +02:00
2018-07-22 18:40:18 +02:00
gBattleMons[battler].status1 = 0;
2018-07-22 19:34:13 +02:00
gBattleMons[battler].status2 &= ~(STATUS2_NIGHTMARE);
2018-07-22 18:40:18 +02:00
gBattleScripting.battler = gActiveBattler = battler;
BattleScriptPushCursorAndCallback(BattleScript_ShedSkinActivates);
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battler].status1);
MarkBattlerForControllerExec(gActiveBattler);
2017-09-17 15:19:15 +02:00
effect++;
}
break;
2018-07-22 18:40:18 +02:00
case ABILITY_SPEED_BOOST:
if (gBattleMons[battler].statStages[STAT_SPEED] < 0xC && gDisableStructs[battler].isFirstTurn != 2)
{
gBattleMons[battler].statStages[STAT_SPEED]++;
gBattleScripting.animArg1 = 0x11;
gBattleScripting.animArg2 = 0;
BattleScriptPushCursorAndCallback(BattleScript_SpeedBoostActivates);
gBattleScripting.battler = battler;
2017-09-17 15:19:15 +02:00
effect++;
}
break;
2018-07-22 18:40:18 +02:00
case ABILITY_TRUANT:
gDisableStructs[gBattlerAttacker].truantCounter ^= 1;
2017-09-17 15:19:15 +02:00
break;
2018-07-22 21:05:12 +02:00
case ABILITY_BAD_DREAMS:
if (gBattleMons[BATTLE_OPPOSITE(battler)].status1 & STATUS1_SLEEP || gBattleMons[BATTLE_OPPOSITE(battler)].status1 & STATUS1_SLEEP)
{
BattleScriptPushCursorAndCallback(BattleScript_BadDreamsActivates);
effect++;
}
break;
2018-07-26 21:56:23 +02:00
case ABILITY_SOLAR_POWER:
if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY)
{
BattleScriptPushCursorAndCallback(BattleScript_SolarPowerActivates);
gBattleMoveDamage = gBattleMons[battler].maxHP / 8;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
effect++;
}
break;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_MOVES_BLOCK: // 2
2018-08-05 13:39:22 +02:00
if ((gLastUsedAbility == ABILITY_SOUNDPROOF && gBattleMoves[move].flags & FLAG_SOUND)
|| (gLastUsedAbility == ABILITY_BULLETPROOF && gBattleMoves[move].flags & FLAG_BALLISTIC))
2018-07-22 18:40:18 +02:00
{
2018-08-02 20:24:18 +02:00
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)
gHitMarker |= HITMARKER_NO_PPDEDUCT;
gBattlescriptCurrInstr = BattleScript_SoundproofProtected;
effect = 1;
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_ABSORBING: // 3
2018-08-02 20:24:18 +02:00
if (move != MOVE_NONE)
2018-07-22 18:40:18 +02:00
{
u8 statId;
switch (gLastUsedAbility)
{
case ABILITY_VOLT_ABSORB:
if (moveType == TYPE_ELECTRIC)
effect = 1;
break;
case ABILITY_WATER_ABSORB:
case ABILITY_DRY_SKIN:
if (moveType == TYPE_WATER)
effect = 1;
break;
case ABILITY_MOTOR_DRIVE:
if (moveType == TYPE_ELECTRIC)
effect = 2, statId = STAT_SPEED;
break;
case ABILITY_LIGHTNING_ROD:
if (moveType == TYPE_ELECTRIC)
effect = 2, statId = STAT_SPATK;
break;
case ABILITY_STORM_DRAIN:
if (moveType == TYPE_WATER)
effect = 2, statId = STAT_SPATK;
break;
case ABILITY_SAP_SIPPER:
if (moveArg == TYPE_GRASS)
effect = 2, statId = STAT_ATK;
break;
case ABILITY_FLASH_FIRE:
if (moveType == TYPE_FIRE && !(gBattleMons[battler].status1 & STATUS1_FREEZE))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
if (!(gBattleResources->flags->flags[battler] & RESOURCE_FLAG_FLASH_FIRE))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
if (gProtectStructs[gBattlerAttacker].notFirstStrike)
gBattlescriptCurrInstr = BattleScript_FlashFireBoost;
else
gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss;
gBattleResources->flags->flags[battler] |= RESOURCE_FLAG_FLASH_FIRE;
effect = 2;
2017-11-26 17:15:28 +01:00
}
2018-07-22 18:40:18 +02:00
else
2017-11-26 17:15:28 +01:00
{
2018-07-22 18:40:18 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
if (gProtectStructs[gBattlerAttacker].notFirstStrike)
gBattlescriptCurrInstr = BattleScript_FlashFireBoost;
else
gBattlescriptCurrInstr = BattleScript_FlashFireBoost_PPLoss;
2017-11-26 17:15:28 +01:00
effect = 2;
}
}
2018-07-22 18:40:18 +02:00
break;
}
2018-09-02 00:07:19 +02:00
2018-07-22 18:40:18 +02:00
if (effect == 1) // Drain Hp ability.
{
2018-07-31 23:09:47 +02:00
if (BATTLER_MAX_HP(battler) || gStatuses3[battler] & STATUS3_HEAL_BLOCK)
2017-11-26 17:15:28 +01:00
{
2018-07-22 18:40:18 +02:00
if ((gProtectStructs[gBattlerAttacker].notFirstStrike))
gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless;
else
gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless_PPLoss;
}
else
{
if (gProtectStructs[gBattlerAttacker].notFirstStrike)
gBattlescriptCurrInstr = BattleScript_MoveHPDrain;
else
gBattlescriptCurrInstr = BattleScript_MoveHPDrain_PPLoss;
2017-10-12 17:49:24 +02:00
2018-07-22 18:40:18 +02:00
gBattleMoveDamage = gBattleMons[battler].maxHP / 4;
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
gBattleMoveDamage *= -1;
2017-09-17 15:19:15 +02:00
}
}
2018-07-22 18:40:18 +02:00
else if (effect == 2) // Boost Stat ability;
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
if (gBattleMons[battler].statStages[statId] == 0xC)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
if ((gProtectStructs[gBattlerAttacker].notFirstStrike))
gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless;
else
gBattlescriptCurrInstr = BattleScript_MonMadeMoveUseless_PPLoss;
}
else
{
if (gProtectStructs[gBattlerAttacker].notFirstStrike)
gBattlescriptCurrInstr = BattleScript_MoveStatDrain;
else
gBattlescriptCurrInstr = BattleScript_MoveStatDrain_PPLoss;
SET_STATCHANGER(statId, 1, FALSE);
gBattleMons[battler].statStages[statId]++;
PREPARE_STAT_BUFFER(gBattleTextBuff1, statId);
2017-09-17 15:19:15 +02:00
}
}
2018-07-22 18:40:18 +02:00
}
break;
2018-09-02 00:07:19 +02:00
case ABILITYEFFECT_MOVE_END: // Think contact abilities.
2018-07-22 18:40:18 +02:00
switch (gLastUsedAbility)
{
2018-07-26 21:56:23 +02:00
case ABILITY_JUSTIFIED:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler)
&& moveType == TYPE_DARK
&& gBattleMons[battler].statStages[STAT_ATK] != 0xC)
{
gBattleMons[battler].statStages[STAT_ATK]++;
SET_STATCHANGER(STAT_ATK, 1, FALSE);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_TargetAbilityStatRaise;
effect++;
}
break;
case ABILITY_RATTLED:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler)
&& (moveType == TYPE_DARK || moveType == TYPE_BUG || moveType == TYPE_GHOST)
&& gBattleMons[battler].statStages[STAT_SPEED] != 0xC)
{
gBattleMons[battler].statStages[STAT_SPEED]++;
SET_STATCHANGER(STAT_SPEED, 1, FALSE);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_TargetAbilityStatRaise;
effect++;
}
break;
case ABILITY_WEAK_ARMOR:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler)
&& (gBattleMons[battler].statStages[STAT_SPEED] != 0xC || gBattleMons[battler].statStages[STAT_DEF] != 0))
{
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_WeakArmorActivates;
effect++;
}
break;
case ABILITY_CURSED_BODY:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED
&& gDisableStructs[gBattlerAttacker].disabledMove == MOVE_NONE
&& IsBattlerAlive(gBattlerAttacker)
&& ((i = GetBattleMonMoveSlot(&gBattleMons[gBattlerAttacker], gChosenMove)) != 4)
&& (Random() % 3) == 0)
{
gDisableStructs[gBattlerAttacker].disabledMove = gChosenMove;
gDisableStructs[gBattlerAttacker].disableTimer1 = 4;
PREPARE_MOVE_BUFFER(gBattleTextBuff1, gChosenMove);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_CursedBodyActivates;
effect++;
}
break;
case ABILITY_MUMMY:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& IsBattlerAlive(gBattlerAttacker)
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT))
{
switch (gBattleMons[gBattlerAttacker].ability)
{
case ABILITY_MUMMY:
case ABILITY_BATTLE_BOND:
case ABILITY_COMATOSE:
case ABILITY_DISGUISE:
case ABILITY_MULTITYPE:
case ABILITY_POWER_CONSTRUCT:
case ABILITY_RKS_SYSTEM:
case ABILITY_SCHOOLING:
case ABILITY_SHIELDS_DOWN:
case ABILITY_STANCE_CHANGE:
break;
default:
gLastUsedAbility = gBattleMons[gBattlerAttacker].ability = ABILITY_MUMMY;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_MummyActivates;
effect++;
break;
}
}
break;
2018-07-22 18:40:18 +02:00
case ABILITY_ANGER_POINT:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& gIsCriticalHit
&& TARGET_TURN_DAMAGED
&& IsBattlerAlive(battler)
&& gBattleMons[battler].statStages[STAT_ATK] != 0xC)
{
gBattleMons[battler].statStages[STAT_ATK] = 0xC;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AngryPointActivates;
effect++;
}
2017-09-17 15:19:15 +02:00
break;
2018-07-22 18:40:18 +02:00
case ABILITY_COLOR_CHANGE:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& move != MOVE_STRUGGLE
&& gBattleMoves[move].power != 0
&& TARGET_TURN_DAMAGED
&& !IS_BATTLER_OF_TYPE(battler, moveType)
&& gBattleMons[battler].hp != 0)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
SET_BATTLER_TYPE(battler, moveType);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, moveType);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_ColorChangeActivates;
effect++;
}
break;
case ABILITY_ROUGH_SKIN:
2018-07-26 21:56:23 +02:00
case ABILITY_IRON_BARBS:
2018-07-22 18:40:18 +02:00
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& gBattleMons[gBattlerAttacker].hp != 0
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& TARGET_TURN_DAMAGED
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT))
{
2018-07-26 21:56:23 +02:00
gBattleMoveDamage = gBattleMons[gBattlerAttacker].maxHP / 8;
2018-07-22 18:40:18 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_RoughSkinActivates;
effect++;
}
break;
case ABILITY_EFFECT_SPORE:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& gBattleMons[gBattlerAttacker].hp != 0
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& TARGET_TURN_DAMAGED
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)
&& (Random() % 10) == 0)
{
do
{
gBattleCommunication[MOVE_EFFECT_BYTE] = Random() & 3;
} while (gBattleCommunication[MOVE_EFFECT_BYTE] == 0);
2017-10-12 17:49:24 +02:00
2018-07-22 18:40:18 +02:00
if (gBattleCommunication[MOVE_EFFECT_BYTE] == MOVE_EFFECT_BURN)
gBattleCommunication[MOVE_EFFECT_BYTE] += 2; // 5 MOVE_EFFECT_PARALYSIS
gBattleCommunication[MOVE_EFFECT_BYTE] += MOVE_EFFECT_AFFECTS_USER;
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2018-07-22 18:40:18 +02:00
gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect;
2017-09-17 15:19:15 +02:00
gHitMarker |= HITMARKER_IGNORE_SAFEGUARD;
effect++;
}
break;
2018-07-22 18:40:18 +02:00
case ABILITY_POISON_POINT:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& gBattleMons[gBattlerAttacker].hp != 0
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& TARGET_TURN_DAMAGED
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)
&& (Random() % 3) == 0)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_POISON;
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2018-07-22 18:40:18 +02:00
gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect;
2017-09-17 15:19:15 +02:00
gHitMarker |= HITMARKER_IGNORE_SAFEGUARD;
effect++;
}
break;
2018-07-22 18:40:18 +02:00
case ABILITY_STATIC:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& gBattleMons[gBattlerAttacker].hp != 0
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& TARGET_TURN_DAMAGED
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)
&& (Random() % 3) == 0)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_PARALYSIS;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect;
gHitMarker |= HITMARKER_IGNORE_SAFEGUARD;
effect++;
}
break;
case ABILITY_FLAME_BODY:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& gBattleMons[gBattlerAttacker].hp != 0
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)
&& TARGET_TURN_DAMAGED
&& (Random() % 3) == 0)
{
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_BURN;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_ApplySecondaryEffect;
gHitMarker |= HITMARKER_IGNORE_SAFEGUARD;
effect++;
}
break;
case ABILITY_CUTE_CHARM:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& gBattleMons[gBattlerAttacker].hp != 0
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)
&& TARGET_TURN_DAMAGED
&& gBattleMons[gBattlerTarget].hp != 0
&& (Random() % 3) == 0
&& gBattleMons[gBattlerAttacker].ability != ABILITY_OBLIVIOUS
&& GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != GetGenderFromSpeciesAndPersonality(speciesDef, pidDef)
&& !(gBattleMons[gBattlerAttacker].status2 & STATUS2_INFATUATION)
&& GetGenderFromSpeciesAndPersonality(speciesAtk, pidAtk) != MON_GENDERLESS
&& GetGenderFromSpeciesAndPersonality(speciesDef, pidDef) != MON_GENDERLESS)
{
gBattleMons[gBattlerAttacker].status2 |= STATUS2_INFATUATED_WITH(gBattlerTarget);
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_CuteCharmActivates;
effect++;
}
break;
}
break;
case ABILITYEFFECT_IMMUNITY: // 5
for (battler = 0; battler < gBattlersCount; battler++)
{
switch (gBattleMons[battler].ability)
{
case ABILITY_IMMUNITY:
if (gBattleMons[battler].status1 & (STATUS1_POISON | STATUS1_TOXIC_POISON | STATUS1_TOXIC_COUNTER))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
effect = 1;
}
break;
case ABILITY_OWN_TEMPO:
if (gBattleMons[battler].status2 & STATUS2_CONFUSION)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn);
effect = 2;
}
break;
case ABILITY_LIMBER:
if (gBattleMons[battler].status1 & STATUS1_PARALYSIS)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
effect = 1;
}
break;
case ABILITY_INSOMNIA:
case ABILITY_VITAL_SPIRIT:
if (gBattleMons[battler].status1 & STATUS1_SLEEP)
{
gBattleMons[battler].status2 &= ~(STATUS2_NIGHTMARE);
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
effect = 1;
}
break;
case ABILITY_WATER_VEIL:
if (gBattleMons[battler].status1 & STATUS1_BURN)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
effect = 1;
}
break;
case ABILITY_MAGMA_ARMOR:
if (gBattleMons[battler].status1 & STATUS1_FREEZE)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
effect = 1;
}
break;
case ABILITY_OBLIVIOUS:
if (gBattleMons[battler].status2 & STATUS2_INFATUATION)
{
StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn);
effect = 3;
}
break;
}
if (effect)
{
switch (effect)
{
case 1: // status cleared
gBattleMons[battler].status1 = 0;
break;
case 2: // get rid of confusion
gBattleMons[battler].status2 &= ~(STATUS2_CONFUSION);
break;
case 3: // get rid of infatuation
gBattleMons[battler].status2 &= ~(STATUS2_INFATUATION);
2017-09-17 15:19:15 +02:00
break;
}
2018-07-22 18:40:18 +02:00
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_AbilityCuredStatus;
gBattleScripting.battler = battler;
gActiveBattler = battler;
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1);
MarkBattlerForControllerExec(gActiveBattler);
return effect;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_FORECAST: // 6
for (battler = 0; battler < gBattlersCount; battler++)
{
if (gBattleMons[battler].ability == ABILITY_FORECAST)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
effect = CastformDataTypeChange(battler);
if (effect)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
BattleScriptPushCursorAndCallback(BattleScript_CastformChange);
gBattleScripting.battler = battler;
*(&gBattleStruct->formToChangeInto) = effect - 1;
return effect;
}
}
}
break;
case ABILITYEFFECT_SYNCHRONIZE: // 7
if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT))
{
gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT);
gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN);
if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect + MOVE_EFFECT_AFFECTS_USER;
gBattleScripting.battler = gBattlerTarget;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_SynchronizeActivates;
gHitMarker |= HITMARKER_IGNORE_SAFEGUARD;
effect++;
}
break;
case ABILITYEFFECT_ATK_SYNCHRONIZE: // 8
if (gLastUsedAbility == ABILITY_SYNCHRONIZE && (gHitMarker & HITMARKER_SYNCHRONISE_EFFECT))
{
gHitMarker &= ~(HITMARKER_SYNCHRONISE_EFFECT);
gBattleStruct->synchronizeMoveEffect &= ~(MOVE_EFFECT_AFFECTS_USER | MOVE_EFFECT_CERTAIN);
if (gBattleStruct->synchronizeMoveEffect == MOVE_EFFECT_TOXIC)
gBattleStruct->synchronizeMoveEffect = MOVE_EFFECT_POISON;
gBattleCommunication[MOVE_EFFECT_BYTE] = gBattleStruct->synchronizeMoveEffect;
gBattleScripting.battler = gBattlerAttacker;
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_SynchronizeActivates;
gHitMarker |= HITMARKER_IGNORE_SAFEGUARD;
effect++;
}
break;
case ABILITYEFFECT_INTIMIDATE1: // 9
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].ability == ABILITY_INTIMIDATE && gStatuses3[i] & STATUS3_INTIMIDATE_POKES)
{
gLastUsedAbility = ABILITY_INTIMIDATE;
gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES);
2018-09-02 00:07:19 +02:00
BattleScriptPushCursorAndCallback(BattleScript_IntimidateActivatesEnd3);
2018-07-22 18:40:18 +02:00
gBattleStruct->intimidateBattler = i;
effect++;
break;
}
}
break;
case ABILITYEFFECT_TRACE: // 11
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].ability == ABILITY_TRACE && (gStatuses3[i] & STATUS3_TRACE))
{
u8 target2;
side = (GetBattlerPosition(i) ^ BIT_SIDE) & BIT_SIDE; // side of the opposing pokemon
target1 = GetBattlerAtPosition(side);
target2 = GetBattlerAtPosition(side + BIT_FLANK);
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0
&& gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gActiveBattler = GetBattlerAtPosition(((Random() & 1) * 2) | side);
gBattleMons[i].ability = gBattleMons[gActiveBattler].ability;
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
effect++;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
else if (gBattleMons[target1].ability != 0 && gBattleMons[target1].hp != 0)
2017-09-17 15:19:15 +02:00
{
2018-02-06 02:46:59 +01:00
gActiveBattler = target1;
2018-07-22 18:40:18 +02:00
gBattleMons[i].ability = gBattleMons[gActiveBattler].ability;
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
effect++;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
else if (gBattleMons[target2].ability != 0 && gBattleMons[target2].hp != 0)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gActiveBattler = target2;
gBattleMons[i].ability = gBattleMons[gActiveBattler].ability;
gLastUsedAbility = gBattleMons[gActiveBattler].ability;
effect++;
2017-09-17 15:19:15 +02:00
}
}
2018-07-22 18:40:18 +02:00
else
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gActiveBattler = target1;
if (gBattleMons[target1].ability && gBattleMons[target1].hp)
{
gBattleMons[i].ability = gBattleMons[target1].ability;
gLastUsedAbility = gBattleMons[target1].ability;
effect++;
}
}
if (effect)
{
BattleScriptPushCursorAndCallback(BattleScript_TraceActivates);
gStatuses3[i] &= ~(STATUS3_TRACE);
gBattleScripting.battler = i;
PREPARE_MON_NICK_WITH_PREFIX_BUFFER(gBattleTextBuff1, gActiveBattler, gBattlerPartyIndexes[gActiveBattler])
PREPARE_ABILITY_BUFFER(gBattleTextBuff2, gLastUsedAbility)
2017-09-17 15:19:15 +02:00
break;
}
}
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_INTIMIDATE2: // 10
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].ability == ABILITY_INTIMIDATE && (gStatuses3[i] & STATUS3_INTIMIDATE_POKES))
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gLastUsedAbility = ABILITY_INTIMIDATE;
gStatuses3[i] &= ~(STATUS3_INTIMIDATE_POKES);
BattleScriptPushCursor();
2018-09-02 00:07:19 +02:00
gBattlescriptCurrInstr = BattleScript_IntimidateActivates;
2018-07-22 18:40:18 +02:00
gBattleStruct->intimidateBattler = i;
effect++;
break;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_CHECK_OTHER_SIDE: // 12
side = GetBattlerSide(battler);
for (i = 0; i < gBattlersCount; i++)
{
if (GetBattlerSide(i) != side && gBattleMons[i].ability == ability)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gLastUsedAbility = ability;
effect = i + 1;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_CHECK_BATTLER_SIDE: // 13
side = GetBattlerSide(battler);
for (i = 0; i < gBattlersCount; i++)
{
if (GetBattlerSide(i) == side && gBattleMons[i].ability == ability)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gLastUsedAbility = ability;
effect = i + 1;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_CHECK_ON_FIELD: // 19
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].ability == ability && gBattleMons[i].hp != 0)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gLastUsedAbility = ability;
effect = i + 1;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_CHECK_FIELD_EXCEPT_BATTLER: // 15
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].ability == ability && i != battler)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gLastUsedAbility = ability;
effect = i + 1;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_COUNT_OTHER_SIDE: // 16
side = GetBattlerSide(battler);
for (i = 0; i < gBattlersCount; i++)
{
if (GetBattlerSide(i) != side && gBattleMons[i].ability == ability)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gLastUsedAbility = ability;
effect++;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
}
break;
case ABILITYEFFECT_COUNT_BATTLER_SIDE: // 17
side = GetBattlerSide(battler);
for (i = 0; i < gBattlersCount; i++)
{
if (GetBattlerSide(i) == side && gBattleMons[i].ability == ability)
2017-09-17 15:19:15 +02:00
{
2018-07-22 18:40:18 +02:00
gLastUsedAbility = ability;
effect++;
2017-09-17 15:19:15 +02:00
}
}
2018-07-22 18:40:18 +02:00
break;
case ABILITYEFFECT_COUNT_ON_FIELD: // 18
for (i = 0; i < gBattlersCount; i++)
{
if (gBattleMons[i].ability == ability && i != battler)
{
gLastUsedAbility = ability;
effect++;
}
}
break;
2017-09-17 15:19:15 +02:00
}
2018-07-22 18:40:18 +02:00
if (effect && caseID < ABILITYEFFECT_CHECK_OTHER_SIDE && gLastUsedAbility != 0xFF)
RecordAbilityBattle(battler, gLastUsedAbility);
2017-09-17 15:19:15 +02:00
return effect;
}
2017-09-17 17:14:32 +02:00
void BattleScriptExecute(const u8 *BS_ptr)
2017-09-17 17:14:32 +02:00
{
gBattlescriptCurrInstr = BS_ptr;
2018-02-06 23:09:39 +01:00
gBattleResources->battleCallbackStack->function[gBattleResources->battleCallbackStack->size++] = gBattleMainFunc;
2017-10-06 00:12:01 +02:00
gBattleMainFunc = RunBattleScriptCommands_PopCallbacksStack;
gCurrentActionFuncId = 0;
2017-09-17 17:14:32 +02:00
}
void BattleScriptPushCursorAndCallback(const u8 *BS_ptr)
2017-09-17 17:14:32 +02:00
{
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattlescriptCurrInstr = BS_ptr;
2018-02-06 23:09:39 +01:00
gBattleResources->battleCallbackStack->function[gBattleResources->battleCallbackStack->size++] = gBattleMainFunc;
2017-10-06 00:12:01 +02:00
gBattleMainFunc = RunBattleScriptCommands;
2017-09-17 17:14:32 +02:00
}
enum
{
ITEM_NO_EFFECT, // 0
ITEM_STATUS_CHANGE, // 1
ITEM_EFFECT_OTHER, // 2
ITEM_PP_CHANGE, // 3
ITEM_HP_CHANGE, // 4
ITEM_STATS_CHANGE, // 5
};
2018-07-28 16:33:01 +02:00
// second argument is 1/X of current hp compared to max hp
static bool32 HasEnoughHpToEatBerry(u8 battlerId, u32 hpFraction)
2017-09-17 17:14:32 +02:00
{
2018-07-28 16:33:01 +02:00
if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / hpFraction)
2017-09-17 17:14:32 +02:00
{
2018-07-28 16:33:01 +02:00
return TRUE;
2017-09-17 17:14:32 +02:00
}
2018-07-28 16:33:01 +02:00
else if (hpFraction <= 4 && GetBattlerAbility(battlerId) == ABILITY_GLUTTONY
&& gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2)
2017-09-17 17:14:32 +02:00
{
2018-07-28 16:33:01 +02:00
RecordAbilityBattle(battlerId, ABILITY_GLUTTONY);
return TRUE;
2017-09-17 17:14:32 +02:00
}
else
{
2018-07-28 16:33:01 +02:00
return FALSE;
2017-09-17 17:14:32 +02:00
}
2018-07-28 16:33:01 +02:00
}
2017-09-17 17:14:32 +02:00
2018-07-28 16:33:01 +02:00
u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn)
{
int i = 0;
u8 effect = ITEM_NO_EFFECT;
u8 changedPP = 0;
u8 battlerHoldEffect, atkHoldEffect;
u8 battlerHoldEffectParam, atkHoldEffectParam;
u16 atkItem;
gLastUsedItem = gBattleMons[battlerId].item;
battlerHoldEffect = GetBattlerHoldEffect(battlerId, TRUE);
battlerHoldEffectParam = GetBattlerHoldEffectParam(battlerId);
atkItem = gBattleMons[gBattlerAttacker].item;
atkHoldEffect = GetBattlerHoldEffect(gBattlerAttacker, TRUE);
atkHoldEffectParam = GetBattlerHoldEffectParam(gBattlerAttacker);
2017-09-17 17:14:32 +02:00
switch (caseID)
{
2017-10-06 00:12:01 +02:00
case ITEMEFFECT_ON_SWITCH_IN:
2018-07-16 20:47:30 +02:00
switch (battlerHoldEffect)
2017-09-17 17:14:32 +02:00
{
case HOLD_EFFECT_DOUBLE_PRIZE:
2018-02-08 11:17:41 +01:00
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
2017-09-17 17:14:32 +02:00
gBattleStruct->moneyMultiplier = 2;
break;
case HOLD_EFFECT_RESTORE_STATS:
2017-11-26 11:55:17 +01:00
for (i = 0; i < BATTLE_STATS_NO; i++)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].statStages[i] < 6)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].statStages[i] = 6;
2017-09-17 17:14:32 +02:00
effect = ITEM_STATS_CHANGE;
}
}
if (effect)
{
2018-02-08 11:17:41 +01:00
gBattleScripting.battler = battlerId;
2018-02-08 12:13:29 +01:00
gPotentialItemEffectBattler = battlerId;
2018-02-08 11:17:41 +01:00
gActiveBattler = gBattlerAttacker = battlerId;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
2017-09-17 17:14:32 +02:00
}
break;
}
break;
case 1:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].hp)
2017-09-17 17:14:32 +02:00
{
2018-07-16 20:47:30 +02:00
switch (battlerHoldEffect)
2017-09-17 17:14:32 +02:00
{
case HOLD_EFFECT_RESTORE_HP:
2018-07-28 16:33:01 +02:00
if (!moveTurn && HasEnoughHpToEatBerry(battlerId, 2))
2017-09-17 17:14:32 +02:00
{
2018-07-16 20:47:30 +02:00
gBattleMoveDamage = battlerHoldEffectParam;
if (gBattleMons[battlerId].hp + battlerHoldEffectParam > gBattleMons[battlerId].maxHP)
2018-02-08 11:17:41 +01:00
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
2017-09-17 17:14:32 +02:00
gBattleMoveDamage *= -1;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
2017-09-17 17:14:32 +02:00
effect = 4;
}
break;
case HOLD_EFFECT_RESTORE_PP:
if (!moveTurn)
{
2017-11-26 11:55:17 +01:00
struct Pokemon *mon;
2017-09-17 17:14:32 +02:00
u8 ppBonuses;
u16 move;
2018-02-08 11:17:41 +01:00
if (GetBattlerSide(battlerId) == B_SIDE_PLAYER)
mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]];
2017-09-17 17:14:32 +02:00
else
2018-02-08 11:17:41 +01:00
mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]];
2017-09-17 17:14:32 +02:00
for (i = 0; i < 4; i++)
{
2017-11-26 11:55:17 +01:00
move = GetMonData(mon, MON_DATA_MOVE1 + i);
changedPP = GetMonData(mon, MON_DATA_PP1 + i);
ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES);
2017-09-17 17:14:32 +02:00
if (move && changedPP == 0)
break;
}
if (i != 4)
{
u8 maxPP = CalculatePPWithBonus(move, ppBonuses, i);
2018-07-16 20:47:30 +02:00
if (changedPP + battlerHoldEffectParam > maxPP)
2017-09-17 17:14:32 +02:00
changedPP = maxPP;
else
2018-07-16 20:47:30 +02:00
changedPP = changedPP + battlerHoldEffectParam;
2017-11-26 11:55:17 +01:00
PREPARE_MOVE_BUFFER(gBattleTextBuff1, move);
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryPPHealEnd2);
2018-02-06 20:48:02 +01:00
BtlController_EmitSetMonData(0, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP);
MarkBattlerForControllerExec(gActiveBattler);
2017-09-17 17:14:32 +02:00
effect = ITEM_PP_CHANGE;
}
}
break;
case HOLD_EFFECT_RESTORE_STATS:
2017-11-26 11:55:17 +01:00
for (i = 0; i < BATTLE_STATS_NO; i++)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].statStages[i] < 6)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].statStages[i] = 6;
2017-09-17 17:14:32 +02:00
effect = ITEM_STATS_CHANGE;
}
}
if (effect)
{
2018-02-08 11:17:41 +01:00
gBattleScripting.battler = battlerId;
2018-02-08 12:13:29 +01:00
gPotentialItemEffectBattler = battlerId;
2018-02-08 11:17:41 +01:00
gActiveBattler = gBattlerAttacker = battlerId;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_WhiteHerbEnd2);
2017-09-17 17:14:32 +02:00
}
break;
case HOLD_EFFECT_LEFTOVERS:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMoveDamage = gBattleMons[battlerId].maxHP / 16;
2017-09-17 17:14:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
2017-09-17 17:14:32 +02:00
gBattleMoveDamage *= -1;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_ItemHealHP_End2);
2017-09-17 17:14:32 +02:00
effect = ITEM_HP_CHANGE;
2018-07-16 20:47:30 +02:00
RecordItemEffectBattle(battlerId, battlerHoldEffect);
2017-09-17 17:14:32 +02:00
}
break;
// nice copy/paste there gamefreak, making a function for confuse berries was too much eh?
case HOLD_EFFECT_CONFUSE_SPICY:
2018-07-28 16:33:01 +02:00
if (!moveTurn && HasEnoughHpToEatBerry(battlerId, 2))
2017-09-17 17:14:32 +02:00
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SPICY);
2017-11-26 11:55:17 +01:00
2018-07-16 20:47:30 +02:00
gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam;
2017-09-17 17:14:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
2017-09-17 17:14:32 +02:00
gBattleMoveDamage *= -1;
2018-02-08 11:17:41 +01:00
if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_SPICY) < 0)
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
2017-09-17 17:14:32 +02:00
else
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
2017-09-17 17:14:32 +02:00
effect = ITEM_HP_CHANGE;
}
break;
case HOLD_EFFECT_CONFUSE_DRY:
2018-07-28 16:33:01 +02:00
if (!moveTurn && HasEnoughHpToEatBerry(battlerId, 2))
2017-09-17 17:14:32 +02:00
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_DRY);
2017-11-26 11:55:17 +01:00
2018-07-16 20:47:30 +02:00
gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam;
2017-09-17 17:14:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
2017-09-17 17:14:32 +02:00
gBattleMoveDamage *= -1;
2018-02-08 11:17:41 +01:00
if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_DRY) < 0)
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
2017-09-17 17:14:32 +02:00
else
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
2017-09-17 17:14:32 +02:00
effect = ITEM_HP_CHANGE;
}
break;
case HOLD_EFFECT_CONFUSE_SWEET:
2018-07-28 16:33:01 +02:00
if (!moveTurn && HasEnoughHpToEatBerry(battlerId, 2))
2017-09-17 17:14:32 +02:00
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SWEET);
2017-11-26 11:55:17 +01:00
2018-07-16 20:47:30 +02:00
gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam;
2017-09-17 17:14:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
2017-09-17 17:14:32 +02:00
gBattleMoveDamage *= -1;
2018-02-08 11:17:41 +01:00
if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_SWEET) < 0)
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
2017-09-17 17:14:32 +02:00
else
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
2017-09-17 17:14:32 +02:00
effect = ITEM_HP_CHANGE;
}
break;
case HOLD_EFFECT_CONFUSE_BITTER:
2018-07-28 16:33:01 +02:00
if (!moveTurn && HasEnoughHpToEatBerry(battlerId, 2))
2017-09-17 17:14:32 +02:00
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_BITTER);
2017-11-26 11:55:17 +01:00
2018-07-16 20:47:30 +02:00
gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam;
2017-09-17 17:14:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
2017-09-17 17:14:32 +02:00
gBattleMoveDamage *= -1;
2018-02-08 11:17:41 +01:00
if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_BITTER) < 0)
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
2017-09-17 17:14:32 +02:00
else
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
2017-09-17 17:14:32 +02:00
effect = ITEM_HP_CHANGE;
}
break;
case HOLD_EFFECT_CONFUSE_SOUR:
2018-07-28 16:33:01 +02:00
if (!moveTurn && HasEnoughHpToEatBerry(battlerId, 2))
2017-09-17 17:14:32 +02:00
{
PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SOUR);
2017-11-26 11:55:17 +01:00
2018-07-16 20:47:30 +02:00
gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam;
2017-09-17 17:14:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = 1;
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP)
gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp;
2017-09-17 17:14:32 +02:00
gBattleMoveDamage *= -1;
2018-02-08 11:17:41 +01:00
if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_SOUR) < 0)
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryConfuseHealEnd2);
2017-09-17 17:14:32 +02:00
else
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem);
2017-09-17 17:14:32 +02:00
effect = ITEM_HP_CHANGE;
}
break;
// copy/paste again, smh
case HOLD_EFFECT_ATTACK_UP:
2018-07-28 16:33:01 +02:00
if (!moveTurn && gBattleMons[battlerId].statStages[STAT_ATK] < 0xC && HasEnoughHpToEatBerry(battlerId, battlerHoldEffectParam))
2017-09-17 17:14:32 +02:00
{
2018-02-08 12:13:29 +01:00
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK);
2017-11-26 11:55:17 +01:00
PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE);
2017-09-17 17:14:32 +02:00
2018-02-08 11:17:41 +01:00
gEffectBattler = battlerId;
2018-02-08 12:13:29 +01:00
SET_STATCHANGER(STAT_ATK, 1, FALSE);
gBattleScripting.animArg1 = 0xE + STAT_ATK;
2017-09-17 17:14:32 +02:00
gBattleScripting.animArg2 = 0;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_DEFENSE_UP:
2018-07-28 16:33:01 +02:00
if (!moveTurn && gBattleMons[battlerId].statStages[STAT_DEF] < 0xC && HasEnoughHpToEatBerry(battlerId, battlerHoldEffectParam))
2017-09-17 17:14:32 +02:00
{
2018-02-08 12:13:29 +01:00
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_DEF);
2017-09-17 17:14:32 +02:00
2018-02-08 11:17:41 +01:00
gEffectBattler = battlerId;
2018-02-08 12:13:29 +01:00
SET_STATCHANGER(STAT_DEF, 1, FALSE);
gBattleScripting.animArg1 = 0xE + STAT_DEF;
2017-09-17 17:14:32 +02:00
gBattleScripting.animArg2 = 0;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_SPEED_UP:
2018-07-28 16:33:01 +02:00
if (!moveTurn && gBattleMons[battlerId].statStages[STAT_SPEED] < 0xC && HasEnoughHpToEatBerry(battlerId, battlerHoldEffectParam))
2017-09-17 17:14:32 +02:00
{
2018-02-08 12:13:29 +01:00
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPEED);
2017-09-17 17:14:32 +02:00
2018-02-08 11:17:41 +01:00
gEffectBattler = battlerId;
2018-02-08 12:13:29 +01:00
SET_STATCHANGER(STAT_SPEED, 1, FALSE);
gBattleScripting.animArg1 = 0xE + STAT_SPEED;
2017-09-17 17:14:32 +02:00
gBattleScripting.animArg2 = 0;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_SP_ATTACK_UP:
2018-07-28 16:33:01 +02:00
if (!moveTurn && gBattleMons[battlerId].statStages[STAT_SPATK] < 0xC && HasEnoughHpToEatBerry(battlerId, battlerHoldEffectParam))
2017-09-17 17:14:32 +02:00
{
2018-02-08 12:13:29 +01:00
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPATK);
2017-09-17 17:14:32 +02:00
2018-02-08 11:17:41 +01:00
gEffectBattler = battlerId;
2018-02-08 12:13:29 +01:00
SET_STATCHANGER(STAT_SPATK, 1, FALSE);
gBattleScripting.animArg1 = 0xE + STAT_SPATK;
2017-09-17 17:14:32 +02:00
gBattleScripting.animArg2 = 0;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_SP_DEFENSE_UP:
2018-07-28 16:33:01 +02:00
if (!moveTurn && gBattleMons[battlerId].statStages[STAT_SPDEF] < 0xC && HasEnoughHpToEatBerry(battlerId, battlerHoldEffectParam))
2017-09-17 17:14:32 +02:00
{
2018-02-08 12:13:29 +01:00
PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPDEF);
2017-09-17 17:14:32 +02:00
2018-02-08 11:17:41 +01:00
gEffectBattler = battlerId;
2018-02-08 12:13:29 +01:00
SET_STATCHANGER(STAT_SPDEF, 1, FALSE);
gBattleScripting.animArg1 = 0xE + STAT_SPDEF;
2017-09-17 17:14:32 +02:00
gBattleScripting.animArg2 = 0;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATS_CHANGE;
}
break;
case HOLD_EFFECT_CRITICAL_UP:
2018-07-28 16:33:01 +02:00
if (!moveTurn && !(gBattleMons[battlerId].status2 & STATUS2_FOCUS_ENERGY) && HasEnoughHpToEatBerry(battlerId, battlerHoldEffectParam))
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status2 |= STATUS2_FOCUS_ENERGY;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_EFFECT_OTHER;
}
break;
case HOLD_EFFECT_RANDOM_STAT_UP:
2018-07-28 16:33:01 +02:00
if (!moveTurn)
2017-09-17 17:14:32 +02:00
{
for (i = 0; i < 5; i++)
{
2018-02-08 12:13:29 +01:00
if (gBattleMons[battlerId].statStages[STAT_ATK + i] < 0xC)
2017-09-17 17:14:32 +02:00
break;
}
2018-07-28 16:33:01 +02:00
if (i != 5 && HasEnoughHpToEatBerry(battlerId, battlerHoldEffectParam))
2017-09-17 17:14:32 +02:00
{
do
{
i = Random() % 5;
2018-02-08 12:13:29 +01:00
} while (gBattleMons[battlerId].statStages[STAT_ATK + i] == 0xC);
2017-09-17 17:14:32 +02:00
2017-11-26 11:55:17 +01:00
PREPARE_STAT_BUFFER(gBattleTextBuff1, i + 1);
gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN;
gBattleTextBuff2[1] = B_BUFF_STRING;
gBattleTextBuff2[2] = STRINGID_STATSHARPLY;
gBattleTextBuff2[3] = STRINGID_STATSHARPLY >> 8;
gBattleTextBuff2[4] = B_BUFF_STRING;
gBattleTextBuff2[5] = STRINGID_STATROSE;
gBattleTextBuff2[6] = STRINGID_STATROSE >> 8;
2017-09-17 17:14:32 +02:00
gBattleTextBuff2[7] = EOS;
2018-02-08 11:17:41 +01:00
gEffectBattler = battlerId;
2017-11-26 11:55:17 +01:00
SET_STATCHANGER(i + 1, 2, FALSE);
2017-09-17 17:14:32 +02:00
gBattleScripting.animArg1 = 0x21 + i + 6;
gBattleScripting.animArg2 = 0;
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryStatRaiseEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATS_CHANGE;
}
}
break;
case HOLD_EFFECT_CURE_PAR:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 &= ~(STATUS1_PARALYSIS);
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryCurePrlzEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_PSN:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER);
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryCurePsnEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_BRN:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_BURN)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 &= ~(STATUS1_BURN);
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryCureBrnEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_FRZ:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_FREEZE)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 &= ~(STATUS1_FREEZE);
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryCureFrzEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_SLP:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_SLEEP)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 &= ~(STATUS1_SLEEP);
gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE);
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryCureSlpEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_CONFUSION:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION);
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryCureConfusionEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_EFFECT_OTHER;
}
break;
case HOLD_EFFECT_CURE_STATUS:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_ANY || gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
2017-09-17 17:14:32 +02:00
{
i = 0;
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY)
2017-09-17 17:14:32 +02:00
{
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
i++;
}
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_SLEEP)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE);
2017-09-17 17:14:32 +02:00
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
i++;
}
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS)
2017-09-17 17:14:32 +02:00
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
i++;
}
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_BURN)
2017-09-17 17:14:32 +02:00
{
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
i++;
}
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_FREEZE)
2017-09-17 17:14:32 +02:00
{
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
i++;
}
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
2017-09-17 17:14:32 +02:00
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn);
i++;
}
if (!(i > 1))
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
else
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 = 0;
gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION);
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2);
2017-09-17 17:14:32 +02:00
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_ATTRACT:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status2 & STATUS2_INFATUATION)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status2 &= ~(STATUS2_INFATUATION);
2017-09-17 17:14:32 +02:00
StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn);
2017-09-28 15:34:21 +02:00
BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2);
2017-09-17 17:14:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
effect = ITEM_EFFECT_OTHER;
}
break;
}
if (effect)
{
2018-02-08 11:17:41 +01:00
gBattleScripting.battler = battlerId;
2018-02-08 12:13:29 +01:00
gPotentialItemEffectBattler = battlerId;
2018-02-08 11:17:41 +01:00
gActiveBattler = gBattlerAttacker = battlerId;
2017-09-17 17:14:32 +02:00
switch (effect)
{
case ITEM_STATUS_CHANGE:
2018-02-08 11:17:41 +01:00
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battlerId].status1);
2018-02-06 20:48:02 +01:00
MarkBattlerForControllerExec(gActiveBattler);
2017-09-17 17:14:32 +02:00
break;
case ITEM_PP_CHANGE:
2018-02-08 11:17:41 +01:00
if (!(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED) && !(gDisableStructs[battlerId].unk18_b & gBitTable[i]))
gBattleMons[battlerId].pp[i] = changedPP;
2017-09-17 17:14:32 +02:00
break;
}
}
}
break;
case 2:
break;
2018-09-01 20:00:13 +02:00
case ITEMEFFECT_MOVE_END:
2018-02-08 11:17:41 +01:00
for (battlerId = 0; battlerId < gBattlersCount; battlerId++)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gLastUsedItem = gBattleMons[battlerId].item;
2018-07-28 16:33:01 +02:00
battlerHoldEffect = GetBattlerHoldEffect(battlerId, TRUE);
battlerHoldEffectParam = GetBattlerHoldEffectParam(battlerId);
2018-07-16 20:47:30 +02:00
switch (battlerHoldEffect)
2017-09-17 17:14:32 +02:00
{
case HOLD_EFFECT_CURE_PAR:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 &= ~(STATUS1_PARALYSIS);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattlescriptCurrInstr = BattleScript_BerryCureParRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_PSN:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattlescriptCurrInstr = BattleScript_BerryCurePsnRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_BRN:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_BURN)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 &= ~(STATUS1_BURN);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattlescriptCurrInstr = BattleScript_BerryCureBrnRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_FRZ:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_FREEZE)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 &= ~(STATUS1_FREEZE);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattlescriptCurrInstr = BattleScript_BerryCureFrzRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_SLP:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_SLEEP)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 &= ~(STATUS1_SLEEP);
gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattlescriptCurrInstr = BattleScript_BerryCureSlpRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_CURE_CONFUSION:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattlescriptCurrInstr = BattleScript_BerryCureConfusionRet;
effect = ITEM_EFFECT_OTHER;
}
break;
case HOLD_EFFECT_CURE_ATTRACT:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status2 & STATUS2_INFATUATION)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status2 &= ~(STATUS2_INFATUATION);
2017-09-17 17:14:32 +02:00
StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
gBattlescriptCurrInstr = BattleScript_BerryCureChosenStatusRet;
effect = ITEM_EFFECT_OTHER;
}
break;
case HOLD_EFFECT_CURE_STATUS:
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_ANY || gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY)
2017-09-17 17:14:32 +02:00
{
StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn);
}
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_SLEEP)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE);
2017-09-17 17:14:32 +02:00
StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn);
}
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS)
2017-09-17 17:14:32 +02:00
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn);
}
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_BURN)
2017-09-17 17:14:32 +02:00
{
StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn);
}
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status1 & STATUS1_FREEZE)
2017-09-17 17:14:32 +02:00
{
StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn);
}
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION)
2017-09-17 17:14:32 +02:00
{
StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn);
}
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].status1 = 0;
gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION);
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattleCommunication[MULTISTRING_CHOOSER] = 0;
gBattlescriptCurrInstr = BattleScript_BerryCureChosenStatusRet;
effect = ITEM_STATUS_CHANGE;
}
break;
case HOLD_EFFECT_RESTORE_STATS:
2017-11-26 11:55:17 +01:00
for (i = 0; i < BATTLE_STATS_NO; i++)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
if (gBattleMons[battlerId].statStages[i] < 6)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gBattleMons[battlerId].statStages[i] = 6;
2017-09-17 17:14:32 +02:00
effect = ITEM_STATS_CHANGE;
}
}
if (effect)
{
2018-02-08 11:17:41 +01:00
gBattleScripting.battler = battlerId;
2018-02-08 12:13:29 +01:00
gPotentialItemEffectBattler = battlerId;
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattlescriptCurrInstr = BattleScript_WhiteHerbRet;
2018-07-28 16:33:01 +02:00
return effect;
2017-09-17 17:14:32 +02:00
}
break;
}
if (effect)
{
2018-02-08 11:17:41 +01:00
gBattleScripting.battler = battlerId;
2018-02-08 12:13:29 +01:00
gPotentialItemEffectBattler = battlerId;
2018-02-08 11:17:41 +01:00
gActiveBattler = battlerId;
2018-02-06 20:48:02 +01:00
BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1);
MarkBattlerForControllerExec(gActiveBattler);
2017-09-17 17:14:32 +02:00
break;
}
}
break;
2018-09-01 20:00:13 +02:00
case ITEMEFFECT_KINGSROCK_SHELLBELL:
2017-09-17 17:14:32 +02:00
if (gBattleMoveDamage)
{
switch (atkHoldEffect)
{
case HOLD_EFFECT_FLINCH:
2018-01-16 22:12:38 +01:00
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
2018-03-01 00:59:52 +01:00
&& TARGET_TURN_DAMAGED
2018-07-16 20:47:30 +02:00
&& (Random() % 100) < atkHoldEffectParam
2017-09-17 17:14:32 +02:00
&& gBattleMoves[gCurrentMove].flags & FLAG_KINGSROCK_AFFECTED
2018-02-06 23:09:39 +01:00
&& gBattleMons[gBattlerTarget].hp)
2017-09-17 17:14:32 +02:00
{
2017-12-02 14:08:55 +01:00
gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_FLINCH;
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
SetMoveEffect(0, 0);
2017-09-22 21:33:49 +02:00
BattleScriptPop();
2017-09-17 17:14:32 +02:00
}
break;
case HOLD_EFFECT_SHELL_BELL:
2018-01-16 22:12:38 +01:00
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
2018-02-07 22:53:40 +01:00
&& gSpecialStatuses[gBattlerTarget].dmg != 0
&& gSpecialStatuses[gBattlerTarget].dmg != 0xFFFF
2018-02-06 23:09:39 +01:00
&& gBattlerAttacker != gBattlerTarget
&& gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP
&& gBattleMons[gBattlerAttacker].hp != 0)
2017-09-17 17:14:32 +02:00
{
gLastUsedItem = atkItem;
2018-02-08 12:13:29 +01:00
gPotentialItemEffectBattler = gBattlerAttacker;
2018-02-06 23:09:39 +01:00
gBattleScripting.battler = gBattlerAttacker;
2018-07-16 20:47:30 +02:00
gBattleMoveDamage = (gSpecialStatuses[gBattlerTarget].dmg / atkHoldEffectParam) * -1;
2017-09-17 17:14:32 +02:00
if (gBattleMoveDamage == 0)
gBattleMoveDamage = -1;
2018-02-07 22:53:40 +01:00
gSpecialStatuses[gBattlerTarget].dmg = 0;
2017-09-22 21:33:49 +02:00
BattleScriptPushCursor();
2017-09-17 17:14:32 +02:00
gBattlescriptCurrInstr = BattleScript_ItemHealHP_Ret;
effect++;
}
break;
}
}
break;
}
return effect;
}
2018-02-08 11:17:41 +01:00
void ClearFuryCutterDestinyBondGrudge(u8 battlerId)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
gDisableStructs[battlerId].furyCutterCounter = 0;
gBattleMons[battlerId].status2 &= ~(STATUS2_DESTINY_BOND);
gStatuses3[battlerId] &= ~(STATUS3_GRUDGE);
2017-09-17 17:14:32 +02:00
}
2017-10-06 17:06:45 +02:00
void HandleAction_RunBattleScript(void) // identical to RunBattleScriptCommands
2017-09-17 17:14:32 +02:00
{
2018-02-06 20:48:02 +01:00
if (gBattleControllerExecFlags == 0)
2017-09-17 17:14:32 +02:00
gBattleScriptingCommandsTable[*gBattlescriptCurrInstr]();
}
2018-03-01 00:59:52 +01:00
u8 GetMoveTarget(u16 move, u8 setTarget)
2017-09-17 17:14:32 +02:00
{
2018-07-01 11:15:42 +02:00
u8 targetBattler = 0;
2017-09-17 17:14:32 +02:00
u8 moveTarget;
u8 side;
2018-03-01 00:59:52 +01:00
if (setTarget)
moveTarget = setTarget - 1;
2017-09-17 17:14:32 +02:00
else
moveTarget = gBattleMoves[move].target;
switch (moveTarget)
{
case MOVE_TARGET_SELECTED:
2018-02-06 23:09:39 +01:00
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
2017-09-17 17:14:32 +02:00
if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp)
2018-07-01 11:15:42 +02:00
targetBattler = gSideTimers[side].followmeTarget;
2017-09-17 17:14:32 +02:00
else
{
2018-02-06 23:09:39 +01:00
side = GetBattlerSide(gBattlerAttacker);
2017-09-17 17:14:32 +02:00
do
{
2018-07-01 11:15:42 +02:00
targetBattler = Random() % gBattlersCount;
} while (targetBattler == gBattlerAttacker || side == GetBattlerSide(targetBattler) || gAbsentBattlerFlags & gBitTable[targetBattler]);
2017-09-17 17:14:32 +02:00
if (gBattleMoves[move].type == TYPE_ELECTRIC
2018-02-06 23:09:39 +01:00
&& AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBattlerAttacker, ABILITY_LIGHTNING_ROD, 0, 0)
2018-07-01 11:15:42 +02:00
&& gBattleMons[targetBattler].ability != ABILITY_LIGHTNING_ROD)
2017-09-17 17:14:32 +02:00
{
2018-07-01 11:15:42 +02:00
targetBattler ^= BIT_FLANK;
RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability);
gSpecialStatuses[targetBattler].lightningRodRedirected = 1;
2017-09-17 17:14:32 +02:00
}
2018-07-22 19:34:13 +02:00
else if (gBattleMoves[move].type == TYPE_WATER
&& AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBattlerAttacker, ABILITY_STORM_DRAIN, 0, 0)
&& gBattleMons[targetBattler].ability != ABILITY_STORM_DRAIN)
{
targetBattler ^= BIT_FLANK;
RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability);
gSpecialStatuses[targetBattler].stormDrainRedirected = 1;
}
2017-09-17 17:14:32 +02:00
}
break;
case MOVE_TARGET_DEPENDS:
case MOVE_TARGET_BOTH:
case MOVE_TARGET_FOES_AND_ALLY:
case MOVE_TARGET_OPPONENTS_FIELD:
2018-07-01 11:15:42 +02:00
targetBattler = GetBattlerAtPosition((GetBattlerPosition(gBattlerAttacker) & BIT_SIDE) ^ BIT_SIDE);
if (gAbsentBattlerFlags & gBitTable[targetBattler])
targetBattler ^= BIT_FLANK;
2017-09-17 17:14:32 +02:00
break;
case MOVE_TARGET_RANDOM:
2018-02-06 23:09:39 +01:00
side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE;
2017-09-17 17:14:32 +02:00
if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp)
2018-07-01 11:15:42 +02:00
targetBattler = gSideTimers[side].followmeTarget;
else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & MOVE_TARGET_RANDOM)
2017-09-17 17:14:32 +02:00
{
2018-02-06 23:09:39 +01:00
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER)
2017-09-17 17:14:32 +02:00
{
if (Random() & 1)
2018-07-01 11:15:42 +02:00
targetBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT);
2017-09-17 17:14:32 +02:00
else
2018-07-01 11:15:42 +02:00
targetBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
2017-09-17 17:14:32 +02:00
}
else
{
if (Random() & 1)
2018-07-01 11:15:42 +02:00
targetBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
2017-09-17 17:14:32 +02:00
else
2018-07-01 11:15:42 +02:00
targetBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
2017-09-17 17:14:32 +02:00
}
2018-07-01 11:15:42 +02:00
if (gAbsentBattlerFlags & gBitTable[targetBattler])
targetBattler ^= BIT_FLANK;
2017-09-17 17:14:32 +02:00
}
else
2018-07-01 11:15:42 +02:00
targetBattler = GetBattlerAtPosition((GetBattlerPosition(gBattlerAttacker) & BIT_SIDE) ^ BIT_SIDE);
2017-09-17 17:14:32 +02:00
break;
2018-02-26 13:24:46 +01:00
case MOVE_TARGET_USER_OR_SELECTED:
case MOVE_TARGET_USER:
2018-07-01 11:15:42 +02:00
targetBattler = gBattlerAttacker;
2017-09-17 17:14:32 +02:00
break;
}
2018-07-01 11:15:42 +02:00
*(gBattleStruct->moveTarget + gBattlerAttacker) = targetBattler;
2017-09-17 17:14:32 +02:00
2018-07-01 11:15:42 +02:00
return targetBattler;
2017-09-17 17:14:32 +02:00
}
2018-02-08 11:17:41 +01:00
static bool32 HasObedientBitSet(u8 battlerId)
2017-09-17 17:14:32 +02:00
{
2018-02-08 11:17:41 +01:00
if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
2017-09-17 17:14:32 +02:00
return TRUE;
2018-02-08 11:17:41 +01:00
if (GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES, NULL) != SPECIES_DEOXYS
&& GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES, NULL) != SPECIES_MEW)
2017-09-17 17:14:32 +02:00
return TRUE;
2018-02-08 11:17:41 +01:00
return GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_OBEDIENCE, NULL);
2017-09-17 17:14:32 +02:00
}
2017-12-02 14:08:55 +01:00
u8 IsMonDisobedient(void)
2017-09-17 17:14:32 +02:00
{
s32 rnd;
s32 calc;
u8 obedienceLevel = 0;
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_x2000000))
return 0;
2018-02-06 23:09:39 +01:00
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT)
2017-09-17 17:14:32 +02:00
return 0;
2018-02-06 23:09:39 +01:00
if (HasObedientBitSet(gBattlerAttacker)) // only if species is Mew or Deoxys
2017-09-17 17:14:32 +02:00
{
2018-02-06 23:09:39 +01:00
if (gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER && GetBattlerPosition(gBattlerAttacker) == 2)
2017-09-17 17:14:32 +02:00
return 0;
if (gBattleTypeFlags & BATTLE_TYPE_FRONTIER)
return 0;
if (gBattleTypeFlags & BATTLE_TYPE_RECORDED)
return 0;
2018-02-06 23:09:39 +01:00
if (!IsOtherTrainer(gBattleMons[gBattlerAttacker].otId, gBattleMons[gBattlerAttacker].otName))
2017-09-17 17:14:32 +02:00
return 0;
2017-11-08 22:20:10 +01:00
if (FlagGet(FLAG_BADGE08_GET))
2017-09-17 17:14:32 +02:00
return 0;
obedienceLevel = 10;
2017-11-08 22:20:10 +01:00
if (FlagGet(FLAG_BADGE02_GET))
2017-09-17 17:14:32 +02:00
obedienceLevel = 30;
2017-11-08 22:20:10 +01:00
if (FlagGet(FLAG_BADGE04_GET))
2017-09-17 17:14:32 +02:00
obedienceLevel = 50;
2017-11-08 22:20:10 +01:00
if (FlagGet(FLAG_BADGE06_GET))
2017-09-17 17:14:32 +02:00
obedienceLevel = 70;
}
2018-02-06 23:09:39 +01:00
if (gBattleMons[gBattlerAttacker].level <= obedienceLevel)
2017-09-17 17:14:32 +02:00
return 0;
rnd = (Random() & 255);
2018-02-06 23:09:39 +01:00
calc = (gBattleMons[gBattlerAttacker].level + obedienceLevel) * rnd >> 8;
2017-09-17 17:14:32 +02:00
if (calc < obedienceLevel)
return 0;
// is not obedient
if (gCurrentMove == MOVE_RAGE)
2018-02-06 23:09:39 +01:00
gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_RAGE);
if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP && (gCurrentMove == MOVE_SNORE || gCurrentMove == MOVE_SLEEP_TALK))
2017-09-17 17:14:32 +02:00
{
2018-09-01 20:00:13 +02:00
gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep;
2017-09-17 17:14:32 +02:00
return 1;
}
rnd = (Random() & 255);
2018-02-06 23:09:39 +01:00
calc = (gBattleMons[gBattlerAttacker].level + obedienceLevel) * rnd >> 8;
2017-09-17 17:14:32 +02:00
if (calc < obedienceLevel)
{
2018-02-06 23:09:39 +01:00
calc = CheckMoveLimitations(gBattlerAttacker, gBitTable[gCurrMovePos], 0xFF);
2017-09-17 17:14:32 +02:00
if (calc == 0xF) // all moves cannot be used
{
gBattleCommunication[MULTISTRING_CHOOSER] = Random() & 3;
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
return 1;
}
else // use a random move
{
do
{
2018-02-08 11:17:41 +01:00
gCurrMovePos = gChosenMovePos = Random() & 3;
2017-09-17 17:14:32 +02:00
} while (gBitTable[gCurrMovePos] & calc);
2018-02-06 23:09:39 +01:00
gRandomMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos];
2017-11-26 17:15:28 +01:00
gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove;
2018-02-06 23:09:39 +01:00
gBattlerTarget = GetMoveTarget(gRandomMove, 0);
2017-09-17 17:14:32 +02:00
gHitMarker |= HITMARKER_x200000;
return 2;
}
}
else
{
2018-02-06 23:09:39 +01:00
obedienceLevel = gBattleMons[gBattlerAttacker].level - obedienceLevel;
2017-09-17 17:14:32 +02:00
calc = (Random() & 255);
2018-02-06 23:09:39 +01:00
if (calc < obedienceLevel && !(gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY) && gBattleMons[gBattlerAttacker].ability != ABILITY_VITAL_SPIRIT && gBattleMons[gBattlerAttacker].ability != ABILITY_INSOMNIA)
2017-09-17 17:14:32 +02:00
{
// try putting asleep
int i;
2018-02-06 02:46:59 +01:00
for (i = 0; i < gBattlersCount; i++)
2017-09-17 17:14:32 +02:00
{
if (gBattleMons[i].status2 & STATUS2_UPROAR)
break;
}
2018-02-06 02:46:59 +01:00
if (i == gBattlersCount)
2017-09-17 17:14:32 +02:00
{
2017-11-26 17:15:28 +01:00
gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep;
2017-09-17 17:14:32 +02:00
return 1;
}
}
calc -= obedienceLevel;
if (calc < obedienceLevel)
{
2018-07-14 22:56:03 +02:00
gBattleMoveDamage = CalculateMoveDamage(MOVE_NONE, gBattlerAttacker, gBattlerAttacker, TYPE_MYSTERY, 40, FALSE, FALSE);
2018-02-06 23:09:39 +01:00
gBattlerTarget = gBattlerAttacker;
2018-09-01 20:00:13 +02:00
gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself;
2017-09-17 17:14:32 +02:00
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
return 2;
}
else
{
gBattleCommunication[MULTISTRING_CHOOSER] = Random() & 3;
gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround;
return 1;
}
}
}
2018-07-14 16:41:14 +02:00
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;
2018-07-18 22:07:48 +02:00
else if (gStatuses3[battlerId] & STATUS3_MAGNET_RISE)
return FALSE;
2018-07-14 16:41:14 +02:00
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;
}
}
2018-07-14 19:29:25 +02:00
2018-07-14 22:56:03 +02:00
static void MulModifier(u16 *modifier, u16 val)
{
*modifier = UQ_4_12_TO_INT((*modifier * val) + UQ_4_12_ROUND);
}
static u32 ApplyModifier(u16 modifier, u32 val)
{
return UQ_4_12_TO_INT((modifier * val) + UQ_4_12_ROUND);
}
static u16 CalcMoveBasePower(u16 move, u8 battlerAtk, u8 battlerDef)
{
u32 i;
u16 basePower = gBattleMoves[move].power;
u32 weight, hpFraction, speed;
switch (gBattleMoves[move].effect)
{
case EFFECT_PLEDGE:
// todo
break;
case EFFECT_FLING:
// todo
break;
case EFFECT_ERUPTION:
basePower = gBattleMons[battlerAtk].hp * basePower / gBattleMons[battlerAtk].maxHP;
break;
case EFFECT_FLAIL:
hpFraction = GetScaledHPFraction(gBattleMons[battlerAtk].hp, gBattleMons[battlerAtk].maxHP, 48);
for (i = 0; i < sizeof(sFlailHpScaleToPowerTable); i += 2)
{
if (hpFraction <= sFlailHpScaleToPowerTable[i])
break;
}
basePower = sFlailHpScaleToPowerTable[i + 1];
break;
case EFFECT_RETURN:
basePower = 10 * (gBattleMons[battlerAtk].friendship) / 25;
break;
case EFFECT_FRUSTRATION:
basePower = 10 * (255 - gBattleMons[battlerAtk].friendship) / 25;
break;
case EFFECT_FURY_CUTTER:
for (i = 1; i < gDisableStructs[battlerAtk].furyCutterCounter; i++)
basePower *= 2;
break;
case EFFECT_ROLLOUT:
for (i = 1; i < (5 - gDisableStructs[battlerAtk].rolloutCounter1); i++)
basePower *= 2;
if (gBattleMons[battlerAtk].status2 & STATUS2_DEFENSE_CURL)
basePower *= 2;
break;
case EFFECT_MAGNITUDE:
basePower = gBattleStruct->magnitudeBasePower;
break;
case EFFECT_PRESENT:
basePower = gBattleStruct->presentBasePower;
break;
case EFFECT_TRIPLE_KICK:
basePower += gBattleScripting.tripleKickPower;
break;
case EFFECT_SPIT_UP:
basePower = 100 * gDisableStructs[battlerAtk].stockpileCounter;
break;
case EFFECT_REVENGE:
if ((gProtectStructs[battlerAtk].physicalDmg
&& gProtectStructs[battlerAtk].physicalBattlerId == battlerDef)
|| (gProtectStructs[battlerAtk].specialDmg
&& gProtectStructs[battlerAtk].specialBattlerId == battlerDef))
basePower *= 2;
break;
case EFFECT_WEATHER_BALL:
if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_ANY)
basePower *= 2;
break;
case EFFECT_PURSUIT:
if (gCurrentActionFuncId == B_ACTION_SWITCH)
basePower *= 2;
break;
case EFFECT_NATURAL_GIFT:
// todo
break;
case EFFECT_WAKE_UP_SLAP:
if (gBattleMons[battlerDef].status1 & STATUS1_SLEEP)
basePower *= 2;
break;
case EFFECT_SMELLINGSALT:
if (gBattleMons[battlerDef].status1 & STATUS1_PARALYSIS)
basePower *= 2;
break;
case EFFECT_WRING_OUT:
basePower = 120 * gBattleMons[battlerDef].hp / gBattleMons[battlerDef].maxHP;
break;
case EFFECT_HEX:
if (gBattleMons[battlerDef].status1 & STATUS1_ANY)
basePower *= 2;
break;
case EFFECT_ASSURANCE:
if (gSpecialStatuses[battlerDef].physicalDmg != 0 || gSpecialStatuses[battlerDef].specialDmg != 0)
basePower *= 2;
break;
case EFFECT_TRUMP_CARD:
i = GetBattleMonMoveSlot(&gBattleMons[battlerAtk], move);
if (i != 4)
{
switch (gBattleMons[battlerAtk].pp[i])
{
case 0:
basePower = 200;
break;
case 1:
basePower = 80;
break;
case 2:
basePower = 60;
break;
case 3:
basePower = 50;
break;
default:
basePower = 40;
break;
}
}
break;
case EFFECT_ACROBATICS:
if (gBattleMons[battlerAtk].item == ITEM_NONE)
basePower *= 2;
break;
case EFFECT_LOW_KICK:
weight = GetBattlerWeight(battlerDef);
for (i = 0; sWeightToDamageTable[i] != 0xFFFF; i += 2)
{
if (sWeightToDamageTable[i] > weight)
break;
}
if (sWeightToDamageTable[i] != 0xFFFF)
basePower = sWeightToDamageTable[i + 1];
else
basePower = 120;
break;
case EFFECT_HEAT_CRASH:
weight = GetBattlerWeight(battlerAtk) / GetBattlerWeight(battlerDef);
if (weight >= 5)
basePower = 120;
else if (weight == 4)
basePower = 100;
else if (weight == 3)
basePower = 80;
else if (weight == 2)
basePower = 60;
else
basePower = 40;
break;
case EFFECT_PUNISHMENT:
basePower = 60 + (CountBattlerStatIncreases(battlerAtk, FALSE) * 20);
if (basePower > 200)
basePower = 200;
break;
case EFFECT_STORED_POWER:
basePower = 60 + (CountBattlerStatIncreases(battlerAtk, TRUE) * 20);
break;
case EFFECT_ELECTRO_BALL:
speed = GetBattlerTotalSpeedStat(battlerAtk) / GetBattlerTotalSpeedStat(battlerDef);
if (speed >= ARRAY_COUNT(sSpeedDiffToDmgTable))
speed = ARRAY_COUNT(sSpeedDiffToDmgTable) - 1;
basePower = sSpeedDiffToDmgTable[speed];
break;
case EFFECT_GYRO_BALL:
basePower = ((25 * GetBattlerTotalSpeedStat(battlerDef)) / GetBattlerTotalSpeedStat(battlerAtk)) + 1;
if (basePower > 150)
basePower = 150;
break;
case EFFECT_ECHOED_VOICE:
if (gFieldTimers.echoVoiceCounter != 0)
{
if (gFieldTimers.echoVoiceCounter >= 5)
basePower *= 5;
else
basePower *= gFieldTimers.echoVoiceCounter;
}
break;
case EFFECT_PAYBACK:
if (GetBattlerTurnOrderNum(battlerAtk) > GetBattlerTurnOrderNum(battlerDef))
basePower *= 2;
break;
case EFFECT_GUST:
case EFFECT_TWISTER:
if (gStatuses3[battlerDef] & STATUS3_ON_AIR)
basePower *= 2;
break;
case EFFECT_ROUND:
if (gChosenMoveByBattler[BATTLE_PARTNER(battlerAtk)] == MOVE_ROUND && !(gAbsentBattlerFlags & gBitTable[BATTLE_PARTNER(battlerAtk)]))
basePower *= 2;
break;
}
if (basePower == 0)
basePower = 1;
return basePower;
}
static u32 CalcMoveBasePowerAfterModifiers(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType)
{
u32 i;
u32 holdEffectAtk, holdEffectParamAtk;
u16 basePower = CalcMoveBasePower(move, battlerAtk, battlerDef);
u16 holdEffectModifier;
u16 modifier = UQ_4_12(1.0);
// attacker's abilities
switch (GetBattlerAbility(battlerAtk))
{
case ABILITY_TECHNICIAN:
if (basePower <= 60)
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_FLARE_BOOST:
if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && IS_MOVE_SPECIAL(move))
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_TOXIC_BOOST:
if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY && IS_MOVE_PHYSICAL(move))
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_RECKLESS:
if (gBattleMoves[move].flags & FLAG_RECKLESS_BOOST)
MulModifier(&modifier, UQ_4_12(1.2));
break;
case ABILITY_IRON_FIST:
if (gBattleMoves[move].flags & FLAG_IRON_FIST_BOOST)
MulModifier(&modifier, UQ_4_12(1.2));
break;
case ABILITY_SHEER_FORCE:
if (gBattleMoves[move].flags & FLAG_SHEER_FORCE_BOOST)
MulModifier(&modifier, UQ_4_12(1.3));
break;
case ABILITY_SAND_FORCE:
if (moveType == TYPE_STEEL || moveType == TYPE_ROCK || moveType == TYPE_GROUND)
MulModifier(&modifier, UQ_4_12(1.3));
break;
case ABILITY_RIVALRY:
if (GetGenderFromSpeciesAndPersonality(gBattleMons[battlerAtk].species, gBattleMons[battlerAtk].personality) != MON_GENDERLESS
&& GetGenderFromSpeciesAndPersonality(gBattleMons[battlerDef].species, gBattleMons[battlerDef].personality) != MON_GENDERLESS)
{
if (GetGenderFromSpeciesAndPersonality(gBattleMons[battlerAtk].species, gBattleMons[battlerAtk].personality)
== GetGenderFromSpeciesAndPersonality(gBattleMons[battlerDef].species, gBattleMons[battlerDef].personality))
MulModifier(&modifier, UQ_4_12(1.25));
else
MulModifier(&modifier, UQ_4_12(0.75));
}
break;
case ABILITY_ANALYTIC:
if (GetBattlerTurnOrderNum(battlerAtk) == gBattlersCount - 1 && move != MOVE_FUTURE_SIGHT && move != MOVE_DOOM_DESIRE)
MulModifier(&modifier, UQ_4_12(1.3));
break;
case ABILITY_TOUGH_CLAWS:
if (gBattleMoves[move].flags & FLAG_MAKES_CONTACT)
MulModifier(&modifier, UQ_4_12(1.3));
break;
case ABILITY_STRONG_JAW:
if (gBattleMoves[move].flags & FLAG_STRONG_JAW_BOOST)
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_MEGA_LAUNCHER:
if (gBattleMoves[move].flags & FLAG_MEGA_LAUNCHER_BOOST)
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_WATER_BUBBLE:
if (moveType == TYPE_WATER)
MulModifier(&modifier, UQ_4_12(2.0));
break;
case ABILITY_STEELWORKER:
if (moveType == TYPE_STEEL)
MulModifier(&modifier, UQ_4_12(1.5));
break;
2018-07-28 18:41:57 +02:00
case ABILITY_PIXILATE:
if (moveType == TYPE_FAIRY && gBattleStruct->ateBoost[battlerAtk])
MulModifier(&modifier, UQ_4_12(1.2));
break;
case ABILITY_GALVANIZE:
if (moveType == TYPE_ELECTRIC && gBattleStruct->ateBoost[battlerAtk])
MulModifier(&modifier, UQ_4_12(1.2));
break;
case ABILITY_REFRIGERATE:
if (moveType == TYPE_ICE && gBattleStruct->ateBoost[battlerAtk])
MulModifier(&modifier, UQ_4_12(1.2));
break;
case ABILITY_AERILATE:
if (moveType == TYPE_FLYING && gBattleStruct->ateBoost[battlerAtk])
MulModifier(&modifier, UQ_4_12(1.2));
break;
case ABILITY_NORMALIZE:
if (moveType == TYPE_NORMAL && gBattleStruct->ateBoost[battlerAtk])
MulModifier(&modifier, UQ_4_12(1.2));
break;
2018-07-14 22:56:03 +02:00
}
// field abilities
if ((ABILITY_ON_FIELD(ABILITY_DARK_AURA) && moveType == TYPE_DARK)
|| (ABILITY_ON_FIELD(ABILITY_FAIRY_AURA) && moveType == TYPE_FAIRY))
{
if (ABILITY_ON_FIELD(ABILITY_AURA_BREAK))
MulModifier(&modifier, UQ_4_12(0.75));
else
MulModifier(&modifier, UQ_4_12(1.25));
}
// attacker partner's abilities
if (IsBattlerAlive(BATTLE_PARTNER(battlerAtk)))
{
switch (GetBattlerAbility(BATTLE_PARTNER(battlerAtk)))
{
case ABILITY_BATTERY:
if (IS_MOVE_SPECIAL(move))
MulModifier(&modifier, UQ_4_12(1.3));
break;
}
}
// target's abilities
switch (GetBattlerAbility(battlerDef))
{
case ABILITY_HEATPROOF:
case ABILITY_WATER_BUBBLE:
if (moveType == TYPE_FIRE)
MulModifier(&modifier, UQ_4_12(0.5));
break;
case ABILITY_DRY_SKIN:
if (moveType == TYPE_FIRE)
MulModifier(&modifier, UQ_4_12(1.25));
break;
case ABILITY_FLUFFY:
if (IsMoveMakingContact(move, battlerAtk))
MulModifier(&modifier, UQ_4_12(0.5));
if (moveType == TYPE_FIRE)
MulModifier(&modifier, UQ_4_12(2.0));
break;
}
holdEffectAtk = GetBattlerHoldEffect(battlerAtk, TRUE);
holdEffectParamAtk = GetBattlerHoldEffectParam(battlerAtk);
if (holdEffectParamAtk > 100)
holdEffectParamAtk = 100;
holdEffectModifier = UQ_4_12(1.0) + sPercentToModifier[holdEffectParamAtk];
// attacker's hold effect
switch (holdEffectAtk)
{
case HOLD_EFFECT_MUSCLE_BAND:
if (IS_MOVE_PHYSICAL(move))
MulModifier(&modifier, holdEffectModifier);
break;
case HOLD_EFFECT_WISE_GLASSES:
if (IS_MOVE_SPECIAL(move))
MulModifier(&modifier, holdEffectModifier);
break;
case HOLD_EFFECT_LUSTROUS_ORB:
if (gBattleMons[battlerAtk].species == SPECIES_PALKIA && (moveType == TYPE_WATER || moveType == TYPE_DRAGON))
MulModifier(&modifier, holdEffectModifier);
break;
case HOLD_EFFECT_ADAMANT_ORB:
if (gBattleMons[battlerAtk].species == SPECIES_DIALGA && (moveType == TYPE_STEEL || moveType == TYPE_DRAGON))
MulModifier(&modifier, holdEffectModifier);
break;
case HOLD_EFFECT_GRISEOUS_ORB:
if (gBattleMons[battlerAtk].species == SPECIES_GIRATINA && (moveType == TYPE_GHOST || moveType == TYPE_DRAGON))
MulModifier(&modifier, holdEffectModifier);
break;
case HOLD_EFFECT_SOUL_DEW:
if ((gBattleMons[battlerAtk].species == SPECIES_LATIAS || gBattleMons[battlerAtk].species == SPECIES_LATIOS) && !(gBattleTypeFlags & BATTLE_TYPE_FRONTIER))
MulModifier(&modifier, holdEffectModifier);
break;
case HOLD_EFFECT_BUG_POWER:
case HOLD_EFFECT_STEEL_POWER:
case HOLD_EFFECT_GROUND_POWER:
case HOLD_EFFECT_ROCK_POWER:
case HOLD_EFFECT_GRASS_POWER:
case HOLD_EFFECT_DARK_POWER:
case HOLD_EFFECT_FIGHTING_POWER:
case HOLD_EFFECT_ELECTRIC_POWER:
case HOLD_EFFECT_WATER_POWER:
case HOLD_EFFECT_FLYING_POWER:
case HOLD_EFFECT_POISON_POWER:
case HOLD_EFFECT_ICE_POWER:
case HOLD_EFFECT_GHOST_POWER:
case HOLD_EFFECT_PSYCHIC_POWER:
case HOLD_EFFECT_FIRE_POWER:
case HOLD_EFFECT_DRAGON_POWER:
case HOLD_EFFECT_NORMAL_POWER:
case HOLD_EFFECT_FAIRY_POWER:
for (i = 0; i < ARRAY_COUNT(sHoldEffectToType); i++)
{
if (holdEffectAtk == sHoldEffectToType[i][0])
{
if (moveType == sHoldEffectToType[i][1])
MulModifier(&modifier, holdEffectModifier);
break;
}
}
break;
}
// move effect
switch (gBattleMoves[move].effect)
{
case EFFECT_FACADE:
if (gBattleMons[battlerAtk].status1 & (STATUS1_BURN | STATUS1_PSN_ANY | STATUS1_PARALYSIS))
MulModifier(&modifier, UQ_4_12(2.0));
break;
case EFFECT_BRINE:
if (gBattleMons[battlerAtk].hp <= (gBattleMons[battlerAtk].maxHP / 2))
MulModifier(&modifier, UQ_4_12(2.0));
break;
case EFFECT_VENOSHOCK:
if (gBattleMons[battlerAtk].status1 & STATUS1_PSN_ANY)
MulModifier(&modifier, UQ_4_12(2.0));
break;
case EFFECT_RETALITATE:
// todo
break;
case EFFECT_SOLARBEAM:
if (WEATHER_HAS_EFFECT && gBattleWeather & (WEATHER_HAIL_ANY | WEATHER_SANDSTORM_ANY | WEATHER_RAIN_ANY))
MulModifier(&modifier, UQ_4_12(0.5));
break;
case EFFECT_BULLDOZE:
case EFFECT_MAGNITUDE:
case EFFECT_EARTHQUAKE:
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && IsBattlerGrounded(battlerDef))
MulModifier(&modifier, UQ_4_12(0.5));
break;
case EFFECT_KNOCK_OFF:
if (gBattleMons[battlerDef].item != ITEM_NONE && GetBattlerAbility(battlerDef) != ABILITY_STICKY_HOLD)
MulModifier(&modifier, UQ_4_12(1.5));
break;
}
// various effecs
if (gProtectStructs[battlerAtk].helpingHand)
MulModifier(&modifier, UQ_4_12(1.5));
if (gStatuses3[battlerAtk] & STATUS3_CHARGED_UP && moveType == TYPE_ELECTRIC)
MulModifier(&modifier, UQ_4_12(2.0));
if (gStatuses3[battlerAtk] & STATUS3_ME_FIRST)
MulModifier(&modifier, UQ_4_12(1.5));
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && moveType == TYPE_GRASS && IsBattlerGrounded(battlerAtk))
MulModifier(&modifier, UQ_4_12(1.5));
if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN && moveType == TYPE_DRAGON && IsBattlerGrounded(battlerDef))
MulModifier(&modifier, UQ_4_12(0.5));
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN && moveType == TYPE_ELECTRIC && IsBattlerGrounded(battlerAtk))
MulModifier(&modifier, UQ_4_12(1.5));
if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN && moveType == TYPE_PSYCHIC && IsBattlerGrounded(battlerAtk))
MulModifier(&modifier, UQ_4_12(1.5));
return ApplyModifier(modifier, basePower);
}
static u32 CalcAttackStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, bool32 isCrit)
{
u8 atkStage;
u32 atkStat;
u16 modifier;
if (gBattleMoves[move].effect == EFFECT_FOUL_PLAY)
{
if (IS_MOVE_PHYSICAL(move))
atkStat = gBattleMons[battlerDef].attack;
else
atkStat = gBattleMons[battlerDef].spAttack;
atkStage = gBattleMons[battlerDef].statStages[STAT_ATK];
}
else
{
if (IS_MOVE_PHYSICAL(move))
atkStat = gBattleMons[battlerAtk].attack;
else
atkStat = gBattleMons[battlerAtk].spAttack;
2018-08-11 12:16:00 +02:00
atkStage = gBattleMons[battlerAtk].statStages[STAT_SPATK];
2018-07-14 22:56:03 +02:00
}
// critical hits ignore attack stat's stage drops
if (isCrit && atkStage < 6)
atkStage = 6;
// pokemon with unaware ignore attack stat changes while taking damage
if (GetBattlerAbility(battlerDef) == ABILITY_UNAWARE)
atkStage = 6;
atkStat *= gStatStageRatios[atkStage][0];
atkStat /= gStatStageRatios[atkStage][1];
// apply attack stat modifiers
modifier = UQ_4_12(1.0);
// attacker's abilities
switch (GetBattlerAbility(battlerAtk))
{
case ABILITY_HUGE_POWER:
case ABILITY_PURE_POWER:
if (IS_MOVE_PHYSICAL(move))
MulModifier(&modifier, UQ_4_12(2.0));
break;
case ABILITY_SLOW_START:
if (gDisableStructs[battlerAtk].slowStartTimer != 0)
MulModifier(&modifier, UQ_4_12(0.5));
break;
case ABILITY_SOLAR_POWER:
if (IS_MOVE_SPECIAL(move) && WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY)
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_DEFEATIST:
if (gBattleMons[battlerAtk].hp <= (gBattleMons[battlerDef].maxHP / 2))
MulModifier(&modifier, UQ_4_12(0.5));
break;
case ABILITY_FLASH_FIRE:
2018-07-19 21:18:20 +02:00
if (moveType == TYPE_FIRE && gBattleResources->flags->flags[battlerAtk] & RESOURCE_FLAG_FLASH_FIRE)
2018-07-14 22:56:03 +02:00
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_SWARM:
if (moveType == TYPE_BUG && gBattleMons[battlerAtk].hp <= (gBattleMons[battlerAtk].maxHP / 3))
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_TORRENT:
if (moveType == TYPE_WATER && gBattleMons[battlerAtk].hp <= (gBattleMons[battlerAtk].maxHP / 3))
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_BLAZE:
if (moveType == TYPE_FIRE && gBattleMons[battlerAtk].hp <= (gBattleMons[battlerAtk].maxHP / 3))
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_OVERGROW:
if (moveType == TYPE_GRASS && gBattleMons[battlerAtk].hp <= (gBattleMons[battlerAtk].maxHP / 3))
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_PLUS:
case ABILITY_MINUS:
if (IsBattlerAlive(BATTLE_PARTNER(battlerAtk)))
{
u32 partnerAbility = GetBattlerAbility(BATTLE_PARTNER(battlerAtk));
if (partnerAbility == ABILITY_PLUS || partnerAbility == ABILITY_MINUS)
MulModifier(&modifier, UQ_4_12(1.5));
}
break;
case ABILITY_FLOWER_GIFT:
if (gBattleMons[battlerAtk].species == SPECIES_CHERRIM && WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY)
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_HUSTLE:
if (IS_MOVE_PHYSICAL(move))
MulModifier(&modifier, UQ_4_12(1.5));
break;
}
// target's abilities
switch (GetBattlerAbility(battlerDef))
{
case ABILITY_THICK_FAT:
if (moveType == TYPE_FIRE || moveType == TYPE_ICE)
MulModifier(&modifier, UQ_4_12(0.5));
break;
}
// ally's abilities
if (IsBattlerAlive(BATTLE_PARTNER(battlerAtk)))
{
switch (GetBattlerAbility(BATTLE_PARTNER(battlerAtk)))
{
case ABILITY_FLOWER_GIFT:
if (gBattleMons[BATTLE_PARTNER(battlerAtk)].species == SPECIES_CHERRIM)
MulModifier(&modifier, UQ_4_12(1.5));
break;
}
}
// attacker's hold effect
switch (GetBattlerHoldEffect(battlerAtk, TRUE))
{
case HOLD_EFFECT_THICK_CLUB:
if ((gBattleMons[battlerAtk].species == SPECIES_CUBONE || gBattleMons[battlerAtk].species == SPECIES_MAROWAK) && IS_MOVE_PHYSICAL(move))
MulModifier(&modifier, UQ_4_12(2.0));
break;
case HOLD_EFFECT_DEEP_SEA_TOOTH:
if (gBattleMons[battlerAtk].species == SPECIES_CLAMPERL && IS_MOVE_SPECIAL(move))
MulModifier(&modifier, UQ_4_12(2.0));
break;
case HOLD_EFFECT_LIGHT_BALL:
if (gBattleMons[battlerAtk].species == SPECIES_PIKACHU)
MulModifier(&modifier, UQ_4_12(2.0));
break;
case HOLD_EFFECT_CHOICE_BAND:
if (IS_MOVE_PHYSICAL(move))
MulModifier(&modifier, UQ_4_12(1.5));
break;
case HOLD_EFFECT_CHOICE_SPECS:
if (IS_MOVE_SPECIAL(move))
MulModifier(&modifier, UQ_4_12(1.5));
break;
}
return ApplyModifier(modifier, atkStat);
}
static u32 CalcDefenseStat(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, bool32 isCrit)
{
bool32 usesDefStat;
u8 defStage;
u32 defStat, def, spDef;
u16 modifier;
if (gFieldStatuses & STATUS_FIELD_WONDER_ROOM) // the defense stats are swapped
{
def = gBattleMons[battlerDef].spDefense;
spDef = gBattleMons[battlerDef].defense;
}
else
{
def = gBattleMons[battlerDef].defense;
spDef = gBattleMons[battlerDef].spDefense;
}
if (gBattleMoves[move].effect == EFFECT_PSYSHOCK || IS_MOVE_PHYSICAL(move)) // uses defense stat instead of sp.def
{
defStat = def;
defStage = gBattleMons[battlerDef].statStages[STAT_DEF];
usesDefStat = TRUE;
}
else // is special
{
defStat = spDef;
defStage = gBattleMons[battlerDef].statStages[STAT_SPDEF];
usesDefStat = FALSE;
}
// critical hits ignore positive stat changes
if (isCrit && defStage > 6)
defStage = 6;
// pokemon with unaware ignore defense stat changes while dealing damage
if (GetBattlerAbility(battlerAtk) == ABILITY_UNAWARE)
defStage = 6;
// certain moves also ignore stat changes
if (gBattleMoves[move].flags & FLAG_STAT_STAGES_IGNORED)
defStage = 6;
defStat *= gStatStageRatios[defStage][0];
defStat /= gStatStageRatios[defStage][1];
// apply defense stat modifiers
modifier = UQ_4_12(1.0);
// target's abilities
switch (GetBattlerAbility(battlerDef))
{
case ABILITY_MARVEL_SCALE:
if (gBattleMons[battlerDef].status1 & STATUS1_ANY && usesDefStat)
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_FUR_COAT:
if (usesDefStat)
MulModifier(&modifier, UQ_4_12(2.0));
break;
case ABILITY_GRASS_PELT:
if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN && usesDefStat)
MulModifier(&modifier, UQ_4_12(1.5));
break;
case ABILITY_FLOWER_GIFT:
if (gBattleMons[battlerDef].species == SPECIES_CHERRIM && WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY && !usesDefStat)
MulModifier(&modifier, UQ_4_12(1.5));
break;
}
// ally's abilities
if (IsBattlerAlive(BATTLE_PARTNER(battlerDef)))
{
switch (GetBattlerAbility(BATTLE_PARTNER(battlerDef)))
{
case ABILITY_FLOWER_GIFT:
if (gBattleMons[BATTLE_PARTNER(battlerDef)].species == SPECIES_CHERRIM && !usesDefStat)
MulModifier(&modifier, UQ_4_12(1.5));
break;
}
}
// target's hold effects
switch (GetBattlerHoldEffect(battlerDef, TRUE))
{
case HOLD_EFFECT_DEEP_SEA_SCALE:
if (gBattleMons[battlerDef].species == SPECIES_CLAMPERL && !usesDefStat)
MulModifier(&modifier, UQ_4_12(2.0));
break;
case HOLD_EFFECT_METAL_POWDER:
if (gBattleMons[battlerDef].species == SPECIES_DITTO && usesDefStat && !(gBattleMons[battlerDef].status2 & STATUS2_TRANSFORMED))
MulModifier(&modifier, UQ_4_12(2.0));
break;
case HOLD_EFFECT_EVIOLITE:
// todo
break;
case HOLD_EFFECT_ASSAULT_VEST:
if (!usesDefStat)
MulModifier(&modifier, UQ_4_12(1.5));
break;
}
return ApplyModifier(modifier, defStat);
}
static u32 CalcFinalDmg(u32 dmg, u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, u16 typeEffectivenessModifier, bool32 isCrit)
{
u32 abilityAtk = GetBattlerAbility(battlerAtk);
u32 abilityDef = GetBattlerAbility(battlerDef);
u32 defSide = GET_BATTLER_SIDE(battlerDef);
u16 finalModifier = UQ_4_12(1.0);
// check multiple targets in double battle
if (GetMoveTargetCount(move, battlerAtk, battlerDef) >= 2)
MulModifier(&finalModifier, UQ_4_12(0.75));
// take type effectiveness
MulModifier(&finalModifier, typeEffectivenessModifier);
// check crit
if (isCrit)
dmg = ApplyModifier(UQ_4_12(1.5), dmg);
// check burn
if (gBattleMons[battlerAtk].status1 & STATUS1_BURN && gBattleMoves[move].effect != EFFECT_FACADE && abilityAtk != ABILITY_GUTS)
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
// check sunny/rain weather
if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_RAIN_ANY)
{
if (moveType == TYPE_FIRE)
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
else if (moveType == TYPE_WATER)
dmg = ApplyModifier(UQ_4_12(1.5), dmg);
}
else if (WEATHER_HAS_EFFECT && gBattleWeather & WEATHER_SUN_ANY)
{
if (moveType == TYPE_FIRE)
dmg = ApplyModifier(UQ_4_12(1.5), dmg);
else if (moveType == TYPE_WATER)
dmg = ApplyModifier(UQ_4_12(0.5), dmg);
}
// check stab
if (IS_BATTLER_OF_TYPE(battlerAtk, moveType) && move != MOVE_STRUGGLE)
{
if (abilityAtk == ABILITY_ADAPTABILITY)
MulModifier(&finalModifier, UQ_4_12(2.0));
else
MulModifier(&finalModifier, UQ_4_12(1.5));
}
// reflect, light screen, aurora veil
if ((gSideStatuses[defSide] & SIDE_STATUS_REFLECT && IS_MOVE_PHYSICAL(move))
|| (gSideStatuses[defSide] & SIDE_STATUS_LIGHTSCREEN && IS_MOVE_SPECIAL(move))
|| (gSideStatuses[defSide] & SIDE_STATUS_AURORA_VEIL))
{
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
MulModifier(&finalModifier, UQ_4_12(0.66));
else
MulModifier(&finalModifier, UQ_4_12(0.5));
}
// attacker's abilities
switch (abilityAtk)
{
case ABILITY_TINTED_LENS:
if (typeEffectivenessModifier <= UQ_4_12(0.5))
MulModifier(&finalModifier, UQ_4_12(2.0));
break;
case ABILITY_SNIPER:
if (isCrit)
MulModifier(&finalModifier, UQ_4_12(1.5));
break;
}
// target's abilities
switch (abilityDef)
{
case ABILITY_MULTISCALE:
if (BATTLER_MAX_HP(battlerDef))
MulModifier(&finalModifier, UQ_4_12(0.5));
break;
case ABILITY_FILTER:
case ABILITY_SOLID_ROCK:
case ABILITY_PRISM_ARMOR:
if (typeEffectivenessModifier >= UQ_4_12(2.0))
MulModifier(&finalModifier, UQ_4_12(0.75));
break;
}
// target's ally's abilities
if (IsBattlerAlive(BATTLE_PARTNER(battlerDef)))
{
switch (GetBattlerAbility(BATTLE_PARTNER(battlerDef)))
{
case ABILITY_FRIEND_GUARD:
MulModifier(&finalModifier, UQ_4_12(0.75));
break;
}
}
// attacker's hold effect
switch (GetBattlerHoldEffect(battlerAtk, TRUE))
{
case HOLD_EFFECT_METRONOME:
// todo
break;
case HOLD_EFFECT_EXPERT_BELT:
if (typeEffectivenessModifier >= UQ_4_12(2.0))
MulModifier(&finalModifier, UQ_4_12(1.2));
break;
case HOLD_EFFECT_LIFE_ORB:
MulModifier(&finalModifier, UQ_4_12(1.3));
break;
}
// target's hold effect
switch (GetBattlerHoldEffect(battlerDef, TRUE))
{
// berries reducing dmg
}
if (gBattleMoves[move].flags & FLAG_DMG_MINIMIZE && gStatuses3[battlerDef] & STATUS3_MINIMIZED)
MulModifier(&finalModifier, UQ_4_12(2.0));
if (gBattleMoves[move].flags & FLAG_DMG_UNDERGROUND && gStatuses3[battlerDef] & STATUS3_UNDERGROUND)
MulModifier(&finalModifier, UQ_4_12(2.0));
if (gBattleMoves[move].flags & FLAG_DMG_UNDERWATER && gStatuses3[battlerDef] & STATUS3_UNDERWATER)
MulModifier(&finalModifier, UQ_4_12(2.0));
dmg = ApplyModifier(finalModifier, dmg);
if (dmg == 0)
dmg = 1;
return dmg;
}
s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit, bool32 randomFactor)
{
s32 dmg;
u16 finalModifier, typeEffectivenessModifier;
typeEffectivenessModifier = CalcTypeEffectivenessMultiplier(move, moveType, battlerAtk, battlerDef, randomFactor);
// Don't calculate damage if the move has no effect on target.
if (typeEffectivenessModifier == UQ_4_12(0))
return 0;
if (fixedBasePower)
gBattleMovePower = fixedBasePower;
else
gBattleMovePower = CalcMoveBasePowerAfterModifiers(move, battlerAtk, battlerDef, moveType);
// long dmg basic formula
dmg = ((gBattleMons[battlerAtk].level * 2) / 5) + 2;
dmg *= gBattleMovePower;
dmg *= CalcAttackStat(move, battlerAtk, battlerDef, moveType, isCrit);
dmg /= CalcDefenseStat(move, battlerAtk, battlerDef, moveType, isCrit);
dmg = (dmg / 50) + 2;
// Calculate final modifiers.
dmg = CalcFinalDmg(dmg, move, battlerAtk, battlerDef, moveType, typeEffectivenessModifier, isCrit);
// Add a random factor.
if (randomFactor)
{
dmg *= 100 - (Random() % 16);
dmg /= 100;
}
if (dmg == 0)
dmg = 1;
return dmg;
}
2018-07-22 19:34:13 +02:00
static inline void MulByTypeEffectiveness(u16 *modifier, u16 move, u8 moveType, u8 battlerDef, u8 defType, u8 atkAblity)
2018-07-14 22:56:03 +02:00
{
u16 mod = sTypeEffectivenessTable[moveType][defType];
if ((moveType == TYPE_FIGHTING || moveType == TYPE_NORMAL) && defType == TYPE_GHOST && gBattleMons[battlerDef].status2 & STATUS2_FORESIGHT)
mod = UQ_4_12(1.0);
2018-07-22 19:34:13 +02:00
if ((moveType == TYPE_FIGHTING || moveType == TYPE_NORMAL) && defType == TYPE_GHOST && atkAblity == ABILITY_SCRAPPY)
mod = UQ_4_12(1.0);
2018-07-14 22:56:03 +02:00
if (moveType == TYPE_PSYCHIC && defType == TYPE_DARK && gStatuses3[battlerDef] & STATUS3_MIRACLE_EYED)
mod = UQ_4_12(1.0);
2018-08-04 23:34:29 +02:00
if (gBattleMoves[move].effect == EFFECT_FREEZE_DRY && defType == TYPE_WATER)
2018-07-14 22:56:03 +02:00
mod = UQ_4_12(2.0);
if (moveType == TYPE_GROUND && defType == TYPE_FLYING && IsBattlerGrounded(battlerDef))
mod = UQ_4_12(1.0);
2018-07-14 22:56:03 +02:00
MulModifier(modifier, mod);
}
2018-07-15 12:39:07 +02:00
static void UpdateMoveResultFlags(u16 modifier)
{
if (modifier == UQ_4_12(0.0))
{
gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE;
gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE);
}
else if (modifier == UQ_4_12(1.0))
{
gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE);
}
else if (modifier > UQ_4_12(1.0))
{
gMoveResultFlags |= MOVE_RESULT_SUPER_EFFECTIVE;
gMoveResultFlags &= ~(MOVE_RESULT_NOT_VERY_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE);
}
else //if (modifier < UQ_4_12(1.0))
{
gMoveResultFlags |= MOVE_RESULT_NOT_VERY_EFFECTIVE;
gMoveResultFlags &= ~(MOVE_RESULT_SUPER_EFFECTIVE | MOVE_RESULT_DOESNT_AFFECT_FOE);
}
}
2018-08-05 13:57:37 +02:00
static u16 CalcTypeEffectivenessMultiplierInternal(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities, u16 modifier)
2018-07-14 19:29:25 +02:00
{
2018-08-05 13:57:37 +02:00
u32 atkAbility = GetBattlerAbility(battlerAtk);
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type1, atkAbility);
if (gBattleMons[battlerDef].type2 != gBattleMons[battlerDef].type1)
MulByTypeEffectiveness(&modifier, move, moveType, battlerDef, gBattleMons[battlerDef].type2, atkAbility);
2018-07-14 22:56:03 +02:00
2018-08-05 13:57:37 +02:00
if (moveType == TYPE_GROUND && !IsBattlerGrounded(battlerDef))
2018-07-14 22:56:03 +02:00
{
2018-08-05 13:57:37 +02:00
modifier = UQ_4_12(0.0);
if (recordAbilities && GetBattlerAbility(battlerDef) == ABILITY_LEVITATE)
2018-07-14 22:56:03 +02:00
{
2018-08-05 13:57:37 +02:00
gLastUsedAbility = ABILITY_LEVITATE;
gMoveResultFlags |= (MOVE_RESULT_MISSED | MOVE_RESULT_DOESNT_AFFECT_FOE);
gLastLandedMoves[battlerDef] = 0;
gBattleCommunication[6] = moveType;
RecordAbilityBattle(battlerDef, ABILITY_LEVITATE);
2018-07-14 22:56:03 +02:00
}
2018-08-05 13:57:37 +02:00
}
if (GetBattlerAbility(battlerDef) == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0) && gBattleMoves[move].power)
{
modifier = UQ_4_12(0.0);
if (recordAbilities)
2018-07-14 22:56:03 +02:00
{
2018-08-05 13:57:37 +02:00
gLastUsedAbility = ABILITY_WONDER_GUARD;
gMoveResultFlags |= MOVE_RESULT_MISSED;
gLastLandedMoves[battlerDef] = 0;
gBattleCommunication[6] = 3;
RecordAbilityBattle(battlerDef, ABILITY_WONDER_GUARD);
2018-07-14 22:56:03 +02:00
}
}
2018-08-05 13:57:37 +02:00
return modifier;
}
u16 CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities)
{
u16 modifier = UQ_4_12(1.0);
if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY)
{
modifier = CalcTypeEffectivenessMultiplierInternal(move, moveType, battlerAtk, battlerDef, recordAbilities, modifier);
if (gBattleMoves[move].effect == EFFECT_TWO_TYPED_MOVE)
modifier = CalcTypeEffectivenessMultiplierInternal(move, gBattleMoves[move].argument, battlerAtk, battlerDef, recordAbilities, modifier);
}
2018-07-15 12:39:07 +02:00
UpdateMoveResultFlags(modifier);
return modifier;
}
u16 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u8 abilityDef)
{
u16 modifier = UQ_4_12(1.0);
u8 moveType = gBattleMoves[move].type;
if (move != MOVE_STRUGGLE && moveType != TYPE_MYSTERY)
2018-07-14 22:56:03 +02:00
{
2018-07-22 19:34:13 +02:00
MulByTypeEffectiveness(&modifier, move, moveType, 0, gBaseStats[speciesDef].type1, ABILITY_NONE);
2018-07-15 12:39:07 +02:00
if (gBaseStats[speciesDef].type2 != gBaseStats[speciesDef].type1)
2018-07-22 19:34:13 +02:00
MulByTypeEffectiveness(&modifier, move, moveType, 0, gBaseStats[speciesDef].type2, ABILITY_NONE);
2018-07-15 12:39:07 +02:00
if (moveType == TYPE_GROUND && abilityDef == ABILITY_LEVITATE && !(gFieldStatuses & STATUS_FIELD_GRAVITY))
modifier = UQ_4_12(0.0);
if (abilityDef == ABILITY_WONDER_GUARD && modifier <= UQ_4_12(1.0) && gBattleMoves[move].power)
modifier = UQ_4_12(0.0);
2018-07-14 22:56:03 +02:00
}
2018-07-14 19:29:25 +02:00
2018-07-15 12:39:07 +02:00
UpdateMoveResultFlags(modifier);
2018-07-14 22:56:03 +02:00
return modifier;
2018-07-14 19:29:25 +02:00
}
2018-07-15 12:39:07 +02:00
u16 GetTypeModifier(u8 atkType, u8 defType)
{
return sTypeEffectivenessTable[atkType][defType];
}
2018-07-24 21:47:00 +02:00
s32 GetStealthHazardDamage(u8 hazardType, u8 battlerId)
{
u8 type1 = gBattleMons[battlerId].type1;
u8 type2 = gBattleMons[battlerId].type2;
u32 maxHp = gBattleMons[battlerId].maxHP;
s32 dmg = 0;
u16 modifier = UQ_4_12(1.0);
MulModifier(&modifier, GetTypeModifier(hazardType, type1));
if (type2 != type1)
MulModifier(&modifier, GetTypeModifier(hazardType, type2));
switch (modifier)
{
case UQ_4_12(0.0):
dmg = 0;
break;
case UQ_4_12(0.25):
dmg = maxHp / 32;
if (dmg == 0)
dmg = 1;
break;
case UQ_4_12(0.5):
dmg = maxHp / 16;
if (dmg == 0)
dmg = 1;
break;
case UQ_4_12(1.0):
dmg = maxHp / 8;
if (dmg == 0)
dmg = 1;
break;
case UQ_4_12(2.0):
dmg = maxHp / 4;
if (dmg == 0)
dmg = 1;
break;
case UQ_4_12(4.0):
dmg = maxHp / 2;
if (dmg == 0)
dmg = 1;
break;
}
return dmg;
}
2018-09-16 18:55:32 +02:00
static bool32 IsPartnerMonFromSameTrainer(u8 battlerId)
{
if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT && gBattleTypeFlags & BATTLE_TYPE_TWO_OPPONENTS)
return FALSE;
else if (GetBattlerSide(battlerId) == B_SIDE_PLAYER && gBattleTypeFlags & BATTLE_TYPE_INGAME_PARTNER)
return FALSE;
else if (gBattleTypeFlags & BATTLE_TYPE_MULTI)
return FALSE;
else
return TRUE;
}
u16 GetMegaEvolutionSpecies(u16 preEvoSpecies, u16 heldItemId)
2018-09-16 18:55:32 +02:00
{
u32 i;
for (i = 0; i < EVOS_PER_MON; i++)
{
if (gEvolutionTable[preEvoSpecies][i].method == EVO_MEGA_EVOLUTION
&& gEvolutionTable[preEvoSpecies][i].param == heldItemId)
return gEvolutionTable[preEvoSpecies][i].targetSpecies;
}
return SPECIES_NONE;
}
bool32 CanMegaEvolve(u8 battlerId)
{
u32 itemId, holdEffect;
struct Pokemon *mon;
2018-09-16 18:55:32 +02:00
u8 battlerPosition = GetBattlerPosition(battlerId);
u8 partnerPosition = GetBattlerPosition(BATTLE_PARTNER(battlerId));
struct MegaEvolutionData *mega = &(((struct ChooseMoveStruct*)(&gBattleBufferA[gActiveBattler][4]))->mega);
2018-09-16 18:55:32 +02:00
// Check if trainer already mega evolved a pokemon.
if (mega->alreadyEvolved[battlerPosition])
2018-09-16 18:55:32 +02:00
return FALSE;
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
{
if (IsPartnerMonFromSameTrainer(battlerId)
&& (mega->alreadyEvolved[partnerPosition] || (mega->toEvolve & gBitTable[BATTLE_PARTNER(battlerId)])))
2018-09-16 18:55:32 +02:00
return FALSE;
}
// Check if the pokemon holds an appropriate item.
if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]];
else
mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]];
itemId = GetMonData(mon, MON_DATA_HELD_ITEM);
if (itemId != ITEM_ENIGMA_BERRY)
holdEffect = ItemId_GetHoldEffect(itemId);
else
holdEffect = gEnigmaBerries[battlerId].holdEffect;
if (holdEffect != HOLD_EFFECT_MEGA_STONE)
2018-09-16 18:55:32 +02:00
return FALSE;
// Check if there is an entry in the evolution table.
if (GetMegaEvolutionSpecies(GetMonData(mon, MON_DATA_SPECIES), itemId) == SPECIES_NONE)
2018-09-16 18:55:32 +02:00
return FALSE;
// All checks passed, the mon CAN mega evolve.
return TRUE;
}
2018-09-16 21:08:49 +02:00
void UndoMegaEvolution(u8 monId)
{
if (gBattleStruct->mega.evolvedPartyIds[B_SIDE_PLAYER] & gBitTable[monId])
2018-09-16 21:08:49 +02:00
{
gBattleStruct->mega.evolvedPartyIds[B_SIDE_PLAYER] &= ~(gBitTable[monId]);
SetMonData(&gPlayerParty[monId], MON_DATA_SPECIES, &gBattleStruct->mega.playerEvolvedSpecies);
2018-09-16 21:08:49 +02:00
CalculateMonStats(&gPlayerParty[monId]);
}
}