Skip to content

Commit

Permalink
Dynamic Move Types in Summary Screen/Battle (#5084)
Browse files Browse the repository at this point in the history
* Dynamic Hidden Power Types

* Dynamic Ivy Cudgel is summary screens

* Dynamic Move types

* missed unnecessary comment that got left in

* format cleanup, return cleanup, added Tera Blast and Tera Starstorm, Revelation dance fix-> now displays live type update when tera is selected during battle before move selection

* forgot to revert config defaults

* Update src/pokemon.c

Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com>

* if block spaces/ raging bull fix/ more condensing on checks/ reallocating config check/ tera blast fix (was displaying tera blast type on non tera'd mons in party when battler was tera'd)

* revert configs

* added Hail check to Weather Ball

* Fixed agbcc compile/brackets/u32 changes

* Quick fix to ensure Judgment/Techno Blast/Natural Gift are not affected by -ate abilities

* Update src/pokemon_summary_screen.c

---------

Co-authored-by: Alex <93446519+AlexOn1ine@users.noreply.github.com>
  • Loading branch information
Galaxeeh and AlexOn1ine authored Aug 8, 2024
1 parent 89cba94 commit 355739d
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 7 deletions.
1 change: 1 addition & 0 deletions include/battle_ai_switch_items.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ void GetAIPartyIndexes(u32 battlerId, s32 *firstId, s32 *lastId);
void AI_TrySwitchOrUseItem(u32 battler);
u32 GetMostSuitableMonToSwitchInto(u32 battler, bool32 switchAfterMonKOd);
bool32 ShouldSwitch(u32 battler, bool32 emitResult);
bool32 IsMonGrounded(u16 heldItemEffect, u32 ability, u8 type1, u8 type2);

#endif // GUARD_BATTLE_AI_SWITCH_ITEMS_H
1 change: 1 addition & 0 deletions include/config/pokemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#define P_TWO_FRAME_FRONT_SPRITES TRUE // In Pokémon Emerald, Pokémon front sprites always consist of two frames. This config can revert it to only use the first frame, as is the case in the other Gen 3 games.
#define P_ONLY_OBTAINABLE_SHINIES FALSE // If TRUE, Pokémon encountered in the Battle Pyramid won't be shiny.
#define P_NO_SHINIES_WITHOUT_POKEBALLS FALSE // If TRUE, Pokémon encountered when the player is out of Poké Balls won't be shiny
#define P_SHOW_DYNAMIC_TYPES FALSE // If TRUE, moves with dynamic type changes will be reflected as their current type in battle/summary screens.

// Learnset helper toggles
#define P_LEARNSET_HELPER_TEACHABLE TRUE // If TRUE, teachable_learnsets.h will be populated by tools/learnset_helpers/teachable.py using the included JSON files based on available TMs and tutors.
Expand Down
2 changes: 2 additions & 0 deletions include/pokemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -882,5 +882,7 @@ const u8 *GetMoveName(u16 moveId);
const u8 *GetMoveAnimationScript(u16 moveId);
void UpdateDaysPassedSinceFormChange(u16 days);
void TrySetDayLimitToFormChange(struct Pokemon *mon);
u8 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler);
u8 CalculateHiddenPowerType(struct Pokemon *mon);

#endif // GUARD_POKEMON_H
2 changes: 1 addition & 1 deletion src/battle_ai_switch_items.c
Original file line number Diff line number Diff line change
Expand Up @@ -1318,7 +1318,7 @@ static u32 GetBestMonDmg(struct Pokemon *party, int firstId, int lastId, u8 inva
return bestMonId;
}

