-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Add Difficulty Mode
voloved edited this page May 9, 2023
·
5 revisions
By devolov. Huge help for FRLG-Plus for inspiring this
Goal: Add difficulty mode that causes trainers' Pokemon's levels to scale with the badge count.
For a given badge count and difficulty setting, the level addition to the trainer's Pokemon is given in the table:
Badges | Easy | Normal | Hard |
---|---|---|---|
<2 | -1 | 0 | 1 |
<4 | -2 | 0 | 2 |
<6 | -3 | 0 | 3 |
<Champion | -4 | 0 | 4 |
Champion | -5 | 0 | 5 |
Ex: At 5 badges and a HARD
setting, a normal level 16 trainer Pokemon will be 19.
If you already have a menu in your game, then adding the logic is all you need along with setting VAR_DIFFICULTY
in your menu (0 = Normal, 1 = Hard, 2 = Easy).
If you don't then you can follow my method, which is allowing the setting to be changed at One of Prof Birch's PCs.
--------------------------- include/constants/vars.h ---------------------------
index 214b80d1b..82378d7fb 100644
@@ -267,9 +267,9 @@
#define VAR_WILD_PKMN_ROUTE_SEEN_1 0x40F8
#define VAR_WILD_PKMN_ROUTE_SEEN_2 0x40F9
#define VAR_WILD_PKMN_ROUTE_SEEN_3 0x40FA
#define VAR_WILD_PKMN_ROUTE_SEEN_4 0x40FB
-#define VAR_UNUSED_0x40FC 0x40FC // Unused Var
+#define VAR_DIFFICULTY 0x40FC
#define VAR_UNUSED_0x40FD 0x40FD // Unused Var
#define VAR_UNUSED_0x40FE 0x40FE // Unused Var
#define VAR_UNUSED_0x40FF 0x40FF // Unused Var
Add #defines for the settings that VAR_DIFFICULTY
holds. Normal setting is 0 so that it will be set as such by default at a new game.
------------------------------- include/global.h -------------------------------
index 6e2cfa9b8..deea675e2 100644
@@ -138,8 +138,12 @@
// This produces an error at compile-time if expr is zero.
// It looks like file.c:line: size of array `id' is negative
#define STATIC_ASSERT(expr, id) typedef char id[(expr) ? 1 : -1];
+#define DIFFICULTY_NORMAL 0
+#define DIFFICULTY_HARD 1
+#define DIFFICULTY_EASY 2
+
struct Coords8
{
s8 x;
s8 y;
Add the code that modifies the Pokemon's level and add it to the GetSumOfEnemyPartyLevel
function (which looks like it's only used for the transition scene).
------------------------------ src/battle_setup.c ------------------------------
index 62158de8d..01b029c06 100644
@@ -810,33 +811,33 @@ static u8 GetSumOfEnemyPartyLevel(u16 opponentId, u8 numMons)
{
const struct TrainerMonNoItemDefaultMoves *party;
party = gTrainers[opponentId].party.NoItemDefaultMoves;
for (i = 0; i < count; i++)
- sum += party[i].lvl;
+ sum += GetScaledLevel(party[i].lvl);
}
break;
case F_TRAINER_PARTY_CUSTOM_MOVESET:
{
const struct TrainerMonNoItemCustomMoves *party;
party = gTrainers[opponentId].party.NoItemCustomMoves;
for (i = 0; i < count; i++)
- sum += party[i].lvl;
+ sum += GetScaledLevel(party[i].lvl);
}
break;
case F_TRAINER_PARTY_HELD_ITEM:
{
const struct TrainerMonItemDefaultMoves *party;
party = gTrainers[opponentId].party.ItemDefaultMoves;
for (i = 0; i < count; i++)
- sum += party[i].lvl;
+ sum += GetScaledLevel(party[i].lvl);
}
break;
case F_TRAINER_PARTY_CUSTOM_MOVESET | F_TRAINER_PARTY_HELD_ITEM:
{
const struct TrainerMonItemCustomMoves *party;
party = gTrainers[opponentId].party.ItemCustomMoves;
for (i = 0; i < count; i++)
- sum += party[i].lvl;
+ sum += GetScaledLevel(party[i].lvl);
}
break;
}
@@ -2347,4 +2348,38 @@ u8 currLocConvertForNuzlocke(u8 currLocation){
default:
return currLocation;
}
}
+
+u8 GetScaledLevel(u8 lvl)
+{
+ u8 badgeCount = 0;
+ u8 levelScaling = 0;
+ u32 i;
+ for (i = FLAG_BADGE01_GET; i < FLAG_BADGE01_GET + NUM_BADGES; i++)
+ {
+ if (FlagGet(i))
+ badgeCount++;
+ }
+
+ if (FlagGet(FLAG_IS_CHAMPION))
+ levelScaling = 5;
+ else if (badgeCount >= 6)
+ levelScaling = 4;
+ else if (badgeCount >= 4)
+ levelScaling = 3;
+ else if (badgeCount >= 2)
+ levelScaling = 2;
+ else
+ levelScaling = 1;
+
+ if (VarGet(VAR_DIFFICULTY) == DIFFICULTY_HARD)
+ lvl += levelScaling;
+ else if (VarGet(VAR_DIFFICULTY) == DIFFICULTY_EASY)
+ lvl -= levelScaling;
+
+ if (lvl > 100)
+ lvl = 100;
+ if (lvl < 1)
+ lvl = 1;
+ return lvl;
+}
---------------------------- include/battle_setup.h ----------------------------
index feaa30c00..5541cbac6 100644
@@ -46,8 +46,9 @@ void SetTrainerFlag(u16 trainerId);
void ClearTrainerFlag(u16 trainerId);
void BattleSetup_StartTrainerBattle(void);
void BattleSetup_StartRematchBattle(void);
void ShowTrainerIntroSpeech(void);
+u8 GetScaledLevel(u8 lvl);
const u8 *BattleSetup_GetScriptAddrAfterBattle(void);
const u8 *BattleSetup_GetTrainerPostBattleScript(void);
void ShowTrainerCantBattleSpeech(void);
void PlayTrainerEncounterMusic(void);
------------------------------ src/battle_main.c ------------------------------
index 0f16660f1..cfd4265a5 100644
@@ -2085,9 +2085,9 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
- CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
+ CreateMon(&party[i], partyData[i].species, GetScaledLevel(partyData[i].lvl), fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
SetMonData(&party[i], MON_DATA_OT_GENDER, &otGender);
SetMonData(&party[i], MON_DATA_OT_NAME, gTrainers[trainerNum].trainerName);
break;
}
@@ -2102,9 +2102,9 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
- CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
+ CreateMon(&party[i], partyData[i].species, GetScaledLevel(partyData[i].lvl), fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
SetMonData(&party[i], MON_DATA_OT_GENDER, &otGender);
SetMonData(&party[i], MON_DATA_OT_NAME, gTrainers[trainerNum].trainerName);
for (j = 0; j < MAX_MON_MOVES; j++)
@@ -2125,9 +2125,9 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
- CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
+ CreateMon(&party[i], partyData[i].species, GetScaledLevel(partyData[i].lvl), fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
SetMonData(&party[i], MON_DATA_OT_GENDER, &otGender);
SetMonData(&party[i], MON_DATA_OT_NAME, gTrainers[trainerNum].trainerName);
SetMonData(&party[i], MON_DATA_HELD_ITEM, &partyData[i].heldItem);
@@ -2144,9 +2144,9 @@ static u8 CreateNPCTrainerParty(struct Pokemon *party, u16 trainerNum, bool8 fir
nameHash += gSpeciesNames[partyData[i].species][j];
personalityValue += nameHash << 8;
fixedIV = partyData[i].iv * MAX_PER_STAT_IVS / 255;
- CreateMon(&party[i], partyData[i].species, partyData[i].lvl, fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
+ CreateMon(&party[i], partyData[i].species, GetScaledLevel(partyData[i].lvl), fixedIV, TRUE, personalityValue, OT_ID_PRESET, fixedOTID);
SetMonData(&party[i], MON_DATA_OT_GENDER, &otGender);
SetMonData(&party[i], MON_DATA_OT_NAME, gTrainers[trainerNum].trainerName);
if (partyData[i].species == SPECIES_SLAKING && gTrainers[trainerNum].trainerPic == TRAINER_PIC_LEADER_NORMAN
&& gTrainers[trainerNum].trainerClass == TRAINER_CLASS_LEADER) //Set Norman's Slaking to have intimidate
------------------------------ src/battle_main.c ------------------------------
index cfd4265a5..06cfb2a0e 100644
@@ -4755,8 +4755,9 @@ u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves)
// badge boost
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_FRONTIER))
&& FlagGet(FLAG_BADGE03_GET)
+ && (VarGet(VAR_DIFFICULTY) != DIFFICULTY_HARD)
&& GetBattlerSide(battler1) == B_SIDE_PLAYER)
{
speedBattler1 = (speedBattler1 * 110) / 100;
}
@@ -4789,8 +4790,9 @@ u8 GetWhoStrikesFirst(u8 battler1, u8 battler2, bool8 ignoreChosenMoves)
// badge boost
if (!(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_FRONTIER))
&& FlagGet(FLAG_BADGE03_GET)
+ && (VarGet(VAR_DIFFICULTY) != DIFFICULTY_HARD)
&& GetBattlerSide(battler2) == B_SIDE_PLAYER)
{
speedBattler2 = (speedBattler2 * 110) / 100;
}
-------------------------------- src/pokemon.c --------------------------------
index db0e8099d..21bf84c15 100644
@@ -3421,8 +3421,10 @@ u8 CountAliveMonsInBattle(u8 caseId)
static bool8 ShouldGetStatBadgeBoost(u16 badgeFlag, u8 battlerId)
{
if (gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_EREADER_TRAINER | BATTLE_TYPE_RECORDED_LINK | BATTLE_TYPE_FRONTIER))
return FALSE;
+ if (VarGet(VAR_DIFFICULTY) == DIFFICULTY_HARD)
+ return FALSE;
else if (GetBattlerSide(battlerId) != B_SIDE_PLAYER)
return FALSE;
else if (gBattleTypeFlags & BATTLE_TYPE_TRAINER && gTrainerBattleOpponent_A == TRAINER_SECRET_BASE)
return FALSE;
----------- data/maps/LittlerootTown_ProfessorBirchsLab/scripts.inc -----------
index 603242d71..d4bc105a4 100644
@@ -686,8 +686,79 @@ LittlerootTown_ProfessorBirchsLab_EventScript_GrindRunNo::
clearflag FLAG_GRINDRUN
msgbox LittlerootTown_ProfessorBirchsLab_Text_GrindRunNo, MSGBOX_SIGN
end
+LittlerootTown_ProfessorBirchsLab_EventScript_Challenge::
+ message LittlerootTown_ProfessorBirchsLab_Text_Challenge
+ waitmessage
+ switch VAR_DIFFICULTY
+ case 0, LittlerootTown_ProfessorBirchsLab_EventScript_DefaultNormal
+ case 1, LittlerootTown_ProfessorBirchsLab_EventScript_DefaultHard
+ case 2, LittlerootTown_ProfessorBirchsLab_EventScript_DefaultEasy
+
+LittlerootTown_ProfessorBirchsLab_EventScript_DefaultNormal:
+ multichoicedefault 21, 6, MULTI_TAG_DIFFICULTY, 1, FALSE
+ goto LittlerootTown_ProfessorBirchsLab_EventScript_ChallengeSelect
+
+LittlerootTown_ProfessorBirchsLab_EventScript_DefaultHard:
+ multichoicedefault 21, 6, MULTI_TAG_DIFFICULTY, 2, FALSE
+ goto LittlerootTown_ProfessorBirchsLab_EventScript_ChallengeSelect
+
+LittlerootTown_ProfessorBirchsLab_EventScript_DefaultEasy:
+ multichoicedefault 21, 6, MULTI_TAG_DIFFICULTY, 0, FALSE
+ goto LittlerootTown_ProfessorBirchsLab_EventScript_ChallengeSelect
+
+LittlerootTown_ProfessorBirchsLab_EventScript_ChallengeSelect:
+ switch VAR_RESULT
+ case 0, LittlerootTown_ProfessorBirchsLab_EventScript_SelectedEasy
+ case 1, LittlerootTown_ProfessorBirchsLab_EventScript_SelectedNormal
+ case 2, LittlerootTown_ProfessorBirchsLab_EventScript_SelectedHard
+ case MULTI_B_PRESSED, LittlerootTown_ProfessorBirchsLab_EventScript_SelectedCancel
+ end
+
+LittlerootTown_ProfessorBirchsLab_EventScript_SelectedNormal:
+ msgbox LittlerootTown_ProfessorBirchsLab_Text_SelectedNormal, MSGBOX_DEFAULT
+ setvar VAR_DIFFICULTY, 0
+ closemessage
+ end
+
+LittlerootTown_ProfessorBirchsLab_EventScript_SelectedHard:
+ msgbox LittlerootTown_ProfessorBirchsLab_Text_SelectedHard, MSGBOX_DEFAULT
+ setvar VAR_DIFFICULTY, 1
+ closemessage
+ end
+
+LittlerootTown_ProfessorBirchsLab_EventScript_SelectedEasy:
+ msgbox LittlerootTown_ProfessorBirchsLab_Text_SelectedEasy, MSGBOX_DEFAULT
+ setvar VAR_DIFFICULTY, 2
+ closemessage
+ end
+
+LittlerootTown_ProfessorBirchsLab_EventScript_SelectedCancel:
+ msgbox LittlerootTown_ProfessorBirchsLab_Text_SelectedCancel, MSGBOX_DEFAULT
+ closemessage
+ end
+
+LittlerootTown_ProfessorBirchsLab_Text_Challenge:
+ .string "What difficulty would\n"
+ .string "you like to play at?$"
+
+LittlerootTown_ProfessorBirchsLab_Text_SelectedEasy:
+ .string "Easy difficulty\n"
+ .string "was chosen.$"
+
+LittlerootTown_ProfessorBirchsLab_Text_SelectedNormal:
+ .string "Normal difficulty\n"
+ .string "was chosen.$"
+
+LittlerootTown_ProfessorBirchsLab_Text_SelectedHard:
+ .string "Hard difficulty\n"
+ .string "was chosen.$"
+
+LittlerootTown_ProfessorBirchsLab_Text_SelectedCancel:
+ .string "Difficulty is\n"
+ .string "unchanged.$"
+
LittlerootTown_ProfessorBirchsLab_Text_SkipIntro:
.string "Would you like to skip\n"
.string "the intro in the future?$"
------------- data/maps/LittlerootTown_ProfessorBirchsLab/map.json -------------
index 00a3912ec..3695c5256 100644
{
"type": "sign",
"x": 1,
"y": 10,
"elevation": 0,
"player_facing_dir": "BG_EVENT_PLAYER_FACING_ANY",
- "script": "LittlerootTown_ProfessorBirchsLab_EventScript_PC"
+ "script": "LittlerootTown_ProfessorBirchsLab_EventScript_Challenge"
},
{
"type": "sign",
"x": 1,
"y": 9,
"elevation": 0,
"player_facing_dir": "BG_EVENT_PLAYER_FACING_ANY",
- "script": "LittlerootTown_ProfessorBirchsLab_EventScript_PC"
+ "script": "LittlerootTown_ProfessorBirchsLab_EventScript_Challenge"
},
----------------------- include/constants/script_menu.h -----------------------
index c58df7335..819e89266 100644
@@ -121,8 +121,9 @@
#define MULTI_WHERES_RAYQUAZA 110
#define MULTI_SLATEPORT_TENT_RULES 111
#define MULTI_FALLARBOR_TENT_RULES 112
#define MULTI_TAG_MATCH_TYPE 113
+#define MULTI_TAG_DIFFICULTY 114
// Lilycove SS Tidal Multichoice Selections
#define SSTIDAL_SELECTION_SLATEPORT 0
#define SSTIDAL_SELECTION_BATTLE_FRONTIER 1
-------------------------------- src/strings.c --------------------------------
index 2107e2d82..6ff3c35bb 100644
@@ -1225,8 +1225,10 @@ const u8 gText_BattlePalace[] = _("BATTLE PALACE");
const u8 gText_BattleFactory[] = _("BATTLE FACTORY");
const u8 gText_BattleArena[] = _("BATTLE ARENA");
const u8 gText_BattlePike[] = _("BATTLE PIKE");
const u8 gText_BattlePyramid[] = _("BATTLE PYRAMID");
+const u8 gText_Easy[] = _("EASY");
+const u8 gText_Hard[] = _("HARD");
ALIGNED(4) const u8 gText_FacilitySingle[] = _("{STR_VAR_1} SINGLE");
ALIGNED(4) const u8 gText_FacilityDouble[] = _("{STR_VAR_1} DOUBLE");
ALIGNED(4) const u8 gText_FacilityMulti[] = _("{STR_VAR_1} MULTI");
------------------------------ include/strings.h ------------------------------
index e944de306..ee63e8f5b 100644
@@ -267,8 +267,11 @@ extern const u8 gText_Floor7[];
extern const u8 gText_Peak[];
extern const u8 gText_SafariBallStock[];
extern const u8 gText_BattlePyramidFloor[];
+extern const u8 gText_Easy[];
+extern const u8 gText_Hard[];
+
extern const u8 gText_MenuOptionPokedex[];
extern const u8 gText_MenuOptionPokemon[];
extern const u8 gText_MenuOptionBag[];
extern const u8 gText_MenuOptionPokenav[];
---------------------------- src/data/script_menu.h ----------------------------
index 79355748c..ee4d60478 100644
@@ -770,8 +770,15 @@ static const struct MenuAction MultichoiceList_TagMatchType[] =
{gText_ExpertTagMatch},
{gText_Exit},
};
+static const struct MenuAction MultichoiceList_TagChallenge[] =
+{
+ {gText_Easy},
+ {gText_Normal},
+ {gText_Hard},
+};
+
static const struct MenuAction MultichoiceList_Exit[] =
{
{gText_Exit},
};
@@ -897,8 +904,9 @@ static const struct MultichoiceListStruct sMultichoiceLists[] =
[MULTI_WHERES_RAYQUAZA] = MULTICHOICE(MultichoiceList_WheresRayquaza),
[MULTI_SLATEPORT_TENT_RULES] = MULTICHOICE(MultichoiceList_SlateportTentRules),
[MULTI_FALLARBOR_TENT_RULES] = MULTICHOICE(MultichoiceList_FallarborTentRules),
[MULTI_TAG_MATCH_TYPE] = MULTICHOICE(MultichoiceList_TagMatchType),
+ [MULTI_TAG_DIFFICULTY] = MULTICHOICE(MultichoiceList_TagChallenge),
};
const u8 *const gStdStrings[] =
{