Merge branch 'RHH/master' into RHH/upcoming

# Conflicts:
#	include/battle.h
This commit is contained in:
Eduardo Quezada 2023-11-25 00:51:33 -03:00
commit c8b0545d20
7 changed files with 155 additions and 14 deletions

View file

@ -2,10 +2,10 @@
## What is the pokeemerald Expansion?
The pokeemerald Expansion is a feature branch meant to be integrated into existing Pokémon Emerald hacks based off pret's [pokeemerald](https://github.com/pret/pokeemerald) decompilation project. This is ***NOT*** a standalone romhack, and as such, most features will be unavailable and/or unbalanced if played as is.
The pokeemerald Expansion is a decomp hack base project based off pret's [pokeemerald](https://github.com/pret/pokeemerald) decompilation project. It's recommended that any new projects that plan on using it, to clone this repository instead of pret's vanilla repository, as we regurlarly incorporate pret's documentation changes. This is ***NOT*** a standalone romhack, and as such, most features will be unavailable and/or unbalanced if played as is.
## What features are included?
- Configuration files that allows you to choose generation-specific behaviors. Full contents here:
- ***IMPORTANT*❗❗ Read through these to learn what features you can toggle**:
- [Battle configurations](/include/config/battle.h)
- [Pokémon configurations](/include/config/pokemon.h)
- [Item configurations](/include/config/item.h)

View file

@ -713,6 +713,7 @@ BattleScript_EffectAttackUpUserAlly_TryAlly:
BattleScript_EffectAttackUpUserAlly_End:
goto BattleScript_MoveEnd
BattleScript_EffectAttackUpUserAlly_TryAlly_:
jumpifability BS_ATTACKER_PARTNER, ABILITY_SOUNDPROOF, BattleScript_EffectAttackUpUserAlly_TryAllyBlocked
setstatchanger STAT_ATK, 1, FALSE
statbuffchange STAT_CHANGE_ALLOW_PTR, BattleScript_EffectAttackUpUserAlly_End
jumpifbyte CMP_NOT_EQUAL, cMULTISTRING_CHOOSER, B_MSG_STAT_WONT_INCREASE, BattleScript_EffectAttackUpUserAlly_AllyAnim
@ -727,6 +728,13 @@ BattleScript_EffectAttackUpUserAlly_AllyAnim:
waitmessage B_WAIT_TIME_LONG
goto BattleScript_EffectAttackUpUserAlly_End
BattleScript_EffectAttackUpUserAlly_TryAllyBlocked:
copybyte sBATTLER, gBattlerTarget
call BattleScript_AbilityPopUpTarget
printstring STRINGID_PKMNSXBLOCKSY2
waitmessage B_WAIT_TIME_LONG
goto BattleScript_MoveEnd
BattleScript_EffectTeatime::
attackcanceler
attackstring

View file

@ -108,6 +108,8 @@ struct DisableStruct
u8 syrupBombTimer;
u8 syrupBombIsShiny:1;
u8 steelSurgeDone:1;
u8 weatherAbilityDone:1;
u8 terrainAbilityDone:1;
};
struct ProtectStruct
@ -199,8 +201,6 @@ struct SpecialStatus
u8 dancerUsedMove:1;
u8 dancerOriginalTarget:3;
// End of byte
u8 weatherAbilityDone:1;
u8 terrainAbilityDone:1;
u8 emergencyExited:1;
u8 afterYou:1;
};

View file

