From 39e3b0b7401ef6d9184f04d093c0e113ca4b56e1 Mon Sep 17 00:00:00 2001 From: DizzyEggg Date: Tue, 31 Dec 2019 19:11:53 +0100 Subject: [PATCH] Form changes layout and Stance Change Aegi --- asm/macros/battle_script.inc | 5 ++ data/battle_anim_scripts.s | 8 ++ data/battle_scripts_1.s | 12 +++ include/battle_scripts.h | 1 + include/battle_util.h | 3 +- include/constants/battle_anim.h | 1 + include/constants/battle_config.h | 3 + include/constants/battle_script_commands.h | 1 + src/battle_main.c | 6 ++ src/battle_script_commands.c | 91 ++++++++++++++++++---- src/battle_util.c | 23 +++++- 11 files changed, 139 insertions(+), 15 deletions(-) diff --git a/asm/macros/battle_script.inc b/asm/macros/battle_script.inc index 8a83036739..fc8ecf8257 100644 --- a/asm/macros/battle_script.inc +++ b/asm/macros/battle_script.inc @@ -1531,6 +1531,11 @@ .byte \case .endm + .macro handleformchange battler:req, case:req + various \battler, VARIOUS_HANDLE_FORM_CHANGE + .byte \case + .endm + .macro jumpifcantuselastresort battler:req, ptr:req various \battler, VARIOUS_TRY_LAST_RESORT .4byte \ptr diff --git a/data/battle_anim_scripts.s b/data/battle_anim_scripts.s index d6328541a4..a18c69be97 100644 --- a/data/battle_anim_scripts.s +++ b/data/battle_anim_scripts.s @@ -683,6 +683,7 @@ gBattleAnims_General:: .4byte General_TerrainElectric .4byte General_TerrainPsychic .4byte General_IllusionOff + .4byte General_FormChange .align 2 gBattleAnims_Special:: @@ -14763,6 +14764,13 @@ General_IllusionOff: waitforvisualfinish clearmonbg ANIM_TARGET end + +General_FormChange: + monbg ANIM_ATTACKER + createvisualtask AnimTask_TransformMon, 2, 0, 1 + waitforvisualfinish + clearmonbg ANIM_ATTACKER + end General_MegaEvolution: loadspritegfx ANIM_TAG_MEGA_STONE diff --git a/data/battle_scripts_1.s b/data/battle_scripts_1.s index 095d4062e3..faf26a9577 100644 --- a/data/battle_scripts_1.s +++ b/data/battle_scripts_1.s @@ -5881,6 +5881,18 @@ BattleScript_MegaEvolution:: printstring STRINGID_MEGAEVOEVOLVED waitmessage 0x40 end2 + +BattleScript_StanceChangeActivates:: + pause 0x5 + call BattleScript_AbilityPopUp + printstring STRINGID_EMPTYSTRING3 + waitmessage 0x1 + handleformchange BS_ATTACKER, 0 + handleformchange BS_ATTACKER, 1 + playanimation BS_ATTACKER, B_ANIM_FORM_CHANGE, NULL + waitanimation + handleformchange BS_ATTACKER, 2 + return BattleScript_IllusionOff:: spriteignore0hp TRUE diff --git a/include/battle_scripts.h b/include/battle_scripts.h index 448f3b29f6..824b96548f 100644 --- a/include/battle_scripts.h +++ b/include/battle_scripts.h @@ -328,5 +328,6 @@ extern const u8 BattleScript_MoveEffectBugBite[]; extern const u8 BattleScript_IllusionOff[]; extern const u8 BattleScript_DancerActivates[]; extern const u8 BattleScript_AftermathDmg[]; +extern const u8 BattleScript_StanceChangeActivates[]; #endif // GUARD_BATTLE_SCRIPTS_H diff --git a/include/battle_util.h b/include/battle_util.h index 5d4dff81ee..b7d572c790 100644 --- a/include/battle_util.h +++ b/include/battle_util.h @@ -103,7 +103,8 @@ u16 GetTypeModifier(u8 atkType, u8 defType); s32 GetStealthHazardDamage(u8 hazardType, u8 battlerId); u16 GetMegaEvolutionSpecies(u16 preEvoSpecies, u16 heldItemId); bool32 CanMegaEvolve(u8 battlerId); -void UndoMegaEvolution(u8 monId); +void UndoMegaEvolution(u32 monId); +void UndoFormChange(u32 monId, u32 side); bool32 DoBattlersShareType(u32 battler1, u32 battler2); bool32 CanBattlerGetOrLoseItem(u8 battlerId, u16 itemId); struct Pokemon *GetIllusionMonPtr(u32 battlerId); diff --git a/include/constants/battle_anim.h b/include/constants/battle_anim.h index 0307357b19..5369e756db 100644 --- a/include/constants/battle_anim.h +++ b/include/constants/battle_anim.h @@ -407,6 +407,7 @@ #define B_ANIM_TERRAIN_ELECTRIC 0x1A #define B_ANIM_TERRAIN_PSYCHIC 0x1B #define B_ANIM_ILLUSION_OFF 0x1C +#define B_ANIM_FORM_CHANGE 0x1D // special animations table #define B_ANIM_LVL_UP 0x0 diff --git a/include/constants/battle_config.h b/include/constants/battle_config.h index b4098ea7d5..2390bee60b 100644 --- a/include/constants/battle_config.h +++ b/include/constants/battle_config.h @@ -9,6 +9,8 @@ #define SPECIES_ARCEUS 0 #define SPECIES_SILVALLY 0 #define SPECIES_GENESECT 0 +#define SPECIES_AEGISLASH 0 +#define SPECIES_AEGISLASH_BLADE 10000 // Items with peculiar battle effects. Remove them if they're properly placed in constant/items.h #define ITEM_GRISEOUS_ORB 0 @@ -50,6 +52,7 @@ #define B_SOUND_SUBSTITUTE GEN_6 // Starting from gen6 sound moves bypass Substitute. #define B_EXP_CATCH GEN_6 // Starting from gen6, pokemon get experience from catching. #define B_ABILITY_POP_UP GEN_6 // Starting from gen5, the pokemon abilities are displayed in a pop-up, when they activate in battle. +#define B_STANCE_CHANGE_FAIL GEN_7 // In Gen7, Aegislash's form change does not happen, if the pokemon cannot use a move, because of confusion, paralysis, etc. In gen6, the form change occurs despite not being able to move. #define B_FAST_INTRO TRUE // If set to TRUE, battle intro texts print at the same time as animation of a pokemon, as opposing to waiting for the animation to end. diff --git a/include/constants/battle_script_commands.h b/include/constants/battle_script_commands.h index 4b94c90331..4e690ab5ea 100644 --- a/include/constants/battle_script_commands.h +++ b/include/constants/battle_script_commands.h @@ -145,6 +145,7 @@ #define VARIOUS_UPDATE_NICK 82 #define VARIOUS_TRY_ILLUSION_OFF 83 #define VARIOUS_SET_SPRITEIGNORE0HP 84 +#define VARIOUS_HANDLE_FORM_CHANGE 85 // Cmd_manipulatedmg #define DMG_CHANGE_SIGN 0 diff --git a/src/battle_main.c b/src/battle_main.c index 8a4b012fc0..b8dc77eb6f 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -3154,6 +3154,7 @@ void FaintClearSetData(void) ClearBattlerMoveHistory(gActiveBattler); ClearBattlerAbilityHistory(gActiveBattler); + UndoFormChange(gBattlerPartyIndexes[gActiveBattler], GET_BATTLER_SIDE(gActiveBattler)); if (GetBattlerSide(gActiveBattler) == B_SIDE_PLAYER) UndoMegaEvolution(gBattlerPartyIndexes[gActiveBattler]); } @@ -4864,7 +4865,10 @@ static void HandleEndTurn_FinishBattle(void) BeginFastPaletteFade(3); FadeOutMapMusic(5); for (i = 0; i < PARTY_SIZE; i++) + { UndoMegaEvolution(i); + UndoFormChange(i, B_SIDE_PLAYER); + } gBattleMainFunc = FreeResetData_ReturnToOvOrDoEvolutions; gCB2_AfterEvolution = BattleMainCB2; } @@ -5360,6 +5364,8 @@ static void HandleAction_Switch(void) if (gBattleResults.playerSwitchesCounter < 255) gBattleResults.playerSwitchesCounter++; + + UndoFormChange(gBattlerPartyIndexes[gBattlerAttacker], GetBattlerSide(gBattlerAttacker)); } static void HandleAction_UseItem(void) diff --git a/src/battle_script_commands.c b/src/battle_script_commands.c index 102b49c867..d8dcc7359a 100644 --- a/src/battle_script_commands.c +++ b/src/battle_script_commands.c @@ -970,6 +970,32 @@ static bool32 NoTargetPresent(u32 move) return FALSE; } +static bool32 TryAegiFormChange(void) +{ + if (GetBattlerAbility(gBattlerAttacker) != ABILITY_STANCE_CHANGE) + return FALSE; + + switch (gBattleMons[gBattlerAttacker].species) + { + default: + return FALSE; + case SPECIES_AEGISLASH: // Shield -> Blade + if (gBattleMoves[gCurrentMove].power == 0) + return FALSE; + gBattleMons[gBattlerAttacker].species = SPECIES_AEGISLASH_BLADE; + break; + case SPECIES_AEGISLASH_BLADE: // Blade -> Shield + if (gCurrentMove != MOVE_KING_S_SHIELD) + return FALSE; + gBattleMons[gBattlerAttacker].species = SPECIES_AEGISLASH; + break; + } + + BattleScriptPushCursor(); + gBattlescriptCurrInstr = BattleScript_StanceChangeActivates; + return TRUE; +} + static void Cmd_attackcanceler(void) { s32 i, moveType; @@ -985,6 +1011,10 @@ static void Cmd_attackcanceler(void) gBattlescriptCurrInstr = BattleScript_MoveEnd; return; } + #if (B_STANCE_CHANGE_FAIL <= GEN_6) + if (TryAegiFormChange()) + return; + #endif if (AtkCanceller_UnableToUseMove()) return; @@ -1014,6 +1044,10 @@ static void Cmd_attackcanceler(void) gMoveResultFlags |= MOVE_RESULT_MISSED; return; } + #if (B_STANCE_CHANGE_FAIL >= GEN_7) + if (TryAegiFormChange()) + return; + #endif gHitMarker &= ~(HITMARKER_x800000); if (!(gHitMarker & HITMARKER_OBEYS) && !(gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)) @@ -4141,6 +4175,7 @@ static void Cmd_playanimation(void) || gBattlescriptCurrInstr[2] == B_ANIM_SNATCH_MOVE || gBattlescriptCurrInstr[2] == B_ANIM_MEGA_EVOLUTION || gBattlescriptCurrInstr[2] == B_ANIM_ILLUSION_OFF + || gBattlescriptCurrInstr[2] == B_ANIM_FORM_CHANGE || gBattlescriptCurrInstr[2] == B_ANIM_SUBSTITUTE_FADE) { BtlController_EmitBattleAnimation(0, gBattlescriptCurrInstr[2], *argumentPtr); @@ -4186,6 +4221,7 @@ static void Cmd_playanimation2(void) // animation Id is stored in the first poin || *animationIdPtr == B_ANIM_SNATCH_MOVE || *animationIdPtr == B_ANIM_MEGA_EVOLUTION || *animationIdPtr == B_ANIM_ILLUSION_OFF + || *animationIdPtr == B_ANIM_FORM_CHANGE || *animationIdPtr == B_ANIM_SUBSTITUTE_FADE) { BtlController_EmitBattleAnimation(0, *animationIdPtr, *argumentPtr); @@ -6676,6 +6712,22 @@ u32 IsLeafGuardProtected(u32 battler) return 0; } +static void RecalcBattlerStats(u32 battler, struct Pokemon *mon) +{ + CalculateMonStats(mon); + gBattleMons[battler].level = GetMonData(mon, MON_DATA_LEVEL); + gBattleMons[battler].hp = GetMonData(mon, MON_DATA_HP); + gBattleMons[battler].maxHP = GetMonData(mon, MON_DATA_MAX_HP); + gBattleMons[battler].attack = GetMonData(mon, MON_DATA_ATK); + gBattleMons[battler].defense = GetMonData(mon, MON_DATA_DEF); + gBattleMons[battler].speed = GetMonData(mon, MON_DATA_SPEED); + gBattleMons[battler].spAttack = GetMonData(mon, MON_DATA_SPATK); + gBattleMons[battler].spDefense = GetMonData(mon, MON_DATA_SPDEF); + gBattleMons[battler].ability = GetMonAbility(mon); + gBattleMons[battler].type1 = gBaseStats[gBattleMons[battler].species].type1; + gBattleMons[battler].type2 = gBaseStats[gBattleMons[battler].species].type2; +} + static void Cmd_various(void) { struct Pokemon *mon; @@ -7297,19 +7349,7 @@ static void Cmd_various(void) // Change stats. else if (gBattlescriptCurrInstr[3] == 1) { - CalculateMonStats(mon); - gBattleMons[gActiveBattler].level = GetMonData(mon, MON_DATA_LEVEL); - gBattleMons[gActiveBattler].hp = GetMonData(mon, MON_DATA_HP); - gBattleMons[gActiveBattler].maxHP = GetMonData(mon, MON_DATA_MAX_HP); - gBattleMons[gActiveBattler].attack = GetMonData(mon, MON_DATA_ATK); - gBattleMons[gActiveBattler].defense = GetMonData(mon, MON_DATA_DEF); - gBattleMons[gActiveBattler].speed = GetMonData(mon, MON_DATA_SPEED); - gBattleMons[gActiveBattler].spAttack = GetMonData(mon, MON_DATA_SPATK); - gBattleMons[gActiveBattler].spDefense = GetMonData(mon, MON_DATA_SPDEF); - gBattleMons[gActiveBattler].ability = GetMonAbility(mon); - gBattleMons[gActiveBattler].type1 = gBaseStats[gBattleMons[gActiveBattler].species].type1; - gBattleMons[gActiveBattler].type2 = gBaseStats[gBattleMons[gActiveBattler].species].type2; - + RecalcBattlerStats(gActiveBattler, mon); gBattleStruct->mega.alreadyEvolved[GetBattlerPosition(gActiveBattler)] = TRUE; gBattleStruct->mega.evolvedPartyIds[GetBattlerSide(gActiveBattler)] |= gBitTable[gBattlerPartyIndexes[gActiveBattler]]; } @@ -7321,6 +7361,31 @@ static void Cmd_various(void) } gBattlescriptCurrInstr += 4; return; + case VARIOUS_HANDLE_FORM_CHANGE: + if (GetBattlerSide(gActiveBattler) == B_SIDE_OPPONENT) + mon = &gEnemyParty[gBattlerPartyIndexes[gActiveBattler]]; + else + mon = &gPlayerParty[gBattlerPartyIndexes[gActiveBattler]]; + + // Change species. + if (gBattlescriptCurrInstr[3] == 0) + { + PREPARE_SPECIES_BUFFER(gBattleTextBuff1, gBattleMons[gActiveBattler].species); + BtlController_EmitSetMonData(0, REQUEST_SPECIES_BATTLE, gBitTable[gBattlerPartyIndexes[gActiveBattler]], 2, &gBattleMons[gActiveBattler].species); + MarkBattlerForControllerExec(gActiveBattler); + } + // Change stats. + else if (gBattlescriptCurrInstr[3] == 1) + { + RecalcBattlerStats(gActiveBattler, mon); + } + // Update healthbox. + else + { + UpdateHealthboxAttribute(gHealthboxSpriteIds[gActiveBattler], mon, HEALTHBOX_ALL); + } + gBattlescriptCurrInstr += 4; + return; case VARIOUS_TRY_LAST_RESORT: if (CanUseLastResort(gActiveBattler)) gBattlescriptCurrInstr += 7; diff --git a/src/battle_util.c b/src/battle_util.c index ee0d3a3814..a80849d5d2 100644 --- a/src/battle_util.c +++ b/src/battle_util.c @@ -6276,7 +6276,7 @@ bool32 CanMegaEvolve(u8 battlerId) return TRUE; } -void UndoMegaEvolution(u8 monId) +void UndoMegaEvolution(u32 monId) { if (gBattleStruct->mega.evolvedPartyIds[B_SIDE_PLAYER] & gBitTable[monId]) { @@ -6286,6 +6286,27 @@ void UndoMegaEvolution(u8 monId) } } +void UndoFormChange(u32 monId, u32 side) +{ + u32 i, currSpecies; + struct Pokemon *party = (side == B_SIDE_PLAYER) ? gPlayerParty : gEnemyParty; + static const u16 species[][2] = // changed form id, default form id + { + {SPECIES_AEGISLASH_BLADE, SPECIES_AEGISLASH}, + }; + + currSpecies = GetMonData(&party[monId], MON_DATA_SPECIES, NULL); + for (i = 0; i < ARRAY_COUNT(species); i++) + { + if (currSpecies == species[i][0]) + { + SetMonData(&party[monId], MON_DATA_SPECIES, &species[i][1]); + CalculateMonStats(&party[monId]); + break; + } + } +} + bool32 DoBattlersShareType(u32 battler1, u32 battler2) { s32 i;