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

Add FORM_CHANGE_BATTLE_TERASTALLIZATION + allow species to force tera types #4438

Merged
merged 19 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion data/battle_anim_scripts.s
Original file line number Diff line number Diff line change
Expand Up @@ -27436,12 +27436,13 @@ General_TeraCharge:
delay 20
createvisualtask AnimTask_BlendBattleAnimPalExclude, 5, 5, 2, 0, 16, RGB_WHITEALPHA
waitforvisualfinish
createvisualtask AnimTask_TransformMon, 2, 1, 0
call TeraChargeParticles
playsewithpan SE_M_BRICK_BREAK, SOUND_PAN_ATTACKER
clearmonbg ANIM_ATK_PARTNER
blendoff
end

TeraChargeParticles:
createsprite gTeraCrystalSpreadSpriteTemplate, ANIM_TARGET, 0, 0, -5, 8
createsprite gTeraCrystalSpreadSpriteTemplate, ANIM_TARGET, 0, 1, 5, 9
Expand Down
16 changes: 16 additions & 0 deletions data/battle_scripts_1.s
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ BattleScript_Terastallization::
waitmessage B_WAIT_TIME_LONG
end3

BattleScript_TeraFormChange::
@ TODO: no string prints in S/V, but right now this helps with clarity
printstring STRINGID_PKMNSTORINGENERGY
handleformchange BS_ATTACKER, 0
handleformchange BS_ATTACKER, 1
playanimation BS_ATTACKER, B_ANIM_TERA_CHARGE
waitanimation
applyterastallization
playanimation BS_ATTACKER, B_ANIM_TERA_ACTIVATE
waitanimation
handleformchange BS_ATTACKER, 2
printstring STRINGID_PKMNTERASTALLIZEDINTO
waitmessage B_WAIT_TIME_LONG
switchinabilities BS_ATTACKER
end3

BattleScript_LowerAtkSpAtk::
jumpifstat BS_EFFECT_BATTLER, CMP_GREATER_THAN, STAT_ATK, MIN_STAT_STAGE, BattleScript_LowerAtkSpAtkDoAnim
jumpifstat BS_EFFECT_BATTLER, CMP_EQUAL, STAT_SPATK, MIN_STAT_STAGE, BattleScript_LowerAtkSpAtkEnd
Expand Down
1 change: 1 addition & 0 deletions include/battle_scripts.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ extern const u8 BattleScript_LowerAtkSpAtk[];
extern const u8 BattleScript_Terastallization[];
extern const u8 BattleScript_BoosterEnergyEnd2[];
extern const u8 BattleScript_TeraShellDistortingTypeMatchups[];
extern const u8 BattleScript_TeraFormChange[];

// zmoves
extern const u8 BattleScript_ZMoveActivateDamaging[];
Expand Down
6 changes: 5 additions & 1 deletion include/constants/form_change_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@
#define FORM_CHANGE_STATUS 20

// Form change that activates after move is used. Currently only used for activating Gulp Missile.
#define FORM_CHANGE_HIT_BY_MOVE 21
#define FORM_CHANGE_HIT_BY_MOVE 21

// Form change that activates when terastallized as as a specific type
// param1: tera type
#define FORM_CHANGE_BATTLE_TERASTALLIZATION 22

#endif // GUARD_CONSTANTS_FORM_CHANGE_TYPES_H
4 changes: 3 additions & 1 deletion include/pokemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ struct SpeciesInfo /*0x8C*/
/* 0x05 */ u8 baseSpDefense;
/* 0x06 */ u8 types[2];
/* 0x08 */ u8 catchRate;
/* 0x09 */ u8 padding1;
/* 0x09 */ u8 forceTeraType;
kittenchilly marked this conversation as resolved.
Show resolved Hide resolved
/* 0x0A */ u16 expYield; // expYield was changed from u8 to u16 for the new Exp System.
/* 0x0C */ u16 evYield_HP:2;
u16 evYield_Attack:2;
Expand All @@ -378,6 +378,7 @@ struct SpeciesInfo /*0x8C*/
/* 0x16 */ u8 eggGroups[2];
/* 0x18 */ u16 abilities[NUM_ABILITY_SLOTS]; // 3 abilities, no longer u8 because we have over 255 abilities now.
/* 0x1E */ u8 safariZoneFleeRate;