@ -1884,12 +1884,13 @@ u32 GetBattlerAffectionHearts(u32 battler)
return GetMonAffectionHearts(&party[gBattlerPartyIndexes[battler]]);
}
static void TryToRevertMimicry(void)
static void TryToRevertMimicryAndFlags(void)
{
u32 i;
for (i = 0; i < gBattlersCount; i++)
{
gDisableStructs[i].terrainAbilityDone = FALSE;
if (GetBattlerAbility(i) == ABILITY_MIMICRY)
RESTORE_BATTLER_TYPE(i);
}
@ -1942,7 +1943,7 @@ static bool32 EndTurnTerrain(u32 terrainFlag, u32 stringTableId)
if (!(gFieldStatuses & STATUS_FIELD_TERRAIN_PERMANENT) && --gFieldTimers.terrainTimer == 0)
{
gFieldStatuses &= ~terrainFlag;
TryToRevertMimicry();
TryToRevertMimicryAndFlags();
gBattleCommunication[MULTISTRING_CHOOSER] = stringTableId;
BattleScriptExecute(BattleScript_TerrainEnds);
return TRUE;
@ -2242,6 +2243,8 @@ u8 DoFieldEndTurnEffects(void)
&& --gWishFutureKnock.weatherDuration == 0)
{
gBattleWeather &= ~B_WEATHER_SUN_TEMPORARY;
for (i = 0; i < gBattlersCount; i++)
gDisableStructs[i].weatherAbilityDone = FALSE;
gBattlescriptCurrInstr = BattleScript_SunlightFaded;
}
else
@ -4096,6 +4099,7 @@ static bool32 TryChangeBattleTerrain(u32 battler, u32 statusFlag, u8 *timer)
{
gFieldStatuses &= ~(STATUS_FIELD_MISTY_TERRAIN | STATUS_FIELD_GRASSY_TERRAIN | STATUS_FIELD_ELECTRIC_TERRAIN | STATUS_FIELD_PSYCHIC_TERRAIN);
gFieldStatuses |= statusFlag;
gDisableStructs[battler].terrainAbilityDone = FALSE;
if (GetBattlerHoldEffect(battler, TRUE) == HOLD_EFFECT_TERRAIN_EXTENDER)
*timer = 8;
@ -6122,10 +6126,11 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITY_PROTOSYNTHESIS:
if (!gSpecialStatuses[battler].weatherAbilityDone && IsBattlerWeatherAffected(battler, B_WEATHER_SUN))
if (!gDisableStructs[battler].weatherAbilityDone && IsBattlerWeatherAffected(battler, B_WEATHER_SUN))
{
gSpecialStatuses[battler].weatherAbilityDone = TRUE;
gDisableStructs[battler].weatherAbilityDone = TRUE;
PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler));
gBattlerAbility = gBattleScripting.battler = battler;
BattleScriptPushCursorAndCallback(BattleScript_ProtosynthesisActivates);
effect++;
}
@ -6137,9 +6142,9 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
switch (gLastUsedAbility)
{
case ABILITY_MIMICRY:
if (!gSpecialStatuses[battler].terrainAbilityDone && ChangeTypeBasedOnTerrain(battler))
if (!gDisableStructs[battler].terrainAbilityDone && ChangeTypeBasedOnTerrain(battler))
{
gSpecialStatuses[battler].terrainAbilityDone = TRUE;
gDisableStructs[battler].terrainAbilityDone = TRUE;
ChangeTypeBasedOnTerrain(battler);
gBattlerAbility = gBattleScripting.battler = battler;
BattleScriptPushCursorAndCallback(BattleScript_MimicryActivates_End3);
@ -6147,11 +6152,11 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
}
break;
case ABILITY_QUARK_DRIVE:
if (!gSpecialStatuses[battler].terrainAbilityDone && IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN))
if (!gDisableStructs[battler].terrainAbilityDone && IsBattlerTerrainAffected(battler, STATUS_FIELD_ELECTRIC_TERRAIN))
{
gSpecialStatuses[battler].terrainAbilityDone = TRUE;
gBattlerAbility = gBattleScripting.battler = battler;
gDisableStructs[battler].terrainAbilityDone = TRUE;
PREPARE_STAT_BUFFER(gBattleTextBuff1, GetHighestStatId(battler));
gBattlerAbility = gBattleScripting.battler = battler;
BattleScriptPushCursorAndCallback(BattleScript_QuarkDriveActivates);
effect++;
}
@ -6160,7 +6165,7 @@ u32 AbilityBattleEffects(u32 caseID, u32 battler, u32 ability, u32 special, u32
break;
}
if (effect && gLastUsedAbility != 0xFF)
if (effect && gLastUsedAbility != 0xFFFF)
RecordAbilityBattle(battler, gLastUsedAbility);
if (effect && caseID <= ABILITYEFFECT_MOVE_END)
gBattlerAbility = battler;

View file

@ -85,3 +85,50 @@ SINGLE_BATTLE_TEST("Protosynthesis either boosts Defense or Special Defense, not
EXPECT_EQ(damage[0], damage[1]);
}
}
SINGLE_BATTLE_TEST("Protosynthesis ability pop up activates only once during the duration of sunny day")
{
u16 turns;
GIVEN {
PLAYER(SPECIES_BELLSPROUT) { Ability(ABILITY_PROTOSYNTHESIS); }
OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); };
} WHEN {
for (turns = 0; turns < 5; turns++)
TURN {}
TURN { MOVE(opponent, MOVE_SUNNY_DAY); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("The harsh sunlight activated Bellsprout's Protosynthesis!");
MESSAGE("Bellsprout's Attack was heightened!");
NONE_OF {
for (turns = 0; turns < 4; turns++) {
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("The harsh sunlight activated Bellsprout's Protosynthesis!");
MESSAGE("Bellsprout's Attack was heightened!");
}
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_SUNNY_DAY, opponent);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("The harsh sunlight activated Bellsprout's Protosynthesis!");
MESSAGE("Bellsprout's Attack was heightened!");
}
}
SINGLE_BATTLE_TEST("Protosynthesis activates on switch-in")
{
KNOWN_FAILING; // Fails because of wrong species
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_BELLSPROUT) { Ability(ABILITY_PROTOSYNTHESIS); }
OPPONENT(SPECIES_NINETALES) { Ability(ABILITY_DROUGHT); };
} WHEN {
TURN { SWITCH(player, 1); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_DROUGHT);
ABILITY_POPUP(player, ABILITY_PROTOSYNTHESIS);
MESSAGE("The harsh sunlight activated Bellsprout's Protosynthesis!");
MESSAGE("Bellsprout's Attack was heightened!");
}
}

View file

@ -85,3 +85,51 @@ SINGLE_BATTLE_TEST("Quark Drive either boosts Defense or Special Defense, not bo
EXPECT_EQ(damage[0], damage[1]);
}
}
SINGLE_BATTLE_TEST("Quark Drive ability pop up activates only once during the duration of electric terrain")
{
u16 turns;
GIVEN {
PLAYER(SPECIES_BELLSPROUT) { Ability(ABILITY_QUARK_DRIVE); }
OPPONENT(SPECIES_WOBBUFFET);
} WHEN {
TURN { MOVE(opponent, MOVE_ELECTRIC_TERRAIN); }
for (turns = 0; turns < 4; turns++)
TURN {}
TURN { MOVE(opponent, MOVE_ELECTRIC_TERRAIN); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, opponent);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("The Electric Terrain activated Bellsprout's Quark Drive!");
MESSAGE("Bellsprout's Attack was heightened!");
NONE_OF {
for (turns = 0; turns < 4; turns++) {
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("The Electric Terrain activated Bellsprout's Quark Drive!");
MESSAGE("Bellsprout's Attack was heightened!");
}
}
ANIMATION(ANIM_TYPE_MOVE, MOVE_ELECTRIC_TERRAIN, opponent);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("The Electric Terrain activated Bellsprout's Quark Drive!");
MESSAGE("Bellsprout's Attack was heightened!");
}
}
SINGLE_BATTLE_TEST("Quark Drive activates on switch-in")
{
KNOWN_FAILING; // Fails because of wrong species
GIVEN {
PLAYER(SPECIES_WOBBUFFET);
PLAYER(SPECIES_BELLSPROUT) { Ability(ABILITY_QUARK_DRIVE); }
OPPONENT(SPECIES_TAPU_KOKO) { Ability(ABILITY_ELECTRIC_SURGE); };
} WHEN {
TURN { SWITCH(player, 1); }
} SCENE {
ABILITY_POPUP(opponent, ABILITY_ELECTRIC_SURGE);
ABILITY_POPUP(player, ABILITY_QUARK_DRIVE);
MESSAGE("The Electric Terrain activated Bellsprout's Quark Drive!");
MESSAGE("Bellsprout's Attack was heightened!");
}
}

View file

@ -63,3 +63,36 @@ DOUBLE_BATTLE_TEST("Howl raises user's and partner's Attack", s16 damageLeft, s1
EXPECT_MUL_EQ(results[0].damageRight, Q_4_12(1.5), results[1].damageRight);
}
}
DOUBLE_BATTLE_TEST("Howl does not work on partner if it has Soundproof")
{
s16 damage[2];
GIVEN {
ASSUME(gBattleMoves[MOVE_TACKLE].split == SPLIT_PHYSICAL);
PLAYER(SPECIES_WOBBUFFET) { Speed(15); }
PLAYER(SPECIES_VOLTORB) { Speed(10); Ability(ABILITY_SOUNDPROOF); }
OPPONENT(SPECIES_WOBBUFFET) { Speed(5); }
OPPONENT(SPECIES_WYNAUT) { Speed(1); }
} WHEN {
TURN { MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); }
TURN { MOVE(playerLeft, MOVE_HOWL); MOVE(playerRight, MOVE_TACKLE, target: opponentLeft); }
} SCENE {
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight);
HP_BAR(opponentLeft, captureDamage: &damage[0]);
ANIMATION(ANIM_TYPE_MOVE, MOVE_HOWL, playerLeft);
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerLeft);
MESSAGE("Wobbuffet's Attack rose!");
NONE_OF {
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, playerRight);
MESSAGE("Wynaut's Attack rose!");
}
ABILITY_POPUP(playerRight, ABILITY_SOUNDPROOF);
MESSAGE("Voltorb's Soundproof blocks Howl!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_TACKLE, playerRight);
HP_BAR(opponentLeft, captureDamage: &damage[1]);
} THEN {
EXPECT_EQ(damage[0], damage[1]);
}
}