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 47 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

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

The remarks about encapsulation would probably remove the need to access someStruct[difficulty] all the time.

fwiw those are in expansion already, I just modified them to use the new substruct

@AlexOn1ine
Copy link
Collaborator

Thoughts on having one trainer (trainer flag) per file? so you would have trainer files like that: trainer/trainer_name.party. Reason for the suggestion is because if someone has 3 difficulty levels for each trainer it could get messy real fast.

@pkmnsnfrn
Copy link
Collaborator Author

Thoughts on having one trainer (trainer flag) per file? so you would have trainer files like that: trainer/trainer_name.party. Reason for the suggestion is because if someone has 3 difficulty levels for each trainer it could get messy real fast.

I certainly don't mind spitting up into smaller files, but unfortunately, I think opponent ID can make things tricky for things like rematches, where ideally TRAINER_DUSTY and TRAINER_DUSTY_2 are in the same file.

Splitting them up would also triple the time take to run preproc (not a blocker imho, but FYI)

(I also don't know how to split them up.)

src/data/trainers.h Outdated Show resolved Hide resolved
@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
trainer->difficulty = literal_string("Normal");

fprintf(f, "#line %d\n", trainer->difficulty_line);
fprint_constant(f, "[DIFFICULTY",trainer->difficulty);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
fprint_constant(f, "[DIFFICULTY",trainer->difficulty);
fprint_constant(f, " [DIFFICULTY",trainer->difficulty);

Should be indented to match existing formatting of trainers.h

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

test/battle/trainer_control.party Outdated Show resolved Hide resolved
@pkmnsnfrn pkmnsnfrn added the type: big feature A feature with big diffs, high impact, and touches lots of the codebase. label Dec 20, 2024
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, high impact, and touches lots of the codebase.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants