Adds Dragon Cheer (#4122)

* Adds Dragon Cheer

* fix assumptions

---------

Co-authored-by: ghoulslash <41651341+ghoulslash@users.noreply.github.com>
This commit is contained in:
Alex 2024-02-03 16:00:41 +01:00 committed by GitHub
parent ac94af3be6
commit ab2774f8c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 138 additions and 26 deletions

View File

@ -17159,7 +17159,7 @@ Move_RAGING_BULL::
restorebg
waitbgfadein
end
@ Credits to Z-nogyroP. Simple anim that combines Force Palm + Fake Out
Move_UPPER_HAND::
loadspritegfx ANIM_TAG_SHADOW_BALL

View File

@ -3579,7 +3579,7 @@ BattleScript_EffectFocusEnergy::
attackcanceler
attackstring
ppreduce
jumpifstatus2 BS_ATTACKER, STATUS2_FOCUS_ENERGY, BattleScript_ButItFailed
jumpifstatus2 BS_ATTACKER, STATUS2_FOCUS_ENERGY_ANY, BattleScript_ButItFailed
setfocusenergy
attackanimation
waitanimation
@ -9941,10 +9941,8 @@ BattleScript_RaiseCritAlliesLoop:
setstatchanger STAT_ATK, 0, FALSE @ for animation
setgraphicalstatchangevalues
playanimation BS_TARGET, B_ANIM_STATS_CHANGE, sB_ANIM_ARG1
swapattackerwithtarget
printstring STRINGID_PKMNGETTINGPUMPED
waitmessage B_WAIT_TIME_LONG
swapattackerwithtarget
BattleScript_RaiseCritAlliesIncrement:
setbyte sSTAT_ANIM_PLAYED, FALSE
jumpifbytenotequal gBattlerTarget, gBattlerAttacker, BattleScript_RaiseCritAlliesEnd

View File

@ -114,7 +114,7 @@ BattleScript_ItemSetMist::
BattleScript_ItemSetFocusEnergy::
call BattleScript_UseItemMessage
jumpifstatus2 BS_ATTACKER, STATUS2_FOCUS_ENERGY, BattleScript_ButItFailed
jumpifstatus2 BS_ATTACKER, STATUS2_FOCUS_ENERGY_ANY, BattleScript_ButItFailed
setfocusenergy
playmoveanimation BS_ATTACKER, MOVE_FOCUS_ENERGY
waitanimation

View File

@ -129,7 +129,7 @@
#define STATUS2_FLINCHED (1 << 3)
#define STATUS2_UPROAR (1 << 4 | 1 << 5 | 1 << 6)
#define STATUS2_UPROAR_TURN(num) ((num) << 4)
#define STATUS2_UNUSED (1 << 7)
#define STATUS2_TORMENT (1 << 7)
#define STATUS2_BIDE (1 << 8 | 1 << 9)
#define STATUS2_BIDE_TURN(num) (((num) << 8) & STATUS2_BIDE)
#define STATUS2_LOCK_CONFUSE (1 << 10 | 1 << 11) // e.g. Thrash
@ -139,7 +139,7 @@
#define STATUS2_POWDER (1 << 14)
#define STATUS2_INFATUATION (1 << 16 | 1 << 17 | 1 << 18 | 1 << 19) // 4 bits, one for every battler
#define STATUS2_INFATUATED_WITH(battler) (gBitTable[battler] << 16)
#define STATUS2_FOCUS_ENERGY (1 << 20)
#define STATUS2_DEFENSE_CURL (1 << 20)
#define STATUS2_TRANSFORMED (1 << 21)
#define STATUS2_RECHARGE (1 << 22)
#define STATUS2_RAGE (1 << 23)
@ -149,8 +149,9 @@
#define STATUS2_NIGHTMARE (1 << 27)
#define STATUS2_CURSED (1 << 28)
#define STATUS2_FORESIGHT (1 << 29)
#define STATUS2_DEFENSE_CURL (1 << 30)
#define STATUS2_TORMENT (1 << 31)
#define STATUS2_DRAGON_CHEER (1 << 30)
#define STATUS2_FOCUS_ENERGY (1 << 31)
#define STATUS2_FOCUS_ENERGY_ANY (STATUS2_DRAGON_CHEER | STATUS2_FOCUS_ENERGY)
#define STATUS3_LEECHSEED_BATTLER (1 << 0 | 1 << 1) // The battler to receive HP from Leech Seed
#define STATUS3_LEECHSEED (1 << 2)

View File

@ -352,6 +352,7 @@ enum {
EFFECT_RAIN_ALWAYS_HIT, // Unlike EFFECT_THUNDER, it doesn't get its accuracy reduced under sun.
EFFECT_SHED_TAIL,
EFFECT_UPPER_HAND,
EFFECT_DRAGON_CHEER,
NUM_BATTLE_MOVE_EFFECTS,
};

View File

@ -1477,7 +1477,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
ADJUST_SCORE(-10);
break;
case EFFECT_FOCUS_ENERGY:
if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY)
if (gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY_ANY)
ADJUST_SCORE(-10);
break;
case EFFECT_CONFUSE:
@ -1762,6 +1762,7 @@ static s32 AI_CheckBadMove(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
break;
case EFFECT_FOLLOW_ME:
case EFFECT_HELPING_HAND:
case EFFECT_DRAGON_CHEER:
if (!isDoubleBattle
|| !IsBattlerAlive(BATTLE_PARTNER(battlerAtk))
|| PartnerHasSameMoveEffectWithoutTarget(BATTLE_PARTNER(battlerAtk), move, aiData->partnerMove)
@ -2781,6 +2782,13 @@ static s32 AI_DoubleBattle(u32 battlerAtk, u32 battlerDef, u32 move, s32 score)
RETURN_SCORE_PLUS(DECENT_EFFECT); // partner has earthquake or magnitude -> good idea to use magnet rise
}
break;
case EFFECT_DRAGON_CHEER:
if (gBattleMons[battlerAtkPartner].status2 & STATUS2_FOCUS_ENERGY_ANY || !HasDamagingMove(battlerAtkPartner))
ADJUST_SCORE(-5);
else if (atkPartnerHoldEffect == HOLD_EFFECT_SCOPE_LENS
|| IS_BATTLER_OF_TYPE(battlerAtkPartner, TYPE_DRAGON)
|| gMovesInfo[aiData->partnerMove].criticalHitStage > 0)
ADJUST_SCORE(GOOD_EFFECT);
} // our effect relative to partner
// consider global move effects

