Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Master to upcoming, 2024-11-29 #5735

Merged
merged 16 commits into from
Nov 29, 2024
Merged
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -6,12 +6,16 @@

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.

## Using pokeemerald-expansion

If you use pokeemerald-expansion in your hack, please add RHH (Rom Hacking Hideout) to your credits list. Optionally, you can list the version used, so it can help players know what features to expect.
You can phrase it as the following:
```
Based off RHH's pokeemerald-expansion 1.9.3 https://github.com/rh-hideout/pokeemerald-expansion/
```

Please follow the instructions in `INSTALL.md` to get pokeemerald-expansion set up on your machine.

## What features are included?
- ***IMPORTANT*❗❗ Read through these to learn what features you can toggle**:
- [Battle configurations](https://github.com/rh-hideout/pokeemerald-expansion/blob/master/include/config/battle.h)
4 changes: 2 additions & 2 deletions data/battle_anim_scripts.s
Original file line number Diff line number Diff line change
@@ -10093,14 +10093,14 @@ gBattleAnimMove_FloralHealing::
loadspritegfx ANIM_TAG_ORBS @circles
loadspritegfx ANIM_TAG_PINK_PETAL @pink particles
monbg ANIM_ATTACKER
monbg ANIM_TARGET
playsewithpan SE_M_DETECT, SOUND_PAN_ATTACKER
call CIRCLES_LEAVES
call CIRCLES_LEAVES
waitforvisualfinish
panse SE_M_COMET_PUNCH, SOUND_PAN_ATTACKER, SOUND_PAN_TARGET, 0x2, 0x0
playsewithpan SE_M_TWISTER, 0x0
createsprite gSweetScentPetalSpriteTemplate, ANIM_ATTACKER, 2, 0x46, 0x1, 0x40
clearmonbg ANIM_ATTACKER
delay 0x2
createsprite gFloralHealingWindLeavesTemplate, ANIM_ATTACKER, 2, 0x3c, 0x0, 0x40
delay 0x2
@@ -10123,6 +10123,7 @@ gBattleAnimMove_FloralHealing::
createsprite gSweetScentPetalSpriteTemplate, ANIM_ATTACKER, 2, 0x55, 0x0, 0x78
delay 0x2
loopsewithpan SE_M_POISON_POWDER, SOUND_PAN_TARGET, 0x12, 0xa
monbg ANIM_TARGET
call FloralHealingSpores
call FloralHealingSpores
call FloralHealingSpores
@@ -10133,7 +10134,6 @@ gBattleAnimMove_FloralHealing::
createsprite gGrantingStarsSpriteTemplate, ANIM_ATTACKER, 16, 0xc, 0xfffb, 0x1, 0x0, 0x20, 0x3c, 0x1
waitforvisualfinish
clearmonbg ANIM_TARGET
clearmonbg ANIM_ATTACKER
end
FloralHealingSpores:
createsprite gFloralHealingFlowerTemplate, ANIM_ATTACKER, 2, 0x0, 0xffec, 0x55, 0x50, 0x0
7 changes: 4 additions & 3 deletions data/battle_scripts_1.s
Original file line number Diff line number Diff line change
@@ -2401,7 +2401,6 @@ BattleScript_EffectHealingWish::
storehealingwish BS_ATTACKER
.if B_HEALING_WISH_SWITCH <= GEN_4
openpartyscreen BS_ATTACKER, BattleScript_EffectHealingWishEnd
switchoutabilities BS_ATTACKER
waitstate
switchhandleorder BS_ATTACKER, 2
returnatktoball
@@ -5755,7 +5754,6 @@ BattleScript_PrintFullBox::

BattleScript_ActionSwitch::
hpthresholds2 BS_ATTACKER
saveattacker
printstring STRINGID_RETURNMON
jumpifbattletype BATTLE_TYPE_DOUBLE, BattleScript_PursuitSwitchDmgSetMultihit
setmultihit 1
@@ -5773,7 +5771,6 @@ BattleScript_DoSwitchOut::
switchoutabilities BS_ATTACKER
updatedynamax
waitstate
restoreattacker
returnatktoball
waitstate
drawpartystatussummary BS_ATTACKER
@@ -9633,7 +9630,9 @@ BattleScript_EjectButtonActivates::
removeitem BS_SCRIPTING
makeinvisible BS_SCRIPTING
openpartyscreen BS_SCRIPTING, BattleScript_EjectButtonEnd
copybyte sSAVED_BATTLER, sBATTLER
switchoutabilities BS_SCRIPTING
copybyte sBATTLER, sSAVED_BATTLER
waitstate
switchhandleorder BS_SCRIPTING 0x2
returntoball BS_SCRIPTING, FALSE
@@ -9730,6 +9729,7 @@ BattleScript_PastelVeilEnd:
end3

BattleScript_NeutralizingGasExits::
saveattacker
savetarget
pause B_WAIT_TIME_SHORT
printstring STRINGID_NEUTRALIZINGGASOVER
@@ -9739,6 +9739,7 @@ BattleScript_NeutralizingGasExitsLoop:
switchinabilities BS_TARGET
addbyte gBattlerTarget, 1
jumpifbytenotequal gBattlerTarget, gBattlersCount, BattleScript_NeutralizingGasExitsLoop
restoreattacker
restoretarget
return

Binary file modified graphics/pokemon/farfetchd/overworld.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified graphics/pokemon/melmetal/overworld.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions graphics/pokemon/melmetal/overworld_normal.pal
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
JASC-PAL
0100
16
255 255 255
120 255 255
254 235 185
220 220 218
235 192 100
@@ -16,4 +16,4 @@ JASC-PAL
64 64 64
45 43 43
8 8 8
0 0 0
255 255 255
2 changes: 1 addition & 1 deletion graphics/pokemon/melmetal/overworld_shiny.pal
Original file line number Diff line number Diff line change
@@ -16,4 +16,4 @@ JASC-PAL
64 64 64
45 43 43
8 8 8
0 0 0
255 255 255
Binary file modified graphics/pokemon/patrat/overworld.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified graphics/pokemon/woobat/overworld.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion include/constants/battle_script_commands.h
Original file line number Diff line number Diff line change
@@ -289,9 +289,9 @@ enum MoveEndEffects
MOVEEND_RECOIL,
MOVEEND_ITEM_EFFECTS_ATTACKER,
MOVEEND_MAGICIAN, // Occurs after final multi-hit strike, and after other items/abilities would activate
MOVEEND_RED_CARD, // Red Card triggers before Eject Pack
MOVEEND_EJECT_ITEMS,
MOVEEND_WHITE_HERB,
MOVEEND_RED_CARD,
MOVEEND_LIFEORB_SHELLBELL, // Includes shell bell, throat spray, etc
MOVEEND_CHANGED_ITEMS,
MOVEEND_PICKPOCKET,
4 changes: 4 additions & 0 deletions include/constants/form_change_types.h
Original file line number Diff line number Diff line change
@@ -134,4 +134,8 @@
// param1: amount of days
#define FORM_CHANGE_DAYS_PASSED 23

// Form change for Aegislash
#define FORM_CHANGE_BATTLE_ATTACK 24
#define FORM_CHANGE_BATTLE_KINGS_SHIELD 25

#endif // GUARD_CONSTANTS_FORM_CHANGE_TYPES_H
26 changes: 20 additions & 6 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
@@ -1125,7 +1125,6 @@ static bool32 NoTargetPresent(u8 battler, u32 move)
return FALSE;
}

