add red card effect

This commit is contained in:
Evan 2021-01-07 19:33:39 -07:00
parent bf644f23a7
commit 5eb49722c0
10 changed files with 136 additions and 9 deletions

View File

@ -5592,16 +5592,27 @@ BattleScript_RoarSuccessSwitch::
waitstate waitstate
printstring STRINGID_PKMNWASDRAGGEDOUT printstring STRINGID_PKMNWASDRAGGEDOUT
switchineffects BS_TARGET switchineffects BS_TARGET
jumpifbyte CMP_EQUAL, sSWITCH_CASE, B_SWITCH_RED_CARD, BattleScript_RoarSuccessSwitch_Ret
setbyte sSWITCH_CASE, B_SWITCH_NORMAL
goto BattleScript_MoveEnd goto BattleScript_MoveEnd
BattleScript_RoarSuccessSwitch_Ret:
swapattackerwithtarget @ continuation of RedCardActivates
removeitem BS_TARGET
setbyte sSWITCH_CASE, B_SWITCH_NORMAL
return
BattleScript_RoarSuccessEndBattle:: BattleScript_RoarSuccessEndBattle::
call BattleScript_RoarSuccessRet call BattleScript_RoarSuccessRet
setbyte sSWITCH_CASE, B_SWITCH_NORMAL
setoutcomeonteleport BS_ATTACKER setoutcomeonteleport BS_ATTACKER
finishaction finishaction
BattleScript_RoarSuccessRet: BattleScript_RoarSuccessRet:
jumpifbyte CMP_EQUAL, sSWITCH_CASE, B_SWITCH_HIT, BattleScript_RoarSuccessRet_Ret
jumpifbyte CMP_EQUAL, sSWITCH_CASE, B_SWITCH_RED_CARD, BattleScript_RoarSuccessRet_Ret
attackanimation attackanimation
waitanimation waitanimation
BattleScript_RoarSuccessRet_Ret:
switchoutabilities BS_TARGET switchoutabilities BS_TARGET
returntoball BS_TARGET returntoball BS_TARGET
waitstate waitstate
@ -7790,3 +7801,31 @@ BattleScript_AnnounceAirLockCloudNine::
waitmessage 0x40 waitmessage 0x40
call BattleScript_WeatherFormChanges call BattleScript_WeatherFormChanges
end3 end3
BattleScript_RedCardActivates::
jumpifcantswitch SWITCH_IGNORE_ESCAPE_PREVENTION | BS_ATTACKER, BattleScript_RedCardEnd
playanimation BS_SCRIPTING, B_ANIM_HELD_ITEM_EFFECT, NULL
printstring STRINGID_REDCARDACTIVATE
waitmessage 0x40
swapattackerwithtarget
jumpifstatus3 BS_EFFECT_BATTLER, STATUS3_ROOTED, BattleScript_RedCardIngrain
jumpifability BS_EFFECT_BATTLER, ABILITY_SUCTION_CUPS, BattleScript_RedCardSuctionCups
setbyte sSWITCH_CASE, B_SWITCH_RED_CARD
forcerandomswitch BattleScript_RedCardEnd
@ changes the current battle script. the rest happens in BattleScript_RoarSuccessSwitch_Ret, if switch is successful
return
BattleScript_RedCardEnd:
return
BattleScript_RedCardIngrain:
printstring STRINGID_PKMNANCHOREDITSELF
waitmessage 0x40
removeitem BS_SCRIPTING
swapattackerwithtarget
return
BattleScript_RedCardSuctionCups:
printstring STRINGID_PKMNANCHORSITSELFWITH
waitmessage 0x40
removeitem BS_SCRIPTING
swapattackerwithtarget
return

View File

@ -614,6 +614,7 @@ struct BattleScripting
u16 multihitMoveEffect; u16 multihitMoveEffect;
u8 illusionNickHack; // To properly display nick in STRINGID_ENEMYABOUTTOSWITCHPKMN. u8 illusionNickHack; // To properly display nick in STRINGID_ENEMYABOUTTOSWITCHPKMN.
bool8 fixedPopup; // force ability popup to stick until manually called back bool8 fixedPopup; // force ability popup to stick until manually called back
u8 switchCase; // special switching conditions, eg. red card
}; };
// rom_80A5C6C // rom_80A5C6C

View File

@ -352,5 +352,6 @@ extern const u8 BattleScript_EmergencyExitWildNoPopUp[];
extern const u8 BattleScript_CheekPouchActivates[]; extern const u8 BattleScript_CheekPouchActivates[];
extern const u8 BattleScript_AnnounceAirLockCloudNine[]; extern const u8 BattleScript_AnnounceAirLockCloudNine[];
extern const u8 BattleScript_AttackerItemStatRaise[]; extern const u8 BattleScript_AttackerItemStatRaise[];
extern const u8 BattleScript_RedCardActivates[];
#endif // GUARD_BATTLE_SCRIPTS_H #endif // GUARD_BATTLE_SCRIPTS_H