View File

@ -2088,7 +2088,7 @@ static bool32 ShouldUseItem(u32 battler)
break;
case EFFECT_ITEM_SET_FOCUS_ENERGY:
if (!gDisableStructs[battler].isFirstTurn
|| gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY
|| gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY
|| AI_OpponentCanFaintAiWithMod(battler, 0))
break;
shouldUse = TRUE;

View File

@ -3106,7 +3106,7 @@ void SwitchInClearSetData(u32 battler)
}
if (gMovesInfo[gCurrentMove].effect == EFFECT_BATON_PASS)
{
gBattleMons[battler].status2 &= (STATUS2_CONFUSION | STATUS2_FOCUS_ENERGY | STATUS2_SUBSTITUTE | STATUS2_ESCAPE_PREVENTION | STATUS2_CURSED);
gBattleMons[battler].status2 &= (STATUS2_CONFUSION | STATUS2_FOCUS_ENERGY_ANY | STATUS2_SUBSTITUTE | STATUS2_ESCAPE_PREVENTION | STATUS2_CURSED);
gStatuses3[battler] &= (STATUS3_LEECHSEED_BATTLER | STATUS3_LEECHSEED | STATUS3_ALWAYS_HITS | STATUS3_PERISH_SONG | STATUS3_ROOTED
| STATUS3_GASTRO_ACID | STATUS3_EMBARGO | STATUS3_TELEKINESIS | STATUS3_MAGNET_RISE | STATUS3_HEAL_BLOCK
| STATUS3_AQUA_RING | STATUS3_POWER_TRICK);

View File

@ -166,7 +166,7 @@ static const u8 sText_PkmnFreedFrom[] = _("{B_ATK_NAME_WITH_PREFIX} was freed\nf
static const u8 sText_PkmnCrashed[] = _("{B_ATK_NAME_WITH_PREFIX} kept going\nand crashed!");
const u8 gText_PkmnShroudedInMist[] = _("{B_ATK_PREFIX2} became\nshrouded in MIST!");
static const u8 sText_PkmnProtectedByMist[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is protected\nby MIST!");
const u8 gText_PkmnGettingPumped[] = _("{B_ATK_NAME_WITH_PREFIX} is getting\npumped!");
const u8 gText_PkmnGettingPumped[] = _("{B_DEF_NAME_WITH_PREFIX} is getting\npumped!");
static const u8 sText_PkmnHitWithRecoil[] = _("{B_ATK_NAME_WITH_PREFIX} is hit\nwith recoil!");
static const u8 sText_PkmnProtectedItself2[] = _("{B_ATK_NAME_WITH_PREFIX} protected\nitself!");
static const u8 sText_PkmnBuffetedBySandstorm[] = _("{B_ATK_NAME_WITH_PREFIX} is buffeted\nby the sandstorm!");

View File

@ -1906,6 +1906,7 @@ s32 CalcCritChanceStageArgs(u32 battlerAtk, u32 battlerDef, u32 move, bool32 rec
else
{
critChance = 2 * ((gBattleMons[battlerAtk].status2 & STATUS2_FOCUS_ENERGY) != 0)
+ 1 * ((gBattleMons[battlerAtk].status2 & STATUS2_DRAGON_CHEER) != 0)
+ gMovesInfo[gCurrentMove].criticalHitStage
+ (holdEffectAtk == HOLD_EFFECT_SCOPE_LENS)
+ 2 * (holdEffectAtk == HOLD_EFFECT_LUCKY_PUNCH && gBattleMons[battlerAtk].species == SPECIES_CHANSEY)
@ -12331,14 +12332,20 @@ static void Cmd_setfocusenergy(void)
{
CMD_ARGS();
if (gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY)
if ((gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_CHEER && (!(gBattleTypeFlags & BATTLE_TYPE_DOUBLE) || (gAbsentBattlerFlags & gBitTable[gBattlerTarget])))
|| gBattleMons[gBattlerTarget].status2 & STATUS2_FOCUS_ENERGY_ANY)
{
gMoveResultFlags |= MOVE_RESULT_FAILED;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_FOCUS_ENERGY_FAILED;
}
else if (gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_CHEER && !IS_BATTLER_OF_TYPE(gBattlerTarget, TYPE_DRAGON))
{
gBattleMons[gBattlerTarget].status2 |= STATUS2_DRAGON_CHEER;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_GETTING_PUMPED;
}
else
{
gBattleMons[gBattlerAttacker].status2 |= STATUS2_FOCUS_ENERGY;
gBattleMons[gBattlerTarget].status2 |= STATUS2_FOCUS_ENERGY;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_GETTING_PUMPED;
}
gBattlescriptCurrInstr = cmd->nextInstr;
@ -16539,10 +16546,10 @@ void BS_TryUpperHand(void)
{
NATIVE_ARGS(const u8 *failInstr);
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget)
|| gChosenMoveByBattler[gBattlerTarget] == MOVE_NONE
|| IS_MOVE_STATUS(gChosenMoveByBattler[gBattlerTarget])
|| GetChosenMovePriority(gBattlerTarget) < 1 || GetChosenMovePriority(gBattlerTarget) > 3) // Fails if priority is less than 1 or greater than 3, if target already moved, or if using a status
if (GetBattlerTurnOrderNum(gBattlerAttacker) > GetBattlerTurnOrderNum(gBattlerTarget)
|| gChosenMoveByBattler[gBattlerTarget] == MOVE_NONE
|| IS_MOVE_STATUS(gChosenMoveByBattler[gBattlerTarget])
|| GetChosenMovePriority(gBattlerTarget) < 1 || GetChosenMovePriority(gBattlerTarget) > 3) // Fails if priority is less than 1 or greater than 3, if target already moved, or if using a status
gBattlescriptCurrInstr = cmd->failInstr;
else
gBattlescriptCurrInstr = cmd->nextInstr;

View File

@ -6859,7 +6859,7 @@ static u8 ItemEffectMoveEnd(u32 battler, u16 holdEffect)
break;
case HOLD_EFFECT_CRITICAL_UP: // lansat berry
if (B_BERRIES_INSTANT >= GEN_4
&& !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY)
&& !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY)
&& HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem))
{
gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY;
@ -6984,7 +6984,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
break;
case HOLD_EFFECT_CRITICAL_UP:
if (B_BERRIES_INSTANT >= GEN_4
&& !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY)
&& !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY)
&& HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem))
{
gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY;
@ -7295,7 +7295,7 @@ u8 ItemBattleEffects(u8 caseID, u32 battler, bool32 moveTurn)
effect = StatRaiseBerry(battler, gLastUsedItem, STAT_SPDEF, TRUE);
break;
case HOLD_EFFECT_CRITICAL_UP:
if (!moveTurn && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY)
if (!moveTurn && !(gBattleMons[battler].status2 & STATUS2_FOCUS_ENERGY_ANY)
&& HasEnoughHpToEatBerry(battler, GetBattlerItemHoldEffectParam(battler, gLastUsedItem), gLastUsedItem))
{
gBattleMons[battler].status2 |= STATUS2_FOCUS_ENERGY;

View File

@ -606,7 +606,7 @@ void SetZEffect(void)
}
break;
case Z_EFFECT_BOOST_CRITS:
if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY))
if (!(gBattleMons[gBattlerAttacker].status2 & STATUS2_FOCUS_ENERGY_ANY))
{
gBattleMons[gBattlerAttacker].status2 |= STATUS2_FOCUS_ENERGY;
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_Z_BOOST_CRITS;

View File

@ -2229,4 +2229,11 @@ const struct BattleMoveEffect gBattleMoveEffects[NUM_BATTLE_MOVE_EFFECTS] =
.battleScript = BattleScript_EffectUpperHand,
.battleTvScore = 0, // TODO: Assign points
},
[EFFECT_DRAGON_CHEER] =
{
.battleScript = BattleScript_EffectFocusEnergy,
.battleTvScore = 1,
.encourageEncore = TRUE,
},
};

