Skip to content

Commit

Permalink
Follower form change using form change table
Browse files Browse the repository at this point in the history
  • Loading branch information
AsparagusEduardo committed Jul 28, 2024
1 parent 1c5ece1 commit acc7355
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 129 deletions.
4 changes: 4 additions & 0 deletions include/constants/form_change_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,8 @@
// param1: amount of days
#define FORM_CHANGE_DAYS_PASSED 23

// Form change that activates when overworld weather changes.
// param1: weather to check.
#define FORM_CHANGE_OVERWORLD_WEATHER 24

#endif // GUARD_CONSTANTS_FORM_CHANGE_TYPES_H
176 changes: 84 additions & 92 deletions src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -10612,20 +10612,17 @@ bool32 DoesSpeciesUseHoldItemToChangeForm(u16 species, u16 heldItemId)
u32 i;
const struct FormChange *formChanges = GetSpeciesFormChanges(species);

if (formChanges != NULL)
for (i = 0; formChanges != NULL && formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
{
for (i = 0; formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
switch (formChanges[i].method)
{
switch (formChanges[i].method)
{
case FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM:
case FORM_CHANGE_BATTLE_PRIMAL_REVERSION:
case FORM_CHANGE_BATTLE_ULTRA_BURST:
case FORM_CHANGE_ITEM_HOLD:
if (formChanges[i].param1 == heldItemId)
return TRUE;
break;
}
case FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM:
case FORM_CHANGE_BATTLE_PRIMAL_REVERSION:
case FORM_CHANGE_BATTLE_ULTRA_BURST:
case FORM_CHANGE_ITEM_HOLD:
if (formChanges[i].param1 == heldItemId)
return TRUE;
break;
}
}
return FALSE;
Expand Down Expand Up @@ -10756,93 +10753,88 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method)
u16 species = gBattleMons[battler].species;
const struct FormChange *formChanges = GetSpeciesFormChanges(species);
struct Pokemon *mon = &GetBattlerParty(battler)[gBattlerPartyIndexes[battler]];
u16 heldItem;
u16 heldItem = gBattleMons[battler].item;

if (formChanges != NULL)
for (i = 0; formChanges != NULL && formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
{
heldItem = gBattleMons[battler].item;

for (i = 0; formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
if (method == formChanges[i].method && species != formChanges[i].targetSpecies)
{
if (method == formChanges[i].method && species != formChanges[i].targetSpecies)
switch (method)
{
switch (method)
{
case FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM:
case FORM_CHANGE_BATTLE_PRIMAL_REVERSION:
case FORM_CHANGE_BATTLE_ULTRA_BURST:
if (heldItem == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_MEGA_EVOLUTION_MOVE:
if (gBattleMons[battler].moves[0] == formChanges[i].param1
|| gBattleMons[battler].moves[1] == formChanges[i].param1
|| gBattleMons[battler].moves[2] == formChanges[i].param1
|| gBattleMons[battler].moves[3] == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_SWITCH:
if (formChanges[i].param1 == GetBattlerAbility(battler) || formChanges[i].param1 == ABILITY_NONE)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_HP_PERCENT:
if (formChanges[i].param1 == GetBattlerAbility(battler))
{
// We multiply by 100 to make sure that integer division doesn't mess with the health check.
u32 hpCheck = gBattleMons[battler].hp * 100 * 100 / gBattleMons[battler].maxHP;
switch(formChanges[i].param2)
{
case HP_HIGHER_THAN:
if (hpCheck > formChanges[i].param3 * 100)
targetSpecies = formChanges[i].targetSpecies;
break;
case HP_LOWER_EQ_THAN:
if (hpCheck <= formChanges[i].param3 * 100)
targetSpecies = formChanges[i].targetSpecies;
break;
}
}
break;
case FORM_CHANGE_BATTLE_GIGANTAMAX:
if (GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR))
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_WEATHER:
// Check if there is a required ability and if the battler's ability does not match it
// or is suppressed. If so, revert to the no weather form.
if (formChanges[i].param2
&& GetBattlerAbility(battler) != formChanges[i].param2
&& formChanges[i].param1 == B_WEATHER_NONE)
{
targetSpecies = formChanges[i].targetSpecies;
}
// We need to revert the weather form if the field is under Air Lock, too.
else if (!WEATHER_HAS_EFFECT && formChanges[i].param1 == B_WEATHER_NONE)
{
targetSpecies = formChanges[i].targetSpecies;
}
// Otherwise, just check for a match between the weather and the form change table.
// Added a check for whether the weather is in effect to prevent end-of-turn soft locks with Cloud Nine / Air Lock
else if (((gBattleWeather & formChanges[i].param1) && WEATHER_HAS_EFFECT)
|| (gBattleWeather == B_WEATHER_NONE && formChanges[i].param1 == B_WEATHER_NONE))
case FORM_CHANGE_BATTLE_MEGA_EVOLUTION_ITEM:
case FORM_CHANGE_BATTLE_PRIMAL_REVERSION:
case FORM_CHANGE_BATTLE_ULTRA_BURST:
if (heldItem == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_MEGA_EVOLUTION_MOVE:
if (gBattleMons[battler].moves[0] == formChanges[i].param1
|| gBattleMons[battler].moves[1] == formChanges[i].param1
|| gBattleMons[battler].moves[2] == formChanges[i].param1
|| gBattleMons[battler].moves[3] == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_SWITCH:
if (formChanges[i].param1 == GetBattlerAbility(battler) || formChanges[i].param1 == ABILITY_NONE)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_HP_PERCENT:
if (formChanges[i].param1 == GetBattlerAbility(battler))
{
// We multiply by 100 to make sure that integer division doesn't mess with the health check.
u32 hpCheck = gBattleMons[battler].hp * 100 * 100 / gBattleMons[battler].maxHP;
switch(formChanges[i].param2)
{
targetSpecies = formChanges[i].targetSpecies;
case HP_HIGHER_THAN:
if (hpCheck > formChanges[i].param3 * 100)
targetSpecies = formChanges[i].targetSpecies;
break;
case HP_LOWER_EQ_THAN:
if (hpCheck <= formChanges[i].param3 * 100)
targetSpecies = formChanges[i].targetSpecies;
break;
}
break;
case FORM_CHANGE_BATTLE_TURN_END:
case FORM_CHANGE_HIT_BY_MOVE:
if (formChanges[i].param1 == GetBattlerAbility(battler))
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_STATUS:
if (gBattleMons[battler].status1 & formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_TERASTALLIZATION:
if (GetBattlerTeraType(battler) == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
}
break;
case FORM_CHANGE_BATTLE_GIGANTAMAX:
if (GetMonData(mon, MON_DATA_GIGANTAMAX_FACTOR))
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_WEATHER:
// Check if there is a required ability and if the battler's ability does not match it
// or is suppressed. If so, revert to the no weather form.
if (formChanges[i].param2
&& GetBattlerAbility(battler) != formChanges[i].param2
&& formChanges[i].param1 == B_WEATHER_NONE)
{
targetSpecies = formChanges[i].targetSpecies;
}
// We need to revert the weather form if the field is under Air Lock, too.
else if (!WEATHER_HAS_EFFECT && formChanges[i].param1 == B_WEATHER_NONE)
{
targetSpecies = formChanges[i].targetSpecies;
}
// Otherwise, just check for a match between the weather and the form change table.
// Added a check for whether the weather is in effect to prevent end-of-turn soft locks with Cloud Nine / Air Lock
else if (((gBattleWeather & formChanges[i].param1) && WEATHER_HAS_EFFECT)
|| (gBattleWeather == B_WEATHER_NONE && formChanges[i].param1 == B_WEATHER_NONE))
{
targetSpecies = formChanges[i].targetSpecies;
}
break;
case FORM_CHANGE_BATTLE_TURN_END:
case FORM_CHANGE_HIT_BY_MOVE:
if (formChanges[i].param1 == GetBattlerAbility(battler))
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_STATUS:
if (gBattleMons[battler].status1 & formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
case FORM_CHANGE_BATTLE_TERASTALLIZATION:
if (GetBattlerTeraType(battler) == formChanges[i].param1)
targetSpecies = formChanges[i].targetSpecies;
break;
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/data/pokemon/form_change_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,13 @@ static const struct FormChange sGlalieFormChangeTable[] = {

#if P_FAMILY_CASTFORM
static const struct FormChange sCastformFormChangeTable[] = {
{FORM_CHANGE_OVERWORLD_WEATHER, SPECIES_CASTFORM_SUNNY, WEATHER_SUNNY_CLOUDS},
{FORM_CHANGE_OVERWORLD_WEATHER, SPECIES_CASTFORM_SUNNY, WEATHER_DROUGHT},
{FORM_CHANGE_OVERWORLD_WEATHER, SPECIES_CASTFORM_RAINY, WEATHER_RAIN},
{FORM_CHANGE_OVERWORLD_WEATHER, SPECIES_CASTFORM_RAINY, WEATHER_RAIN_THUNDERSTORM},
{FORM_CHANGE_OVERWORLD_WEATHER, SPECIES_CASTFORM_RAINY, WEATHER_DOWNPOUR},
{FORM_CHANGE_OVERWORLD_WEATHER, SPECIES_CASTFORM_SNOWY, WEATHER_SNOW},
{FORM_CHANGE_OVERWORLD_WEATHER, SPECIES_CASTFORM_NORMAL, WEATHER_NONE},
#if B_WEATHER_FORMS >= GEN_5
{FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_SUNNY, B_WEATHER_SUN, ABILITY_FORECAST},
{FORM_CHANGE_BATTLE_WEATHER, SPECIES_CASTFORM_RAINY, B_WEATHER_RAIN, ABILITY_FORECAST},
Expand Down
42 changes: 13 additions & 29 deletions src/event_object_movement.c
Original file line number Diff line number Diff line change
Expand Up @@ -2018,36 +2018,22 @@ static void RefreshFollowerGraphics(struct ObjectEvent *objEvent)
}
}

static u16 GetOverworldWeatherSpecies(u32 species)
static u16 GetOverworldWeatherSpecies(u16 species)
{
u32 i;
u32 weather = GetCurrentWeather();
u32 baseSpecies = GET_BASE_SPECIES_ID(species);
const struct FormChange *formChanges = GetSpeciesFormChanges(species);

if (baseSpecies == SPECIES_CASTFORM)
{
switch (GetCurrentWeather())
{
case WEATHER_SUNNY_CLOUDS:
case WEATHER_DROUGHT:
return SPECIES_CASTFORM_SUNNY;
case WEATHER_RAIN:
case WEATHER_RAIN_THUNDERSTORM:
case WEATHER_DOWNPOUR:
return SPECIES_CASTFORM_RAINY;
case WEATHER_SNOW:
return SPECIES_CASTFORM_SNOWY;
}
return SPECIES_CASTFORM_NORMAL;
}
else if (baseSpecies == SPECIES_CHERRIM)
for (i = 0; formChanges != NULL && formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
{
switch (GetCurrentWeather())
// Unlike other form change checks, we don't do the "species != formChanges[i].targetSpecies" check
if (formChanges[i].method == FORM_CHANGE_OVERWORLD_WEATHER)
{
case WEATHER_SUNNY_CLOUDS:
case WEATHER_DROUGHT:
return SPECIES_CHERRIM_SUNSHINE;
if (formChanges[i].param1 == weather)
return formChanges[i].targetSpecies;
else if (formChanges[i].param1 == WEATHER_NONE) // Set the default form for weather not defined in form change table
species = formChanges[i].targetSpecies;
}
return SPECIES_CHERRIM_OVERCAST;
}
return species;
}
Expand All @@ -2064,14 +2050,12 @@ static bool8 GetMonInfo(struct Pokemon *mon, u16 *species, u8 *form, u8 *shiny)
}
*species = GetMonData(mon, MON_DATA_SPECIES);
*shiny = IsMonShiny(mon);
switch (GET_BASE_SPECIES_ID(*species))
switch (*species)
{
case SPECIES_UNOWN:
*form = GET_UNOWN_LETTER(mon->box.personality);
break;
// form is based on overworld weather
case SPECIES_CASTFORM:
case SPECIES_CHERRIM:
default:
*species = GetOverworldWeatherSpecies(*species);
break;
}
Expand Down Expand Up @@ -5228,7 +5212,7 @@ static bool32 TryStartFollowerTransformEffect(struct ObjectEvent *objectEvent, s
u32 multi;
u32 baseSpecies = GET_BASE_SPECIES_ID(OW_SPECIES(objectEvent));
if (OW_FOLLOWERS_WEATHER_FORMS
&& (baseSpecies == SPECIES_CASTFORM || baseSpecies == SPECIES_CHERRIM)
&& DoesSpeciesHaveFormChangeMethod(OW_SPECIES(objectEvent), FORM_CHANGE_BATTLE_WEATHER)
&& OW_SPECIES(objectEvent) != (multi = GetOverworldWeatherSpecies(OW_SPECIES(objectEvent))))
{
sprite->data[7] = TRANSFORM_TYPE_WEATHER << 8;
Expand Down
13 changes: 5 additions & 8 deletions src/pokemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -4401,7 +4401,7 @@ static u32 GetGMaxTargetSpecies(u32 species)
{
const struct FormChange *formChanges = GetSpeciesFormChanges(species);
u32 i;
for (i = 0; formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
for (i = 0; formChanges != NULL && formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
{
if (formChanges[i].method == FORM_CHANGE_BATTLE_GIGANTAMAX)
return formChanges[i].targetSpecies;
Expand Down Expand Up @@ -6579,7 +6579,7 @@ void TrySetDayLimitToFormChange(struct Pokemon *mon)
u16 species = GetMonData(mon, MON_DATA_SPECIES, NULL);
const struct FormChange *formChanges = GetSpeciesFormChanges(species);

for (i = 0; formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
for (i = 0; formChanges != NULL && formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
{
if (formChanges[i].method == FORM_CHANGE_DAYS_PASSED && species != formChanges[i].targetSpecies)
{
Expand All @@ -6594,13 +6594,10 @@ bool32 DoesSpeciesHaveFormChangeMethod(u16 species, u16 method)
u32 i;
const struct FormChange *formChanges = GetSpeciesFormChanges(species);

if (formChanges != NULL)
for (i = 0; formChanges != NULL && formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
{
for (i = 0; formChanges[i].method != FORM_CHANGE_TERMINATOR; i++)
{
if (method == formChanges[i].method && species != formChanges[i].targetSpecies)
return TRUE;
}
if (method == formChanges[i].method && species != formChanges[i].targetSpecies)
return TRUE;
}

return FALSE;
Expand Down

0 comments on commit acc7355

Please sign in to comment.