View File

@ -132,5 +132,6 @@ bool8 ShouldGetStatBadgeBoost(u16 flagId, u8 battlerId);
u8 GetBattleMoveSplit(u32 moveId); u8 GetBattleMoveSplit(u32 moveId);
u8 TryHandleSeed(u8 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 execute); u8 TryHandleSeed(u8 battler, u32 terrainFlag, u8 statId, u16 itemId, bool32 execute);
bool32 IsBattlerAffectedByHazards(u8 battlerId, bool32 toxicSpikes); bool32 IsBattlerAffectedByHazards(u8 battlerId, bool32 toxicSpikes);
void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast);
bool32 TestSheerForceFlag(u8 battler, u16 move);
#endif // GUARD_BATTLE_UTIL_H #endif // GUARD_BATTLE_UTIL_H

View File

@ -36,6 +36,7 @@
#define sMULTIHIT_EFFECT gBattleScripting + 0x30 #define sMULTIHIT_EFFECT gBattleScripting + 0x30
#define sILLUSION_NICK_HACK gBattleScripting + 0x32 #define sILLUSION_NICK_HACK gBattleScripting + 0x32
#define sFIXED_ABILITY_POPUP gBattleScripting + 0x33 #define sFIXED_ABILITY_POPUP gBattleScripting + 0x33
#define sSWITCH_CASE gBattleScripting + 0x34
#define cMULTISTRING_CHOOSER gBattleCommunication + 5 #define cMULTISTRING_CHOOSER gBattleCommunication + 5
@ -234,4 +235,9 @@
#define BIT_ACC 0x40 #define BIT_ACC 0x40
#define BIT_EVASION 0x80 #define BIT_EVASION 0x80
// switch cases
#define B_SWITCH_NORMAL 0
#define B_SWITCH_HIT 1 // dragon tail, circle throw
#define B_SWITCH_RED_CARD 2
#endif // GUARD_CONSTANTS_BATTLE_SCRIPT_COMMANDS_H #endif // GUARD_CONSTANTS_BATTLE_SCRIPT_COMMANDS_H

View File

@ -558,8 +558,9 @@
#define STRINGID_AURABREAKENTERS 554 #define STRINGID_AURABREAKENTERS 554
#define STRINGID_COMATOSEENTERS 555 #define STRINGID_COMATOSEENTERS 555
#define STRINGID_SCREENCLEANERENTERS 556 #define STRINGID_SCREENCLEANERENTERS 556
#define STRINGID_REDCARDACTIVATE 557
#define BATTLESTRINGS_COUNT 557 #define BATTLESTRINGS_COUNT 558
//// multichoice message IDs //// multichoice message IDs
// switch in ability message // switch in ability message

View File

@ -3041,6 +3041,10 @@ void SwitchInClearSetData(void)
gBattleResources->flags->flags[gActiveBattler] = 0; gBattleResources->flags->flags[gActiveBattler] = 0;
gCurrentMove = 0; gCurrentMove = 0;
gBattleStruct->arenaTurnCounter = 0xFF; gBattleStruct->arenaTurnCounter = 0xFF;
// reset damage to prevent things like red card activating if the switched-in mon is holding it
gSpecialStatuses[gActiveBattler].physicalDmg = 0;
gSpecialStatuses[gActiveBattler].specialDmg = 0;
ClearBattlerMoveHistory(gActiveBattler); ClearBattlerMoveHistory(gActiveBattler);
ClearBattlerAbilityHistory(gActiveBattler); ClearBattlerAbilityHistory(gActiveBattler);

View File

