Skip to content

Commit

Permalink
Customizable FrontierMon Sets (#4313)
Browse files Browse the repository at this point in the history
* more customization to struct FacilityMon, remove facility item ids, convert vanilla data, add CreateFacilityMon universal function

* fix some unused vars

* use TrainerMon struct instead of FacilityMon

* add dynamaxLevel, gigantamaxFactor to CreateFacilityMon

* some struct TrainerMon documentation

---------

Co-authored-by: ghoulslash <[email protected]>
  • Loading branch information
ghoulslash and ghoulslash authored Mar 29, 2024
1 parent b58ccac commit 5a986c6
Show file tree
Hide file tree
Showing 10 changed files with 2,262 additions and 2,518 deletions.
19 changes: 6 additions & 13 deletions include/battle_tower.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef GUARD_BATTLE_TOWER_H
#define GUARD_BATTLE_TOWER_H

#include "data.h"

struct RSBattleTowerRecord
{
/*0x00*/ u8 lvlMode; // 0 = level 50, 1 = level 100
Expand All @@ -24,31 +26,21 @@ struct BattleFrontierTrainer
const u16 *monSet;
};

struct FacilityMon
{
u16 species;
u16 moves[MAX_MON_MOVES];
u8 itemTableId;
u8 evSpread;
u8 nature;
};

extern const u8 gTowerMaleFacilityClasses[30];
extern const u8 gTowerMaleTrainerGfxIds[30];
extern const u8 gTowerFemaleFacilityClasses[20];
extern const u8 gTowerFemaleTrainerGfxIds[20];
extern const u16 gBattleFrontierHeldItems[];
extern const struct FacilityMon gBattleFrontierMons[];
extern const struct TrainerMon gBattleFrontierMons[];
extern const struct BattleFrontierTrainer gBattleFrontierTrainers[];
extern const struct FacilityMon gSlateportBattleTentMons[];
extern const struct TrainerMon gSlateportBattleTentMons[];
extern const struct BattleFrontierTrainer gSlateportBattleTentTrainers[];

// Temporary storage for monIds of the opponent team
// during team generation in battle factory and similar facilities.
extern u16 gFrontierTempParty[];

extern const struct BattleFrontierTrainer *gFacilityTrainers;
extern const struct FacilityMon *gFacilityTrainerMons;
extern const struct TrainerMon *gFacilityTrainerMons;

void CallBattleTowerFunc(void);
u16 GetRandomScaledFrontierTrainerId(u8 challengeNum, u8 battleNum);
Expand Down Expand Up @@ -84,5 +76,6 @@ s32 GetHighestLevelInPlayerParty(void);
u8 FacilityClassToGraphicsId(u8 facilityClass);
bool32 ValidateBattleTowerRecord(u8 recordId); // unused
void TrySetLinkBattleTowerEnemyPartyLevel(void);
void CreateFacilityMon(const struct TrainerMon *fmon, u16 level, u8 fixedIV, u32 otID, u32 flags, struct Pokemon *dst);

#endif //GUARD_BATTLE_TOWER_H
66 changes: 3 additions & 63 deletions include/constants/battle_frontier.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,75 +116,15 @@
#define EXCHANGE_CORNER_VITAMIN_CLERK 2
#define EXCHANGE_CORNER_HOLD_ITEM_CLERK 3

// unused
#define F_EV_SPREAD_HP (1 << 0)
#define F_EV_SPREAD_ATTACK (1 << 1)
#define F_EV_SPREAD_DEFENSE (1 << 2)
#define F_EV_SPREAD_SPEED (1 << 3)
#define F_EV_SPREAD_SP_ATTACK (1 << 4)
#define F_EV_SPREAD_SP_DEFENSE (1 << 5)

#define BATTLE_FRONTIER_ITEM_NONE 0
#define BATTLE_FRONTIER_ITEM_KINGS_ROCK 1
#define BATTLE_FRONTIER_ITEM_SITRUS_BERRY 2
#define BATTLE_FRONTIER_ITEM_ORAN_BERRY 3
#define BATTLE_FRONTIER_ITEM_CHESTO_BERRY 4
#define BATTLE_FRONTIER_ITEM_HARD_STONE 5
#define BATTLE_FRONTIER_ITEM_FOCUS_BAND 6
#define BATTLE_FRONTIER_ITEM_PERSIM_BERRY 7
#define BATTLE_FRONTIER_ITEM_MIRACLE_SEED 8
#define BATTLE_FRONTIER_ITEM_BERRY_JUICE 9
#define BATTLE_FRONTIER_ITEM_MACHO_BRACE 10
#define BATTLE_FRONTIER_ITEM_SILVER_POWDER 11
#define BATTLE_FRONTIER_ITEM_CHERI_BERRY 12
#define BATTLE_FRONTIER_ITEM_BLACK_GLASSES 13
#define BATTLE_FRONTIER_ITEM_BLACK_BELT 14
#define BATTLE_FRONTIER_ITEM_SOUL_DEW 15
#define BATTLE_FRONTIER_ITEM_CHOICE_BAND 16
#define BATTLE_FRONTIER_ITEM_MAGNET 17
#define BATTLE_FRONTIER_ITEM_SILK_SCARF 18
#define BATTLE_FRONTIER_ITEM_WHITE_HERB 19
#define BATTLE_FRONTIER_ITEM_DEEP_SEA_SCALE 20
#define BATTLE_FRONTIER_ITEM_DEEP_SEA_TOOTH 21
#define BATTLE_FRONTIER_ITEM_MYSTIC_WATER 22
#define BATTLE_FRONTIER_ITEM_SHARP_BEAK 23
#define BATTLE_FRONTIER_ITEM_QUICK_CLAW 24
#define BATTLE_FRONTIER_ITEM_LEFTOVERS 25
#define BATTLE_FRONTIER_ITEM_RAWST_BERRY 26
#define BATTLE_FRONTIER_ITEM_LIGHT_BALL 27
#define BATTLE_FRONTIER_ITEM_POISON_BARB 28
#define BATTLE_FRONTIER_ITEM_NEVER_MELT_ICE 29
#define BATTLE_FRONTIER_ITEM_ASPEAR_BERRY 30
#define BATTLE_FRONTIER_ITEM_SPELL_TAG 31
#define BATTLE_FRONTIER_ITEM_BRIGHT_POWDER 32
#define BATTLE_FRONTIER_ITEM_LEPPA_BERRY 33
#define BATTLE_FRONTIER_ITEM_SCOPE_LENS 34
#define BATTLE_FRONTIER_ITEM_TWISTED_SPOON 35
#define BATTLE_FRONTIER_ITEM_METAL_COAT 36
#define BATTLE_FRONTIER_ITEM_MENTAL_HERB 37
#define BATTLE_FRONTIER_ITEM_CHARCOAL 38
#define BATTLE_FRONTIER_ITEM_PECHA_BERRY 39
#define BATTLE_FRONTIER_ITEM_SOFT_SAND 40
#define BATTLE_FRONTIER_ITEM_LUM_BERRY 41
#define BATTLE_FRONTIER_ITEM_DRAGON_SCALE 42
#define BATTLE_FRONTIER_ITEM_DRAGON_FANG 43
#define BATTLE_FRONTIER_ITEM_IAPAPA_BERRY 44
#define BATTLE_FRONTIER_ITEM_WIKI_BERRY 45
#define BATTLE_FRONTIER_ITEM_SEA_INCENSE 46
#define BATTLE_FRONTIER_ITEM_SHELL_BELL 47
#define BATTLE_FRONTIER_ITEM_SALAC_BERRY 48
#define BATTLE_FRONTIER_ITEM_LANSAT_BERRY 49
#define BATTLE_FRONTIER_ITEM_APICOT_BERRY 50
#define BATTLE_FRONTIER_ITEM_STARF_BERRY 51
#define BATTLE_FRONTIER_ITEM_LIECHI_BERRY 52
#define BATTLE_FRONTIER_ITEM_LEEK 53
#define BATTLE_FRONTIER_ITEM_LAX_INCENSE 54
#define BATTLE_FRONTIER_ITEM_AGUAV_BERRY 55
#define BATTLE_FRONTIER_ITEM_FIGY_BERRY 56
#define BATTLE_FRONTIER_ITEM_THICK_CLUB 57
#define BATTLE_FRONTIER_ITEM_MAGO_BERRY 58
#define BATTLE_FRONTIER_ITEM_METAL_POWDER 59
#define BATTLE_FRONTIER_ITEM_PETAYA_BERRY 60
#define BATTLE_FRONTIER_ITEM_LUCKY_PUNCH 61
#define BATTLE_FRONTIER_ITEM_GANLON_BERRY 62
// CreateFacilityMonFlags
#define FLAG_FRONTIER_MON_FACTORY (1 << 0)

#endif // GUARD_CONSTANTS_BATTLE_FRONTIER_H
2 changes: 2 additions & 0 deletions include/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ struct TrainerBacksprite
#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})

// Shared by both trainer and frontier mons
// See CreateNPCTrainerPartyFromTrainer and CreateFacilityMon
struct TrainerMon
{
const u8 *nickname;
Expand Down
98 changes: 28 additions & 70 deletions src/battle_dome.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ enum {

static u8 GetDomeTrainerMonIvs(u16);
static void SwapDomeTrainers(int, int, u16 *);
static void CalcDomeMonStats(u16, int, int, u8, u8, int *);
static void CalcDomeMonStats(const struct TrainerMon *fmon, int level, u8 ivs, int *stats);
static void CreateDomeOpponentMons(u16);
static int SelectOpponentMons_Good(u16, bool8);
static int SelectOpponentMons_Bad(u16, bool8);
Expand Down Expand Up @@ -2000,7 +2000,7 @@ static void InitDomeTrainers(void)
if (alreadySelectedMonId == monId
|| species[0] == gFacilityTrainerMons[monId].species
|| species[1] == gFacilityTrainerMons[monId].species
|| gFacilityTrainerMons[alreadySelectedMonId].itemTableId == gFacilityTrainerMons[monId].itemTableId)
|| gFacilityTrainerMons[alreadySelectedMonId].heldItem == gFacilityTrainerMons[monId].heldItem)
break;
}
} while (k != j);
Expand Down Expand Up @@ -2053,11 +2053,8 @@ static void InitDomeTrainers(void)
ivs = GetDomeTrainerMonIvs(DOME_TRAINERS[i].trainerId);
for (j = 0; j < FRONTIER_PARTY_SIZE; j++)
{
CalcDomeMonStats(gFacilityTrainerMons[DOME_MONS[i][j]].species,
monLevel, ivs,
gFacilityTrainerMons[DOME_MONS[i][j]].evSpread,
gFacilityTrainerMons[DOME_MONS[i][j]].nature,
statValues);
CalcDomeMonStats(&gFacilityTrainerMons[DOME_MONS[i][j]],
monLevel, ivs, statValues);

rankingScores[i] += statValues[STAT_ATK];
rankingScores[i] += statValues[STAT_DEF];
Expand Down Expand Up @@ -2130,40 +2127,31 @@ static void InitDomeTrainers(void)

#define CALC_STAT(base, statIndex) \
{ \
u8 baseStat = gSpeciesInfo[species].base; \
u8 baseStat = gSpeciesInfo[fmon->species].base; \
stats[statIndex] = (((2 * baseStat + ivs + evs[statIndex] / 4) * level) / 100) + 5; \
stats[statIndex] = (u8) ModifyStatByNature(nature, stats[statIndex], statIndex); \
stats[statIndex] = (u8) ModifyStatByNature(fmon->nature, stats[statIndex], statIndex); \
}

static void CalcDomeMonStats(u16 species, int level, int ivs, u8 evBits, u8 nature, int *stats)
static void CalcDomeMonStats(const struct TrainerMon *fmon, int level, u8 ivs, int *stats)
{
int i, count;
u8 bits;
u16 resultingEvs;
int evs[NUM_STATS];

count = 0, bits = evBits;
for (i = 0; i < NUM_STATS; bits >>= 1, i++)
{
if (bits & 1)
count++;
}

resultingEvs = MAX_TOTAL_EVS / count;
for (i = 0; i < NUM_STATS; bits <<= 1, i++)
int i;

for (i = 0; i < NUM_STATS; i++)
{
evs[i] = 0;
if (evBits & bits)
evs[i] = resultingEvs;
if (fmon->ev != NULL)
evs[i] = fmon->ev[i];
else
evs[i] = 0;
}

if (species == SPECIES_SHEDINJA)
if (fmon->species == SPECIES_SHEDINJA)
{
stats[STAT_HP] = 1;
}
else
{
int n = 2 * gSpeciesInfo[species].baseHP;
int n = 2 * gSpeciesInfo[fmon->species].baseHP;
stats[STAT_HP] = (((n + ivs + evs[STAT_HP] / 4) * level) / 100) + level + 10;
}

Expand Down Expand Up @@ -2205,33 +2193,15 @@ static void InitDomeOpponentParty(void)

static void CreateDomeOpponentMon(u8 monPartyId, u16 tournamentTrainerId, u8 tournamentMonId, u32 otId)
{
int i;
u8 friendship = MAX_FRIENDSHIP;
#ifdef BUGFIX
u8 fixedIv = GetDomeTrainerMonIvs(DOME_TRAINERS[tournamentTrainerId].trainerId);
#else
u8 fixedIv = GetDomeTrainerMonIvs(tournamentTrainerId); // BUG: Using the wrong ID. As a result, all Pokémon have ivs of 3.
#endif
u8 level = SetFacilityPtrsGetLevel();
CreateMonWithEVSpreadNatureOTID(&gEnemyParty[monPartyId],
gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].species,
level,
gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].nature,
fixedIv,
gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].evSpread, otId);

