diff options
author | DizzyEggg <jajkodizzy@wp.pl> | 2017-09-04 21:43:13 +0200 |
---|---|---|
committer | DizzyEggg <jajkodizzy@wp.pl> | 2017-09-04 21:43:13 +0200 |
commit | 2702b0ec9b4b2ae25d847ccd3b5b8ec1ad8cf1ff (patch) | |
tree | f804cd23f6dd6d2c1ca6b132d667be7951d7bb29 /src | |
parent | 92892d140a2ed704a1cfa2748ea015c9007da14c (diff) |
decomp calc dmg and clean up battle ai
Diffstat (limited to 'src')
-rw-r--r-- | src/battle_ai.c | 240 | ||||
-rw-r--r-- | src/calculate_base_damage.c | 284 | ||||
-rw-r--r-- | src/load_save.c | 25 |
3 files changed, 367 insertions, 182 deletions
diff --git a/src/battle_ai.c b/src/battle_ai.c index 7c4b7604d..f8a52c889 100644 --- a/src/battle_ai.c +++ b/src/battle_ai.c @@ -3,6 +3,7 @@ #include "battle.h" #include "species.h" #include "abilities.h" +#include "rng.h" #define AIScriptRead32(ptr) ((ptr)[0] | (ptr)[1] << 8 | (ptr)[2] << 16 | (ptr)[3] << 24) #define AIScriptRead16(ptr) ((ptr)[0] | (ptr)[1] << 8) @@ -10,9 +11,7 @@ #define AIScriptReadPtr(ptr) (u8*) AIScriptRead32(ptr) #define AI_THINKING_STRUCT ((struct AI_ThinkingStruct *)(gBattleResources->ai)) -#define UNK_2016A00_STRUCT ((struct UnknownStruct2 *)(gBattleResources->unk18)) -#define UNK_2016C00_STRUCT ((struct UnknownStruct4 *)(gBattleResources->unk1C)) -#define UNK_BATTLE_STRUCT ((struct UnknownStruct1 *)(gBattleResources)) +#define BATTLE_HISTORY ((struct BattleHistory *)(gBattleResources->battleHistory)) #define AI_ACTION_UNK1 0x0001 #define AI_ACTION_UNK2 0x0002 @@ -54,112 +53,6 @@ struct Trainer /*0x24*/ void *party; }; -#define POKEMON_NAME_LENGTH 10 - -struct BattlePokemon -{ - /* 0x00 */ u16 species; - /* 0x02 */ u16 attack; - /* 0x04 */ u16 defense; - /* 0x06 */ u16 speed; - /* 0x08 */ u16 spAttack; - /* 0x0A */ u16 spDefense; - /* 0x0C */ u16 moves[4]; - /* 0x14 */ u32 hpIV:5; - /* 0x14 */ u32 attackIV:5; - /* 0x15 */ u32 defenseIV:5; - /* 0x15 */ u32 speedIV:5; - /* 0x16 */ u32 spAttackIV:5; - /* 0x17 */ u32 spDefenseIV:5; - /* 0x17 */ u32 isEgg:1; - /* 0x17 */ u32 altAbility:1; - /* 0x18 */ s8 statStages[8]; - /* 0x20 */ u8 ability; - /* 0x21 */ u8 type1; - /* 0x22 */ u8 type2; - /* 0x23 */ u8 unknown; - /* 0x24 */ u8 pp[4]; - /* 0x28 */ u16 hp; - /* 0x2A */ u8 level; - /* 0x2B */ u8 friendship; - /* 0x2C */ u16 maxHP; - /* 0x2E */ u16 item; - /* 0x30 */ u8 nickname[POKEMON_NAME_LENGTH + 1]; - /* 0x3B */ u8 ppBonuses; - /* 0x3C */ u8 otName[8]; - /* 0x44 */ u32 experience; - /* 0x48 */ u32 personality; - /* 0x4C */ u32 status1; - /* 0x50 */ u32 status2; - /* 0x54 */ u32 otId; -}; - -//size should be 0x1C -struct AI_ThinkingStruct -{ - u8 aiState; - u8 movesetIndex; - u16 moveConsidered; - s8 score[4]; - u32 funcResult; - u32 aiFlags; - u8 aiAction; - u8 aiLogicId; - u8 filler12[6]; - u8 unk18[4]; -}; - -//size should be 0x54 -struct UnknownStruct2 -{ - u16 unk0[2][8]; - u8 unk20[2]; - u8 filler20[0x1E]; - u8 unk40[4]; - u8 unk44[4]; - u16 unk48[4]; - u8 unk50; -}; - -struct UnknownStruct4 -{ - u8 *ptr[8]; - u8 unk20; -}; - -struct SimpleUnknownStruct -{ - u32 unkArray[4]; // unknown size -}; - -struct UnknownStruct1 -{ - u8 unk0; - u8 filler1[0x3]; - struct SimpleUnknownStruct *unk4; - u8 filler8[0xC]; - struct AI_ThinkingStruct *ai; - struct UnknownStruct2 *unk18; - struct UnknownStruct4 *unk1C; -}; - -struct UnknownStruct5 -{ - u8 filler0[0x3]; - u16 unk4; - u16 unk6; - u8 unk8; - u8 unk9; - u8 fillerA[0x9]; - u8 taunt:4; - u8 unkC:4; - u8 fillerD[0x2]; - u8 unk16; - u8 filler17[0x4]; -}; - -extern struct UnknownStruct5 gDisableStructs[]; - /* gAIScriptPtr is a pointer to the next battle AI cmd command to read. when a command finishes processing, gAIScriptPtr is incremented by @@ -177,7 +70,6 @@ extern u8 gBankTarget; extern u8 gAbsentBankFlags; extern u16 gUnknown_02024248[]; extern u8 *gBattleStruct; -extern struct UnknownStruct1 *gBattleResources; extern u16 gUnknown_02038BCA; extern u16 gUnknown_02038BCC; extern u8 gPlayerMonIndex; @@ -211,8 +103,6 @@ typedef void (*BattleAICmdFunc)(void); extern const BattleAICmdFunc sBattleAICmdTable[]; extern u8 sub_803FECC(); -extern u16 Random(); -extern u8 GetBankSide(); extern u32 sub_8186438(); extern u32 sub_81A6FB4(); @@ -225,8 +115,8 @@ void BattleAI_DoAIProcessing(void); void BattleAI_HandleItemUseBeforeAISetup(u8 a) { s32 i; - u8 *data = (u8 *)gBattleResources->unk18; - + u8 *data = (u8 *)gBattleResources->battleHistory; + for (i = 0; (u32)i < 0x54; i++) data[i] = 0; if ((gBattleTypeFlags & 0x0A7F098A) == 8) @@ -235,12 +125,12 @@ void BattleAI_HandleItemUseBeforeAISetup(u8 a) { if (gTrainers[gUnknown_02038BCA].items[i] != 0) { - gBattleResources->unk18->unk48[gBattleResources->unk18->unk50] = gTrainers[gUnknown_02038BCA].items[i]; - gBattleResources->unk18->unk50++; + gBattleResources->battleHistory->TrainerItems[gBattleResources->battleHistory->unk50] = gTrainers[gUnknown_02038BCA].items[i]; + gBattleResources->battleHistory->unk50++; } } } - + BattleAI_SetupAIData(a); } @@ -273,7 +163,7 @@ void BattleAI_SetupAIData(u8 a) AI_THINKING_STRUCT->unk18[i] = 100 - (Random() % 16); } - gBattleResources->unk1C->unk20 = 0; + gBattleResources->AI_ScriptsStack->size = 0; gPlayerMonIndex = gActiveBank; if (gBattleTypeFlags & 1) { @@ -311,7 +201,7 @@ u8 sub_8130BA4(void) { u16 r4 = gCurrentMove; u8 ret; - + if (!(gBattleTypeFlags & 1)) ret = BattleAI_GetAIActionToUse(); else @@ -327,7 +217,7 @@ u8 BattleAI_GetAIActionToUse(void) u8 consideredMoveArray[4]; u8 numOfBestMoves; s32 i; - + sub_8131074(); while (AI_THINKING_STRUCT->aiFlags != 0) @@ -391,7 +281,7 @@ u8 sub_8130CF4(void) //u8 *sp1C = spC; //u8 *sp18 = sp8; //u8 *sp20 = spC; - + for (i = 0; i < 4; i++) //_08130D14 { if (i == gPlayerMonIndex || gBattleMons[i].hp == 0) @@ -465,9 +355,9 @@ u8 sub_8130CF4(void) } //_08130EAE } - + //#define i r5 - + //_08130EC4 r5_2 = sp0[0]; sp8[0] = 0; @@ -835,15 +725,15 @@ void BattleAI_DoAIProcessing(void) void sub_8131074(void) { s32 i; - + for (i = 0; i < 4; i++) { - if (gBattleResources->unk18->unk0[gBankTarget][i] == gUnknown_02024248[gBankTarget]) + if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] == gUnknown_02024248[gBankTarget]) break; - if (gBattleResources->unk18->unk0[gBankTarget][i] != gUnknown_02024248[gBankTarget] //HACK: This redundant condition is a hack to make the asm match. - && gBattleResources->unk18->unk0[gBankTarget][i] == 0) + if (gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] != gUnknown_02024248[gBankTarget] //HACK: This redundant condition is a hack to make the asm match. + && gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] == 0) { - gBattleResources->unk18->unk0[gBankTarget][i] = gUnknown_02024248[gBankTarget]; + gBattleResources->battleHistory->usedMoves[gBankTarget].moves[i] = gUnknown_02024248[gBankTarget]; break; } } @@ -852,29 +742,29 @@ void sub_8131074(void) void sub_81310F0(u8 a) { s32 i; - + for (i = 0; i < 4; i++) - gBattleResources->unk18->unk0[a][i] = 0; + gBattleResources->battleHistory->usedMoves[a].moves[i] = 0; } void RecordAbilityBattle(u8 a, u8 b) { - gBattleResources->unk18->unk40[a] = b; + gBattleResources->battleHistory->abilities[a] = b; } void sub_8131130(u8 a) { - gBattleResources->unk18->unk40[a] = 0; + gBattleResources->battleHistory->abilities[a] = 0; } void b_history__record_item_x12_of_player(u8 a, u8 b) { - gBattleResources->unk18->unk44[a] = b; + gBattleResources->battleHistory->itemEffects[a] = b; } void sub_8131160(u8 a) { - gBattleResources->unk18->unk44[a] = 0; + gBattleResources->battleHistory->itemEffects[a] = 0; } void BattleAICmd_if_random_less_than(void) @@ -1372,7 +1262,7 @@ u8 sub_8131E70(u8 index) void BattleAICmd_unk_5F(void) { u8 index = sub_8131E70(gAIScriptPtr[1]); - + if(gBattleMons[index].type1 == gAIScriptPtr[2] || gBattleMons[index].type2 == gAIScriptPtr[2]) { AI_THINKING_STRUCT->funcResult = 1; @@ -1754,16 +1644,16 @@ void BattleAICmd_get_ability(void) if(gActiveBank != index) { - if(UNK_2016A00_STRUCT->unk40[index] != 0) + if(BATTLE_HISTORY->abilities[index] != 0) { - AI_THINKING_STRUCT->funcResult = UNK_2016A00_STRUCT->unk40[index]; + AI_THINKING_STRUCT->funcResult = BATTLE_HISTORY->abilities[index]; gAIScriptPtr += 2; return; } - + // abilities that prevent fleeing. - if (gBattleMons[index].ability == ABILITY_SHADOW_TAG - || gBattleMons[index].ability == ABILITY_MAGNET_PULL + if (gBattleMons[index].ability == ABILITY_SHADOW_TAG + || gBattleMons[index].ability == ABILITY_MAGNET_PULL || gBattleMons[index].ability == ABILITY_ARENA_TRAP) { AI_THINKING_STRUCT->funcResult = gBattleMons[index].ability; @@ -1784,7 +1674,7 @@ void BattleAICmd_get_ability(void) { AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability2; } - } + } else { AI_THINKING_STRUCT->funcResult = gBaseStats[gBattleMons[index].species].ability1; // it's definitely ability 1. @@ -1809,20 +1699,20 @@ void tai60_unk(void) u8 index = sub_8131E70(gAIScriptPtr[1]); u8 arg2 = gAIScriptPtr[2]; u8 var; - + if(gAIScriptPtr[1] == 0 || gAIScriptPtr[1] == 2) { // _0813253A - if(UNK_2016A00_STRUCT->unk40[index] != 0) + if(BATTLE_HISTORY->abilities[index] != 0) { - var = UNK_2016A00_STRUCT->unk40[index]; + var = BATTLE_HISTORY->abilities[index]; AI_THINKING_STRUCT->funcResult = var; } else { // _0813255C - if (gBattleMons[index].ability == ABILITY_SHADOW_TAG - || gBattleMons[index].ability == ABILITY_MAGNET_PULL + if (gBattleMons[index].ability == ABILITY_SHADOW_TAG + || gBattleMons[index].ability == ABILITY_MAGNET_PULL || gBattleMons[index].ability == ABILITY_ARENA_TRAP) { var = gBattleMons[index].ability; @@ -1862,7 +1752,7 @@ void tai60_unk(void) // _081325BC var = gBattleMons[index].ability; } - + // _081325CA if(var == ABILITY_NONE) { @@ -2317,7 +2207,7 @@ void BattleAICmd_if_has_move(void) { int i; u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); - + switch(gAIScriptPtr[1]) { case 1: @@ -2336,7 +2226,7 @@ void BattleAICmd_if_has_move(void) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); return; - } + } case 3: // new to Emerald if(gBattleMons[gPlayerMonIndex ^ 2].hp == 0) { @@ -2360,12 +2250,12 @@ void BattleAICmd_if_has_move(void) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); return; - } + } case 0: case 2: for (i = 0; i < 4; i++) { - if (UNK_2016A00_STRUCT->unk0[gBankTarget][i] == *temp_ptr) + if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] == *temp_ptr) break; } if (i == 4) @@ -2385,7 +2275,7 @@ void BattleAICmd_if_dont_have_move(void) { int i; u16 *temp_ptr = (u16 *)(gAIScriptPtr + 2); - + switch(gAIScriptPtr[1]) { case 1: @@ -2409,7 +2299,7 @@ void BattleAICmd_if_dont_have_move(void) case 2: for (i = 0; i < 4; i++) { - if (UNK_2016A00_STRUCT->unk0[gBankTarget][i] == *temp_ptr) + if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] == *temp_ptr) break; } if (i != 4) @@ -2447,7 +2337,7 @@ void BattleAICmd_if_move_effect(void) case 2: // _08133090 for (i = 0; i < 4; i++) { - if (gBattleMons[gPlayerMonIndex].moves[i] != 0 && gBattleMoves[UNK_2016A00_STRUCT->unk0[gBankTarget][i]].effect == gAIScriptPtr[2]) + if (gBattleMons[gPlayerMonIndex].moves[i] != 0 && gBattleMoves[BATTLE_HISTORY->usedMoves[gBankTarget].moves[i]].effect == gAIScriptPtr[2]) break; } if (i == 4) @@ -2480,7 +2370,7 @@ void BattleAICmd_if_not_move_effect(void) case 2: // _08133188 for (i = 0; i < 4; i++) { - if (UNK_2016A00_STRUCT->unk0[gBankTarget][i] && gBattleMoves[UNK_2016A00_STRUCT->unk0[gBankTarget][i]].effect == gAIScriptPtr[2]) + if (BATTLE_HISTORY->usedMoves[gBankTarget].moves[i] && gBattleMoves[BATTLE_HISTORY->usedMoves[gBankTarget].moves[i]].effect == gAIScriptPtr[2]) break; } if (i != 4) @@ -2502,7 +2392,7 @@ void BattleAICmd_if_last_move_did_damage(void) if (gAIScriptPtr[2] == 0) { - if (gDisableStructs[index].unk4 == 0) + if (gDisableStructs[index].disabledMove == 0) { gAIScriptPtr += 7; return; @@ -2515,7 +2405,7 @@ void BattleAICmd_if_last_move_did_damage(void) gAIScriptPtr += 7; return; } - else if (gDisableStructs[index].unk6 != 0) + else if (gDisableStructs[index].encoredMove != 0) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 3); return; @@ -2528,7 +2418,7 @@ void BattleAICmd_if_encored(void) switch (gAIScriptPtr[1]) { case 0: // _08109348 - if (gDisableStructs[gActiveBank].unk4 == AI_THINKING_STRUCT->moveConsidered) + if (gDisableStructs[gActiveBank].disabledMove == AI_THINKING_STRUCT->moveConsidered) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); return; @@ -2536,7 +2426,7 @@ void BattleAICmd_if_encored(void) gAIScriptPtr += 6; return; case 1: // _08109370 - if (gDisableStructs[gActiveBank].unk6 == AI_THINKING_STRUCT->moveConsidered) + if (gDisableStructs[gActiveBank].encoredMove == AI_THINKING_STRUCT->moveConsidered) { gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); return; @@ -2581,7 +2471,7 @@ void BattleAICmd_get_hold_effect(void) if (gActiveBank != index) { - AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(UNK_2016A00_STRUCT->unk44[index]); + AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(BATTLE_HISTORY->itemEffects[index]); } else AI_THINKING_STRUCT->funcResult = ItemId_GetHoldEffect(gBattleMons[index].item); @@ -2594,16 +2484,16 @@ void tai62_unk(void) u8 index = sub_8131E70(gAIScriptPtr[1]); u16 item; u8 var1, var2; - + if((index & 1) == (gPlayerMonIndex & 1)) item = gBattleMons[index].item; else - item = UNK_2016A00_STRUCT->unk44[index]; + item = BATTLE_HISTORY->itemEffects[index]; // strange way of loading a 16-bit argument from the AI command. var2 = gAIScriptPtr[2]; var1 = gAIScriptPtr[3]; - + if((var1 | var2) == item) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 4); else @@ -2633,7 +2523,7 @@ void BattleAICmd_is_first_turn(void) else index = gBankTarget; - AI_THINKING_STRUCT->funcResult = gDisableStructs[index].unk16; + AI_THINKING_STRUCT->funcResult = gDisableStructs[index].isFirstTurn; gAIScriptPtr += 2; } @@ -2647,7 +2537,7 @@ void BattleAICmd_get_stockpile_count(void) else index = gBankTarget; - AI_THINKING_STRUCT->funcResult = gDisableStructs[index].unk9; + AI_THINKING_STRUCT->funcResult = gDisableStructs[index].stockpileCounter; gAIScriptPtr += 2; } @@ -2704,7 +2594,7 @@ void BattleAICmd_get_protect_count(void) else index = gBankTarget; - AI_THINKING_STRUCT->funcResult = gDisableStructs[index].unk8; + AI_THINKING_STRUCT->funcResult = gDisableStructs[index].protectUses; gAIScriptPtr += 2; } @@ -2783,7 +2673,7 @@ void BattleAICmd_if_level_cond(void) void BattleAICmd_if_taunted(void) { - if (gDisableStructs[gBankTarget].taunt != 0) + if (gDisableStructs[gBankTarget].tauntTimer1 != 0) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); else gAIScriptPtr += 5; @@ -2791,7 +2681,7 @@ void BattleAICmd_if_taunted(void) void BattleAICmd_if_not_taunted(void) { - if (gDisableStructs[gBankTarget].taunt == 0) + if (gDisableStructs[gBankTarget].tauntTimer1 == 0) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 1); else gAIScriptPtr += 5; @@ -2808,8 +2698,8 @@ void tai5E_unk(void) void tai61_unk(void) { u8 index = sub_8131E70(gAIScriptPtr[1]); - - if(UNK_BATTLE_STRUCT->unk4->unkArray[index] & 1) + + if(gBattleResources->flags->flags[index] & 1) gAIScriptPtr = AIScriptReadPtr(gAIScriptPtr + 2); else gAIScriptPtr += 6; @@ -2817,20 +2707,20 @@ void tai61_unk(void) void b_mc_stack_push(u8 *var) { - UNK_2016C00_STRUCT->ptr[UNK_2016C00_STRUCT->unk20++] = var; + gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = var; } void b_mc_stack_push_cursor(void) { - UNK_2016C00_STRUCT->ptr[UNK_2016C00_STRUCT->unk20++] = gAIScriptPtr; + gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size++] = gAIScriptPtr; } bool8 b_mc_stack_pop_cursor(void) { - if (UNK_2016C00_STRUCT->unk20 != 0) + if (gBattleResources->AI_ScriptsStack->size != 0) { - --UNK_2016C00_STRUCT->unk20; - gAIScriptPtr = UNK_2016C00_STRUCT->ptr[UNK_2016C00_STRUCT->unk20]; + --gBattleResources->AI_ScriptsStack->size; + gAIScriptPtr = gBattleResources->AI_ScriptsStack->ptr[gBattleResources->AI_ScriptsStack->size]; return TRUE; } else diff --git a/src/calculate_base_damage.c b/src/calculate_base_damage.c new file mode 100644 index 000000000..be0bb9b6b --- /dev/null +++ b/src/calculate_base_damage.c @@ -0,0 +1,284 @@ +#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; + +u8 CountAliveMonsInBattle(u8); +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_BATTLE_TOWER | BATTLE_TYPE_FRONTIER)) && (attacker->species == SPECIES_LATIAS || attacker->species == SPECIES_LATIOS)) + spAttack = (150 * spAttack) / 100; + if (defenderHoldEffect == HOLD_EFFECT_SOUL_DEW && !(gBattleTypeFlags & (BATTLE_TYPE_BATTLE_TOWER | 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; +} diff --git a/src/load_save.c b/src/load_save.c index 43b2475f3..bc3839346 100644 --- a/src/load_save.c +++ b/src/load_save.c @@ -63,11 +63,20 @@ void SetSaveBlocksPointers(u16 offset) SetBagItemsPointers(); SetDecorationInventoriesPointers(); } + +struct SaveBlocksInOne +{ + struct SaveBlock2 sav2; + struct SaveBlock1 sav1; + struct PokemonStorage sav3; +}; + /* void MoveSaveBlocks_ResetHeap(void) { void *vblankCB, *hblankCB; u32 encryptionKey; + struct SaveBlocksInOne* copiedSavs; // save interrupt functions and turn them off vblankCB = gMain.vblankCallback; @@ -76,19 +85,21 @@ void MoveSaveBlocks_ResetHeap(void) gMain.hblankCallback = NULL; gUnknown_0203CF5C = NULL; + copiedSavs = (void*)(gHeap); + // copy saveblocks' content - memcpy(gHeap, gSaveBlock2Ptr, sizeof(struct SaveBlock2)); - memcpy(gHeap + sizeof(struct SaveBlock2), gSaveBlock1Ptr, sizeof(struct SaveBlock1)); - memcpy(gHeap + sizeof(struct SaveBlock2) + sizeof(struct SaveBlock1), gPokemonStoragePtr, sizeof(struct PokemonStorage)); + copiedSavs->sav2 = *gSaveBlock2Ptr; + copiedSavs->sav1 = *gSaveBlock1Ptr; + copiedSavs->sav3 = *gPokemonStoragePtr; // change saveblocks' pointers // argument is a sum of the individual trainerId bytes - SetSaveBlocksPointers(gHeap[10] + gHeap[11] + gHeap[12] + gHeap[13]); + SetSaveBlocksPointers(copiedSavs->sav2.playerTrainerId[0] + copiedSavs->sav2.playerTrainerId[1] + copiedSavs->sav2.playerTrainerId[2] + copiedSavs->sav2.playerTrainerId[3]); // restore saveblock data since the pointers changed - memcpy(gSaveBlock2Ptr, gHeap, sizeof(struct SaveBlock2)); - memcpy(gSaveBlock1Ptr, gHeap + sizeof(struct SaveBlock2), sizeof(struct SaveBlock1)); - memcpy(gPokemonStoragePtr, gHeap + sizeof(struct SaveBlock2) + sizeof(struct SaveBlock1), sizeof(struct PokemonStorage)); + *gSaveBlock2Ptr = copiedSavs->sav2; + *gSaveBlock1Ptr = copiedSavs->sav1; + *gPokemonStoragePtr = copiedSavs->sav3; // heap was destroyed in the copying process, so reset it InitHeap(gHeap, sizeof(gHeap)); |