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

Adds B_VAR_DIFFICULTY and related functions READ DESC #5337

Merged
merged 56 commits into from
Jan 4, 2025

Conversation

pkmnsnfrn
Copy link
Collaborator

@pkmnsnfrn pkmnsnfrn commented Sep 7, 2024

DO NOT MERGE

until Sbird and Mgriffin have completed their reviews.

Closes #4197

Description

Player battling Maxie HARD and then Maxie EASY

  • Adds B_VAR_DIFFICULTY which changes the loaded Trainers opponents, partners and and battle slide messages based on the value of this variable.
  • Adds script macros for safely checking and changing B_VAR_DIFFICULTY

Details

Adding New Difficulty Levels

By default, the included difficulty levels are

  • DIFFICULTY_EASY
  • DIFFICULTY_NORMAL
  • DIFFICULTY_HARD

If a developer wants to adjust the number of difficulty levels, add a constant to the above DIFFICULTY_COUNT and the system will automatically update to match.

Constants

The following constants are set to protect the player from accidently setting the difficulty value to an incorrect state. Developers are free to change these.

DIFFICULTY_MIN

This is the lowest possible difficulty that the player can be on. Any attempts to decrease past this will fail.

DIFFICULTY_MAX

This is the highest possible difficulty that the player can be on. Any attempts to increase past this will fail.

Defining Difficulty for Trainers and Partners

To define a difficulty for a Trainer, add a Difficulty field to the trainer in src/data/trainers.party

 === TRAINER_SAWYER_1 ===
 Name: SAWYER
 Class: Hiker
 Pic: Hiker
 Gender: Male
 Music: Hiker
 Double Battle: No
 AI: Basic Trainer
 
 Geodude
 Level: 21
 IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe

+  === TRAINER_SAWYER_1 ===
+  Name: SAWYER
+  Class: Hiker
+  Pic: Hiker
+  Gender: Male
+  Music: Hiker
+  Double Battle: No
+  AI: Basic Trainer
+  Difficulty: Easy
+  
+  Pichu
+  Level: 1
+  IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe
+  
+  === TRAINER_SAWYER_1 ===
+  Name: SAWYER
+  Class: Hiker
+  Pic: Hiker
+  Gender: Male
+  Music: Hiker
+  Double Battle: No
+  AI: Basic Trainer
+  Difficulty: Hard
+  
+  Golem
+  Level: 60
+  IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe
+  
+  Rhydon
+  Level: 60
+  IVs: 0 HP / 0 Atk / 0 Def / 0 SpA / 0 SpD / 0 Spe

If a Trainer does not have a defined difficulty, it will use DIFFICULTY_NORMAL If you do not want this to occur.

The same syntax is applied for partners in src/data/trainers.party.

 === PARTNER_STEVEN ===
 Name: STEVEN
 Class: Rival
 Pic: Steven
 Gender: Male
 Music: Male
 
 Metang
 Brave Nature
 Level: 42
 IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
 EVs: 252 Atk / 252 Def / 6 SpA
 - Light Screen
 - Psychic
 - Reflect
 - Metal Claw
 
 Skarmory
 Impish Nature
 Level: 43
 IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
 EVs: 252 HP / 6 SpA / 252 SpD
 - Toxic
 - Aerial Ace
 - Protect
 - Steel Wing
 
 Aggron
 Adamant Nature
 Level: 44
 IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
 EVs: 252 Atk / 252 SpA / 6 SpD
 - Thunder
 - Protect
 - Solar Beam
 - Dragon Claw

+ === PARTNER_STEVEN ===
+ Name: STEVEN
+ Class: Rival
+ Pic: Steven
+ Gender: Male
+ Music: Male
+ Difficulty: Easy
+ 
+ Beldum
+ Brave Nature
+ Level: 4
+ IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
+ EVs: 252 Atk / 252 Def / 6 SpA
+ - Light Screen
+ - Psychic
+ - Reflect
+ - Metal Claw
+ 
+ Mawile
+ Impish Nature
+ Level: 4
+ IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
+ EVs: 252 HP / 6 SpA / 252 SpD
+ - Toxic
+ - Aerial Ace
+ - Protect
+ - Steel Wing
+ 
+ Aron
+ Adamant Nature
+ Level: 4
+ IVs: 31 HP / 31 Atk / 31 Def / 31 SpA / 31 SpD / 31 Spe
+ EVs: 252 Atk / 252 SpA / 6 SpD
+ - Thunder
+ - Protect
+ - Solar Beam
+ - Dragon Claw

New Difficulty Levels

If a developer adds a new difficulty level, the defined property in the .party files will need to match.

Example
Constant Name trainerproc Definition
DIFFICULTY_EASY Difficulty: Easy
DIFFICULTY_NORMAL Difficulty: Normal
DIFFICULTY_HARD Difficulty: Hard
DIFFICULTY_WEENIEHUTJR Difficulty: WeenieHutJr
DIFFICULTY_WILD Difficulty: Wild

