Skip to content

Commit

Permalink
Added support for XY's Sky Battles (#2950)
Browse files Browse the repository at this point in the history
* Original implementation from Phlayne

* Moved Sky Battle Flag / Var into a config

* Optimized existing code and fixed existing bugs

Added error message for when sky battle var and flag are not set
Merged CanDoSkyBattle and PrepareSkyBattle into one special

* Added compatibility for Gen7+

* Commented out Volt Crash from banned moves

* Cleaned up debug scripts from testing

* Fixed bug where player did not white out even if they had no healthy Pokémon and only an egg
Zeroed out both Sky Battle configs

* Removed extra include from src/field_specials.c
Removed extra line break in src/battle_script_commands.c

* Added FLAG_DISABLED_IN_SKY_BATTLE
Added FLAG_DISABLED_IN_SKY_BATTLE to appropriate moves

* Changed DoesSkyBattleCancelCurrentMove to look at move flags

* Fixed alignment and spacing in battle_moves.h

* Added FLAG_DISABLED_IN_SKY_BATTLE to Sticky Web

* Added FLAG_DISABLED_IN_SKY_BATTLE to Steel Roller

* Disabled the ability to change Battle Terrain when Sky Battle is happening
Stopped Ceaseless Edge from spawning Spikes when Sky Battle is happening
Added B_SKY_BATTLE_STRICT_MECHANICS config

* Fixed bug with SKY_BATTLE_STRICT_MECHANICS where conditions were not consistently being applied

* Add rulesVariants to the BattleStruct
Added skyBattle check in AllocateBattleResources

* Replaced B_FLAG_SKY_BATTLE checks with rulesVariants.skyBattle checks

* Fixed debug script

* Reverted include/config/battle.h

* Fixed spacing and placement of functions

* Fixed debug script omission
Fixed bug where Spikes did not set from Ceaseless Edge and Stone Axe

* Added FLAG_DISABLED_IN_SKY_BATTLE to Psychic Terrain

* Addressed DizzyEgg PR feedback

* Forgot a file in last commit

* Addressed feedback from DizzyEggg

* Address Lunos' PR feedback

* Update specials.inc

Added an empty line at the end of data/specials.inc

* Fixed spacing

* Apply suggestions from code review

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>

* Updated skyBattleBanned and HandleBattleVariantEndParty to use correct names

* Removed STRICT_MOVES and STRICT_MECHANICS

* Fixed minor spacing issues with merge

* Merged in upcoming

* Implemented feedback from Jasper
https://github.com/rh-hideout/pokeemerald-expansion/pull/2950/files/5da6117d1bc725900c6386e62ab719f8e1695027

---------

Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>
  • Loading branch information
pkmnsnfrn and AsparagusEduardo authored Nov 26, 2023
1 parent 0fe203c commit 493478e
Show file tree
Hide file tree
Showing 17 changed files with 222 additions and 6 deletions.
13 changes: 13 additions & 0 deletions data/scripts/debug.inc
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,19 @@ Debug_BoxFilledMessage::
Debug_BoxFilledMessage_Text:
.string "Storage boxes filled!$"

Debug_FlagsAndVarNotSetBattleConfigMessage::
lockall
message Debug_FlagsAndVarNotSetBattleConfigMessage_Text
waitmessage
waitbuttonpress
releaseall
end

Debug_FlagsAndVarNotSetBattleConfigMessage_Text:
.string "Feature unavailable! Please define a\n"
.string "usable flag and a usable var in:\l"
.string "'include/config/battle.h'!$"

Debug_EventScript_Script_1::
end

Expand Down
1 change: 1 addition & 0 deletions data/specials.inc
Original file line number Diff line number Diff line change
Expand Up @@ -539,3 +539,4 @@ gSpecials::
def_special GetNumberSprayStrength
def_special GetSprayId
def_special GetLastUsedSprayType
def_special TrySkyBattle
1 change: 1 addition & 0 deletions include/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,7 @@ struct BattleStruct
u32 aiDelayFrames; // Number of frames it took to choose an action.
bool8 transformZeroToHero[PARTY_SIZE][NUM_BATTLE_SIDES];
u8 pledgeMove:1;
bool8 isSkyBattle:1;
};

