fixed bug with type3 not being intialized leading to wrong type calculations

removed unused functions
This commit is contained in:
cawtds 2024-05-03 11:57:21 +02:00
parent 15e04f6f97
commit 963be8c077
8 changed files with 142 additions and 533 deletions

View File

@ -94,5 +94,8 @@ s8 GetChosenMovePriority(u32 battlerId);
u32 GetBattlerTotalSpeedStatArgs(u32 battler, u32 ability, u32 holdEffect);
u32 GetBattlerTotalSpeedStat(u32 battler);
void SpecialStatusesClear(void);
s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2,
u32 holdEffectBattler1, u32 holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2);
s32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves);
#endif // GUARD_BATTLE_MAIN_H

View File

@ -668,7 +668,6 @@ void SetMonMoveSlot(struct Pokemon *mon, u16 move, u8 slot);
void SetBattleMonMoveSlot(struct BattlePokemon *mon, u16 move, u8 slot);
u16 MonTryLearningNewMove(struct Pokemon *mon, bool8 firstMove);
void DeleteFirstMoveAndGiveMoveToMon(struct Pokemon *mon, u16 move);
s32 CalculateBaseDamageOld(struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 move, u32 sideStatus, u16 powerOverride, u8 typeOverride, u8 battlerIdAtk, u8 battlerIdDef);
u32 GetMonAffectionHearts(struct Pokemon *pokemon);
u8 CountAliveMonsInBattle(u8 caseId, u32 battler);

View File

@ -1102,7 +1102,7 @@ static void Cmd_if_not_equal_(void) // Same as if_not_equal.
static void Cmd_if_would_go_first(void)
{
if (GetWhoStrikesFirst(gBattlerAttacker, gBattlerTarget, TRUE) == sAIScriptPtr[1])
if ((GetWhichBattlerFaster(gBattlerAttacker, gBattlerTarget, TRUE) == 1) == sAIScriptPtr[1])
sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2);
else
sAIScriptPtr += 6;
@ -1110,7 +1110,7 @@ static void Cmd_if_would_go_first(void)
static void Cmd_if_would_not_go_first(void)
{
if (GetWhoStrikesFirst(gBattlerAttacker, gBattlerTarget, TRUE) != sAIScriptPtr[1])
if ((GetWhichBattlerFaster(gBattlerAttacker, gBattlerTarget, TRUE) == 1) != sAIScriptPtr[1])
sAIScriptPtr = T1_READ_PTR(sAIScriptPtr + 2);
else
sAIScriptPtr += 6;

View File

@ -2692,6 +2692,7 @@ static void BattleIntroDrawTrainersOrMonsSprites(void)
gBattleMons[gActiveBattler].type1 = gSpeciesInfo[gBattleMons[gActiveBattler].species].types[0];
gBattleMons[gActiveBattler].type2 = gSpeciesInfo[gBattleMons[gActiveBattler].species].types[1];
gBattleMons[gActiveBattler].type3 = TYPE_MYSTERY;
gBattleMons[gActiveBattler].ability = GetAbilityBySpecies(gBattleMons[gActiveBattler].species, gBattleMons[gActiveBattler].abilityNum);
hpOnSwitchout = &gBattleStruct->hpOnSwitchout[GetBattlerSide(gActiveBattler)];
*hpOnSwitchout = gBattleMons[gActiveBattler].hp;
@ -2900,13 +2901,6 @@ static void BattleIntroRecordMonsToDex(void)
}
}
// not used
static void Unused_AutoProgressToIntro(void)
{
if (gBattleControllerExecFlags == 0)
gBattleMainFunc = BattleIntroPrintPlayerSendsOut;
}
static void BattleIntroPrintPlayerSendsOut(void)
{
if (gBattleControllerExecFlags == 0)
@ -2944,28 +2938,6 @@ static void BattleIntroPlayerSendsOutMonAnimation(void)
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
}
// Unused
static void BattleIntroSwitchInPlayerMons(void)
{
if (gBattleControllerExecFlags == 0)
{
for (gActiveBattler = 0; gActiveBattler < gBattlersCount; gActiveBattler++)
{
if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER)
{
BtlController_EmitSwitchInAnim(BUFFER_A, gBattlerPartyIndexes[gActiveBattler], FALSE);
MarkBattlerForControllerExec(gActiveBattler);
}
}
gBattleStruct->switchInAbilitiesCounter = 0;
gBattleStruct->switchInItemsCounter = 0;
gBattleStruct->overworldWeatherDone = FALSE;
gBattleMainFunc = TryDoEventsBeforeFirstTurn;
}
}
static void TryDoEventsBeforeFirstTurn(void)
{
s32 i, j;
@ -2980,7 +2952,7 @@ static void TryDoEventsBeforeFirstTurn(void)
gBattlerByTurnOrder[i] = i;
for (i = 0; i < gBattlersCount - 1; i++)
for (j = i + 1; j < gBattlersCount; j++)
if (GetWhoStrikesFirst(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], TRUE) != 0)
if ((GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], TRUE) == 1) != 0)
SwapTurnOrder(i, j);
}
if (!gBattleStruct->overworldWeatherDone
@ -3504,138 +3476,95 @@ void SwapTurnOrder(u8 id1, u8 id2)
SWAP(gBattlerByTurnOrder[id1], gBattlerByTurnOrder[id2], temp);
}
u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves)
// Function for AI with variables provided as arguments to speed the computation time
s32 GetWhichBattlerFasterArgs(u32 battler1, u32 battler2, bool32 ignoreChosenMoves, u32 ability1, u32 ability2,
u32 holdEffectBattler1, u32 holdEffectBattler2, u32 speedBattler1, u32 speedBattler2, s32 priority1, s32 priority2)
{
u8 strikesFirst = 0;
u8 speedMultiplierBattler1 = 0, speedMultiplierBattler2 = 0;
u32 speedBattler1 = 0, speedBattler2 = 0;
u8 holdEffect = 0;
u8 holdEffectParam = 0;
u16 moveBattler1 = 0, moveBattler2 = 0;
u32 strikesFirst = 0;
if (WEATHER_HAS_EFFECT)
if (priority1 == priority2)
{
if ((gBattleMons[battler1].ability == ABILITY_SWIFT_SWIM && gBattleWeather & B_WEATHER_RAIN)
|| (gBattleMons[battler1].ability == ABILITY_CHLOROPHYLL && gBattleWeather & B_WEATHER_SUN))
speedMultiplierBattler1 = 2;
else
speedMultiplierBattler1 = 1;
if ((gBattleMons[battler2].ability == ABILITY_SWIFT_SWIM && gBattleWeather & B_WEATHER_RAIN)
|| (gBattleMons[battler2].ability == ABILITY_CHLOROPHYLL && gBattleWeather & B_WEATHER_SUN))
speedMultiplierBattler2 = 2;
else
speedMultiplierBattler2 = 1;
}
else
{
speedMultiplierBattler1 = 1;
speedMultiplierBattler2 = 1;
}
// QUICK CLAW / CUSTAP - always first
// LAGGING TAIL - always last
// STALL - always last
speedBattler1 = (gBattleMons[battler1].speed * speedMultiplierBattler1)
* (gStatStageRatios[gBattleMons[battler1].statStages[STAT_SPEED]][0])
/ (gStatStageRatios[gBattleMons[battler1].statStages[STAT_SPEED]][1]);
if (gBattleMons[battler1].item == ITEM_ENIGMA_BERRY)
{
holdEffect = gEnigmaBerries[battler1].holdEffect;
holdEffectParam = gEnigmaBerries[battler1].holdEffectParam;
}
else
{
holdEffect = ItemId_GetHoldEffect(gBattleMons[battler1].item);
holdEffectParam = ItemId_GetHoldEffectParam(gBattleMons[battler1].item);
}
// badge boost
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)
&& FlagGet(FLAG_BADGE03_GET)
&& GetBattlerSide(battler1) == B_SIDE_PLAYER)
speedBattler1 = (speedBattler1 * 110) / 100;
if (holdEffect == HOLD_EFFECT_MACHO_BRACE)
speedBattler1 /= 2;
if (gBattleMons[battler1].status1 & STATUS1_PARALYSIS)
speedBattler1 /= 4;
if (holdEffect == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * holdEffectParam) / 100)
speedBattler1 = UINT_MAX;
// check second battlerId's speed
speedBattler2 = (gBattleMons[battler2].speed * speedMultiplierBattler2)
* (gStatStageRatios[gBattleMons[battler2].statStages[STAT_SPEED]][0])
/ (gStatStageRatios[gBattleMons[battler2].statStages[STAT_SPEED]][1]);
if (gBattleMons[battler2].item == ITEM_ENIGMA_BERRY)
{
holdEffect = gEnigmaBerries[battler2].holdEffect;
holdEffectParam = gEnigmaBerries[battler2].holdEffectParam;
}
else
{
holdEffect = ItemId_GetHoldEffect(gBattleMons[battler2].item);
holdEffectParam = ItemId_GetHoldEffectParam(gBattleMons[battler2].item);
}
// badge boost
if (!(gBattleTypeFlags & BATTLE_TYPE_LINK)
&& FlagGet(FLAG_BADGE03_GET)
&& GetBattlerSide(battler2) == B_SIDE_PLAYER)
speedBattler2 = (speedBattler2 * 110) / 100;
if (holdEffect == HOLD_EFFECT_MACHO_BRACE)
speedBattler2 /= 2;
if (gBattleMons[battler2].status1 & STATUS1_PARALYSIS)
speedBattler2 /= 4;
if (holdEffect == HOLD_EFFECT_QUICK_CLAW && gRandomTurnNumber < (0xFFFF * holdEffectParam) / 100)
speedBattler2 = UINT_MAX;
if (ignoreChosenMoves)
{
moveBattler1 = MOVE_NONE;
moveBattler2 = MOVE_NONE;
}
else
{
if (gChosenActionByBattler[battler1] == B_ACTION_USE_MOVE)
{
if (gProtectStructs[battler1].noValidMoves)
moveBattler1 = MOVE_STRUGGLE;
else
moveBattler1 = gBattleMons[battler1].moves[*(gBattleStruct->chosenMovePositions + battler1)];
}
if (gProtectStructs[battler1].quickDraw && !gProtectStructs[battler2].quickDraw)
strikesFirst = 1;
else if (!gProtectStructs[battler1].quickDraw && gProtectStructs[battler2].quickDraw)
strikesFirst = -1;
else if (gProtectStructs[battler1].usedCustapBerry && !gProtectStructs[battler2].usedCustapBerry)
strikesFirst = 1;
else if (gProtectStructs[battler2].usedCustapBerry && !gProtectStructs[battler1].usedCustapBerry)
strikesFirst = -1;
else if (holdEffectBattler1 == HOLD_EFFECT_LAGGING_TAIL && holdEffectBattler2 != HOLD_EFFECT_LAGGING_TAIL)
strikesFirst = -1;
else if (holdEffectBattler2 == HOLD_EFFECT_LAGGING_TAIL && holdEffectBattler1 != HOLD_EFFECT_LAGGING_TAIL)
strikesFirst = 1;
else if (ability1 == ABILITY_STALL && ability2 != ABILITY_STALL)
strikesFirst = -1;
else if (ability2 == ABILITY_STALL && ability1 != ABILITY_STALL)
strikesFirst = 1;
else if (ability1 == ABILITY_MYCELIUM_MIGHT && ability2 != ABILITY_MYCELIUM_MIGHT && IS_MOVE_STATUS(gChosenMoveByBattler[battler1]))
strikesFirst = -1;
else if (ability2 == ABILITY_MYCELIUM_MIGHT && ability1 != ABILITY_MYCELIUM_MIGHT && IS_MOVE_STATUS(gChosenMoveByBattler[battler2]))
strikesFirst = 1;
else
moveBattler1 = MOVE_NONE;
if (gChosenActionByBattler[battler2] == B_ACTION_USE_MOVE)
{
if (gProtectStructs[battler2].noValidMoves)
moveBattler2 = MOVE_STRUGGLE;
else
moveBattler2 = gBattleMons[battler2].moves[*(gBattleStruct->chosenMovePositions + battler2)];
}
else
moveBattler2 = MOVE_NONE;
}
// both move priorities are different than 0
if (gMovesInfo[moveBattler1].priority != 0 || gMovesInfo[moveBattler2].priority != 0)
{
// both priorities are the same
if (gMovesInfo[moveBattler1].priority == gMovesInfo[moveBattler2].priority)
{
if (speedBattler1 == speedBattler2 && Random() & 1)
strikesFirst = 2; // same speeds, same priorities
{
strikesFirst = 0; // same speeds, same priorities
}
else if (speedBattler1 < speedBattler2)
strikesFirst = 1; // battler2 has more speed
// else battler1 has more speed
{
// battler2 has more speed
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM)
strikesFirst = 1;
else
strikesFirst = -1;
}
else
{
// battler1 has more speed
if (gFieldStatuses & STATUS_FIELD_TRICK_ROOM)
strikesFirst = -1;
else
strikesFirst = 1;
}
}
else if (gMovesInfo[moveBattler1].priority < gMovesInfo[moveBattler2].priority)
strikesFirst = 1; // battler2's move has greater priority
// else battler1's move has greater priority
}
// both priorities are equal to 0
else if (priority1 < priority2)
{
strikesFirst = -1; // battler2's move has greater priority
}
else
{
if (speedBattler1 == speedBattler2 && Random() & 1)
strikesFirst = 2; // same speeds, same priorities
else if (speedBattler1 < speedBattler2)
strikesFirst = 1; // battler2 has more speed
// else battler1 has more speed
strikesFirst = 1; // battler1's move has greater priority
}
return strikesFirst;
}
s32 GetWhichBattlerFaster(u32 battler1, u32 battler2, bool32 ignoreChosenMoves)
{
s32 priority1 = 0, priority2 = 0;
u32 ability1 = GetBattlerAbility(battler1);
u32 speedBattler1 = GetBattlerTotalSpeedStat(battler1);
u32 holdEffectBattler1 = GetBattlerHoldEffect(battler1, TRUE);
u32 speedBattler2 = GetBattlerTotalSpeedStat(battler2);
u32 holdEffectBattler2 = GetBattlerHoldEffect(battler2, TRUE);
u32 ability2 = GetBattlerAbility(battler2);
if (!ignoreChosenMoves)
{
if (gChosenActionByBattler[battler1] == B_ACTION_USE_MOVE)
priority1 = GetChosenMovePriority(battler1);
if (gChosenActionByBattler[battler2] == B_ACTION_USE_MOVE)
priority2 = GetChosenMovePriority(battler2);
}
return GetWhichBattlerFasterArgs(battler1, battler2, ignoreChosenMoves, ability1, ability2,
holdEffectBattler1, holdEffectBattler2, speedBattler1, speedBattler2, priority1, priority2);
}
static void SetActionsAndBattlersTurnOrder(void)
{
s32 turnOrderId = 0;
@ -3717,7 +3646,7 @@ static void SetActionsAndBattlersTurnOrder(void)
&& gActionsByTurnOrder[j] != B_ACTION_USE_ITEM
&& gActionsByTurnOrder[i] != B_ACTION_SWITCH
&& gActionsByTurnOrder[j] != B_ACTION_SWITCH)
if (GetWhoStrikesFirst(battler1, battler2, FALSE))
if (GetWhichBattlerFaster(battler1, battler2, FALSE) == 1)
SwapTurnOrder(i, j);
}
}
@ -4613,15 +4542,18 @@ static void HandleAction_NothingIsFainted(void)
static void HandleAction_ActionFinished(void)
{
++gCurrentTurnActionNumber;
u32 i, j;
bool32 afterYouActive = gSpecialStatuses[gBattlerByTurnOrder[gCurrentTurnActionNumber + 1]].afterYou;
*(gBattleStruct->monToSwitchIntoId + gBattlerByTurnOrder[gCurrentTurnActionNumber]) = gSelectedMonPartyId = PARTY_SIZE;
gCurrentTurnActionNumber++;
gCurrentActionFuncId = gActionsByTurnOrder[gCurrentTurnActionNumber];
SpecialStatusesClear();
gHitMarker &= ~(HITMARKER_DESTINYBOND | HITMARKER_IGNORE_SUBSTITUTE | HITMARKER_ATTACKSTRING_PRINTED
| HITMARKER_NO_PPDEDUCT | HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_IGNORE_ON_AIR
| HITMARKER_IGNORE_UNDERGROUND | HITMARKER_IGNORE_UNDERWATER | HITMARKER_PASSIVE_DAMAGE
| HITMARKER_NO_PPDEDUCT | HITMARKER_STATUS_ABILITY_EFFECT | HITMARKER_PASSIVE_DAMAGE
| HITMARKER_OBEYS | HITMARKER_WAKE_UP_CLEAR | HITMARKER_SYNCHRONISE_EFFECT
| HITMARKER_CHARGING | HITMARKER_NEVER_SET);
gCurrentMove = MOVE_NONE;
| HITMARKER_CHARGING | HITMARKER_NEVER_SET | HITMARKER_IGNORE_DISGUISE);
gCurrentMove = 0;
gBattleMoveDamage = 0;
gMoveResultFlags = 0;
gBattleScripting.animTurn = 0;
@ -4629,12 +4561,43 @@ static void HandleAction_ActionFinished(void)
gLastLandedMoves[gBattlerAttacker] = 0;
gLastHitByType[gBattlerAttacker] = 0;
gBattleStruct->dynamicMoveType = 0;
gDynamicBasePower = 0;
gBattleScripting.moveendState = 0;
gBattleCommunication[MOVE_EFFECT_BYTE] = 0;
gBattleCommunication[ACTIONS_CONFIRMED_COUNT] = 0;
gBattleCommunication[3] = 0;
gBattleCommunication[4] = 0;
gBattleScripting.multihitMoveEffect = 0;
gBattleResources->battleScriptsStack->size = 0;
gBattleStruct->dynamax.usingMaxMove[gBattlerAttacker] = 0;
if (B_RECALC_TURN_AFTER_ACTIONS >= GEN_8 && !afterYouActive && !gBattleStruct->pledgeMove)
{
// i starts at `gCurrentTurnActionNumber` because we don't want to recalculate turn order for mon that have already
// taken action. It's been previously increased, which we want in order to not recalculate the turn of the mon that just finished its action
for (i = gCurrentTurnActionNumber; i < gBattlersCount - 1; i++)
{
for (j = i + 1; j < gBattlersCount; j++)
{
u32 battler1 = gBattlerByTurnOrder[i];
u32 battler2 = gBattlerByTurnOrder[j];
if (gProtectStructs[battler1].quash || gProtectStructs[battler2].quash
|| gProtectStructs[battler1].shellTrap || gProtectStructs[battler2].shellTrap)
continue;
// We recalculate order only for action of the same priority. If any action other than switch/move has been taken, they should
// have been executed before. The only recalculation needed is for moves/switch. Mega evolution is handled in src/battle_main.c/TryChangeOrder
if((gActionsByTurnOrder[i] == B_ACTION_USE_MOVE && gActionsByTurnOrder[j] == B_ACTION_USE_MOVE))
{
if (GetWhichBattlerFaster(battler1, battler2, FALSE) == -1)
SwapTurnOrder(i, j);
}
else if ((gActionsByTurnOrder[i] == B_ACTION_SWITCH && gActionsByTurnOrder[j] == B_ACTION_SWITCH))
{
if (GetWhichBattlerFaster(battler1, battler2, TRUE) == -1) // If the actions chosen are switching, we recalc order but ignoring the moves
SwapTurnOrder(i, j);
}
}
}
}
}
s8 GetMovePriority(u32 battler, u16 move)