friendship = MAX_FRIENDSHIP;
for (i = 0; i < MAX_MON_MOVES; i++)
{
SetMonMoveSlot(&gEnemyParty[monPartyId],
gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].moves[i], i);
if (gMovesInfo[gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].moves[i]].effect == EFFECT_FRUSTRATION)
friendship = 0;
}

SetMonData(&gEnemyParty[monPartyId], MON_DATA_FRIENDSHIP, &friendship);
SetMonData(&gEnemyParty[monPartyId], MON_DATA_HELD_ITEM,
&gBattleFrontierHeldItems[gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]].itemTableId]);

CreateFacilityMon(&gFacilityTrainerMons[DOME_MONS[tournamentTrainerId][tournamentMonId]],
level, fixedIv, otId, 0, &gEnemyParty[monPartyId]);
}

static void CreateDomeOpponentMons(u16 tournamentTrainerId)
Expand Down Expand Up @@ -4463,23 +4433,14 @@ static void DisplayTrainerInfoOnCard(u8 flags, u8 trainerTourneyId)
{
for (i = 0; i < FRONTIER_PARTY_SIZE; i++)
{
int evBits = gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].evSpread;
for (k = 0, j = 0; j < NUM_STATS; j++)
{
allocatedArray[j] = 0;
if (evBits & 1)
k++;
evBits >>= 1;
}
k = MAX_TOTAL_EVS / k;
evBits = gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].evSpread;
for (j = 0; j < NUM_STATS; j++)
{
if (evBits & 1)
allocatedArray[j] = k;
evBits >>= 1;
if (gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].ev != NULL)
allocatedArray[j] = gFacilityTrainerMons[DOME_MONS[trainerTourneyId][i]].ev[j];
else
allocatedArray[j] = 0;
}

