mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2025-01-27 13:53:52 +01:00
Create template of new dmg calc
This commit is contained in:
parent
2ebf14a83d
commit
c00fa14b66
@ -79,5 +79,6 @@ bool32 IsMoveMakingContact(u16 move, u8 battlerAtk);
|
||||
bool32 IsBattlerGrounded(u8 battlerId);
|
||||
u8 GetBattleMonMoveSlot(struct BattlePokemon *battleMon, u16 move);
|
||||
u32 GetBattlerWeight(u8 battlerId);
|
||||
s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit);
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
@ -488,7 +488,6 @@ void GiveBoxMonInitialMoveset(struct BoxPokemon *boxMon);
|
||||
u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove);
|
||||
void DeleteFirstMoveAndGiveMoveToMon(struct Pokemon *mon, u16 move);
|
||||
void DeleteFirstMoveAndGiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 move);
|
||||
s32 CalculateBaseDamage(struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 move, u16 sideStatus, u16 powerOverride, u8 typeOverride, u8 bankAtk, u8 bankDef);
|
||||
|
||||
u8 CountAliveMonsInBattle(u8 caseId);
|
||||
#define BATTLE_ALIVE_EXCEPT_ACTIVE 0
|
||||
|
@ -1282,33 +1282,16 @@ static void atk04_critcalc(void)
|
||||
|
||||
static void atk05_damagecalc(void)
|
||||
{
|
||||
u16 sideStatus = gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)];
|
||||
gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerTarget], gCurrentMove,
|
||||
sideStatus, gDynamicBasePower,
|
||||
gBattleStruct->dynamicMoveType, gBattlerAttacker, gBattlerTarget);
|
||||
gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier;
|
||||
|
||||
if (gStatuses3[gBattlerAttacker] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC)
|
||||
gBattleMoveDamage *= 2;
|
||||
if (gProtectStructs[gBattlerAttacker].helpingHand)
|
||||
gBattleMoveDamage = gBattleMoveDamage * 15 / 10;
|
||||
u8 moveType;
|
||||
|
||||
GET_MOVE_TYPE(gCurrentMove, moveType);
|
||||
gBattleMoveDamage = CalculateMoveDamage(gCurrentMove, gBattlerAttacker, gBattlerTarget, moveType, 0, gCritMultiplier);
|
||||
gBattlescriptCurrInstr++;
|
||||
}
|
||||
|
||||
void AI_CalcDmg(u8 attacker, u8 defender)
|
||||
{
|
||||
u16 sideStatus = gSideStatuses[GET_BATTLER_SIDE(defender)];
|
||||
gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[attacker], &gBattleMons[defender], gCurrentMove,
|
||||
sideStatus, gDynamicBasePower,
|
||||
gBattleStruct->dynamicMoveType, attacker, defender);
|
||||
gDynamicBasePower = 0;
|
||||
gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier;
|
||||
|
||||
if (gStatuses3[attacker] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC)
|
||||
gBattleMoveDamage *= 2;
|
||||
if (gProtectStructs[attacker].helpingHand)
|
||||
gBattleMoveDamage = gBattleMoveDamage * 15 / 10;
|
||||
// To modify.
|
||||
}
|
||||
|
||||
static void ModulateDmgByType(u8 multiplier)
|
||||
@ -7121,14 +7104,7 @@ static void atk86_stockpiletobasedamage(void)
|
||||
{
|
||||
if (gBattleCommunication[6] != 1)
|
||||
{
|
||||
gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerTarget], gCurrentMove,
|
||||
gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)], 0,
|
||||
0, gBattlerAttacker, gBattlerTarget)
|
||||
* gDisableStructs[gBattlerAttacker].stockpileCounter;
|
||||
gBattleScripting.animTurn = gDisableStructs[gBattlerAttacker].stockpileCounter;
|
||||
|
||||
if (gProtectStructs[gBattlerAttacker].helpingHand)
|
||||
gBattleMoveDamage = gBattleMoveDamage * 15 / 10;
|
||||
}
|
||||
|
||||
gDisableStructs[gBattlerAttacker].stockpileCounter = 0;
|
||||
@ -9106,12 +9082,6 @@ static void atkC3_trysetfutureattack(void)
|
||||
gWishFutureKnock.futureSightMove[gBattlerTarget] = gCurrentMove;
|
||||
gWishFutureKnock.futureSightAttacker[gBattlerTarget] = gBattlerAttacker;
|
||||
gWishFutureKnock.futureSightCounter[gBattlerTarget] = 3;
|
||||
gWishFutureKnock.futureSightDmg[gBattlerTarget] = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerTarget], gCurrentMove,
|
||||
gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)], 0,
|
||||
0, gBattlerAttacker, gBattlerTarget);
|
||||
|
||||
if (gProtectStructs[gBattlerAttacker].helpingHand)
|
||||
gWishFutureKnock.futureSightDmg[gBattlerTarget] = gWishFutureKnock.futureSightDmg[gBattlerTarget] * 15 / 10;
|
||||
|
||||
if (gCurrentMove == MOVE_DOOM_DESIRE)
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
||||
|
@ -1430,9 +1430,7 @@ static void TrySetBattleSeminarShow(void)
|
||||
{
|
||||
u8 moveResultFlags;
|
||||
u16 sideStatus = gSideStatuses[GET_BATTLER_SIDE(gBattlerTarget)];
|
||||
gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerTarget], gCurrentMove,
|
||||
sideStatus, powerOverride,
|
||||
0, gBattlerAttacker, gBattlerTarget);
|
||||
gBattleMoveDamage = CalculateMoveDamage(gCurrentMove, gBattlerAttacker, gBattlerTarget, gBattleMoves[gCurrentMove].type, powerOverride, FALSE);
|
||||
|
||||
if (gStatuses3[gBattlerAttacker] & STATUS3_CHARGED_UP && gBattleMoves[gCurrentMove].type == TYPE_ELECTRIC)
|
||||
gBattleMoveDamage *= 2;
|
||||
|
@ -1552,7 +1552,7 @@ u8 AtkCanceller_UnableToUseMove(void)
|
||||
{
|
||||
gBattleCommunication[MULTISTRING_CHOOSER] = 1;
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerAttacker], MOVE_POUND, 0, 40, 0, gBattlerAttacker, gBattlerAttacker);
|
||||
gBattleMoveDamage = CalculateMoveDamage(MOVE_NONE, gBattlerAttacker, gBattlerAttacker, TYPE_MYSTERY, 40, FALSE);
|
||||
gProtectStructs[gBattlerAttacker].confusionSelfDmg = 1;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
}
|
||||
@ -3472,7 +3472,7 @@ u8 IsMonDisobedient(void)
|
||||
calc -= obedienceLevel;
|
||||
if (calc < obedienceLevel)
|
||||
{
|
||||
gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerAttacker], MOVE_POUND, 0, 40, 0, gBattlerAttacker, gBattlerAttacker);
|
||||
gBattleMoveDamage = CalculateMoveDamage(MOVE_NONE, gBattlerAttacker, gBattlerAttacker, TYPE_MYSTERY, 40, FALSE);
|
||||
gBattlerTarget = gBattlerAttacker;
|
||||
gBattlescriptCurrInstr = BattleScript_82DB6F0;
|
||||
gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE;
|
||||
@ -3653,3 +3653,8 @@ u32 GetMoveTargetCount(u16 move, u8 battlerAtk, u8 battlerDef)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
s32 CalculateMoveDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, s32 fixedBasePower, bool32 isCrit)
|
||||
{
|
||||
|
||||
}
|
||||
|
245
src/pokemon.c
245
src/pokemon.c
@ -1016,7 +1016,7 @@ const u8 gStatStageRatios[][2] =
|
||||
{40, 10}, // +6
|
||||
};
|
||||
|
||||
static const u16 sDeoxysBaseStats[] =
|
||||
static const u8 sDeoxysBaseStats[] =
|
||||
{
|
||||
50, // Hp
|
||||
95, // Attack
|
||||
@ -2171,249 +2171,6 @@ void DeleteFirstMoveAndGiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 move)
|
||||
SetBoxMonData(boxMon, MON_DATA_PP_BONUSES, &ppBonuses);
|
||||
}
|
||||
|
||||
#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 battlerIdAtk, u8 battlerIdDef)
|
||||
{
|
||||
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[battlerIdAtk].holdEffect;
|
||||
attackerHoldEffectParam = gEnigmaBerries[battlerIdAtk].holdEffectParam;
|
||||
}
|
||||
else
|
||||
{
|
||||
attackerHoldEffect = ItemId_GetHoldEffect(attacker->item);
|
||||
attackerHoldEffectParam = ItemId_GetHoldEffectParam(attacker->item);
|
||||
}
|
||||
|
||||
if (defender->item == ITEM_ENIGMA_BERRY)
|
||||
{
|
||||
defenderHoldEffect = gEnigmaBerries[battlerIdDef].holdEffect;
|
||||
defenderHoldEffectParam = gEnigmaBerries[battlerIdDef].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(FLAG_BADGE01_GET, battlerIdAtk))
|
||||
attack = (110 * attack) / 100;
|
||||
if (ShouldGetStatBadgeBoost(FLAG_BADGE05_GET, battlerIdDef))
|
||||
defense = (110 * defense) / 100;
|
||||
if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, battlerIdAtk))
|
||||
spAttack = (110 * spAttack) / 100;
|
||||
if (ShouldGetStatBadgeBoost(FLAG_BADGE07_GET, battlerIdDef))
|
||||
spDefense = (110 * spDefense) / 100;
|
||||
|
||||
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 && ABILITY_ON_FIELD(ABILITY_MINUS))
|
||||
spAttack = (150 * spAttack) / 100;
|
||||
if (attacker->ability == ABILITY_MINUS && ABILITY_ON_FIELD(ABILITY_PLUS))
|
||||
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 && gFieldStatuses & STATUS_FIELD_MUDSPORT)
|
||||
gBattleMovePower /= 2;
|
||||
if (type == TYPE_FIRE && gFieldStatuses & STATUS_FIELD_WATERSPORT)
|
||||
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_ATK] > 6)
|
||||
APPLY_STAT_MOD(damage, attacker, attack, STAT_ATK)
|
||||
else
|
||||
damage = attack;
|
||||
}
|
||||
else
|
||||
APPLY_STAT_MOD(damage, attacker, attack, STAT_ATK)
|
||||
|
||||
damage = damage * gBattleMovePower;
|
||||
damage *= (2 * attacker->level / 5 + 2);
|
||||
|
||||
if (gCritMultiplier == 2)
|
||||
{
|
||||
if (defender->statStages[STAT_DEF] < 6)
|
||||
APPLY_STAT_MOD(damageHelper, defender, defense, STAT_DEF)
|
||||
else
|
||||
damageHelper = defense;
|
||||
}
|
||||
else
|
||||
APPLY_STAT_MOD(damageHelper, defender, defense, STAT_DEF)
|
||||
|
||||
damage = damage / damageHelper;
|
||||
damage /= 50;
|
||||
|
||||
if ((attacker->status1 & STATUS1_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_SPATK] > 6)
|
||||
APPLY_STAT_MOD(damage, attacker, spAttack, STAT_SPATK)
|
||||
else
|
||||
damage = spAttack;
|
||||
}
|
||||
else
|
||||
APPLY_STAT_MOD(damage, attacker, spAttack, STAT_SPATK)
|
||||
|
||||
damage = damage * gBattleMovePower;
|
||||
damage *= (2 * attacker->level / 5 + 2);
|
||||
|
||||
if (gCritMultiplier == 2)
|
||||
{
|
||||
if (defender->statStages[STAT_SPDEF] < 6)
|
||||
APPLY_STAT_MOD(damageHelper, defender, spDefense, STAT_SPDEF)
|
||||
else
|
||||
damageHelper = spDefense;
|
||||
}
|
||||
else
|
||||
APPLY_STAT_MOD(damageHelper, defender, spDefense, STAT_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 (WEATHER_HAS_EFFECT)
|
||||
{
|
||||
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[battlerIdAtk] & UNKNOWN_FLAG_FLASH_FIRE) && type == TYPE_FIRE)
|
||||
damage = (15 * damage) / 10;
|
||||
}
|
||||
|
||||
return damage + 2;
|
||||
}
|
||||
|
||||
u8 CountAliveMonsInBattle(u8 caseId)
|
||||
{
|
||||
s32 i;
|
||||
|
Loading…
x
Reference in New Issue
Block a user