mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-26 19:54:21 +01:00
Fixed Point Math (#3115)
This commit is contained in:
commit
d8c8ee1183
@ -656,7 +656,7 @@ struct BattleStruct
|
||||
u8 battleBondTransformed[NUM_BATTLE_SIDES]; // Bitfield for each party.
|
||||
u8 storedHealingWish:4; // Each battler as a bit.
|
||||
u8 storedLunarDance:4; // Each battler as a bit.
|
||||
u16 supremeOverlordModifier[MAX_BATTLERS_COUNT];
|
||||
uq4_12_t supremeOverlordModifier[MAX_BATTLERS_COUNT];
|
||||
u8 itemPartyIndex[MAX_BATTLERS_COUNT];
|
||||
u8 itemMoveIndex[MAX_BATTLERS_COUNT];
|
||||
bool8 trainerSlideHalfHpMsgDone;
|
||||
|
@ -87,7 +87,7 @@ bool32 MovesWithSplitUnusable(u32 attacker, u32 target, u32 split);
|
||||
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *effectiveness, bool32 considerZPower);
|
||||
u8 GetMoveDamageResult(u16 move);
|
||||
u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef);
|
||||
u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
|
||||
uq4_12_t AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
|
||||
u32 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
|
||||
u16 *GetMovesArray(u32 battler);
|
||||
bool32 IsConfusionMoveEffect(u16 moveEffect);
|
||||
|
@ -166,10 +166,10 @@ bool32 IsBattlerAlive(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, bool32 randomFactor, bool32 updateFlags);
|
||||
s32 CalculateMoveDamageAndEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, u16 *typeEffectivenessModifier);
|
||||
u16 CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities);
|
||||
u16 CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef);
|
||||
u16 GetTypeModifier(u8 atkType, u8 defType);
|
||||
s32 CalculateMoveDamageAndEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef, u8 moveType, uq4_12_t *typeEffectivenessModifier);
|
||||
uq4_12_t CalcTypeEffectivenessMultiplier(u16 move, u8 moveType, u8 battlerAtk, u8 battlerDef, bool32 recordAbilities);
|
||||
uq4_12_t CalcPartyMonTypeEffectivenessMultiplier(u16 move, u16 speciesDef, u16 abilityDef);
|
||||
uq4_12_t GetTypeModifier(u8 atkType, u8 defType);
|
||||
s32 GetStealthHazardDamage(u8 hazardType, u8 battlerId);
|
||||
s32 GetStealthHazardDamageByTypesAndHP(u8 hazardType, u8 type1, u8 type2, u32 maxHp);
|
||||
bool32 CanMegaEvolve(u8 battlerId);
|
||||
@ -240,4 +240,9 @@ u8 GetBattlerGender(u8 battlerId);
|
||||
bool8 AreBattlersOfOppositeGender(u8 battler1, u8 battler2);
|
||||
u32 CalcSecondaryEffectChance(u8 battlerId, u8 secondaryEffectChance);
|
||||
|
||||
static inline u32 ApplyModifier(uq4_12_t modifier, u32 val)
|
||||
{
|
||||
return UQ_4_12_TO_INT((modifier * val) + UQ_4_12_ROUND);
|
||||
}
|
||||
|
||||
#endif // GUARD_BATTLE_UTIL_H
|
||||
|
61
include/fpmath.h
Normal file
61
include/fpmath.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef FPMATH_H_
|
||||
#define FPMATH_H_
|
||||
|
||||
typedef s32 q4_12_t;
|
||||
typedef u32 uq4_12_t;
|
||||
|
||||
#define Q_4_12_SHIFT (12)
|
||||
#define UQ_4_12_SHIFT (12)
|
||||
|
||||
// Converts a number to Q8.8 fixed-point format
|
||||
#define Q_8_8(n) ((s16)((n) * 256))
|
||||
|
||||
// Converts a number to Q4.12 fixed-point format
|
||||
#define Q_4_12(n) ((q4_12_t)((n) * 4096))
|
||||
#define UQ_4_12(n) ((uq4_12_t)((n) * 4096))
|
||||
|
||||
// Converts a number to Q24.8 fixed-point format
|
||||
#define Q_24_8(n) ((s32)((n) * 256))
|
||||
|
||||
// Converts a Q8.8 fixed-point format number to a regular integer
|
||||
#define Q_8_8_TO_INT(n) ((s32)((n) / 256))
|
||||
|
||||
// Converts a Q4.12 fixed-point format number to a regular integer
|
||||
#define Q_4_12_TO_INT(n) ((s32)((n) / 4096))
|
||||
#define UQ_4_12_TO_INT(n) ((u32)((n) / 4096))
|
||||
|
||||
// Converts a Q24.8 fixed-point format number to a regular integer
|
||||
#define Q_24_8_TO_INT(n) ((s32)((n) / 256))
|
||||
|
||||
// Rounding value for Q4.12 fixed-point format
|
||||
#define Q_4_12_ROUND ((1) << (Q_4_12_SHIFT - 1))
|
||||
#define UQ_4_12_ROUND ((1) << (UQ_4_12_SHIFT - 1))
|
||||
|
||||
// Basic arithmetic for fixed point number formats
|
||||
// Consumers should use encapsulated functions where possible
|
||||
|
||||
// FP API does not provide sanity checks against overflows
|
||||
|
||||
static inline uq4_12_t uq4_12_add(uq4_12_t a, uq4_12_t b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
static inline uq4_12_t uq4_12_subtract(uq4_12_t a, uq4_12_t b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static inline uq4_12_t uq4_12_multiply(uq4_12_t a, uq4_12_t b)
|
||||
{
|
||||
u32 product = (u32) a * b;
|
||||
return (product + UQ_4_12_ROUND) >> UQ_4_12_SHIFT;
|
||||
}
|
||||
|
||||
static inline uq4_12_t uq4_12_divide(uq4_12_t dividend, uq4_12_t divisor)
|
||||
{
|
||||
if (divisor == UQ_4_12(0.0)) return UQ_4_12(0);
|
||||
return (dividend << UQ_4_12_SHIFT) / divisor;
|
||||
}
|
||||
|
||||
#endif // FPMATH_H_
|
@ -5,6 +5,7 @@
|
||||
#include <limits.h>
|
||||
#include "config.h" // we need to define config before gba headers as print stuff needs the functions nulled before defines.
|
||||
#include "gba/gba.h"
|
||||
#include "fpmath.h"
|
||||
#include "constants/global.h"
|
||||
#include "constants/flags.h"
|
||||
#include "constants/vars.h"
|
||||
@ -51,32 +52,6 @@
|
||||
b = temp; \
|
||||
}
|
||||
|
||||
// useful math macros
|
||||
|
||||
// Converts a number to Q8.8 fixed-point format
|
||||
#define Q_8_8(n) ((s16)((n) * 256))
|
||||
|
||||
// Converts a number to Q4.12 fixed-point format
|
||||
#define Q_4_12(n) ((s16)((n) * 4096))
|
||||
#define UQ_4_12(n) ((u16)((n) * 4096))
|
||||
|
||||
// Converts a number to Q24.8 fixed-point format
|
||||
#define Q_24_8(n) ((s32)((n) << 8))
|
||||
|
||||
// Converts a Q8.8 fixed-point format number to a regular integer
|
||||
#define Q_8_8_TO_INT(n) ((int)((n) / 256))
|
||||
|
||||
// Converts a Q4.12 fixed-point format number to a regular integer
|
||||
#define Q_4_12_TO_INT(n) ((int)((n) / 4096))
|
||||
#define UQ_4_12_TO_INT(n) ((int)((n) / 4096))
|
||||
|
||||
// Converts a Q24.8 fixed-point format number to a regular integer
|
||||
#define Q_24_8_TO_INT(n) ((int)((n) >> 8))
|
||||
|
||||
// Rounding value for Q4.12 fixed-point format
|
||||
#define Q_4_12_ROUND ((1) << (12 - 1))
|
||||
#define UQ_4_12_ROUND ((1) << (12 - 1))
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define max(a, b) ((a) >= (b) ? (a) : (b))
|
||||
|
||||
|
@ -822,7 +822,7 @@ static u32 GetBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId,
|
||||
|
||||
while (bits != 0x3F) // All mons were checked.
|
||||
{
|
||||
u16 bestResist = UQ_4_12(1.0);
|
||||
uq4_12_t bestResist = UQ_4_12(1.0);
|
||||
int bestMonId = PARTY_SIZE;
|
||||
// Find the mon whose type is the most suitable defensively.
|
||||
for (i = firstId; i < lastId; i++)
|
||||
@ -830,21 +830,21 @@ static u32 GetBestMonTypeMatchup(struct Pokemon *party, int firstId, int lastId,
|
||||
if (!(gBitTable[i] & invalidMons) && !(gBitTable[i] & bits))
|
||||
{
|
||||
u16 species = GetMonData(&party[i], MON_DATA_SPECIES);
|
||||
u16 typeEffectiveness = UQ_4_12(1.0);
|
||||
uq4_12_t typeEffectiveness = UQ_4_12(1.0);
|
||||
|
||||
u8 atkType1 = gBattleMons[opposingBattler].type1;
|
||||
u8 atkType2 = gBattleMons[opposingBattler].type2;
|
||||
u8 defType1 = gSpeciesInfo[species].types[0];
|
||||
u8 defType2 = gSpeciesInfo[species].types[1];
|
||||
|
||||
MulModifier(&typeEffectiveness, (GetTypeModifier(atkType1, defType1)));
|
||||
typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType1, defType1)));
|
||||
if (atkType2 != atkType1)
|
||||
MulModifier(&typeEffectiveness, (GetTypeModifier(atkType2, defType1)));
|
||||
typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType2, defType1)));
|
||||
if (defType2 != defType1)
|
||||
{
|
||||
MulModifier(&typeEffectiveness, (GetTypeModifier(atkType1, defType2)));
|
||||
typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType1, defType2)));
|
||||
if (atkType2 != atkType1)
|
||||
MulModifier(&typeEffectiveness, (GetTypeModifier(atkType2, defType2)));
|
||||
typeEffectiveness = uq4_12_multiply(typeEffectiveness, (GetTypeModifier(atkType2, defType2)));
|
||||
}
|
||||
if (typeEffectiveness < bestResist)
|
||||
{
|
||||
|
@ -31,7 +31,7 @@
|
||||
} \
|
||||
return FALSE
|
||||
|
||||
static u32 AI_GetEffectiveness(u16 multiplier);
|
||||
static u32 AI_GetEffectiveness(uq4_12_t multiplier);
|
||||
|
||||
// Const Data
|
||||
static const s8 sAiAbilityRatings[ABILITIES_COUNT] =
|
||||
@ -768,7 +768,7 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, u8 *typeEffectiveness,
|
||||
{
|
||||
s32 dmg, moveType, critDmg, normalDmg;
|
||||
s8 critChance;
|
||||
u16 effectivenessMultiplier;
|
||||
uq4_12_t effectivenessMultiplier;
|
||||
|
||||
if (considerZPower && IsViableZMove(battlerAtk, move))
|
||||
{
|
||||
@ -1003,9 +1003,10 @@ u32 GetCurrDamageHpPercent(u8 battlerAtk, u8 battlerDef)
|
||||
return (bestDmg * 100) / gBattleMons[battlerDef].maxHP;
|
||||
}
|
||||
|
||||
u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef)
|
||||
uq4_12_t AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef)
|
||||
{
|
||||
u16 typeEffectiveness, moveType;
|
||||
uq4_12_t typeEffectiveness;
|
||||
u16 moveType;
|
||||
|
||||
SaveBattlerData(battlerAtk);
|
||||
SaveBattlerData(battlerDef);
|
||||
@ -1030,7 +1031,7 @@ u32 AI_GetMoveEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef)
|
||||
return AI_GetEffectiveness(AI_GetTypeEffectiveness(move, battlerAtk, battlerDef));
|
||||
}
|
||||
|
||||
static u32 AI_GetEffectiveness(u16 multiplier)
|
||||
static u32 AI_GetEffectiveness(uq4_12_t multiplier)
|
||||
{
|
||||
switch (multiplier)
|
||||
{
|
||||
|
@ -5206,7 +5206,7 @@ static u16 GetWinningMove(int winnerTournamentId, int loserTournamentId, u8 roun
|
||||
u32 personality = 0;
|
||||
u32 targetSpecies = 0;
|
||||
u32 targetAbility = 0;
|
||||
u32 typeMultiplier = 0;
|
||||
uq4_12_t typeMultiplier = 0;
|
||||
do
|
||||
{
|
||||
personality = Random32();
|
||||
|
File diff suppressed because it is too large
Load Diff
18
test/fpmath.c
Normal file
18
test/fpmath.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include "global.h"
|
||||
#include "test.h"
|
||||
|
||||
TEST("uq4_12_add adds 4.12 numbers") {
|
||||
EXPECT_EQ(uq4_12_add(UQ_4_12(3.5), UQ_4_12(2.5)), UQ_4_12(6.0));
|
||||
}
|
||||
|
||||
TEST("uq4_12_subtract subtracts 4.12 numbers") {
|
||||
EXPECT_EQ(uq4_12_subtract(UQ_4_12(3.5), UQ_4_12(2.0)), UQ_4_12(1.5));
|
||||
}
|
||||
|
||||
TEST("uq4_12_multiply multiplies 4.12 numbers") {
|
||||
EXPECT_EQ(uq4_12_multiply(UQ_4_12(3.5), UQ_4_12(2.0)), UQ_4_12(7.0));
|
||||
}
|
||||
|
||||
TEST("uq4_12_divide divides 4.12 numbers") {
|
||||
EXPECT_EQ(uq4_12_divide(UQ_4_12(5.0), UQ_4_12(2.0)), UQ_4_12(2.5));
|
||||
}
|
Loading…
Reference in New Issue
Block a user