static bool32 IsMonGrounded(u16 heldItemEffect, u32 ability, u8 type1, u8 type2)
bool32 IsMonGrounded(u16 heldItemEffect, u32 ability, u8 type1, u8 type2)
{
// List that makes mon not grounded
if (type1 == TYPE_FLYING || type2 == TYPE_FLYING || ability == ABILITY_LEVITATE
Expand Down
17 changes: 14 additions & 3 deletions src/battle_controller_player.c
Original file line number Diff line number Diff line change
Expand Up @@ -1716,15 +1716,14 @@ static void MoveSelectionDisplayMoveType(u32 battler)
u8 type;
u32 speciesId;
struct ChooseMoveStruct *moveInfo = (struct ChooseMoveStruct *)(&gBattleResources->bufferA[battler][4]);

txtPtr = StringCopy(gDisplayedStringBattle, gText_MoveInterfaceType);

type = gMovesInfo[moveInfo->moves[gMoveSelectionCursor[battler]]].type;

if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_TERA_BLAST)
{
if (IsGimmickSelected(battler, GIMMICK_TERA) || GetActiveGimmick(battler) == GIMMICK_TERA)
type = GetBattlerTeraType(battler);
end = StringCopy(txtPtr, gTypesInfo[type].name);
}
else if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_IVY_CUDGEL)
{
Expand All @@ -1734,21 +1733,33 @@ static void MoveSelectionDisplayMoveType(u32 battler)
|| speciesId == SPECIES_OGERPON_HEARTHFLAME_MASK || speciesId == SPECIES_OGERPON_HEARTHFLAME_MASK_TERA
|| speciesId == SPECIES_OGERPON_CORNERSTONE_MASK || speciesId == SPECIES_OGERPON_CORNERSTONE_MASK_TERA)
type = gBattleMons[battler].type2;
end = StringCopy(txtPtr, gTypesInfo[type].name);
}
// Max Guard is a Normal-type move
else if (gMovesInfo[moveInfo->moves[gMoveSelectionCursor[battler]]].category == DAMAGE_CATEGORY_STATUS
&& (GetActiveGimmick(battler) == GIMMICK_DYNAMAX || IsGimmickSelected(battler, GIMMICK_DYNAMAX)))
{
type = TYPE_NORMAL;
end = StringCopy(txtPtr, gTypesInfo[type].name);
}
else if (moveInfo->moves[gMoveSelectionCursor[battler]] == MOVE_TERA_STARSTORM)
{
if (gBattleMons[battler].species == SPECIES_TERAPAGOS_STELLAR
|| (IsGimmickSelected(battler, GIMMICK_TERA) && gBattleMons[battler].species == SPECIES_TERAPAGOS_TERASTAL))
type = TYPE_STELLAR;
end = StringCopy(txtPtr, gTypesInfo[type].name);
}
else if (P_SHOW_DYNAMIC_TYPES)
{
struct Pokemon *mon = &gPlayerParty[gBattlerPartyIndexes[battler]];
type = CheckDynamicMoveType(mon, moveInfo->moves[gMoveSelectionCursor[battler]], battler);
end = StringCopy(txtPtr, gTypesInfo[type].name);
}
else
{
end = StringCopy(txtPtr, gTypesInfo[type].name);
}

end = StringCopy(txtPtr, gTypesInfo[type].name);
PrependFontIdToFit(txtPtr, end, FONT_NORMAL, WindowWidthPx(B_WIN_MOVE_TYPE) - 25);
BattlePutTextOnWindow(gDisplayedStringBattle, B_WIN_MOVE_TYPE);
}
Expand Down
147 changes: 147 additions & 0 deletions src/pokemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "malloc.h"
#include "apprentice.h"
#include "battle.h"
#include "battle_ai_switch_items.h"
#include "battle_anim.h"
#include "battle_controllers.h"
#include "battle_message.h"
Expand Down Expand Up @@ -6941,3 +6942,149 @@ void UpdateDaysPassedSinceFormChange(u16 days)
}
}
}