View File

@ -2884,6 +2884,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.priority = 0,
.category = DAMAGE_CATEGORY_STATUS,
.zMove = { .effect = Z_EFFECT_ACC_UP_1 },
.argument = STATUS2_FOCUS_ENERGY,
.ignoresProtect = TRUE,
.mirrorMoveBanned = TRUE,
.snatchAffected = TRUE,
@ -19859,7 +19860,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.description = COMPOUND_STRING(
"Increases allies' critical hit\n"
"ratio, especially if Dragons."),
.effect = EFFECT_PLACEHOLDER, //EFFECT_DRAGON_CHEER
.effect = EFFECT_DRAGON_CHEER,
.power = 0,
.type = TYPE_DRAGON,
.accuracy = 0,

View File

@ -1192,7 +1192,7 @@ bool32 CannotUseItemsInBattle(u16 itemId, struct Pokemon *mon)
cannotUse = TRUE;
break;
case EFFECT_ITEM_SET_FOCUS_ENERGY:
if (gBattleMons[gBattlerInMenuId].status2 & STATUS2_FOCUS_ENERGY)
if (gBattleMons[gBattlerInMenuId].status2 & STATUS2_FOCUS_ENERGY_ANY)
cannotUse = TRUE;
break;
case EFFECT_ITEM_SET_MIST:

