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

Open
wants to merge 51 commits into
base: upcoming
Choose a base branch
from

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
@mrgriffin
Copy link
Collaborator

I'm probably missing something, but I'm surprised that there isn't a change in test/battle/trainer_control.c to account for these arrays now being indexed by difficulty, and a Difficulty: ... line in test/battle/trainer_control.party.

Maybe the problem is that .party files don't get rebuilt if trainerproc changes. I think this is a general problem with our Makefile, generated files could say that they depend on the tool that generates them. Maybe something like would do the trick for trainerproc:

-%.h: %.party tools ; $(CPP) $(CPPFLAGS) -traditional-cpp - < $< | $(TRAINERPROC) -o $@ -i $< -
+%.h: %.party tools $(TRAINERPROC) ; $(CPP) $(CPPFLAGS) -traditional-cpp - < $< | $(TRAINERPROC) -o $@ -i $< 

@pkmnsnfrn
Copy link
Collaborator Author

I'm probably missing something, but I'm surprised that there isn't a change in test/battle/trainer_control.c to account for these arrays now being indexed by difficulty, and a Difficulty: ... line in test/battle/trainer_control.party.

Maybe the problem is that .party files don't get rebuilt if trainerproc changes. I think this is a general problem with our Makefile, generated files could say that they depend on the tool that generates them. Maybe something like would do the trick for trainerproc:

-%.h: %.party tools ; $(CPP) $(CPPFLAGS) -traditional-cpp - < $< | $(TRAINERPROC) -o $@ -i $< -
+%.h: %.party tools $(TRAINERPROC) ; $(CPP) $(CPPFLAGS) -traditional-cpp - < $< | $(TRAINERPROC) -o $@ -i $< 

To be clear, you're saying "hey, tests shouldn't have passed with this change"? I assumed that them passing meant that my fallback to DIFFCULTY_NORMAL was working correctly.

@mrgriffin
Copy link
Collaborator

To be clear, you're saying "hey, tests shouldn't have passed with this change"? I assumed that them passing meant that my fallback to DIFFCULTY_NORMAL was working correctly.

That's what I thought, yeah. I'd have thought that we'd at least need a 2D trainers array in the tests. You're right about the fallback though, the .party file shouldn't need to change (but maybe it's worth adding an explicit Difficulty: Normal for documentation purposes?).

But I checked out your PR locally and it seemed to work fine, so my assumption was wrong 😅

SBird1337
SBird1337 previously approved these changes Oct 24, 2024
Co-authored-by: Martin Griffin <[email protected]>
include/difficulty.h Outdated Show resolved Hide resolved
sbird and others added 2 commits October 24, 2024 05:30
@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.

tools/trainerproc/main.c Show resolved Hide resolved
tools/trainerproc/main.c Outdated Show resolved Hide resolved
test/battle/trainer_control.party Outdated Show resolved Hide resolved
@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.

src/battle_message.c Outdated Show resolved Hide resolved
src/battle_message.c Show resolved Hide resolved
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.

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