// TODO: Convert this to a proper FORM_CHANGE type.
static bool32 TryAegiFormChange(void)
{
// Only Aegislash with Stance Change can transform, transformed mons cannot.
@@ -1140,12 +1139,12 @@ static bool32 TryAegiFormChange(void)
case SPECIES_AEGISLASH_SHIELD: // Shield -> Blade
if (IS_MOVE_STATUS(gCurrentMove))
return FALSE;
gBattleMons[gBattlerAttacker].species = SPECIES_AEGISLASH_BLADE;
TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_ATTACK);
break;
case SPECIES_AEGISLASH_BLADE: // Blade -> Shield
if (gCurrentMove != MOVE_KINGS_SHIELD)
return FALSE;
gBattleMons[gBattlerAttacker].species = SPECIES_AEGISLASH_SHIELD;
TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_KINGS_SHIELD);
break;
}

@@ -1782,8 +1781,6 @@ static void AccuracyCheck(bool32 recalcDragonDarts, const u8 *nextInstr, const u
if (!RandomPercentage(RNG_ACCURACY, accuracy))
{
gMoveResultFlags |= MOVE_RESULT_MISSED;
if (holdEffectAtk == HOLD_EFFECT_BLUNDER_POLICY)
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks

if (gMovesInfo[gCurrentMove].effect == EFFECT_DRAGON_DARTS
&& !recalcDragonDarts // So we don't jump back and forth between targets
@@ -2266,6 +2263,7 @@ static void Cmd_adjustdamage(void)
}
if (gSpecialStatuses[gBattlerAttacker].gemBoost
&& !(gMoveResultFlags & MOVE_RESULT_NO_EFFECT)
&& !(gHitMarker & HITMARKER_UNABLE_TO_USE_MOVE)
&& gBattleMons[gBattlerAttacker].item
&& gMovesInfo[gCurrentMove].effect != EFFECT_PLEDGE
&& gCurrentMove != MOVE_STRUGGLE)
@@ -2678,6 +2676,13 @@ static void Cmd_resultmessage(void)
return;
}

if (gMoveResultFlags & MOVE_RESULT_MISSED && !(gMoveResultFlags & (MOVE_RESULT_DOESNT_AFFECT_FOE | MOVE_RESULT_FAILED)))
{
if (GetBattlerHoldEffect(gBattlerAttacker, TRUE) == HOLD_EFFECT_BLUNDER_POLICY
&& !IsBattlerProtected(gBattlerAttacker, gBattlerTarget, gCurrentMove))
gBattleStruct->blunderPolicy = TRUE; // Only activates from missing through acc/evasion checks
}

if (gMoveResultFlags & MOVE_RESULT_MISSED && (!(gMoveResultFlags & MOVE_RESULT_DOESNT_AFFECT_FOE) || gBattleCommunication[MISS_TYPE] > B_MSG_AVOIDED_ATK))
{
if (gBattleCommunication[MISS_TYPE] > B_MSG_AVOIDED_ATK) // Wonder Guard or Levitate - show the ability pop-up
@@ -4157,6 +4162,15 @@ static void Cmd_tryfaintmon(void)
}
else
{
if (gBattleMons[battler].ability == ABILITY_NEUTRALIZING_GAS
&& !(gAbsentBattlerFlags & (1u << battler))
&& !IsBattlerAlive(battler))
{
gBattleMons[battler].ability = ABILITY_NONE;
BattleScriptPush(gBattlescriptCurrInstr);
gBattlescriptCurrInstr = BattleScript_NeutralizingGasExits;
return;
}
if (cmd->battler == BS_ATTACKER)
{
destinyBondBattler = gBattlerTarget;
@@ -14788,7 +14802,7 @@ static void Cmd_switchoutabilities(void)
MarkBattlerForControllerExec(battler);
break;
case ABILITY_REGENERATOR:
gBattleMoveDamage = GetNonDynamaxMaxHP(gBattlerAttacker) / 3;
gBattleMoveDamage = GetNonDynamaxMaxHP(battler) / 3;
gBattleMoveDamage += gBattleMons[battler].hp;
if (gBattleMoveDamage > gBattleMons[battler].maxHP)
gBattleMoveDamage = gBattleMons[battler].maxHP;
8 changes: 6 additions & 2 deletions src/battle_util.c
Original file line number Diff line number Diff line change
@@ -6889,7 +6889,7 @@ static u8 TrySetEnigmaBerry(u32 battler)
{
if (IsBattlerAlive(battler)
&& !DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
&& ((TARGET_TURN_DAMAGED && gMoveResultFlags & MOVE_RESULT_SUPER_EFFECTIVE) || gBattleScripting.overrideBerryRequirements)
&& ((BATTLER_TURN_DAMAGED(battler) && gMoveResultFlags & MOVE_RESULT_SUPER_EFFECTIVE) || gBattleScripting.overrideBerryRequirements)
&& !(gBattleScripting.overrideBerryRequirements && gBattleMons[battler].hp == gBattleMons[battler].maxHP)
&& (B_HEAL_BLOCKING < GEN_5 || !(gStatuses3[battler] & STATUS3_HEAL_BLOCK)))
{
@@ -6913,7 +6913,7 @@ static u8 DamagedStatBoostBerryEffect(u32 battler, u8 statId, u8 category)
|| (!DoesSubstituteBlockMove(gBattlerAttacker, battler, gCurrentMove)
&& GetBattleMoveCategory(gCurrentMove) == category
&& battler != gBattlerAttacker
&& TARGET_TURN_DAMAGED))
&& BATTLER_TURN_DAMAGED(battler)))
)
{
BufferStatChange(battler, statId, STRINGID_STATROSE);
@@ -10936,6 +10936,10 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method)
if (GetBattlerTeraType(battler) == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_ATTACK:
case FORM_CHANGE_BATTLE_KINGS_SHIELD:
targetSpecies = formChanges[i].targetSpecies;
break;
}
}
}
5 changes: 3 additions & 2 deletions src/data/moves_info.h
Original file line number Diff line number Diff line change
@@ -12217,7 +12217,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
{
.name = COMPOUND_STRING("Coil"),
.description = COMPOUND_STRING(
"Coils up to raise Attack\n"
"Coils up to raise Attack,\n"
"Defense and Accuracy."),
.effect = EFFECT_COIL,
.power = 0,
@@ -17335,7 +17335,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.name = COMPOUND_STRING("Octolock"),
.description = COMPOUND_STRING(
"Traps the foe to lower Def\n"
"and Sp. Def fall each turn."),
"and Sp. Def each turn."),
.effect = EFFECT_OCTOLOCK,
.power = 0,
.type = TYPE_FIGHTING,
@@ -20610,6 +20610,7 @@ const struct MoveInfo gMovesInfo[MOVES_COUNT_DYNAMAX] =
.priority = 0,
.category = DAMAGE_CATEGORY_PHYSICAL,
.makesContact = TRUE,
.minimizeDoubleDamage = TRUE,
.battleAnimScript = gBattleAnimMove_SupercellSlam,
},