View File

@ -212,7 +212,6 @@ SINGLE_BATTLE_TEST("Signature items Leek and Lucky Punch increase the critical h
u32 species;
u32 item;
ASSUME(B_CRIT_CHANCE >= GEN_7);
PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT);
PARAMETRIZE { species = SPECIES_FARFETCHD; item = ITEM_LEEK; }
@ -250,3 +249,93 @@ SINGLE_BATTLE_TEST("Dire Hit increases a battler's critical hit chance by 2 stag
MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Focus Energy increases critical hit ratio by two")
{
PASSES_RANDOMLY(8, 8, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1);
ASSUME(gMovesInfo[MOVE_FOCUS_ENERGY].effect == EFFECT_FOCUS_ENERGY);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_FOCUS_ENERGY); }
TURN { MOVE(player, MOVE_SLASH); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, player);
MESSAGE("Wobbuffet is getting pumped!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_SLASH, player);
MESSAGE("A critical hit!");
}
}
SINGLE_BATTLE_TEST("Dragon Cheer fails in a single battle")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(player, MOVE_DRAGON_CHEER); }
} SCENE {
MESSAGE("But it failed!");
}
}
DOUBLE_BATTLE_TEST("Dragon Cheer increases critical hit ratio by one on non Dragon types")
{
PASSES_RANDOMLY(1, 8, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(gMovesInfo[MOVE_TACKLE].criticalHitStage == 0);
ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WYNAUT);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_DRAGON_CHEER, target: playerRight); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_CHEER, playerLeft);
MESSAGE("Wynaut is getting pumped!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight);
MESSAGE("A critical hit!");
}
}
DOUBLE_BATTLE_TEST("Dragon Cheer increases critical hit ratio by two on Dragon types")
{
PASSES_RANDOMLY(1, 2, RNG_CRITICAL_HIT);
GIVEN {
ASSUME(gMovesInfo[MOVE_TACKLE].criticalHitStage == 0);
ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_DRATINI);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_DRAGON_CHEER, target: playerRight); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_DRAGON_CHEER, playerLeft);
MESSAGE("Dratini is getting pumped!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight);
MESSAGE("A critical hit!");
}
}
DOUBLE_BATTLE_TEST("Dragon Cheer fails if critical hit stage was already increased by Focus Energy")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_SLASH].criticalHitStage == 1);
ASSUME(gMovesInfo[MOVE_FOCUS_ENERGY].effect == EFFECT_FOCUS_ENERGY);
ASSUME(gMovesInfo[MOVE_DRAGON_CHEER].effect == EFFECT_DRAGON_CHEER);
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(playerLeft, MOVE_FOCUS_ENERGY); MOVE(playerRight, MOVE_DRAGON_CHEER, target: playerLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_FOCUS_ENERGY, playerLeft);
MESSAGE("But it failed!");
}
}