// The palaceFlags member of struct BattleStruct contains 1 flag per move to indicate which moves the AI should consider,
Expand Down
2 changes: 2 additions & 0 deletions include/battle_script_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ s32 CalcCritChanceStage(u32 battlerAtk, u32 battlerDef, u32 move, bool32 recordA
s32 GetCritHitChance(s32 critChanceIndex);
u32 GetTotalAccuracy(u32 battlerAtk, u32 battlerDef, u32 move, u32 atkAbility, u32 defAbility, u32 atkHoldEffect, u32 defHoldEffect);
u8 GetBattlerTurnOrderNum(u8 battlerId);
bool32 NoAliveMonsForPlayer(void);
bool32 NoAliveMonsForEitherParty(void);
void SetMoveEffect(bool32 primary, u32 certain);
bool32 CanBattlerSwitch(u32 battlerId);
Expand All @@ -52,6 +53,7 @@ void StealTargetItem(u8 battlerStealer, u8 battlerItem);
u8 GetCatchingBattler(void);
u32 GetHighestStatId(u32 battlerId);
bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType);
bool32 IsMoveNotAllowedInSkyBattles(u32 move);
bool32 DoSwitchInAbilitiesItems(u32 battlerId);
u8 GetFirstFaintedPartyIndex(u8 battlerId);
bool32 IsMoveAffectedByParentalBond(u32 move, u32 battler);
Expand Down
2 changes: 2 additions & 0 deletions include/battle_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,7 @@ bool32 AreBattlersOfOppositeGender(u32 battler1, u32 battler2);
bool32 AreBattlersOfSameGender(u32 battler1, u32 battler2);
u32 CalcSecondaryEffectChance(u32 battler, u8 secondaryEffectChance, u16 moveEffect);
u8 GetBattlerType(u32 battler, u8 typeIndex);
bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon);
bool8 IsMonBannedFromSkyBattles(u16 species);

#endif // GUARD_BATTLE_UTIL_H
6 changes: 6 additions & 0 deletions include/config/battle.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@
#define VAR_TERRAIN 0 // If this var has a value, assigning a STATUS_FIELD_xx_TERRAIN to it before battle causes the battle to start with that terrain active
#define B_VAR_WILD_AI_FLAGS 0 // If not 0, you can use this var to add to default wild AI flags. NOT usable with flags above (1 << 15)

// Sky Battles
#define B_FLAG_SKY_BATTLE 0 // If this flag has a value, the player will be able to engage in scripted Sky Battles.
#define B_VAR_SKY_BATTLE 0 // If this var has a value, the game will remember the positions of Pokémon used in Sky Battles.

#define B_SKY_BATTLE_STRICT_ELIGIBILITY FALSE //If TRUE, Sky Battles will use the eligibility from Pokémon XY. If FALSE, all Flying-types or Pokémon with Levitate are allowed.

// Flag and Var settings
#define B_RESET_FLAGS_VARS_AFTER_WHITEOUT TRUE // If TRUE, Overworld_ResetBattleFlagsAndVars will reset battle-related Flags and Vars when the player whites out.

Expand Down
1 change: 1 addition & 0 deletions include/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define GUARD_DEBUG_H

void Debug_ShowMainMenu(void);
extern const u8 Debug_FlagsAndVarNotSetBattleConfigMessage[];

extern EWRAM_DATA bool8 gIsDebugBattle;
extern EWRAM_DATA u32 gDebugAIFlags;
Expand Down
1 change: 1 addition & 0 deletions include/field_specials.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ bool8 UsedPokemonCenterWarp(void);
void ResetFanClub(void);
bool8 ShouldShowBoxWasFullMessage(void);
void SetPCBoxToSendMon(u8 boxId);
void PreparePartyForSkyBattle(void);

#endif // GUARD_FIELD_SPECIALS_H
1 change: 1 addition & 0 deletions include/pokemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ struct BattleMove
u32 instructBanned:1;
u32 encoreBanned:1;
u32 parentalBondBanned:1;
u32 skyBattleBanned:1;
};

