mirror of
https://github.com/Ninjdai1/pokeemerald.git
synced 2024-12-27 04:04:17 +01:00
handle double and multi battles
This commit is contained in:
parent
fd8951d040
commit
ce19e33cc4
@ -431,19 +431,20 @@ struct ZMoveData
|
||||
{
|
||||
/*0x00*/ u8 viable:1; // current move can become a z move
|
||||
u8 viewing:1; //if player is viewing the z move name instead of regular moves
|
||||
u8 split:2;
|
||||
u8 active:1; //is z move being used this turn
|
||||
u8 zStatusActive:1;
|
||||
u8 healReplacement:1; //TODO: z-parting shot
|
||||
u8 activeSplit:1; //active z move split
|
||||
u8 zUnused:2;
|
||||
/*0x02*/ u16 currZMove; //z move of move cursor is on
|
||||
/*0x06*/ u8 triggerSpriteId;
|
||||
/*0x01*/ u8 triggerSpriteId;
|
||||
/*0x02*/ u8 possibleZMoves[MAX_BATTLERS_COUNT];
|
||||
/*0x02*/ u16 chosenZMove; //z move of move cursor is on
|
||||
u8 effect;
|
||||
u8 used[MAX_BATTLERS_COUNT]; //one per bank for multi-battles
|
||||
u16 toBeUsed[MAX_BATTLERS_COUNT]; //TODO z moves per battler to be used
|
||||
u16 baseMoves[MAX_BATTLERS_COUNT];
|
||||
u8 splits[MAX_BATTLERS_COUNT];
|
||||
}; /* size = 8 */
|
||||
};
|
||||
|
||||
struct BattleStruct
|
||||
{
|
||||
|
@ -7,7 +7,7 @@
|
||||
#define AI_CHOICE_WATCH 5
|
||||
#define AI_CHOICE_SWITCH 7
|
||||
|
||||
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef);
|
||||
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, bool32 considerZPower);
|
||||
s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon *mon);
|
||||
u16 AI_GetTypeEffectiveness(u16 move, u8 battlerAtk, u8 battlerDef);
|
||||
void BattleAI_SetupItems(void);
|
||||
|
@ -113,6 +113,7 @@ struct ChooseMoveStruct
|
||||
u8 monType2;
|
||||
u8 monType3;
|
||||
struct MegaEvolutionData mega;
|
||||
struct ZMoveData zmove;
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -15,7 +15,7 @@ struct SignatureZMove
|
||||
|
||||
void QueueZMove(u8 battlerId, u16 baseMove);
|
||||
bool32 IsViableZMove(u8 battlerId, u16 move);
|
||||
bool32 TryChangeZIndicator(u8 battlerId, u16 move);
|
||||
bool32 TryChangeZIndicator(u8 battlerId, u8 moveIndex);
|
||||
void CreateZMoveTriggerSprite(u8, bool8);
|
||||
void HideZMoveTriggerSprite(void);
|
||||
bool32 IsZMoveTriggerSpriteActive(void);
|
||||
@ -23,6 +23,8 @@ void DestroyZMoveTriggerSprite(void);
|
||||
bool32 MoveSelectionDisplayZMove(u16 zmove);
|
||||
const u8* GetZMoveName(u16 move);
|
||||
void SetZEffect(void);
|
||||
bool32 ShouldAIUseZMove(u8 activeId, u8 targetId, u16 *baseMove, u8 *chosenMoveId);
|
||||
bool32 ShouldAIUseZMove(u8 activeId, u8 targetId, u16 chosenMove);
|
||||
bool32 IsZMoveUsable(u8 battlerId, u16 moveIndex);
|
||||
void GetUsableZMoves(u8 battlerId, u16 *moves);
|
||||
|
||||
#endif // GUARD_BATTLE_Z_MOVE_H
|
@ -145,9 +145,6 @@
|
||||
#define B_INCINERATE_GEMS GEN_6 // In Gen6+, Incinerate can destroy Gems.
|
||||
#define B_MINIMIZE_DMG_ACC GEN_6 // In Gen6+, moves that causes double damage to minimized Pokémon will also skip accuracy checks.
|
||||
|
||||
// AI Settings
|
||||
#define B_AI_PREFER_STATUS_Z_MOVES FALSE // If TRUE, the AI will prefer z-status moves over damaging z moves
|
||||
|
||||
// Ability settings
|
||||
#define B_ABILITY_WEATHER GEN_6 // In Gen5+, weather caused by abilities lasts the same amount of turns as induced from a move. Before, they lasted till the battle's end or weather change by a move.
|
||||
#define B_GALE_WINGS GEN_6 // In Gen7+ requires full HP to trigger.
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "battle_ai_script_commands.h"
|
||||
#include "battle_factory.h"
|
||||
#include "battle_setup.h"
|
||||
#include "battle_z_move.h"
|
||||
#include "data.h"
|
||||
#include "item.h"
|
||||
#include "pokemon.h"
|
||||
@ -422,9 +423,10 @@ void BattleAI_SetupAIData(u8 defaultScoreMoves)
|
||||
{
|
||||
dmg = 0;
|
||||
move = gBattleMons[sBattler_AI].moves[i];
|
||||
|
||||
if (gBattleMoves[move].power != 0 && !(moveLimitations & gBitTable[i]))
|
||||
{
|
||||
dmg = AI_CalcDamage(move, sBattler_AI, gBattlerTarget) * (100 - (Random() % 10)) / 100;
|
||||
dmg = AI_CalcDamage(move, sBattler_AI, gBattlerTarget, TRUE) * (100 - (Random() % 10)) / 100;
|
||||
if (dmg == 0)
|
||||
dmg = 1;
|
||||
}
|
||||
@ -904,10 +906,16 @@ static bool32 AI_GetIfCrit(u32 move, u8 battlerAtk, u8 battlerDef)
|
||||
return isCrit;
|
||||
}
|
||||
|
||||
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef)
|
||||
s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef, bool32 considerZPower)
|
||||
{
|
||||
s32 dmg, moveType;
|
||||
|
||||
|
||||
if (considerZPower && IsViableZMove(battlerAtk, move))
|
||||
{
|
||||
gBattleStruct->zmove.baseMoves[battlerAtk] = move;
|
||||
gBattleStruct->zmove.active = TRUE; //temporarily enable z moves for damage calcs
|
||||
}
|
||||
|
||||
SaveBattlerData(battlerAtk);
|
||||
SaveBattlerData(battlerDef);
|
||||
|
||||
@ -922,6 +930,8 @@ s32 AI_CalcDamage(u16 move, u8 battlerAtk, u8 battlerDef)
|
||||
RestoreBattlerData(battlerAtk);
|
||||
RestoreBattlerData(battlerDef);
|
||||
|
||||
gBattleStruct->zmove.active = FALSE;
|
||||
gBattleStruct->zmove.baseMoves[battlerAtk] = MOVE_NONE;
|
||||
return dmg;
|
||||
}
|
||||
|
||||
@ -935,7 +945,7 @@ s32 AI_CalcPartyMonDamage(u16 move, u8 battlerAtk, u8 battlerDef, struct Pokemon
|
||||
battleMons[i] = gBattleMons[i];
|
||||
|
||||
PokemonToBattleMon(mon, &gBattleMons[battlerAtk]);
|
||||
dmg = AI_CalcDamage(move, battlerAtk, battlerDef);
|
||||
dmg = AI_CalcDamage(move, battlerAtk, battlerDef, TRUE);
|
||||
|
||||
for (i = 0; i < MAX_BATTLERS_COUNT; i++)
|
||||
gBattleMons[i] = battleMons[i];
|
||||
@ -2674,7 +2684,7 @@ static void Cmd_if_ai_can_go_down(void)
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && moves[i] != 0xFFFF && !(unusable & gBitTable[i])
|
||||
&& AI_CalcDamage(moves[i], gBattlerTarget, sBattler_AI) >= gBattleMons[sBattler_AI].hp)
|
||||
&& AI_CalcDamage(moves[i], gBattlerTarget, sBattler_AI, TRUE) >= gBattleMons[sBattler_AI].hp)
|
||||
{
|
||||
gAIScriptPtr = T1_READ_PTR(gAIScriptPtr + 1);
|
||||
return;
|
||||
|
@ -1576,26 +1576,18 @@ static void OpponentHandleChooseMove(void)
|
||||
default:
|
||||
{
|
||||
u16 chosenMove = moveInfo->moves[chosenMoveId];
|
||||
|
||||
if (ShouldAIUseZMove(gActiveBattler, gBattlerTarget, moveInfo->moves, &chosenMoveId))
|
||||
|
||||
if (gBattleMoves[chosenMove].target & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER))
|
||||
gBattlerTarget = gActiveBattler;
|
||||
if (gBattleMoves[chosenMove].target & MOVE_TARGET_BOTH)
|
||||
{
|
||||
QueueZMove(gActiveBattler, moveInfo->moves[chosenMoveId]);
|
||||
chosenMove = moveInfo->moves[chosenMoveId];
|
||||
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
||||
if (gAbsentBattlerFlags & gBitTable[gBattlerTarget])
|
||||
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gBattleMoves[chosenMove].target & (MOVE_TARGET_USER_OR_SELECTED | MOVE_TARGET_USER))
|
||||
gBattlerTarget = gActiveBattler;
|
||||
if (gBattleMoves[chosenMove].target & MOVE_TARGET_BOTH)
|
||||
{
|
||||
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_LEFT);
|
||||
if (gAbsentBattlerFlags & gBitTable[gBattlerTarget])
|
||||
gBattlerTarget = GetBattlerAtPosition(B_POSITION_PLAYER_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
if (ShouldAIUseZMove(gActiveBattler, gBattlerTarget, chosenMove))
|
||||
QueueZMove(gActiveBattler, moveInfo->moves[chosenMoveId]);
|
||||
|
||||
if (CanMegaEvolve(gActiveBattler)) // If opponent can mega evolve, do it.
|
||||
BtlController_EmitTwoReturnValues(1, 10, (chosenMoveId) | (RET_MEGA_EVOLUTION) | (gBattlerTarget << 8));
|
||||
|
@ -653,9 +653,9 @@ static void HandleInputChooseMove(void)
|
||||
PlayerBufferExecCompleted();
|
||||
}
|
||||
}
|
||||
else if (JOY_NEW(DPAD_LEFT))
|
||||
else if (JOY_NEW(DPAD_LEFT) && !gBattleStruct->zmove.viewing)
|
||||
{
|
||||
if (!gBattleStruct->zmove.viewing && gMoveSelectionCursor[gActiveBattler] & 1)
|
||||
if (gMoveSelectionCursor[gActiveBattler] & 1)
|
||||
{
|
||||
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
||||
gMoveSelectionCursor[gActiveBattler] ^= 1;
|
||||
@ -663,12 +663,12 @@ static void HandleInputChooseMove(void)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
||||
MoveSelectionDisplayPpNumber();
|
||||
MoveSelectionDisplayMoveType();
|
||||
TryChangeZIndicator(gActiveBattler, moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]);
|
||||
TryChangeZIndicator(gActiveBattler, gMoveSelectionCursor[gActiveBattler]);
|
||||
}
|
||||
}
|
||||
else if (JOY_NEW(DPAD_RIGHT))
|
||||
else if (JOY_NEW(DPAD_RIGHT) && !gBattleStruct->zmove.viewing)
|
||||
{
|
||||
if (!gBattleStruct->zmove.viewing && !(gMoveSelectionCursor[gActiveBattler] & 1)
|
||||
if (!(gMoveSelectionCursor[gActiveBattler] & 1)
|
||||
&& (gMoveSelectionCursor[gActiveBattler] ^ 1) < gNumberOfMovesToChoose)
|
||||
{
|
||||
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
||||
@ -677,12 +677,12 @@ static void HandleInputChooseMove(void)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
||||
MoveSelectionDisplayPpNumber();
|
||||
MoveSelectionDisplayMoveType();
|
||||
TryChangeZIndicator(gActiveBattler, moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]);
|
||||
TryChangeZIndicator(gActiveBattler, gMoveSelectionCursor[gActiveBattler]);
|
||||
}
|
||||
}
|
||||
else if (JOY_NEW(DPAD_UP))
|
||||
else if (JOY_NEW(DPAD_UP) && !gBattleStruct->zmove.viewing)
|
||||
{
|
||||
if (!gBattleStruct->zmove.viewing && gMoveSelectionCursor[gActiveBattler] & 2)
|
||||
if (gMoveSelectionCursor[gActiveBattler] & 2)
|
||||
{
|
||||
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
||||
gMoveSelectionCursor[gActiveBattler] ^= 2;
|
||||
@ -690,12 +690,12 @@ static void HandleInputChooseMove(void)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
||||
MoveSelectionDisplayPpNumber();
|
||||
MoveSelectionDisplayMoveType();
|
||||
TryChangeZIndicator(gActiveBattler, moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]);
|
||||
TryChangeZIndicator(gActiveBattler, gMoveSelectionCursor[gActiveBattler]);
|
||||
}
|
||||
}
|
||||
else if (JOY_NEW(DPAD_DOWN))
|
||||
else if (JOY_NEW(DPAD_DOWN) && !gBattleStruct->zmove.viewing)
|
||||
{
|
||||
if (!gBattleStruct->zmove.viewing && !(gMoveSelectionCursor[gActiveBattler] & 2)
|
||||
if (!(gMoveSelectionCursor[gActiveBattler] & 2)
|
||||
&& (gMoveSelectionCursor[gActiveBattler] ^ 2) < gNumberOfMovesToChoose)
|
||||
{
|
||||
MoveSelectionDestroyCursorAt(gMoveSelectionCursor[gActiveBattler]);
|
||||
@ -704,7 +704,7 @@ static void HandleInputChooseMove(void)
|
||||
MoveSelectionCreateCursorAt(gMoveSelectionCursor[gActiveBattler], 0);
|
||||
MoveSelectionDisplayPpNumber();
|
||||
MoveSelectionDisplayMoveType();
|
||||
TryChangeZIndicator(gActiveBattler, moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]);
|
||||
TryChangeZIndicator(gActiveBattler, gMoveSelectionCursor[gActiveBattler]);
|
||||
}
|
||||
}
|
||||
else if (JOY_NEW(SELECT_BUTTON) && !gBattleStruct->zmove.viewing)
|
||||
@ -723,7 +723,7 @@ static void HandleInputChooseMove(void)
|
||||
gBattlerControllerFuncs[gActiveBattler] = HandleMoveSwitching;
|
||||
}
|
||||
}
|
||||
else if (gMain.newKeys & START_BUTTON)
|
||||
else if (JOY_NEW(START_BUTTON))
|
||||
{
|
||||
if (CanMegaEvolve(gActiveBattler))
|
||||
{
|
||||
@ -731,13 +731,13 @@ static void HandleInputChooseMove(void)
|
||||
ChangeMegaTriggerSprite(gBattleStruct->mega.triggerSpriteId, gBattleStruct->mega.playerSelect);
|
||||
PlaySE(SE_SELECT);
|
||||
}
|
||||
else if (gBattleStruct->zmove.currZMove != MOVE_NONE)
|
||||
else if (gBattleStruct->zmove.viable)
|
||||
{
|
||||
// show z move name / info
|
||||
//TODO: brighten z move symbol
|
||||
PlaySE(SE_SELECT);
|
||||
if (!gBattleStruct->zmove.viewing)
|
||||
MoveSelectionDisplayZMove(gBattleStruct->zmove.currZMove);
|
||||
MoveSelectionDisplayZMove(gBattleStruct->zmove.chosenZMove);
|
||||
else
|
||||
ReloadMoveNames();
|
||||
}
|
||||
@ -2766,7 +2766,9 @@ static void PlayerHandleChooseMove(void)
|
||||
CreateMegaTriggerSprite(gActiveBattler, 0);
|
||||
if (!IsZMoveTriggerSpriteActive())
|
||||
gBattleStruct->zmove.triggerSpriteId = 0xFF;
|
||||
gBattleStruct->zmove.viable = IsViableZMove(gActiveBattler, moveInfo->moves[gMoveSelectionCursor[gActiveBattler]]); //is current move a z move
|
||||
|
||||
GetUsableZMoves(gActiveBattler, moveInfo->moves);
|
||||
gBattleStruct->zmove.viable = IsZMoveUsable(gActiveBattler, gMoveSelectionCursor[gActiveBattler]);
|
||||
CreateZMoveTriggerSprite(gActiveBattler, gBattleStruct->zmove.viable);
|
||||
gBattlerControllerFuncs[gActiveBattler] = HandleChooseMoveAfterDma3;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "battle_interface.h"
|
||||
#include "battle_setup.h"
|
||||
#include "battle_tower.h"
|
||||
#include "battle_z_move.h"
|
||||
#include "bg.h"
|
||||
#include "data.h"
|
||||
#include "item_use.h"
|
||||
@ -1516,7 +1517,7 @@ static void PlayerPartnerHandleChooseMove(void)
|
||||
|
||||
BattleAI_SetupAIData(0xF);
|
||||
chosenMoveId = BattleAI_ChooseMoveOrAction();
|
||||
|
||||
|
||||
if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & (MOVE_TARGET_USER | MOVE_TARGET_USER_OR_SELECTED))
|
||||
gBattlerTarget = gActiveBattler;
|
||||
if (gBattleMoves[moveInfo->moves[chosenMoveId]].target & MOVE_TARGET_BOTH)
|
||||
@ -1525,6 +1526,9 @@ static void PlayerPartnerHandleChooseMove(void)
|
||||
if (gAbsentBattlerFlags & gBitTable[gBattlerTarget])
|
||||
gBattlerTarget = GetBattlerAtPosition(B_POSITION_OPPONENT_RIGHT);
|
||||
}
|
||||
|
||||
if (ShouldAIUseZMove(gActiveBattler, gBattlerTarget, moveInfo->moves[chosenMoveId]))
|
||||
QueueZMove(gActiveBattler, moveInfo->moves[chosenMoveId]);
|
||||
|
||||
BtlController_EmitTwoReturnValues(1, 10, chosenMoveId | (gBattlerTarget << 8));
|
||||
PlayerPartnerBufferExecCompleted();
|
||||
|
@ -3801,6 +3801,7 @@ static void HandleTurnActionSelectionState(void)
|
||||
{
|
||||
struct ChooseMoveStruct moveInfo;
|
||||
|
||||
moveInfo.zmove = gBattleStruct->zmove;
|
||||
moveInfo.mega = gBattleStruct->mega;
|
||||
moveInfo.species = gBattleMons[gActiveBattler].species;
|
||||
moveInfo.monType1 = gBattleMons[gActiveBattler].type1;
|
||||
@ -3913,6 +3914,7 @@ static void HandleTurnActionSelectionState(void)
|
||||
}
|
||||
|
||||
gBattleStruct->mega.toEvolve &= ~(gBitTable[BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))]);
|
||||
gBattleStruct->zmove.toBeUsed[BATTLE_PARTNER(GetBattlerPosition(gActiveBattler))] = MOVE_NONE;
|
||||
BtlController_EmitEndBounceEffect(0);
|
||||
MarkBattlerForControllerExec(gActiveBattler);
|
||||
return;
|
||||
|
@ -1400,7 +1400,7 @@ u8 TrySetCantSelectMoveBattleScript(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (gDisableStructs[gActiveBattler].tauntTimer != 0 && gBattleMoves[move].power == 0)
|
||||
if (!gBattleStruct->zmove.active && gDisableStructs[gActiveBattler].tauntTimer != 0 && gBattleMoves[move].power == 0)
|
||||
{
|
||||
gCurrentMove = move;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
||||
@ -1415,7 +1415,7 @@ u8 TrySetCantSelectMoveBattleScript(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (gDisableStructs[gActiveBattler].throatChopTimer != 0 && gBattleMoves[move].flags & FLAG_SOUND)
|
||||
if (!gBattleStruct->zmove.active && gDisableStructs[gActiveBattler].throatChopTimer != 0 && gBattleMoves[move].flags & FLAG_SOUND)
|
||||
{
|
||||
gCurrentMove = move;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
||||
@ -1430,7 +1430,7 @@ u8 TrySetCantSelectMoveBattleScript(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (GetImprisonedMovesCount(gActiveBattler, move))
|
||||
if (!gBattleStruct->zmove.active && GetImprisonedMovesCount(gActiveBattler, move))
|
||||
{
|
||||
gCurrentMove = move;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
||||
@ -1445,7 +1445,7 @@ u8 TrySetCantSelectMoveBattleScript(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (IsGravityPreventingMove(move))
|
||||
if (!gBattleStruct->zmove.active && IsGravityPreventingMove(move))
|
||||
{
|
||||
gCurrentMove = move;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
||||
@ -1460,7 +1460,7 @@ u8 TrySetCantSelectMoveBattleScript(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (IsHealBlockPreventingMove(gActiveBattler, move))
|
||||
if (!gBattleStruct->zmove.active && IsHealBlockPreventingMove(gActiveBattler, move))
|
||||
{
|
||||
gCurrentMove = move;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
||||
@ -1475,7 +1475,7 @@ u8 TrySetCantSelectMoveBattleScript(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (IsBelchPreventingMove(gActiveBattler, move))
|
||||
if (!gBattleStruct->zmove.active && IsBelchPreventingMove(gActiveBattler, move))
|
||||
{
|
||||
gCurrentMove = move;
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_PALACE)
|
||||
@ -1543,7 +1543,7 @@ u8 CheckMoveLimitations(u8 battlerId, u8 unusableMoves, u8 check)
|
||||
s32 i;
|
||||
|
||||
gPotentialItemEffectBattler = battlerId;
|
||||
|
||||
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (gBattleMons[battlerId].moves[i] == 0 && check & MOVE_LIMITATION_ZEROMOVE)
|
||||
@ -3191,9 +3191,12 @@ u8 AtkCanceller_UnableToUseMove(void)
|
||||
{
|
||||
//attacker has a queued z move
|
||||
gBattleStruct->zmove.active = TRUE;
|
||||
gBattleStruct->zmove.activeSplit = gBattleStruct->zmove.splits[gBattlerAttacker];
|
||||
RecordItemEffectBattle(gBattlerAttacker, HOLD_EFFECT_Z_CRYSTAL);
|
||||
gBattleStruct->zmove.used[gBattlerAttacker] = TRUE;
|
||||
//TODO - partner battles
|
||||
gBattleStruct->zmove.used[gBattlerAttacker] = TRUE;
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && IsPartnerMonFromSameTrainer(gBattlerAttacker))
|
||||
gBattleStruct->zmove.used[BATTLE_PARTNER(gBattlerAttacker)] = TRUE; //if 1v1 double, set partner used flag as well
|
||||
|
||||
gBattleScripting.battler = gBattlerAttacker;
|
||||
if (IS_MOVE_STATUS(gBattleStruct->zmove.splits[gBattlerAttacker]))
|
||||
{
|
||||
@ -7811,9 +7814,8 @@ bool8 ShouldGetStatBadgeBoost(u16 badgeFlag, u8 battlerId)
|
||||
|
||||
u8 GetBattleMoveSplit(u32 moveId)
|
||||
{
|
||||
//TODO - light that burns the sky, photon geyser
|
||||
if (gBattleStruct->zmove.active && !IS_MOVE_STATUS(moveId))
|
||||
return gBattleStruct->zmove.split;
|
||||
return gBattleStruct->zmove.activeSplit;
|
||||
else if (IS_MOVE_STATUS(moveId) || B_PHYSICAL_SPECIAL_SPLIT >= GEN_4)
|
||||
return gBattleMoves[moveId].split;
|
||||
else if (gBattleMoves[moveId].type < TYPE_MYSTERY)
|
||||
|
@ -140,9 +140,10 @@ bool8 IsZMove(u16 move)
|
||||
|
||||
void QueueZMove(u8 battlerId, u16 baseMove)
|
||||
{
|
||||
gBattleStruct->zmove.toBeUsed[battlerId] = gBattleStruct->zmove.currZMove;
|
||||
gBattleStruct->zmove.toBeUsed[battlerId] = gBattleStruct->zmove.chosenZMove;
|
||||
gBattleStruct->zmove.baseMoves[battlerId] = baseMove;
|
||||
gBattleStruct->zmove.splits[battlerId] = GetBattleMoveSplit(baseMove);
|
||||
//TODO - light that burns the sky
|
||||
gBattleStruct->zmove.splits[battlerId] = gBattleMoves[baseMove].split;
|
||||
}
|
||||
|
||||
bool32 IsViableZMove(u8 battlerId, u16 move)
|
||||
@ -155,19 +156,19 @@ bool32 IsViableZMove(u8 battlerId, u16 move)
|
||||
u16 holdEffect;
|
||||
u16 species;
|
||||
|
||||
gBattleStruct->zmove.currZMove = MOVE_NONE; //init
|
||||
|
||||
if (gBattleStruct->zmove.used[battlerId])
|
||||
return FALSE;
|
||||
|
||||
// Gets mon data.
|
||||
if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
|
||||
// Gets mon data
|
||||
species = gBattleMons[battlerId].species;
|
||||
item = gBattleMons[battlerId].item;
|
||||
/*if (GetBattlerSide(battlerId) == B_SIDE_OPPONENT)
|
||||
mon = &gEnemyParty[gBattlerPartyIndexes[battlerId]];
|
||||
else
|
||||
mon = &gPlayerParty[gBattlerPartyIndexes[battlerId]];
|
||||
|
||||
species = GetMonData(mon, MON_DATA_SPECIES);
|
||||
item = GetMonData(mon, MON_DATA_HELD_ITEM);
|
||||
item = GetMonData(mon, MON_DATA_HELD_ITEM);*/
|
||||
|
||||
if (gBattleTypeFlags & (BATTLE_TYPE_SAFARI | BATTLE_TYPE_WALLY_TUTORIAL | BATTLE_TYPE_FRONTIER))
|
||||
return FALSE;
|
||||
@ -202,16 +203,16 @@ bool32 IsViableZMove(u8 battlerId, u16 move)
|
||||
u16 zMove = GetSignatureZMove(move, gBattleMons[battlerId].species, item);
|
||||
if (zMove != MOVE_NONE)
|
||||
{
|
||||
gBattleStruct->zmove.currZMove = zMove; //signature z move exists
|
||||
gBattleStruct->zmove.chosenZMove = zMove; //signature z move exists
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (move != MOVE_NONE && zMove != MOVE_Z_STATUS && gBattleMoves[move].type == ItemId_GetSecondaryId(item))
|
||||
{
|
||||
if (IS_MOVE_STATUS(gBattleMoves[move].split))
|
||||
gBattleStruct->zmove.currZMove = MOVE_Z_STATUS;
|
||||
gBattleStruct->zmove.chosenZMove = move;
|
||||
else
|
||||
gBattleStruct->zmove.currZMove = GetTypeBasedZMove(move, battlerId);
|
||||
gBattleStruct->zmove.chosenZMove = GetTypeBasedZMove(move, battlerId);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -220,9 +221,30 @@ bool32 IsViableZMove(u8 battlerId, u16 move)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 TryChangeZIndicator(u8 battlerId, u16 move)
|
||||
void GetUsableZMoves(u8 battlerId, u16 *moves)
|
||||
{
|
||||
bool32 viableZMove = IsViableZMove(battlerId, move);
|
||||
u32 i;
|
||||
gBattleStruct->zmove.possibleZMoves[battlerId] = 0;
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (moves[i] != MOVE_NONE && IsViableZMove(battlerId, moves[i]))
|
||||
gBattleStruct->zmove.possibleZMoves[battlerId] |= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
bool32 IsZMoveUsable(u8 battlerId, u16 moveIndex)
|
||||
{
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && IsPartnerMonFromSameTrainer(battlerId) && gBattleStruct->zmove.toBeUsed[BATTLE_PARTNER(battlerId)] != MOVE_NONE)
|
||||
return FALSE; //player's other mon has a z move queued up already
|
||||
if (gBattleStruct->zmove.possibleZMoves[battlerId] & (1 << moveIndex))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bool32 TryChangeZIndicator(u8 battlerId, u8 moveIndex)
|
||||
{
|
||||
//bool32 viableZMove = IsViableZMove(battlerId, move);
|
||||
bool32 viableZMove = IsZMoveUsable(battlerId, moveIndex);
|
||||
|
||||
if (gBattleStruct->zmove.viable && !viableZMove)
|
||||
HideZMoveTriggerSprite(); //was a viable z move, now is not -> slide out
|
||||
@ -268,7 +290,6 @@ void CreateZMoveTriggerSprite(u8 battlerId, bool8 viable)
|
||||
|
||||
gSprites[gBattleStruct->zmove.triggerSpriteId].tBattler = battlerId;
|
||||
gSprites[gBattleStruct->zmove.triggerSpriteId].tHide = (viable == TRUE) ? FALSE : TRUE;
|
||||
ChangeMegaTriggerSprite(gBattleStruct->zmove.triggerSpriteId, 0);
|
||||
}
|
||||
|
||||
static void SpriteCB_ZMoveTrigger(struct Sprite *sprite)
|
||||
@ -351,6 +372,7 @@ void DestroyZMoveTriggerSprite(void)
|
||||
FreeSpriteTilesByTag(TAG_ZMOVE_TRIGGER_TILE);
|
||||
if (gBattleStruct->zmove.triggerSpriteId != 0xFF)
|
||||
DestroySprite(&gSprites[gBattleStruct->zmove.triggerSpriteId]);
|
||||
|
||||
gBattleStruct->zmove.triggerSpriteId = 0xFF;
|
||||
}
|
||||
|
||||
@ -370,13 +392,9 @@ static u16 GetSignatureZMove(u16 move, u16 species, u16 item)
|
||||
|
||||
static u16 GetTypeBasedZMove(u16 move, u8 battler)
|
||||
{
|
||||
u8 moveType;
|
||||
//handle dynamic move types
|
||||
SetTypeBeforeUsingMove(battler, move);
|
||||
GET_MOVE_TYPE(move, moveType);
|
||||
u8 moveType = gBattleMoves[move].type;
|
||||
|
||||
// get z move from split
|
||||
// TODO: light that burns the sky gets split from relative stats
|
||||
// get z move from type
|
||||
if (moveType < TYPE_FIRE)
|
||||
return MOVE_BREAKNECK_BLITZ + moveType;
|
||||
else if (moveType >= TYPE_FAIRY)
|
||||
@ -683,259 +701,35 @@ static bool32 AreStatsMaxed(u8 battlerId, u8 n)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define STAT_CAN_RISE(bank, stat) ((gBattleMons[bank].statStages[stat-1] < 12 && GetBattlerAbility(bank) != ABILITY_CONTRARY) || (GetBattlerAbility(bank) == ABILITY_CONTRARY && gBattleMons[bank].statStages[stat-1] > 0))
|
||||
#define STAT_CAN_FALL(bank, stat) ((gBattleMons[bank].statStages[stat-1] > 0 && GetBattlerAbility(bank) != ABILITY_CONTRARY) || (GetBattlerAbility(bank) == ABILITY_CONTRARY && gBattleMons[bank].statStages[stat-1] < 12))
|
||||
//TODO - this could be a lot better
|
||||
bool32 ShouldAIUseZMove(u8 battlerAtk, u8 battlerDef, u16 *baseMoves, u8 *chosenMoveId)
|
||||
bool32 ShouldAIUseZMove(u8 battlerAtk, u8 battlerDef, u16 chosenMove)
|
||||
{
|
||||
u32 i;
|
||||
u16 possibleZMoves[MAX_MON_MOVES];
|
||||
u8 zMoveIndex = 0xFF;
|
||||
u16 zMove = MOVE_NONE;
|
||||
u8 scores[MAX_MON_MOVES] = {0};
|
||||
|
||||
// simple logic. just upgrades chosen move to z move if possible, unless regular move would kill opponent
|
||||
if ((gBattleTypeFlags & BATTLE_TYPE_DOUBLE) && battlerDef == BATTLE_PARTNER(battlerAtk))
|
||||
return FALSE; //don't use z move on partner
|
||||
|
||||
if (gBattleStruct->zmove.used[battlerAtk])
|
||||
return FALSE; //cant use z move twice
|
||||
|
||||
// check possible z moves and select the 'best' one
|
||||
for (i = 0; i < MAX_MON_MOVES; i++)
|
||||
{
|
||||
if (baseMoves[i] != MOVE_NONE && IsViableZMove(battlerAtk, baseMoves[i])) //updates gBattleStruct->zmove.currZMove
|
||||
{
|
||||
if (zMove != MOVE_NONE)
|
||||
{
|
||||
scores[i] = GetZMoveScore(battlerAtk, battlerDef, baseMoves[i], zMove);
|
||||
// another z move option already exists. compare them
|
||||
#if B_AI_PREFER_STATUS_Z_MOVES == TRUE
|
||||
if (scores[i] > scores[zMoveIndex] || (IS_MOVE_STATUS(gBattleStruct->zmove.currZMove) && !IS_MOVE_STATUS(zMove) && scores[i] != 0))
|
||||
{
|
||||
zMove = gBattleStruct->zmove.currZMove;
|
||||
zMoveIndex = i;
|
||||
}
|
||||
#else
|
||||
if (scores[i] > scores[zMoveIndex] || (!IS_MOVE_STATUS(gBattleStruct->zmove.currZMove) && IS_MOVE_STATUS(zMove) && scores[i] != 0))
|
||||
{
|
||||
zMove = gBattleStruct->zmove.currZMove;
|
||||
zMoveIndex = i;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
zMove = gBattleStruct->zmove.currZMove;
|
||||
zMoveIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zMoveIndex == 0xFF || scores[zMoveIndex] == 0)
|
||||
if (IsViableZMove(battlerAtk, chosenMove))
|
||||
{
|
||||
return FALSE; //no available z moves
|
||||
}
|
||||
else
|
||||
{
|
||||
*chosenMoveId = zMoveIndex;
|
||||
gBattleStruct->zmove.baseMoves[battlerAtk] = baseMoves[*chosenMoveId];
|
||||
gBattleStruct->zmove.currZMove = zMove; //z move the AI is looking at
|
||||
#ifdef POKEMON_EXPANSION
|
||||
if (defAbility == ABILITY_DISGUISE && defSpecies == SPECIES_MIMIKYU)
|
||||
return 0; //Don't waste a Z-Move busting Mimikyu's disguise
|
||||
if (defAbility == ABILITY_ICEFACE && defSpecies == SPECIES_EISCUE && IS_MOVE_PHYSICAL(chosenMove))
|
||||
return 0; //Don't waste a Z-Move busting Eiscue's Ice Face
|
||||
#endif
|
||||
|
||||
if (IS_MOVE_STATUS(chosenMove) && !IS_MOVE_STATUS(gBattleStruct->zmove.chosenZMove))
|
||||
return FALSE;
|
||||
else if (!IS_MOVE_STATUS(chosenMove) && IS_MOVE_STATUS(gBattleStruct->zmove.chosenZMove))
|
||||
return FALSE;
|
||||
|
||||
if (!IS_MOVE_STATUS(chosenMove) && AI_CalcDamage(chosenMove, battlerAtk, battlerDef, FALSE) >= gBattleMons[battlerDef].hp)
|
||||
return FALSE; //don't waste damaging z move if regular is expected to faint target
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static u8 GetZMoveScore(u8 battlerAtk, u8 battlerDef, u16 baseMove, u16 zMove)
|
||||
{
|
||||
u8 score = 0;
|
||||
u8 expectedDamage = 0;
|
||||
u32 i;
|
||||
|
||||
if (zMove != MOVE_Z_STATUS)
|
||||
{
|
||||
u8 defAbility = GetBattlerAbility(battlerDef);
|
||||
u16 defSpecies = gBattleMons[battlerDef].species;
|
||||
|
||||
/*if (baseMove == MOVE_FAKE_OUT && gDisableStructs[battlerAtk].isFirstTurn)
|
||||
return FALSE; //Prefer actual Fake Out over Breakneck Blitz*/
|
||||
|
||||
/*if (MoveBlockedBySubstitute(zMove, battlerAtk, battlerDef)
|
||||
|| (defMovePrediction == MOVE_SUBSTITUTE
|
||||
&& !MoveWouldHitFirst(zMove, battlerAtk, battlerDef)
|
||||
&& !MoveIgnoresSubstitutes(zMove, ABILITY(battlerAtk))))
|
||||
return FALSE; //Don't use a Z-Move on a Substitute or if the enemy is going to go first and use Substitute*/
|
||||
|
||||
#ifdef POKEMON_EXPANSION
|
||||
if (defAbility == ABILITY_DISGUISE && defSpecies == SPECIES_MIMIKYU)
|
||||
return 0; //Don't waste a Z-Move busting Mimikyu's disguise
|
||||
if (defAbility == ABILITY_ICEFACE && defSpecies == SPECIES_EISCUE && IS_MOVE_PHYSICAL(baseMove))
|
||||
return 0; //Don't waste a Z-Move busting Eiscue's Ice Face
|
||||
#endif
|
||||
|
||||
/*if (defMovePrediction == MOVE_PROTECT || defMovePrediction == MOVE_KINGSSHIELD || defMovePrediction == MOVE_SPIKYSHIELD || defMovePrediction == MOVE_OBSTRUCT
|
||||
|| (IsDynamaxed(battlerDef) && SPLIT(defMovePrediction) == SPLIT_STATUS))
|
||||
return FALSE; //Don't waste a Z-Move on a Protect*/
|
||||
|
||||
/*if (IsRaidBattle() && gNewBS->dynamaxData.raidShieldsUp && SIDE(battlerAtk) == B_SIDE_PLAYER && SIDE(battlerDef) == B_SIDE_OPPONENT) //Partner AI on Raid Pokemon with shields up
|
||||
{
|
||||
if (gNewBS->dynamaxData.shieldCount - gNewBS->dynamaxData.shieldsDestroyed <= 2 //Less than 3 shields left
|
||||
&& gNewBS->dynamaxData.stormLevel < 3) //The Raid boss hasn't almost won
|
||||
return FALSE; //Don't waste a Z-Move breaking a shield
|
||||
|
||||
u16 bankAtkPartner = BATTLE_PARTNER(battlerAtk);
|
||||
u16 partnerMove = GetAIChosenMove(bankAtkPartner, battlerDef);
|
||||
|
||||
if (SPLIT(partnerMove) == SPLIT_STATUS
|
||||
|| MoveWouldHitFirst(partnerMove, bankAtkPartner, battlerAtk)
|
||||
|| (gChosenMovesByBanks[bankAtkPartner] != MOVE_NONE && gBattleStruct->moveTarget[bankAtkPartner] != battlerDef)) //Not targeting raid Pokemon
|
||||
return FALSE; //Don't waste a Z-Move if partner can't destroy shield first
|
||||
}*/
|
||||
|
||||
//These moves should always be turned into Z-Moves, regardless if they KO or not
|
||||
switch (gBattleMoves[baseMove].effect)
|
||||
{
|
||||
case EFFECT_RECHARGE:
|
||||
case EFFECT_SEMI_INVULNERABLE:
|
||||
case EFFECT_SKULL_BASH:
|
||||
case EFFECT_SOLARBEAM:
|
||||
case EFFECT_LAST_RESORT:
|
||||
//todo: sky drop
|
||||
return 255;
|
||||
}
|
||||
if (baseMove == MOVE_SKY_ATTACK)
|
||||
return 255;
|
||||
|
||||
gBattleStruct->zmove.active = TRUE; //for damage calc only
|
||||
expectedDamage = AI_CalcDamage(baseMove, battlerAtk, battlerDef);
|
||||
gBattleStruct->zmove.active = FALSE;
|
||||
if (expectedDamage >= gBattleMons[battlerDef].hp)
|
||||
return 0; //base move knocks out already, no need for z move
|
||||
|
||||
return (expectedDamage > 255) ? 255 : expectedDamage;
|
||||
}
|
||||
else //Status Move
|
||||
{
|
||||
u8 zEffect = gBattleMoves[baseMove].zMoveEffect;
|
||||
|
||||
switch (zEffect)
|
||||
{
|
||||
case Z_EFFECT_NONE:
|
||||
return 0;
|
||||
case Z_EFFECT_RESET_STATS:
|
||||
for (i = STAT_ATK; i < NUM_BATTLE_STATS; i++)
|
||||
{
|
||||
if (i == STAT_ATK && !HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL)) //Only reset lowered Attack if useful
|
||||
continue;
|
||||
else if (i == STAT_ATK && !HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL)) //Only reset lowered Special Attack if useful
|
||||
continue;
|
||||
|
||||
if (STAT_STAGE(battlerAtk, i) < 6)
|
||||
return 50; //Want to reset any negative stats
|
||||
}
|
||||
break;
|
||||
case Z_EFFECT_ALL_STATS_UP_1:
|
||||
if (!AreStatsMaxed(battlerAtk, STAT_EVASION)) //all battle stats maxed
|
||||
return 80;
|
||||
break;
|
||||
case Z_EFFECT_BOOST_CRITS:
|
||||
if (!(gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY))
|
||||
return 30; //kinda meh?
|
||||
break;
|
||||
case Z_EFFECT_FOLLOW_ME:
|
||||
if (gBattleTypeFlags & BATTLE_TYPE_DOUBLE)
|
||||
return 30; //kinda meh?
|
||||
break;
|
||||
case Z_EFFECT_ATK_UP_1:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_ATK) && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL))
|
||||
return 60;
|
||||
break;
|
||||
case Z_EFFECT_ATK_UP_2:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_ATK) && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL))
|
||||
return 70;
|
||||
break;
|
||||
case Z_EFFECT_ATK_UP_3:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_ATK) && HasMoveWithSplit(battlerAtk, SPLIT_PHYSICAL))
|
||||
return 80;
|
||||
break;
|
||||
case Z_EFFECT_DEF_UP_1:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_DEF))
|
||||
return 50;
|
||||
break;
|
||||
case Z_EFFECT_DEF_UP_2:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_DEF))
|
||||
return 60;
|
||||
break;
|
||||
case Z_EFFECT_DEF_UP_3:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_DEF))
|
||||
return 70;
|
||||
break;
|
||||
case Z_EFFECT_SPATK_UP_1:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_SPATK) && HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL))
|
||||
return 50;
|
||||
break;
|
||||
case Z_EFFECT_SPATK_UP_2:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_SPATK) && HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL))
|
||||
return 60;
|
||||
break;
|
||||
case Z_EFFECT_SPATK_UP_3:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_SPATK) && HasMoveWithSplit(battlerAtk, SPLIT_SPECIAL))
|
||||
return 70;
|
||||
break;
|
||||
case Z_EFFECT_SPDEF_UP_1:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_SPDEF))
|
||||
return 50;
|
||||
break;
|
||||
case Z_EFFECT_SPDEF_UP_2:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_SPDEF))
|
||||
return 60;
|
||||
break;
|
||||
case Z_EFFECT_SPDEF_UP_3:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_SPDEF))
|
||||
return 70;
|
||||
break;
|
||||
case Z_EFFECT_SPD_UP_1:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_SPEED))
|
||||
return 50;
|
||||
break;
|
||||
case Z_EFFECT_SPD_UP_2:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_SPEED))
|
||||
return 60;
|
||||
break;
|
||||
case Z_EFFECT_SPD_UP_3:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_SPEED))
|
||||
return 70;
|
||||
break;
|
||||
case Z_EFFECT_ACC_UP_1:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_ACC))
|
||||
return 20; //TODO: only if knows low-accuracy move
|
||||
break;
|
||||
case Z_EFFECT_ACC_UP_2:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_ACC))
|
||||
return 40; //TODO: only if knows low-accuracy move
|
||||
break;
|
||||
case Z_EFFECT_ACC_UP_3:
|
||||
//if (STAT_CAN_RISE(battlerAtk, STAT_ACC) && MoveInMovesetWithAccuracyLessThan(battlerAtk, battlerDef, 90, FALSE))
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_ACC))
|
||||
return 60; //TODO: only if knows low-accuracy move
|
||||
break;
|
||||
case Z_EFFECT_EVSN_UP_1:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_EVASION))
|
||||
return 40;
|
||||
break;
|
||||
case Z_EFFECT_EVSN_UP_2:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_EVASION))
|
||||
return 60;
|
||||
break;
|
||||
case Z_EFFECT_EVSN_UP_3:
|
||||
if (STAT_CAN_RISE(battlerAtk, STAT_EVASION))
|
||||
return 80;
|
||||
break;
|
||||
default: //Recover HP
|
||||
return 70;
|
||||
}
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user