Adds missing evolution methods (#4087)
* Add evolution tracker to BoxMon struct * Add "use move 20 times, then lv up" evolution method * Add recoil tracker * Reduce to 9 bits * Fix agbcc complaint * Put MOVEEND_CLEAR_BITS at the end * Remove battle argument from tryupdaterecoiltrackker * Add null checks * Fix upcoming merge * Add requested formatting changes * Condense evolution check into a single function for easier customisation later * Incorporate review requests * Update src/pokedex_plus_hgss.c Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com> --------- Co-authored-by: Eduardo Quezada D'Ottone <eduardo602002@gmail.com>
This commit is contained in:
parent
09d12fb154
commit
ccfebe5e05
@ -1587,6 +1587,10 @@
|
||||
callnative BS_TryUpperHand
|
||||
.4byte \failInstr
|
||||
.endm
|
||||
|
||||
.macro tryupdaterecoiltracker
|
||||
callnative BS_TryUpdateRecoilTracker
|
||||
.endm
|
||||
|
||||
@ various command changed to more readable macros
|
||||
.macro cancelmultiturnmoves battler:req
|
||||
|
||||
@ -7704,6 +7704,7 @@ BattleScript_DoRecoil::
|
||||
datahpupdate BS_ATTACKER
|
||||
printstring STRINGID_PKMNHITWITHRECOIL
|
||||
waitmessage B_WAIT_TIME_LONG
|
||||
tryupdaterecoiltracker
|
||||
tryfaintmon BS_ATTACKER
|
||||
BattleScript_RecoilEnd::
|
||||
return
|
||||
|
||||
@ -316,8 +316,9 @@
|
||||
#define MOVEEND_SYMBIOSIS 34
|
||||
#define MOVEEND_OPPORTUNIST 35 // Occurs after other stat change items/abilities to try and copy the boosts
|
||||
#define MOVEEND_SAME_MOVE_TURNS 36
|
||||
#define MOVEEND_CLEAR_BITS 37
|
||||
#define MOVEEND_COUNT 38
|
||||
#define MOVEEND_SET_EVOLUTION_TRACKER 37
|
||||
#define MOVEEND_CLEAR_BITS 38
|
||||
#define MOVEEND_COUNT 39
|
||||
|
||||
// switch cases
|
||||
#define B_SWITCH_NORMAL 0
|
||||
|
||||
@ -291,6 +291,9 @@
|
||||
#define EVO_MOVE_THREE_SEGMENT 44 // Pokémon levels up, knows specified move, has a personality value with a modulus of 1-99
|
||||
#define EVO_LEVEL_FAMILY_OF_THREE 45 // Pokémon reaches the specified level with a personality value with a modulus of 0
|
||||
#define EVO_LEVEL_FAMILY_OF_FOUR 46 // Pokémon reaches the specified level with a personality value with a modulus of 1-99
|
||||
#define EVO_LEVEL_MOVE_TWENTY_TIMES 47 // Pokémon levels up after having used a move for at least 20 times
|
||||
#define EVO_LEVEL_RECOIL_DAMAGE_MALE 48 // Pokémon levels up after having suffered specified amount of non-fainting recoil damage as a male
|
||||
#define EVO_LEVEL_RECOIL_DAMAGE_FEMALE 49 // Pokémon levels up after having suffered specified amount of non-fainting recoil damage as a female
|
||||
|
||||
// Evolution 'modes,' for GetEvolutionTargetSpecies
|
||||
#define EVO_MODE_NORMAL 0
|
||||
|
||||
@ -113,6 +113,7 @@ enum {
|
||||
MON_DATA_DYNAMAX_LEVEL,
|
||||
MON_DATA_GIGANTAMAX_FACTOR,
|
||||
MON_DATA_TERA_TYPE,
|
||||
MON_DATA_EVOLUTION_TRACKER,
|
||||
};
|
||||
|
||||
struct PokemonSubstruct0
|
||||
@ -134,9 +135,10 @@ struct PokemonSubstruct0
|
||||
struct PokemonSubstruct1
|
||||
{
|
||||
u16 move1:11; // 2047 moves.
|
||||
u16 unused_00:5;
|
||||
u16 evolutionTracker1:5;
|
||||
u16 move2:11; // 2047 moves.
|
||||
u16 unused_02:5;
|
||||
u16 evolutionTracker2:4;
|
||||
u16 unused_02:1;
|
||||
u16 move3:11; // 2047 moves.
|
||||
u16 unused_04:5;
|
||||
u16 move4:11; // 2047 moves.
|
||||
|
||||
@ -356,6 +356,7 @@ static void RemoveAllTerrains(void);
|
||||
static bool8 CanAbilityPreventStatLoss(u16 abilityDef, bool8 isIntimidate);
|
||||
static bool8 CanBurnHitThaw(u16 move);
|
||||
static u32 GetNextTarget(u32 moveTarget, bool32 excludeCurrent);
|
||||
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount);
|
||||
|
||||
static void Cmd_attackcanceler(void);
|
||||
static void Cmd_accuracycheck(void);
|
||||
@ -6201,6 +6202,12 @@ static void Cmd_moveend(void)
|
||||
gBattleStruct->sameMoveTurns[gBattlerAttacker]++;
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_SET_EVOLUTION_TRACKER:
|
||||
// If the Pokémon needs to keep track of move usage for its evolutions, do it
|
||||
if (originallyUsedMove != MOVE_NONE)
|
||||
TryUpdateEvolutionTracker(EVO_LEVEL_MOVE_TWENTY_TIMES, 1);
|
||||
gBattleScripting.moveendState++;
|
||||
break;
|
||||
case MOVEEND_CLEAR_BITS: // Clear/Set bits for things like using a move for all targets and all hits.
|
||||
if (gSpecialStatuses[gBattlerAttacker].instructedChosenTarget)
|
||||
*(gBattleStruct->moveTarget + gBattlerAttacker) = gSpecialStatuses[gBattlerAttacker].instructedChosenTarget & 0x3;
|
||||
@ -16588,3 +16595,45 @@ void BS_SetPhotonGeyserCategory(void)
|
||||
gBattleStruct->swapDamageCategory = (GetCategoryBasedOnStats(gBattlerAttacker) == DAMAGE_CATEGORY_PHYSICAL);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
static void TryUpdateEvolutionTracker(u32 evolutionMethod, u32 upAmount)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
if (GetBattlerSide(gBattlerAttacker) == B_SIDE_PLAYER
|
||||
&& !(gBattleTypeFlags & (BATTLE_TYPE_LINK
|
||||
| BATTLE_TYPE_EREADER_TRAINER
|
||||
| BATTLE_TYPE_RECORDED_LINK
|
||||
| BATTLE_TYPE_TRAINER_HILL
|
||||
| BATTLE_TYPE_FRONTIER)))
|
||||
{
|
||||
const struct Evolution *evolutions = GetSpeciesEvolutions(gBattleMons[gBattlerAttacker].species);
|
||||
if (evolutions == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; evolutions[i].method != EVOLUTIONS_END; i++)
|
||||
{
|
||||
if (SanitizeSpeciesId(evolutions[i].targetSpecies) == SPECIES_NONE)
|
||||
continue;
|
||||
|
||||
if (evolutions[i].method == evolutionMethod)
|
||||
{
|
||||
// We only have 9 bits to use
|
||||
u16 val = min(511, GetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]], MON_DATA_EVOLUTION_TRACKER) + upAmount);
|
||||
// Reset progress if you faint for the recoil method.
|
||||
if (gBattleMons[gBattlerAttacker].hp == 0 && (evolutionMethod == EVO_LEVEL_RECOIL_DAMAGE_MALE || evolutionMethod == EVO_LEVEL_RECOIL_DAMAGE_FEMALE))
|
||||
val = 0;
|
||||
SetMonData(&gPlayerParty[gBattlerPartyIndexes[gBattlerAttacker]], MON_DATA_EVOLUTION_TRACKER, &val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BS_TryUpdateRecoilTracker(void)
|
||||
{
|
||||
NATIVE_ARGS();
|
||||
TryUpdateEvolutionTracker(EVO_LEVEL_RECOIL_DAMAGE_MALE, gBattleMoveDamage);
|
||||
TryUpdateEvolutionTracker(EVO_LEVEL_RECOIL_DAMAGE_FEMALE, gBattleMoveDamage);
|
||||
gBattlescriptCurrInstr = cmd->nextInstr;
|
||||
}
|
||||
|
||||
@ -4508,7 +4508,7 @@ const struct SpeciesInfo gSpeciesInfoGen1[] =
|
||||
ICON(Primeape, 2),
|
||||
FOOTPRINT(Primeape)
|
||||
LEARNSETS(Primeape),
|
||||
.evolutions = EVOLUTION({EVO_MOVE, MOVE_RAGE_FIST, SPECIES_ANNIHILAPE}),
|
||||
.evolutions = EVOLUTION({EVO_LEVEL_MOVE_TWENTY_TIMES, MOVE_RAGE_FIST, SPECIES_ANNIHILAPE}),
|
||||
},
|
||||
|
||||
#if P_GEN_9_CROSS_EVOS
|
||||
|
||||
@ -5170,7 +5170,7 @@ const struct SpeciesInfo gSpeciesInfoGen2[] =
|
||||
ICON(Stantler, 2),
|
||||
FOOTPRINT(Stantler)
|
||||
LEARNSETS(Stantler),
|
||||
.evolutions = EVOLUTION({EVO_MOVE, MOVE_PSYSHIELD_BASH, SPECIES_WYRDEER}),
|
||||
.evolutions = EVOLUTION({EVO_LEVEL_MOVE_TWENTY_TIMES, MOVE_PSYSHIELD_BASH, SPECIES_WYRDEER}),
|
||||
},
|
||||
|
||||
#if P_GEN_8_CROSS_EVOS
|
||||
|
||||
@ -3036,8 +3036,8 @@ const struct SpeciesInfo gSpeciesInfoGen5[] =
|
||||
PALETTES(BasculinWhiteStriped),
|
||||
ICON(BasculinWhiteStriped, 0),
|
||||
LEARNSETS(BasculinWhiteStriped),
|
||||
.evolutions = EVOLUTION({EVO_NONE, 0, SPECIES_BASCULEGION_MALE},
|
||||
{EVO_NONE, 0, SPECIES_BASCULEGION_FEMALE}),
|
||||
.evolutions = EVOLUTION({EVO_LEVEL_RECOIL_DAMAGE_MALE, 294, SPECIES_BASCULEGION_MALE},
|
||||
{EVO_LEVEL_RECOIL_DAMAGE_FEMALE, 294, SPECIES_BASCULEGION_FEMALE}),
|
||||
},
|
||||
|
||||
#define BASCULEGION_MISC_INFO \
|
||||
|
||||
@ -244,6 +244,9 @@ static const u8 sText_EVO_WATER_SCROLL[] = _("ScrollOfWatrs is used");
|
||||
static const u8 sText_EVO_ITEM_NIGHT[] = _("{STR_VAR_2} is used, night");
|
||||
static const u8 sText_EVO_ITEM_DAY[] = _("{STR_VAR_2} is used, day");
|
||||
static const u8 sText_EVO_ITEM_HOLD[] = _("{LV}{UP_ARROW}, holds {STR_VAR_2}");
|
||||
static const u8 sText_EVO_LEVEL_MOVE_TWENTY_TIMES[] = _("{LV}{UP_ARROW} after 20x {STR_VAR_2}");
|
||||
static const u8 sText_EVO_LEVEL_RECOIL_DAMAGE_MALE[] = _("{LV}{UP_ARROW} with {STR_VAR_2} recoil, male");
|
||||
static const u8 sText_EVO_LEVEL_RECOIL_DAMAGE_FEMALE[] = _("{LV}{UP_ARROW} with {STR_VAR_2} recoil, female");
|
||||
static const u8 sText_EVO_UNKNOWN[] = _("Method unknown");
|
||||
static const u8 sText_EVO_NONE[] = _("{STR_VAR_1} has no evolution.");
|
||||
|
||||
@ -6770,6 +6773,18 @@ static u8 PrintEvolutionTargetSpeciesAndMethod(u8 taskId, u16 species, u8 depth,
|
||||
CopyItemName(item, gStringVar2);
|
||||
StringExpandPlaceholders(gStringVar4, sText_EVO_ITEM_HOLD );
|
||||
break;
|
||||
case EVO_LEVEL_MOVE_TWENTY_TIMES:
|
||||
StringCopy(gStringVar2, GetMoveName(evolutions[i].param));
|
||||
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_MOVE_TWENTY_TIMES );
|
||||
break;
|
||||
case EVO_LEVEL_RECOIL_DAMAGE_MALE:
|
||||
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, 3);
|
||||
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_RECOIL_DAMAGE_MALE);
|
||||
break;
|
||||
case EVO_LEVEL_RECOIL_DAMAGE_FEMALE:
|
||||
ConvertIntToDecimalStringN(gStringVar2, evolutions[i].param, STR_CONV_MODE_LEADING_ZEROS, 3);
|
||||
StringExpandPlaceholders(gStringVar4, sText_EVO_LEVEL_RECOIL_DAMAGE_FEMALE);
|
||||
break;
|
||||
default:
|
||||
StringExpandPlaceholders(gStringVar4, sText_EVO_UNKNOWN );
|
||||
break;
|
||||
|
||||
@ -2087,6 +2087,19 @@ u32 GetMonData2(struct Pokemon *mon, s32 field)
|
||||
return GetMonData3(mon, field, NULL);
|
||||
}
|
||||
|
||||
struct EvolutionTrackerBitfield
|
||||
{
|
||||
u16 a: 5;
|
||||
u16 b: 4;
|
||||
u16 unused: 7;
|
||||
};
|
||||
|
||||
union EvolutionTracker
|
||||
{
|
||||
u16 value;
|
||||
struct EvolutionTrackerBitfield asField;
|
||||
};
|
||||
|
||||
/* GameFreak called GetBoxMonData with either 2 or 3 arguments, for type
|
||||
* safety we have a GetBoxMonData macro (in include/pokemon.h) which
|
||||
* dispatches to either GetBoxMonData2 or GetBoxMonData3 based on the
|
||||
@ -2099,6 +2112,7 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
|
||||
struct PokemonSubstruct1 *substruct1 = NULL;
|
||||
struct PokemonSubstruct2 *substruct2 = NULL;
|
||||
struct PokemonSubstruct3 *substruct3 = NULL;
|
||||
union EvolutionTracker evoTracker;
|
||||
|
||||
// Any field greater than MON_DATA_ENCRYPT_SEPARATOR is encrypted and must be treated as such
|
||||
if (field > MON_DATA_ENCRYPT_SEPARATOR)
|
||||
@ -2479,6 +2493,11 @@ u32 GetBoxMonData3(struct BoxPokemon *boxMon, s32 field, u8 *data)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MON_DATA_EVOLUTION_TRACKER:
|
||||
evoTracker.asField.a = substruct1->evolutionTracker1;
|
||||
evoTracker.asField.b = substruct1->evolutionTracker2;
|
||||
retVal = evoTracker.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -2894,6 +2913,16 @@ void SetBoxMonData(struct BoxPokemon *boxMon, s32 field, const void *dataArg)
|
||||
substruct0->teraType = 1 + teraType;
|
||||
break;
|
||||
}
|
||||
case MON_DATA_EVOLUTION_TRACKER:
|
||||
{
|
||||
union EvolutionTracker evoTracker;
|
||||
u32 evoTrackerValue;
|
||||
SET32(evoTrackerValue);
|
||||
evoTracker.value = evoTrackerValue;
|
||||
substruct1->evolutionTracker1 = evoTracker.asField.a;
|
||||
substruct1->evolutionTracker2 = evoTracker.asField.b;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -4047,6 +4076,7 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem, s
|
||||
u16 upperPersonality = personality >> 16;
|
||||
u32 holdEffect, currentMap, partnerSpecies, partnerHeldItem, partnerHoldEffect;
|
||||
bool32 consumeItem = FALSE;
|
||||
u16 evolutionTracker = GetMonData(mon, MON_DATA_EVOLUTION_TRACKER, 0);
|
||||
const struct Evolution *evolutions = GetSpeciesEvolutions(species);
|
||||
|
||||
if (evolutions == NULL)
|
||||
@ -4307,6 +4337,18 @@ u16 GetEvolutionTargetSpecies(struct Pokemon *mon, u8 mode, u16 evolutionItem, s
|
||||
consumeItem = TRUE;
|
||||
}
|
||||
break;
|
||||
case EVO_LEVEL_MOVE_TWENTY_TIMES:
|
||||
if (evolutionTracker >= 20)
|
||||
targetSpecies = evolutions[i].targetSpecies;
|
||||
break;
|
||||
case EVO_LEVEL_RECOIL_DAMAGE_MALE:
|
||||
if (evolutionTracker >= evolutions[i].param && GetMonGender(mon) == MON_MALE)
|
||||
targetSpecies = evolutions[i].targetSpecies;
|
||||
break;
|
||||
case EVO_LEVEL_RECOIL_DAMAGE_FEMALE:
|
||||
if (evolutionTracker >= evolutions[i].param && GetMonGender(mon) == MON_FEMALE)
|
||||
targetSpecies = evolutions[i].targetSpecies;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user