u8 CheckDynamicMoveType(struct Pokemon *mon, u32 move, u32 battler)
{
u32 type = gMovesInfo[move].type;
u32 species = GetMonData(mon, MON_DATA_SPECIES);
u32 heldItem = GetMonData(mon, MON_DATA_HELD_ITEM, 0);
u32 heldItemEffect = ItemId_GetHoldEffect(heldItem);
u32 ability = GetMonAbility(mon);
u32 type1 = gSpeciesInfo[species].types[0];
u32 type2 = gSpeciesInfo[species].types[1];

if (move == MOVE_IVY_CUDGEL
&& (species == SPECIES_OGERPON_WELLSPRING_MASK || species == SPECIES_OGERPON_WELLSPRING_MASK_TERA
|| species == SPECIES_OGERPON_HEARTHFLAME_MASK || species == SPECIES_OGERPON_HEARTHFLAME_MASK_TERA
|| species == SPECIES_OGERPON_CORNERSTONE_MASK || species == SPECIES_OGERPON_CORNERSTONE_MASK_TERA))
{
type = type2;
}
else if (move == MOVE_STRUGGLE)
{
return TYPE_NORMAL;
}
else if (move == MOVE_TERA_BLAST && GetActiveGimmick(battler) == GIMMICK_TERA && gBattleMons[battler].species == species)
{
return GetMonData(mon, MON_DATA_TERA_TYPE);
}
else if (move == MOVE_TERA_STARSTORM && species == SPECIES_TERAPAGOS_STELLAR)
{
return TYPE_STELLAR;
}
else if (move == MOVE_HIDDEN_POWER)
{
return CalculateHiddenPowerType(mon);
}
else if (move == MOVE_AURA_WHEEL && species == SPECIES_MORPEKO_HANGRY)
{
type = TYPE_DARK;
}
else if (gMovesInfo[move].effect == EFFECT_CHANGE_TYPE_ON_ITEM)
{
if (heldItemEffect == gMovesInfo[move].argument)
return ItemId_GetSecondaryId(heldItem);
else
return TYPE_NORMAL;
}
else if (move == MOVE_NATURAL_GIFT)
{
if (ItemId_GetPocket(heldItem) == POCKET_BERRIES)
return gNaturalGiftTable[ITEM_TO_BERRY(heldItem)].type;
else
return TYPE_NORMAL;
}
else if (move == MOVE_RAGING_BULL
&& (species == SPECIES_TAUROS_PALDEAN_COMBAT_BREED
|| species == SPECIES_TAUROS_PALDEAN_BLAZE_BREED
|| species == SPECIES_TAUROS_PALDEAN_AQUA_BREED))
{
return type2;
}
else if (move == MOVE_REVELATION_DANCE)
{
if (gBattleMons[battler].species != species && type1 != TYPE_MYSTERY)
type = type1;
else if (gBattleMons[battler].species != species && type2 != TYPE_MYSTERY)
type = type2;
else if (GetBattlerTeraType(battler) != TYPE_STELLAR && (GetActiveGimmick(battler) == GIMMICK_TERA || IsGimmickSelected(battler, GIMMICK_TERA)))
type = GetMonData(mon, MON_DATA_TERA_TYPE);
else if (gBattleMons[battler].type1 != TYPE_MYSTERY)
type = gBattleMons[battler].type1;
else if (gBattleMons[battler].type2 != TYPE_MYSTERY)
type = gBattleMons[battler].type2;
else if (gBattleMons[battler].type3 != TYPE_MYSTERY)
type = gBattleMons[battler].type3;
}
else if (gMovesInfo[move].effect == EFFECT_TERRAIN_PULSE
&& ((IsMonGrounded(heldItemEffect, ability, type1, type2) && gBattleMons[battler].species != species)
|| (IsBattlerTerrainAffected(battler, STATUS_FIELD_TERRAIN_ANY) && gBattleMons[battler].species == species)))
{
if (gFieldStatuses & STATUS_FIELD_ELECTRIC_TERRAIN)
return TYPE_ELECTRIC;
else if (gFieldStatuses & STATUS_FIELD_GRASSY_TERRAIN)
return TYPE_GRASS;
else if (gFieldStatuses & STATUS_FIELD_MISTY_TERRAIN)
return TYPE_FAIRY;
else if (gFieldStatuses & STATUS_FIELD_PSYCHIC_TERRAIN)
return TYPE_PSYCHIC;
else //failsafe
type = TYPE_NORMAL;
}

if (gMovesInfo[move].effect == EFFECT_WEATHER_BALL && WEATHER_HAS_EFFECT)
{
if (gBattleWeather & B_WEATHER_RAIN && heldItemEffect != HOLD_EFFECT_UTILITY_UMBRELLA)
return TYPE_WATER;
else if (gBattleWeather & B_WEATHER_SANDSTORM)
return TYPE_ROCK;
else if (gBattleWeather & B_WEATHER_SUN && heldItemEffect != HOLD_EFFECT_UTILITY_UMBRELLA)
return TYPE_FIRE;
else if (gBattleWeather & (B_WEATHER_SNOW | B_WEATHER_HAIL))
return TYPE_ICE;
else
return TYPE_NORMAL;
}

if (ability == ABILITY_NORMALIZE && gMovesInfo[move].type != TYPE_NORMAL && GetActiveGimmick(battler) != GIMMICK_Z_MOVE)
type = TYPE_NORMAL;

if ((gFieldStatuses & STATUS_FIELD_ION_DELUGE && type == TYPE_NORMAL) || gStatuses4[battler] & STATUS4_ELECTRIFIED)
type = TYPE_ELECTRIC;

if (gMovesInfo[move].type == TYPE_NORMAL && gMovesInfo[move].category != DAMAGE_CATEGORY_STATUS)
{
switch (ability)
{
case ABILITY_PIXILATE: return TYPE_FAIRY;
case ABILITY_REFRIGERATE: return TYPE_ICE;
case ABILITY_AERILATE: return TYPE_FLYING;
case ABILITY_GALVANIZE: return TYPE_ELECTRIC;
default: break;
}
}

if (ability == ABILITY_LIQUID_VOICE && gMovesInfo[move].soundMove == TRUE)
return TYPE_WATER;

return type;
}

u8 CalculateHiddenPowerType(struct Pokemon *mon)
{
u32 typehp;
u32 type;
u8 typeBits = ((GetMonData(mon, MON_DATA_HP_IV) & 1) << 0)
| ((GetMonData(mon, MON_DATA_ATK_IV) & 1) << 1)
| ((GetMonData(mon, MON_DATA_DEF_IV) & 1) << 2)
| ((GetMonData(mon, MON_DATA_SPEED_IV) & 1) << 3)
| ((GetMonData(mon, MON_DATA_SPATK_IV) & 1) << 4)
| ((GetMonData(mon, MON_DATA_SPDEF_IV) & 1) << 5);

type = (15 * typeBits) / 63 + 2;
if (type >= TYPE_MYSTERY)
type++;
type |= 0xC0;
typehp = type & 0x3F;
return typehp;
}
29 changes: 26 additions & 3 deletions src/pokemon_summary_screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -3957,16 +3957,29 @@ static void SetMonTypeIcons(void)

static void SetMoveTypeIcons(void)
{
u8 i;
u32 i;
u32 type;
struct PokeSummary *summary = &sMonSummaryScreen->summary;
struct Pokemon *mon = &sMonSummaryScreen->currentMon;

for (i = 0; i < MAX_MON_MOVES; i++)
{
if (summary->moves[i] != MOVE_NONE)
{
SetTypeSpritePosAndPal(gMovesInfo[summary->moves[i]].type, 85, 32 + (i * 16), i + SPRITE_ARR_ID_TYPE);
if (P_SHOW_DYNAMIC_TYPES)
{
type = CheckDynamicMoveType(mon, summary->moves[i], 0);
SetTypeSpritePosAndPal(type, 85, 32 + (i * 16), i + SPRITE_ARR_ID_TYPE);
}
else
{
SetTypeSpritePosAndPal(gMovesInfo[summary->moves[i]].type, 85, 32 + (i * 16), i + SPRITE_ARR_ID_TYPE);
}
}
else
{
SetSpriteInvisibility(i + SPRITE_ARR_ID_TYPE, TRUE);
}
}
}

Expand All @@ -3985,16 +3998,26 @@ static void SetContestMoveTypeIcons(void)

static void SetNewMoveTypeIcon(void)
{
u32 type = gMovesInfo[sMonSummaryScreen->newMove].type;
struct Pokemon *mon = &sMonSummaryScreen->currentMon;

if (P_SHOW_DYNAMIC_TYPES)
type = CheckDynamicMoveType(mon, sMonSummaryScreen->newMove, 0);

if (sMonSummaryScreen->newMove == MOVE_NONE)
{
SetSpriteInvisibility(SPRITE_ARR_ID_TYPE + 4, TRUE);
}
else
{
if (sMonSummaryScreen->currPageIndex == PSS_PAGE_BATTLE_MOVES)
SetTypeSpritePosAndPal(gMovesInfo[sMonSummaryScreen->newMove].type, 85, 96, SPRITE_ARR_ID_TYPE + 4);
{
SetTypeSpritePosAndPal(type, 85, 96, SPRITE_ARR_ID_TYPE + 4);
}
else
{
SetTypeSpritePosAndPal(NUMBER_OF_MON_TYPES + gMovesInfo[sMonSummaryScreen->newMove].contestCategory, 85, 96, SPRITE_ARR_ID_TYPE + 4);
}
}
}

Expand Down

0 comments on commit 355739d

Please sign in to comment.