Defining Difficulty for Slide Messages

Slide messages work in a similar way in src/battle_message.c.

static const struct TrainerSlide sTrainerSlides[DIFFICULTY_COUNT][TRAINERS_COUNT] =
{
    [DIFFICULTY_NORMAL] =
    {
   		{
+	        .trainerId = TRAINER_WALLY_VR_2,
+	        .msgLastSwitchIn = sText_AarghAlmostHadIt,
    	},
    },
    [DIFFICULTY_EASY] =
    {
   		{
+	        .trainerId = TRAINER_WALLY_VR_2,
+	        .msgLastSwitchIn = sText_123Poof,
    	},
    },
    [DIFFICULTY_HARD] =
    {
   		{
+	        .trainerId = TRAINER_WALLY_VR_2,
+	        .msgLastSwitchIn = sText_PowderExplodes,
    	},
    },
};

Fallback

If a Trainer is called for the current difficulty and that Trainer does not have an entry for that difficulty, the game will fallback on the version defined for DIFFICULTY_NORMAL.

Testing

Clean Branch

You can recreate this branch by applying a patch or pulling the repo. From a clean version of expansion's upcoming, you can either:

Patch

wget https://files.catbox.moe/bg2ywt.patch -O difficulty.patch ; git apply difficulty.patch ; rm difficulty.patch

Repo

git remote add psf-expansion https://github.com/PokemonSanFran/pokeemerald-expansion/ ; git pull psf-expansion difficultySystem

Manual Tests

After replicating the branch, to recreate my testing environment, you can either directly download the debugging changes.

Download

B_VAR_DIFFICULTY == VAR_UNUSED_0x404E

wget https://files.catbox.moe/b6x9q5.party -O src/data/trainers.party ; \
wget https://files.catbox.moe/vj4g6n.party -O src/data/battle_partners.party ; \
wget https://files.catbox.moe/05ifz4.c -O src/battle_message.c ; \
wget https://files.catbox.moe/oxwlvj.inc -O data/scripts/debug.inc ; \
wget https://files.catbox.moe/5s17gx.h -O include/config/battle.h ;

B_VAR_DIFFICULTY == 0

wget https://files.catbox.moe/b6x9q5.party -O src/data/trainers.party ; \
wget https://files.catbox.moe/vj4g6n.party -O src/data/battle_partners.party ; \
wget https://files.catbox.moe/05ifz4.c -O src/battle_message.c ; \
wget https://files.catbox.moe/oxwlvj.inc -O data/scripts/debug.inc ; \

Verified Scenarios

After compiling the game and starting a new save, the first videos show:

  • Decrease Difficulty from DIFFICULTY_NORMAL to DIFFICULTY_EASY. (Script 1)
  • Increase Difficulty from DIFFICULTY_NORMAL. (Script 2)
  • Start a battle with a Partner (Hard defined) versus a Opponent A (Hard defined) and Opponent B (Hard not defined). (Script 3)
  • Set Difficulty to DIFFICULTY_MIN. (Script 4)
  • Attempt to decrease difficulty from DIFFICULTY_MIN. (Script 5)
  • Start a battle with a Partner (Normal defined) versus a Opponent A (Easy defined) and Opponent B (Easy not defined). (Script 6)
  • Challenge the Battle Tower, complete a two battles. (Script 6)

There is a second video that shows a battle against Maxie HARD and Maxie EASY to show off the changes in battle messages.

B_VAR_DIFFICULTY == VAR_UNUSED_0x404E

test.mp4
slideon.mp4

B_VAR_DIFFICULTY == 0

off.mp4
slideoff.mp4

Things to note in the release changelog:

  • trainers.h has changed with this PR. If you're using that instead of trainers.party, reject incoming changes and replace [TRAINER_ with [DIFFICULTY_NORMAL][TRAINER_.

People who collaborated with me in this PR

@TheSylphIsIn is the original author, @mrgriffin was instrumental in getting this to work with trainerproc, @hedara90 wrote tests.

Discord Contact Info

I am pkmnsnfrn on Discord, there is a a discussion thread.

@pkmnsnfrn pkmnsnfrn requested a review from SBird1337 September 7, 2024 20:36
@pkmnsnfrn pkmnsnfrn added category: battle-mechanic Pertains to battle mechanics new-feature Adds a feature type: BREAKING Not to be merged lightly, needs to be reviewed labels Sep 8, 2024
@hedara90
Copy link
Collaborator

Is it possible to implement this without changing trainers.h?

Copy link
Collaborator

@hedara90 hedara90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some things, I haven't looked at it in more depth yet.

@pkmnsnfrn pkmnsnfrn added the type: big feature A feature with big diffs and / or high impact / subjectivity / pervasiveness label Dec 20, 2024
@hedara90
Copy link
Collaborator

I would add the "Things to note in the changelog" heading to the PR body.
Primarily with a warning about trainers.h containing changes and for people who use that to ignore incoming changes and to fix it with sed.