allocatedArray[NUM_STATS] += allocatedArray[STAT_HP];
for (j = 0; j < NUM_NATURE_STATS; j++)
{
Expand Down Expand Up @@ -5800,7 +5761,7 @@ static void InitRandomTourneyTreeResults(void)
if (alreadySelectedMonId == monId
|| species[0] == gFacilityTrainerMons[monId].species
|| species[1] == gFacilityTrainerMons[monId].species
|| gFacilityTrainerMons[alreadySelectedMonId].itemTableId == gFacilityTrainerMons[monId].itemTableId)
|| gFacilityTrainerMons[alreadySelectedMonId].heldItem == gFacilityTrainerMons[monId].heldItem)
break;
}
} while (k != j);
Expand All @@ -5821,11 +5782,8 @@ static void InitRandomTourneyTreeResults(void)
ivs = GetDomeTrainerMonIvs(DOME_TRAINERS[i].trainerId);
for (j = 0; j < FRONTIER_PARTY_SIZE; j++)
{
CalcDomeMonStats(gFacilityTrainerMons[DOME_MONS[i][j]].species,
monLevel, ivs,
gFacilityTrainerMons[DOME_MONS[i][j]].evSpread,
gFacilityTrainerMons[DOME_MONS[i][j]].nature,
statValues);
CalcDomeMonStats(&gFacilityTrainerMons[DOME_MONS[i][j]],
monLevel, ivs, statValues);

statSums[i] += statValues[STAT_ATK];
statSums[i] += statValues[STAT_DEF];
Expand Down
Loading

0 comments on commit 5a986c6

Please sign in to comment.