// Pokédex data
/* 0x1F */ u8 categoryName[13];
/* 0x1F */ u8 speciesName[POKEMON_NAME_LENGTH + 1];
Expand Down Expand Up @@ -431,6 +432,7 @@ struct SpeciesInfo /*0x8C*/
u32 isPrimalReversion:1;
u32 isUltraBurst:1;
u32 isGigantamax:1;
u32 isTeraForm:1;
u32 isAlolanForm:1;
u32 isGalarianForm:1;
u32 isHisuianForm:1;
Expand Down
5 changes: 4 additions & 1 deletion src/battle_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5086,7 +5086,10 @@ static bool32 TryDoGimmicksBeforeMoves(void)
gBattleStruct->tera.toTera &= ~(gBitTable[gBattlerAttacker]);
PrepareBattlerForTera(gBattlerAttacker);
PREPARE_TYPE_BUFFER(gBattleTextBuff1, GetBattlerTeraType(gBattlerAttacker));
BattleScriptExecute(BattleScript_Terastallization);
if (TryBattleFormChange(gBattlerAttacker, FORM_CHANGE_BATTLE_TERASTALLIZATION))
BattleScriptExecute(BattleScript_TeraFormChange);
else
BattleScriptExecute(BattleScript_Terastallization);
return TRUE;
}
// Dynamax Check
Expand Down
18 changes: 9 additions & 9 deletions src/battle_script_commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -2050,7 +2050,7 @@ static void Cmd_adjustdamage(void)
gLastUsedItem = gBattleMons[gBattlerTarget].item;
gSpecialStatuses[gBattlerTarget].focusBanded = FALSE;
gSpecialStatuses[gBattlerTarget].focusSashed = FALSE;

}
else if (gSpecialStatuses[gBattlerTarget].sturdied)
{
Expand Down Expand Up @@ -3172,8 +3172,8 @@ void SetMoveEffect(bool32 primary, bool32 certain)
{
gBattleMons[gEffectBattler].status2 |= sStatusFlagsForMoveEffects[gBattleScripting.moveEffect];
gBattlescriptCurrInstr++;
}
else
}
else
{
gBattlescriptCurrInstr++;
}
Expand Down Expand Up @@ -6243,7 +6243,7 @@ static void Cmd_moveend(void)
break;
}
}

if (!(gBattleStruct->lastMoveFailed & gBitTable[gBattlerAttacker]
|| (!gSpecialStatuses[gBattlerAttacker].dancerUsedMove
&& gBattleStruct->bouncedMoveIsUsed)))
Expand Down Expand Up @@ -6341,9 +6341,9 @@ static void Cmd_moveend(void)
&& (gMoveResultFlags & MOVE_RESULT_NO_EFFECT) // And it is unusable
&& (gBattleMons[gBattlerAttacker].status2 & STATUS2_LOCK_CONFUSE) != STATUS2_LOCK_CONFUSE_TURN(1)) // And won't end this turn
CancelMultiTurnMoves(gBattlerAttacker); // Cancel it