View File

@ -321,7 +321,6 @@ static const u16 sWhiteOutBadgeMoney[9] = { 8, 16, 24, 36, 48, 64, 80, 100, 120
static void TrySetDestinyBondToHappen(void);
static u8 AttacksThisTurn(u8 battlerId, u16 move); // Note: returns 1 if it's a charging turn, otherwise 2.
static void CheckWonderGuardAndLevitate(void);
static u32 ChangeStatBuffs(s8 statValue, u32 statId, u32 flags, const u8 *BS_ptr);
static void InitLevelUpBanner(void);
static bool8 SlideInLevelUpBanner(void);
@ -1977,16 +1976,14 @@ static void Cmd_damagecalc(void)
void AI_CalcDmg(u8 attacker, u8 defender)
{
u32 sideStatus = gSideStatuses[GET_BATTLER_SIDE(defender)];
gBattleMoveDamage = CalculateBaseDamageOld(&gBattleMons[attacker], &gBattleMons[defender], gCurrentMove,
sideStatus, gDynamicBasePower,
gBattleStruct->dynamicMoveType, attacker, defender);
gDynamicBasePower = 0;
gBattleMoveDamage = gBattleMoveDamage * gCritMultiplier * gBattleScripting.dmgMultiplier;
u8 moveType;
s32 critChance;
if (gStatuses3[attacker] & STATUS3_CHARGED_UP && gMovesInfo[gCurrentMove].type == TYPE_ELECTRIC)
gBattleMoveDamage *= 2;
if (gProtectStructs[attacker].helpingHand)
gBattleMoveDamage = gBattleMoveDamage * 15 / 10;
GET_MOVE_TYPE(gCurrentMove, moveType);
critChance = CalcCritChanceStage(attacker, defender, gCurrentMove, TRUE);
gIsCriticalHit = RandomWeighted(RNG_CRITICAL_HIT, sCriticalHitChance[critChance] - 1, 1);
gBattleMoveDamage = CalculateMoveDamage(gCurrentMove, attacker, defender, moveType, 0, gIsCriticalHit, TRUE, TRUE);
CalcTypeEffectivenessMultiplier(gCurrentMove, moveType, gBattlerAttacker, gBattlerTarget, GetBattlerAbility(gBattlerTarget), TRUE);
}
static void ModulateDmgByType(u8 multiplier)
@ -2035,81 +2032,6 @@ static void Cmd_typecalc(void)
gBattlescriptCurrInstr = cmd->nextInstr;
}
static void CheckWonderGuardAndLevitate(void)
{
u8 flags = 0;
s32 i = 0;
u8 moveType;
if (gCurrentMove == MOVE_STRUGGLE || !gMovesInfo[gCurrentMove].power)
return;
GET_MOVE_TYPE(gCurrentMove, moveType);
if (gBattleMons[gBattlerTarget].ability == ABILITY_LEVITATE && moveType == TYPE_GROUND)
{
gLastUsedAbility = ABILITY_LEVITATE;
gBattleCommunication[MISS_TYPE] = B_MSG_GROUND_MISS;
RecordAbilityBattle(gBattlerTarget, ABILITY_LEVITATE);
return;
}
while (TYPE_EFFECT_ATK_TYPE(i) != TYPE_ENDTABLE)
{
if (TYPE_EFFECT_ATK_TYPE(i) == TYPE_FORESIGHT)
{
if (gBattleMons[gBattlerTarget].status2 & STATUS2_FORESIGHT)
break;
i += 3;
continue;
}
if (TYPE_EFFECT_ATK_TYPE(i) == moveType)
{
// check no effect
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type1
&& TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_NO_EFFECT)
{
gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE;
gProtectStructs[gBattlerAttacker].targetNotAffected = 1;
}
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2 &&
gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2 &&
TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_NO_EFFECT)
{
gMoveResultFlags |= MOVE_RESULT_DOESNT_AFFECT_FOE;
gProtectStructs[gBattlerAttacker].targetNotAffected = 1;
}
// check super effective
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type1 && TYPE_EFFECT_MULTIPLIER(i) == 20)
flags |= 1;
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2
&& gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2
&& TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_SUPER_EFFECTIVE)
flags |= 1;
// check not very effective
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type1 && TYPE_EFFECT_MULTIPLIER(i) == 5)
flags |= 2;
if (TYPE_EFFECT_DEF_TYPE(i) == gBattleMons[gBattlerTarget].type2
&& gBattleMons[gBattlerTarget].type1 != gBattleMons[gBattlerTarget].type2
&& TYPE_EFFECT_MULTIPLIER(i) == TYPE_MUL_NOT_EFFECTIVE)
flags |= 2;
}
i += 3;
}
if (gBattleMons[gBattlerTarget].ability == ABILITY_WONDER_GUARD && AttacksThisTurn(gBattlerAttacker, gCurrentMove) == 2)
{
if (((flags & 2) || !(flags & 1)) && gMovesInfo[gCurrentMove].power)
{
gLastUsedAbility = ABILITY_WONDER_GUARD;
gBattleCommunication[MISS_TYPE] = B_MSG_AVOIDED_DMG;
RecordAbilityBattle(gBattlerTarget, ABILITY_WONDER_GUARD);
}
}
}
// Same as ModulateDmgByType except different arguments
static void ModulateDmgByType2(u8 multiplier, u16 move, u8 *flags)
{

View File

@ -34,14 +34,6 @@
#define BATTLE_HISTORY (gBattleResources->battleHistory)
#define SOUND_MOVES_END 0xFFFF
static const u16 sSoundMovesTable[] =
{
MOVE_GROWL, MOVE_ROAR, MOVE_SING, MOVE_SUPERSONIC, MOVE_SCREECH, MOVE_SNORE,
MOVE_UPROAR, MOVE_METAL_SOUND, MOVE_GRASS_WHISTLE, MOVE_HYPER_VOICE, SOUND_MOVES_END
};
static bool32 TryRemoveScreens(u32 battler);
static bool32 IsUnnerveAbilityOnOpposingSide(u32 battler);
static u32 GetFlingPowerFromItemId(u32 itemId);
@ -542,7 +534,7 @@ u8 DoFieldEndTurnEffects(void)
s32 j;
for (j = i + 1; j < gBattlersCount; j++)
{
if (GetWhoStrikesFirst(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE))
if (GetWhichBattlerFaster(gBattlerByTurnOrder[i], gBattlerByTurnOrder[j], FALSE) == 1)
SwapTurnOrder(i, j);
}
}
@ -8387,6 +8379,7 @@ static inline void MulByTypeEffectiveness(uq4_12_t *modifier, u32 move, u32 move
{
uq4_12_t mod = GetTypeModifier(moveType, defType);
u32 abilityAtk = GetBattlerAbility(battlerAtk);
DebugPrintfLevel(MGBA_LOG_ERROR, "MulByTypeEffectiveness: mod = %d, moveType=%d, defType=%d", mod, moveType, defType);
if (mod == UQ_4_12(0.0) && GetBattlerHoldEffect(battlerDef, TRUE) == HOLD_EFFECT_RING_TARGET)
{
@ -8591,12 +8584,18 @@ u8 GetBattlerType(u32 battler, u8 typeIndex)
if (gBattleResources->flags->flags[battler] & RESOURCE_FLAG_ROOST)
{
if (types[0] == TYPE_FLYING && types[1] == TYPE_FLYING)
{
DebugPrintfLevel(MGBA_LOG_ERROR, "GetBattlerType: roost1, typeIndex=%d, type=%d", typeIndex, B_ROOST_PURE_FLYING >= GEN_5 ? TYPE_NORMAL : TYPE_MYSTERY);
return B_ROOST_PURE_FLYING >= GEN_5 ? TYPE_NORMAL : TYPE_MYSTERY;
}
else
{
DebugPrintfLevel(MGBA_LOG_ERROR, "GetBattlerType: roost1, typeIndex=%d, type=%d", typeIndex, types[typeIndex] == TYPE_FLYING ? TYPE_MYSTERY : types[typeIndex]);
return types[typeIndex] == TYPE_FLYING ? TYPE_MYSTERY : types[typeIndex];
}
}
}
DebugPrintfLevel(MGBA_LOG_ERROR, "GetBattlerType: typeIndex=%d, type=%d", typeIndex, types[typeIndex]);
return types[typeIndex];
}

View File

@ -8273,17 +8273,17 @@
{
"min_level": 3,
"max_level": 3,
"species": "SPECIES_CASTFORM"
"species": "SPECIES_MIMIKYU"
},
{
"min_level": 3,
"max_level": 3,
"species": "SPECIES_CASTFORM"
"species": "SPECIES_MIMIKYU"
},
{
"min_level": 2,
"max_level": 2,
"species": "SPECIES_CASTFORM"
"species": "SPECIES_MIMIKYU"
},
{
"min_level": 2,

View File

@ -1803,283 +1803,6 @@ static void DeleteFirstMoveAndGiveMoveToBoxMon(struct BoxPokemon *boxMon, u16 mo
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]; \
}
// Own function in pokeemerald
#define ShouldGetStatBadgeBoost(flag, battler)\
(!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER)) && FlagGet(flag) && GetBattlerSide(battler) == B_SIDE_PLAYER)
s32 CalculateBaseDamageOld(struct BattlePokemon *attacker, struct BattlePokemon *defender, u32 move, u32 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 = gMovesInfo[move].power;
else
gBattleMovePower = powerOverride;
if (!typeOverride)
type = gMovesInfo[move].type;
else
type = typeOverride & DYNAMIC_TYPE_MASK;
attack = attacker->attack;
defense = defender->defense;
spAttack = attacker->spAttack;
spDefense = defender->spDefense;
// Get attacker hold item info
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);
}
// Get defender hold item info
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;
// Apply type-bonus hold item
for (i = 0; i < ARRAY_COUNT(sHoldEffectToType); i++)
{
if (attackerHoldEffect == sHoldEffectToType[i][0]
&& type == sHoldEffectToType[i][1])
{
if (IS_TYPE_PHYSICAL(type))
attack = (attack * (attackerHoldEffectParam + 100)) / 100;
else
spAttack = (spAttack * (attackerHoldEffectParam + 100)) / 100;
break;
}
}
// Apply boosts from hold items
if (attackerHoldEffect == HOLD_EFFECT_CHOICE_BAND)
attack = (150 * attack) / 100;
if (attackerHoldEffect == HOLD_EFFECT_SOUL_DEW && !(gBattleTypeFlags & (BATTLE_TYPE_BATTLE_TOWER)) && (attacker->species == SPECIES_LATIAS || attacker->species == SPECIES_LATIOS))
spAttack = (150 * spAttack) / 100;
if (defenderHoldEffect == HOLD_EFFECT_SOUL_DEW && !(gBattleTypeFlags & (BATTLE_TYPE_BATTLE_TOWER)) && (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_FIELD2(ABILITY_MINUS))
spAttack = (150 * spAttack) / 100;
if (attacker->ability == ABILITY_MINUS && ABILITY_ON_FIELD2(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 && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, 0, ABILITYEFFECT_MUD_SPORT, 0))
gBattleMovePower /= 2;
if (type == TYPE_FIRE && AbilityBattleEffects(ABILITYEFFECT_FIELD_SPORT, 0, 0, ABILITYEFFECT_WATER_SPORT, 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;
// Self-destruct / Explosion cut defense in half
if (gMovesInfo[gCurrentMove].effect == EFFECT_EXPLOSION)
defense /= 2;
if (IS_TYPE_PHYSICAL(type))
{
if (gCritMultiplier == 2)
{
// Critical hit, if attacker has lost attack stat stages then ignore stat drop
if (attacker->statStages[STAT_ATK] > DEFAULT_STAT_STAGE)
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)
{
// Critical hit, if defender has gained defense stat stages then ignore stat increase
if (defender->statStages[STAT_DEF] < DEFAULT_STAT_STAGE)
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;
// Burn cuts attack in half
if ((attacker->status1 & STATUS1_BURN) && attacker->ability != ABILITY_GUTS)
damage /= 2;
// Apply Reflect
if ((sideStatus & SIDE_STATUS_REFLECT) && gCritMultiplier == 1)
{
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerTarget) == 2)
damage = 2 * (damage / 3);
else
damage /= 2;
}
// Moves hitting both targets do half damage in double battles
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gMovesInfo[move].target == MOVE_TARGET_BOTH && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerTarget) == 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 (IS_TYPE_SPECIAL(type))
{
if (gCritMultiplier == 2)
{
// Critical hit, if attacker has lost sp. attack stat stages then ignore stat drop
if (attacker->statStages[STAT_SPATK] > DEFAULT_STAT_STAGE)
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)
{
// Critical hit, if defender has gained sp. defense stat stages then ignore stat increase
if (defender->statStages[STAT_SPDEF] < DEFAULT_STAT_STAGE)
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;
// Apply Lightscreen
if ((sideStatus & SIDE_STATUS_LIGHTSCREEN) && gCritMultiplier == 1)
{
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerTarget) == 2)
damage = 2 * (damage / 3);
else
damage /= 2;
}
// Moves hitting both targets do half damage in double battles
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && gMovesInfo[move].target == MOVE_TARGET_BOTH && CountAliveMonsInBattle(BATTLE_ALIVE_SIDE, gBattlerTarget) == 2)
damage /= 2;
// Are effects of weather negated with cloud nine or air lock
if (WEATHER_HAS_EFFECT2)
{
// Rain weakens Fire, boosts Water
if (gBattleWeather & B_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 & (B_WEATHER_RAIN | B_WEATHER_SANDSTORM | B_WEATHER_HAIL_TEMPORARY)) && gCurrentMove == MOVE_SOLAR_BEAM)
damage /= 2;
// Sun boosts Fire, weakens Water
if (gBattleWeather & B_WEATHER_SUN)
{
switch (type)
{
case TYPE_FIRE:
damage = (15 * damage) / 10;
break;
case TYPE_WATER:
damage /= 2;
break;
}
}
}
// Flash fire triggered
if ((gBattleResources->flags->flags[battlerIdAtk] & RESOURCE_FLAG_FLASH_FIRE) && type == TYPE_FIRE)
damage = (15 * damage) / 10;
}
return damage + 2;
}
u8 CountAliveMonsInBattle(u8 caseId, u32 battler)
{
s32 i;