#define SPINDA_SPOT_WIDTH 16
Expand Down
18 changes: 14 additions & 4 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,11 @@ bool32 ProteanTryChangeType(u32 battler, u32 ability, u32 move, u32 moveType)
return FALSE;
}

bool32 IsMoveNotAllowedInSkyBattles(u32 move)
{
return ((gBattleStruct->isSkyBattle) && (gBattleMoves[gCurrentMove].skyBattleBanned));
}

static void Cmd_attackcanceler(void)
{
CMD_ARGS();
Expand Down Expand Up @@ -1363,9 +1368,10 @@ static void Cmd_attackcanceler(void)
}

gHitMarker |= HITMARKER_OBEYS;
// Check if no available target present on the field.
if (NoTargetPresent(gBattlerAttacker, gCurrentMove)
// Check if no available target present on the field or if Sky Battles ban the move
if ((NoTargetPresent(gBattlerAttacker, gCurrentMove)
&& (!gBattleMoves[gCurrentMove].twoTurnMove || (gBattleMons[gBattlerAttacker].status2 & STATUS2_MULTIPLETURNS)))
|| (IsMoveNotAllowedInSkyBattles(gCurrentMove)))
{
if (gBattleMoves[gCurrentMove].effect == EFFECT_FLING) // Edge case for removing a mon's item when there is no target available after using Fling.
gBattlescriptCurrInstr = BattleScript_FlingFailConsumeItem;
Expand Down Expand Up @@ -3595,7 +3601,11 @@ void SetMoveEffect(bool32 primary, u32 certain)
{
gBattleCommunication[MULTISTRING_CHOOSER] = B_MSG_SPIKESSCATTERED;
BattleScriptPush(gBattlescriptCurrInstr + 1);
gBattlescriptCurrInstr = BattleScript_SpikesActivates;

if (gBattleStruct->isSkyBattle)
gBattlescriptCurrInstr++;
else
gBattlescriptCurrInstr = BattleScript_SpikesActivates;
}
break;
case MOVE_EFFECT_TRIPLE_ARROWS:
Expand Down Expand Up @@ -4324,7 +4334,7 @@ static bool32 NoAliveMonsForPlayerAndPartner(void)
return (HP_count == 0);
}

static bool32 NoAliveMonsForPlayer(void)
bool32 NoAliveMonsForPlayer(void)
{
u32 i;
u32 HP_count = 0;
Expand Down
30 changes: 29 additions & 1 deletion src/battle_setup.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "global.h"
#include "battle.h"
#include "load_save.h"
#include "battle_setup.h"
#include "battle_transition.h"
#include "main.h"
Expand Down Expand Up @@ -81,6 +82,8 @@ static void TryUpdateGymLeaderRematchFromTrainer(void);
static void CB2_GiveStarter(void);
static void CB2_StartFirstBattle(void);
static void CB2_EndFirstBattle(void);
static void SaveChangesToPlayerParty(void);
static void HandleBattleVariantEndParty(void);
static void CB2_EndTrainerBattle(void);
static bool32 IsPlayerDefeated(u32 battleOutcome);
static u16 GetRematchTrainerId(u16 trainerId);
Expand Down Expand Up @@ -1380,15 +1383,40 @@ void BattleSetup_StartTrainerBattle_Debug(void)
ScriptContext_Stop();
}

static void SaveChangesToPlayerParty(void)
{
u8 i = 0, j = 0;
u8 participatedPokemon = VarGet(B_VAR_SKY_BATTLE);
for (i = 0; i < PARTY_SIZE; i++)
{
if ((participatedPokemon >> i & 1) == 1)
{
gSaveBlock1Ptr->playerParty[i] = gPlayerParty[j];
j++;
}
}
}

static void HandleBattleVariantEndParty(void)
{
if (B_FLAG_SKY_BATTLE == 0 || !FlagGet(B_FLAG_SKY_BATTLE))
return;
SaveChangesToPlayerParty();
LoadPlayerParty();
FlagClear(B_FLAG_SKY_BATTLE);
}

static void CB2_EndTrainerBattle(void)
{
HandleBattleVariantEndParty();

if (gTrainerBattleOpponent_A == TRAINER_SECRET_BASE)
{
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
}
else if (IsPlayerDefeated(gBattleOutcome) == TRUE)
{
if (InBattlePyramid() || InTrainerHillChallenge())
if (InBattlePyramid() || InTrainerHillChallenge() || (!NoAliveMonsForPlayer()))
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
else
SetMainCallback2(CB2_WhiteOut);
Expand Down
53 changes: 52 additions & 1 deletion src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -4095,7 +4095,7 @@ bool32 TryChangeBattleWeather(u32 battler, u32 weatherEnumId, bool32 viaAbility)

static bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag, u8 *timer)
{
if (!(gFieldStatuses & statusFlag))
if ((!(gFieldStatuses & statusFlag) && (!gBattleStruct->isSkyBattle)))
{
gFieldStatuses &= ~(STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_GRASSY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_PSYCHIC_TERRAIN);
gFieldStatuses |= statusFlag;
Expand Down Expand Up @@ -5756,6 +5756,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
break;
case ABILITY_TOXIC_DEBRIS:
if (!(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& (!gBattleStruct->isSkyBattle)
&& !gProtectStructs[gBattlerAttacker].confusionSelfDmg
&& IS_MOVE_PHYSICAL(gCurrentMove)
&& TARGET_TURN_DAMAGED
Expand Down Expand Up @@ -11267,6 +11268,56 @@ bool32 IsGen6ExpShareEnabled(void)
#endif
}

bool8 CanMonParticipateInSkyBattle(struct Pokemon *mon)
{
u16 species = GetMonData(mon, MON_DATA_SPECIES);
u16 monAbilityNum = GetMonData(mon, MON_DATA_ABILITY_NUM, NULL);

bool8 hasLevitateAbility = gSpeciesInfo[species].abilities[monAbilityNum] == ABILITY_LEVITATE;
bool8 isFlyingType = gSpeciesInfo[species].types[0] == TYPE_FLYING || gSpeciesInfo[species].types[1] == TYPE_FLYING;
bool8 monIsValidAndNotEgg = GetMonData(mon, MON_DATA_SANITY_HAS_SPECIES) && !GetMonData(mon, MON_DATA_IS_EGG);

if (monIsValidAndNotEgg)
{
if ((hasLevitateAbility || isFlyingType) && !IsMonBannedFromSkyBattles(species))
return TRUE;
}
return FALSE;
}

bool8 IsMonBannedFromSkyBattles(u16 species)
{
switch (species)
{
#if B_SKY_BATTLE_STRICT_ELIGIBILITY == TRUE
case SPECIES_SPEAROW:
case SPECIES_FARFETCHD:
case SPECIES_DODUO:
case SPECIES_DODRIO:
case SPECIES_HOOTHOOT:
case SPECIES_NATU:
case SPECIES_MURKROW:
case SPECIES_DELIBIRD:
case SPECIES_TAILLOW:
case SPECIES_STARLY:
case SPECIES_CHATOT:
case SPECIES_SHAYMIN:
case SPECIES_PIDOVE:
case SPECIES_ARCHEN:
case SPECIES_DUCKLETT:
case SPECIES_RUFFLET:
case SPECIES_VULLABY:
case SPECIES_FLETCHLING:
case SPECIES_HAWLUCHA:
case SPECIES_ROWLET:
case SPECIES_PIKIPEK:
#endif
case SPECIES_EGG:
return TRUE;
default:
return FALSE;
}
}

u8 GetBattlerType(u32 battler, u8 typeIndex)
{
Expand Down
4 changes: 4 additions & 0 deletions src/battle_util2.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ void AllocateBattleResources(void)

gBattleStruct = AllocZeroed(sizeof(*gBattleStruct));

#if B_FLAG_SKY_BATTLE
gBattleStruct->isSkyBattle = FlagGet(B_FLAG_SKY_BATTLE);
#endif

gBattleResources = AllocZeroed(sizeof(*gBattleResources));
gBattleResources->secretBase = AllocZeroed(sizeof(*gBattleResources->secretBase));
gBattleResources->flags = AllocZeroed(sizeof(*gBattleResources->flags));
Expand Down
Loading

0 comments on commit 493478e

Please sign in to comment.