From 963be8c077792e623db52c7dac2e44dcb52cf296 Mon Sep 17 00:00:00 2001 From: cawtds Date: Fri, 3 May 2024 11:57:21 +0200 Subject: [PATCH] fixed bug with type3 not being intialized leading to wrong type calculations removed unused functions --- include/battle_main.h | 3 + include/pokemon.h | 1 - src/battle_ai_script_commands.c | 4 +- src/battle_main.c | 273 ++++++++++++++----------------- src/battle_script_commands.c | 92 +---------- src/battle_util.c | 19 ++- src/data/wild_encounters.json | 6 +- src/pokemon.c | 277 -------------------------------- 8 files changed, 142 insertions(+), 533 deletions(-) diff --git a/include/battle_main.h b/include/battle_main.h index 16b3ac5b2..2a589e369 100644 --- a/include/battle_main.h +++ b/include/battle_main.h @@ -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 diff --git a/include/pokemon.h b/include/pokemon.h index c86804f5f..c4512dc1f 100644 --- a/include/pokemon.h +++ b/include/pokemon.h @@ -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); diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index bfa8df2f6..d788392ee 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -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; diff --git a/src/battle_main.c b/src/battle_main.c index 349ae5d82..c47a2acbd 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -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) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 2147db967..3b19d81c4 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -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) { diff --git a/src/battle_util.c b/src/battle_util.c index 2ce10fc83..75e8b5c8c 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -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]; } diff --git a/src/data/wild_encounters.json b/src/data/wild_encounters.json index def9ade07..99074872f 100644 --- a/src/data/wild_encounters.json +++ b/src/data/wild_encounters.json @@ -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, diff --git a/src/pokemon.c b/src/pokemon.c index 7f3560b7c..3340a0e13 100644 --- a/src/pokemon.c +++ b/src/pokemon.c @@ -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;