@ -685,9 +685,11 @@ static const u8 sText_FairyAuraActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX}
static const u8 sText_AuraBreakActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} reversed all\nother POKéMON's auras!"); static const u8 sText_AuraBreakActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} reversed all\nother POKéMON's auras!");
static const u8 sText_ComatoseActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is drowsing!"); static const u8 sText_ComatoseActivates[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} is drowsing!");
static const u8 sText_ScreenCleanerActivates[] = _("All screens on the field were\ncleansed!"); static const u8 sText_ScreenCleanerActivates[] = _("All screens on the field were\ncleansed!");
static const u8 sText_RedCardActivate[] = _("{B_SCR_ACTIVE_NAME_WITH_PREFIX} held up its {B_LAST_ITEM}\nagainst {B_ATK_NAME_WITH_PREFIX}!");
const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] = const u8 *const gBattleStringsTable[BATTLESTRINGS_COUNT] =
{ {
[STRINGID_REDCARDACTIVATE - 12] = sText_RedCardActivate,
[STRINGID_STATWASNOTLOWERED - 12] = sText_StatWasNotLowered, [STRINGID_STATWASNOTLOWERED - 12] = sText_StatWasNotLowered,
[STRINGID_CLOAKEDINAFREEZINGLIGHT - 12] = sText_CloakedInAFreezingLight, [STRINGID_CLOAKEDINAFREEZINGLIGHT - 12] = sText_CloakedInAFreezingLight,
[STRINGID_DESTINYKNOTACTIVATES - 12] = sText_DestinyKnotActivates, [STRINGID_DESTINYKNOTACTIVATES - 12] = sText_DestinyKnotActivates,

View File

@ -5010,22 +5010,47 @@ static void Cmd_moveend(void)
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_EJECT_BUTTON: case MOVEEND_EJECT_BUTTON:
/*if (gCurrentMove != MOVE_DRAGON_TAIL && gCurrentMove != MOVE_CIRCLE_THROW)
{
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed
}
BattleScript_ForceRandomSwitch*/
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_RED_CARD: case MOVEEND_RED_CARD:
if (gCurrentMove != MOVE_DRAGON_TAIL
&& gCurrentMove != MOVE_CIRCLE_THROW
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& IsBattlerAlive(gBattlerAttacker)
&& !TestSheerForceFlag(gBattlerAttacker, gCurrentMove)
&& (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER || (gBattleTypeFlags & BATTLE_TYPE_TRAINER)))
{
u8 battlers[4] = {0, 1, 2, 3};
SortBattlersBySpeed(battlers, FALSE);
for (i = 0; i < gBattlersCount; i++)
{
u8 battler = battlers[i];
// attacker is the one to be switched out, battler is one with red card
if (battler != gBattlerAttacker
&& IsBattlerAlive(battler)
&& !DoesSubstituteBlockMove(gCurrentMove, gBattlerAttacker, battler)
&& GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_RED_CARD
&& (gSpecialStatuses[battler].physicalDmg != 0 || gSpecialStatuses[battler].specialDmg != 0))
{
gLastUsedItem = gBattleMons[battler].item;
gActiveBattler = gBattleScripting.battler = battler; // battler with red card
gEffectBattler = gBattlerAttacker;
if (gBattleMoves[gCurrentMove].effect == EFFECT_HIT_ESCAPE)
gBattlescriptCurrInstr = BattleScript_MoveEnd; // prevent user switch-in selection
BattleScriptPushCursor();
gBattlescriptCurrInstr = BattleScript_RedCardActivates;
effect = TRUE;
break; // only fastest red card activates
}
}
}
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_EJECT_PACK: case MOVEEND_EJECT_PACK:
gBattleScripting.moveendState++; gBattleScripting.moveendState++;
break; break;
case MOVEEND_LIFE_ORB: case MOVEEND_LIFE_ORB:
// TODO shell bell goes here too
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIFE_ORB if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_LIFE_ORB
&& IsBattlerAlive(gBattlerAttacker) && IsBattlerAlive(gBattlerAttacker)
&& !(GetBattlerAbility(gBattlerAttacker) == ABILITY_SHEER_FORCE && gBattleMoves[gCurrentMove].flags & FLAG_SHEER_FORCE_BOOST) && !(GetBattlerAbility(gBattlerAttacker) == ABILITY_SHEER_FORCE && gBattleMoves[gCurrentMove].flags & FLAG_SHEER_FORCE_BOOST)
@ -7981,6 +8006,7 @@ static void Cmd_various(void)
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT) && !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& TARGET_TURN_DAMAGED) && TARGET_TURN_DAMAGED)
{ {
gBattleScripting.switchCase = B_SWITCH_HIT;
gBattlescriptCurrInstr = BattleScript_ForceRandomSwitch; gBattlescriptCurrInstr = BattleScript_ForceRandomSwitch;
} }
else else

View File

@ -7930,3 +7930,49 @@ bool32 IsBattlerAffectedByHazards(u8 battlerId, bool32 toxicSpikes)
} }
return ret; return ret;
} }
bool32 TestSheerForceFlag(u8 battler, u16 move)
{
if (GetBattlerAbility(battler) == ABILITY_SHEER_FORCE && gBattleMoves[move].flags & FLAG_SHEER_FORCE_BOOST)
return TRUE;
else
return FALSE;
}
void SortBattlersBySpeed(u8 *battlers, bool8 slowToFast)
{
int i, j, currSpeed, currBattler;
u16 speeds[4] = {0};
for (i = 0; i < gBattlersCount; i++)
speeds[i] = GetBattlerTotalSpeedStat(battlers[i]);
for (i = 1; i < gBattlersCount; i++)
{
currBattler = battlers[i];
currSpeed = speeds[i];
j = i - 1;
if (slowToFast)
{
while (j >= 0 && speeds[j] > currSpeed)
{
battlers[j + 1] = battlers[j];
speeds[j + 1] = speeds[j];
j = j - 1;
}
}
else
{
while (j >= 0 && speeds[j] < currSpeed)
{
battlers[j + 1] = battlers[j];
speeds[j + 1] = speeds[j];
j = j - 1;
}
}
battlers[j + 1] = currBattler;
speeds[j + 1] = currSpeed;
}
}