if (gBattleStruct->savedAttackerCount > 0)
{
// #if TESTING
Expand Down Expand Up @@ -16845,8 +16845,8 @@ void BS_AllySwitchFailChance(void)
void BS_SetPhotonGeyserCategory(void)
{
NATIVE_ARGS();
if (!(gMovesInfo[gCurrentMove].effect == EFFECT_TERA_BLAST && !IsTerastallized(gBattlerAttacker))
&& !(gMovesInfo[gCurrentMove].effect == EFFECT_TERA_STARSTORM && gBattleMons[gBattlerAttacker].species != SPECIES_TERAPAGOS_STELLAR))
if (!((gMovesInfo[gCurrentMove].effect == EFFECT_TERA_BLAST && !IsTerastallized(gBattlerAttacker))
|| (gMovesInfo[gCurrentMove].effect == EFFECT_TERA_STARSTORM && !(IsTerastallized(gBattlerAttacker) && gBattleMons[gBattlerAttacker].species == SPECIES_TERAPAGOS_STELLAR))))
gBattleStruct->swapDamageCategory = (GetCategoryBasedOnStats(gBattlerAttacker) == DAMAGE_CATEGORY_PHYSICAL);
gBattlescriptCurrInstr = cmd->nextInstr;
}
Expand Down
7 changes: 3 additions & 4 deletions src/battle_terastal.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void PrepareBattlerForTera(u32 battler)
gBattleStruct->tera.isTerastallized[side] |= gBitTable[index];
gBattleStruct->tera.alreadyTerastallized[battler] = TRUE;

// Remove Tera Orb charge.
// Remove Tera Orb charge.
if (B_FLAG_TERA_ORB_CHARGED != 0
&& (B_FLAG_TERA_ORB_NO_COST == 0 || !FlagGet(B_FLAG_TERA_ORB_NO_COST))
&& side == B_SIDE_PLAYER
Expand Down Expand Up @@ -91,8 +91,7 @@ bool32 CanTerastallize(u32 battler)
// Returns a battler's Tera type.
u32 GetBattlerTeraType(u32 battler)
{
struct Pokemon *mon = &GetBattlerParty(battler)[gBattlerPartyIndexes[battler]];
return GetMonData(mon, MON_DATA_TERA_TYPE);
return GetMonData(&GetBattlerParty(battler)[gBattlerPartyIndexes[battler]], MON_DATA_TERA_TYPE);
}

// Returns whether a battler is terastallized.
Expand Down Expand Up @@ -128,7 +127,7 @@ uq4_12_t GetTeraMultiplier(u32 battler, u32 type)
// Safety check.
if (!IsTerastallized(battler))
return UQ_4_12(1.0);

// Stellar-type checks.
if (teraType == TYPE_STELLAR)
{
Expand Down
31 changes: 18 additions & 13 deletions src/battle_tower.c
Original file line number Diff line number Diff line change
Expand Up @@ -1568,7 +1568,7 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32
u8 ball = (fmon->ball == 0xFF) ? Random() % POKEBALL_COUNT : fmon->ball;
u16 move;
u32 personality, ability, friendship, j;

if (fmon->gender == TRAINER_MON_MALE)
{
personality = GeneratePersonalityForGender(MON_MALE, fmon->species);
Expand All @@ -1577,26 +1577,26 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32
{
personality = GeneratePersonalityForGender(MON_FEMALE, fmon->species);
}

ModifyPersonalityForNature(&personality, fmon->nature);
CreateMon(dst, fmon->species, level, fixedIV, TRUE, personality, otID, OT_ID_PRESET);

friendship = MAX_FRIENDSHIP;
// Give the chosen Pokémon its specified moves.
for (j = 0; j < MAX_MON_MOVES; j++)
{
move = fmon->moves[j];
if (flags & FLAG_FRONTIER_MON_FACTORY && move == MOVE_RETURN)
move = MOVE_FRUSTRATION;

SetMonMoveSlot(dst, move, j);
if (gMovesInfo[move].effect == EFFECT_FRUSTRATION)
friendship = 0; // Frustration is more powerful the lower the pokemon's friendship is.
}

SetMonData(dst, MON_DATA_FRIENDSHIP, &friendship);
SetMonData(dst, MON_DATA_HELD_ITEM, &fmon->heldItem);

// try to set ability. Otherwise, random of non-hidden as per vanilla
if (fmon->ability != ABILITY_NONE)
{
Expand All @@ -1611,7 +1611,7 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32
ability = 0;
SetMonData(dst, MON_DATA_ABILITY_NUM, &ability);
}

if (fmon->ev != NULL)
{
SetMonData(dst, MON_DATA_HP_EV, &(fmon->ev[0]));
Expand All @@ -1621,10 +1621,10 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32
SetMonData(dst, MON_DATA_SPDEF_EV, &(fmon->ev[4]));
SetMonData(dst, MON_DATA_SPEED_EV, &(fmon->ev[5]));
}

if (fmon->iv)
SetMonData(dst, MON_DATA_IVS, &(fmon->iv));

if (fmon->isShiny)
{
u32 data = TRUE;
Expand All @@ -1640,8 +1640,13 @@ void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32
u32 data = fmon->gigantamaxFactor;
SetMonData(dst, MON_DATA_GIGANTAMAX_FACTOR, &data);
}


if (fmon->teraType)
{
u32 data = fmon->teraType;
SetMonData(dst, MON_DATA_TERA_TYPE, &data);
}


SetMonData(dst, MON_DATA_POKEBALL, &ball);
CalculateMonStats(dst);
}
Expand Down Expand Up @@ -1743,7 +1748,7 @@ static void FillTrainerParty(u16 trainerId, u8 firstMonId, u8 monCount)
continue;

chosenMonIndices[i] = monId;

// Place the chosen Pokémon into the trainer's party.
CreateFacilityMon(&gFacilityTrainerMons[monId], level, fixedIV, otID, 0, &gEnemyParty[i + firstMonId]);

Expand Down Expand Up @@ -2032,7 +2037,7 @@ void DoSpecialTrainerBattle(void)
BattleTransition_StartOnField(GetSpecialBattleTransition(B_TRANSITION_GROUP_SECRET_BASE));
break;
case SPECIAL_BATTLE_EREADER:
#if FREE_BATTLE_TOWER_E_READER == FALSE
#if FREE_BATTLE_TOWER_E_READER == FALSE
ZeroEnemyPartyMons();
for (i = 0; i < (int)ARRAY_COUNT(gSaveBlock2Ptr->frontier.ereaderTrainer.party); i++)
CreateBattleTowerMon(&gEnemyParty[i], &gSaveBlock2Ptr->frontier.ereaderTrainer.party[i]);
Expand Down Expand Up @@ -3095,7 +3100,7 @@ static void FillPartnerParty(u16 trainerId)
for (i = 0; i < FRONTIER_MULTI_PARTY_SIZE; i++)
{
monId = gSaveBlock2Ptr->frontier.trainerIds[i + 18];
CreateFacilityMon(&gFacilityTrainerMons[monId], level, ivs, otID, 0, &gPlayerParty[MULTI_PARTY_SIZE + i]);
CreateFacilityMon(&gFacilityTrainerMons[monId], level, ivs, otID, 0, &gPlayerParty[MULTI_PARTY_SIZE + i]);
for (j = 0; j < PLAYER_NAME_LENGTH + 1; j++)
trainerName[j] = gFacilityTrainers[trainerId].trainerName[j];
SetMonData(&gPlayerParty[MULTI_PARTY_SIZE + i], MON_DATA_OT_NAME, &trainerName);
Expand Down
16 changes: 14 additions & 2 deletions src/battle_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -10595,6 +10595,14 @@ bool32 IsBattlerUltraBursted(u32 battler)
return (gSpeciesInfo[gBattleMons[battler].species].isUltraBurst);
}

bool32 IsBattlerInTeraForm(u32 battler)
{
// While Transform does copy stats and visuals, it shouldn't be counted as a true Tera Form.
if (gBattleMons[battler].status2 & STATUS2_TRANSFORMED)
return FALSE;
return (gSpeciesInfo[gBattleMons[battler].species].isTeraForm);
}

// Returns SPECIES_NONE if no form change is possible
u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method)
{
Expand Down Expand Up @@ -10685,6 +10693,10 @@ u16 GetBattleFormChangeTargetSpecies(u32 battler, u16 method)
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 All @@ -10700,7 +10712,7 @@ bool32 CanBattlerFormChange(u32 battler, u16 method)
&& B_TRANSFORM_FORM_CHANGES >= GEN_5)
return FALSE;
// Mega Evolved and Ultra Bursted Pokémon should always revert to normal upon fainting or ending the battle.
if ((IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE))
if ((IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE))
return TRUE;
else if (IsBattlerPrimalReverted(battler) && (method == FORM_CHANGE_END_BATTLE))
return TRUE;
Expand Down Expand Up @@ -10740,7 +10752,7 @@ bool32 TryBattleFormChange(u32 battler, u16 method)
bool32 restoreSpecies = FALSE;

// Mega Evolved and Ultra Bursted Pokémon should always revert to normal upon fainting or ending the battle, so no need to add it to the form change tables.
if ((IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE))
if ((IsBattlerMegaEvolved(battler) || IsBattlerUltraBursted(battler) || IsBattlerInTeraForm(battler)) && (method == FORM_CHANGE_FAINT || method == FORM_CHANGE_END_BATTLE))
restoreSpecies = TRUE;

// Unlike Megas, Primal Reversion isn't canceled on fainting.
Expand Down
18 changes: 12 additions & 6 deletions src/data/pokemon/form_change_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -1259,10 +1259,16 @@ static const struct FormChange sPalafinZeroFormChangeTable[] =

#if P_FAMILY_OGERPON
static const struct FormChange sOgerponFormChangeTable[] = {
{FORM_CHANGE_ITEM_HOLD, SPECIES_OGERPON_TEAL_MASK, ITEM_NONE},
{FORM_CHANGE_ITEM_HOLD, SPECIES_OGERPON_WELLSPRING_MASK, ITEM_WELLSPRING_MASK},
{FORM_CHANGE_ITEM_HOLD, SPECIES_OGERPON_HEARTHFLAME_MASK, ITEM_HEARTHFLAME_MASK},
{FORM_CHANGE_ITEM_HOLD, SPECIES_OGERPON_CORNERSTONE_MASK, ITEM_CORNERSTONE_MASK},
{FORM_CHANGE_ITEM_HOLD, SPECIES_OGERPON_TEAL_MASK, ITEM_NONE},
{FORM_CHANGE_ITEM_HOLD, SPECIES_OGERPON_WELLSPRING_MASK, ITEM_WELLSPRING_MASK},
{FORM_CHANGE_ITEM_HOLD, SPECIES_OGERPON_HEARTHFLAME_MASK, ITEM_HEARTHFLAME_MASK},
{FORM_CHANGE_ITEM_HOLD, SPECIES_OGERPON_CORNERSTONE_MASK, ITEM_CORNERSTONE_MASK},
#if P_TERA_FORMS
{FORM_CHANGE_BATTLE_TERASTALLIZATION, SPECIES_OGERPON_TEAL_MASK_TERA, TYPE_GRASS},
{FORM_CHANGE_BATTLE_TERASTALLIZATION, SPECIES_OGERPON_WELLSPRING_MASK_TERA, TYPE_WATER},
{FORM_CHANGE_BATTLE_TERASTALLIZATION, SPECIES_OGERPON_HEARTHFLAME_MASK_TERA, TYPE_FIRE},
{FORM_CHANGE_BATTLE_TERASTALLIZATION, SPECIES_OGERPON_CORNERSTONE_MASK_TERA, TYPE_ROCK},
#endif
{FORM_CHANGE_TERMINATOR},
};
#endif //P_FAMILY_OGERPON
Expand All @@ -1271,9 +1277,9 @@ static const struct FormChange sOgerponFormChangeTable[] = {
static const struct FormChange sTerapagosFormChangeTable[] = {
{FORM_CHANGE_BATTLE_SWITCH, SPECIES_TERAPAGOS_TERASTAL, ABILITY_TERA_SHIFT},
#if P_TERA_FORMS
//{FORM_CHANGE_TERASTALLIZATION, SPECIES_TERAPAGOS_STELLAR},
{FORM_CHANGE_BATTLE_TERASTALLIZATION, SPECIES_TERAPAGOS_STELLAR, TYPE_STELLAR},
#endif
{FORM_CHANGE_END_BATTLE, SPECIES_TERAPAGOS_NORMAL},
{FORM_CHANGE_END_BATTLE, SPECIES_TERAPAGOS_NORMAL},
{FORM_CHANGE_TERMINATOR},
};
#endif //P_FAMILY_TERAPAGOS
Expand Down
6 changes: 6 additions & 0 deletions src/data/pokemon/form_species_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -2161,6 +2161,12 @@ static const u16 sOgerponFormSpeciesIdTable[] = {
SPECIES_OGERPON_WELLSPRING_MASK,
SPECIES_OGERPON_HEARTHFLAME_MASK,
SPECIES_OGERPON_CORNERSTONE_MASK,
#if P_TERA_FORMS
SPECIES_OGERPON_TEAL_MASK_TERA,
SPECIES_OGERPON_WELLSPRING_MASK_TERA,
SPECIES_OGERPON_HEARTHFLAME_MASK_TERA,
SPECIES_OGERPON_CORNERSTONE_MASK_TERA,
#endif
FORM_SPECIES_END,
};
#endif //P_FAMILY_OGERPON
Expand Down
Loading
Loading