From 7ab23cf426afeb5b1d8250b7212e66edd332ff42 Mon Sep 17 00:00:00 2001 From: Alex <93446519+AlexOn1ine@users.noreply.github.com> Date: Sun, 18 Feb 2024 15:02:58 +0100 Subject: [PATCH] Sets neutral nature and ability 0 as default in trainer control (#4172) * Sets neutral nature and ability 0 as default in trainer control * add config to generate a random ability * minor correction * move config to battle.h * fixed compiling --- include/config/battle.h | 1 + include/data.h | 1 - src/battle_main.c | 24 +++++++++++++++++------- src/data/partner_parties.h | 6 +++--- test/battle/trainer_control.c | 8 +++++++- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/include/config/battle.h b/include/config/battle.h index 3b4b5ed96f..5ec007e686 100644 --- a/include/config/battle.h +++ b/include/config/battle.h @@ -230,6 +230,7 @@ #define B_WILD_NATURAL_ENEMIES TRUE // If set to TRUE, certain wild mon species will attack other species when partnered in double wild battles (eg. Zangoose vs Seviper) #define B_AFFECTION_MECHANICS TRUE // In Gen6+, there's a stat called affection that can trigger different effects in battle. From LGPE onwards, those effects use friendship instead. #define B_TRAINER_CLASS_POKE_BALLS GEN_LATEST // In Gen7+, trainers will use certain types of Poké Balls depending on their trainer class. +#define B_TRAINER_MON_RANDOM_ABILITY FALSE // If this is set to TRUE a random legal ability will be generated for a trainer mon #define B_OBEDIENCE_MECHANICS GEN_LATEST // In PLA+ (here Gen8+), obedience restrictions also apply to non-outsider Pokémon, albeit based on their level met rather than actual level #define B_USE_FROSTBITE FALSE // In PLA, Frostbite replaces Freeze. Enabling this flag does the same here. Moves can still be cherry-picked to either Freeze or Frostbite. Freeze-Dry, Secret Power & Tri Attack depend on this config. #define B_OVERWORLD_SNOW GEN_LATEST // In Gen9+, overworld Snow will summon snow instead of hail. diff --git a/include/data.h b/include/data.h index 4ac1d327fa..6baf5b3059 100644 --- a/include/data.h +++ b/include/data.h @@ -52,7 +52,6 @@ struct TrainerBacksprite #define GET_MON_COORDS_HEIGHT(size)((size & 0xF) * 8) #define TRAINER_PARTY_IVS(hp, atk, def, speed, spatk, spdef) (hp | (atk << 5) | (def << 10) | (speed << 15) | (spatk << 20) | (spdef << 25)) #define TRAINER_PARTY_EVS(hp, atk, def, speed, spatk, spdef) ((const u8[6]){hp,atk,def,spatk,spdef,speed}) -#define TRAINER_PARTY_NATURE(nature) (nature+1) struct TrainerMon { diff --git a/src/battle_main.c b/src/battle_main.c index 7ed28ea63c..3ae5289c58 100644 --- a/src/battle_main.c +++ b/src/battle_main.c @@ -1928,7 +1928,7 @@ void CustomTrainerPartyAssignMoves(struct Pokemon *mon, const struct TrainerMon u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer *trainer, bool32 firstTrainer, u32 battleTypeFlags) { u32 personalityValue; - s32 i, j; + s32 i; u8 monsCount; if (battleTypeFlags & BATTLE_TYPE_TRAINER && !(battleTypeFlags & (BATTLE_TYPE_FRONTIER | BATTLE_TYPE_EREADER_TRAINER @@ -1956,6 +1956,7 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer const struct TrainerMon *partyData = trainer->party; u32 otIdType = OT_ID_RANDOM_NO_SHINY; u32 fixedOtId = 0; + u32 ability = 0; if (trainer->doubleBattle == TRUE) personalityValue = 0x80; @@ -1969,8 +1970,7 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer personalityValue = (personalityValue & 0xFFFFFF00) | GeneratePersonalityForGender(MON_MALE, partyData[i].species); else if (partyData[i].gender == TRAINER_MON_FEMALE) personalityValue = (personalityValue & 0xFFFFFF00) | GeneratePersonalityForGender(MON_FEMALE, partyData[i].species); - if (partyData[i].nature != 0) - ModifyPersonalityForNature(&personalityValue, partyData[i].nature - 1); + ModifyPersonalityForNature(&personalityValue, partyData[i].nature); if (partyData[i].isShiny) { otIdType = OT_ID_PRESET; @@ -1994,14 +1994,24 @@ u8 CreateNPCTrainerPartyFromTrainer(struct Pokemon *party, const struct Trainer { const struct SpeciesInfo *speciesInfo = &gSpeciesInfo[partyData[i].species]; u32 maxAbilities = ARRAY_COUNT(speciesInfo->abilities); - for (j = 0; j < maxAbilities; ++j) + for (ability = 0; ability < maxAbilities; ++ability) { - if (speciesInfo->abilities[j] == partyData[i].ability) + if (speciesInfo->abilities[ability] == partyData[i].ability) break; } - if (j < maxAbilities) - SetMonData(&party[i], MON_DATA_ABILITY_NUM, &j); + if (ability >= maxAbilities) + ability = 0; } + else if (B_TRAINER_MON_RANDOM_ABILITY) + { + const struct SpeciesInfo *speciesInfo = &gSpeciesInfo[partyData[i].species]; + ability = personalityHash % 3; + while (speciesInfo->abilities[ability] == ABILITY_NONE) + { + ability--; + } + } + SetMonData(&party[i], MON_DATA_ABILITY_NUM, &ability); SetMonData(&party[i], MON_DATA_FRIENDSHIP, &(partyData[i].friendship)); if (partyData[i].ball != ITEM_NONE) { diff --git a/src/data/partner_parties.h b/src/data/partner_parties.h index fec80c6ca1..1b071ec28e 100644 --- a/src/data/partner_parties.h +++ b/src/data/partner_parties.h @@ -2,7 +2,7 @@ static const struct TrainerMon sParty_StevenPartner[] = { { .species = SPECIES_METANG, .lvl = 42, - .nature = TRAINER_PARTY_NATURE(NATURE_BRAVE), + .nature = NATURE_BRAVE, .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .ev = TRAINER_PARTY_EVS(0, 252, 252, 0, 6, 0), .moves = {MOVE_LIGHT_SCREEN, MOVE_PSYCHIC, MOVE_REFLECT, MOVE_METAL_CLAW}, @@ -10,7 +10,7 @@ static const struct TrainerMon sParty_StevenPartner[] = { { .species = SPECIES_SKARMORY, .lvl = 43, - .nature = TRAINER_PARTY_NATURE(NATURE_IMPISH), + .nature = NATURE_IMPISH, .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .ev = TRAINER_PARTY_EVS(252, 0, 0, 0, 6, 252), .moves = {MOVE_TOXIC, MOVE_AERIAL_ACE, MOVE_PROTECT, MOVE_STEEL_WING}, @@ -18,7 +18,7 @@ static const struct TrainerMon sParty_StevenPartner[] = { { .species = SPECIES_AGGRON, .lvl = 44, - .nature = TRAINER_PARTY_NATURE(NATURE_ADAMANT), + .nature = NATURE_ADAMANT, .iv = TRAINER_PARTY_IVS(31, 31, 31, 31, 31, 31), .ev = TRAINER_PARTY_EVS(0, 252, 0, 0, 252, 6), .moves = {MOVE_THUNDER, MOVE_PROTECT, MOVE_SOLAR_BEAM, MOVE_DRAGON_CLAW}, diff --git a/test/battle/trainer_control.c b/test/battle/trainer_control.c index e3e071745d..9415360948 100644 --- a/test/battle/trainer_control.c +++ b/test/battle/trainer_control.c @@ -26,7 +26,7 @@ static const struct TrainerMon sTestParty1[] = .ev = TRAINER_PARTY_EVS(252, 0, 0, 252, 4, 0), .lvl = 67, .moves = {MOVE_AIR_SLASH, MOVE_BARRIER, MOVE_SOLAR_BEAM, MOVE_EXPLOSION}, - .nature = TRAINER_PARTY_NATURE(NATURE_HASTY), + .nature = NATURE_HASTY, .nickname = COMPOUND_STRING("Bubbles"), .dynamaxLevel = 5, }, @@ -35,6 +35,10 @@ static const struct TrainerMon sTestParty1[] = .ability = ABILITY_SHADOW_TAG, .lvl = 5, }, + { + .species = SPECIES_WYNAUT, + .lvl = 5, + }, }; static const struct Trainer sTestTrainer1 = @@ -59,6 +63,7 @@ TEST("CreateNPCTrainerPartyForTrainer generates customized Pokémon") EXPECT(GetMonAbility(&testParty[0]) == ABILITY_TELEPATHY); EXPECT(GetMonAbility(&testParty[1]) == ABILITY_SHADOW_TAG); + EXPECT(GetMonAbility(&testParty[2]) == ABILITY_SHADOW_TAG); EXPECT(GetMonData(&testParty[0], MON_DATA_FRIENDSHIP, 0) == 42); EXPECT(GetMonData(&testParty[1], MON_DATA_FRIENDSHIP, 0) == 0); @@ -110,6 +115,7 @@ TEST("CreateNPCTrainerPartyForTrainer generates customized Pokémon") EXPECT(GetMonGender(&testParty[0]) == MON_FEMALE); EXPECT(GetNature(&testParty[0]) == NATURE_HASTY); + EXPECT(GetNature(&testParty[1]) == NATURE_HARDY); EXPECT_EQ(GetMonData(&testParty[0], MON_DATA_DYNAMAX_LEVEL), 5); EXPECT_EQ(GetMonData(&testParty[1], MON_DATA_DYNAMAX_LEVEL), 0);