Merge branch '_RHH/master' into _RHH/upcoming
This commit is contained in:
commit
64c5113b23
@ -1727,11 +1727,6 @@
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro tryhitswitchtarget failInstr:req
|
||||
callnative BS_TryHitSwitchTarget
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro setmagiccoattarget
|
||||
callnative BS_SetMagicCoatTarget
|
||||
.endm
|
||||
|
||||
@ -1806,25 +1806,17 @@ BattleScript_EffectFinalGambit::
|
||||
tryfaintmon BS_ATTACKER
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_EffectHitSwitchTarget::
|
||||
call BattleScript_EffectHit_Ret
|
||||
tryfaintmon BS_TARGET
|
||||
jumpiffainted BS_TARGET, TRUE, BattleScript_MoveEnd
|
||||
jumpifability BS_TARGET, ABILITY_SUCTION_CUPS, BattleScript_AbilityPreventsPhasingOut
|
||||
jumpifability BS_TARGET, ABILITY_GUARD_DOG, BattleScript_MoveEnd
|
||||
jumpifstatus3 BS_TARGET, STATUS3_ROOTED, BattleScript_PrintMonIsRooted
|
||||
jumpiftargetdynamaxed BattleScript_HitSwitchTargetDynamaxed
|
||||
tryhitswitchtarget BattleScript_MoveEnd
|
||||
BattleScript_TryHitSwitchTarget::
|
||||
forcerandomswitch BattleScript_HitSwitchTargetForceRandomSwitchFailed
|
||||
goto BattleScript_MoveEnd
|
||||
return
|
||||
|
||||
BattleScript_HitSwitchTargetDynamaxed:
|
||||
BattleScript_HitSwitchTargetDynamaxed::
|
||||
printstring STRINGID_MOVEBLOCKEDBYDYNAMAX
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
BattleScript_HitSwitchTargetForceRandomSwitchFailed:
|
||||
hitswitchtargetfailed
|
||||
setbyte sSWITCH_CASE, B_SWITCH_NORMAL
|
||||
goto BattleScript_MoveEnd
|
||||
return
|
||||
|
||||
BattleScript_EffectToxicThread::
|
||||
setstatchanger STAT_SPEED, 1, TRUE
|
||||
@ -6722,6 +6714,12 @@ BattleScript_PrintMonIsRooted::
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_PrintMonIsRootedRet::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
printstring STRINGID_PKMNANCHOREDITSELF
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_AtkDefDown::
|
||||
setbyte sSTAT_ANIM_PLAYED, FALSE
|
||||
playstatchangeanimation BS_ATTACKER, BIT_DEF | BIT_ATK, STAT_CHANGE_CANT_PREVENT | STAT_CHANGE_NEGATIVE | STAT_CHANGE_MULTIPLE_STATS
|
||||
@ -7766,8 +7764,12 @@ BattleScript_IntimidateEffect:
|
||||
printstring STRINGID_PKMNCUTSATTACKWITH
|
||||
BattleScript_IntimidateEffect_WaitString:
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
saveattacker
|
||||
savetarget
|
||||
copybyte sBATTLER, gBattlerTarget
|
||||
call BattleScript_TryIntimidateHoldEffects
|
||||
restoreattacker
|
||||
restoretarget
|
||||
BattleScript_IntimidateLoopIncrement:
|
||||
addbyte gBattlerTarget, 1
|
||||
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_IntimidateLoop
|
||||
@ -8202,6 +8204,13 @@ BattleScript_AbilityPreventsPhasingOut::
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
goto BattleScript_MoveEnd
|
||||
|
||||
BattleScript_AbilityPreventsPhasingOutRet::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
call BattleScript_AbilityPopUp
|
||||
printstring STRINGID_PKMNANCHORSITSELFWITH
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
return
|
||||
|
||||
BattleScript_AbilityNoStatLoss::
|
||||
pause B_WAIT_TIME_SHORT
|
||||
call BattleScript_AbilityPopUp
|
||||
|
||||
BIN
graphics/battle_interface/move_info_window_l.png
Normal file
BIN
graphics/battle_interface/move_info_window_l.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 291 B |
BIN
graphics/battle_interface/move_info_window_r.png
Normal file
BIN
graphics/battle_interface/move_info_window_r.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 295 B |
@ -782,6 +782,7 @@ struct BattleStruct
|
||||
u8 ballSwapped:1; // Used for the last used ball feature
|
||||
u8 throwingPokeBall:1;
|
||||
u8 ballSpriteIds[2]; // item gfx, window gfx
|
||||
u8 moveInfoSpriteId; // move info, window gfx
|
||||
u8 appearedInBattle; // Bitfield to track which Pokemon appeared in battle. Used for Burmy's form change
|
||||
u8 skyDropTargets[MAX_BATTLERS_COUNT]; // For Sky Drop, to account for if multiple Pokemon use Sky Drop in a double battle.
|
||||
// When using a move which hits multiple opponents which is then bounced by a target, we need to make sure, the move hits both opponents, the one with bounce, and the one without.
|
||||
|
||||
@ -128,5 +128,7 @@ void SwapBallToDisplay(bool32 sameBall);
|
||||
void ArrowsChangeColorLastBallCycle(bool32 showArrows);
|
||||
void UpdateAbilityPopup(u8 battlerId);
|
||||
void CategoryIcons_LoadSpritesGfx(void);
|
||||
void TryToAddMoveInfoWindow(void);
|
||||
void TryToHideMoveInfoWindow(void);
|
||||
|
||||
#endif // GUARD_BATTLE_INTERFACE_H
|
||||
|
||||
@ -770,7 +770,10 @@ extern const u8 BattleScript_EffectDefenseUp3[];
|
||||
extern const u8 BattleScript_EffectNobleRoar[];
|
||||
extern const u8 BattleScript_EffectVenomDrench[];
|
||||
extern const u8 BattleScript_EffectToxicThread[];
|
||||
extern const u8 BattleScript_EffectHitSwitchTarget[];
|
||||
extern const u8 BattleScript_TryHitSwitchTarget[];
|
||||
extern const u8 BattleScript_HitSwitchTargetDynamaxed[];
|
||||
extern const u8 BattleScript_AbilityPreventsPhasingOutRet[];
|
||||
extern const u8 BattleScript_PrintMonIsRootedRet[];
|
||||
extern const u8 BattleScript_EffectFinalGambit[];
|
||||
extern const u8 BattleScript_EffectAutotomize[];
|
||||
extern const u8 BattleScript_EffectCopycat[];
|
||||
|
||||
@ -274,6 +274,7 @@ enum MoveEndEffects
|
||||
MOVEEND_ITEM_EFFECTS_TARGET,
|
||||
MOVEEND_MOVE_EFFECTS2,
|
||||
MOVEEND_ITEM_EFFECTS_ALL,
|
||||
MOVEEND_HIT_SWITCH_TARGET,
|
||||
MOVEEND_KINGSROCK, // These item effects will occur each strike of a multi-hit move
|
||||
MOVEEND_NUM_HITS,
|
||||
MOVEEND_SUBSTITUTE,
|
||||
|
||||
@ -669,6 +669,7 @@ void HandleInputChooseMove(u32 battler)
|
||||
|
||||
if (JOY_NEW(A_BUTTON) && !gBattleStruct->descriptionSubmenu)
|
||||
{
|
||||
TryToHideMoveInfoWindow();
|
||||
PlaySE(SE_SELECT);
|
||||
|
||||
moveTarget = GetBattlerMoveTargetType(battler, moveInfo->moves[gMoveSelectionCursor[battler]]);
|
||||
@ -779,6 +780,7 @@ void HandleInputChooseMove(u32 battler)
|
||||
BtlController_EmitTwoReturnValues(battler, BUFFER_B, 10, 0xFFFF);
|
||||
HideGimmickTriggerSprite();
|
||||
PlayerBufferExecCompleted(battler);
|
||||
TryToHideMoveInfoWindow();
|
||||
}
|
||||
}
|
||||
else if (JOY_NEW(DPAD_LEFT) && !gBattleStruct->zmove.viewing)
|
||||
@ -878,7 +880,7 @@ void HandleInputChooseMove(u32 battler)
|
||||
MoveSelectionDisplayMoveType(battler);
|
||||
}
|
||||
}
|
||||
else if (JOY_NEW(B_MOVE_DESCRIPTION_BUTTON) && B_MOVE_DESCRIPTION_BUTTON != B_LAST_USED_BALL_BUTTON)
|
||||
else if (JOY_NEW(B_MOVE_DESCRIPTION_BUTTON))
|
||||
{
|
||||
gBattleStruct->descriptionSubmenu = TRUE;
|
||||
MoveSelectionDisplayMoveDescription(battler);
|
||||
@ -2127,6 +2129,7 @@ void PlayerHandleChooseMove(u32 battler)
|
||||
|
||||
InitMoveSelectionsVarsAndStrings(battler);
|
||||
gBattleStruct->gimmick.playerSelect = FALSE;
|
||||
TryToAddMoveInfoWindow();
|
||||
|
||||
AssignUsableZMoves(battler, moveInfo->moves);
|
||||
gBattleStruct->zmove.viable = (gBattleStruct->zmove.possibleZMoves[battler] & (1u << gMoveSelectionCursor[battler])) != 0;
|
||||
|
||||
@ -206,6 +206,7 @@ static void Task_FreeAbilityPopUpGfx(u8);
|
||||
|
||||
static void SpriteCB_LastUsedBall(struct Sprite *);
|
||||
static void SpriteCB_LastUsedBallWin(struct Sprite *);
|
||||
static void SpriteCB_MoveInfoWin(struct Sprite *sprite);
|
||||
|
||||
static const struct OamData sOamData_64x32 =
|
||||
{
|
||||
@ -732,6 +733,7 @@ u8 CreateBattlerHealthboxSprites(u8 battlerId)
|
||||
|
||||
gBattleStruct->ballSpriteIds[0] = MAX_SPRITES;
|
||||
gBattleStruct->ballSpriteIds[1] = MAX_SPRITES;
|
||||
gBattleStruct->moveInfoSpriteId = MAX_SPRITES;
|
||||
|
||||
return healthboxLeftSpriteId;
|
||||
}
|
||||
@ -2886,6 +2888,36 @@ static const struct SpriteTemplate sSpriteTemplate_LastUsedBallWindow =
|
||||
.callback = SpriteCB_LastUsedBallWin
|
||||
};
|
||||
|
||||
#define MOVE_INFO_WINDOW_TAG 0xE722
|
||||
|
||||
static const struct OamData sOamData_MoveInfoWindow =
|
||||
{
|
||||
.y = 0,
|
||||
.affineMode = 0,
|
||||
.objMode = 0,
|
||||
.mosaic = 0,
|
||||
.bpp = 0,
|
||||
.shape = SPRITE_SHAPE(32x32),
|
||||
.x = 0,
|
||||
.matrixNum = 0,
|
||||
.size = SPRITE_SIZE(32x32),
|
||||
.tileNum = 0,
|
||||
.priority = 1,
|
||||
.paletteNum = 0,
|
||||
.affineParam = 0,
|
||||
};
|
||||
|
||||
static const struct SpriteTemplate sSpriteTemplate_MoveInfoWindow =
|
||||
{
|
||||
.tileTag = MOVE_INFO_WINDOW_TAG,
|
||||
.paletteTag = ABILITY_POP_UP_TAG,
|
||||
.oam = &sOamData_MoveInfoWindow,
|
||||
.anims = gDummySpriteAnimTable,
|
||||
.images = NULL,
|
||||
.affineAnims = gDummySpriteAffineAnimTable,
|
||||
.callback = SpriteCB_MoveInfoWin
|
||||
};
|
||||
|
||||
#if B_LAST_USED_BALL_BUTTON == R_BUTTON && B_LAST_USED_BALL_CYCLE == TRUE
|
||||
static const u8 ALIGNED(4) sLastUsedBallWindowGfx[] = INCBIN_U8("graphics/battle_interface/last_used_ball_r_cycle.4bpp");
|
||||
#elif B_LAST_USED_BALL_CYCLE == TRUE
|
||||
@ -2900,6 +2932,17 @@ static const struct SpriteSheet sSpriteSheet_LastUsedBallWindow =
|
||||
sLastUsedBallWindowGfx, sizeof(sLastUsedBallWindowGfx), LAST_BALL_WINDOW_TAG
|
||||
};
|
||||
|
||||
#if B_MOVE_DESCRIPTION_BUTTON == R_BUTTON
|
||||
static const u8 sMoveInfoWindowGfx[] = INCBIN_U8("graphics/battle_interface/move_info_window_r.4bpp");
|
||||
#else
|
||||
static const u8 sMoveInfoWindowGfx[] = INCBIN_U8("graphics/battle_interface/move_info_window_l.4bpp");
|
||||
#endif
|
||||
|
||||
static const struct SpriteSheet sSpriteSheet_MoveInfoWindow =
|
||||
{
|
||||
sMoveInfoWindowGfx, sizeof(sMoveInfoWindowGfx), MOVE_INFO_WINDOW_TAG
|
||||
};
|
||||
|
||||
#define LAST_USED_BALL_X_F 14
|
||||
#define LAST_USED_BALL_X_0 -14
|
||||
#define LAST_USED_BALL_Y ((IsDoubleBattle()) ? 78 : 68)
|
||||
@ -2958,7 +3001,7 @@ void TryAddLastUsedBallItemSprites(void)
|
||||
gBattleStruct->ballSpriteIds[0] = AddItemIconSprite(102, 102, gBallToDisplay);
|
||||
gSprites[gBattleStruct->ballSpriteIds[0]].x = LAST_USED_BALL_X_0;
|
||||
gSprites[gBattleStruct->ballSpriteIds[0]].y = LAST_USED_BALL_Y;
|
||||
gSprites[gBattleStruct->ballSpriteIds[0]].sHide = FALSE; // restore
|
||||
gSprites[gBattleStruct->ballSpriteIds[0]].sHide = FALSE;
|
||||
gLastUsedBallMenuPresent = TRUE;
|
||||
gSprites[gBattleStruct->ballSpriteIds[0]].callback = SpriteCB_LastUsedBall;
|
||||
}
|
||||
@ -2973,7 +3016,8 @@ void TryAddLastUsedBallItemSprites(void)
|
||||
gBattleStruct->ballSpriteIds[1] = CreateSprite(&sSpriteTemplate_LastUsedBallWindow,
|
||||
LAST_BALL_WIN_X_0,
|
||||
LAST_USED_WIN_Y, 5);
|
||||
gSprites[gBattleStruct->ballSpriteIds[1]].sHide = FALSE; // restore
|
||||
gSprites[gBattleStruct->ballSpriteIds[1]].sHide = FALSE;
|
||||
gSprites[gBattleStruct->moveInfoSpriteId].sHide = TRUE;
|
||||
gLastUsedBallMenuPresent = TRUE;
|
||||
}
|
||||
if (B_LAST_USED_BALL_CYCLE == TRUE)
|
||||
@ -2996,6 +3040,32 @@ static void DestroyLastUsedBallGfx(struct Sprite *sprite)
|
||||
gBattleStruct->ballSpriteIds[0] = MAX_SPRITES;
|
||||
}
|
||||
|
||||
void TryToAddMoveInfoWindow(void)
|
||||
{
|
||||
LoadSpritePalette(&sSpritePalette_AbilityPopUp);
|
||||
if (GetSpriteTileStartByTag(MOVE_INFO_WINDOW_TAG) == 0xFFFF)
|
||||
LoadSpriteSheet(&sSpriteSheet_MoveInfoWindow);
|
||||
|
||||
if (gBattleStruct->moveInfoSpriteId == MAX_SPRITES)
|
||||
{
|
||||
gBattleStruct->moveInfoSpriteId = CreateSprite(&sSpriteTemplate_MoveInfoWindow, LAST_BALL_WIN_X_0, LAST_USED_WIN_Y + 32, 6);
|
||||
gSprites[gBattleStruct->moveInfoSpriteId].sHide = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void TryToHideMoveInfoWindow(void)
|
||||
{
|
||||
gSprites[gBattleStruct->moveInfoSpriteId].sHide = TRUE;
|
||||
}
|
||||
|
||||
static void DestroyMoveInfoWinGfx(struct Sprite *sprite)
|
||||
{
|
||||
FreeSpriteTilesByTag(MOVE_INFO_WINDOW_TAG);
|
||||
FreeSpritePaletteByTag(ABILITY_POP_UP_TAG);
|
||||
DestroySprite(sprite);
|
||||
gBattleStruct->moveInfoSpriteId = MAX_SPRITES;
|
||||
}
|
||||
|
||||
static void SpriteCB_LastUsedBallWin(struct Sprite *sprite)
|
||||
{
|
||||
if (sprite->sHide)
|
||||
@ -3033,6 +3103,23 @@ static void SpriteCB_LastUsedBall(struct Sprite *sprite)
|
||||
}
|
||||
}
|
||||
|
||||
static void SpriteCB_MoveInfoWin(struct Sprite *sprite)
|
||||
{
|
||||
if (sprite->sHide)
|
||||
{
|
||||
if (sprite->x != LAST_BALL_WIN_X_0)
|
||||
sprite->x--;
|
||||
|
||||
if (sprite->x == LAST_BALL_WIN_X_0)
|
||||
DestroyMoveInfoWinGfx(sprite);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sprite->x != LAST_BALL_WIN_X_F)
|
||||
sprite->x++;
|
||||
}
|
||||
}
|
||||
|
||||
static void TryHideOrRestoreLastUsedBall(u8 caseId)
|
||||
{
|
||||
if (B_LAST_USED_BALL == FALSE)
|
||||
@ -3044,16 +3131,16 @@ static void TryHideOrRestoreLastUsedBall(u8 caseId)
|
||||
{
|
||||
case 0: // hide
|
||||
if (gBattleStruct->ballSpriteIds[0] != MAX_SPRITES)
|
||||
gSprites[gBattleStruct->ballSpriteIds[0]].sHide = TRUE; // hide
|
||||
gSprites[gBattleStruct->ballSpriteIds[0]].sHide = TRUE;
|
||||
if (gBattleStruct->ballSpriteIds[1] != MAX_SPRITES)
|
||||
gSprites[gBattleStruct->ballSpriteIds[1]].sHide = TRUE; // hide
|
||||
gSprites[gBattleStruct->ballSpriteIds[1]].sHide = TRUE;
|
||||
gLastUsedBallMenuPresent = FALSE;
|
||||
break;
|
||||
case 1: // restore
|
||||
if (gBattleStruct->ballSpriteIds[0] != MAX_SPRITES)
|
||||
gSprites[gBattleStruct->ballSpriteIds[0]].sHide = FALSE; // restore
|
||||
gSprites[gBattleStruct->ballSpriteIds[0]].sHide = FALSE;
|
||||
if (gBattleStruct->ballSpriteIds[1] != MAX_SPRITES)
|
||||
gSprites[gBattleStruct->ballSpriteIds[1]].sHide = FALSE; // restore
|
||||
gSprites[gBattleStruct->ballSpriteIds[1]].sHide = FALSE;
|
||||
gLastUsedBallMenuPresent = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -5829,11 +5829,12 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost)
|
||||
u32 moveType = GetMoveType(move);
|
||||
u32 moveEffect = GetMoveEffect(move);
|
||||
u32 species, heldItem, holdEffect, ability, type1, type2, type3;
|
||||
bool32 monInBattle = gMain.inBattle && gPartyMenu.menuType != PARTY_MENU_TYPE_IN_BATTLE;
|
||||
|
||||
if (move == MOVE_STRUGGLE)
|
||||
return TYPE_NORMAL;
|
||||
|
||||
if (gMain.inBattle)
|
||||
if (monInBattle)
|
||||
{
|
||||
species = gBattleMons[battler].species;
|
||||
heldItem = gBattleMons[battler].item;
|
||||
@ -5857,18 +5858,21 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost)
|
||||
switch (moveEffect)
|
||||
{
|
||||
case EFFECT_WEATHER_BALL:
|
||||
if (gMain.inBattle && HasWeatherEffect())
|
||||
if (monInBattle)
|
||||
{
|
||||
if (gBattleWeather & B_WEATHER_RAIN && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA)
|
||||
return TYPE_WATER;
|
||||
else if (gBattleWeather & B_WEATHER_SANDSTORM)
|
||||
return TYPE_ROCK;
|
||||
else if (gBattleWeather & B_WEATHER_SUN && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA)
|
||||
return TYPE_FIRE;
|
||||
else if (gBattleWeather & (B_WEATHER_SNOW | B_WEATHER_HAIL))
|
||||
return TYPE_ICE;
|
||||
else
|
||||
return moveType;
|
||||
if (HasWeatherEffect())
|
||||
{
|
||||
if (gBattleWeather & B_WEATHER_RAIN && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA)
|
||||
return TYPE_WATER;
|
||||
else if (gBattleWeather & B_WEATHER_SANDSTORM)
|
||||
return TYPE_ROCK;
|
||||
else if (gBattleWeather & B_WEATHER_SUN && holdEffect != HOLD_EFFECT_UTILITY_UMBRELLA)
|
||||
return TYPE_FIRE;
|
||||
else if (gBattleWeather & (B_WEATHER_SNOW | B_WEATHER_HAIL))
|
||||
return TYPE_ICE;
|
||||
else
|
||||
return moveType;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -5895,7 +5899,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost)
|
||||
case EFFECT_HIDDEN_POWER:
|
||||
{
|
||||
u32 typeBits = 0;
|
||||
if (gMain.inBattle)
|
||||
if (monInBattle)
|
||||
{
|
||||
typeBits = ((gBattleMons[battler].hpIV & 1) << 0)
|
||||
| ((gBattleMons[battler].attackIV & 1) << 1)
|
||||
@ -5974,7 +5978,7 @@ u32 GetDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler, u8 *ateBoost)
|
||||
else
|
||||
return moveType;
|
||||
case EFFECT_TERRAIN_PULSE:
|
||||
if (gMain.inBattle)
|
||||
if (monInBattle)
|
||||
{
|
||||
if (IsBattlerTerrainAffected(battler, STATUS_FIELD_TERRAIN_ANY))
|
||||
{
|
||||
|
||||
@ -6303,6 +6303,43 @@ static void Cmd_moveend(void)
|
||||
else
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_HIT_SWITCH_TARGET:
|
||||
if (gMovesInfo[gCurrentMove].effect == EFFECT_HIT_SWITCH_TARGET
|
||||
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& IsBattlerAlive(gBattlerAttacker)
|
||||
&& gSpecialStatuses[gBattlerAttacker].parentalBondState != PARENTAL_BOND_1ST_HIT)
|
||||
{
|
||||
u32 targetAbility = GetBattlerAbility(gBattlerTarget);
|
||||
if (targetAbility == ABILITY_GUARD_DOG)
|
||||
{
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
}
|
||||
|
||||
effect = TRUE;
|
||||
BattleScriptPushCursor();
|
||||
if (targetAbility == ABILITY_SUCTION_CUPS)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_AbilityPreventsPhasingOutRet;
|
||||
}
|
||||
else if (gStatuses3[gBattlerTarget] & STATUS3_ROOTED)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_PrintMonIsRootedRet;
|
||||
}
|
||||
else if (GetActiveGimmick(gBattlerTarget) == GIMMICK_DYNAMAX)
|
||||
{
|
||||
gBattlescriptCurrInstr = BattleScript_HitSwitchTargetDynamaxed;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattleScripting.switchCase = B_SWITCH_HIT;
|
||||
gBattlescriptCurrInstr = BattleScript_TryHitSwitchTarget;
|
||||
}
|
||||
}
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_KINGSROCK: // King's rock
|
||||
// These effects will occur at each hit in a multi-strike move
|
||||
if (ItemBattleEffects(ITEMEFFECT_KINGSROCK, 0, FALSE))
|
||||
@ -17683,26 +17720,6 @@ void BS_JumpIfBlockedBySoundproof(void)
|
||||
}
|
||||
}
|
||||
|
||||
void BS_TryHitSwitchTarget(void)
|
||||
{
|
||||
NATIVE_ARGS(const u8 *failInstr);
|
||||
|
||||
if (IsBattlerAlive(gBattlerAttacker)
|
||||
&& IsBattlerAlive(gBattlerTarget)
|
||||
&& !(gBattleStruct->moveResultFlags[gBattlerTarget] & MOVE_RESULT_NO_EFFECT)
|
||||
&& IsBattlerTurnDamaged(gBattlerTarget)
|
||||
&& gSpecialStatuses[gBattlerAttacker].parentalBondState != PARENTAL_BOND_1ST_HIT
|
||||
&& GetBattlerAbility(gBattlerTarget) != ABILITY_GUARD_DOG)
|
||||
{
|
||||
gBattleScripting.switchCase = B_SWITCH_HIT;
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gBattlescriptCurrInstr = cmd->failInstr;
|
||||
}
|
||||
}
|
||||
|
||||
void BS_SetMagicCoatTarget(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
|
||||
@ -1592,7 +1592,7 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
|
||||
|
||||
[EFFECT_HIT_SWITCH_TARGET] =
|
||||
{
|
||||
.battleScript = BattleScript_EffectHitSwitchTarget,
|
||||
.battleScript = BattleScript_EffectHit,
|
||||
.battleTvScore = 0, // TODO: Assign points
|
||||
},
|
||||
|
||||
|
||||
@ -2155,6 +2155,20 @@ static const u16 sGimmighoulFormSpeciesIdTable[] = {
|
||||
};
|
||||
#endif //P_FAMILY_GIMMIGHOUL
|
||||
|
||||
#if P_FAMILY_POLTCHAGEIST
|
||||
static const u16 sPoltchageistFormSpeciesIdTable[] = {
|
||||
SPECIES_POLTCHAGEIST_COUNTERFEIT,
|
||||
SPECIES_POLTCHAGEIST_ARTISAN,
|
||||
FORM_SPECIES_END,
|
||||
};
|
||||
|
||||
static const u16 sSinistchaFormSpeciesIdTable[] = {
|
||||
SPECIES_SINISTCHA_UNREMARKABLE,
|
||||
SPECIES_SINISTCHA_MASTERPIECE,
|
||||
FORM_SPECIES_END,
|
||||
};
|
||||
#endif //P_FAMILY_POLTCHAGEIST
|
||||
|
||||
#if P_FAMILY_OGERPON
|
||||
static const u16 sOgerponFormSpeciesIdTable[] = {
|
||||
SPECIES_OGERPON_TEAL,
|
||||
|
||||
@ -7091,6 +7091,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] =
|
||||
.levelUpLearnset = sPoltchageistLevelUpLearnset,
|
||||
.teachableLearnset = sPoltchageistTeachableLearnset,
|
||||
.evolutions = EVOLUTION({EVO_ITEM, ITEM_UNREMARKABLE_TEACUP, SPECIES_SINISTCHA_UNREMARKABLE}),
|
||||
.formSpeciesIdTable = sPoltchageistFormSpeciesIdTable,
|
||||
},
|
||||
[SPECIES_POLTCHAGEIST_ARTISAN] =
|
||||
{
|
||||
@ -7154,6 +7155,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] =
|
||||
.levelUpLearnset = sPoltchageistLevelUpLearnset,
|
||||
.teachableLearnset = sPoltchageistTeachableLearnset,
|
||||
.evolutions = EVOLUTION({EVO_ITEM, ITEM_MASTERPIECE_TEACUP, SPECIES_SINISTCHA_MASTERPIECE}),
|
||||
.formSpeciesIdTable = sPoltchageistFormSpeciesIdTable,
|
||||
},
|
||||
|
||||
[SPECIES_SINISTCHA_UNREMARKABLE] =
|
||||
@ -7217,6 +7219,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] =
|
||||
)
|
||||
.levelUpLearnset = sSinistchaLevelUpLearnset,
|
||||
.teachableLearnset = sSinistchaTeachableLearnset,
|
||||
.formSpeciesIdTable = sSinistchaFormSpeciesIdTable,
|
||||
},
|
||||
[SPECIES_SINISTCHA_MASTERPIECE] =
|
||||
{
|
||||
@ -7279,6 +7282,7 @@ const struct SpeciesInfo gSpeciesInfoGen9[] =
|
||||
)
|
||||
.levelUpLearnset = sSinistchaLevelUpLearnset,
|
||||
.teachableLearnset = sSinistchaTeachableLearnset,
|
||||
.formSpeciesIdTable = sSinistchaFormSpeciesIdTable,
|
||||
},
|
||||
#endif //P_FAMILY_POLTCHAGEIST
|
||||
|
||||
|
||||
116
test/battle/ability/big_pecks.c
Normal file
116
test/battle/ability/big_pecks.c
Normal file
@ -0,0 +1,116 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Big Pecks prevents Defense stage reduction from moves")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PIDGEY) { Ability(ABILITY_BIG_PECKS); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_LEER); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponent, ABILITY_BIG_PECKS);
|
||||
MESSAGE("The opposing Pidgey's Big Pecks prevents Defense loss!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Big Pecks is ignored by Mold Breaker")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN);
|
||||
PLAYER(SPECIES_PINSIR) { Ability(ABILITY_MOLD_BREAKER); }
|
||||
OPPONENT(SPECIES_PIDGEY) { Ability(ABILITY_BIG_PECKS); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_LEER); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(player, ABILITY_MOLD_BREAKER);
|
||||
MESSAGE("Pinsir breaks the mold!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LEER, player);
|
||||
MESSAGE("The opposing Pidgey's Defense fell!");
|
||||
NONE_OF {
|
||||
ABILITY_POPUP(opponent, ABILITY_BIG_PECKS);
|
||||
MESSAGE("The opposing Pidgey's Big Pecks prevents Defense loss!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Big Pecks doesn't prevent Defense stage reduction from moves used by the user")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(MoveHasAdditionalEffectSelf(MOVE_SUPERPOWER, MOVE_EFFECT_ATK_DEF_DOWN) == TRUE);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PIDGEY) { Ability(ABILITY_BIG_PECKS); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SUPERPOWER); }
|
||||
TURN {}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUPERPOWER, opponent);
|
||||
MESSAGE("The opposing Pidgey's Attack fell!");
|
||||
MESSAGE("The opposing Pidgey's Defense fell!");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Big Pecks doesn't prevent Topsy-Turvy")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_HARDEN].effect == EFFECT_DEFENSE_UP);
|
||||
ASSUME(gMovesInfo[MOVE_TOPSY_TURVY].effect == EFFECT_TOPSY_TURVY);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PIDGEY) { Ability(ABILITY_BIG_PECKS); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_HARDEN); MOVE(player, MOVE_TOPSY_TURVY); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HARDEN, opponent);
|
||||
MESSAGE("The opposing Pidgey's Defense rose!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_TOPSY_TURVY, player);
|
||||
MESSAGE("All stat changes on the opposing Pidgey were inverted!");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Big Pecks doesn't prevent Spectral Thief from resetting positive Defense stage changes")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_HARDEN].effect == EFFECT_DEFENSE_UP);
|
||||
ASSUME(MoveHasAdditionalEffect(MOVE_SPECTRAL_THIEF, MOVE_EFFECT_SPECTRAL_THIEF));
|
||||
ASSUME(gMovesInfo[MOVE_SOAK].effect == EFFECT_SOAK);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PIDGEY) { Ability(ABILITY_BIG_PECKS); }
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_CELEBRATE); MOVE(player,MOVE_SOAK); }
|
||||
TURN { MOVE(opponent, MOVE_HARDEN); MOVE(player, MOVE_SPECTRAL_THIEF); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_HARDEN, opponent);
|
||||
MESSAGE("The opposing Pidgey's Defense rose!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SPECTRAL_THIEF, player);
|
||||
MESSAGE("Wobbuffet stole the target's boosted stats!");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Big Pecks doesn't prevent receiving negative Defense stage changes from Baton Pass")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_LEER].effect == EFFECT_DEFENSE_DOWN);
|
||||
ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS);
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_PIDGEY) { Ability(ABILITY_BIG_PECKS); }
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_LEER);
|
||||
MOVE(opponent, MOVE_BATON_PASS);
|
||||
SEND_OUT(opponent, 1);
|
||||
}
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_LEER, player);
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_BATON_PASS, opponent);
|
||||
MESSAGE("2 sent out Pidgey!");
|
||||
} THEN {
|
||||
EXPECT_EQ(opponent->statStages[STAT_DEF], DEFAULT_STAT_STAGE - 1);
|
||||
}
|
||||
}
|
||||
@ -351,3 +351,27 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutral
|
||||
}
|
||||
}
|
||||
|
||||
DOUBLE_BATTLE_TEST("Intimidate will correctly decrease the attack of the second mon after Protosynthesis activated")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET) { Item(ITEM_EJECT_PACK); }
|
||||
PLAYER(SPECIES_WYNAUT);
|
||||
PLAYER(SPECIES_WALKING_WAKE) { Ability(ABILITY_PROTOSYNTHESIS); Item(ITEM_BOOSTER_ENERGY); }
|
||||
OPPONENT(SPECIES_WYNAUT);
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_EKANS) { Ability(ABILITY_INTIMIDATE); }
|
||||
} WHEN {
|
||||
TURN { SWITCH(opponentLeft, 2); SEND_OUT(playerLeft, 2); }
|
||||
} SCENE {
|
||||
ABILITY_POPUP(opponentLeft, ABILITY_INTIMIDATE);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, playerLeft);
|
||||
ABILITY_POPUP(playerLeft, ABILITY_PROTOSYNTHESIS);
|
||||
NONE_OF {
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentLeft);
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponentRight);
|
||||
}
|
||||
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
|
||||
}
|
||||
}
|
||||
|
||||
61
test/battle/ability/water_compaction.c
Normal file
61
test/battle/ability/water_compaction.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include "global.h"
|
||||
#include "test/battle.h"
|
||||
|
||||
SINGLE_BATTLE_TEST("Water Compaction raises Defense 2 stages when hit by a water type move")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER);
|
||||
PLAYER(SPECIES_SANDYGAST) { Ability(ABILITY_WATER_COMPACTION); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_WATER_GUN); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent);
|
||||
ABILITY_POPUP(player, ABILITY_WATER_COMPACTION);
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 2);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Water Compaction raises Defense 2 stages on each hit of a multi-hit Water type move")
|
||||
{
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_SURGING_STRIKES].type == TYPE_WATER);
|
||||
ASSUME(gMovesInfo[MOVE_SURGING_STRIKES].strikeCount == 3);
|
||||
PLAYER(SPECIES_SANDYGAST) { Ability(ABILITY_WATER_COMPACTION); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_SURGING_STRIKES); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURGING_STRIKES, opponent);
|
||||
ABILITY_POPUP(player, ABILITY_WATER_COMPACTION);
|
||||
MESSAGE("Sandygast's Defense sharply rose!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURGING_STRIKES, opponent);
|
||||
ABILITY_POPUP(player, ABILITY_WATER_COMPACTION);
|
||||
MESSAGE("Sandygast's Defense sharply rose!");
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_SURGING_STRIKES, opponent);
|
||||
ABILITY_POPUP(player, ABILITY_WATER_COMPACTION);
|
||||
MESSAGE("Sandygast's Defense sharply rose!");
|
||||
} THEN {
|
||||
EXPECT_EQ(player->statStages[STAT_DEF], DEFAULT_STAT_STAGE + 6);
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Water Compaction does not affect damage taken from Water type moves", s16 damage)
|
||||
{
|
||||
u16 ability;
|
||||
PARAMETRIZE { ability = ABILITY_SAND_VEIL; }
|
||||
PARAMETRIZE { ability = ABILITY_WATER_COMPACTION; }
|
||||
GIVEN {
|
||||
ASSUME(gMovesInfo[MOVE_WATER_GUN].type == TYPE_WATER);
|
||||
PLAYER(SPECIES_SANDYGAST) { Ability(ability); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
} WHEN {
|
||||
TURN { MOVE(opponent, MOVE_WATER_GUN); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_WATER_GUN, opponent);
|
||||
HP_BAR(player, captureDamage: &results[i].damage);
|
||||
} FINALLY {
|
||||
EXPECT_EQ(results[0].damage, results[1].damage);
|
||||
}
|
||||
}
|
||||
@ -69,3 +69,52 @@ SINGLE_BATTLE_TEST("Dragon Tail does not fail if replacements fainted")
|
||||
NOT MESSAGE("But it failed!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Dragon Tail switches the target after Rocky Helmet and Iron Barbs")
|
||||
{
|
||||
PASSES_RANDOMLY(1, 2, RNG_FORCE_RANDOM_SWITCH);
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_TOGEDEMARU) { Ability(ABILITY_IRON_BARBS); Item(ITEM_ROCKY_HELMET); }
|
||||
OPPONENT(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_CHARMANDER);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DRAGON_TAIL); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, player);
|
||||
HP_BAR(player);
|
||||
MESSAGE("Wobbuffet was hurt by the opposing Togedemaru's Iron Barbs!");
|
||||
HP_BAR(player);
|
||||
MESSAGE("Wobbuffet was hurt by the opposing Togedemaru's Rocky Helmet!");
|
||||
MESSAGE("The opposing Charmander was dragged out!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Dragon Tail effect will fails against Guard Dog ability")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_OKIDOGI) { Ability(ABILITY_GUARD_DOG); }
|
||||
OPPONENT(SPECIES_CHARMANDER);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DRAGON_TAIL); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, player);
|
||||
NOT MESSAGE("The opposing Charmander was dragged out!");
|
||||
}
|
||||
}
|
||||
|
||||
SINGLE_BATTLE_TEST("Dragon Tail effect will fails against Suction Cups ability")
|
||||
{
|
||||
GIVEN {
|
||||
PLAYER(SPECIES_WOBBUFFET);
|
||||
OPPONENT(SPECIES_OCTILLERY) { Ability(ABILITY_SUCTION_CUPS); }
|
||||
OPPONENT(SPECIES_CHARMANDER);
|
||||
} WHEN {
|
||||
TURN { MOVE(player, MOVE_DRAGON_TAIL); }
|
||||
} SCENE {
|
||||
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_TAIL, player);
|
||||
MESSAGE("The opposing Octillery anchors itself with Suction Cups!");
|
||||
NOT MESSAGE("The opposing Charmander was dragged out!");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user