## Things to note in the release changelog:
- `trainers.h` has changed with this PR. If you're using that instead of `trainers.party`, reject incoming changes and replace `[TRAINER_` with `[DIFFICULTY_NORMAL][TRAINER_`.

@hedara90 hedara90 mentioned this pull request Dec 29, 2024
Copy link
Collaborator

@hedara90 hedara90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the game should first check if a trainerSlide for the current difficulty level exists, things get harder.
But I don't know what the best implementation is.

rh-hideout#5337 (comment)

Made it so trainerSlides fallback to normal when not set

Co-authored-by: hedara90 <[email protected]>
Copy link
Collaborator

@hedara90 hedara90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested manually:

  • Trainer is selected from the correct difficulty, all combinations of single, double multi.
  • Fallback difficulty works as expected in all cases.
  • TrainerSlides pull from the correct difficulty.
  • Increasing or decreasing difficulty works as expected, including when at max or min.
  • trainerproc integration.

This has my approval.

src/difficulty.c Outdated
Comment on lines 55 to 83
void Script_IncreaseDifficulty(struct ScriptContext *ctx)
{
enum DifficultyLevel currentDifficulty;

if (!B_VAR_DIFFICULTY)
return;

currentDifficulty = GetCurrentDifficultyLevel();

if (currentDifficulty++ > DIFFICULTY_MAX)
return;

SetCurrentDifficultyLevel(currentDifficulty);
}

void Script_DecreaseDifficulty(struct ScriptContext *ctx)
{
enum DifficultyLevel currentDifficulty;

if (!B_VAR_DIFFICULTY)
return;

currentDifficulty = GetCurrentDifficultyLevel();

if (!currentDifficulty)
return;

SetCurrentDifficultyLevel(--currentDifficulty);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can there be non-script functions for these functions too?
Some people might want to have access to setting this from C

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

diff --git a/include/difficulty.h b/include/difficulty.h
index a8c2c09102..f3bbab121f 100644
--- a/include/difficulty.h
+++ b/include/difficulty.h
@@ -9,9 +9,9 @@ void SetCurrentDifficultyLevel(enum DifficultyLevel);
 
 enum DifficultyLevel GetBattlePartnerDifficultyLevel(u16);
 enum DifficultyLevel GetTrainerDifficultyLevel(u16);
-void Script_IncreaseDifficulty(struct ScriptContext *);
-void Script_DecreaseDifficulty(struct ScriptContext *);
-void Script_GetDifficulty(struct ScriptContext *);
-void Script_SetDifficulty(struct ScriptContext *);
+void Script_IncreaseDifficulty(void);
+void Script_DecreaseDifficulty(void);
+void Script_GetDifficulty(void);
+void Script_SetDifficulty(struct ScriptContext *ctx);
 
 #endif // GUARD_DIFFICULTY_H
diff --git a/src/difficulty.c b/src/difficulty.c
index b57859e269..bf7caca313 100644
--- a/src/difficulty.c
+++ b/src/difficulty.c
@@ -52,7 +52,7 @@ enum DifficultyLevel GetTrainerDifficultyLevel(u16 trainerId)
     return difficulty;
 }
 
-void Script_IncreaseDifficulty(struct ScriptContext *ctx)
+void Script_IncreaseDifficulty(void)
 {
     enum DifficultyLevel currentDifficulty;
 
@@ -67,7 +67,7 @@ void Script_IncreaseDifficulty(struct ScriptContext *ctx)
     SetCurrentDifficultyLevel(currentDifficulty);
 }
 
-void Script_DecreaseDifficulty(struct ScriptContext *ctx)
+void Script_DecreaseDifficulty(void)
 {
     enum DifficultyLevel currentDifficulty;
 
@@ -82,7 +82,7 @@ void Script_DecreaseDifficulty(struct ScriptContext *ctx)
     SetCurrentDifficultyLevel(--currentDifficulty);
 }
 
-void Script_GetDifficulty(struct ScriptContext *ctx)
+void Script_GetDifficulty(void)
 {
     gSpecialVar_Result = GetCurrentDifficultyLevel();
 }

waiting for your tests to pass locally, but I'm 80% confident sure this will satisfy your request without breaking anything. The non script version of Script_SetDifficulty is SetCurrentDifficultyLevel.

Copy link
Collaborator Author

@pkmnsnfrn pkmnsnfrn Jan 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CreateNPCTrainerPartyForTrainer generates different personalities for different mons.

This test failed locally. I reverted my changes and ran the test again, and it still fails. This tells me my changes didn't cause it to fail and I suspect it will magically pass on the remote CI

988211e (#5337)

Copy link
Collaborator

@hedara90 hedara90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Send it

@hedara90 hedara90 merged commit a7f77ed into rh-hideout:upcoming Jan 4, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category: battle-mechanic Pertains to battle mechanics new-feature Adds a feature type: big feature A feature with big diffs and / or high impact / subjectivity / pervasiveness
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants