mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-11-17 12:07:38 +01:00
284 lines
10 KiB
C
284 lines
10 KiB
C
#include "global.h"
|
|
#include "abilities.h"
|
|
#include "battle.h"
|
|
#include "hold_effects.h"
|
|
#include "event_data.h"
|
|
#include "item.h"
|
|
#include "items.h"
|
|
#include "pokemon.h"
|
|
#include "species.h"
|
|
#include "moves.h"
|
|
#include "battle_move_effects.h"
|
|
|
|
extern u32 gBattleTypeFlags;
|
|
extern struct BattlePokemon gBattleMons[4];
|
|
extern u16 gCurrentMove;
|
|
extern u8 gCritMultiplier;
|
|
extern u16 gBattleWeather;
|
|
extern struct BattleEnigmaBerry gEnigmaBerries[];
|
|
extern u16 gBattleMovePower;
|
|
extern u16 gTrainerBattleOpponent_A;
|
|
|
|
bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 bank);
|
|
|
|
extern const struct BattleMove gBattleMoves[];
|
|
extern const u8 gHoldEffectToType[][2];
|
|
extern const u8 gStatStageRatios[][2];
|
|
|
|
#define APPLY_STAT_MOD(var, mon, stat, statIndex) \
|
|
{ \
|
|
(var) = (stat) * (gStatStageRatios)[(mon)->statStages[(statIndex)]][0]; \
|
|
(var) /= (gStatStageRatios)[(mon)->statStages[(statIndex)]][1]; \
|
|
}
|
|
|
|
s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 move, u16 sideStatus, u16 powerOverride, u8 typeOverride, u8 bankAtk, u8 bankDef)
|
|
{
|
|
u32 i;
|
|
s32 damage = 0;
|
|
s32 damageHelper;
|
|
u8 type;
|
|
u16 attack, defense;
|
|
u16 spAttack, spDefense;
|
|
u8 defenderHoldEffect;
|
|
u8 defenderHoldEffectParam;
|
|
u8 attackerHoldEffect;
|
|
u8 attackerHoldEffectParam;
|
|
|
|
if (!powerOverride)
|
|
gBattleMovePower = gBattleMoves[move].power;
|
|
else
|
|
gBattleMovePower = powerOverride;
|
|
|
|
if (!typeOverride)
|
|
type = gBattleMoves[move].type;
|
|
else
|
|
type = typeOverride & 0x3F;
|
|
|
|
attack = attacker->attack;
|
|
defense = defender->defense;
|
|
spAttack = attacker->spAttack;
|
|
spDefense = defender->spDefense;
|
|
|
|
if (attacker->item == ITEM_ENIGMA_BERRY)
|
|
{
|
|
attackerHoldEffect = gEnigmaBerries[bankAtk].holdEffect;
|
|
attackerHoldEffectParam = gEnigmaBerries[bankAtk].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
attackerHoldEffect = ItemId_GetHoldEffect(attacker->item);
|
|
attackerHoldEffectParam = ItemId_GetHoldEffectParam(attacker->item);
|
|
}
|
|
|
|
if (defender->item == ITEM_ENIGMA_BERRY)
|
|
{
|
|
defenderHoldEffect = gEnigmaBerries[bankDef].holdEffect;
|
|
defenderHoldEffectParam = gEnigmaBerries[bankDef].holdEffectParam;
|
|
}
|
|
else
|
|
{
|
|
defenderHoldEffect = ItemId_GetHoldEffect(defender->item);
|
|
defenderHoldEffectParam = ItemId_GetHoldEffectParam(defender->item);
|
|
}
|
|
|
|
if (attacker->ability == ABILITY_HUGE_POWER || attacker->ability == ABILITY_PURE_POWER)
|
|
attack *= 2;
|
|
|
|
if (ShouldGetStatBadgeBoost(BADGE01_GET, bankAtk))
|
|
attack = (110 * attack) / 100;
|
|
if (ShouldGetStatBadgeBoost(BADGE05_GET, bankDef))
|
|
defense = (110 * defense) / 100;
|
|
if (ShouldGetStatBadgeBoost(BADGE07_GET, bankAtk))
|
|
spAttack = (110 * spAttack) / 100;
|
|
if (ShouldGetStatBadgeBoost(BADGE07_GET, bankDef))
|
|
spDefense = (110 * spDefense) / 100;
|
|
|
|
for (i = 0; i < 17; i++)
|
|
{
|
|
if (attackerHoldEffect == gHoldEffectToType[i][0]
|
|
&& type == gHoldEffectToType[i][1])
|
|
{
|
|
if (type <= 8)
|
|
attack = (attack * (attackerHoldEffectParam + 100)) / 100;
|
|
else
|
|
spAttack = (spAttack * (attackerHoldEffectParam + 100)) / 100;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (attackerHoldEffect == HOLD_EFFECT_CHOICE_BAND)
|
|
attack = (150 * attack) / 100;
|
|
if (attackerHoldEffect == HOLD_EFFECT_SOUL_DEW && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER)) && (attacker->species == SPECIES_LATIAS || attacker->species == SPECIES_LATIOS))
|
|
spAttack = (150 * spAttack) / 100;
|
|
if (defenderHoldEffect == HOLD_EFFECT_SOUL_DEW && !(gBattleTypeFlags & (BATTLE_TYPE_FRONTIER)) && (defender->species == SPECIES_LATIAS || defender->species == SPECIES_LATIOS))
|
|
spDefense = (150 * spDefense) / 100;
|
|
if (attackerHoldEffect == HOLD_EFFECT_DEEP_SEA_TOOTH && attacker->species == SPECIES_CLAMPERL)
|
|
spAttack *= 2;
|
|
if (defenderHoldEffect == HOLD_EFFECT_DEEP_SEA_SCALE && defender->species == SPECIES_CLAMPERL)
|
|
spDefense *= 2;
|
|
if (attackerHoldEffect == HOLD_EFFECT_LIGHT_BALL && attacker->species == SPECIES_PIKACHU)
|
|
spAttack *= 2;
|
|
if (defenderHoldEffect == HOLD_EFFECT_METAL_POWDER && defender->species == SPECIES_DITTO)
|
|
defense *= 2;
|
|
if (attackerHoldEffect == HOLD_EFFECT_THICK_CLUB && (attacker->species == SPECIES_CUBONE || attacker->species == SPECIES_MAROWAK))
|
|
attack *= 2;
|
|
if (defender->ability == ABILITY_THICK_FAT && (type == TYPE_FIRE || type == TYPE_ICE))
|
|
spAttack /= 2;
|
|
if (attacker->ability == ABILITY_HUSTLE)
|
|
attack = (150 * attack) / 100;
|
|
if (attacker->ability == ABILITY_PLUS && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_MINUS, 0, 0))
|
|
spAttack = (150 * spAttack) / 100;
|
|
if (attacker->ability == ABILITY_MINUS && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_PLUS, 0, 0))
|
|
spAttack = (150 * spAttack) / 100;
|
|
if (attacker->ability == ABILITY_GUTS && attacker->status1)
|
|
attack = (150 * attack) / 100;
|
|
if (defender->ability == ABILITY_MARVEL_SCALE && defender->status1)
|
|
defense = (150 * defense) / 100;
|
|
if (type == TYPE_ELECTRIC && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, 0, 0xFD, 0))
|
|
gBattleMovePower /= 2;
|
|
if (type == TYPE_FIRE && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, 0, 0xFE, 0))
|
|
gBattleMovePower /= 2;
|
|
if (type == TYPE_GRASS && attacker->ability == ABILITY_OVERGROW && attacker->hp <= (attacker->maxHP / 3))
|
|
gBattleMovePower = (150 * gBattleMovePower) / 100;
|
|
if (type == TYPE_FIRE && attacker->ability == ABILITY_BLAZE && attacker->hp <= (attacker->maxHP / 3))
|
|
gBattleMovePower = (150 * gBattleMovePower) / 100;
|
|
if (type == TYPE_WATER && attacker->ability == ABILITY_TORRENT && attacker->hp <= (attacker->maxHP / 3))
|
|
gBattleMovePower = (150 * gBattleMovePower) / 100;
|
|
if (type == TYPE_BUG && attacker->ability == ABILITY_SWARM && attacker->hp <= (attacker->maxHP / 3))
|
|
gBattleMovePower = (150 * gBattleMovePower) / 100;
|
|
if (gBattleMoves[gCurrentMove].effect == EFFECT_EXPLOSION)
|
|
defense /= 2;
|
|
|
|
if (type < TYPE_MYSTERY) // is physical
|
|
{
|
|
if (gCritMultiplier == 2)
|
|
{
|
|
if (attacker->statStages[STAT_STAGE_ATK] > 6)
|
|
APPLY_STAT_MOD(damage, attacker, attack, STAT_STAGE_ATK)
|
|
else
|
|
damage = attack;
|
|
}
|
|
else
|
|
APPLY_STAT_MOD(damage, attacker, attack, STAT_STAGE_ATK)
|
|
|
|
damage = damage * gBattleMovePower;
|
|
damage *= (2 * attacker->level / 5 + 2);
|
|
|
|
if (gCritMultiplier == 2)
|
|
{
|
|
if (defender->statStages[STAT_STAGE_DEF] < 6)
|
|
APPLY_STAT_MOD(damageHelper, defender, defense, STAT_STAGE_DEF)
|
|
else
|
|
damageHelper = defense;
|
|
}
|
|
else
|
|
APPLY_STAT_MOD(damageHelper, defender, defense, STAT_STAGE_DEF)
|
|
|
|
damage = damage / damageHelper;
|
|
damage /= 50;
|
|
|
|
if ((attacker->status1 & STATUS_BURN) && attacker->ability != ABILITY_GUTS)
|
|
damage /= 2;
|
|
|
|
if ((sideStatus & SIDE_STATUS_REFLECT) && gCritMultiplier == 1)
|
|
{
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && CountAliveMonsInBattle(2) == 2)
|
|
damage = 2 * (damage / 3);
|
|
else
|
|
damage /= 2;
|
|
}
|
|
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gBattleMoves[move].target == 8 && CountAliveMonsInBattle(2) == 2)
|
|
damage /= 2;
|
|
|
|
// moves always do at least 1 damage.
|
|
if (damage == 0)
|
|
damage = 1;
|
|
}
|
|
|
|
if (type == TYPE_MYSTERY)
|
|
damage = 0; // is ??? type. does 0 damage.
|
|
|
|
if (type > TYPE_MYSTERY) // is special?
|
|
{
|
|
if (gCritMultiplier == 2)
|
|
{
|
|
if (attacker->statStages[STAT_STAGE_SPATK] > 6)
|
|
APPLY_STAT_MOD(damage, attacker, spAttack, STAT_STAGE_SPATK)
|
|
else
|
|
damage = spAttack;
|
|
}
|
|
else
|
|
APPLY_STAT_MOD(damage, attacker, spAttack, STAT_STAGE_SPATK)
|
|
|
|
damage = damage * gBattleMovePower;
|
|
damage *= (2 * attacker->level / 5 + 2);
|
|
|
|
if (gCritMultiplier == 2)
|
|
{
|
|
if (defender->statStages[STAT_STAGE_SPDEF] < 6)
|
|
APPLY_STAT_MOD(damageHelper, defender, spDefense, STAT_STAGE_SPDEF)
|
|
else
|
|
damageHelper = spDefense;
|
|
}
|
|
else
|
|
APPLY_STAT_MOD(damageHelper, defender, spDefense, STAT_STAGE_SPDEF)
|
|
|
|
damage = (damage / damageHelper);
|
|
damage /= 50;
|
|
|
|
if ((sideStatus & SIDE_STATUS_LIGHTSCREEN) && gCritMultiplier == 1)
|
|
{
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && CountAliveMonsInBattle(2) == 2)
|
|
damage = 2 * (damage / 3);
|
|
else
|
|
damage /= 2;
|
|
}
|
|
|
|
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gBattleMoves[move].target == 8 && CountAliveMonsInBattle(2) == 2)
|
|
damage /= 2;
|
|
|
|
// are effects of weather negated with cloud nine or air lock
|
|
if (!AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_CLOUD_NINE, 0, 0)
|
|
&& !AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, ABILITY_AIR_LOCK, 0, 0))
|
|
{
|
|
if (gBattleWeather & WEATHER_RAIN_TEMPORARY)
|
|
{
|
|
switch (type)
|
|
{
|
|
case TYPE_FIRE:
|
|
damage /= 2;
|
|
break;
|
|
case TYPE_WATER:
|
|
damage = (15 * damage) / 10;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// any weather except sun weakens solar beam
|
|
if ((gBattleWeather & (WEATHER_RAIN_ANY | WEATHER_SANDSTORM_ANY | WEATHER_HAIL)) && gCurrentMove == MOVE_SOLAR_BEAM)
|
|
damage /= 2;
|
|
|
|
// sunny
|
|
if (gBattleWeather & WEATHER_SUN_ANY)
|
|
{
|
|
switch (type)
|
|
{
|
|
case TYPE_FIRE:
|
|
damage = (15 * damage) / 10;
|
|
break;
|
|
case TYPE_WATER:
|
|
damage /= 2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// flash fire triggered
|
|
if ((gBattleResources->flags->flags[bankAtk] & UNKNOWN_FLAG_FLASH_FIRE) && type == TYPE_FIRE)
|
|
damage = (15 * damage) / 10;
|
|
}
|
|
|
|
return damage + 2;
|
|
}
|