diff options
author | jiangzhengwenjz <jiangzhengwenjzw@qq.com> | 2019-08-02 05:05:35 +0800 |
---|---|---|
committer | jiangzhengwenjz <jiangzhengwenjzw@qq.com> | 2019-08-02 05:05:35 +0800 |
commit | c2964e818143757ca5586b1a811669a1c287e870 (patch) | |
tree | a0e7eed74397995d6e7f4970d43a40f6e9a97b9c /src | |
parent | 3eb1f1bc783308dac445eaacc05c9f14e9b78822 (diff) |
ported battle_util from pokeem
Diffstat (limited to 'src')
-rw-r--r-- | src/battle_ai_script_commands.c | 2 | ||||
-rw-r--r-- | src/battle_util.c | 882 |
2 files changed, 879 insertions, 5 deletions
diff --git a/src/battle_ai_script_commands.c b/src/battle_ai_script_commands.c index 913068aed..1be10d228 100644 --- a/src/battle_ai_script_commands.c +++ b/src/battle_ai_script_commands.c @@ -485,7 +485,7 @@ void RecordAbilityBattle(u8 a, u8 b) BATTLE_HISTORY->abilities[GetBattlerPosition(a) & 1] = b; } -void sub_80C7208(u8 a, u8 b) +void RecordItemEffectBattle(u8 a, u8 b) { if (GetBattlerSide(a) == 0) BATTLE_HISTORY->itemEffects[GetBattlerPosition(a) & 1] = b; diff --git a/src/battle_util.c b/src/battle_util.c index 55f674215..cf91b122f 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -8,25 +8,28 @@ #include "pokemon.h" #include "string_util.h" #include "field_weather.h" +#include "event_data.h" #include "battle.h" #include "battle_anim.h" #include "battle_scripts.h" #include "battle_message.h" +#include "constants/battle_anim.h" #include "battle_controllers.h" +#include "battle_string_ids.h" #include "battle_ai_script_commands.h" #include "constants/battle.h" #include "constants/moves.h" #include "constants/items.h" +#include "constants/flags.h" #include "constants/species.h" #include "constants/weather.h" #include "constants/abilities.h" #include "constants/pokemon.h" -#include "constants/battle_anim.h" #include "constants/hold_effects.h" #include "constants/battle_move_effects.h" #include "constants/battle_script_commands.h" -const u16 sSoundMovesTable[] = +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, 0xFFFF @@ -392,6 +395,7 @@ u8 GetImprisonedMovesCount(u8 battlerId, u16 move) if (battlerSide != GetBattlerSide(i) && gStatuses3[i] & STATUS3_IMPRISONED_OTHERS) { s32 j; + for (j = 0; j < MAX_MON_MOVES && move != gBattleMons[i].moves[j]; ++j); if (j < MAX_MON_MOVES) ++imprisonedMoves; @@ -914,6 +918,7 @@ u8 DoBattlerEndTurnEffects(void) if (gDisableStructs[gActiveBattler].disableTimer != 0) { s32 i; + for (i = 0; i < MAX_MON_MOVES; ++i) { if (gDisableStructs[gActiveBattler].disabledMove == gBattleMons[gActiveBattler].moves[i]) @@ -1582,7 +1587,6 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA if (gBattlerAttacker >= gBattlersCount) gBattlerAttacker = battler; - if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) pokeAtk = &gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]]; else @@ -1992,7 +1996,7 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA } break; case ABILITYEFFECT_IMMUNITY: // 5 - for (battler = 0; battler < gBattlersCount; battler++) + for (battler = 0; battler < gBattlersCount; ++battler) { switch (gBattleMons[battler].ability) { @@ -2323,3 +2327,873 @@ u8 AbilityBattleEffects(u8 caseID, u8 battler, u8 ability, u8 special, u16 moveA } return effect; } + +void BattleScriptExecute(const u8 *BS_ptr) +{ + gBattlescriptCurrInstr = BS_ptr; + gBattleResources->battleCallbackStack->function[gBattleResources->battleCallbackStack->size++] = gBattleMainFunc; + gBattleMainFunc = RunBattleScriptCommands_PopCallbacksStack; + gCurrentActionFuncId = 0; +} + +void BattleScriptPushCursorAndCallback(const u8 *BS_ptr) +{ + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BS_ptr; + gBattleResources->battleCallbackStack->function[gBattleResources->battleCallbackStack->size++] = gBattleMainFunc; + gBattleMainFunc = RunBattleScriptCommands; +} + +enum +{ + ITEM_NO_EFFECT, + ITEM_STATUS_CHANGE, + ITEM_EFFECT_OTHER, + ITEM_PP_CHANGE, + ITEM_HP_CHANGE, + ITEM_STATS_CHANGE, +}; + +u8 ItemBattleEffects(u8 caseID, u8 battlerId, bool8 moveTurn) +{ + int i = 0; + u8 effect = ITEM_NO_EFFECT; + u8 changedPP = 0; + u8 battlerHoldEffect, atkHoldEffect, defHoldEffect; + u8 battlerHoldEffectParam, atkHoldEffectParam, defHoldEffectParam; + u16 atkItem, defItem; + + gLastUsedItem = gBattleMons[battlerId].item; + if (gLastUsedItem == ITEM_ENIGMA_BERRY) + { + battlerHoldEffect = gEnigmaBerries[battlerId].holdEffect; + battlerHoldEffectParam = gEnigmaBerries[battlerId].holdEffectParam; + } + else + { + battlerHoldEffect = ItemId_GetHoldEffect(gLastUsedItem); + battlerHoldEffectParam = ItemId_GetHoldEffectParam(gLastUsedItem); + } + + atkItem = gBattleMons[gBattlerAttacker].item; + if (atkItem == ITEM_ENIGMA_BERRY) + { + atkHoldEffect = gEnigmaBerries[gBattlerAttacker].holdEffect; + atkHoldEffectParam = gEnigmaBerries[gBattlerAttacker].holdEffectParam; + } + else + { + atkHoldEffect = ItemId_GetHoldEffect(atkItem); + atkHoldEffectParam = ItemId_GetHoldEffectParam(atkItem); + } + + // def variables are unused + defItem = gBattleMons[gBattlerTarget].item; + if (defItem == ITEM_ENIGMA_BERRY) + { + defHoldEffect = gEnigmaBerries[gBattlerTarget].holdEffect; + defHoldEffectParam = gEnigmaBerries[gBattlerTarget].holdEffectParam; + } + else + { + defHoldEffect = ItemId_GetHoldEffect(defItem); + defHoldEffectParam = ItemId_GetHoldEffectParam(defItem); + } + switch (caseID) + { + case ITEMEFFECT_ON_SWITCH_IN: + switch (battlerHoldEffect) + { + case HOLD_EFFECT_DOUBLE_PRIZE: + gBattleStruct->moneyMultiplier = 2; + break; + case HOLD_EFFECT_RESTORE_STATS: + for (i = 0; i < NUM_BATTLE_STATS; ++i) + { + if (gBattleMons[battlerId].statStages[i] < 6) + { + gBattleMons[battlerId].statStages[i] = 6; + effect = ITEM_STATS_CHANGE; + } + } + if (effect) + { + gBattleScripting.battler = battlerId; + gPotentialItemEffectBattler = battlerId; + gActiveBattler = gBattlerAttacker = battlerId; + BattleScriptExecute(BattleScript_WhiteHerbEnd2); + } + break; + } + break; + case 1: + if (gBattleMons[battlerId].hp) + { + switch (battlerHoldEffect) + { + case HOLD_EFFECT_RESTORE_HP: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn) + { + gBattleMoveDamage = battlerHoldEffectParam; + if (gBattleMons[battlerId].hp + battlerHoldEffectParam > gBattleMons[battlerId].maxHP) + gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp; + gBattleMoveDamage *= -1; + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); + effect = 4; + } + break; + case HOLD_EFFECT_RESTORE_PP: + if (!moveTurn) + { + struct Pokemon *mon; + u8 ppBonuses; + u16 move; + + if (GetBattlerSide(battlerId) == B_SIDE_PLAYER) + mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]]; + else + mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]]; + for (i = 0; i < MAX_MON_MOVES; ++i) + { + move = GetMonData(mon, MON_DATA_MOVE1 + i); + changedPP = GetMonData(mon, MON_DATA_PP1 + i); + ppBonuses = GetMonData(mon, MON_DATA_PP_BONUSES); + if (move && changedPP == 0) + break; + } + if (i != MAX_MON_MOVES) + { + u8 maxPP = CalculatePPWithBonus(move, ppBonuses, i); + if (changedPP + battlerHoldEffectParam > maxPP) + changedPP = maxPP; + else + changedPP = changedPP + battlerHoldEffectParam; + PREPARE_MOVE_BUFFER(gBattleTextBuff1, move); + BattleScriptExecute(BattleScript_BerryPPHealEnd2); + BtlController_EmitSetMonData(0, i + REQUEST_PPMOVE1_BATTLE, 0, 1, &changedPP); + MarkBattlerForControllerExec(gActiveBattler); + effect = ITEM_PP_CHANGE; + } + } + break; + case HOLD_EFFECT_RESTORE_STATS: + for (i = 0; i < NUM_BATTLE_STATS; ++i) + { + if (gBattleMons[battlerId].statStages[i] < 6) + { + gBattleMons[battlerId].statStages[i] = 6; + effect = ITEM_STATS_CHANGE; + } + } + if (effect) + { + gBattleScripting.battler = battlerId; + gPotentialItemEffectBattler = battlerId; + gActiveBattler = gBattlerAttacker = battlerId; + BattleScriptExecute(BattleScript_WhiteHerbEnd2); + } + break; + case HOLD_EFFECT_LEFTOVERS: + if (gBattleMons[battlerId].hp < gBattleMons[battlerId].maxHP && !moveTurn) + { + gBattleMoveDamage = gBattleMons[battlerId].maxHP / 16; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP) + gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp; + gBattleMoveDamage *= -1; + BattleScriptExecute(BattleScript_ItemHealHP_End2); + effect = ITEM_HP_CHANGE; + RecordItemEffectBattle(battlerId, battlerHoldEffect); + } + break; + case HOLD_EFFECT_CONFUSE_SPICY: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn) + { + PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SPICY); + gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP) + gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp; + gBattleMoveDamage *= -1; + if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_SPICY) < 0) + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); + else + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); + effect = ITEM_HP_CHANGE; + } + break; + case HOLD_EFFECT_CONFUSE_DRY: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn) + { + PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_DRY); + gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP) + gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp; + gBattleMoveDamage *= -1; + if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_DRY) < 0) + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); + else + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); + effect = ITEM_HP_CHANGE; + } + break; + case HOLD_EFFECT_CONFUSE_SWEET: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn) + { + PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SWEET); + gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP) + gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp; + gBattleMoveDamage *= -1; + if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_SWEET) < 0) + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); + else + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); + effect = ITEM_HP_CHANGE; + } + break; + case HOLD_EFFECT_CONFUSE_BITTER: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn) + { + PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_BITTER); + gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP) + gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp; + gBattleMoveDamage *= -1; + if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_BITTER) < 0) + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); + else + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); + effect = ITEM_HP_CHANGE; + } + break; + case HOLD_EFFECT_CONFUSE_SOUR: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / 2 && !moveTurn) + { + PREPARE_FLAVOR_BUFFER(gBattleTextBuff1, FLAVOR_SOUR); + gBattleMoveDamage = gBattleMons[battlerId].maxHP / battlerHoldEffectParam; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = 1; + if (gBattleMons[battlerId].hp + gBattleMoveDamage > gBattleMons[battlerId].maxHP) + gBattleMoveDamage = gBattleMons[battlerId].maxHP - gBattleMons[battlerId].hp; + gBattleMoveDamage *= -1; + if (GetFlavorRelationByPersonality(gBattleMons[battlerId].personality, FLAVOR_SOUR) < 0) + BattleScriptExecute(BattleScript_BerryConfuseHealEnd2); + else + BattleScriptExecute(BattleScript_ItemHealHP_RemoveItem); + effect = ITEM_HP_CHANGE; + } + break; + case HOLD_EFFECT_ATTACK_UP: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && gBattleMons[battlerId].statStages[STAT_ATK] < 0xC) + { + PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_ATK); + PREPARE_STRING_BUFFER(gBattleTextBuff2, STRINGID_STATROSE); + gEffectBattler = battlerId; + SET_STATCHANGER(STAT_ATK, 1, FALSE); + gBattleScripting.animArg1 = 0xE + STAT_ATK; + gBattleScripting.animArg2 = 0; + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); + effect = ITEM_STATS_CHANGE; + } + break; + case HOLD_EFFECT_DEFENSE_UP: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && gBattleMons[battlerId].statStages[STAT_DEF] < 0xC) + { + PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_DEF); + gEffectBattler = battlerId; + SET_STATCHANGER(STAT_DEF, 1, FALSE); + gBattleScripting.animArg1 = 0xE + STAT_DEF; + gBattleScripting.animArg2 = 0; + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); + effect = ITEM_STATS_CHANGE; + } + break; + case HOLD_EFFECT_SPEED_UP: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && gBattleMons[battlerId].statStages[STAT_SPEED] < 0xC) + { + PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPEED); + gEffectBattler = battlerId; + SET_STATCHANGER(STAT_SPEED, 1, FALSE); + gBattleScripting.animArg1 = 0xE + STAT_SPEED; + gBattleScripting.animArg2 = 0; + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); + effect = ITEM_STATS_CHANGE; + } + break; + case HOLD_EFFECT_SP_ATTACK_UP: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && gBattleMons[battlerId].statStages[STAT_SPATK] < 0xC) + { + PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPATK); + gEffectBattler = battlerId; + SET_STATCHANGER(STAT_SPATK, 1, FALSE); + gBattleScripting.animArg1 = 0xE + STAT_SPATK; + gBattleScripting.animArg2 = 0; + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); + effect = ITEM_STATS_CHANGE; + } + break; + case HOLD_EFFECT_SP_DEFENSE_UP: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && gBattleMons[battlerId].statStages[STAT_SPDEF] < 0xC) + { + PREPARE_STAT_BUFFER(gBattleTextBuff1, STAT_SPDEF); + gEffectBattler = battlerId; + SET_STATCHANGER(STAT_SPDEF, 1, FALSE); + gBattleScripting.animArg1 = 0xE + STAT_SPDEF; + gBattleScripting.animArg2 = 0; + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); + effect = ITEM_STATS_CHANGE; + } + break; + case HOLD_EFFECT_CRITICAL_UP: + if (gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam && !moveTurn && !(gBattleMons[battlerId].status2 & STATUS2_FOCUS_ENERGY)) + { + gBattleMons[battlerId].status2 |= STATUS2_FOCUS_ENERGY; + BattleScriptExecute(BattleScript_BerryFocusEnergyEnd2); + effect = ITEM_EFFECT_OTHER; + } + break; + case HOLD_EFFECT_RANDOM_STAT_UP: + if (!moveTurn && gBattleMons[battlerId].hp <= gBattleMons[battlerId].maxHP / battlerHoldEffectParam) + { + for (i = 0; i < 5 && gBattleMons[battlerId].statStages[STAT_ATK + i] >= 0xC; ++i); + if (i != 5) + { + do + i = Random() % 5; + while (gBattleMons[battlerId].statStages[STAT_ATK + i] == 0xC); + PREPARE_STAT_BUFFER(gBattleTextBuff1, i + 1); + gBattleTextBuff2[0] = B_BUFF_PLACEHOLDER_BEGIN; + gBattleTextBuff2[1] = B_BUFF_STRING; + gBattleTextBuff2[2] = STRINGID_STATSHARPLY; + gBattleTextBuff2[3] = STRINGID_STATSHARPLY >> 8; + gBattleTextBuff2[4] = B_BUFF_STRING; + gBattleTextBuff2[5] = STRINGID_STATROSE; + gBattleTextBuff2[6] = STRINGID_STATROSE >> 8; + gBattleTextBuff2[7] = EOS; + gEffectBattler = battlerId; + SET_STATCHANGER(i + 1, 2, FALSE); + gBattleScripting.animArg1 = 0x21 + i + 6; + gBattleScripting.animArg2 = 0; + BattleScriptExecute(BattleScript_BerryStatRaiseEnd2); + effect = ITEM_STATS_CHANGE; + } + } + break; + case HOLD_EFFECT_CURE_PAR: + if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS) + { + gBattleMons[battlerId].status1 &= ~(STATUS1_PARALYSIS); + BattleScriptExecute(BattleScript_BerryCurePrlzEnd2); + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_PSN: + if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY) + { + gBattleMons[battlerId].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); + BattleScriptExecute(BattleScript_BerryCurePsnEnd2); + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_BRN: + if (gBattleMons[battlerId].status1 & STATUS1_BURN) + { + gBattleMons[battlerId].status1 &= ~(STATUS1_BURN); + BattleScriptExecute(BattleScript_BerryCureBrnEnd2); + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_FRZ: + if (gBattleMons[battlerId].status1 & STATUS1_FREEZE) + { + gBattleMons[battlerId].status1 &= ~(STATUS1_FREEZE); + BattleScriptExecute(BattleScript_BerryCureFrzEnd2); + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_SLP: + if (gBattleMons[battlerId].status1 & STATUS1_SLEEP) + { + gBattleMons[battlerId].status1 &= ~(STATUS1_SLEEP); + gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE); + BattleScriptExecute(BattleScript_BerryCureSlpEnd2); + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_CONFUSION: + if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION) + { + gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION); + BattleScriptExecute(BattleScript_BerryCureConfusionEnd2); + effect = ITEM_EFFECT_OTHER; + } + break; + case HOLD_EFFECT_CURE_STATUS: + if (gBattleMons[battlerId].status1 & STATUS1_ANY || gBattleMons[battlerId].status2 & STATUS2_CONFUSION) + { + i = 0; + if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); + ++i; + } + if (gBattleMons[battlerId].status1 & STATUS1_SLEEP) + { + gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE); + StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); + ++i; + } + if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); + ++i; + } + if (gBattleMons[battlerId].status1 & STATUS1_BURN) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); + ++i; + } + if (gBattleMons[battlerId].status1 & STATUS1_FREEZE) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); + ++i; + } + if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); + ++i; + } + if (!(i > 1)) + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + else + gBattleCommunication[MULTISTRING_CHOOSER] = 1; + gBattleMons[battlerId].status1 = 0; + gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION); + BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2); + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_ATTRACT: + if (gBattleMons[battlerId].status2 & STATUS2_INFATUATION) + { + gBattleMons[battlerId].status2 &= ~(STATUS2_INFATUATION); + StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); + BattleScriptExecute(BattleScript_BerryCureChosenStatusEnd2); + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + effect = ITEM_EFFECT_OTHER; + } + break; + } + if (effect) + { + gBattleScripting.battler = battlerId; + gPotentialItemEffectBattler = battlerId; + gActiveBattler = gBattlerAttacker = battlerId; + switch (effect) + { + case ITEM_STATUS_CHANGE: + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[battlerId].status1); + MarkBattlerForControllerExec(gActiveBattler); + break; + case ITEM_PP_CHANGE: + if (!(gBattleMons[battlerId].status2 & STATUS2_TRANSFORMED) && !(gDisableStructs[battlerId].mimickedMoves & gBitTable[i])) + gBattleMons[battlerId].pp[i] = changedPP; + break; + } + } + } + break; + case 2: + break; + case ITEMEFFECT_MOVE_END: + for (battlerId = 0; battlerId < gBattlersCount; ++battlerId) + { + gLastUsedItem = gBattleMons[battlerId].item; + if (gBattleMons[battlerId].item == ITEM_ENIGMA_BERRY) + { + battlerHoldEffect = gEnigmaBerries[battlerId].holdEffect; + battlerHoldEffectParam = gEnigmaBerries[battlerId].holdEffectParam; + } + else + { + battlerHoldEffect = ItemId_GetHoldEffect(gLastUsedItem); + battlerHoldEffectParam = ItemId_GetHoldEffectParam(gLastUsedItem); + } + switch (battlerHoldEffect) + { + case HOLD_EFFECT_CURE_PAR: + if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS) + { + gBattleMons[battlerId].status1 &= ~(STATUS1_PARALYSIS); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BerryCureParRet; + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_PSN: + if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY) + { + gBattleMons[battlerId].status1 &= ~(STATUS1_PSN_ANY | STATUS1_TOXIC_COUNTER); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BerryCurePsnRet; + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_BRN: + if (gBattleMons[battlerId].status1 & STATUS1_BURN) + { + gBattleMons[battlerId].status1 &= ~(STATUS1_BURN); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BerryCureBrnRet; + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_FRZ: + if (gBattleMons[battlerId].status1 & STATUS1_FREEZE) + { + gBattleMons[battlerId].status1 &= ~(STATUS1_FREEZE); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BerryCureFrzRet; + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_SLP: + if (gBattleMons[battlerId].status1 & STATUS1_SLEEP) + { + gBattleMons[battlerId].status1 &= ~(STATUS1_SLEEP); + gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BerryCureSlpRet; + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_CURE_CONFUSION: + if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION) + { + gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION); + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_BerryCureConfusionRet; + effect = ITEM_EFFECT_OTHER; + } + break; + case HOLD_EFFECT_CURE_ATTRACT: + if (gBattleMons[battlerId].status2 & STATUS2_INFATUATION) + { + gBattleMons[battlerId].status2 &= ~(STATUS2_INFATUATION); + StringCopy(gBattleTextBuff1, gStatusConditionString_LoveJpn); + BattleScriptPushCursor(); + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gBattlescriptCurrInstr = BattleScript_BerryCureChosenStatusRet; + effect = ITEM_EFFECT_OTHER; + } + break; + case HOLD_EFFECT_CURE_STATUS: + if (gBattleMons[battlerId].status1 & STATUS1_ANY || gBattleMons[battlerId].status2 & STATUS2_CONFUSION) + { + if (gBattleMons[battlerId].status1 & STATUS1_PSN_ANY) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_PoisonJpn); + } + if (gBattleMons[battlerId].status1 & STATUS1_SLEEP) + { + gBattleMons[battlerId].status2 &= ~(STATUS2_NIGHTMARE); + StringCopy(gBattleTextBuff1, gStatusConditionString_SleepJpn); + } + if (gBattleMons[battlerId].status1 & STATUS1_PARALYSIS) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ParalysisJpn); + } + if (gBattleMons[battlerId].status1 & STATUS1_BURN) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_BurnJpn); + } + if (gBattleMons[battlerId].status1 & STATUS1_FREEZE) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_IceJpn); + } + if (gBattleMons[battlerId].status2 & STATUS2_CONFUSION) + { + StringCopy(gBattleTextBuff1, gStatusConditionString_ConfusionJpn); + } + gBattleMons[battlerId].status1 = 0; + gBattleMons[battlerId].status2 &= ~(STATUS2_CONFUSION); + BattleScriptPushCursor(); + gBattleCommunication[MULTISTRING_CHOOSER] = 0; + gBattlescriptCurrInstr = BattleScript_BerryCureChosenStatusRet; + effect = ITEM_STATUS_CHANGE; + } + break; + case HOLD_EFFECT_RESTORE_STATS: + for (i = 0; i < NUM_BATTLE_STATS; ++i) + { + if (gBattleMons[battlerId].statStages[i] < 6) + { + gBattleMons[battlerId].statStages[i] = 6; + effect = ITEM_STATS_CHANGE; + } + } + if (effect) + { + gBattleScripting.battler = battlerId; + gPotentialItemEffectBattler = battlerId; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_WhiteHerbRet; + return effect; + } + break; + } + if (effect) + { + gBattleScripting.battler = battlerId; + gPotentialItemEffectBattler = battlerId; + gActiveBattler = battlerId; + BtlController_EmitSetMonData(0, REQUEST_STATUS_BATTLE, 0, 4, &gBattleMons[gActiveBattler].status1); + MarkBattlerForControllerExec(gActiveBattler); + break; + } + } + break; + case ITEMEFFECT_KINGSROCK_SHELLBELL: + if (gBattleMoveDamage) + { + switch (atkHoldEffect) + { + case HOLD_EFFECT_FLINCH: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && TARGET_TURN_DAMAGED + && (Random() % 100) < battlerHoldEffectParam + && gBattleMoves[gCurrentMove].flags & FLAG_KINGSROCK_AFFECTED + && gBattleMons[gBattlerTarget].hp) + { + gBattleCommunication[MOVE_EFFECT_BYTE] = MOVE_EFFECT_FLINCH; + BattleScriptPushCursor(); + SetMoveEffect(0, 0); + BattleScriptPop(); + } + break; + case HOLD_EFFECT_SHELL_BELL: + if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) + && gSpecialStatuses[gBattlerTarget].dmg != 0 + && gSpecialStatuses[gBattlerTarget].dmg != 0xFFFF + && gBattlerAttacker != gBattlerTarget + && gBattleMons[gBattlerAttacker].hp != gBattleMons[gBattlerAttacker].maxHP + && gBattleMons[gBattlerAttacker].hp != 0) + { + gLastUsedItem = atkItem; + gPotentialItemEffectBattler = gBattlerAttacker; + gBattleScripting.battler = gBattlerAttacker; + gBattleMoveDamage = (gSpecialStatuses[gBattlerTarget].dmg / atkHoldEffectParam) * -1; + if (gBattleMoveDamage == 0) + gBattleMoveDamage = -1; + gSpecialStatuses[gBattlerTarget].dmg = 0; + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_ItemHealHP_Ret; + ++effect; + } + break; + } + } + break; + } + return effect; +} + +void ClearFuryCutterDestinyBondGrudge(u8 battlerId) +{ + gDisableStructs[battlerId].furyCutterCounter = 0; + gBattleMons[battlerId].status2 &= ~(STATUS2_DESTINY_BOND); + gStatuses3[battlerId] &= ~(STATUS3_GRUDGE); +} + +void HandleAction_RunBattleScript(void) // identical to RunBattleScriptCommands +{ + if (!gBattleControllerExecFlags) + gBattleScriptingCommandsTable[*gBattlescriptCurrInstr](); +} + +u8 GetMoveTarget(u16 move, u8 setTarget) +{ + u8 targetBattler = 0; + u8 moveTarget; + u8 side; + + if (setTarget) + moveTarget = setTarget - 1; + else + moveTarget = gBattleMoves[move].target; + switch (moveTarget) + { + case MOVE_TARGET_SELECTED: + side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; + if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp) + targetBattler = gSideTimers[side].followmeTarget; + else + { + side = GetBattlerSide(gBattlerAttacker); + do + { + targetBattler = Random() % gBattlersCount; + } while (targetBattler == gBattlerAttacker || side == GetBattlerSide(targetBattler) || gAbsentBattlerFlags & gBitTable[targetBattler]); + if (gBattleMoves[move].type == TYPE_ELECTRIC + && AbilityBattleEffects(ABILITYEFFECT_COUNT_OTHER_SIDE, gBattlerAttacker, ABILITY_LIGHTNING_ROD, 0, 0) + && gBattleMons[targetBattler].ability != ABILITY_LIGHTNING_ROD) + { + targetBattler ^= BIT_FLANK; + RecordAbilityBattle(targetBattler, gBattleMons[targetBattler].ability); + gSpecialStatuses[targetBattler].lightningRodRedirected = 1; + } + } + break; + case MOVE_TARGET_DEPENDS: + case MOVE_TARGET_BOTH: + case MOVE_TARGET_FOES_AND_ALLY: + case MOVE_TARGET_OPPONENTS_FIELD: + targetBattler = GetBattlerAtPosition((GetBattlerPosition(gBattlerAttacker) & BIT_SIDE) ^ BIT_SIDE); + if (gAbsentBattlerFlags & gBitTable[targetBattler]) + targetBattler ^= BIT_FLANK; + break; + case MOVE_TARGET_RANDOM: + side = GetBattlerSide(gBattlerAttacker) ^ BIT_SIDE; + if (gSideTimers[side].followmeTimer && gBattleMons[gSideTimers[side].followmeTarget].hp) + targetBattler = gSideTimers[side].followmeTarget; + else if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE && moveTarget & MOVE_TARGET_RANDOM) + { + if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER) + { + if (Random() & 1) + targetBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_LEFT); + else + targetBattler = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT); + } + else + { + if (Random() & 1) + targetBattler = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT); + else + targetBattler = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT); + } + if (gAbsentBattlerFlags & gBitTable[targetBattler]) + targetBattler ^= BIT_FLANK; + } + else + targetBattler = GetBattlerAtPosition((GetBattlerPosition(gBattlerAttacker) & BIT_SIDE) ^ BIT_SIDE); + break; + case MOVE_TARGET_USER_OR_SELECTED: + case MOVE_TARGET_USER: + targetBattler = gBattlerAttacker; + break; + } + *(gBattleStruct->moveTarget + gBattlerAttacker) = targetBattler; + return targetBattler; +} + +static bool32 HasObedientBitSet(u8 battlerId) +{ + if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT + || (GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES, NULL) != SPECIES_DEOXYS + && GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_SPECIES, NULL) != SPECIES_MEW)) + return TRUE; + return GetMonData(&gPlayerParty[gBattlerPartyIndexes[battlerId]], MON_DATA_OBEDIENCE, NULL); +} + +u8 IsMonDisobedient(void) +{ + s32 rnd; + s32 calc; + u8 obedienceLevel = 0; + + if ((gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_POKEDUDE)) || GetBattlerSide(gBattlerAttacker) == B_SIDE_OPPONENT) + return 0; + if (HasObedientBitSet(gBattlerAttacker)) // only if species is Mew or Deoxys + { + if (!IsOtherTrainer(gBattleMons[gBattlerAttacker].otId, gBattleMons[gBattlerAttacker].otName) || FlagGet(FLAG_0x827)) + return 0; + obedienceLevel = 10; + if (FlagGet(FLAG_0x821)) + obedienceLevel = 30; + if (FlagGet(FLAG_0x823)) + obedienceLevel = 50; + if (FlagGet(FLAG_0x825)) + obedienceLevel = 70; + } + if (gBattleMons[gBattlerAttacker].level <= obedienceLevel) + return 0; + rnd = (Random() & 255); + calc = (gBattleMons[gBattlerAttacker].level + obedienceLevel) * rnd >> 8; + if (calc < obedienceLevel) + return 0; + // is not obedient + if (gCurrentMove == MOVE_RAGE) + gBattleMons[gBattlerAttacker].status2 &= ~(STATUS2_RAGE); + if (gBattleMons[gBattlerAttacker].status1 & STATUS1_SLEEP && (gCurrentMove == MOVE_SNORE || gCurrentMove == MOVE_SLEEP_TALK)) + { + gBattlescriptCurrInstr = BattleScript_IgnoresWhileAsleep; + return 1; + } + rnd = (Random() & 255); + calc = (gBattleMons[gBattlerAttacker].level + obedienceLevel) * rnd >> 8; + if (calc < obedienceLevel && gCurrentMove != MOVE_FOCUS_PUNCH) // Additional check for focus punch in FR + { + calc = CheckMoveLimitations(gBattlerAttacker, gBitTable[gCurrMovePos], 0xFF); + if (calc == 0xF) // all moves cannot be used + { + gBattleCommunication[MULTISTRING_CHOOSER] = Random() & 3; + gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround; + return 1; + } + else // use a random move + { + do + gCurrMovePos = gChosenMovePos = Random() & 3; + while (gBitTable[gCurrMovePos] & calc); + gCalledMove = gBattleMons[gBattlerAttacker].moves[gCurrMovePos]; + gBattlescriptCurrInstr = BattleScript_IgnoresAndUsesRandomMove; + gBattlerTarget = GetMoveTarget(gCalledMove, 0); + gHitMarker |= HITMARKER_x200000; + return 2; + } + } + else + { + obedienceLevel = gBattleMons[gBattlerAttacker].level - obedienceLevel; + calc = (Random() & 255); + if (calc < obedienceLevel && !(gBattleMons[gBattlerAttacker].status1 & STATUS1_ANY) && gBattleMons[gBattlerAttacker].ability != ABILITY_VITAL_SPIRIT && gBattleMons[gBattlerAttacker].ability != ABILITY_INSOMNIA) + { + // try putting asleep + int i; + + for (i = 0; i < gBattlersCount; ++i) + if (gBattleMons[i].status2 & STATUS2_UPROAR) + break; + if (i == gBattlersCount) + { + gBattlescriptCurrInstr = BattleScript_IgnoresAndFallsAsleep; + return 1; + } + } + calc -= obedienceLevel; + if (calc < obedienceLevel) + { + gBattleMoveDamage = CalculateBaseDamage(&gBattleMons[gBattlerAttacker], &gBattleMons[gBattlerAttacker], MOVE_POUND, 0, 40, 0, gBattlerAttacker, gBattlerAttacker); + gBattlerTarget = gBattlerAttacker; + gBattlescriptCurrInstr = BattleScript_IgnoresAndHitsItself; + gHitMarker |= HITMARKER_UNABLE_TO_USE_MOVE; + return 2; + } + else + { + gBattleCommunication[MULTISTRING_CHOOSER] = Random() & 3; + gBattlescriptCurrInstr = BattleScript_MoveUsedLoafingAround; + return 1; + } + } +} |