8 changes: 5 additions & 3 deletions src/data/pokemon/form_change_tables.h
Original file line number Diff line number Diff line change
@@ -789,9 +789,11 @@ static const struct FormChange sFurfrouFormChangeTable[] = {

#if P_FAMILY_HONEDGE
static const struct FormChange sAegislashFormChangeTable[] = {
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_FAINT, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_END_BATTLE, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_BATTLE_ATTACK, SPECIES_AEGISLASH_BLADE},
{FORM_CHANGE_BATTLE_KINGS_SHIELD, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_FAINT, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_END_BATTLE, SPECIES_AEGISLASH_SHIELD},
{FORM_CHANGE_TERMINATOR},
};
#endif //P_FAMILY_HONEDGE
2 changes: 1 addition & 1 deletion test/battle/ability/dauntless_shield.c
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@

ASSUMPTIONS
{
ASSUME(B_PROTEAN_LIBERO == GEN_9);
ASSUME(B_DAUNTLESS_SHIELD == GEN_9);
}

SINGLE_BATTLE_TEST("Dauntless Shield raises Defense by one stage")
90 changes: 89 additions & 1 deletion test/battle/ability/intimidate.c
Original file line number Diff line number Diff line change
@@ -246,7 +246,7 @@ DOUBLE_BATTLE_TEST("Intimidate is not going to trigger if a mon switches out thr
}
}

SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutralizing Gas")
SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutralizing Gas - switching out")
{
GIVEN {
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
@@ -263,3 +263,91 @@ SINGLE_BATTLE_TEST("Intimidate activates when it's no longer effected by Neutral
SEND_IN_MESSAGE("Wobbuffet");
}
}

SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - switching moves")
{
u32 move;
PARAMETRIZE { move = MOVE_U_TURN; }
PARAMETRIZE { move = MOVE_HEALING_WISH; }
PARAMETRIZE { move = MOVE_BATON_PASS; }
GIVEN {
ASSUME(gMovesInfo[MOVE_U_TURN].effect == EFFECT_HIT_ESCAPE);
ASSUME(gMovesInfo[MOVE_HEALING_WISH].effect == EFFECT_HEALING_WISH);
ASSUME(gMovesInfo[MOVE_BATON_PASS].effect == EFFECT_BATON_PASS);
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); }
PLAYER(SPECIES_WOBBUFFET) { HP(1); }
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
} WHEN {
TURN { MOVE(player, move); SEND_OUT(player, 1); }
} SCENE {
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
MESSAGE("Neutralizing Gas filled the area!");
ANIMATION(ANIM_TYPE_MOVE, move, player);
MESSAGE("The effects of Neutralizing Gas wore off!");
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
SEND_IN_MESSAGE("Wobbuffet");
} THEN {
if (move == MOVE_HEALING_WISH)
EXPECT_EQ(player->hp, player->maxHP);
}
}

SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - opponent caused switches")
{
u32 move, item;
PARAMETRIZE { move = MOVE_TACKLE; item = ITEM_EJECT_BUTTON; }
PARAMETRIZE { move = MOVE_GROWL; item = ITEM_EJECT_PACK; }
PARAMETRIZE { move = MOVE_ROAR; item = ITEM_NONE; }
PARAMETRIZE { move = MOVE_DRAGON_TAIL; item = ITEM_NONE; }
GIVEN {
ASSUME(gItemsInfo[ITEM_EJECT_BUTTON].holdEffect == HOLD_EFFECT_EJECT_BUTTON);
ASSUME(gItemsInfo[ITEM_EJECT_PACK].holdEffect == HOLD_EFFECT_EJECT_PACK);
ASSUME(gMovesInfo[MOVE_GROWL].effect == EFFECT_ATTACK_DOWN);
ASSUME(gMovesInfo[MOVE_ROAR].effect == EFFECT_ROAR);
ASSUME(gMovesInfo[MOVE_DRAGON_TAIL].effect == EFFECT_HIT_SWITCH_TARGET);
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); Item(item); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
} WHEN {
if (item != ITEM_NONE) {
TURN { MOVE(opponent, move); SEND_OUT(player, 1); }
} else {
TURN { MOVE(opponent, move); }
}
} SCENE {
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
MESSAGE("Neutralizing Gas filled the area!");
ANIMATION(ANIM_TYPE_MOVE, move, opponent);
if (item != ITEM_NONE)
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_HELD_ITEM_EFFECT, player);
MESSAGE("The effects of Neutralizing Gas wore off!");
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
if (item != ITEM_NONE) {
SEND_IN_MESSAGE("Wobbuffet");
} else {
MESSAGE("Wobbuffet was dragged out!");
}
}
}

SINGLE_BATTLE_TEST("Intimidate activates when it's no longer affected by Neutralizing Gas - fainted")
{
GIVEN {
ASSUME(gMovesInfo[MOVE_FELL_STINGER].effect == EFFECT_FELL_STINGER);
PLAYER(SPECIES_WEEZING) { Ability(ABILITY_NEUTRALIZING_GAS); HP(1); }
PLAYER(SPECIES_WOBBUFFET);
OPPONENT(SPECIES_ARBOK) { Ability(ABILITY_INTIMIDATE); }
} WHEN {
TURN { MOVE(opponent, MOVE_FELL_STINGER); SEND_OUT(player, 1); }
} SCENE {
ABILITY_POPUP(player, ABILITY_NEUTRALIZING_GAS);
MESSAGE("Neutralizing Gas filled the area!");
ANIMATION(ANIM_TYPE_MOVE, MOVE_FELL_STINGER, opponent);
MESSAGE("The effects of Neutralizing Gas wore off!");
ABILITY_POPUP(opponent, ABILITY_INTIMIDATE);
MESSAGE("Weezing fainted!");
ANIMATION(ANIM_TYPE_GENERAL, B_ANIM_STATS_CHANGE, opponent);
SEND_IN_MESSAGE("Wobbuffet");
}
}

Loading